All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.zving.preloader.zip.ZipFile Maven / Gradle / Ivy
package com.zving.preloader.zip;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.zip.CRC32;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
import java.util.zip.ZipException;
public class ZipFile
{
private static final int HASH_SIZE = 509;
private static final int SHORT = 2;
private static final int WORD = 4;
private static final int NIBLET_MASK = 15;
private static final int BYTE_SHIFT = 8;
private static final int POS_0 = 0;
private static final int POS_1 = 1;
private static final int POS_2 = 2;
private static final int POS_3 = 3;
private final Map entries;
private final Map nameMap;
private String encoding;
private final ZipEncoding zipEncoding;
private RandomAccessFile archive;
private final boolean useUnicodeExtraFields;
private static final int CFH_LEN = 42;
private static final int MIN_EOCD_SIZE = 22;
private static final int MAX_EOCD_SIZE = 65557;
private static final int CFD_LOCATOR_OFFSET = 16;
private static final long LFH_OFFSET_FOR_FILENAME_LENGTH = 26L;
private static final class OffsetEntry
{
private long headerOffset;
private long dataOffset;
private OffsetEntry()
{
headerOffset = -1L;
dataOffset = -1L;
}
OffsetEntry(OffsetEntry offsetentry)
{
this();
}
}
public ZipFile(File f)
throws IOException
{
this(f, null);
}
public ZipFile(String name)
throws IOException
{
this(new File(name), null);
}
public ZipFile(String name, String encoding)
throws IOException
{
this(new File(name), encoding, true);
}
public ZipFile(File f, String encoding)
throws IOException
{
this(f, encoding, true);
}
public ZipFile(File f, String encoding, boolean useUnicodeExtraFields)
throws IOException
{
boolean success;
entries = new HashMap(509);
nameMap = new HashMap(509);
this.encoding = null;
this.encoding = encoding;
zipEncoding = ZipEncodingHelper.getZipEncoding(encoding);
this.useUnicodeExtraFields = useUnicodeExtraFields;
archive = new RandomAccessFile(f, "r");
success = false;
Map entriesWithoutUTF8Flag = populateFromCentralDirectory();
resolveLocalFileHeaderData(entriesWithoutUTF8Flag);
success = true;
if(!success)
try
{
archive.close();
}
catch(IOException ioexception) { }
return;
}
public String getEncoding()
{
return this.encoding;
}
public void close()
throws IOException
{
this.archive.close();
}
public static void closeQuietly(ZipFile zipfile)
{
if (zipfile != null) {
try
{
zipfile.close();
}
catch (IOException localIOException) {}
}
}
public Enumeration getEntries()
{
return Collections.enumeration(this.entries.keySet());
}
public ZipEntry getEntry(String name)
{
return (ZipEntry)this.nameMap.get(name);
}
public InputStream getInputStream(ZipEntry ze)
throws IOException, ZipException
{
OffsetEntry offsetEntry = (OffsetEntry)this.entries.get(ze);
if (offsetEntry == null) {
return null;
}
long start = offsetEntry.dataOffset;
BoundedInputStream bis = new BoundedInputStream(start, ze.getCompressedSize());
switch (ze.getMethod())
{
case 0:
return bis;
case 8:
bis.addDummy();
final Inflater inflater = new Inflater(true);
new InflaterInputStream(bis, inflater)
{
public void close()
throws IOException
{
super.close();
inflater.end();
}
};
}
throw new ZipException("Found unsupported compression method " + ze.getMethod());
}
private Map populateFromCentralDirectory()
throws IOException
{
HashMap noUTF8Flag = new HashMap();
positionAtCentralDirectory();
byte[] cfh = new byte[42];
byte[] signatureBytes = new byte[4];
this.archive.readFully(signatureBytes);
long sig = ZipLong.getValue(signatureBytes);
long cfhSig = ZipLong.getValue(ZipOutputStream.CFH_SIG);
if ((sig != cfhSig) && (startsWithLocalFileHeader())) {
throw new IOException("central directory is empty, can't expand corrupt archive.");
}
while (sig == cfhSig)
{
this.archive.readFully(cfh);
int off = 0;
ZipEntry ze = new ZipEntry();
int versionMadeBy = ZipShort.getValue(cfh, off);
off += 2;
ze.setPlatform(versionMadeBy >> 8 & 0xF);
off += 2;
int generalPurposeFlag = ZipShort.getValue(cfh, off);
boolean hasUTF8Flag = (generalPurposeFlag & 0x800) != 0;
ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : this.zipEncoding;
off += 2;
ze.setMethod(ZipShort.getValue(cfh, off));
off += 2;
long time = dosToJavaTime(ZipLong.getValue(cfh, off));
ze.setTime(time);
off += 4;
ze.setCrc(ZipLong.getValue(cfh, off));
off += 4;
ze.setCompressedSize(ZipLong.getValue(cfh, off));
off += 4;
ze.setSize(ZipLong.getValue(cfh, off));
off += 4;
int fileNameLen = ZipShort.getValue(cfh, off);
off += 2;
int extraLen = ZipShort.getValue(cfh, off);
off += 2;
int commentLen = ZipShort.getValue(cfh, off);
off += 2;
off += 2;
ze.setInternalAttributes(ZipShort.getValue(cfh, off));
off += 2;
ze.setExternalAttributes(ZipLong.getValue(cfh, off));
off += 4;
byte[] fileName = new byte[fileNameLen];
this.archive.readFully(fileName);
String fileNameStr = entryEncoding.decode(fileName);
if (ZipUtil.isUTF8(fileName))
{
fileNameStr = new String(fileName, "UTF-8");
hasUTF8Flag = true;
}
ze.setName(fileNameStr);
OffsetEntry offset = new OffsetEntry(null);
offset.headerOffset = ZipLong.getValue(cfh, off);
this.entries.put(ze, offset);
this.nameMap.put(ze.getName(), ze);
byte[] cdExtraData = new byte[extraLen];
this.archive.readFully(cdExtraData);
ze.setCentralDirectoryExtra(cdExtraData);
byte[] comment = new byte[commentLen];
this.archive.readFully(comment);
String commentStr = entryEncoding.decode(comment);
if (ZipUtil.isUTF8(comment))
{
commentStr = new String(comment, "UTF-8");
hasUTF8Flag = true;
}
ze.setComment(commentStr);
this.archive.readFully(signatureBytes);
sig = ZipLong.getValue(signatureBytes);
if ((!hasUTF8Flag) && (this.useUnicodeExtraFields)) {
noUTF8Flag.put(ze, new NameAndComment(fileName, comment));
}
}
return noUTF8Flag;
}
private void positionAtCentralDirectory()
throws IOException
{
boolean found = false;
long off = this.archive.length() - 22L;
long stopSearching = Math.max(0L, this.archive.length() - 65557L);
if (off >= 0L)
{
byte[] sig = ZipOutputStream.EOCD_SIG;
for (; off >= stopSearching; off -= 1L)
{
this.archive.seek(off);
int curr = this.archive.read();
if (curr == -1) {
break;
}
if (curr == sig[0])
{
curr = this.archive.read();
if (curr == sig[1])
{
curr = this.archive.read();
if (curr == sig[2])
{
curr = this.archive.read();
if (curr == sig[3])
{
found = true;
break;
}
}
}
}
}
}
if (!found) {
throw new ZipException("archive is not a ZIP archive");
}
this.archive.seek(off + 16L);
byte[] cfdOffset = new byte[4];
this.archive.readFully(cfdOffset);
this.archive.seek(ZipLong.getValue(cfdOffset));
}
private void resolveLocalFileHeaderData(Map entriesWithoutUTF8Flag)
throws IOException
{
Enumeration e = Collections.enumeration(new HashSet(this.entries.keySet()));
while (e.hasMoreElements())
{
ZipEntry ze = (ZipEntry)e.nextElement();
OffsetEntry offsetEntry = (OffsetEntry)this.entries.get(ze);
long offset = offsetEntry.headerOffset;
this.archive.seek(offset + 26L);
byte[] b = new byte[2];
this.archive.readFully(b);
int fileNameLen = ZipShort.getValue(b);
this.archive.readFully(b);
int extraFieldLen = ZipShort.getValue(b);
int lenToSkip = fileNameLen;
while (lenToSkip > 0)
{
int skipped = this.archive.skipBytes(lenToSkip);
if (skipped <= 0) {
throw new RuntimeException("failed to skip file name in local file header");
}
lenToSkip -= skipped;
}
byte[] localExtraData = new byte[extraFieldLen];
this.archive.readFully(localExtraData);
ze.setExtra(localExtraData);
offsetEntry.dataOffset = (offset + 26L + 2L + 2L + fileNameLen + extraFieldLen);
if (entriesWithoutUTF8Flag.containsKey(ze))
{
this.entries.remove(ze);
setNameAndCommentFromExtraFields(ze, (NameAndComment)entriesWithoutUTF8Flag.get(ze));
this.entries.put(ze, offsetEntry);
}
}
}
protected static Date fromDosTime(ZipLong zipDosTime)
{
long dosTime = zipDosTime.getValue();
return new Date(dosToJavaTime(dosTime));
}
private static long dosToJavaTime(long dosTime)
{
Calendar cal = Calendar.getInstance();
cal.set(1, (int)(dosTime >> 25 & 0x7F) + 1980);
cal.set(2, (int)(dosTime >> 21 & 0xF) - 1);
cal.set(5, (int)(dosTime >> 16) & 0x1F);
cal.set(11, (int)(dosTime >> 11) & 0x1F);
cal.set(12, (int)(dosTime >> 5) & 0x3F);
cal.set(13, (int)(dosTime << 1) & 0x3E);
return cal.getTime().getTime();
}
protected String getString(byte[] bytes)
throws ZipException
{
try
{
return ZipEncodingHelper.getZipEncoding(this.encoding).decode(bytes);
}
catch (IOException ex)
{
throw new ZipException("Failed to decode name: " + ex.getMessage());
}
}
private boolean startsWithLocalFileHeader()
throws IOException
{
this.archive.seek(0L);
byte[] start = new byte[4];
this.archive.readFully(start);
for (int i = 0; i < start.length; i++) {
if (start[i] != ZipOutputStream.LFH_SIG[i]) {
return false;
}
}
return true;
}
private void setNameAndCommentFromExtraFields(ZipEntry ze, NameAndComment nc)
{
UnicodePathExtraField name = (UnicodePathExtraField)ze.getExtraField(UnicodePathExtraField.UPATH_ID);
String originalName = ze.getName();
String newName = getUnicodeStringIfOriginalMatches(name, nc.name);
if ((newName != null) && (!originalName.equals(newName)))
{
ze.setName(newName);
this.nameMap.remove(originalName);
this.nameMap.put(newName, ze);
}
if ((nc.comment != null) && (nc.comment.length > 0))
{
UnicodeCommentExtraField cmt = (UnicodeCommentExtraField)ze.getExtraField(UnicodeCommentExtraField.UCOM_ID);
String newComment = getUnicodeStringIfOriginalMatches(cmt, nc.comment);
if (newComment != null) {
ze.setComment(newComment);
}
}
}
private String getUnicodeStringIfOriginalMatches(AbstractUnicodeExtraField f, byte[] orig)
{
if (f != null)
{
CRC32 crc32 = new CRC32();
crc32.update(orig);
long origCRC32 = crc32.getValue();
if (origCRC32 == f.getNameCRC32()) {
try
{
return ZipEncodingHelper.UTF8_ZIP_ENCODING.decode(f.getUnicodeName());
}
catch (IOException ex)
{
return null;
}
}
}
return null;
}
private class BoundedInputStream
extends InputStream
{
private long remaining;
private long loc;
private boolean addDummyByte = false;
BoundedInputStream(long start, long remaining)
{
this.remaining = remaining;
this.loc = start;
}
public int read()
throws IOException
{
if (this.remaining-- <= 0L)
{
if (this.addDummyByte)
{
this.addDummyByte = false;
return 0;
}
return -1;
}
synchronized (ZipFile.this.archive)
{
ZipFile.this.archive.seek(this.loc++);
return ZipFile.this.archive.read();
}
}
public int read(byte[] b, int off, int len)
throws IOException
{
if (this.remaining <= 0L)
{
if (this.addDummyByte)
{
this.addDummyByte = false;
b[off] = 0;
return 1;
}
return -1;
}
if (len <= 0) {
return 0;
}
if (len > this.remaining) {
len = (int)this.remaining;
}
int ret = -1;
synchronized (ZipFile.this.archive)
{
ZipFile.this.archive.seek(this.loc);
ret = ZipFile.this.archive.read(b, off, len);
}
if (ret > 0)
{
this.loc += ret;
this.remaining -= ret;
}
return ret;
}
void addDummy()
{
this.addDummyByte = true;
}
}
private static final class NameAndComment
{
private final byte[] name;
private final byte[] comment;
private NameAndComment(byte[] name, byte[] comment)
{
this.name = name;
this.comment = comment;
}
}
}