Return-Path:
Delivered-To: apmail-commons-commits-archive@minotaur.apache.org
Received: (qmail 35614 invoked from network); 16 Feb 2010 13:59:32 -0000
Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3)
by minotaur.apache.org with SMTP; 16 Feb 2010 13:59:32 -0000
Received: (qmail 44529 invoked by uid 500); 16 Feb 2010 13:59:32 -0000
Delivered-To: apmail-commons-commits-archive@commons.apache.org
Received: (qmail 44438 invoked by uid 500); 16 Feb 2010 13:59:31 -0000
Mailing-List: contact commits-help@commons.apache.org; run by ezmlm
Precedence: bulk
List-Help:
List-Unsubscribe:
List-Post:
List-Id:
Reply-To: dev@commons.apache.org
Delivered-To: mailing list commits@commons.apache.org
Received: (qmail 44429 invoked by uid 99); 16 Feb 2010 13:59:31 -0000
Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136)
by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 16 Feb 2010 13:59:31 +0000
X-ASF-Spam-Status: No, hits=-2000.0 required=10.0
tests=ALL_TRUSTED
X-Spam-Check-By: apache.org
Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4)
by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 16 Feb 2010 13:59:24 +0000
Received: by eris.apache.org (Postfix, from userid 65534)
id E39272388A2C; Tue, 16 Feb 2010 13:59:03 +0000 (UTC)
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: svn commit: r910519 - in /commons/proper/compress/trunk/src:
changes/changes.xml
main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java
site/xdoc/zip.xml
Date: Tue, 16 Feb 2010 13:59:03 -0000
To: commits@commons.apache.org
From: bodewig@apache.org
X-Mailer: svnmailer-1.0.8
Message-Id: <20100216135903.E39272388A2C@eris.apache.org>
Author: bodewig
Date: Tue Feb 16 13:59:03 2010
New Revision: 910519
URL: http://svn.apache.org/viewvc?rev=910519&view=rev
Log:
Allow extra fields to violate the recommended structure. COMPRESS-73
Modified:
commons/proper/compress/trunk/src/changes/changes.xml
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java
commons/proper/compress/trunk/src/site/xdoc/zip.xml
Modified: commons/proper/compress/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/changes/changes.xml?rev=910519&r1=910518&r2=910519&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/changes/changes.xml (original)
+++ commons/proper/compress/trunk/src/changes/changes.xml Tue Feb 16 13:59:03 2010
@@ -23,6 +23,10 @@
+
+ ZipArchiveEntry, ZipFile and ZipArchiveInputStream are now
+ more lenient when parsing extra fields.
+
Improved exception message if the extra field data in ZIP
archives cannot be parsed.
Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java?rev=910519&r1=910518&r2=910519&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java (original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java Tue Feb 16 13:59:03 2010
@@ -18,9 +18,11 @@
package org.apache.commons.compress.archivers.zip;
import java.io.File;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashMap;
+import java.util.List;
import java.util.zip.ZipException;
import org.apache.commons.compress.archivers.ArchiveEntry;
@@ -28,6 +30,22 @@
* Extension that adds better handling of extra fields and provides
* access to the internal and external file attributes.
*
+ * The extra data is expected to follow the recommendation of
+ * {@link http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+ * APPNOTE.txt}:
+ *
+ * - the extra byte array consists of a sequence of extra fields
+ * - each extra fields starts by a two byte header id followed by
+ * a two byte sequence holding the length of the remainder of
+ * data.
+ *
+ *
+ * Any extra data that cannot be parsed by the rules above will be
+ * consumed as "unparseable" extra data and treated differently by the
+ * methods of this class. Versions prior to Apache Commons Compress
+ * 1.1 would have thrown an exception if any attempt was made to read
+ * or write extra data not conforming to the recommendation.
+ *
* @NotThreadSafe
*/
public class ZipArchiveEntry extends java.util.zip.ZipEntry
@@ -54,6 +72,7 @@
private int platform = PLATFORM_FAT;
private long externalAttributes = 0;
private LinkedHashMap/**/ extraFields = null;
+ private UnparseableExtraFieldData unparseableExtra = null;
private String name = null;
/**
@@ -75,7 +94,9 @@
setName(entry.getName());
byte[] extra = entry.getExtra();
if (extra != null) {
- setExtraFields(ExtraFieldUtils.parse(extra));
+ setExtraFields(ExtraFieldUtils.parse(extra, true,
+ ExtraFieldUtils
+ .UnparseableExtraField.READ));
} else {
// initializes extra data to an empty byte array
setExtra();
@@ -92,7 +113,7 @@
this((java.util.zip.ZipEntry) entry);
setInternalAttributes(entry.getInternalAttributes());
setExternalAttributes(entry.getExternalAttributes());
- setExtraFields(entry.getExtraFields());
+ setExtraFields(entry.getExtraFields(true));
}
/**
@@ -118,10 +139,9 @@
public Object clone() {
ZipArchiveEntry e = (ZipArchiveEntry) super.clone();
- e.extraFields = extraFields != null ? (LinkedHashMap) extraFields.clone() : null;
e.setInternalAttributes(getInternalAttributes());
e.setExternalAttributes(getExternalAttributes());
- e.setExtraFields(getExtraFields());
+ e.setExtraFields(getExtraFields(true));
return e;
}
@@ -246,25 +266,45 @@
public void setExtraFields(ZipExtraField[] fields) {
extraFields = new LinkedHashMap();
for (int i = 0; i < fields.length; i++) {
+ if (fields[i] instanceof UnparseableExtraFieldData) {
+ unparseableExtra = (UnparseableExtraFieldData) fields[i];
+ } else {
extraFields.put(fields[i].getHeaderId(), fields[i]);
+ }
}
setExtra();
}
/**
- * Retrieves extra fields.
+ * Retrieves all extra fields that have been parsed successfully.
* @return an array of the extra fields
*/
public ZipExtraField[] getExtraFields() {
+ return getExtraFields(false);
+ }
+
+ /**
+ * Retrieves extra fields.
+ * @param includeUnparseable whether to also return unparseable
+ * extra fields as {@link UnparseableExtraFieldData} if such data
+ * exists.
+ * @return an array of the extra fields
+ */
+ public ZipExtraField[] getExtraFields(boolean includeUnparseable) {
if (extraFields == null) {
- return new ZipExtraField[0];
+ return !includeUnparseable || unparseableExtra == null
+ ? new ZipExtraField[0]
+ : new ZipExtraField[] { unparseableExtra };
}
- ZipExtraField[] result = new ZipExtraField[extraFields.size()];
- return (ZipExtraField[]) extraFields.values().toArray(result);
+ List result = new ArrayList(extraFields.values());
+ if (includeUnparseable && unparseableExtra != null) {
+ result.add(unparseableExtra);
+ }
+ return (ZipExtraField[]) result.toArray(new ZipExtraField[0]);
}
/**
- * Adds an extra fields - replacing an already present extra field
+ * Adds an extra field - replacing an already present extra field
* of the same type.
*
* If no extra field of the same type exists, the field will be
@@ -272,21 +312,28 @@
* @param ze an extra field
*/
public void addExtraField(ZipExtraField ze) {
+ if (ze instanceof UnparseableExtraFieldData) {
+ unparseableExtra = (UnparseableExtraFieldData) ze;
+ } else {
if (extraFields == null) {
extraFields = new LinkedHashMap();
}
extraFields.put(ze.getHeaderId(), ze);
+ }
setExtra();
}
/**
- * Adds an extra fields - replacing an already present extra field
+ * Adds an extra field - replacing an already present extra field
* of the same type.
*
*
The new extra field will be the first one.
* @param ze an extra field
*/
public void addAsFirstExtraField(ZipExtraField ze) {
+ if (ze instanceof UnparseableExtraFieldData) {
+ unparseableExtra = (UnparseableExtraFieldData) ze;
+ } else {
LinkedHashMap copy = extraFields;
extraFields = new LinkedHashMap();
extraFields.put(ze.getHeaderId(), ze);
@@ -294,11 +341,12 @@
copy.remove(ze.getHeaderId());
extraFields.putAll(copy);
}
+ }
setExtra();
}
/**
- * Remove an extra fields.
+ * Remove an extra field.
* @param type the type of extra field to remove
*/
public void removeExtraField(ZipShort type) {
@@ -312,6 +360,17 @@
}
/**
+ * Removes unparseable extra field data.
+ */
+ public void removeUnparseableExtraFieldData() {
+ if (unparseableExtra == null) {
+ throw new java.util.NoSuchElementException();
+ }
+ unparseableExtra = null;
+ setExtra();
+ }
+
+ /**
* Looks up an extra field by its header id.
*
* @return null if no such field exists.
@@ -324,16 +383,30 @@
}
/**
- * Throws an Exception if extra data cannot be parsed into extra fields.
+ * Looks up extra field data that couldn't be parsed correctly.
+ *
+ * @return null if no such field exists.
+ */
+ public UnparseableExtraFieldData getUnparseableExtraFieldData() {
+ return unparseableExtra;
+ }
+
+ /**
+ * Parses the given bytes as extra field data and consumes any
+ * unparseable data as an {@link UnparseableExtraFieldData}
+ * instance.
* @param extra an array of bytes to be parsed into extra fields
* @throws RuntimeException if the bytes cannot be parsed
* @throws RuntimeException on error
*/
public void setExtra(byte[] extra) throws RuntimeException {
try {
- ZipExtraField[] local = ExtraFieldUtils.parse(extra, true);
+ ZipExtraField[] local =
+ ExtraFieldUtils.parse(extra, true,
+ ExtraFieldUtils.UnparseableExtraField.READ);
mergeExtraFields(local, true);
} catch (ZipException e) {
+ // actually this is not be possible as of Commons Compress 1.1
throw new RuntimeException("Error parsing extra fields for entry: "
+ getName() + " - " + e.getMessage(), e);
}
@@ -346,7 +419,7 @@
* modify super's data directly.
*/
protected void setExtra() {
- super.setExtra(ExtraFieldUtils.mergeLocalFileDataData(getExtraFields()));
+ super.setExtra(ExtraFieldUtils.mergeLocalFileDataData(getExtraFields(true)));
}
/**
@@ -354,7 +427,9 @@
*/
public void setCentralDirectoryExtra(byte[] b) {
try {
- ZipExtraField[] central = ExtraFieldUtils.parse(b, false);
+ ZipExtraField[] central =
+ ExtraFieldUtils.parse(b, false,
+ ExtraFieldUtils.UnparseableExtraField.READ);
mergeExtraFields(central, false);
} catch (ZipException e) {
throw new RuntimeException(e.getMessage(), e);
@@ -375,7 +450,7 @@
* @return the central directory extra data
*/
public byte[] getCentralDirectoryExtra() {
- return ExtraFieldUtils.mergeCentralDirectoryData(getExtraFields());
+ return ExtraFieldUtils.mergeCentralDirectoryData(getExtraFields(true));
}
/**
@@ -429,7 +504,12 @@
setExtraFields(f);
} else {
for (int i = 0; i < f.length; i++) {
- ZipExtraField existing = getExtraField(f[i].getHeaderId());
+ ZipExtraField existing;
+ if (f[i] instanceof UnparseableExtraFieldData) {
+ existing = unparseableExtra;
+ } else {
+ existing = getExtraField(f[i].getHeaderId());
+ }
if (existing == null) {
addExtraField(f[i]);
} else {
Modified: commons/proper/compress/trunk/src/site/xdoc/zip.xml
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/site/xdoc/zip.xml?rev=910519&r1=910518&r2=910519&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/site/xdoc/zip.xml (original)
+++ commons/proper/compress/trunk/src/site/xdoc/zip.xml Tue Feb 16 13:59:03 2010
@@ -99,6 +99,13 @@
the package, any other extra field will be stored
as UnrecognizedExtraField
.
+ Prior to version 1.1 of this library trying to read an
+ archive with extra fields that didn't follow the recommended
+ structure for those fields would cause Compress to throw an
+ exception. Starting with version 1.1 these extra fields
+ will now be read
+ as UnparseableExtraFieldData
.
+