You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2022/12/08 01:53:54 UTC
[commons-compress] branch master updated: COMPRESS-621: Fix calculation the offset of the first zip central directory entry (#334)
This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-compress.git
The following commit(s) were added to refs/heads/master by this push:
new 0bacf83e COMPRESS-621: Fix calculation the offset of the first zip central directory entry (#334)
0bacf83e is described below
commit 0bacf83eb0b3367cd5572ab27e42a444efbcd5f8
Author: Glavo <zj...@gmail.com>
AuthorDate: Thu Dec 8 09:53:48 2022 +0800
COMPRESS-621: Fix calculation the offset of the first zip central directory entry (#334)
---
.../commons/compress/archivers/zip/ZipFile.java | 49 +++++++++++++++++----
.../compress/archivers/zip/ZipFileTest.java | 24 ++++++++++
src/test/resources/COMPRESS-621.zip | Bin 0 -> 217 bytes
3 files changed, 64 insertions(+), 9 deletions(-)
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
index df18dd41..3caf12f3 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
@@ -163,6 +163,7 @@ public class ZipFile implements Closeable {
private long centralDirectoryStartDiskNumber, centralDirectoryStartRelativeOffset;
private long centralDirectoryStartOffset;
+ private long firstLocalFileHeaderOffset = 0L;
/**
* Opens the given file for reading, assuming "UTF8" for file names.
@@ -720,6 +721,28 @@ public class ZipFile implements Closeable {
return null;
}
+ /**
+ * Offset of the first local file header in the file.
+ *
+ * @return the length of the content before the first local file header
+ * @since 1.23
+ */
+ public long getFirstLocalFileHeaderOffset() {
+ return firstLocalFileHeaderOffset;
+ }
+
+ /**
+ * Returns an InputStream for reading the content before the first local file header.
+ *
+ * @return null if there is no content before the first local file header.
+ * Otherwise returns a stream to read the content before the first local file header.
+ * @since 1.23
+ */
+ public InputStream getContentBeforeFirstLocalFileHeader() {
+ return firstLocalFileHeaderOffset == 0
+ ? null : createBoundedInputStream(0, firstLocalFileHeaderOffset);
+ }
+
/**
* Ensures that the close method of this zipfile is called when
* there are no more references to it.
@@ -896,7 +919,7 @@ public class ZipFile implements Closeable {
ze.setName(entryEncoding.decode(fileName), fileName);
// LFH offset,
- ze.setLocalHeaderOffset(ZipLong.getValue(cfhBuf, off));
+ ze.setLocalHeaderOffset(ZipLong.getValue(cfhBuf, off) + firstLocalFileHeaderOffset);
// data offset will be filled later
entries.add(ze);
@@ -1038,12 +1061,12 @@ public class ZipFile implements Closeable {
/* maximum length of zipfile comment */ + ZIP64_MAGIC_SHORT;
/**
- * Offset of the field that holds the location of the first
- * central directory entry inside the "End of central directory
+ * Offset of the field that holds the location of the length of
+ * the central directory inside the "End of central directory
* record" relative to the start of the "End of central directory
* record".
*/
- private static final int CFD_LOCATOR_OFFSET =
+ private static final int CFD_LENGTH_OFFSET =
/* end of central dir signature */ WORD
/* number of this disk */ + SHORT
/* number of the disk with the */
@@ -1051,8 +1074,7 @@ public class ZipFile implements Closeable {
/* total number of entries in */
/* the central dir on this disk */ + SHORT
/* total number of entries in */
- /* the central dir */ + SHORT
- /* size of the central directory */ + WORD;
+ /* the central dir */ + SHORT;
/**
* Offset of the field that holds the disk number of the first
@@ -1253,6 +1275,7 @@ public class ZipFile implements Closeable {
*/
private void positionAtCentralDirectory32()
throws IOException {
+ long endOfCentralDirectoryRecordOffset = archive.position();
if (isSplitZipArchive) {
skipBytes(CFD_DISK_OFFSET);
shortBbuf.rewind();
@@ -1267,12 +1290,20 @@ public class ZipFile implements Closeable {
((ZipSplitReadOnlySeekableByteChannel) archive)
.position(centralDirectoryStartDiskNumber, centralDirectoryStartRelativeOffset);
} else {
- skipBytes(CFD_LOCATOR_OFFSET);
+ skipBytes(CFD_LENGTH_OFFSET);
+ wordBbuf.rewind();
+ IOUtils.readFully(archive, wordBbuf);
+ long centralDirectoryLength = ZipLong.getValue(wordBuf);
+
wordBbuf.rewind();
IOUtils.readFully(archive, wordBbuf);
centralDirectoryStartDiskNumber = 0;
centralDirectoryStartRelativeOffset = ZipLong.getValue(wordBuf);
- archive.position(centralDirectoryStartRelativeOffset);
+
+ firstLocalFileHeaderOffset = Long.max(
+ endOfCentralDirectoryRecordOffset - centralDirectoryLength - centralDirectoryStartRelativeOffset,
+ 0L);
+ archive.position(centralDirectoryStartRelativeOffset + firstLocalFileHeaderOffset);
}
}
@@ -1448,7 +1479,7 @@ public class ZipFile implements Closeable {
* it may be an empty archive.
*/
private boolean startsWithLocalFileHeader() throws IOException {
- archive.position(0);
+ archive.position(firstLocalFileHeaderOffset);
wordBbuf.rewind();
IOUtils.readFully(archive, wordBbuf);
return Arrays.equals(wordBuf, ZipArchiveOutputStream.LFH_SIG);
diff --git a/src/test/java/org/apache/commons/compress/archivers/zip/ZipFileTest.java b/src/test/java/org/apache/commons/compress/archivers/zip/ZipFileTest.java
index 9f1056ba..eed9e9eb 100644
--- a/src/test/java/org/apache/commons/compress/archivers/zip/ZipFileTest.java
+++ b/src/test/java/org/apache/commons/compress/archivers/zip/ZipFileTest.java
@@ -827,6 +827,30 @@ public class ZipFileTest {
}
}
+ /**
+ * Test case for
+ * <a href="https://issues.apache.org/jira/browse/COMPRESS-621"
+ * >COMPRESS-621</a>.
+ */
+ @Test
+ public void testReadingOfExtraDataBeforeZip() throws IOException {
+ final byte[] fileHeader = "Before Zip file".getBytes(UTF_8);
+ final String entryName = "COMPRESS-621.txt";
+ final byte[] entryContent = "https://issues.apache.org/jira/browse/COMPRESS-621".getBytes(UTF_8);
+ try (ZipFile archive = new ZipFile(getFile("COMPRESS-621.zip"))) {
+ assertEquals(fileHeader.length, archive.getFirstLocalFileHeaderOffset());
+ try (InputStream input = archive.getContentBeforeFirstLocalFileHeader()) {
+ assertArrayEquals(fileHeader, IOUtils.toByteArray(input));
+ }
+
+ ZipArchiveEntry e = archive.getEntry(entryName);
+ assertEquals(entryContent.length, e.getSize());
+ try (InputStream input = archive.getInputStream(e)) {
+ assertArrayEquals(entryContent, IOUtils.toByteArray(input));
+ }
+ }
+ }
+
private void multiByteReadConsistentlyReturnsMinusOneAtEof(final File file) throws Exception {
final byte[] buf = new byte[2];
try (ZipFile archive = new ZipFile(file)) {
diff --git a/src/test/resources/COMPRESS-621.zip b/src/test/resources/COMPRESS-621.zip
new file mode 100644
index 00000000..e4ce3e38
Binary files /dev/null and b/src/test/resources/COMPRESS-621.zip differ