Browse Source

Parse central directory part of ZIP extra fields. PR 46637

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@749610 13f79535-47bb-0310-9956-ffa450edef68
master
Stefan Bodewig 16 years ago
parent
commit
6cd0de1022
6 changed files with 176 additions and 18 deletions
  1. +40
    -0
      src/main/org/apache/tools/zip/CentralDirectoryParsingZipExtraField.java
  2. +24
    -3
      src/main/org/apache/tools/zip/ExtraFieldUtils.java
  3. +18
    -1
      src/main/org/apache/tools/zip/UnrecognizedExtraField.java
  4. +47
    -1
      src/main/org/apache/tools/zip/ZipEntry.java
  5. +3
    -9
      src/main/org/apache/tools/zip/ZipFile.java
  6. +44
    -4
      src/tests/junit/org/apache/tools/zip/ZipEntryTest.java

+ 40
- 0
src/main/org/apache/tools/zip/CentralDirectoryParsingZipExtraField.java View File

@@ -0,0 +1,40 @@
/*
* 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;

import java.util.zip.ZipException;

/**
* {@link ZipExtraField ZipExtraField} that knows how to parse central
* directory data.
*
* @since Ant 1.8.0
*/
public interface CentralDirectoryParsingZipExtraField extends ZipExtraField {
/**
* Populate data from this array as if it was in central directory data.
* @param data an array of bytes
* @param offset the start offset
* @param length the number of bytes in the array from offset
*
* @throws ZipException on error
*/
void parseFromCentralDirectoryData(byte[] data, int offset, int length)
throws ZipException;
}

+ 24
- 3
src/main/org/apache/tools/zip/ExtraFieldUtils.java View File

@@ -92,13 +92,27 @@ public class ExtraFieldUtils {

/**
* Split the array into ExtraFields and populate them with the
* give data.
* given data as local file data.
* @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);
}

/**
* 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
* @return an array of ExtraFields
* @since 1.1
* @throws ZipException on error
*/
public static ZipExtraField[] parse(byte[] data) throws ZipException {
public static ZipExtraField[] parse(byte[] data, boolean local)
throws ZipException {
List v = new ArrayList();
int start = 0;
while (start <= data.length - WORD) {
@@ -110,7 +124,14 @@ public class ExtraFieldUtils {
}
try {
ZipExtraField ze = createExtraField(headerId);
ze.parseFromLocalFileData(data, start + WORD, length);
if (local
|| !(ze instanceof CentralDirectoryParsingZipExtraField)) {
ze.parseFromLocalFileData(data, start + WORD, length);
} else {
((CentralDirectoryParsingZipExtraField) ze)
.parseFromCentralDirectoryData(data, start + WORD,
length);
}
v.add(ze);
} catch (InstantiationException ie) {
throw new ZipException(ie.getMessage());


+ 18
- 1
src/main/org/apache/tools/zip/UnrecognizedExtraField.java View File

@@ -26,7 +26,8 @@ package org.apache.tools.zip;
* identical - unless told the opposite.</p>
*
*/
public class UnrecognizedExtraField implements ZipExtraField {
public class UnrecognizedExtraField
implements CentralDirectoryParsingZipExtraField {

/**
* The Header-ID.
@@ -135,6 +136,22 @@ public class UnrecognizedExtraField implements ZipExtraField {
setLocalFileDataData(tmp);
}

/**
* @param data the array of bytes.
* @param offset the source location in the data array.
* @param length the number of bytes to use in the data array.
* @see ZipExtraField#parseFromCentralDirectoryData(byte[], int, int)
*/
public void parseFromCentralDirectoryData(byte[] data, int offset,
int length) {
byte[] tmp = new byte[length];
System.arraycopy(data, offset, tmp, 0, length);
setCentralDirectoryData(tmp);
if (localData == null) {
setLocalFileDataData(tmp);
}
}

private static byte[] copy(byte[] from) {
if (from != null) {
byte[] to = new byte[from.length];


+ 47
- 1
src/main/org/apache/tools/zip/ZipEntry.java View File

@@ -284,7 +284,8 @@ public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
*/
public void setExtra(byte[] extra) throws RuntimeException {
try {
setExtraFields(ExtraFieldUtils.parse(extra));
ZipExtraField[] local = ExtraFieldUtils.parse(extra, true);
mergeExtraFields(local, true);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
@@ -302,6 +303,18 @@ public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
super.setExtra(ExtraFieldUtils.mergeLocalFileDataData(getExtraFields()));
}

/**
* Sets the central directory part of extra fields.
*/
public void setCentralDirectoryExtra(byte[] b) {
try {
ZipExtraField[] central = ExtraFieldUtils.parse(b, false);
mergeExtraFields(central, false);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}

/**
* Retrieves the extra data for the local file data.
* @return the extra data for local file
@@ -386,4 +399,37 @@ public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
return (this == o);
}

/**
* If there are no extra fields, use the given fields as new extra
* data - otherwise merge the fields assuming the existing fields
* and the new fields stem from different locations inside the
* archive.
* @param f the extra fields to merge
* @param local whether the new fields originate from local data
*/
private void mergeExtraFields(ZipExtraField[] f, boolean local)
throws ZipException {
if (extraFields == null) {
setExtraFields(f);
} else {
for (int i = 0; i < f.length; i++) {
ZipExtraField existing = getExtraField(f[i].getHeaderId());
if (existing == null) {
addExtraField(f[i]);
} else {
if (local
|| !(existing
instanceof CentralDirectoryParsingZipExtraField)) {
byte[] b = f[i].getLocalFileDataData();
existing.parseFromLocalFileData(b, 0, b.length);
} else {
byte[] b = f[i].getCentralDirectoryData();
((CentralDirectoryParsingZipExtraField) existing)
.parseFromCentralDirectoryData(b, 0, b.length);
}
}
}
setExtra();
}
}
}

+ 3
- 9
src/main/org/apache/tools/zip/ZipFile.java View File

@@ -389,15 +389,9 @@ public class ZipFile {

nameMap.put(ze.getName(), ze);

int lenToSkip = extraLen;
while (lenToSkip > 0) {
int skipped = archive.skipBytes(lenToSkip);
if (skipped <= 0) {
throw new RuntimeException("failed to skip extra data in"
+ " central directory");
}
lenToSkip -= skipped;
}
byte[] cdExtraData = new byte[extraLen];
archive.readFully(cdExtraData);
ze.setCentralDirectoryExtra(cdExtraData);

byte[] comment = new byte[commentLen];
archive.readFully(comment);


+ 44
- 4
src/tests/junit/org/apache/tools/zip/ZipEntryTest.java View File

@@ -32,8 +32,6 @@ public class ZipEntryTest extends TestCase {

/**
* test handling of extra fields
*
* @since 1.1
*/
public void testExtraFields() {
AsiExtraField a = new AsiExtraField();
@@ -85,10 +83,52 @@ public class ZipEntryTest extends TestCase {
}
}

/**
* test handling of extra fields via central directory
*/
public void testExtraFieldMerging() {
AsiExtraField a = new AsiExtraField();
a.setDirectory(true);
a.setMode(0755);
UnrecognizedExtraField u = new UnrecognizedExtraField();
u.setHeaderId(new ZipShort(1));
u.setLocalFileDataData(new byte[0]);

ZipEntry ze = new ZipEntry("test/");
ze.setExtraFields(new ZipExtraField[] {a, u});

// merge
// Header-ID 1 + length 1 + one byte of data
ze.setCentralDirectoryExtra(new byte[] {1, 0, 1, 0, 127});

ZipExtraField[] result = ze.getExtraFields();
assertEquals("first pass", 2, result.length);
assertSame(a, result[0]);
assertEquals(new ZipShort(1), result[1].getHeaderId());
assertEquals(new ZipShort(0), result[1].getLocalFileDataLength());
assertEquals(new ZipShort(1), result[1].getCentralDirectoryLength());

// add new
// Header-ID 2 + length 0
ze.setCentralDirectoryExtra(new byte[] {2, 0, 0, 0});

result = ze.getExtraFields();
assertEquals("second pass", 3, result.length);

// merge
// Header-ID 2 + length 1 + one byte of data
ze.setExtra(new byte[] {2, 0, 1, 0, 127});

result = ze.getExtraFields();
assertEquals("third pass", 3, result.length);
assertSame(a, result[0]);
assertEquals(new ZipShort(2), result[2].getHeaderId());
assertEquals(new ZipShort(1), result[2].getLocalFileDataLength());
assertEquals(new ZipShort(0), result[2].getCentralDirectoryLength());
}

/**
* test handling of extra fields
*
* @since 1.1
*/
public void testAddAsFirstExtraField() {
AsiExtraField a = new AsiExtraField();


Loading…
Cancel
Save