Author: bodewig
Date: Tue Feb 16 14:41:11 2010
New Revision: 910537
URL: http://svn.apache.org/viewvc?rev=910537&view=rev
Log:
accept a wider range of existing zip archives by being more lenient when
parsing extra fields
Added:
ant/core/trunk/src/main/org/apache/tools/zip/UnparseableExtraFieldData.java
(contents, props changed)
- copied, changed from r910483,
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/UnparseableExtraFieldData.java
ant/core/trunk/src/main/org/apache/tools/zip/ZipUtil.java (contents,
props changed)
- copied, changed from r910483,
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipUtil.java
Removed:
ant/core/trunk/src/tests/antunit/taskdefs/zip/Bugzilla-46559.zip
Modified:
ant/core/trunk/WHATSNEW
ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Zip.java
ant/core/trunk/src/main/org/apache/tools/ant/types/resources/ZipResource.java
ant/core/trunk/src/main/org/apache/tools/zip/ExtraFieldUtils.java
(contents, props changed)
ant/core/trunk/src/main/org/apache/tools/zip/UnrecognizedExtraField.java
(contents, props changed)
ant/core/trunk/src/main/org/apache/tools/zip/ZipEntry.java (contents,
props changed)
ant/core/trunk/src/tests/antunit/taskdefs/unzip-test.xml
ant/core/trunk/src/tests/junit/org/apache/tools/zip/ExtraFieldUtilsTest.java
(contents, props changed)
Modified: ant/core/trunk/WHATSNEW
URL:
http://svn.apache.org/viewvc/ant/core/trunk/WHATSNEW?rev=910537&r1=910536&r2=910537&view=diff
==============================================================================
--- ant/core/trunk/WHATSNEW (original)
+++ ant/core/trunk/WHATSNEW Tue Feb 16 14:41:11 2010
@@ -31,6 +31,9 @@
* Project provides new get methods that return copies instead of the
live maps of task and type definitions, references and targets.
+ * Ant is now more lenient with ZIP extra fields and will be able to
+ read archives that it failed to read in earlier versions.
+
Changes from Ant 1.8.0RC1 TO Ant 1.8.0
======================================
Modified: ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Zip.java
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Zip.java?rev=910537&r1=910536&r2=910537&view=diff
==============================================================================
--- ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Zip.java (original)
+++ ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Zip.java Tue Feb 16
14:41:11 2010
@@ -1026,7 +1026,7 @@
try {
is = zf.getInputStream(ze);
zipFile(is, zOut, prefix + name, ze.getTime(),
- fromArchive, mode, ze.getExtraFields());
+ fromArchive, mode, ze.getExtraFields(true));
} finally {
doCompress = oldCompress;
FileUtils.close(is);
Modified:
ant/core/trunk/src/main/org/apache/tools/ant/types/resources/ZipResource.java
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/types/resources/ZipResource.java?rev=910537&r1=910536&r2=910537&view=diff
==============================================================================
---
ant/core/trunk/src/main/org/apache/tools/ant/types/resources/ZipResource.java
(original)
+++
ant/core/trunk/src/main/org/apache/tools/ant/types/resources/ZipResource.java
Tue Feb 16 14:41:11 2010
@@ -219,7 +219,7 @@
setDirectory(e.isDirectory());
setSize(e.getSize());
setMode(e.getUnixMode());
- extras = e.getExtraFields();
+ extras = e.getExtraFields(true);
method = e.getMethod();
}
Modified: ant/core/trunk/src/main/org/apache/tools/zip/ExtraFieldUtils.java
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/zip/ExtraFieldUtils.java?rev=910537&r1=910536&r2=910537&view=diff
==============================================================================
--- ant/core/trunk/src/main/org/apache/tools/zip/ExtraFieldUtils.java (original)
+++ ant/core/trunk/src/main/org/apache/tools/zip/ExtraFieldUtils.java Tue Feb
16 14:41:11 2010
@@ -92,18 +92,19 @@
/**
* Split the array into ExtraFields and populate them with the
- * given data as local file data.
+ * given data as local file data, throwing an exception if the
+ * data cannot be parsed.
* @param data an array of bytes as it appears in local file data
* @return an array of ExtraFields
* @throws ZipException on error
*/
public static ZipExtraField[] parse(byte[] data) throws ZipException {
- return parse(data, true);
+ return parse(data, true, UnparseableExtraField.THROW);
}
/**
* Split the array into ExtraFields and populate them with the
- * given data.
+ * given data, throwing an exception if the data cannot be parsed.
* @param data an array of bytes
* @param local whether data originates from the local file data
* or the central directory
@@ -113,14 +114,60 @@
*/
public static ZipExtraField[] parse(byte[] data, boolean local)
throws ZipException {
+ return parse(data, local, UnparseableExtraField.THROW);
+ }
+
+ /**
+ * Split the array into ExtraFields and populate them with the
+ * given data.
+ * @param data an array of bytes
+ * @param local whether data originates from the local file data
+ * or the central directory
+ * @param onUnparseableData what to do if the extra field data
+ * cannot be parsed.
+ * @return an array of ExtraFields
+ * @throws ZipException on error
+ * @since Ant 1.8.1
+ */
+ public static ZipExtraField[] parse(byte[] data, boolean local,
+ UnparseableExtraField
onUnparseableData)
+ throws ZipException {
List v = new ArrayList();
int start = 0;
+ LOOP:
while (start <= data.length - WORD) {
ZipShort headerId = new ZipShort(data, start);
int length = (new ZipShort(data, start + 2)).getValue();
if (start + WORD + length > data.length) {
- throw new ZipException("data starting at " + start
- + " is in unknown format");
+ switch(onUnparseableData.getKey()) {
+ case UnparseableExtraField.THROW_KEY:
+ throw new ZipException("bad extra field starting at "
+ + start + ". Block length of "
+ + length + " bytes exceeds
remaining"
+ + " data of "
+ + (data.length - start - WORD)
+ + " bytes.");
+ case UnparseableExtraField.READ_KEY:
+ UnparseableExtraFieldData field =
+ new UnparseableExtraFieldData();
+ if (local) {
+ field.parseFromLocalFileData(data, start,
+ data.length - start);
+ } else {
+ field.parseFromCentralDirectoryData(data, start,
+ data.length -
start);
+ }
+ v.add(field);
+ /*FALLTHROUGH*/
+ case UnparseableExtraField.SKIP_KEY:
+ // since we cannot parse the data we must assume
+ // the extra field consumes the whole rest of the
+ // available data
+ break LOOP;
+ default:
+ throw new ZipException("unknown UnparseableExtraField key:
"
+ + onUnparseableData.getKey());
+ }
}
try {
ZipExtraField ze = createExtraField(headerId);
@@ -152,13 +199,19 @@
* @since 1.1
*/
public static byte[] mergeLocalFileDataData(ZipExtraField[] data) {
- int sum = WORD * data.length;
+ final boolean lastIsUnparseableHolder = data.length > 0
+ && data[data.length - 1] instanceof UnparseableExtraFieldData;
+ int regularExtraFieldCount =
+ lastIsUnparseableHolder ? data.length - 1 : data.length;
+
+ int sum = WORD * regularExtraFieldCount;
for (int i = 0; i < data.length; i++) {
sum += data[i].getLocalFileDataLength().getValue();
}
+
byte[] result = new byte[sum];
int start = 0;
- for (int i = 0; i < data.length; i++) {
+ for (int i = 0; i < regularExtraFieldCount; i++) {
System.arraycopy(data[i].getHeaderId().getBytes(),
0, result, start, 2);
System.arraycopy(data[i].getLocalFileDataLength().getBytes(),
@@ -167,6 +220,10 @@
System.arraycopy(local, 0, result, start + WORD, local.length);
start += (local.length + WORD);
}
+ if (lastIsUnparseableHolder) {
+ byte[] local = data[data.length - 1].getLocalFileDataData();
+ System.arraycopy(local, 0, result, start, local.length);
+ }
return result;
}
@@ -177,13 +234,18 @@
* @since 1.1
*/
public static byte[] mergeCentralDirectoryData(ZipExtraField[] data) {
- int sum = WORD * data.length;
+ final boolean lastIsUnparseableHolder = data.length > 0
+ && data[data.length - 1] instanceof UnparseableExtraFieldData;
+ int regularExtraFieldCount =
+ lastIsUnparseableHolder ? data.length - 1 : data.length;
+
+ int sum = WORD * regularExtraFieldCount;
for (int i = 0; i < data.length; i++) {
sum += data[i].getCentralDirectoryLength().getValue();
}
byte[] result = new byte[sum];
int start = 0;
- for (int i = 0; i < data.length; i++) {
+ for (int i = 0; i < regularExtraFieldCount; i++) {
System.arraycopy(data[i].getHeaderId().getBytes(),
0, result, start, 2);
System.arraycopy(data[i].getCentralDirectoryLength().getBytes(),
@@ -192,6 +254,60 @@
System.arraycopy(local, 0, result, start + WORD, local.length);
start += (local.length + WORD);
}
+ if (lastIsUnparseableHolder) {
+ byte[] local = data[data.length - 1].getCentralDirectoryData();
+ System.arraycopy(local, 0, result, start, local.length);
+ }
return result;
}
+
+ /**
+ * "enum" for the possible actions to take if the extra field
+ * cannot be parsed.
+ */
+ public static final class UnparseableExtraField {
+ /**
+ * Key for "throw an exception" action.
+ */
+ public static final int THROW_KEY = 0;
+ /**
+ * Key for "skip" action.
+ */
+ public static final int SKIP_KEY = 1;
+ /**
+ * Key for "read" action.
+ */
+ public static final int READ_KEY = 2;
+
+ /**
+ * Throw an exception if field cannot be parsed.
+ */
+ public static final UnparseableExtraField THROW
+ = new UnparseableExtraField(THROW_KEY);
+
+ /**
+ * Skip the extra field entirely and don't make its data
+ * available - effectively removing the extra field data.
+ */
+ public static final UnparseableExtraField SKIP
+ = new UnparseableExtraField(SKIP_KEY);
+
+ /**
+ * Read the extra field data into an instance of {...@link
+ * UnparseableExtraFieldData UnparseableExtraFieldData}.
+ */
+ public static final UnparseableExtraField READ
+ = new UnparseableExtraField(READ_KEY);
+
+ private final int key;
+
+ private UnparseableExtraField(int k) {
+ key = k;
+ }
+
+ /**
+ * Key of the action to take.
+ */
+ public int getKey() { return key; }
+ }
}
Propchange: ant/core/trunk/src/main/org/apache/tools/zip/ExtraFieldUtils.java
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Feb 16 14:41:11 2010
@@ -1 +1,2 @@
+/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java:910483-910521
/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java:745528,746933,748133,749524,749603,749855,749859
Copied:
ant/core/trunk/src/main/org/apache/tools/zip/UnparseableExtraFieldData.java
(from r910483,
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/UnparseableExtraFieldData.java)
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/zip/UnparseableExtraFieldData.java?p2=ant/core/trunk/src/main/org/apache/tools/zip/UnparseableExtraFieldData.java&p1=commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/UnparseableExtraFieldData.java&r1=910483&r2=910537&rev=910537&view=diff
==============================================================================
---
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/UnparseableExtraFieldData.java
(original)
+++ ant/core/trunk/src/main/org/apache/tools/zip/UnparseableExtraFieldData.java
Tue Feb 16 14:41:11 2010
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.commons.compress.archivers.zip;
+package org.apache.tools.zip;
/**
* Wrapper for extra field data that doesn't conform to the recommended format
of header-tag + size + data.
@@ -25,9 +25,11 @@
* {...@link http://www.pkware.com/documents/casestudies/APPNOTE.TXT
* APPNOTE.TXT}. Since it isn't used anywhere except to satisfy the
* ZipExtraField contract it shouldn't matter anyway.</p>
- * @NotThreadSafe
+ * @since Ant 1.8.1
*/
-public final class UnparseableExtraFieldData implements ZipExtraField {
+public final class UnparseableExtraFieldData
+ implements CentralDirectoryParsingZipExtraField {
+
private static final ZipShort HEADER_ID = new ZipShort(0xACC1);
private byte[] localFileData;
Propchange:
ant/core/trunk/src/main/org/apache/tools/zip/UnparseableExtraFieldData.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
ant/core/trunk/src/main/org/apache/tools/zip/UnparseableExtraFieldData.java
------------------------------------------------------------------------------
svn:mergeinfo =
Modified:
ant/core/trunk/src/main/org/apache/tools/zip/UnrecognizedExtraField.java
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/zip/UnrecognizedExtraField.java?rev=910537&r1=910536&r2=910537&view=diff
==============================================================================
--- ant/core/trunk/src/main/org/apache/tools/zip/UnrecognizedExtraField.java
(original)
+++ ant/core/trunk/src/main/org/apache/tools/zip/UnrecognizedExtraField.java
Tue Feb 16 14:41:11 2010
@@ -66,7 +66,7 @@
* @param data the field data to use
*/
public void setLocalFileDataData(byte[] data) {
- localData = copy(data);
+ localData = ZipUtil.copy(data);
}
/**
@@ -82,7 +82,7 @@
* @return the local data
*/
public byte[] getLocalFileDataData() {
- return copy(localData);
+ return ZipUtil.copy(localData);
}
/**
@@ -98,7 +98,7 @@
* @param data the data to use
*/
public void setCentralDirectoryData(byte[] data) {
- centralData = copy(data);
+ centralData = ZipUtil.copy(data);
}
/**
@@ -119,7 +119,7 @@
*/
public byte[] getCentralDirectoryData() {
if (centralData != null) {
- return copy(centralData);
+ return ZipUtil.copy(centralData);
}
return getLocalFileDataData();
}
@@ -151,12 +151,4 @@
}
}
- private static byte[] copy(byte[] from) {
- if (from != null) {
- byte[] to = new byte[from.length];
- System.arraycopy(from, 0, to, 0, to.length);
- return to;
- }
- return null;
- }
}
Propchange:
ant/core/trunk/src/main/org/apache/tools/zip/UnrecognizedExtraField.java
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Feb 16 14:41:11 2010
@@ -1 +1,2 @@
+/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/UnrecognizedExtraField.java:910483-910521
/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/UnrecognizedExtraField.java:746933,748133,749603,749855,749859
Modified: ant/core/trunk/src/main/org/apache/tools/zip/ZipEntry.java
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/zip/ZipEntry.java?rev=910537&r1=910536&r2=910537&view=diff
==============================================================================
--- ant/core/trunk/src/main/org/apache/tools/zip/ZipEntry.java (original)
+++ ant/core/trunk/src/main/org/apache/tools/zip/ZipEntry.java Tue Feb 16
14:41:11 2010
@@ -18,13 +18,32 @@
package org.apache.tools.zip;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.LinkedHashMap;
+import java.util.List;
import java.util.zip.ZipException;
/**
* Extension that adds better handling of extra fields and provides
* access to the internal and external file attributes.
*
+ * <p>The extra data is expected to follow the recommendation of
+ * {...@link http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+ * APPNOTE.txt}:</p>
+ * <ul>
+ * <li>the extra byte array consists of a sequence of extra fields</li>
+ * <li>each extra fields starts by a two byte header id followed by
+ * a two byte sequence holding the length of the remainder of
+ * data.</li>
+ * </ul>
+ *
+ * <p>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.</p>
+ *
*/
public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
@@ -37,6 +56,7 @@
private int platform = PLATFORM_FAT;
private long externalAttributes = 0;
private LinkedHashMap/*<ZipShort, ZipExtraField>*/ extraFields = null;
+ private UnparseableExtraFieldData unparseableExtra = null;
private String name = null;
/**
@@ -58,7 +78,9 @@
super(entry);
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();
@@ -75,7 +97,7 @@
this((java.util.zip.ZipEntry) entry);
setInternalAttributes(entry.getInternalAttributes());
setExternalAttributes(entry.getExternalAttributes());
- setExtraFields(entry.getExtraFields());
+ setExtraFields(entry.getExtraFields(true));
}
/**
@@ -93,10 +115,9 @@
public Object clone() {
ZipEntry e = (ZipEntry) 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;
}
@@ -194,26 +215,46 @@
public void setExtraFields(ZipExtraField[] fields) {
extraFields = new LinkedHashMap();
for (int i = 0; i < fields.length; i++) {
- extraFields.put(fields[i].getHeaderId(), fields[i]);
+ if (fields[i] instanceof UnparseableExtraFieldData) {
+ unparseableExtra = (UnparseableExtraFieldData) fields[i];
+ } else {
+ extraFields.put(fields[i].getHeaderId(), fields[i]);
+ }
}
setExtra();
}
/**
+ * 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
* @since 1.1
*/
- public ZipExtraField[] getExtraFields() {
+ public ZipExtraField[] getExtraFields(boolean includeUnparseable) {
if (extraFields == null) {
- return new ZipExtraField[0];
+ return !includeUnparseable || unparseableExtra == null
+ ? new ZipExtraField[0]
+ : new ZipExtraField[] { unparseableExtra };
+ }
+ List result = new ArrayList(extraFields.values());
+ if (includeUnparseable && unparseableExtra != null) {
+ result.add(unparseableExtra);
}
- ZipExtraField[] result = new ZipExtraField[extraFields.size()];
- return (ZipExtraField[]) extraFields.values().toArray(result);
+ 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.
*
* <p>If no extra field of the same type exists, the field will be
@@ -222,15 +263,19 @@
* @since 1.1
*/
public void addExtraField(ZipExtraField ze) {
- if (extraFields == null) {
- extraFields = new LinkedHashMap();
+ if (ze instanceof UnparseableExtraFieldData) {
+ unparseableExtra = (UnparseableExtraFieldData) ze;
+ } else {
+ if (extraFields == null) {
+ extraFields = new LinkedHashMap();
+ }
+ extraFields.put(ze.getHeaderId(), ze);
}
- 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.
*
* <p>The new extra field will be the first one.</p>
@@ -238,18 +283,22 @@
* @since 1.1
*/
public void addAsFirstExtraField(ZipExtraField ze) {
- LinkedHashMap copy = extraFields;
- extraFields = new LinkedHashMap();
- extraFields.put(ze.getHeaderId(), ze);
- if (copy != null) {
- copy.remove(ze.getHeaderId());
- extraFields.putAll(copy);
+ if (ze instanceof UnparseableExtraFieldData) {
+ unparseableExtra = (UnparseableExtraFieldData) ze;
+ } else {
+ LinkedHashMap copy = extraFields;
+ extraFields = new LinkedHashMap();
+ extraFields.put(ze.getHeaderId(), ze);
+ if (copy != null) {
+ 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
* @since 1.1
*/
@@ -264,6 +313,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.
@@ -276,7 +336,18 @@
}
/**
- * 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
* @since 1.1
@@ -284,10 +355,14 @@
*/
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 (Exception e) {
- throw new RuntimeException(e.getMessage(), e);
+ // actually this is not be possible as of Ant 1.8.1
+ throw new RuntimeException("Error parsing extra fields for entry: "
+ + getName() + " - " + e.getMessage(),
e);
}
}
@@ -300,7 +375,7 @@
* @since 1.1
*/
protected void setExtra() {
-
super.setExtra(ExtraFieldUtils.mergeLocalFileDataData(getExtraFields()));
+
super.setExtra(ExtraFieldUtils.mergeLocalFileDataData(getExtraFields(true)));
}
/**
@@ -308,7 +383,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 (Exception e) {
throw new RuntimeException(e.getMessage(), e);
@@ -331,7 +408,7 @@
* @since 1.1
*/
public byte[] getCentralDirectoryExtra() {
- return ExtraFieldUtils.mergeCentralDirectoryData(getExtraFields());
+ return ExtraFieldUtils.mergeCentralDirectoryData(getExtraFields(true));
}
/**
@@ -413,7 +490,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 {
Propchange: ant/core/trunk/src/main/org/apache/tools/zip/ZipEntry.java
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Feb 16 14:41:11 2010
@@ -1,2 +1,3 @@
+/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java:910483-910521
/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java:747850,749603
/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipEntry.java:746933,748133,749524,749855,749859
Copied: ant/core/trunk/src/main/org/apache/tools/zip/ZipUtil.java (from
r910483,
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipUtil.java)
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/zip/ZipUtil.java?p2=ant/core/trunk/src/main/org/apache/tools/zip/ZipUtil.java&p1=commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipUtil.java&r1=910483&r2=910537&rev=910537&view=diff
==============================================================================
---
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipUtil.java
(original)
+++ ant/core/trunk/src/main/org/apache/tools/zip/ZipUtil.java Tue Feb 16
14:41:11 2010
@@ -15,159 +15,14 @@
* limitations under the License.
*
*/
-package org.apache.commons.compress.archivers.zip;
-
-import java.io.IOException;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.zip.CRC32;
+package org.apache.tools.zip;
/**
* Utility class for handling DOS and Java time conversions.
- * @Immutable
+ * @since Ant 1.8.1
*/
public abstract class ZipUtil {
/**
- * Smallest date/time ZIP can handle.
- */
- private static final byte[] DOS_TIME_MIN = ZipLong.getBytes(0x00002100L);
-
- /**
- * Convert a Date object to a DOS date/time field.
- * @param time the <code>Date</code> to convert
- * @return the date as a <code>ZipLong</code>
- */
- public static ZipLong toDosTime(Date time) {
- return new ZipLong(toDosTime(time.getTime()));
- }
-
- /**
- * Convert a Date object to a DOS date/time field.
- *
- * <p>Stolen from InfoZip's <code>fileio.c</code></p>
- * @param t number of milliseconds since the epoch
- * @return the date as a byte array
- */
- public static byte[] toDosTime(long t) {
- Calendar c = Calendar.getInstance();
- c.setTimeInMillis(t);
-
- int year = c.get(Calendar.YEAR);
- if (year < 1980) {
- return (byte[]) DOS_TIME_MIN.clone(); // stop callers from
changing the array
- }
- int month = c.get(Calendar.MONTH) + 1;
- long value = ((year - 1980) << 25)
- | (month << 21)
- | (c.get(Calendar.DAY_OF_MONTH) << 16)
- | (c.get(Calendar.HOUR_OF_DAY) << 11)
- | (c.get(Calendar.MINUTE) << 5)
- | (c.get(Calendar.SECOND) >> 1);
- return ZipLong.getBytes(value);
- }
-
- /**
- * Assumes a negative integer really is a positive integer that
- * has wrapped around and re-creates the original value.
- * @param i the value to treat as unsigned int.
- * @return the unsigned int as a long.
- */
- public static long adjustToLong(int i) {
- if (i < 0) {
- return 2 * ((long) Integer.MAX_VALUE) + 2 + i;
- } else {
- return i;
- }
- }
-
- /**
- * Convert a DOS date/time field to a Date object.
- *
- * @param zipDosTime contains the stored DOS time.
- * @return a Date instance corresponding to the given time.
- */
- public static Date fromDosTime(ZipLong zipDosTime) {
- long dosTime = zipDosTime.getValue();
- return new Date(dosToJavaTime(dosTime));
- }
-
- /**
- * Converts DOS time to Java time (number of milliseconds since
- * epoch).
- */
- public static long dosToJavaTime(long dosTime) {
- Calendar cal = Calendar.getInstance();
- // CheckStyle:MagicNumberCheck OFF - no point
- cal.set(Calendar.YEAR, (int) ((dosTime >> 25) & 0x7f) + 1980);
- cal.set(Calendar.MONTH, (int) ((dosTime >> 21) & 0x0f) - 1);
- cal.set(Calendar.DATE, (int) (dosTime >> 16) & 0x1f);
- cal.set(Calendar.HOUR_OF_DAY, (int) (dosTime >> 11) & 0x1f);
- cal.set(Calendar.MINUTE, (int) (dosTime >> 5) & 0x3f);
- cal.set(Calendar.SECOND, (int) (dosTime << 1) & 0x3e);
- // CheckStyle:MagicNumberCheck ON
- return cal.getTime().getTime();
- }
-
- /**
- * If the entry has Unicode*ExtraFields and the CRCs of the
- * names/comments match those of the extra fields, transfer the
- * known Unicode values from the extra field.
- */
- static void setNameAndCommentFromExtraFields(ZipArchiveEntry ze,
- byte[] originalNameBytes,
- byte[] commentBytes) {
- UnicodePathExtraField name = (UnicodePathExtraField)
- ze.getExtraField(UnicodePathExtraField.UPATH_ID);
- String originalName = ze.getName();
- String newName = getUnicodeStringIfOriginalMatches(name,
- originalNameBytes);
- if (newName != null && !originalName.equals(newName)) {
- ze.setName(newName);
- }
-
- if (commentBytes != null && commentBytes.length > 0) {
- UnicodeCommentExtraField cmt = (UnicodeCommentExtraField)
- ze.getExtraField(UnicodeCommentExtraField.UCOM_ID);
- String newComment =
- getUnicodeStringIfOriginalMatches(cmt, commentBytes);
- if (newComment != null) {
- ze.setComment(newComment);
- }
- }
- }
-
- /**
- * If the stored CRC matches the one of the given name, return the
- * Unicode name of the given field.
- *
- * <p>If the field is null or the CRCs don't match, return null
- * instead.</p>
- */
- private static
- String getUnicodeStringIfOriginalMatches(AbstractUnicodeExtraField f,
- byte[] orig) {
- if (f != null) {
- CRC32 crc32 = new CRC32();
- crc32.update(orig);
- long origCRC32 = crc32.getValue();
-
- if (origCRC32 == f.getNameCRC32()) {
- try {
- return ZipEncodingHelper
- .UTF8_ZIP_ENCODING.decode(f.getUnicodeName());
- } catch (IOException ex) {
- // UTF-8 unsupported? should be impossible the
- // Unicode*ExtraField must contain some bad bytes
-
- // TODO log this anywhere?
- return null;
- }
- }
- }
- return null;
- }
-
- /**
* Create a copy of the given array - or return null if the
* argument is null.
*/
Propchange: ant/core/trunk/src/main/org/apache/tools/zip/ZipUtil.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: ant/core/trunk/src/main/org/apache/tools/zip/ZipUtil.java
------------------------------------------------------------------------------
svn:mergeinfo =
Modified: ant/core/trunk/src/tests/antunit/taskdefs/unzip-test.xml
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/tests/antunit/taskdefs/unzip-test.xml?rev=910537&r1=910536&r2=910537&view=diff
==============================================================================
--- ant/core/trunk/src/tests/antunit/taskdefs/unzip-test.xml (original)
+++ ant/core/trunk/src/tests/antunit/taskdefs/unzip-test.xml Tue Feb 16
14:41:11 2010
@@ -59,7 +59,7 @@
>
<mkdir dir="${input}"/>
<mkdir dir="${output}"/>
- <copy file="zip/Bugzilla-46559.zip" tofile="${input}/test.zip"/>
+ <copy file="broken_cd.zip" tofile="${input}/test.zip"/>
<au:expectfailure>
<unzip src="${input}/test.zip" dest="${output}"/>
</au:expectfailure>
Modified:
ant/core/trunk/src/tests/junit/org/apache/tools/zip/ExtraFieldUtilsTest.java
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/tests/junit/org/apache/tools/zip/ExtraFieldUtilsTest.java?rev=910537&r1=910536&r2=910537&view=diff
==============================================================================
---
ant/core/trunk/src/tests/junit/org/apache/tools/zip/ExtraFieldUtilsTest.java
(original)
+++
ant/core/trunk/src/tests/junit/org/apache/tools/zip/ExtraFieldUtilsTest.java
Tue Feb 16 14:41:11 2010
@@ -18,6 +18,7 @@
package org.apache.tools.zip;
+import java.util.Arrays;
import junit.framework.TestCase;
/**
@@ -78,11 +79,65 @@
fail("data should be invalid");
} catch (Exception e) {
assertEquals("message",
- "data starting at "+(4+aLocal.length)+" is in unknown
format",
+ "bad extra field starting at "+(4 + aLocal.length)
+ + ". Block length of 1 bytes exceeds remaining data
of 0 bytes.",
e.getMessage());
}
}
+ public void testParseWithRead() throws Exception {
+ ZipExtraField[] ze =
+ ExtraFieldUtils.parse(data, true,
+ ExtraFieldUtils.UnparseableExtraField.READ);
+ assertEquals("number of fields", 2, ze.length);
+ assertTrue("type field 1", ze[0] instanceof AsiExtraField);
+ assertEquals("mode field 1", 040755,
+ ((AsiExtraField) ze[0]).getMode());
+ assertTrue("type field 2", ze[1] instanceof UnrecognizedExtraField);
+ assertEquals("data length field 2", 1,
+ ze[1].getLocalFileDataLength().getValue());
+
+ byte[] data2 = new byte[data.length-1];
+ System.arraycopy(data, 0, data2, 0, data2.length);
+ ze = ExtraFieldUtils.parse(data2, true,
+ ExtraFieldUtils.UnparseableExtraField.READ);
+ assertEquals("number of fields", 2, ze.length);
+ assertTrue("type field 1", ze[0] instanceof AsiExtraField);
+ assertEquals("mode field 1", 040755,
+ ((AsiExtraField) ze[0]).getMode());
+ assertTrue("type field 2", ze[1] instanceof UnparseableExtraFieldData);
+ assertEquals("data length field 2", 4,
+ ze[1].getLocalFileDataLength().getValue());
+ byte[] expectedData = new byte[4];
+ for (int i = 0; i < 4; i++) {
+ assertEquals("byte number " + i,
+ data2[data.length - 5 + i],
+ ze[1].getLocalFileDataData()[i]);
+ }
+ }
+
+ public void testParseWithSkip() throws Exception {
+ ZipExtraField[] ze =
+ ExtraFieldUtils.parse(data, true,
+ ExtraFieldUtils.UnparseableExtraField.SKIP);
+ assertEquals("number of fields", 2, ze.length);
+ assertTrue("type field 1", ze[0] instanceof AsiExtraField);
+ assertEquals("mode field 1", 040755,
+ ((AsiExtraField) ze[0]).getMode());
+ assertTrue("type field 2", ze[1] instanceof UnrecognizedExtraField);
+ assertEquals("data length field 2", 1,
+ ze[1].getLocalFileDataLength().getValue());
+
+ byte[] data2 = new byte[data.length-1];
+ System.arraycopy(data, 0, data2, 0, data2.length);
+ ze = ExtraFieldUtils.parse(data2, true,
+ ExtraFieldUtils.UnparseableExtraField.SKIP);
+ assertEquals("number of fields", 1, ze.length);
+ assertTrue("type field 1", ze[0] instanceof AsiExtraField);
+ assertEquals("mode field 1", 040755,
+ ((AsiExtraField) ze[0]).getMode());
+ }
+
/**
* Test merge methods
*/
@@ -111,4 +166,30 @@
}
}
+
+ public void testMergeWithUnparseableData() throws Exception {
+ ZipExtraField d = new UnparseableExtraFieldData();
+ d.parseFromLocalFileData(new byte[] {1, 0, 1, 0}, 0, 4);
+ byte[] local =
+ ExtraFieldUtils.mergeLocalFileDataData(new ZipExtraField[] {a, d});
+ assertEquals("local length", data.length - 1, local.length);
+ for (int i = 0; i < local.length; i++) {
+ assertEquals("local byte " + i, data[i], local[i]);
+ }
+
+ byte[] dCentral = d.getCentralDirectoryData();
+ byte[] data2 = new byte[4 + aLocal.length + dCentral.length];
+ System.arraycopy(data, 0, data2, 0, 4 + aLocal.length + 2);
+ System.arraycopy(dCentral, 0, data2,
+ 4 + aLocal.length, dCentral.length);
+
+
+ byte[] central =
+ ExtraFieldUtils.mergeCentralDirectoryData(new ZipExtraField[] {a,
d});
+ assertEquals("central length", data2.length, central.length);
+ for (int i = 0; i < central.length; i++) {
+ assertEquals("central byte " + i, data2[i], central[i]);
+ }
+
+ }
}
Propchange:
ant/core/trunk/src/tests/junit/org/apache/tools/zip/ExtraFieldUtilsTest.java
------------------------------------------------------------------------------
--- svn:mergeinfo (added)
+++ svn:mergeinfo Tue Feb 16 14:41:11 2010
@@ -0,0 +1,2 @@
+/commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtilsTest.java:910483-910521
+/commons/sandbox/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtilsTest.java:749906-749907