Browse Source

accept a wider range of existing zip archives by being more lenient when parsing extra fields

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@910537 13f79535-47bb-0310-9956-ffa450edef68
master
Stefan Bodewig 15 years ago
parent
commit
f665a4d335
11 changed files with 480 additions and 53 deletions
  1. +3
    -0
      WHATSNEW
  2. +1
    -1
      src/main/org/apache/tools/ant/taskdefs/Zip.java
  3. +1
    -1
      src/main/org/apache/tools/ant/types/resources/ZipResource.java
  4. +125
    -9
      src/main/org/apache/tools/zip/ExtraFieldUtils.java
  5. +115
    -0
      src/main/org/apache/tools/zip/UnparseableExtraFieldData.java
  6. +4
    -12
      src/main/org/apache/tools/zip/UnrecognizedExtraField.java
  7. +110
    -28
      src/main/org/apache/tools/zip/ZipEntry.java
  8. +38
    -0
      src/main/org/apache/tools/zip/ZipUtil.java
  9. +1
    -1
      src/tests/antunit/taskdefs/unzip-test.xml
  10. BIN
      src/tests/antunit/taskdefs/zip/Bugzilla-46559.zip
  11. +82
    -1
      src/tests/junit/org/apache/tools/zip/ExtraFieldUtilsTest.java

+ 3
- 0
WHATSNEW View File

@@ -31,6 +31,9 @@ Other changes:
* 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
======================================



+ 1
- 1
src/main/org/apache/tools/ant/taskdefs/Zip.java View File

@@ -1026,7 +1026,7 @@ public class Zip extends MatchingTask {
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);


+ 1
- 1
src/main/org/apache/tools/ant/types/resources/ZipResource.java View File

@@ -219,7 +219,7 @@ public class ZipResource extends ArchiveResource {
setDirectory(e.isDirectory());
setSize(e.getSize());
setMode(e.getUnixMode());
extras = e.getExtraFields();
extras = e.getExtraFields(true);
method = e.getMethod();
}



+ 125
- 9
src/main/org/apache/tools/zip/ExtraFieldUtils.java View File

@@ -92,18 +92,19 @@ public class ExtraFieldUtils {

/**
* 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 class ExtraFieldUtils {
*/
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 @@ public class ExtraFieldUtils {
* @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 @@ public class ExtraFieldUtils {
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 @@ public class ExtraFieldUtils {
* @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 @@ public class ExtraFieldUtils {
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; }
}
}

+ 115
- 0
src/main/org/apache/tools/zip/UnparseableExtraFieldData.java View File

@@ -0,0 +1,115 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.tools.zip;

/**
* Wrapper for extra field data that doesn't conform to the recommended format of header-tag + size + data.
*
* <p>The header-id is artificial (and not listed as a know ID in
* {@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>
* @since Ant 1.8.1
*/
public final class UnparseableExtraFieldData
implements CentralDirectoryParsingZipExtraField {

private static final ZipShort HEADER_ID = new ZipShort(0xACC1);

private byte[] localFileData;
private byte[] centralDirectoryData;

/**
* The Header-ID.
*
* @return a completely arbitrary value that should be ignored.
*/
public ZipShort getHeaderId() {
return HEADER_ID;
}

/**
* Length of the complete extra field in the local file data.
*
* @return The LocalFileDataLength value
*/
public ZipShort getLocalFileDataLength() {
return new ZipShort(localFileData == null ? 0 : localFileData.length);
}

/**
* Length of the complete extra field in the central directory.
*
* @return The CentralDirectoryLength value
*/
public ZipShort getCentralDirectoryLength() {
return centralDirectoryData == null
? getLocalFileDataLength()
: new ZipShort(centralDirectoryData.length);
}

/**
* The actual data to put into local file data.
*
* @return The LocalFileDataData value
*/
public byte[] getLocalFileDataData() {
return ZipUtil.copy(localFileData);
}

/**
* The actual data to put into central directory.
*
* @return The CentralDirectoryData value
*/
public byte[] getCentralDirectoryData() {
return centralDirectoryData == null
? getLocalFileDataData() : ZipUtil.copy(centralDirectoryData);
}

/**
* Populate data from this array as if it was in local file data.
*
* @param buffer the buffer to read data from
* @param offset offset into buffer to read data
* @param length the length of data
*/
public void parseFromLocalFileData(byte[] buffer, int offset, int length) {
localFileData = new byte[length];
System.arraycopy(buffer, offset, localFileData, 0, length);
}

/**
* Populate data from this array as if it was in central directory data.
*
* @param buffer the buffer to read data from
* @param offset offset into buffer to read data
* @param length the length of data
* @exception ZipException on error
*/
public void parseFromCentralDirectoryData(byte[] buffer, int offset,
int length) {
centralDirectoryData = new byte[length];
System.arraycopy(buffer, offset, centralDirectoryData, 0, length);
if (localFileData == null) {
parseFromLocalFileData(buffer, offset, length);
}
}

}

+ 4
- 12
src/main/org/apache/tools/zip/UnrecognizedExtraField.java View File

@@ -66,7 +66,7 @@ public class UnrecognizedExtraField
* @param data the field data to use
*/
public void setLocalFileDataData(byte[] data) {
localData = copy(data);
localData = ZipUtil.copy(data);
}

/**
@@ -82,7 +82,7 @@ public class UnrecognizedExtraField
* @return the local data
*/
public byte[] getLocalFileDataData() {
return copy(localData);
return ZipUtil.copy(localData);
}

/**
@@ -98,7 +98,7 @@ public class UnrecognizedExtraField
* @param data the data to use
*/
public void setCentralDirectoryData(byte[] data) {
centralData = copy(data);
centralData = ZipUtil.copy(data);
}

/**
@@ -119,7 +119,7 @@ public class UnrecognizedExtraField
*/
public byte[] getCentralDirectoryData() {
if (centralData != null) {
return copy(centralData);
return ZipUtil.copy(centralData);
}
return getLocalFileDataData();
}
@@ -151,12 +151,4 @@ public class UnrecognizedExtraField
}
}

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;
}
}

+ 110
- 28
src/main/org/apache/tools/zip/ZipEntry.java View File

@@ -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 @@ public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
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 @@ public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
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 @@ public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
this((java.util.zip.ZipEntry) entry);
setInternalAttributes(entry.getInternalAttributes());
setExternalAttributes(entry.getExternalAttributes());
setExtraFields(entry.getExtraFields());
setExtraFields(entry.getExtraFields(true));
}

/**
@@ -93,10 +115,9 @@ public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
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 class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
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 @@ public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
* @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 @@ public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
* @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
*/
@@ -263,6 +312,17 @@ public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
setExtra();
}

/**
* 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.
*
@@ -276,7 +336,18 @@ public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
}

/**
* 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 class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
*/
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 @@ public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
* @since 1.1
*/
protected void setExtra() {
super.setExtra(ExtraFieldUtils.mergeLocalFileDataData(getExtraFields()));
super.setExtra(ExtraFieldUtils.mergeLocalFileDataData(getExtraFields(true)));
}

/**
@@ -308,7 +383,9 @@ public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
*/
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 @@ public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
* @since 1.1
*/
public byte[] getCentralDirectoryExtra() {
return ExtraFieldUtils.mergeCentralDirectoryData(getExtraFields());
return ExtraFieldUtils.mergeCentralDirectoryData(getExtraFields(true));
}

/**
@@ -413,7 +490,12 @@ public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
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 {


+ 38
- 0
src/main/org/apache/tools/zip/ZipUtil.java View File

@@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.tools.zip;

/**
* Utility class for handling DOS and Java time conversions.
* @since Ant 1.8.1
*/
public abstract class ZipUtil {
/**
* Create a copy of the given array - or return null if the
* argument is null.
*/
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;
}

}

+ 1
- 1
src/tests/antunit/taskdefs/unzip-test.xml View File

@@ -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>


BIN
src/tests/antunit/taskdefs/zip/Bugzilla-46559.zip View File


+ 82
- 1
src/tests/junit/org/apache/tools/zip/ExtraFieldUtilsTest.java View File

@@ -18,6 +18,7 @@

package org.apache.tools.zip;

import java.util.Arrays;
import junit.framework.TestCase;

/**
@@ -78,11 +79,65 @@ public class ExtraFieldUtilsTest extends TestCase implements UnixStat {
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 class ExtraFieldUtilsTest extends TestCase implements UnixStat {
}

}

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]);
}

}
}

Loading…
Cancel
Save