javajs.util.ZipTools Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jmol Show documentation
Show all versions of jmol Show documentation
Jmol: an open-source Java viewer for chemical structures in 3D
/* $RCSfile$
* $Author$
* $Date$
* $Revision$
*
* Copyright (C) 2006 The Jmol Development Team
*
* Contact: [email protected]
*
* 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, String exclude,
Map 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))
|| exclude != null && name.contains(exclude))
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";
String key = name0 + "|" + name;
fileData.put(key, 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 v = new Lst();
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 bdata, String name) {
int pt = (name == null ? -1 : name.indexOf("|"));
name = (pt >= 0 ? name.substring(pt + 1) : null);
byte[] bytes = null;
try {
if (Rdr.isPngZipStream(bis)) {
boolean isImage = "_IMAGE_".equals(name);
if (name == null || isImage) {
bytes = getPngImageBytes(bis);
bdata.put((isImage ? "_DATA_" : "_IMAGE_"), new BArray(bytes));
}
if (!isImage)
cacheZipContents(bis, name, bdata, true);
} else if (Rdr.isZipS(bis)) {
cacheZipContents(bis, name, bdata, true);
} else if (name == null){
bytes = Rdr.getLimitedStreamBytes(Rdr.getUnzippedInputStream(this, bis), -1);
bdata.put("_DATA_", new BArray(bytes));
} else {
throw new IOException("ZIP file " + name + " not found");
}
if (bytes != null)
bdata.put("_LEN_", Integer.valueOf(bytes.length));
bdata.put("$_BINARY_$", Boolean.TRUE);
} catch (IOException e) {
bdata.clear();
bdata.put("_ERROR_", e.getMessage());
}
}
@Override
public String cacheZipContents(BufferedInputStream bis,
String fileName,
Map 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;
}
}