Author: bodewig
Date: Fri Jul 29 14:41:25 2011
New Revision: 1152242

URL: http://svn.apache.org/viewvc?rev=1152242&view=rev
Log:
add ZIP64 extended information to the central directory if needed.  COMPRESS-150

Modified:
    
commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/Zip64ExtendedInformationExtraField.java
    
commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java

Modified: 
commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/Zip64ExtendedInformationExtraField.java
URL: 
http://svn.apache.org/viewvc/commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/Zip64ExtendedInformationExtraField.java?rev=1152242&r1=1152241&r2=1152242&view=diff
==============================================================================
--- 
commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/Zip64ExtendedInformationExtraField.java
 (original)
+++ 
commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/Zip64ExtendedInformationExtraField.java
 Fri Jul 29 14:41:25 2011
@@ -20,6 +20,9 @@ package org.apache.commons.compress.arch
 
 import java.util.zip.ZipException;
 
+import static org.apache.commons.compress.archivers.zip.ZipConstants.DWORD;
+import static org.apache.commons.compress.archivers.zip.ZipConstants.WORD;
+
 /**
  * Holds size and other extended information for entries that use Zip64
  * features.
@@ -71,15 +74,12 @@ import java.util.zip.ZipException;
  * @NotThreadSafe
  */
 public class Zip64ExtendedInformationExtraField implements ZipExtraField {
-    // TODO: the LFH should probably not contain relativeHeaderOffset
-    // and diskStart but then ZipArchivePOutputStream won't write it to
-    // the CD either - need to test interop with other implementations
-    // to see whether they do have a problem with the extraneous
-    // information inside the LFH
 
     static final ZipShort HEADER_ID = new ZipShort(0x0001);
 
-    private static final int WORD = 4, DWORD = 8;
+    private static final String LFH_MUST_HAVE_BOTH_SIZES_MSG =
+        "Zip64 extended information must contain"
+        + " both size values in the local file header.";
 
     private ZipEightByteInteger size, compressedSize, relativeHeaderOffset;
     private ZipLong diskStart;
@@ -115,12 +115,6 @@ public class Zip64ExtendedInformationExt
                                               ZipEightByteInteger 
compressedSize,
                                               ZipEightByteInteger 
relativeHeaderOffset,
                                               ZipLong diskStart) {
-        if (size == null) {
-            throw new IllegalArgumentException("size must not be null");
-        }
-        if (compressedSize == null) {
-            throw new IllegalArgumentException("compressedSize must not be 
null");
-        }
         this.size = size;
         this.compressedSize = compressedSize;
         this.relativeHeaderOffset = relativeHeaderOffset;
@@ -134,26 +128,34 @@ public class Zip64ExtendedInformationExt
 
     /** {@inheritDoc} */
     public ZipShort getLocalFileDataLength() {
-        return getCentralDirectoryLength();
+        return new ZipShort(size != null ? 2 * DWORD : 0);
     }
 
     /** {@inheritDoc} */
     public ZipShort getCentralDirectoryLength() {
-        return new ZipShort(2 * DWORD  // both size fields
+        return new ZipShort((size != null ? DWORD : 0)
+                            + (compressedSize != null ? DWORD : 0)
                             + (relativeHeaderOffset != null ? DWORD : 0)
                             + (diskStart != null ? WORD : 0));
     }
 
     /** {@inheritDoc} */
     public byte[] getLocalFileDataData() {
-        return getCentralDirectoryData();
+        if (size != null || compressedSize != null) {
+            if (size == null || compressedSize == null) {
+                throw new 
IllegalArgumentException(LFH_MUST_HAVE_BOTH_SIZES_MSG);
+            }
+            byte[] data = new byte[2 * DWORD];
+            addSizes(data);
+            return data;
+        }
+        return new byte[0];
     }
 
     /** {@inheritDoc} */
     public byte[] getCentralDirectoryData() {
         byte[] data = new byte[getCentralDirectoryLength().getValue()];
-        addSizes(data);
-        int off = 2 * DWORD;
+        int off = addSizes(data);
         if (relativeHeaderOffset != null) {
             System.arraycopy(relativeHeaderOffset.getBytes(), 0, data, off, 
DWORD);
             off += DWORD;
@@ -169,9 +171,7 @@ public class Zip64ExtendedInformationExt
     public void parseFromLocalFileData(byte[] buffer, int offset, int length)
         throws ZipException {
         if (length < 2 * DWORD) {
-            throw new ZipException("Zip64 extended information must contain"
-                                   + " both size values in the local file"
-                                   + " header.");
+            throw new ZipException(LFH_MUST_HAVE_BOTH_SIZES_MSG);
         }
         size = new ZipEightByteInteger(buffer, offset);
         offset += DWORD;
@@ -214,6 +214,13 @@ public class Zip64ExtendedInformationExt
     }
 
     /**
+     * The uncompressed size stored in this extra field.
+     */
+    public void setSize(ZipEightByteInteger size) {
+        this.size = size;
+    }
+
+    /**
      * The compressed size stored in this extra field.
      */
     public ZipEightByteInteger getCompressedSize() {
@@ -221,6 +228,13 @@ public class Zip64ExtendedInformationExt
     }
 
     /**
+     * The uncompressed size stored in this extra field.
+     */
+    public void setCompressedSize(ZipEightByteInteger compressedSize) {
+        this.compressedSize = compressedSize;
+    }
+
+    /**
      * The relative header offset stored in this extra field.
      */
     public ZipEightByteInteger getRelativeHeaderOffset() {
@@ -228,14 +242,36 @@ public class Zip64ExtendedInformationExt
     }
 
     /**
+     * The relative header offset stored in this extra field.
+     */
+    public void setRelativeHeaderOffset(ZipEightByteInteger rho) {
+        relativeHeaderOffset = rho;
+    }
+
+    /**
      * The disk start number stored in this extra field.
      */
     public ZipLong getDiskStartNumber() {
         return diskStart;
     }
 
-    private void addSizes(byte[] data) {
-        System.arraycopy(size.getBytes(), 0, data, 0, DWORD);
-        System.arraycopy(compressedSize.getBytes(), 0, data, DWORD, DWORD);
+    /**
+     * The disk start number stored in this extra field.
+     */
+    public void setDiskStartNumber(ZipLong ds) {
+        diskStart = ds;
+    }
+
+    private int addSizes(byte[] data) {
+        int off = 0;
+        if (size != null) {
+            System.arraycopy(size.getBytes(), 0, data, 0, DWORD);
+            off += DWORD;
+        }
+        if (compressedSize != null) {
+            System.arraycopy(compressedSize.getBytes(), 0, data, off, DWORD);
+            off += DWORD;
+        }
+        return off;
     }
 }
\ No newline at end of file

Modified: 
commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
URL: 
http://svn.apache.org/viewvc/commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java?rev=1152242&r1=1152241&r2=1152242&view=diff
==============================================================================
--- 
commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
 (original)
+++ 
commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
 Fri Jul 29 14:41:25 2011
@@ -702,7 +702,8 @@ public class ZipArchiveOutputStream exte
 
         writeVersionNeededToExtractAndGeneralPurposeBits(zipMethod,
                                                          !encodable
-                                                         && fallbackToUTF8);
+                                                         && fallbackToUTF8,
+                                                         false);
         written += WORD;
 
         // compression method
@@ -786,9 +787,38 @@ public class ZipArchiveOutputStream exte
 
         final int zipMethod = ze.getMethod();
         final boolean encodable = zipEncoding.canEncode(ze.getName());
+
+        final long lfhOffset = offsets.get(ze).longValue();
+        final boolean needsZip64Extra = ze.getCompressedSize() >= ZIP64_MAGIC
+            || ze.getSize() >= ZIP64_MAGIC
+            || lfhOffset >= ZIP64_MAGIC;
+
+        if (needsZip64Extra) {
+            hasUsedZip64 = true;
+            Zip64ExtendedInformationExtraField z64 =  
+                (Zip64ExtendedInformationExtraField)
+                ze.getExtraField(Zip64ExtendedInformationExtraField
+                                 .HEADER_ID);
+            if (z64 == null) {
+                z64 = new Zip64ExtendedInformationExtraField();
+                ze.addExtraField(z64);
+            }
+            if (ze.getCompressedSize() >= ZIP64_MAGIC) {
+                z64.setCompressedSize(new 
ZipEightByteInteger(ze.getCompressedSize()));
+            }
+            if (ze.getSize() >= ZIP64_MAGIC) {
+                z64.setSize(new ZipEightByteInteger(ze.getSize()));
+            }
+            if (lfhOffset >= ZIP64_MAGIC) {
+                z64.setRelativeHeaderOffset(new 
ZipEightByteInteger(lfhOffset));
+            }
+            ze.setExtra();
+        }
+
         writeVersionNeededToExtractAndGeneralPurposeBits(zipMethod,
                                                          !encodable
-                                                         && fallbackToUTF8);
+                                                         && fallbackToUTF8,
+                                                         needsZip64Extra);
         written += WORD;
 
         // compression method
@@ -803,8 +833,8 @@ public class ZipArchiveOutputStream exte
         // compressed length
         // uncompressed length
         writeOut(ZipLong.getBytes(ze.getCrc()));
-        writeOut(ZipLong.getBytes(ze.getCompressedSize()));
-        writeOut(ZipLong.getBytes(ze.getSize()));
+        writeOut(ZipLong.getBytes(Math.min(ze.getCompressedSize(), 
ZIP64_MAGIC)));
+        writeOut(ZipLong.getBytes(Math.min(ze.getSize(), ZIP64_MAGIC)));
         // CheckStyle:MagicNumber OFF
         written += 12;
         // CheckStyle:MagicNumber ON
@@ -852,7 +882,7 @@ public class ZipArchiveOutputStream exte
         written += WORD;
 
         // relative offset of LFH
-        writeOut(ZipLong.getBytes(offsets.get(ze).longValue()));
+        writeOut(ZipLong.getBytes(Math.min(lfhOffset, ZIP64_MAGIC)));
         written += WORD;
 
         // file name
@@ -996,7 +1026,9 @@ public class ZipArchiveOutputStream exte
     private void writeVersionNeededToExtractAndGeneralPurposeBits(final int
                                                                   zipMethod,
                                                                   final boolean
-                                                                  utfFallback)
+                                                                  utfFallback,
+                                                                  final boolean
+                                                                  zip64)
         throws IOException {
 
         // CheckStyle:MagicNumber OFF
@@ -1006,9 +1038,12 @@ public class ZipArchiveOutputStream exte
         if (zipMethod == DEFLATED && raf == null) {
             // requires version 2 as we are going to store length info
             // in the data descriptor
-            versionNeededToExtract =  20;
+            versionNeededToExtract = DEFLATE_MIN_VERSION;
             b.useDataDescriptor(true);
         }
+        if (zip64) {
+            versionNeededToExtract = ZIP64_MIN_VERSION;
+        }
         // CheckStyle:MagicNumber ON
 
         // version needed to extract


Reply via email to