Author: bodewig
Date: Tue Jun 4 04:39:26 2013
New Revision: 1489286
URL: http://svn.apache.org/r1489286
Log:
Merge handling of duplicate entries from Commons Compress' ZipFile - needed to
fix PR 54967
Modified:
ant/core/trunk/src/main/org/apache/tools/zip/ZipFile.java (contents,
props changed)
Modified: ant/core/trunk/src/main/org/apache/tools/zip/ZipFile.java
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/zip/ZipFile.java?rev=1489286&r1=1489285&r2=1489286&view=diff
==============================================================================
--- ant/core/trunk/src/main/org/apache/tools/zip/ZipFile.java (original)
+++ ant/core/trunk/src/main/org/apache/tools/zip/ZipFile.java Tue Jun 4
04:39:26 2013
@@ -28,7 +28,9 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
-import java.util.LinkedHashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
@@ -80,17 +82,16 @@ public class ZipFile {
private static final int POS_3 = 3;
/**
- * Maps ZipEntrys to two longs, recording the offsets of
- * the local file headers and the start of entry data.
+ * List of entries in the order they appear inside the central
+ * directory.
*/
- private final Map<ZipEntry, OffsetEntry> entries =
- new LinkedHashMap<ZipEntry, OffsetEntry>(HASH_SIZE);
+ private final List<ZipEntry> entries = new LinkedList<ZipEntry>();
/**
- * Maps String to ZipEntrys, name -> actual entry.
+ * Maps String to list of ZipEntrys, name -> actual entries.
*/
- private final Map<String, ZipEntry> nameMap =
- new HashMap<String, ZipEntry>(HASH_SIZE);
+ private final Map<String, LinkedList<ZipEntry>> nameMap =
+ new HashMap<String, LinkedList<ZipEntry>>(HASH_SIZE);
private static final class OffsetEntry {
private long headerOffset = -1;
@@ -272,7 +273,7 @@ public class ZipFile {
* @return all entries as {@link ZipEntry} instances
*/
public Enumeration<ZipEntry> getEntries() {
- return Collections.enumeration(entries.keySet());
+ return Collections.enumeration(entries);
}
/**
@@ -286,8 +287,7 @@ public class ZipFile {
* @since Ant 1.9.0
*/
public Enumeration<ZipEntry> getEntriesInPhysicalOrder() {
- ZipEntry[] allEntries =
- entries.keySet().toArray(new ZipEntry[0]);
+ ZipEntry[] allEntries = entries.toArray(new ZipEntry[0]);
Arrays.sort(allEntries, OFFSET_COMPARATOR);
return Collections.enumeration(Arrays.asList(allEntries));
}
@@ -295,12 +295,51 @@ public class ZipFile {
/**
* Returns a named entry - or {@code null} if no entry by
* that name exists.
+ *
+ * <p>If multiple entries with the same name exist the first entry
+ * in the archive's central directory by that name is
+ * returned.</p>
+ *
* @param name name of the entry.
* @return the ZipEntry corresponding to the given name - or
* {@code null} if not present.
*/
public ZipEntry getEntry(String name) {
- return nameMap.get(name);
+ LinkedList<ZipEntry> entriesOfThatName = nameMap.get(name);
+ return entriesOfThatName != null ? entriesOfThatName.getFirst() : null;
+ }
+
+ /**
+ * Returns all named entries in the same order they appear within
+ * the archive's central directory.
+ *
+ * @param name name of the entry.
+ * @return the Iterable<ZipEntry> corresponding to the
+ * given name
+ * @since 1.9.2
+ */
+ public Iterable<ZipEntry> getEntries(String name) {
+ List<ZipEntry> entriesOfThatName = nameMap.get(name);
+ return entriesOfThatName != null ? entriesOfThatName
+ : Collections.<ZipEntry>emptyList();
+ }
+
+ /**
+ * Returns all named entries in the same order their contents
+ * appear within the archive.
+ *
+ * @param name name of the entry.
+ * @return the Iterable<ZipEntry> corresponding to the
+ * given name
+ * @since 1.9.2
+ */
+ public Iterable<ZipEntry> getEntriesInPhysicalOrder(String name) {
+ ZipEntry[] entriesOfThatName = new ZipEntry[0];
+ if (nameMap.containsKey(name)) {
+ entriesOfThatName = nameMap.get(name).toArray(entriesOfThatName);
+ Arrays.sort(entriesOfThatName, OFFSET_COMPARATOR);
+ }
+ return Arrays.asList(entriesOfThatName);
}
/**
@@ -323,10 +362,11 @@ public class ZipFile {
*/
public InputStream getInputStream(ZipEntry ze)
throws IOException, ZipException {
- OffsetEntry offsetEntry = entries.get(ze);
- if (offsetEntry == null) {
+ if (!(ze instanceof Entry)) {
return null;
}
+ // cast valididty is checked just above
+ OffsetEntry offsetEntry = ((Entry) ze).getOffsetEntry();
ZipUtil.checkRequestedFeatures(ze);
long start = offsetEntry.dataOffset;
BoundedInputStream bis =
@@ -441,7 +481,8 @@ public class ZipFile {
throws IOException {
archive.readFully(CFH_BUF);
int off = 0;
- ZipEntry ze = new ZipEntry();
+ OffsetEntry offset = new OffsetEntry();
+ Entry ze = new Entry(offset);
int versionMadeBy = ZipShort.getValue(CFH_BUF, off);
off += SHORT;
@@ -496,12 +537,9 @@ public class ZipFile {
ze.setName(entryEncoding.decode(fileName), fileName);
// LFH offset,
- OffsetEntry offset = new OffsetEntry();
offset.headerOffset = ZipLong.getValue(CFH_BUF, off);
// data offset will be filled later
- entries.put(ze, offset);
-
- nameMap.put(ze.getName(), ze);
+ entries.add(ze);
byte[] cdExtraData = new byte[extraLen];
archive.readFully(cdExtraData);
@@ -814,16 +852,11 @@ public class ZipFile {
private void resolveLocalFileHeaderData(Map<ZipEntry, NameAndComment>
entriesWithoutUTF8Flag)
throws IOException {
- // changing the name of a ZipEntry is going to change
- // the hashcode - see COMPRESS-164
- // Map needs to be reconstructed in order to keep central
- // directory order
- Map<ZipEntry, OffsetEntry> origMap =
- new LinkedHashMap<ZipEntry, OffsetEntry>(entries);
- entries.clear();
- for (Map.Entry<ZipEntry, OffsetEntry> ent : origMap.entrySet()) {
- ZipEntry ze = ent.getKey();
- OffsetEntry offsetEntry = ent.getValue();
+ for (Iterator<ZipEntry> it = entries.iterator(); it.hasNext(); ) {
+ // entries is filled in populateFromCentralDirectory and
+ // never modified
+ Entry ze = (Entry) it.next();
+ OffsetEntry offsetEntry = ze.getOffsetEntry();
long offset = offsetEntry.headerOffset;
archive.seek(offset + LFH_OFFSET_FOR_FILENAME_LENGTH);
archive.readFully(SHORT_BUF);
@@ -846,16 +879,18 @@ public class ZipFile {
+ SHORT + SHORT + fileNameLen + extraFieldLen;
if (entriesWithoutUTF8Flag.containsKey(ze)) {
- String orig = ze.getName();
NameAndComment nc = entriesWithoutUTF8Flag.get(ze);
ZipUtil.setNameAndCommentFromExtraFields(ze, nc.name,
nc.comment);
- if (!orig.equals(ze.getName())) {
- nameMap.remove(orig);
- nameMap.put(ze.getName(), ze);
- }
}
- entries.put(ze, offsetEntry);
+
+ String name = ze.getName();
+ LinkedList<ZipEntry> entriesOfThatName = nameMap.get(name);
+ if (entriesOfThatName == null) {
+ entriesOfThatName = new LinkedList<ZipEntry>();
+ nameMap.put(name, entriesOfThatName);
+ }
+ entriesOfThatName.addLast(ze);
}
}
@@ -962,16 +997,52 @@ public class ZipFile {
return 0;
}
- OffsetEntry off1 = entries.get(e1);
- OffsetEntry off2 = entries.get(e2);
- if (off1 == null) {
+ Entry ent1 = e1 instanceof Entry ? (Entry) e1 : null;
+ Entry ent2 = e2 instanceof Entry ? (Entry) e2 : null;
+ if (ent1 == null) {
return 1;
}
- if (off2 == null) {
+ if (ent2 == null) {
return -1;
}
- long val = (off1.headerOffset - off2.headerOffset);
+ long val = (ent1.getOffsetEntry().headerOffset
+ - ent2.getOffsetEntry().headerOffset);
return val == 0 ? 0 : val < 0 ? -1 : +1;
}
};
+
+ /**
+ * Extends ZipEntry to store the offset within the archive.
+ */
+ private static class Entry extends ZipEntry {
+
+ private final OffsetEntry offsetEntry;
+
+ Entry(OffsetEntry offset) {
+ this.offsetEntry = offset;
+ }
+
+ OffsetEntry getOffsetEntry() {
+ return offsetEntry;
+ }
+
+ @Override
+ public int hashCode() {
+ return 3 * super.hashCode()
+ + (int) (offsetEntry.headerOffset % Integer.MAX_VALUE);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (super.equals(other)) {
+ // super.equals would return false if other were not an Entry
+ Entry otherEntry = (Entry) other;
+ return offsetEntry.headerOffset
+ == otherEntry.offsetEntry.headerOffset
+ && offsetEntry.dataOffset
+ == otherEntry.offsetEntry.dataOffset;
+ }
+ return false;
+ }
+ }
}
Propchange: ant/core/trunk/src/main/org/apache/tools/zip/ZipFile.java
------------------------------------------------------------------------------
Merged
/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java:r1484499-1489284