You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by bo...@apache.org on 2020/01/21 17:30:09 UTC
[commons-compress] 01/04: COMPRESS-477 : add Zip64 support for
split zip
This is an automated email from the ASF dual-hosted git repository.
bodewig pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-compress.git
commit b4fd49a959cc58db476e1c79f25df1728c7f22b8
Author: Lee <pe...@gmail.com>
AuthorDate: Fri Dec 27 20:07:47 2019 +0800
COMPRESS-477 : add Zip64 support for split zip
---
.../archivers/zip/Zip64RequiredException.java | 12 +++
.../archivers/zip/ZipArchiveOutputStream.java | 95 +++++++++++++++++++---
2 files changed, 94 insertions(+), 13 deletions(-)
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/Zip64RequiredException.java b/src/main/java/org/apache/commons/compress/archivers/zip/Zip64RequiredException.java
index 625ea64..eb11d06 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/Zip64RequiredException.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/Zip64RequiredException.java
@@ -37,6 +37,18 @@ public class Zip64RequiredException extends ZipException {
return ze.getName() + "'s size exceeds the limit of 4GByte.";
}
+ static final String NUMBER_OF_THIS_DISK_TOO_BIG_MESSAGE =
+ "Number of the disk of End Of Central Directory exceeds the limmit of 65535.";
+
+ static final String NUMBER_OF_THE_DISK_OF_CENTRAL_DIRECTORY_TOO_BIG_MESSAGE =
+ "Number of the disk with the start of Central Directory exceeds the limmit of 65535.";
+
+ static final String TOO_MANY_ENTRIES_ON_THIS_DISK_MESSAGE =
+ "Number of entries on this disk exceeds the limmit of 65535.";
+
+ static final String SIZE_OF_CENTRAL_DIRECTORY_TOO_BIG_MESSAGE =
+ "The size of the entire central directory exceeds the limit of 4GByte.";
+
static final String ARCHIVE_TOO_BIG_MESSAGE =
"Archive's size exceeds the limit of 4GByte.";
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
index 345a5ad..759aa75 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
@@ -1297,6 +1297,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
|| ze.getCompressedSize() >= ZIP64_MAGIC
|| ze.getSize() >= ZIP64_MAGIC
|| entryMetaData.offset >= ZIP64_MAGIC
+ || ze.getDiskNumberStart() >= ZIP64_MAGIC_SHORT
|| zip64Mode == Zip64Mode.Always;
if (needsZip64Extra && zip64Mode == Zip64Mode.Never) {
@@ -1392,7 +1393,11 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
// disk number start
if(isSplitZip) {
- putShort((int) ze.getDiskNumberStart(), buf, CFH_DISK_NUMBER_OFFSET);
+ if (ze.getDiskNumberStart() >= ZIP64_MAGIC_SHORT || zip64Mode == Zip64Mode.Always) {
+ putShort(ZIP64_MAGIC_SHORT, buf, CFH_DISK_NUMBER_OFFSET);
+ } else {
+ putShort((int) ze.getDiskNumberStart(), buf, CFH_DISK_NUMBER_OFFSET);
+ }
} else {
System.arraycopy(ZERO, 0, buf, CFH_DISK_NUMBER_OFFSET, SHORT);
}
@@ -1444,6 +1449,9 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
if (lfhOffset >= ZIP64_MAGIC || zip64Mode == Zip64Mode.Always) {
z64.setRelativeHeaderOffset(new ZipEightByteInteger(lfhOffset));
}
+ if (ze.getDiskNumberStart() >= ZIP64_MAGIC_SHORT || zip64Mode == Zip64Mode.Always) {
+ z64.setDiskStartNumber(new ZipLong(ze.getDiskNumberStart()));
+ }
ze.setExtra();
}
}
@@ -1460,6 +1468,8 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
((ZipSplitOutputStream)this.out).prepareToWriteUnsplittableContent(eocdLength);
}
+ validateIfZip64IsNeededInEOCD();
+
writeCounted(EOCD_SIG);
// number of this disk
@@ -1474,15 +1484,6 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
// number of entries
final int numberOfEntries = entries.size();
- if (numberOfEntries > ZIP64_MAGIC_SHORT
- && zip64Mode == Zip64Mode.Never) {
- throw new Zip64RequiredException(Zip64RequiredException
- .TOO_MANY_ENTRIES_MESSAGE);
- }
- if (cdOffset > ZIP64_MAGIC && zip64Mode == Zip64Mode.Never) {
- throw new Zip64RequiredException(Zip64RequiredException
- .ARCHIVE_TOO_BIG_MESSAGE);
- }
// total number of entries in the central directory on this disk
int numOfEntriesOnThisDisk = numberOfCDInDiskData.get(numberOfThisDisk) == null ? 0 : numberOfCDInDiskData.get(numberOfThisDisk);
@@ -1507,6 +1508,54 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
}
/**
+ * If the Zip64 mode is set to never, then all the data in End Of Central Directory
+ * should not exceed their limits.
+ * @throws Zip64RequiredException if Zip64 is actually needed
+ */
+ private void validateIfZip64IsNeededInEOCD() throws Zip64RequiredException {
+ // exception will only be thrown if the Zip64 mode is never while Zip64 is actually needed
+ if (zip64Mode != Zip64Mode.Never) {
+ return;
+ }
+
+ long numberOfThisDisk = 0;
+ if (isSplitZip) {
+ numberOfThisDisk = ((ZipSplitOutputStream)this.out).getCurrentSplitSegmentIndex();
+ }
+ if (numberOfThisDisk >= ZIP64_MAGIC_SHORT) {
+ throw new Zip64RequiredException(Zip64RequiredException
+ .NUMBER_OF_THIS_DISK_TOO_BIG_MESSAGE);
+ }
+
+ if (cdDiskNumberStart >= ZIP64_MAGIC_SHORT) {
+ throw new Zip64RequiredException(Zip64RequiredException
+ .NUMBER_OF_THE_DISK_OF_CENTRAL_DIRECTORY_TOO_BIG_MESSAGE);
+ }
+
+ final int numOfEntriesOnThisDisk = numberOfCDInDiskData.get(numberOfThisDisk) == null ? 0 : numberOfCDInDiskData.get(numberOfThisDisk);
+ if (numOfEntriesOnThisDisk >= ZIP64_MAGIC_SHORT) {
+ throw new Zip64RequiredException(Zip64RequiredException
+ .TOO_MANY_ENTRIES_ON_THIS_DISK_MESSAGE);
+ }
+
+ // number of entries
+ if (entries.size() >= ZIP64_MAGIC_SHORT) {
+ throw new Zip64RequiredException(Zip64RequiredException
+ .TOO_MANY_ENTRIES_MESSAGE);
+ }
+
+ if (cdLength >= ZIP64_MAGIC) {
+ throw new Zip64RequiredException(Zip64RequiredException
+ .SIZE_OF_CENTRAL_DIRECTORY_TOO_BIG_MESSAGE);
+ }
+
+ if (cdOffset >= ZIP64_MAGIC) {
+ throw new Zip64RequiredException(Zip64RequiredException
+ .ARCHIVE_TOO_BIG_MESSAGE);
+ }
+ }
+
+ /**
* Writes the "ZIP64 End of central dir record" and
* "ZIP64 End of central dir locator".
* @throws IOException on error
@@ -1517,9 +1566,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
return;
}
- if (!hasUsedZip64
- && (cdOffset >= ZIP64_MAGIC || cdLength >= ZIP64_MAGIC
- || entries.size() >= ZIP64_MAGIC_SHORT)) {
+ if (!hasUsedZip64 && shouldUseZip64EOCD()) {
// actually "will use"
hasUsedZip64 = true;
}
@@ -1614,6 +1661,28 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
}
/**
+ * 4.4.1.4 If one of the fields in the end of central directory
+ * record is too small to hold required data, the field SHOULD be
+ * set to -1 (0xFFFF or 0xFFFFFFFF) and the ZIP64 format record
+ * SHOULD be created.
+ * @return true if zip64 End Of Central Directory is needed
+ */
+ private boolean shouldUseZip64EOCD() {
+ int numberOfThisDisk = 0;
+ if(isSplitZip) {
+ numberOfThisDisk = ((ZipSplitOutputStream)this.out).getCurrentSplitSegmentIndex();
+ }
+ int numOfEntriesOnThisDisk = numberOfCDInDiskData.get(numberOfThisDisk) == null ? 0 : numberOfCDInDiskData.get(numberOfThisDisk);
+ return numberOfThisDisk >= ZIP64_MAGIC_SHORT /* number of this disk */
+ || cdDiskNumberStart >= ZIP64_MAGIC_SHORT /* number of the disk with the start of the central directory */
+ || numOfEntriesOnThisDisk >= ZIP64_MAGIC_SHORT /* total number of entries in the central directory on this disk */
+ || entries.size() >= ZIP64_MAGIC_SHORT /* total number of entries in the central directory */
+ || cdLength >= ZIP64_MAGIC /* size of the central directory */
+ || cdOffset >= ZIP64_MAGIC; /* offset of start of central directory with respect to
+ the starting disk number */
+ }
+
+ /**
* Write bytes to output or random access file.
* @param data the byte array to write
* @throws IOException on error