This is an automated email from the ASF dual-hosted git repository.

peterlee 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 f4b5586  COMPRESS-565 : add a new option in Zip64Mode
f4b5586 is described below

commit f4b5586835e56373d6099c44a8be58a77efe5db4
Author: PeterAlfredLee <peteralfred...@gmail.com>
AuthorDate: Mon Feb 22 15:17:49 2021 +0800

    COMPRESS-565 : add a new option in Zip64Mode
    
    Add a new AlwaysWithCompatibility in Zip64Mode, this is a compromise for 
some libraries including 7z and Expand-Archive Powershell utility(and likely 
Excel)
    
    And we will encode LFH Offset in the Zip64 Extended Information Extra
    Field if the Disk Number Start needs to be encoded, even through the LFH
    Offset itself doesn't need to be encoded.
---
 .../commons/compress/archivers/zip/Zip64Mode.java  | 12 ++++-
 .../archivers/zip/ZipArchiveOutputStream.java      | 23 ++++++---
 .../compress/archivers/zip/Zip64SupportIT.java     | 56 ++++++++++++++++++++++
 3 files changed, 84 insertions(+), 7 deletions(-)

diff --git 
a/src/main/java/org/apache/commons/compress/archivers/zip/Zip64Mode.java 
b/src/main/java/org/apache/commons/compress/archivers/zip/Zip64Mode.java
index d051e89..428b970 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/Zip64Mode.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/Zip64Mode.java
@@ -43,5 +43,15 @@ public enum Zip64Mode {
      * Use Zip64 extensions for all entries where they are required,
      * don't use them for entries that clearly don't require them.
      */
-    AsNeeded
+    AsNeeded,
+    /**
+     * Always use Zip64 extensions for LFH and central directory as
+     * {@link Zip64Mode#Always} did, and at the meantime encode
+     * the relative offset of LFH and disk number start as needed in
+     * CFH as {@link Zip64Mode#AsNeeded} did.
+     * <p>
+     * This is a compromise for some libraries including 7z and
+     * Expand-Archive Powershell utility(and likely Excel).
+     */
+    AlwaysWithCompatibility
 }
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 5808bf5..f73af51 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
@@ -749,7 +749,8 @@ public class ZipArchiveOutputStream extends 
ArchiveOutputStream {
     }
 
     private boolean isZip64Required(final ZipArchiveEntry entry1, final 
Zip64Mode requestedMode) {
-        return requestedMode == Zip64Mode.Always || isTooLargeForZip32(entry1);
+        return requestedMode == Zip64Mode.Always || requestedMode == 
Zip64Mode.AlwaysWithCompatibility
+                || isTooLargeForZip32(entry1);
     }
 
     private boolean isTooLargeForZip32(final ZipArchiveEntry zipArchiveEntry){
@@ -940,6 +941,7 @@ public class ZipArchiveOutputStream extends 
ArchiveOutputStream {
      */
     private boolean shouldAddZip64Extra(final ZipArchiveEntry entry, final 
Zip64Mode mode) {
         return mode == Zip64Mode.Always
+            || mode == Zip64Mode.AlwaysWithCompatibility
             || entry.getSize() >= ZIP64_MAGIC
             || entry.getCompressedSize() >= ZIP64_MAGIC
             || (entry.getSize() == ArchiveEntry.SIZE_UNKNOWN
@@ -1339,7 +1341,8 @@ public class ZipArchiveOutputStream extends 
ArchiveOutputStream {
                 || ze.getSize() >= ZIP64_MAGIC
                 || entryMetaData.offset >= ZIP64_MAGIC
                 || ze.getDiskNumberStart() >= ZIP64_MAGIC_SHORT
-                || zip64Mode == Zip64Mode.Always;
+                || zip64Mode == Zip64Mode.Always
+                || zip64Mode == Zip64Mode.AlwaysWithCompatibility;
 
         if (needsZip64Extra && zip64Mode == Zip64Mode.Never) {
             // must be the offset that is too big, otherwise an
@@ -1418,7 +1421,8 @@ public class ZipArchiveOutputStream extends 
ArchiveOutputStream {
         putLong(ze.getCrc(), buf, CFH_CRC_OFFSET);
         if (ze.getCompressedSize() >= ZIP64_MAGIC
                 || ze.getSize() >= ZIP64_MAGIC
-                || zip64Mode == Zip64Mode.Always) {
+                || zip64Mode == Zip64Mode.Always
+                || zip64Mode == Zip64Mode.AlwaysWithCompatibility) {
             ZipLong.ZIP64_MAGIC.putLong(buf, CFH_COMPRESSED_SIZE_OFFSET);
             ZipLong.ZIP64_MAGIC.putLong(buf, CFH_ORIGINAL_SIZE_OFFSET);
         } else {
@@ -1480,7 +1484,8 @@ public class ZipArchiveOutputStream extends 
ArchiveOutputStream {
             final Zip64ExtendedInformationExtraField z64 = getZip64Extra(ze);
             if (ze.getCompressedSize() >= ZIP64_MAGIC
                 || ze.getSize() >= ZIP64_MAGIC
-                || zip64Mode == Zip64Mode.Always) {
+                || zip64Mode == Zip64Mode.Always
+                || zip64Mode == Zip64Mode.AlwaysWithCompatibility) {
                 z64.setCompressedSize(new 
ZipEightByteInteger(ze.getCompressedSize()));
                 z64.setSize(new ZipEightByteInteger(ze.getSize()));
             } else {
@@ -1488,10 +1493,16 @@ public class ZipArchiveOutputStream extends 
ArchiveOutputStream {
                 z64.setCompressedSize(null);
                 z64.setSize(null);
             }
-            if (lfhOffset >= ZIP64_MAGIC || zip64Mode == Zip64Mode.Always) {
+
+            final boolean needsToEncodeLfhOffset =
+                    lfhOffset >= ZIP64_MAGIC || zip64Mode == Zip64Mode.Always;
+            final boolean needsToEncodeDiskNumberStart =
+                    ze.getDiskNumberStart() >= ZIP64_MAGIC_SHORT || zip64Mode 
== Zip64Mode.Always;
+
+            if (needsToEncodeLfhOffset || needsToEncodeDiskNumberStart) {
                 z64.setRelativeHeaderOffset(new 
ZipEightByteInteger(lfhOffset));
             }
-            if (ze.getDiskNumberStart() >= ZIP64_MAGIC_SHORT || zip64Mode == 
Zip64Mode.Always) {
+            if (needsToEncodeDiskNumberStart) {
                 z64.setDiskStartNumber(new ZipLong(ze.getDiskNumberStart()));
             }
             ze.setExtra();
diff --git 
a/src/test/java/org/apache/commons/compress/archivers/zip/Zip64SupportIT.java 
b/src/test/java/org/apache/commons/compress/archivers/zip/Zip64SupportIT.java
index 9e8cb74..07c85c7 100644
--- 
a/src/test/java/org/apache/commons/compress/archivers/zip/Zip64SupportIT.java
+++ 
b/src/test/java/org/apache/commons/compress/archivers/zip/Zip64SupportIT.java
@@ -39,6 +39,7 @@ import java.util.Random;
 import java.util.zip.ZipEntry;
 
 import org.apache.commons.compress.AbstractTestCase;
+import org.apache.commons.compress.utils.IOUtils;
 import org.junit.Test;
 
 public class Zip64SupportIT {
@@ -2338,6 +2339,43 @@ public class Zip64SupportIT {
                 true, 65536L);
     }
 
+    @Test
+    public void testZip64ModeAlwaysWithCompatibility() throws Throwable {
+        final File inputFile = getFile("test3.xml");
+
+        // with Zip64Mode.AlwaysWithCompatibility, the relative header offset 
and disk number
+        // start will not be set in extra fields
+        final File zipUsingModeAlwaysWithCompatibility = buildZipWithZip64Mode(
+                "testZip64ModeAlwaysWithCompatibility-output-1",
+                Zip64Mode.AlwaysWithCompatibility, inputFile);
+        final ZipFile zipFileWithAlwaysWithCompatibility = new 
ZipFile(zipUsingModeAlwaysWithCompatibility);
+        ZipArchiveEntry entry = 
zipFileWithAlwaysWithCompatibility.getEntries().nextElement();
+        for (final ZipExtraField extraField : entry.getExtraFields()) {
+            if (!(extraField instanceof Zip64ExtendedInformationExtraField)) {
+                continue;
+            }
+
+            assertNull(((Zip64ExtendedInformationExtraField) 
extraField).getRelativeHeaderOffset());
+            assertNull(((Zip64ExtendedInformationExtraField) 
extraField).getDiskStartNumber());
+        }
+
+        // with Zip64Mode.Always, the relative header offset and disk number 
start will be
+        // set in extra fields
+        final File zipUsingModeAlways = buildZipWithZip64Mode(
+                "testZip64ModeAlwaysWithCompatibility-output-2",
+                Zip64Mode.Always, inputFile);
+        final ZipFile zipFileWithAlways = new ZipFile(zipUsingModeAlways);
+        entry = zipFileWithAlways.getEntries().nextElement();
+        for (final ZipExtraField extraField : entry.getExtraFields()) {
+            if (!(extraField instanceof Zip64ExtendedInformationExtraField)) {
+                continue;
+            }
+
+            assertNotNull(((Zip64ExtendedInformationExtraField) 
extraField).getRelativeHeaderOffset());
+            assertNotNull(((Zip64ExtendedInformationExtraField) 
extraField).getDiskStartNumber());
+        }
+    }
+
     interface ZipOutputTest {
         void test(File f, ZipArchiveOutputStream zos) throws IOException;
     }
@@ -2609,4 +2647,22 @@ public class Zip64SupportIT {
         zos.closeArchiveEntry();
         zos.close();
     }
+
+    private File buildZipWithZip64Mode(final String fileName, final Zip64Mode 
zip64Mode, final File inputFile) throws Throwable {
+        final File outputFile = getTempFile(fileName);
+        outputFile.createNewFile();
+        try(ZipArchiveOutputStream zipArchiveOutputStream = new 
ZipArchiveOutputStream(new BufferedOutputStream(new 
FileOutputStream(outputFile)))) {
+            zipArchiveOutputStream.setUseZip64(zip64Mode);
+            
zipArchiveOutputStream.setCreateUnicodeExtraFields(ZipArchiveOutputStream.UnicodeExtraFieldPolicy.ALWAYS);
+
+            zipArchiveOutputStream.putArchiveEntry(new 
ZipArchiveEntry("input.bin"));
+
+            final InputStream inputStream = new FileInputStream(inputFile);
+            IOUtils.copy(inputStream, zipArchiveOutputStream);
+
+            zipArchiveOutputStream.closeArchiveEntry();
+        }
+
+        return outputFile;
+    }
 }

Reply via email to