commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ebo...@apache.org
Subject svn commit: r1552325 - in /commons/proper/compress/trunk/src: changes/ main/java/org/apache/commons/compress/archivers/zip/ test/java/org/apache/commons/compress/archivers/ test/java/org/apache/commons/compress/archivers/zip/ test/resources/ test/resou...
Date Thu, 19 Dec 2013 16:09:55 GMT
Author: ebourg
Date: Thu Dec 19 16:09:54 2013
New Revision: 1552325

URL: http://svn.apache.org/r1552325
Log:
Explode support for ZipFile and ZipArchiveInputStream (COMPRESS-115)

Added:
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/BinaryTree.java   (with props)
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/BitStream.java   (with props)
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/CircularBuffer.java   (with props)
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ExplodingInputStream.java   (with props)
    commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/BinaryTreeTest.java   (with props)
    commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/BitStreamTest.java   (with props)
    commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/CircularBufferTest.java   (with props)
    commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ExplodeSupportTest.java   (with props)
    commons/proper/compress/trunk/src/test/resources/archives/imploding-4Kdict-2trees.zip   (with props)
    commons/proper/compress/trunk/src/test/resources/archives/imploding-8Kdict-3trees.zip   (with props)
Modified:
    commons/proper/compress/trunk/src/changes/changes.xml
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/GeneralPurposeBit.java
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipUtil.java
    commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/ZipTestCase.java
    commons/proper/compress/trunk/src/test/resources/moby.zip

Modified: commons/proper/compress/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/changes/changes.xml?rev=1552325&r1=1552324&r2=1552325&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/changes/changes.xml (original)
+++ commons/proper/compress/trunk/src/changes/changes.xml Thu Dec 19 16:09:54 2013
@@ -78,6 +78,9 @@ The <action> type attribute can be add,u
         GzipCompressorOutputStream now supports setting the compression level and the header metadata
         (filename, comment, modification time, operating system and extra flags)
       </action>
+      <action issue="COMPRESS-115" type="add" date="2012-12-19" due-to="Emmanuel Bourg">
+        ZipFile and ZipArchiveInputStream now support reading entries compressed using the IMPLODE method.
+      </action>
     </release>
     <release version="1.6" date="2013-10-26"
              description="Release 1.6">

Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/BinaryTree.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/BinaryTree.java?rev=1552325&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/BinaryTree.java (added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/BinaryTree.java Thu Dec 19 16:09:54 2013
@@ -0,0 +1,189 @@
+/*
+ * 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.commons.compress.archivers.zip;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+
+/**
+ * Binary tree of positive values.
+ * 
+ * @author Emmanuel Bourg
+ * @since 1.7
+ */
+class BinaryTree {
+
+    /** Value in the array indicating an undefined node */
+    private static final int UNDEFINED = -1;
+    
+    /** Value in the array indicating a non leaf node */
+    private static final int NODE = -2;
+
+    /** 
+     * The array representing the binary tree. The root is at index 0,
+     * the left children are at 2*i+1 and the right children at 2*i+2.
+     */
+    private final int[] tree;
+
+    public BinaryTree(int depth) {
+        tree = new int[(1 << (depth + 1)) - 1];
+        Arrays.fill(tree, UNDEFINED);
+    }
+
+    /**
+     * Adds a leaf to the tree.
+     * 
+     * @param node   the index of the node where the path is appended
+     * @param path   the path to the leaf (bits are parsed from the right to the left)
+     * @param depth  the number of nodes in the path
+     * @param value  the value of the leaf (must be positive)
+     */
+    public void addLeaf(int node, int path, int depth, int value) {
+        if (depth == 0) {
+            // end of the path reached, add the value to the current node
+            if (tree[node] == UNDEFINED) {
+                tree[node] = value;
+            } else {
+                throw new IllegalArgumentException("Tree value at index " + node + " has already been assigned (" + tree[node] + ")");
+            }
+        } else {
+            // mark the current node as a non leaf node
+            tree[node] = NODE;
+            
+            // move down the path recursively
+            int nextChild = 2 * node + 1 + (path & 1);
+            addLeaf(nextChild, path >>> 1, depth - 1, value);
+        }
+    }
+
+    /**
+     * Reads a value from the specified bit stream.
+     * 
+     * @param stream
+     * @return the value decoded, or -1 if the end of the stream is reached
+     */
+    public int read(BitStream stream) throws IOException {
+        short currentIndex = 0;
+
+        while (true) {
+            int bit = stream.nextBit();
+            if (bit == -1) {
+                return -1;
+            }
+
+            short childIndex = (short) (2 * currentIndex + 1 + bit);
+            int value = tree[childIndex];
+            if (value == NODE) {
+                // consume the next bit
+                currentIndex = childIndex;
+            } else if (value != UNDEFINED) {
+                return value;
+            } else {
+                throw new IOException("The child " + bit + " of node at index " + currentIndex + " is not defined");
+            }
+        }
+    }
+    
+
+    /**
+     * Decodes the packed binary tree from the specified stream.
+     */
+    static BinaryTree decode(InputStream in, final int totalNumberOfValues) throws IOException {
+        // the first byte contains the size of the structure minus one
+        int size = in.read() + 1;
+        if (size == 0) {
+            throw new IOException("Cannot read the size of the encoded tree, unexpected end of stream");
+        }
+
+        byte[] encodedTree = new byte[size];
+        new DataInputStream(in).readFully(encodedTree);
+
+        /** The maximum bit length for a value (16 or lower) */
+        int maxLength = 0;
+        
+        int[] originalBitLengths = new int[totalNumberOfValues];
+        int pos = 0;
+        for (byte b : encodedTree) {
+            // each byte encodes the number of values (upper 4 bits) for a bit length (lower 4 bits)
+            int numberOfValues = ((b & 0xF0) >> 4) + 1;
+            int bitLength = (b & 0x0F) + 1;
+
+            for (int j = 0; j < numberOfValues; j++) {
+                originalBitLengths[pos++] = bitLength;
+            }
+            
+            maxLength = Math.max(maxLength, bitLength);
+        }
+
+        // sort the array of bit lengths and memorize the permutation used to restore the order of the codes
+        int[] permutation = new int[originalBitLengths.length];
+        for (int k = 0; k < permutation.length; k++) {
+            permutation[k] = k;
+        }
+        
+        int c = 0;
+        int[] sortedBitLengths = new int[originalBitLengths.length];
+        for (int k = 0; k < originalBitLengths.length; k++) {
+            // iterate over the values
+            for (int l = 0; l < originalBitLengths.length; l++) {
+                // look for the value in the original array
+                if (originalBitLengths[l] == k) {
+                    // put the value at the current position in the sorted array...
+                    sortedBitLengths[c] = k;
+                    
+                    // ...and memorize the permutation
+                    permutation[c] = l; 
+                    
+                    c++;
+                }
+            }
+        }
+
+        // decode the values of the tree
+        int code = 0;
+        int codeIncrement = 0;
+        int lastBitLength = 0;
+
+        int[] codes = new int[totalNumberOfValues];
+
+        for (int i = totalNumberOfValues - 1; i >= 0; i--) {
+            code = code + codeIncrement;
+            if (sortedBitLengths[i] != lastBitLength) {
+                lastBitLength = sortedBitLengths[i];
+                codeIncrement = 1 << (16 - lastBitLength);
+            }
+            codes[permutation[i]] = code;
+        }
+        
+        // build the tree
+        BinaryTree tree = new BinaryTree(maxLength);
+        
+        for (int k = 0; k < codes.length; k++) {
+            int bitLength = originalBitLengths[k];
+            if (bitLength > 0) {
+                tree.addLeaf(0, Integer.reverse(codes[k] << 16), bitLength, k);
+            }
+        }
+
+        return tree;
+    }
+}

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/BinaryTree.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/BinaryTree.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/BitStream.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/BitStream.java?rev=1552325&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/BitStream.java (added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/BitStream.java Thu Dec 19 16:09:54 2013
@@ -0,0 +1,119 @@
+/*
+ * 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.commons.compress.archivers.zip;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Iterates over the bits of an InputStream. For each byte the bits
+ * are read from the right to the left.
+ *
+ * @since 1.7
+ */
+class BitStream {
+
+    private final InputStream in;
+
+    /** The bits read from the underlying stream but not consumed by nextBits() */
+    private long bitCache;
+
+    /** The number of bits available in the bit cache */
+    private int bitCacheSize;
+
+    /** Bit masks for extracting the right most bits from a byte */
+    private static final int[] MASKS = new int[]{ 
+            0x00, // 00000000
+            0x01, // 00000001
+            0x03, // 00000011
+            0x07, // 00000111
+            0x0F, // 00001111
+            0x1F, // 00011111
+            0x3F, // 00111111
+            0x7F, // 01111111
+            0xFF  // 11111111
+    };
+
+    BitStream(InputStream in) {
+        this.in = in;
+    }
+
+    private boolean fillCache() throws IOException {
+        boolean filled = false;
+        
+        while (bitCacheSize <= 56) {
+            long nextByte = in.read();
+            if (nextByte == -1) {
+                break;
+            }
+            
+            filled = true;
+            bitCache = bitCache | (nextByte << bitCacheSize);
+            bitCacheSize += 8;
+        }
+
+        return filled;
+    }
+
+    /**
+     * Returns the next bit.
+     * 
+     * @return The next bit (0 or 1) or -1 if the end of the stream has been reached
+     */
+    int nextBit() throws IOException {
+        if (bitCacheSize == 0) {
+            if (!fillCache()) {
+                return -1;
+            }
+        }
+
+        int bit = (int) (bitCache & 1); // extract the right most bit
+
+        bitCache = (bitCache >>> 1); // shift the remaning bits to the right
+        bitCacheSize--;
+
+        return bit;
+    }
+
+    /**
+     * Returns the integer value formed by the n next bits (up to 8 bits).
+     *
+     * @param n the number of bits read (up to 8)
+     * @return The value formed by the n bits, or -1 if the end of the stream has been reached
+     */
+    int nextBits(final int n) throws IOException {
+        if (bitCacheSize < n) {
+            if (!fillCache()) {
+                return -1;
+            }
+        }
+
+        final int bits = (int) (bitCache & MASKS[n]); // extract the right most bits
+
+        bitCache = (bitCache >>> n); // shift the remaning bits to the right
+        bitCacheSize = bitCacheSize - n;
+
+        return bits;
+    }
+
+    int nextByte() throws IOException {
+        return nextBits(8);
+    }
+}

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/BitStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/BitStream.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/CircularBuffer.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/CircularBuffer.java?rev=1552325&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/CircularBuffer.java (added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/CircularBuffer.java Thu Dec 19 16:09:54 2013
@@ -0,0 +1,89 @@
+/*
+ * 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.commons.compress.archivers.zip;
+
+/**
+ * Circular byte buffer.
+ * 
+ * @author Emmanuel Bourg
+ * @since 1.7
+ */
+class CircularBuffer {
+
+    /** Size of the buffer */
+    private final int size;
+    
+    /** The buffer */
+    private final byte[] buffer;
+
+    /** Index of the next data to be read from the buffer */
+    private int readIndex;
+
+    /** Index of the next data written in the buffer */
+    private int writeIndex;
+
+    CircularBuffer(int size) {
+        this.size = size;
+        buffer = new byte[size];
+    }
+
+    /**
+     * Tells if a new byte can be read from the buffer.
+     */
+    public boolean available() {
+        return readIndex != writeIndex;
+    }
+
+    /**
+     * Writes a byte to the buffer.
+     */
+    public void put(int value) {
+        buffer[writeIndex] = (byte) value;
+        writeIndex = (writeIndex + 1) % size;
+    }
+
+    /**
+     * Reads a byte from the buffer.
+     */
+    public int get() {
+        if (available()) {
+            int value = buffer[readIndex];
+            readIndex = (readIndex + 1) % size;
+            return value & 0xFF;
+        } else {
+            return -1;
+        }
+    }
+
+    /**
+     * Copy a previous interval in the buffer to the current position.
+     * 
+     * @param distance the distance from the current write position
+     * @param length   the number of bytes to copy
+     */
+    public void copy(int distance, int length) {
+        int pos1 = writeIndex - distance;
+        int pos2 = pos1 + length;
+        for (int i = pos1; i < pos2; i++) {
+            buffer[writeIndex] = buffer[(i + size) % size];
+            writeIndex = (writeIndex + 1) % size;
+        }
+    }
+}

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/CircularBuffer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/CircularBuffer.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ExplodingInputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ExplodingInputStream.java?rev=1552325&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ExplodingInputStream.java (added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ExplodingInputStream.java Thu Dec 19 16:09:54 2013
@@ -0,0 +1,158 @@
+/*
+ * 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.commons.compress.archivers.zip;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * The implode compression method was added to PKZIP 1.01 released in 1989.
+ * It was then dropped from PKZIP 2.0 released in 1993 in favor of the deflate
+ * method.
+ * <p>
+ * The algorithm is described in the ZIP File Format Specification.
+ * 
+ * @see <a href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">ZIP File Format Specification</a>
+ * 
+ * @author Emmanuel Bourg
+ * @since 1.7
+ */
+class ExplodingInputStream extends InputStream {
+
+    /** The underlying stream containing the compressed data */
+    private final InputStream in;
+    
+    /** The stream of bits read from the input stream */
+    private BitStream bits;
+
+    /** The size of the sliding dictionary (4K or 8K) */
+    private final int dictionarySize;
+
+    /** The number of Shannon-Fano trees (2 or 3) */
+    private final int numberOfTrees;
+
+    private final int minimumMatchLength;
+
+    /** The binary tree containing the 256 encoded literals (null when only two trees are used) */
+    private BinaryTree literalTree;
+
+    /** The binary tree containing the 64 encoded lengths */
+    private BinaryTree lengthTree;
+
+    /** The binary tree containing the 64 encoded distances */
+    private BinaryTree distanceTree;
+
+    /** Output buffer holding the decompressed data */
+    private final CircularBuffer buffer = new CircularBuffer(32 * 1024);
+
+    /**
+     * Create a new stream decompressing the content of the specified stream
+     * using the explode algorithm.
+     *
+     * @param dictionarySize the size of the sliding dictionary (4096 or 8192)
+     * @param numberOfTrees  the number of trees (2 or 3)
+     * @param in             the compressed data stream
+     */
+    public ExplodingInputStream(int dictionarySize, int numberOfTrees, InputStream in) {
+        if (dictionarySize != 4096 && dictionarySize != 8192) {
+            throw new IllegalArgumentException("The dictionary size must be 4096 or 8192");
+        }
+        if (numberOfTrees != 2 && numberOfTrees != 3) {
+            throw new IllegalArgumentException("The number of trees must be 2 or 3");
+        }
+        this.dictionarySize = dictionarySize;
+        this.numberOfTrees = numberOfTrees;
+        this.minimumMatchLength = numberOfTrees;
+        this.in = in;
+    }
+
+    /**
+     * Reads the encoded binary trees and prepares the bit stream.
+     * 
+     * @throws IOException
+     */
+    private void init() throws IOException {
+        if (bits == null) {
+            if (numberOfTrees == 3) {
+                literalTree = BinaryTree.decode(in, 256);
+            }
+
+            lengthTree = BinaryTree.decode(in, 64);
+            distanceTree = BinaryTree.decode(in, 64);
+            
+            bits = new BitStream(in);
+        }
+    }
+
+    @Override
+    public int read() throws IOException {
+        if (!buffer.available()) {
+            fillBuffer();
+        }
+
+        return buffer.get();
+    }
+
+    /**
+     * Fill the sliding dictionary with more data.
+     * @throws IOException
+     */
+    private void fillBuffer() throws IOException {
+        init();
+        
+        int bit = bits.nextBit();
+        if (bit == 1) {
+            // literal value
+            int literal;
+            if (literalTree != null) {
+                literal = literalTree.read(bits);
+            } else {
+                literal = bits.nextBits(8);
+            }
+
+            if (literal == -1) {
+                // end of stream reached, nothing left to decode
+                return;
+            }
+            
+            buffer.put(literal);
+
+        } else if (bit == 0) {
+            // back reference
+            int distanceLowSize = dictionarySize == 4096 ? 6 : 7;
+            int distanceLow = bits.nextBits(distanceLowSize);
+            int distanceHigh = distanceTree.read(bits);
+            if (distanceHigh == -1 && distanceLow <= 0) {
+                // end of stream reached, nothing left to decode
+                return;
+            }
+            int distance = distanceHigh << distanceLowSize | distanceLow;
+            
+            int length = lengthTree.read(bits);
+            if (length == 63) {
+                length += bits.nextBits(8);
+            }
+            length += minimumMatchLength;
+
+            buffer.copy(distance + 1, length);
+        }
+    }
+
+}

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ExplodingInputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ExplodingInputStream.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/GeneralPurposeBit.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/GeneralPurposeBit.java?rev=1552325&r1=1552324&r2=1552325&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/GeneralPurposeBit.java (original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/GeneralPurposeBit.java Thu Dec 19 16:09:54 2013
@@ -20,16 +20,36 @@ package org.apache.commons.compress.arch
 /**
  * Parser/encoder for the "general purpose bit" field in ZIP's local
  * file and central directory headers.
+ * 
  * @since 1.1
  * @NotThreadSafe
  */
 public final class GeneralPurposeBit {
+
     /**
      * Indicates that the file is encrypted.
      */
     private static final int ENCRYPTION_FLAG = 1 << 0;
 
     /**
+     * Indicates the size of the sliding dictionary used by the compression method 6 (imploding).
+     * <ul>
+     *   <li>0: 4096 bytes</li>
+     *   <li>1: 8192 bytes</li>
+     * </ul>
+     */
+    private static final int SLIDING_DICTIONARY_SIZE_FLAG = 1 << 1;
+
+    /**
+     * Indicates the number of Shannon-Fano trees used by the compression method 6 (imploding).
+     * <ul>
+     *   <li>0: 2 trees (lengths, distances)</li>
+     *   <li>1: 3 trees (literals, lengths, distances)</li>
+     * </ul>
+     */
+    private static final int NUMBER_OF_SHANNON_FANO_TREES_FLAG = 1 << 2;
+
+    /**
      * Indicates that a data descriptor stored after the file contents
      * will hold CRC and size information.
      */
@@ -53,6 +73,8 @@ public final class GeneralPurposeBit {
     private boolean dataDescriptorFlag = false;
     private boolean encryptionFlag = false;
     private boolean strongEncryptionFlag = false;
+    private int slidingDictionarySize;
+    private int numberOfShannonFanoTrees;
 
     public GeneralPurposeBit() {
     }
@@ -119,6 +141,20 @@ public final class GeneralPurposeBit {
     }
 
     /**
+     * Returns the sliding dictionary size used by the compression method 6 (imploding).
+     */
+    int getSlidingDictionarySize() {
+        return slidingDictionarySize;
+    }
+
+    /**
+     * Returns the number of trees used by the compression method 6 (imploding).
+     */
+    int getNumberOfShannonFanoTrees() {
+        return numberOfShannonFanoTrees;
+    }
+
+    /**
      * Encodes the set bits in a form suitable for ZIP archives.
      */
     public byte[] encode() {
@@ -135,6 +171,7 @@ public final class GeneralPurposeBit {
 
     /**
      * Parses the supported flags from the given archive data.
+     * 
      * @param data local file header or a central directory entry.
      * @param offset offset at which the general purpose bit starts
      */
@@ -143,9 +180,10 @@ public final class GeneralPurposeBit {
         GeneralPurposeBit b = new GeneralPurposeBit();
         b.useDataDescriptor((generalPurposeFlag & DATA_DESCRIPTOR_FLAG) != 0);
         b.useUTF8ForNames((generalPurposeFlag & UFT8_NAMES_FLAG) != 0);
-        b.useStrongEncryption((generalPurposeFlag & STRONG_ENCRYPTION_FLAG)
-                              != 0);
+        b.useStrongEncryption((generalPurposeFlag & STRONG_ENCRYPTION_FLAG) != 0);
         b.useEncryption((generalPurposeFlag & ENCRYPTION_FLAG) != 0);
+        b.slidingDictionarySize = ((generalPurposeFlag & SLIDING_DICTIONARY_SIZE_FLAG) != 0) ? 8192 : 4096;
+        b.numberOfShannonFanoTrees = ((generalPurposeFlag & NUMBER_OF_SHANNON_FANO_TREES_FLAG) != 0) ? 3 : 2;
         return b;
     }
 

Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java?rev=1552325&r1=1552324&r2=1552325&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java (original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java Thu Dec 19 16:09:54 2013
@@ -271,10 +271,16 @@ public class ZipArchiveInputStream exten
         }
 
         processZip64Extra(size, cSize);
-        
-        if (current.entry.getCompressedSize() != -1 
-                && current.entry.getMethod() == ZipMethod.UNSHRINKING.getCode()) {
-            current.in = new UnshrinkingInputStream(new BoundedInputStream(in, current.entry.getCompressedSize()));
+
+        if (current.entry.getCompressedSize() != -1) {
+            if (current.entry.getMethod() == ZipMethod.UNSHRINKING.getCode()) {
+                current.in = new UnshrinkingInputStream(new BoundedInputStream(in, current.entry.getCompressedSize()));
+            } else if (current.entry.getMethod() == ZipMethod.IMPLODING.getCode()) {
+                current.in = new ExplodingInputStream(
+                        current.entry.getGeneralPurposeBit().getSlidingDictionarySize(),
+                        current.entry.getGeneralPurposeBit().getNumberOfShannonFanoTrees(),
+                        new BoundedInputStream(in, current.entry.getCompressedSize()));
+            }
         }
         
         entriesRead++;
@@ -374,7 +380,8 @@ public class ZipArchiveInputStream exten
             read = readStored(buffer, offset, length);
         } else if (current.entry.getMethod() == ZipArchiveOutputStream.DEFLATED) {
             read = readDeflated(buffer, offset, length);
-        } else if (current.entry.getMethod() == ZipMethod.UNSHRINKING.getCode()) {
+        } else if (current.entry.getMethod() == ZipMethod.UNSHRINKING.getCode()
+                || current.entry.getMethod() == ZipMethod.IMPLODING.getCode()) {
             read = current.in.read(buffer, offset, length);
         } else {
             throw new UnsupportedZipFeatureException(ZipMethod.getMethodByCode(current.entry.getMethod()),

Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java?rev=1552325&r1=1552324&r2=1552325&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java (original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java Thu Dec 19 16:09:54 2013
@@ -741,7 +741,8 @@ public class ZipArchiveOutputStream exte
     @Override
     public boolean canWriteEntryData(ArchiveEntry ae) {
         if (ae instanceof ZipArchiveEntry) {
-            return ZipUtil.canHandleEntryData((ZipArchiveEntry) ae);
+            ZipArchiveEntry zae = (ZipArchiveEntry) ae;
+            return zae.getMethod() != ZipMethod.IMPLODING.getCode() && ZipUtil.canHandleEntryData(zae);
         }
         return false;
     }

Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java?rev=1552325&r1=1552324&r2=1552325&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java (original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java Thu Dec 19 16:09:54 2013
@@ -17,6 +17,7 @@
  */
 package org.apache.commons.compress.archivers.zip;
 
+import java.io.BufferedInputStream;
 import java.io.EOFException;
 import java.io.File;
 import java.io.IOException;
@@ -378,6 +379,9 @@ public class ZipFile {
                 return bis;
             case UNSHRINKING:
                 return new UnshrinkingInputStream(bis);
+            case IMPLODING:
+                return new ExplodingInputStream(ze.getGeneralPurposeBit().getSlidingDictionarySize(),
+                        ze.getGeneralPurposeBit().getNumberOfShannonFanoTrees(), new BufferedInputStream(bis));
             case DEFLATED:
                 bis.addDummy();
                 final Inflater inflater = new Inflater(true);

Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipUtil.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipUtil.java?rev=1552325&r1=1552324&r2=1552325&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipUtil.java (original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipUtil.java Thu Dec 19 16:09:54 2013
@@ -303,6 +303,7 @@ public abstract class ZipUtil {
     private static boolean supportsMethodOf(ZipArchiveEntry entry) {
         return entry.getMethod() == ZipEntry.STORED
             || entry.getMethod() == ZipMethod.UNSHRINKING.getCode()
+            || entry.getMethod() == ZipMethod.IMPLODING.getCode()
             || entry.getMethod() == ZipEntry.DEFLATED;
     }
 

Modified: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/ZipTestCase.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/ZipTestCase.java?rev=1552325&r1=1552324&r2=1552325&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/ZipTestCase.java (original)
+++ commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/ZipTestCase.java Thu Dec 19 16:09:54 2013
@@ -32,6 +32,7 @@ import org.apache.commons.compress.archi
 import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
 import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
 import org.apache.commons.compress.archivers.zip.ZipFile;
+import org.apache.commons.compress.archivers.zip.ZipMethod;
 import org.apache.commons.compress.utils.IOUtils;
 
 public final class ZipTestCase extends AbstractTestCase {
@@ -139,12 +140,16 @@ public final class ZipTestCase extends A
      * >COMPRESS-93</a>.
      */
     public void testSupportedCompressionMethod() throws IOException {
+        /*
         ZipFile bla = new ZipFile(getFile("bla.zip"));
         assertTrue(bla.canReadEntryData(bla.getEntry("test1.xml")));
         bla.close();
-
+        */
+        
         ZipFile moby = new ZipFile(getFile("moby.zip"));
-        assertFalse(moby.canReadEntryData(moby.getEntry("README")));
+        ZipArchiveEntry entry = moby.getEntry("README");
+        assertEquals("method", ZipMethod.TOKENIZATION.getCode(), entry.getMethod());
+        assertFalse(moby.canReadEntryData(entry));
         moby.close();
     }
 
@@ -162,6 +167,7 @@ public final class ZipTestCase extends A
             new ZipArchiveInputStream(new FileInputStream(getFile("moby.zip")));
         try {
             ZipArchiveEntry entry = zip.getNextZipEntry();
+            assertEquals("method", ZipMethod.TOKENIZATION.getCode(), entry.getMethod());
             assertEquals("README", entry.getName());
             assertFalse(zip.canReadEntryData(entry));
             try {

Added: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/BinaryTreeTest.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/BinaryTreeTest.java?rev=1552325&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/BinaryTreeTest.java (added)
+++ commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/BinaryTreeTest.java Thu Dec 19 16:09:54 2013
@@ -0,0 +1,47 @@
+/*
+ * 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.commons.compress.archivers.zip;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+
+public class BinaryTreeTest extends TestCase {
+
+    public void testDecode() throws IOException {
+        InputStream in = new ByteArrayInputStream(new byte[] { 0x02, 0x42, 0x01, 0x13 });
+        
+        BinaryTree tree = BinaryTree.decode(in, 8);
+        
+        assertNotNull(tree);
+        
+        BitStream stream = new BitStream(new ByteArrayInputStream(new byte[] { (byte) 0x8D, (byte) 0xC5, (byte) 0x11, 0x00 }));
+        assertEquals(0, tree.read(stream));
+        assertEquals(1, tree.read(stream));
+        assertEquals(2, tree.read(stream));
+        assertEquals(3, tree.read(stream));
+        assertEquals(4, tree.read(stream));
+        assertEquals(5, tree.read(stream));
+        assertEquals(6, tree.read(stream));
+        assertEquals(7, tree.read(stream));
+    }
+}

Propchange: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/BinaryTreeTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/BinaryTreeTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/BitStreamTest.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/BitStreamTest.java?rev=1552325&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/BitStreamTest.java (added)
+++ commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/BitStreamTest.java Thu Dec 19 16:09:54 2013
@@ -0,0 +1,82 @@
+/*
+ * 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.commons.compress.archivers.zip;
+
+import java.io.ByteArrayInputStream;
+
+import junit.framework.TestCase;
+
+public class BitStreamTest extends TestCase {
+
+    public void testEmptyStream() throws Exception {
+        BitStream stream = new BitStream(new ByteArrayInputStream(new byte[0]));
+        assertEquals("next bit", -1, stream.nextBit());
+        assertEquals("next bit", -1, stream.nextBit());
+        assertEquals("next bit", -1, stream.nextBit());
+    }
+
+    public void testStream() throws Exception {
+        BitStream stream = new BitStream(new ByteArrayInputStream(new byte[] { (byte) 0xEA, 0x03 }));
+
+        assertEquals("bit 0", 0, stream.nextBit());
+        assertEquals("bit 1", 1, stream.nextBit());
+        assertEquals("bit 2", 0, stream.nextBit());
+        assertEquals("bit 3", 1, stream.nextBit());
+        assertEquals("bit 4", 0, stream.nextBit());
+        assertEquals("bit 5", 1, stream.nextBit());
+        assertEquals("bit 6", 1, stream.nextBit());
+        assertEquals("bit 7", 1, stream.nextBit());
+
+        assertEquals("bit 8", 1, stream.nextBit());
+        assertEquals("bit 9", 1, stream.nextBit());
+        assertEquals("bit 10", 0, stream.nextBit());
+        assertEquals("bit 11", 0, stream.nextBit());
+        assertEquals("bit 12", 0, stream.nextBit());
+        assertEquals("bit 13", 0, stream.nextBit());
+        assertEquals("bit 14", 0, stream.nextBit());
+        assertEquals("bit 15", 0, stream.nextBit());
+        
+        assertEquals("next bit", -1, stream.nextBit());
+    }
+
+    public void testNextByteFromEmptyStream() throws Exception {
+        BitStream stream = new BitStream(new ByteArrayInputStream(new byte[0]));
+        assertEquals("next byte", -1, stream.nextByte());
+        assertEquals("next byte", -1, stream.nextByte());
+    }
+
+    public void testReadAlignedBytes() throws Exception {
+        BitStream stream = new BitStream(new ByteArrayInputStream(new byte[] { (byte) 0xEA, 0x35 }));
+        assertEquals("next byte", 0xEA, stream.nextByte());
+        assertEquals("next byte", 0x35, stream.nextByte());
+        assertEquals("next byte", -1, stream.nextByte());
+    }
+
+    public void testNextByte() throws Exception {
+        BitStream stream = new BitStream(new ByteArrayInputStream(new byte[] { (byte) 0xEA, 0x35 }));
+        assertEquals("bit 0", 0, stream.nextBit());
+        assertEquals("bit 1", 1, stream.nextBit());
+        assertEquals("bit 2", 0, stream.nextBit());
+        assertEquals("bit 3", 1, stream.nextBit());
+        
+        assertEquals("next byte", 0x5E, stream.nextByte());
+        assertEquals("next byte", -1, stream.nextByte()); // not enough bits left to read a byte
+    }
+}

Propchange: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/BitStreamTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/BitStreamTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/CircularBufferTest.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/CircularBufferTest.java?rev=1552325&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/CircularBufferTest.java (added)
+++ commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/CircularBufferTest.java Thu Dec 19 16:09:54 2013
@@ -0,0 +1,76 @@
+/*
+ * 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.commons.compress.archivers.zip;
+
+import junit.framework.TestCase;
+
+public class CircularBufferTest extends TestCase {
+
+    public void testPutAndGet() throws Exception {
+        int size = 16;
+        CircularBuffer buffer = new CircularBuffer(size);
+        for (int i = 0; i < size / 2; i++) {
+            buffer.put(i);
+        }
+
+        assertTrue("available", buffer.available());
+
+        for (int i = 0; i < size / 2; i++) {
+            assertEquals("buffer[" + i + "]", i, buffer.get());
+        }
+
+        assertEquals(-1, buffer.get());
+        assertFalse("available", buffer.available());
+    }
+
+    public void testCopy() throws Exception {
+        CircularBuffer buffer = new CircularBuffer(16);
+        
+        buffer.put(1);
+        buffer.put(2);
+        buffer.get();
+        buffer.get();
+        
+        // copy uninitialized data
+        buffer.copy(6, 8);
+        
+        for (int i = 2; i < 6; i++) {
+            assertEquals("buffer[" + i + "]", 0, buffer.get());
+        }
+        assertEquals("buffer[" + 6 + "]", 1, buffer.get());
+        assertEquals("buffer[" + 7 + "]", 2, buffer.get());
+        assertEquals("buffer[" + 8 + "]", 0, buffer.get());
+        assertEquals("buffer[" + 9 + "]", 0, buffer.get());
+        
+        for (int i = 10; i < 14; i++) {
+            buffer.put(i);
+            buffer.get();
+        }
+        
+        assertFalse("available", buffer.available());
+        
+        // copy data and wrap
+        buffer.copy(2, 8);
+        
+        for (int i = 14; i < 18; i++) {
+            assertEquals("buffer[" + i + "]", i % 2 == 0 ? 12 : 13, buffer.get());
+        }
+    }
+}

Propchange: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/CircularBufferTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/CircularBufferTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ExplodeSupportTest.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ExplodeSupportTest.java?rev=1552325&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ExplodeSupportTest.java (added)
+++ commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ExplodeSupportTest.java Thu Dec 19 16:09:54 2013
@@ -0,0 +1,85 @@
+/*
+ * 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.commons.compress.archivers.zip;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.CRC32;
+import java.util.zip.CheckedOutputStream;
+
+import junit.framework.TestCase;
+import org.apache.commons.compress.utils.BoundedInputStream;
+import org.apache.commons.compress.utils.IOUtils;
+
+public class ExplodeSupportTest extends TestCase {
+
+    private void testArchiveWithImplodeCompression(String filename, String entryName) throws IOException {
+        ZipFile zip = new ZipFile(new File(filename));
+        ZipArchiveEntry entry = zip.getEntries().nextElement();
+        assertEquals("entry name", entryName, entry.getName());
+        assertTrue("entry can't be read", zip.canReadEntryData(entry));
+        assertEquals("method", ZipMethod.IMPLODING.getCode(), entry.getMethod());
+
+        ByteArrayOutputStream bout = new ByteArrayOutputStream();
+        CheckedOutputStream out = new CheckedOutputStream(bout, new CRC32());
+        IOUtils.copy(zip.getInputStream(entry), out);
+
+        out.flush();
+
+        assertEquals("CRC32", entry.getCrc(), out.getChecksum().getValue());
+    }
+
+    public void testArchiveWithImplodeCompression4K2Trees() throws IOException {
+        testArchiveWithImplodeCompression("target/test-classes/archives/imploding-4Kdict-2trees.zip", "HEADER.TXT");
+    }
+
+    public void testArchiveWithImplodeCompression8K3Trees() throws IOException {
+        testArchiveWithImplodeCompression("target/test-classes/archives/imploding-8Kdict-3trees.zip", "LICENSE.TXT");
+    }
+
+    private void testZipStreamWithImplodeCompression(String filename, String entryName) throws IOException {
+        ZipArchiveInputStream zin = new ZipArchiveInputStream(new FileInputStream(new File(filename)));
+        ZipArchiveEntry entry = zin.getNextZipEntry();
+        assertEquals("entry name", entryName, entry.getName());
+        assertTrue("entry can't be read", zin.canReadEntryData(entry));
+        assertEquals("method", ZipMethod.IMPLODING.getCode(), entry.getMethod());
+
+        InputStream bio = new BoundedInputStream(zin, entry.getSize());
+        
+        ByteArrayOutputStream bout = new ByteArrayOutputStream();
+        CheckedOutputStream out = new CheckedOutputStream(bout, new CRC32());
+        IOUtils.copy(bio, out);
+
+        out.flush();
+
+        assertEquals("CRC32", entry.getCrc(), out.getChecksum().getValue());
+    }
+
+    public void testZipStreamWithImplodeCompression4K2Trees() throws IOException {
+        testZipStreamWithImplodeCompression("target/test-classes/archives/imploding-4Kdict-2trees.zip", "HEADER.TXT");
+    }
+
+    public void testZipStreamWithImplodeCompression8K3Trees() throws IOException {
+        testZipStreamWithImplodeCompression("target/test-classes/archives/imploding-8Kdict-3trees.zip", "LICENSE.TXT");
+    }
+}

Propchange: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ExplodeSupportTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ExplodeSupportTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/compress/trunk/src/test/resources/archives/imploding-4Kdict-2trees.zip
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/resources/archives/imploding-4Kdict-2trees.zip?rev=1552325&view=auto
==============================================================================
Binary file - no diff available.

Propchange: commons/proper/compress/trunk/src/test/resources/archives/imploding-4Kdict-2trees.zip
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: commons/proper/compress/trunk/src/test/resources/archives/imploding-8Kdict-3trees.zip
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/resources/archives/imploding-8Kdict-3trees.zip?rev=1552325&view=auto
==============================================================================
Binary file - no diff available.

Propchange: commons/proper/compress/trunk/src/test/resources/archives/imploding-8Kdict-3trees.zip
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Modified: commons/proper/compress/trunk/src/test/resources/moby.zip
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/resources/moby.zip?rev=1552325&r1=1552324&r2=1552325&view=diff
==============================================================================
Binary files - no diff available.



Mime
View raw message