Merge branch 'master' of https://source.jalview.org/git/jalviewjs.git
[jalviewjs.git] / src / javajs / util / ZipTools.java
index c7b21a2..deed8c8 100644 (file)
-/* $RCSfile$\r
- * $Author$\r
- * $Date$\r
- * $Revision$\r
- *\r
- * Copyright (C) 2006  The Jmol Development Team\r
- *\r
- * Contact: jmol-developers@lists.sf.net\r
- *\r
- *  This library is free software; you can redistribute it and/or\r
- *  modify it under the terms of the GNU Lesser General Public\r
- *  License as published by the Free Software Foundation; either\r
- *  version 2.1 of the License, or (at your option) any later version.\r
- *\r
- *  This library is distributed in the hope that it will be useful,\r
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- *  Lesser General Public License for more details.\r
- *\r
- *  You should have received a copy of the GNU Lesser General Public\r
- *  License along with this library; if not, write to the Free Software\r
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
- *  02110-1301, USA.\r
- */\r
-\r
-package javajs.util;\r
-\r
-import java.io.BufferedInputStream;\r
-import java.io.IOException;\r
-import java.io.InputStream;\r
-import java.io.OutputStream;\r
-\r
-import javajs.J2SIgnoreImport;\r
-import javajs.api.GenericZipInputStream;\r
-import javajs.api.GenericZipTools;\r
-import javajs.api.ZInputStream;\r
-\r
-import java.util.Map;\r
-import java.util.zip.CRC32;\r
-import java.util.zip.GZIPInputStream;\r
-import java.util.zip.ZipEntry;\r
-import java.util.zip.ZipInputStream;\r
-import java.util.zip.ZipOutputStream;\r
-\r
-\r
-/**\r
- * Note the JSmol/HTML5 must use its own version of java.util.zip.ZipOutputStream.\r
- * \r
- */\r
-@J2SIgnoreImport({ java.util.zip.ZipOutputStream.class })\r
-public class ZipTools implements GenericZipTools {\r
-\r
-  public ZipTools() {\r
-    // for reflection\r
-  }\r
-  \r
-  @Override\r
-  public ZInputStream newZipInputStream(InputStream is) {\r
-    return newZIS(is);\r
-  }\r
-\r
-  @SuppressWarnings("resource")\r
-  private static ZInputStream newZIS(InputStream is) {\r
-    return (is instanceof ZInputStream ? (ZInputStream) is\r
-        : is instanceof BufferedInputStream ? new GenericZipInputStream(is)\r
-            : new GenericZipInputStream(new BufferedInputStream(is)));\r
-  }\r
-\r
-  /**\r
-   * reads a ZIP file and saves all data in a Hashtable so that the files may be\r
-   * organized later in a different order. Also adds a #Directory_Listing entry.\r
-   * \r
-   * Files are bracketed by BEGIN Directory Entry and END Directory Entry lines,\r
-   * similar to CompoundDocument.getAllData.\r
-   * \r
-   * @param is\r
-   * @param subfileList\r
-   * @param name0\r
-   *        prefix for entry listing\r
-   * @param binaryFileList\r
-   *        |-separated list of files that should be saved as xx xx xx hex byte\r
-   *        strings. The directory listing is appended with ":asBinaryString"\r
-   * @param fileData\r
-   */\r
-  @Override\r
-  public void getAllZipData(InputStream is, String[] subfileList,\r
-                                          String name0, String binaryFileList,\r
-                                          Map<String, String> fileData) {\r
-    ZipInputStream zis = (ZipInputStream) newZIS(is);\r
-    ZipEntry ze;\r
-    SB listing = new SB();\r
-    binaryFileList = "|" + binaryFileList + "|";\r
-    String prefix = PT.join(subfileList, '/', 1);\r
-    String prefixd = null;\r
-    if (prefix != null) {\r
-      prefixd = prefix.substring(0, prefix.indexOf("/") + 1);\r
-      if (prefixd.length() == 0)\r
-        prefixd = null;\r
-    }\r
-    try {\r
-      while ((ze = zis.getNextEntry()) != null) {\r
-        String name = ze.getName();\r
-        if (prefix != null && prefixd != null\r
-            && !(name.equals(prefix) || name.startsWith(prefixd)))\r
-          continue;\r
-        //System.out.println("ziputil: " + name);\r
-        listing.append(name).appendC('\n');\r
-        String sname = "|" + name.substring(name.lastIndexOf("/") + 1) + "|";\r
-        boolean asBinaryString = (binaryFileList.indexOf(sname) >= 0);\r
-        byte[] bytes = Rdr.getLimitedStreamBytes(zis, ze.getSize());\r
-        String str;\r
-        if (asBinaryString) {\r
-          str = getBinaryStringForBytes(bytes);\r
-          name += ":asBinaryString";\r
-        } else {\r
-          str = Rdr.fixUTF(bytes);\r
-        }\r
-        str = "BEGIN Directory Entry " + name + "\n" + str\r
-            + "\nEND Directory Entry " + name + "\n";\r
-        fileData.put(name0 + "|" + name, str);\r
-      }\r
-    } catch (Exception e) {\r
-    }\r
-    fileData.put("#Directory_Listing", listing.toString());\r
-  }\r
-\r
-  private String getBinaryStringForBytes(byte[] bytes) {\r
-    SB ret = new SB();\r
-    for (int i = 0; i < bytes.length; i++)\r
-      ret.append(Integer.toHexString(bytes[i] & 0xFF)).appendC(' ');\r
-    return ret.toString();\r
-  }\r
-\r
-  /**\r
-   * iteratively drills into zip files of zip files to extract file content or\r
-   * zip file directory. Also works with JAR files.\r
-   * \r
-   * Does not return "__MACOS" paths\r
-   * \r
-   * @param bis\r
-   * @param list\r
-   * @param listPtr\r
-   * @param asBufferedInputStream\r
-   *        for Pmesh\r
-   * @return directory listing or subfile contents\r
-   */\r
-  @Override\r
-  public Object getZipFileDirectory(BufferedInputStream bis, String[] list,\r
-                                    int listPtr, boolean asBufferedInputStream) {\r
-    SB ret;\r
-    if (list == null || listPtr >= list.length)\r
-      return getZipDirectoryAsStringAndClose(bis);\r
-    bis = Rdr.getPngZipStream(bis, true);\r
-    String fileName = list[listPtr];\r
-    ZipInputStream zis = new ZipInputStream(bis);\r
-    ZipEntry ze;\r
-    //System.out.println("fname=" + fileName);\r
-    try {\r
-      boolean isAll = (fileName.equals("."));\r
-      if (isAll || fileName.lastIndexOf("/") == fileName.length() - 1) {\r
-        ret = new SB();\r
-        while ((ze = zis.getNextEntry()) != null) {\r
-          String name = ze.getName();\r
-          if (isAll || name.startsWith(fileName))\r
-            ret.append(name).appendC('\n');\r
-        }\r
-        String str = ret.toString();\r
-        return (asBufferedInputStream ? Rdr.getBIS(str.getBytes()) : str);\r
-      }\r
-      int pt = fileName.indexOf(":asBinaryString");\r
-      boolean asBinaryString = (pt > 0);\r
-      if (asBinaryString)\r
-        fileName = fileName.substring(0, pt);\r
-      fileName = fileName.replace('\\', '/');\r
-      while ((ze = zis.getNextEntry()) != null\r
-          && !fileName.equals(ze.getName())) {\r
-      }\r
-      byte[] bytes = (ze == null ? null : Rdr.getLimitedStreamBytes(zis,\r
-          ze.getSize()));\r
-      ze = null;\r
-      zis.close();\r
-      if (bytes == null)\r
-        return "";\r
-      if (Rdr.isZipB(bytes) || Rdr.isPngZipB(bytes))\r
-        return getZipFileDirectory(Rdr.getBIS(bytes), list, ++listPtr,\r
-            asBufferedInputStream);\r
-      if (asBufferedInputStream)\r
-        return Rdr.getBIS(bytes);\r
-      if (asBinaryString) {\r
-        ret = new SB();\r
-        for (int i = 0; i < bytes.length; i++)\r
-          ret.append(Integer.toHexString(bytes[i] & 0xFF)).appendC(' ');\r
-        return ret.toString();\r
-      }\r
-      if (Rdr.isGzipB(bytes))\r
-        bytes = Rdr.getLimitedStreamBytes(getUnGzippedInputStream(bytes), -1);\r
-      return Rdr.fixUTF(bytes);\r
-    } catch (Exception e) {\r
-      return "";\r
-    }\r
-  }\r
-\r
-  @Override\r
-  public byte[] getZipFileContentsAsBytes(BufferedInputStream bis,\r
-                                          String[] list, int listPtr) {\r
-    byte[] ret = new byte[0];\r
-    String fileName = list[listPtr];\r
-    if (fileName.lastIndexOf("/") == fileName.length() - 1)\r
-      return ret;\r
-    try {\r
-      bis = Rdr.getPngZipStream(bis, true);\r
-      ZipInputStream zis = new ZipInputStream(bis);\r
-      ZipEntry ze;\r
-      while ((ze = zis.getNextEntry()) != null) {\r
-        if (!fileName.equals(ze.getName()))\r
-          continue;\r
-        byte[] bytes = Rdr.getLimitedStreamBytes(zis, ze.getSize());\r
-        return ((Rdr.isZipB(bytes) || Rdr.isPngZipB(bytes)) && ++listPtr < list.length ? getZipFileContentsAsBytes(\r
-            Rdr.getBIS(bytes), list, listPtr) : bytes);\r
-      }\r
-    } catch (Exception e) {\r
-    }\r
-    return ret;\r
-  }\r
-  \r
-  @Override\r
-  public String getZipDirectoryAsStringAndClose(BufferedInputStream bis) {\r
-    SB sb = new SB();\r
-    String[] s = new String[0];\r
-    try {\r
-      s = getZipDirectoryOrErrorAndClose(bis, null);\r
-      bis.close();\r
-    } catch (Exception e) {\r
-      System.out.println(e.toString());\r
-    }\r
-    for (int i = 0; i < s.length; i++)\r
-      sb.append(s[i]).appendC('\n');\r
-    return sb.toString();\r
-  }\r
-\r
-  @Override\r
-  public String[] getZipDirectoryAndClose(BufferedInputStream bis,\r
-                                                 String manifestID) {\r
-    String[] s = new String[0];\r
-    try {\r
-      s = getZipDirectoryOrErrorAndClose(bis, manifestID);\r
-      bis.close();\r
-    } catch (Exception e) {\r
-      System.out.println(e.toString());\r
-    }\r
-    return s;\r
-  }\r
-\r
-  private String[] getZipDirectoryOrErrorAndClose(BufferedInputStream bis,\r
-                                                  String manifestID)\r
-      throws IOException {\r
-    bis = Rdr.getPngZipStream(bis, true);\r
-    Lst<String> v = new Lst<String>();\r
-    ZipInputStream zis = new ZipInputStream(bis);\r
-    ZipEntry ze;\r
-    String manifest = null;\r
-    while ((ze = zis.getNextEntry()) != null) {\r
-      String fileName = ze.getName();\r
-      if (manifestID != null && fileName.startsWith(manifestID))\r
-        manifest = getStreamAsString(zis);\r
-      else if (!fileName.startsWith("__MACOS")) // resource fork not nec.\r
-        v.addLast(fileName);\r
-    }\r
-    zis.close();\r
-    if (manifestID != null)\r
-      v.add(0, manifest == null ? "" : manifest + "\n############\n");\r
-    return v.toArray(new String[v.size()]);\r
-  }\r
-\r
-  public static String getStreamAsString(InputStream is) throws IOException {\r
-    return Rdr.fixUTF(Rdr.getLimitedStreamBytes(is, -1));\r
-  }\r
-\r
-  @Override\r
-  public InputStream newGZIPInputStream(InputStream is) throws IOException {\r
-    return new BufferedInputStream(new GZIPInputStream(is, 512));\r
-  }\r
-\r
-  @Override\r
-  public BufferedInputStream getUnGzippedInputStream(byte[] bytes) {\r
-    try {\r
-      return Rdr.getUnzippedInputStream(this, Rdr.getBIS(bytes));\r
-    } catch (Exception e) {\r
-      return null;\r
-    }\r
-  }\r
-\r
-  @Override\r
-  public void addZipEntry(Object zos, String fileName) throws IOException {\r
-    ((ZipOutputStream) zos).putNextEntry(new ZipEntry(fileName));\r
-  }\r
-\r
-  @Override\r
-  public void closeZipEntry(Object zos) throws IOException {\r
-    ((ZipOutputStream) zos).closeEntry();\r
-  }\r
-\r
-  @Override\r
-  public Object getZipOutputStream(Object bos) {\r
-    /**\r
-     * @j2sNative\r
-     * \r
-     *            return javajs.api.Interface.getInterface(\r
-     *            "java.util.zip.ZipOutputStream").setZOS(bos);\r
-     * \r
-     */\r
-    {\r
-      return new ZipOutputStream((OutputStream) bos);\r
-    }\r
-  }\r
-\r
-  @Override\r
-  public int getCrcValue(byte[] bytes) {\r
-    CRC32 crc = new CRC32();\r
-    crc.update(bytes, 0, bytes.length);\r
-    return (int) crc.getValue();\r
-  }\r
-\r
-  @Override\r
-  public void readFileAsMap(BufferedInputStream bis, Map<String, Object> bdata, String name) {\r
-    int pt = (name == null ? -1 : name.indexOf("|"));\r
-    name = (pt >= 0 ? name.substring(pt + 1) : null);\r
-    try {\r
-      if (Rdr.isPngZipStream(bis)) {\r
-        boolean isImage = "_IMAGE_".equals(name);\r
-        if (name == null || isImage)\r
-          bdata.put((isImage ? "_DATA_" : "_IMAGE_"), new BArray(getPngImageBytes(bis)));\r
-        if (!isImage)\r
-          cacheZipContents(bis, name, bdata, true);\r
-      } else if (Rdr.isZipS(bis)) {\r
-        cacheZipContents(bis, name, bdata, true);\r
-      } else if (name == null){\r
-        bdata.put("_DATA_", new BArray(Rdr.getLimitedStreamBytes(bis, -1)));\r
-      } else {\r
-        throw new IOException("ZIP file " + name + " not found");\r
-      }\r
-      bdata.put("$_BINARY_$", Boolean.TRUE);\r
-    } catch (IOException e) {\r
-      bdata.clear();\r
-      bdata.put("_ERROR_", e.getMessage());\r
-    }\r
-  }\r
-\r
-  @Override\r
-  public String cacheZipContents(BufferedInputStream bis,\r
-                                        String fileName,\r
-                                        Map<String, Object> cache, \r
-                                        boolean asByteArray) {\r
-    ZipInputStream zis = (ZipInputStream) newZIS(bis);\r
-    ZipEntry ze;\r
-    SB listing = new SB();\r
-    long n = 0;\r
-    boolean oneFile = (asByteArray && fileName != null);\r
-    int pt = (oneFile ? fileName.indexOf("|") : -1);\r
-    String file0 = (pt >= 0 ? fileName : null);\r
-    if (pt >= 0)\r
-      fileName = fileName.substring(0,  pt);\r
-    try {\r
-      while ((ze = zis.getNextEntry()) != null) {\r
-        String name = ze.getName();\r
-        if (fileName != null) {\r
-          if (oneFile) {\r
-            if (!name.equalsIgnoreCase(fileName))\r
-              continue;\r
-          } else {\r
-            listing.append(name).appendC('\n');\r
-          }\r
-        }\r
-        long nBytes = ze.getSize();\r
-        byte[] bytes = Rdr.getLimitedStreamBytes(zis, nBytes);\r
-        if (file0 != null) {\r
-          readFileAsMap(Rdr.getBIS(bytes), cache, file0);\r
-          return null;\r
-        }\r
-        n += bytes.length;\r
-        Object o = (asByteArray ? new BArray(bytes) : bytes);        \r
-        cache.put((oneFile ? "_DATA_" : (fileName == null ? "" : fileName + "|") + name), o);\r
-        if (oneFile)\r
-          break;\r
-      }\r
-      zis.close();\r
-    } catch (Exception e) {\r
-      try {\r
-        zis.close();\r
-      } catch (IOException e1) {\r
-      }\r
-      return null;\r
-    }\r
-    if (n == 0 || fileName == null)\r
-      return null;\r
-    System.out.println("ZipTools cached " + n + " bytes from " + fileName);\r
-    return listing.toString();\r
-  }\r
-\r
-  private static byte[] getPngImageBytes(BufferedInputStream bis) {\r
-    try {\r
-      if (Rdr.isPngZipStream(bis)) {\r
-        int pt_count[] = new int[2];\r
-        Rdr.getPngZipPointAndCount(bis, pt_count);\r
-        if (pt_count[1] != 0)\r
-          return deActivatePngZipB(Rdr.getLimitedStreamBytes(bis, pt_count[0]));\r
-      }\r
-      return Rdr.getLimitedStreamBytes(bis, -1);\r
-    } catch (IOException e) {\r
-      return null;\r
-    }\r
-  }\r
-\r
-  /**\r
-   * Once a PNGJ image has been extracted, we want to red-line its\r
-   * iTXt "Jmol Type PNGJ" tag, since it is no longer associated with\r
-   * ZIP data.\r
-   *  \r
-   * @param bytes\r
-   * @return disfigured bytes\r
-   * \r
-   */\r
-  private static byte[] deActivatePngZipB(byte[] bytes) {\r
-    // \0PNGJ starting at byte 50 changed to \0 NGJ\r
-    if (Rdr.isPngZipB(bytes))\r
-      bytes[51] = 32;\r
-    return bytes;\r
-  }\r
-\r
-\r
-\r
-}\r
+/* $RCSfile$
+ * $Author$
+ * $Date$
+ * $Revision$
+ *
+ * Copyright (C) 2006  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+package javajs.util;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javajs.J2SIgnoreImport;
+import javajs.api.GenericZipInputStream;
+import javajs.api.GenericZipTools;
+import javajs.api.ZInputStream;
+
+import java.util.Map;
+import java.util.zip.CRC32;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+
+/**
+ * Note the JSmol/HTML5 must use its own version of java.util.zip.ZipOutputStream.
+ * 
+ */
+@J2SIgnoreImport({ java.util.zip.ZipOutputStream.class })
+public class ZipTools implements GenericZipTools {
+
+  public ZipTools() {
+    // for reflection
+  }
+  
+  @Override
+  public ZInputStream newZipInputStream(InputStream is) {
+    return newZIS(is);
+  }
+
+  @SuppressWarnings("resource")
+  private static ZInputStream newZIS(InputStream is) {
+    return (is instanceof ZInputStream ? (ZInputStream) is
+        : is instanceof BufferedInputStream ? new GenericZipInputStream(is)
+            : new GenericZipInputStream(new BufferedInputStream(is)));
+  }
+
+  /**
+   * reads a ZIP file and saves all data in a Hashtable so that the files may be
+   * organized later in a different order. Also adds a #Directory_Listing entry.
+   * 
+   * Files are bracketed by BEGIN Directory Entry and END Directory Entry lines,
+   * similar to CompoundDocument.getAllData.
+   * 
+   * @param is
+   * @param subfileList
+   * @param name0
+   *        prefix for entry listing
+   * @param binaryFileList
+   *        |-separated list of files that should be saved as xx xx xx hex byte
+   *        strings. The directory listing is appended with ":asBinaryString"
+   * @param fileData
+   */
+  @Override
+  public void getAllZipData(InputStream is, String[] subfileList,
+                                          String name0, String binaryFileList,
+                                          Map<String, String> fileData) {
+    ZipInputStream zis = (ZipInputStream) newZIS(is);
+    ZipEntry ze;
+    SB listing = new SB();
+    binaryFileList = "|" + binaryFileList + "|";
+    String prefix = PT.join(subfileList, '/', 1);
+    String prefixd = null;
+    if (prefix != null) {
+      prefixd = prefix.substring(0, prefix.indexOf("/") + 1);
+      if (prefixd.length() == 0)
+        prefixd = null;
+    }
+    try {
+      while ((ze = zis.getNextEntry()) != null) {
+        String name = ze.getName();
+        if (prefix != null && prefixd != null
+            && !(name.equals(prefix) || name.startsWith(prefixd)))
+          continue;
+        //System.out.println("ziputil: " + name);
+        listing.append(name).appendC('\n');
+        String sname = "|" + name.substring(name.lastIndexOf("/") + 1) + "|";
+        boolean asBinaryString = (binaryFileList.indexOf(sname) >= 0);
+        byte[] bytes = Rdr.getLimitedStreamBytes(zis, ze.getSize());
+        String str;
+        if (asBinaryString) {
+          str = getBinaryStringForBytes(bytes);
+          name += ":asBinaryString";
+        } else {
+          str = Rdr.fixUTF(bytes);
+        }
+        str = "BEGIN Directory Entry " + name + "\n" + str
+            + "\nEND Directory Entry " + name + "\n";
+        fileData.put(name0 + "|" + name, str);
+      }
+    } catch (Exception e) {
+    }
+    fileData.put("#Directory_Listing", listing.toString());
+  }
+
+  private String getBinaryStringForBytes(byte[] bytes) {
+    SB ret = new SB();
+    for (int i = 0; i < bytes.length; i++)
+      ret.append(Integer.toHexString(bytes[i] & 0xFF)).appendC(' ');
+    return ret.toString();
+  }
+
+  /**
+   * iteratively drills into zip files of zip files to extract file content or
+   * zip file directory. Also works with JAR files.
+   * 
+   * Does not return "__MACOS" paths
+   * 
+   * @param bis
+   * @param list
+   * @param listPtr
+   * @param asBufferedInputStream
+   *        for Pmesh
+   * @return directory listing or subfile contents
+   */
+  @Override
+  public Object getZipFileDirectory(BufferedInputStream bis, String[] list,
+                                    int listPtr, boolean asBufferedInputStream) {
+    SB ret;
+    if (list == null || listPtr >= list.length)
+      return getZipDirectoryAsStringAndClose(bis);
+    bis = Rdr.getPngZipStream(bis, true);
+    String fileName = list[listPtr];
+    ZipInputStream zis = new ZipInputStream(bis);
+    ZipEntry ze;
+    //System.out.println("fname=" + fileName);
+    try {
+      boolean isAll = (fileName.equals("."));
+      if (isAll || fileName.lastIndexOf("/") == fileName.length() - 1) {
+        ret = new SB();
+        while ((ze = zis.getNextEntry()) != null) {
+          String name = ze.getName();
+          if (isAll || name.startsWith(fileName))
+            ret.append(name).appendC('\n');
+        }
+        String str = ret.toString();
+        return (asBufferedInputStream ? Rdr.getBIS(str.getBytes()) : str);
+      }
+      int pt = fileName.indexOf(":asBinaryString");
+      boolean asBinaryString = (pt > 0);
+      if (asBinaryString)
+        fileName = fileName.substring(0, pt);
+      fileName = fileName.replace('\\', '/');
+      while ((ze = zis.getNextEntry()) != null
+          && !fileName.equals(ze.getName())) {
+      }
+      byte[] bytes = (ze == null ? null : Rdr.getLimitedStreamBytes(zis,
+          ze.getSize()));
+      ze = null;
+      zis.close();
+      if (bytes == null)
+        return "";
+      if (Rdr.isZipB(bytes) || Rdr.isPngZipB(bytes))
+        return getZipFileDirectory(Rdr.getBIS(bytes), list, ++listPtr,
+            asBufferedInputStream);
+      if (asBufferedInputStream)
+        return Rdr.getBIS(bytes);
+      if (asBinaryString) {
+        ret = new SB();
+        for (int i = 0; i < bytes.length; i++)
+          ret.append(Integer.toHexString(bytes[i] & 0xFF)).appendC(' ');
+        return ret.toString();
+      }
+      if (Rdr.isGzipB(bytes))
+        bytes = Rdr.getLimitedStreamBytes(getUnGzippedInputStream(bytes), -1);
+      return Rdr.fixUTF(bytes);
+    } catch (Exception e) {
+      return "";
+    }
+  }
+
+  @Override
+  public byte[] getZipFileContentsAsBytes(BufferedInputStream bis,
+                                          String[] list, int listPtr) {
+    byte[] ret = new byte[0];
+    String fileName = list[listPtr];
+    if (fileName.lastIndexOf("/") == fileName.length() - 1)
+      return ret;
+    try {
+      bis = Rdr.getPngZipStream(bis, true);
+      ZipInputStream zis = new ZipInputStream(bis);
+      ZipEntry ze;
+      while ((ze = zis.getNextEntry()) != null) {
+        if (!fileName.equals(ze.getName()))
+          continue;
+        byte[] bytes = Rdr.getLimitedStreamBytes(zis, ze.getSize());
+        return ((Rdr.isZipB(bytes) || Rdr.isPngZipB(bytes)) && ++listPtr < list.length ? getZipFileContentsAsBytes(
+            Rdr.getBIS(bytes), list, listPtr) : bytes);
+      }
+    } catch (Exception e) {
+    }
+    return ret;
+  }
+  
+  @Override
+  public String getZipDirectoryAsStringAndClose(BufferedInputStream bis) {
+    SB sb = new SB();
+    String[] s = new String[0];
+    try {
+      s = getZipDirectoryOrErrorAndClose(bis, null);
+      bis.close();
+    } catch (Exception e) {
+      System.out.println(e.toString());
+    }
+    for (int i = 0; i < s.length; i++)
+      sb.append(s[i]).appendC('\n');
+    return sb.toString();
+  }
+
+  @Override
+  public String[] getZipDirectoryAndClose(BufferedInputStream bis,
+                                                 String manifestID) {
+    String[] s = new String[0];
+    try {
+      s = getZipDirectoryOrErrorAndClose(bis, manifestID);
+      bis.close();
+    } catch (Exception e) {
+      System.out.println(e.toString());
+    }
+    return s;
+  }
+
+  private String[] getZipDirectoryOrErrorAndClose(BufferedInputStream bis,
+                                                  String manifestID)
+      throws IOException {
+    bis = Rdr.getPngZipStream(bis, true);
+    Lst<String> v = new Lst<String>();
+    ZipInputStream zis = new ZipInputStream(bis);
+    ZipEntry ze;
+    String manifest = null;
+    while ((ze = zis.getNextEntry()) != null) {
+      String fileName = ze.getName();
+      if (manifestID != null && fileName.startsWith(manifestID))
+        manifest = getStreamAsString(zis);
+      else if (!fileName.startsWith("__MACOS")) // resource fork not nec.
+        v.addLast(fileName);
+    }
+    zis.close();
+    if (manifestID != null)
+      v.add(0, manifest == null ? "" : manifest + "\n############\n");
+    return v.toArray(new String[v.size()]);
+  }
+
+  public static String getStreamAsString(InputStream is) throws IOException {
+    return Rdr.fixUTF(Rdr.getLimitedStreamBytes(is, -1));
+  }
+
+  @Override
+  public InputStream newGZIPInputStream(InputStream is) throws IOException {
+    return new BufferedInputStream(new GZIPInputStream(is, 512));
+  }
+
+  @Override
+  public BufferedInputStream getUnGzippedInputStream(byte[] bytes) {
+    try {
+      return Rdr.getUnzippedInputStream(this, Rdr.getBIS(bytes));
+    } catch (Exception e) {
+      return null;
+    }
+  }
+
+  @Override
+  public void addZipEntry(Object zos, String fileName) throws IOException {
+    ((ZipOutputStream) zos).putNextEntry(new ZipEntry(fileName));
+  }
+
+  @Override
+  public void closeZipEntry(Object zos) throws IOException {
+    ((ZipOutputStream) zos).closeEntry();
+  }
+
+  @Override
+  public Object getZipOutputStream(Object bos) {
+    /**
+     * @j2sNative
+     * 
+     *            return javajs.api.Interface.getInterface(
+     *            "java.util.zip.ZipOutputStream").setZOS(bos);
+     * 
+     */
+    {
+      return new ZipOutputStream((OutputStream) bos);
+    }
+  }
+
+  @Override
+  public int getCrcValue(byte[] bytes) {
+    CRC32 crc = new CRC32();
+    crc.update(bytes, 0, bytes.length);
+    return (int) crc.getValue();
+  }
+
+  @Override
+  public void readFileAsMap(BufferedInputStream bis, Map<String, Object> bdata, String name) {
+    int pt = (name == null ? -1 : name.indexOf("|"));
+    name = (pt >= 0 ? name.substring(pt + 1) : null);
+    try {
+      if (Rdr.isPngZipStream(bis)) {
+        boolean isImage = "_IMAGE_".equals(name);
+        if (name == null || isImage)
+          bdata.put((isImage ? "_DATA_" : "_IMAGE_"), new BArray(getPngImageBytes(bis)));
+        if (!isImage)
+          cacheZipContents(bis, name, bdata, true);
+      } else if (Rdr.isZipS(bis)) {
+        cacheZipContents(bis, name, bdata, true);
+      } else if (name == null){
+        bdata.put("_DATA_", new BArray(Rdr.getLimitedStreamBytes(bis, -1)));
+      } else {
+        throw new IOException("ZIP file " + name + " not found");
+      }
+      bdata.put("$_BINARY_$", Boolean.TRUE);
+    } catch (IOException e) {
+      bdata.clear();
+      bdata.put("_ERROR_", e.getMessage());
+    }
+  }
+
+  @Override
+  public String cacheZipContents(BufferedInputStream bis,
+                                        String fileName,
+                                        Map<String, Object> cache, 
+                                        boolean asByteArray) {
+    ZipInputStream zis = (ZipInputStream) newZIS(bis);
+    ZipEntry ze;
+    SB listing = new SB();
+    long n = 0;
+    boolean oneFile = (asByteArray && fileName != null);
+    int pt = (oneFile ? fileName.indexOf("|") : -1);
+    String file0 = (pt >= 0 ? fileName : null);
+    if (pt >= 0)
+      fileName = fileName.substring(0,  pt);
+    try {
+      while ((ze = zis.getNextEntry()) != null) {
+        String name = ze.getName();
+        if (fileName != null) {
+          if (oneFile) {
+            if (!name.equalsIgnoreCase(fileName))
+              continue;
+          } else {
+            listing.append(name).appendC('\n');
+          }
+        }
+        long nBytes = ze.getSize();
+        byte[] bytes = Rdr.getLimitedStreamBytes(zis, nBytes);
+        if (file0 != null) {
+          readFileAsMap(Rdr.getBIS(bytes), cache, file0);
+          return null;
+        }
+        n += bytes.length;
+        Object o = (asByteArray ? new BArray(bytes) : bytes);        
+        cache.put((oneFile ? "_DATA_" : (fileName == null ? "" : fileName + "|") + name), o);
+        if (oneFile)
+          break;
+      }
+      zis.close();
+    } catch (Exception e) {
+      try {
+        zis.close();
+      } catch (IOException e1) {
+      }
+      return null;
+    }
+    if (n == 0 || fileName == null)
+      return null;
+    System.out.println("ZipTools cached " + n + " bytes from " + fileName);
+    return listing.toString();
+  }
+
+  private static byte[] getPngImageBytes(BufferedInputStream bis) {
+    try {
+      if (Rdr.isPngZipStream(bis)) {
+        int pt_count[] = new int[2];
+        Rdr.getPngZipPointAndCount(bis, pt_count);
+        if (pt_count[1] != 0)
+          return deActivatePngZipB(Rdr.getLimitedStreamBytes(bis, pt_count[0]));
+      }
+      return Rdr.getLimitedStreamBytes(bis, -1);
+    } catch (IOException e) {
+      return null;
+    }
+  }
+
+  /**
+   * Once a PNGJ image has been extracted, we want to red-line its
+   * iTXt "Jmol Type PNGJ" tag, since it is no longer associated with
+   * ZIP data.
+   *  
+   * @param bytes
+   * @return disfigured bytes
+   * 
+   */
+  private static byte[] deActivatePngZipB(byte[] bytes) {
+    // \0PNGJ starting at byte 50 changed to \0 NGJ
+    if (Rdr.isPngZipB(bytes))
+      bytes[51] = 32;
+    return bytes;
+  }
+
+
+
+}