You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by bo...@apache.org on 2009/03/03 13:42:28 UTC

svn commit: r749603 - in /commons/sandbox/compress/trunk/src: main/java/org/apache/commons/compress/archivers/zip/ test/java/org/apache/commons/compress/archivers/zip/

Author: bodewig
Date: Tue Mar  3 12:42:28 2009
New Revision: 749603

URL: http://svn.apache.org/viewvc?rev=749603&view=rev
Log:
parse central directory part of extra fields.  SANDBOX-292

Modified:
    commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/AbstractUnicodeExtraField.java
    commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java
    commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java
    commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/JarMarker.java
    commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/UnrecognizedExtraField.java
    commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java
    commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipExtraField.java
    commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
    commons/sandbox/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/UTF8ZipFilesTest.java
    commons/sandbox/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntryTest.java

Modified: commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/AbstractUnicodeExtraField.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/AbstractUnicodeExtraField.java?rev=749603&r1=749602&r2=749603&view=diff
==============================================================================
--- commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/AbstractUnicodeExtraField.java (original)
+++ commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/AbstractUnicodeExtraField.java Tue Mar  3 12:42:28 2009
@@ -159,4 +159,13 @@
         data = null;
     }
 
+    /**
+     * Doesn't do anything special since this class always uses the
+     * same data in central directory and local file data.
+     */
+    public void parseFromCentralDirectoryData(byte[] buffer, int offset,
+                                              int length)
+        throws ZipException {
+        parseFromLocalFileData(buffer, offset, length);
+    }
 }

Modified: commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java?rev=749603&r1=749602&r2=749603&view=diff
==============================================================================
--- commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java (original)
+++ commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java Tue Mar  3 12:42:28 2009
@@ -288,6 +288,16 @@
     }
 
     /**
+     * Doesn't do anything special since this class always uses the
+     * same data in central directory and local file data.
+     */
+    public void parseFromCentralDirectoryData(byte[] buffer, int offset,
+                                              int length)
+        throws ZipException {
+        parseFromLocalFileData(buffer, offset, length);
+    }
+
+    /**
      * Get the file mode for given permissions with the correct file type.
      * @param mode the mode
      * @return the type with the mode

Modified: commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java?rev=749603&r1=749602&r2=749603&view=diff
==============================================================================
--- commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java (original)
+++ commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java Tue Mar  3 12:42:28 2009
@@ -86,12 +86,26 @@
 
     /**
      * Split the array into ExtraFields and populate them with the
-     * give data.
-     * @param data an array of bytes
+     * 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
+     * @throws ZipException on error
+     */
+    public static ZipExtraField[] parse(byte[] data, boolean local)
+        throws ZipException {
         List v = new ArrayList();
         int start = 0;
         while (start <= data.length - WORD) {
@@ -103,7 +117,12 @@
             }
             try {
                 ZipExtraField ze = createExtraField(headerId);
-                ze.parseFromLocalFileData(data, start + WORD, length);
+                if (local) {
+                    ze.parseFromLocalFileData(data, start + WORD, length);
+                } else {
+                    ze.parseFromCentralDirectoryData(data, start + WORD,
+                                                     length);
+                }
                 v.add(ze);
             } catch (InstantiationException ie) {
                 throw new ZipException(ie.getMessage());

Modified: commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/JarMarker.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/JarMarker.java?rev=749603&r1=749602&r2=749603&view=diff
==============================================================================
--- commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/JarMarker.java (original)
+++ commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/JarMarker.java Tue Mar  3 12:42:28 2009
@@ -101,4 +101,14 @@
             throw new ZipException("JarMarker doesn't expect any data");
         }
     }
+
+    /**
+     * Doesn't do anything special since this class always uses the
+     * same data in central directory and local file data.
+     */
+    public void parseFromCentralDirectoryData(byte[] buffer, int offset,
+                                              int length)
+        throws ZipException {
+        parseFromLocalFileData(buffer, offset, length);
+    }
 }

Modified: commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/UnrecognizedExtraField.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/UnrecognizedExtraField.java?rev=749603&r1=749602&r2=749603&view=diff
==============================================================================
--- commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/UnrecognizedExtraField.java (original)
+++ commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/UnrecognizedExtraField.java Tue Mar  3 12:42:28 2009
@@ -129,6 +129,22 @@
         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];

Modified: commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java?rev=749603&r1=749602&r2=749603&view=diff
==============================================================================
--- commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java (original)
+++ commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java Tue Mar  3 12:42:28 2009
@@ -265,7 +265,8 @@
      */
     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);
         }
@@ -282,6 +283,18 @@
     }
 
     /**
+     * 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
      */
@@ -345,4 +358,34 @@
         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) {
+                        byte[] b = f[i].getLocalFileDataData();
+                        existing.parseFromLocalFileData(b, 0, b.length);
+                    } else {
+                        byte[] b = f[i].getCentralDirectoryData();
+                        existing.parseFromCentralDirectoryData(b, 0, b.length);
+                    }
+                }
+            }
+            setExtra();
+        }
+    }
 }

Modified: commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipExtraField.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipExtraField.java?rev=749603&r1=749602&r2=749603&view=diff
==============================================================================
--- commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipExtraField.java (original)
+++ commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipExtraField.java Tue Mar  3 12:42:28 2009
@@ -28,8 +28,7 @@
  * to be. {@link java.util.zip.ZipOutputStream java.util.zip.ZipOutputStream}
  * will only use the local file data in both places.</p>
  */
-public interface ZipExtraField
-{
+public interface ZipExtraField {
     /**
      * The Header-ID.
      *
@@ -77,6 +76,17 @@
      * @param length the length of data
      * @exception ZipException on error
      */
-    void parseFromLocalFileData( byte[] buffer, int offset, int length )
+    void parseFromLocalFileData(byte[] buffer, int offset, int length)
+        throws ZipException;
+
+    /**
+     * 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
+     */
+    void parseFromCentralDirectoryData(byte[] buffer, int offset, int length)
         throws ZipException;
 }

Modified: commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java?rev=749603&r1=749602&r2=749603&view=diff
==============================================================================
--- commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java (original)
+++ commons/sandbox/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java Tue Mar  3 12:42:28 2009
@@ -388,15 +388,9 @@
 
             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);

Modified: commons/sandbox/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/UTF8ZipFilesTest.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/UTF8ZipFilesTest.java?rev=749603&r1=749602&r2=749603&view=diff
==============================================================================
--- commons/sandbox/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/UTF8ZipFilesTest.java (original)
+++ commons/sandbox/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/UTF8ZipFilesTest.java Tue Mar  3 12:42:28 2009
@@ -99,6 +99,24 @@
         }
     }
 
+    /*
+     * WinZIP created archive, uses Unicode Extra Fields but only in
+     * the central directory.
+     */
+    public void testReadWinZipArchive() throws IOException, URISyntaxException {
+        URL zip = getClass().getResource("/utf8-winzip-test.zip");
+        File archive = new File(new URI(zip.toString()));
+        ZipFile zf = null;
+        try {
+            zf = new ZipFile(archive, null, true);
+            assertNotNull(zf.getEntry(ASCII_TXT));
+            assertNotNull(zf.getEntry(EURO_FOR_DOLLAR_TXT));
+            assertNotNull(zf.getEntry(OIL_BARREL_TXT));
+        } finally {
+            ZipFile.closeQuietly(zf);
+        }
+    }
+
     public void testZipFileReadsUnicodeFields() throws IOException {
         File file = File.createTempFile("unicode-test", ".zip");
         ZipFile zf = null;

Modified: commons/sandbox/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntryTest.java
URL: http://svn.apache.org/viewvc/commons/sandbox/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntryTest.java?rev=749603&r1=749602&r2=749603&view=diff
==============================================================================
--- commons/sandbox/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntryTest.java (original)
+++ commons/sandbox/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntryTest.java Tue Mar  3 12:42:28 2009
@@ -32,8 +32,6 @@
 
     /**
      * test handling of extra fields
-     *
-     * @since 1.1
      */
     public void testExtraFields() {
         AsiExtraField a = new AsiExtraField();
@@ -86,9 +84,51 @@
     }
 
     /**
+     * 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]);
+
+        ZipArchiveEntry ze = new ZipArchiveEntry("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();