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