ant-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bode...@apache.org
Subject svn commit: r1489286 - /ant/core/trunk/src/main/org/apache/tools/zip/ZipFile.java
Date Tue, 04 Jun 2013 04:39:26 GMT
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



Mime
View raw message