|
|
@@ -131,6 +131,12 @@ public class ZipFile { |
|
|
|
*/ |
|
|
|
private boolean closed; |
|
|
|
|
|
|
|
// cached buffers |
|
|
|
private final byte[] DWORD_BUF = new byte[DWORD]; |
|
|
|
private final byte[] WORD_BUF = new byte[WORD]; |
|
|
|
private final byte[] CFH_BUF = new byte[CFH_LEN]; |
|
|
|
private final byte[] SHORT_BUF = new byte[SHORT]; |
|
|
|
|
|
|
|
/** |
|
|
|
* Opens the given file for reading, assuming the platform's |
|
|
|
* native encoding for file names. |
|
|
@@ -405,9 +411,8 @@ public class ZipFile { |
|
|
|
|
|
|
|
positionAtCentralDirectory(); |
|
|
|
|
|
|
|
byte[] signatureBytes = new byte[WORD]; |
|
|
|
archive.readFully(signatureBytes); |
|
|
|
long sig = ZipLong.getValue(signatureBytes); |
|
|
|
archive.readFully(WORD_BUF); |
|
|
|
long sig = ZipLong.getValue(WORD_BUF); |
|
|
|
|
|
|
|
if (sig != CFH_SIG && startsWithLocalFileHeader()) { |
|
|
|
throw new IOException("central directory is empty, can't expand" |
|
|
@@ -416,8 +421,8 @@ public class ZipFile { |
|
|
|
|
|
|
|
while (sig == CFH_SIG) { |
|
|
|
readCentralDirectoryEntry(noUTF8Flag); |
|
|
|
archive.readFully(signatureBytes); |
|
|
|
sig = ZipLong.getValue(signatureBytes); |
|
|
|
archive.readFully(WORD_BUF); |
|
|
|
sig = ZipLong.getValue(WORD_BUF); |
|
|
|
} |
|
|
|
return noUTF8Flag; |
|
|
|
} |
|
|
@@ -434,19 +439,17 @@ public class ZipFile { |
|
|
|
private void |
|
|
|
readCentralDirectoryEntry(Map<ZipEntry, NameAndComment> noUTF8Flag) |
|
|
|
throws IOException { |
|
|
|
byte[] cfh = new byte[CFH_LEN]; |
|
|
|
|
|
|
|
archive.readFully(cfh); |
|
|
|
archive.readFully(CFH_BUF); |
|
|
|
int off = 0; |
|
|
|
ZipEntry ze = new ZipEntry(); |
|
|
|
|
|
|
|
int versionMadeBy = ZipShort.getValue(cfh, off); |
|
|
|
int versionMadeBy = ZipShort.getValue(CFH_BUF, off); |
|
|
|
off += SHORT; |
|
|
|
ze.setPlatform((versionMadeBy >> BYTE_SHIFT) & NIBLET_MASK); |
|
|
|
|
|
|
|
off += SHORT; // skip version info |
|
|
|
|
|
|
|
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(cfh, off); |
|
|
|
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(CFH_BUF, off); |
|
|
|
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames(); |
|
|
|
final ZipEncoding entryEncoding = |
|
|
|
hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding; |
|
|
@@ -454,38 +457,38 @@ public class ZipFile { |
|
|
|
|
|
|
|
off += SHORT; |
|
|
|
|
|
|
|
ze.setMethod(ZipShort.getValue(cfh, off)); |
|
|
|
ze.setMethod(ZipShort.getValue(CFH_BUF, off)); |
|
|
|
off += SHORT; |
|
|
|
|
|
|
|
long time = ZipUtil.dosToJavaTime(ZipLong.getValue(cfh, off)); |
|
|
|
long time = ZipUtil.dosToJavaTime(ZipLong.getValue(CFH_BUF, off)); |
|
|
|
ze.setTime(time); |
|
|
|
off += WORD; |
|
|
|
|
|
|
|
ze.setCrc(ZipLong.getValue(cfh, off)); |
|
|
|
ze.setCrc(ZipLong.getValue(CFH_BUF, off)); |
|
|
|
off += WORD; |
|
|
|
|
|
|
|
ze.setCompressedSize(ZipLong.getValue(cfh, off)); |
|
|
|
ze.setCompressedSize(ZipLong.getValue(CFH_BUF, off)); |
|
|
|
off += WORD; |
|
|
|
|
|
|
|
ze.setSize(ZipLong.getValue(cfh, off)); |
|
|
|
ze.setSize(ZipLong.getValue(CFH_BUF, off)); |
|
|
|
off += WORD; |
|
|
|
|
|
|
|
int fileNameLen = ZipShort.getValue(cfh, off); |
|
|
|
int fileNameLen = ZipShort.getValue(CFH_BUF, off); |
|
|
|
off += SHORT; |
|
|
|
|
|
|
|
int extraLen = ZipShort.getValue(cfh, off); |
|
|
|
int extraLen = ZipShort.getValue(CFH_BUF, off); |
|
|
|
off += SHORT; |
|
|
|
|
|
|
|
int commentLen = ZipShort.getValue(cfh, off); |
|
|
|
int commentLen = ZipShort.getValue(CFH_BUF, off); |
|
|
|
off += SHORT; |
|
|
|
|
|
|
|
int diskStart = ZipShort.getValue(cfh, off); |
|
|
|
int diskStart = ZipShort.getValue(CFH_BUF, off); |
|
|
|
off += SHORT; |
|
|
|
|
|
|
|
ze.setInternalAttributes(ZipShort.getValue(cfh, off)); |
|
|
|
ze.setInternalAttributes(ZipShort.getValue(CFH_BUF, off)); |
|
|
|
off += SHORT; |
|
|
|
|
|
|
|
ze.setExternalAttributes(ZipLong.getValue(cfh, off)); |
|
|
|
ze.setExternalAttributes(ZipLong.getValue(CFH_BUF, off)); |
|
|
|
off += WORD; |
|
|
|
|
|
|
|
byte[] fileName = new byte[fileNameLen]; |
|
|
@@ -494,7 +497,7 @@ public class ZipFile { |
|
|
|
|
|
|
|
// LFH offset, |
|
|
|
OffsetEntry offset = new OffsetEntry(); |
|
|
|
offset.headerOffset = ZipLong.getValue(cfh, off); |
|
|
|
offset.headerOffset = ZipLong.getValue(CFH_BUF, off); |
|
|
|
// data offset will be filled later |
|
|
|
entries.put(ze, offset); |
|
|
|
|
|
|
@@ -684,24 +687,17 @@ public class ZipFile { |
|
|
|
private void positionAtCentralDirectory64() |
|
|
|
throws IOException { |
|
|
|
skipBytes(ZIP64_EOCDL_LOCATOR_OFFSET); |
|
|
|
byte[] zip64EocdOffset = new byte[DWORD]; |
|
|
|
archive.readFully(zip64EocdOffset); |
|
|
|
archive.seek(ZipEightByteInteger.getLongValue(zip64EocdOffset)); |
|
|
|
byte[] sig = new byte[WORD]; |
|
|
|
archive.readFully(sig); |
|
|
|
if (sig[POS_0] != ZipOutputStream.ZIP64_EOCD_SIG[POS_0] |
|
|
|
|| sig[POS_1] != ZipOutputStream.ZIP64_EOCD_SIG[POS_1] |
|
|
|
|| sig[POS_2] != ZipOutputStream.ZIP64_EOCD_SIG[POS_2] |
|
|
|
|| sig[POS_3] != ZipOutputStream.ZIP64_EOCD_SIG[POS_3] |
|
|
|
) { |
|
|
|
archive.readFully(DWORD_BUF); |
|
|
|
archive.seek(ZipEightByteInteger.getLongValue(DWORD_BUF)); |
|
|
|
archive.readFully(WORD_BUF); |
|
|
|
if (!Arrays.equals(WORD_BUF, ZipOutputStream.ZIP64_EOCD_SIG)) { |
|
|
|
throw new ZipException("archive's ZIP64 end of central " |
|
|
|
+ "directory locator is corrupt."); |
|
|
|
} |
|
|
|
skipBytes(ZIP64_EOCD_CFD_LOCATOR_OFFSET |
|
|
|
- WORD /* signature has already been read */); |
|
|
|
byte[] cfdOffset = new byte[DWORD]; |
|
|
|
archive.readFully(cfdOffset); |
|
|
|
archive.seek(ZipEightByteInteger.getLongValue(cfdOffset)); |
|
|
|
archive.readFully(DWORD_BUF); |
|
|
|
archive.seek(ZipEightByteInteger.getLongValue(DWORD_BUF)); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@@ -717,9 +713,8 @@ public class ZipFile { |
|
|
|
throw new ZipException("archive is not a ZIP archive"); |
|
|
|
} |
|
|
|
skipBytes(CFD_LOCATOR_OFFSET); |
|
|
|
byte[] cfdOffset = new byte[WORD]; |
|
|
|
archive.readFully(cfdOffset); |
|
|
|
archive.seek(ZipLong.getValue(cfdOffset)); |
|
|
|
archive.readFully(WORD_BUF); |
|
|
|
archive.seek(ZipLong.getValue(WORD_BUF)); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@@ -814,11 +809,10 @@ public class ZipFile { |
|
|
|
OffsetEntry offsetEntry = ent.getValue(); |
|
|
|
long offset = offsetEntry.headerOffset; |
|
|
|
archive.seek(offset + LFH_OFFSET_FOR_FILENAME_LENGTH); |
|
|
|
byte[] b = new byte[SHORT]; |
|
|
|
archive.readFully(b); |
|
|
|
int fileNameLen = ZipShort.getValue(b); |
|
|
|
archive.readFully(b); |
|
|
|
int extraFieldLen = ZipShort.getValue(b); |
|
|
|
archive.readFully(SHORT_BUF); |
|
|
|
int fileNameLen = ZipShort.getValue(SHORT_BUF); |
|
|
|
archive.readFully(SHORT_BUF); |
|
|
|
int extraFieldLen = ZipShort.getValue(SHORT_BUF); |
|
|
|
int lenToSkip = fileNameLen; |
|
|
|
while (lenToSkip > 0) { |
|
|
|
int skipped = archive.skipBytes(lenToSkip); |
|
|
@@ -854,14 +848,8 @@ public class ZipFile { |
|
|
|
*/ |
|
|
|
private boolean startsWithLocalFileHeader() throws IOException { |
|
|
|
archive.seek(0); |
|
|
|
final byte[] start = new byte[WORD]; |
|
|
|
archive.readFully(start); |
|
|
|
for (int i = 0; i < start.length; i++) { |
|
|
|
if (start[i] != ZipOutputStream.LFH_SIG[i]) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
return true; |
|
|
|
archive.readFully(WORD_BUF); |
|
|
|
return Arrays.equals(WORD_BUF, ZipOutputStream.LFH_SIG); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|