commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bode...@apache.org
Subject svn commit: r1551026 - in /commons/proper/compress/trunk/src/main/java/org/apache/commons/compress: archivers/zip/UnshrinkingInputStream.java compressors/z/AbstractLZWInputStream.java compressors/z/ZCompressorInputStream.java
Date Sun, 15 Dec 2013 15:23:36 GMT
Author: bodewig
Date: Sun Dec 15 15:23:35 2013
New Revision: 1551026

URL: http://svn.apache.org/r1551026
Log:
reduce code duplication in the two LZW input streams

Added:
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/z/AbstractLZWInputStream.java
  (with props)
Modified:
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/UnshrinkingInputStream.java
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/z/ZCompressorInputStream.java

Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/UnshrinkingInputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/UnshrinkingInputStream.java?rev=1551026&r1=1551025&r2=1551026&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/UnshrinkingInputStream.java
(original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/UnshrinkingInputStream.java
Sun Dec 15 15:23:35 2013
@@ -21,84 +21,43 @@ package org.apache.commons.compress.arch
 import java.io.IOException;
 import java.io.InputStream;
 
-import org.apache.commons.compress.compressors.CompressorInputStream;
+import org.apache.commons.compress.compressors.z.AbstractLZWInputStream;
 
 /**
  * Input stream that decompresses ZIP method 1 (unshrinking). A variation of the LZW algorithm,
with some twists.
  * @NotThreadSafe
  * @since 1.7
  */
-class UnshrinkingInputStream extends CompressorInputStream {
-    private final InputStream in;
-    private final int clearCode;
-    private final int MAX_CODE_SIZE = 13;
-    private int codeSize = 9;
-    private int bitsCached = 0;
-    private int bitsCachedSize = 0;
-    private int previousCode = -1;
-    private int tableSize = 0;
-    private final int[] prefixes;
-    private final byte[] characters;
+class UnshrinkingInputStream extends AbstractLZWInputStream {
+    private static final int MAX_CODE_SIZE = 13;
+    private static final int MAX_TABLE_SIZE = 1 << MAX_CODE_SIZE;
     private final boolean[] isUsed;
-    private final byte[] outputStack;
-    private int outputStackLocation;
     
     public UnshrinkingInputStream(InputStream inputStream) throws IOException {
-        this.in = inputStream;
-        clearCode = (1 << (codeSize - 1));
-        final int maxTableSize = 1 << MAX_CODE_SIZE;
-        prefixes = new int[maxTableSize];
-        characters = new byte[maxTableSize];
-        isUsed = new boolean[maxTableSize];
-        outputStack = new byte[maxTableSize];
-        outputStackLocation = maxTableSize;
+        super(inputStream);
+        setClearCode(codeSize);
+        initializeTables(MAX_CODE_SIZE);
+        isUsed = new boolean[prefixes.length];
         for (int i = 0; i < (1 << 8); i++) {
-            prefixes[i] = -1;
-            characters[i] = (byte)i;
             isUsed[i] = true;
         }
         tableSize = clearCode + 1;
     }
-    
-    public void close() throws IOException {
-        in.close();
-    }
-    
-    private int readNextCode() throws IOException {
-        while (bitsCachedSize < codeSize) {
-            final int nextByte = in.read();
-            if (nextByte < 0) {
-                return nextByte;
-            }
-            bitsCached |= (nextByte << bitsCachedSize);
-            bitsCachedSize += 8;
-        }
-        final int mask = (1 << codeSize) - 1;
-        final int code = (bitsCached & mask);
-        bitsCached >>>= codeSize;
-        bitsCachedSize -= codeSize;
-        return code;
-    }
-    
-    private int addEntry(int previousCode, byte character) throws IOException {
-        final int maxTableSize = 1 << MAX_CODE_SIZE;
-        while ((tableSize < maxTableSize) && isUsed[tableSize]) {
+
+    @Override
+    protected int addEntry(int previousCode, byte character) throws IOException {
+        while ((tableSize < MAX_TABLE_SIZE) && isUsed[tableSize]) {
             tableSize++;
         }
-        if (tableSize < maxTableSize) {
-            final int index = tableSize;
-            prefixes[tableSize] = previousCode;
-            characters[tableSize] = character;
-            isUsed[tableSize] = true;
-            tableSize++;
-            return index;
-        } else {
-            return -1;
+        int idx = addEntry(previousCode, character, MAX_TABLE_SIZE);
+        if (idx >= 0) {
+            isUsed[idx] = true;
         }
+        return idx;
     }
     
     private void partialClear() throws IOException {
-        final boolean[] isParent = new boolean[1 << MAX_CODE_SIZE];
+        final boolean[] isParent = new boolean[MAX_TABLE_SIZE];
         for (int i = 0; i < isUsed.length; i++) {
             if (isUsed[i] && prefixes[i] != -1) {
                 isParent[prefixes[i]] = true;
@@ -112,7 +71,8 @@ class UnshrinkingInputStream extends Com
         }
     }
 
-    private int decompressNextSymbol() throws IOException {
+    @Override
+    protected int decompressNextSymbol() throws IOException {
         //
         //                   table entry    table entry
         //                  _____________   _____
@@ -147,76 +107,12 @@ class UnshrinkingInputStream extends Com
             return 0;
         } else {
             boolean addedUnfinishedEntry = false;
-            final int effectiveCode;
-            if (isUsed[code]) {
-                effectiveCode = code;
-            } else {
-                // must be a repeat of the previous entry we haven't added yet
-                if (previousCode == -1) {
-                    // ... which isn't possible for the very first code
-                    throw new IOException("The first code can't be a reference to its preceding
code");
-                }
-                byte firstCharacter = 0;
-                for (int last = previousCode; last >= 0; last = prefixes[last]) {
-                    firstCharacter = characters[last];
-                }
-                effectiveCode = addEntry(previousCode, firstCharacter);
+            int effectiveCode = code;
+            if (!isUsed[code]) {
+                effectiveCode = addRepeatOfPreviousCode();
                 addedUnfinishedEntry = true;
             }
-            for (int entry = effectiveCode; entry >= 0; entry = prefixes[entry]) {
-                outputStack[--outputStackLocation] = characters[entry];
-            }
-            if (previousCode != -1 && !addedUnfinishedEntry) {
-                addEntry(previousCode, outputStack[outputStackLocation]);
-            }
-            previousCode = code;
-            return outputStackLocation;
-        }
-    }
-    
-    public int read() throws IOException {
-        byte[] b = new byte[1];
-        int ret;
-        while ((ret = read(b)) == 0) {
-        }
-        if (ret < 0) {
-            return ret;
-        }
-        return 0xff & b[0];
-    }
-    
-    public int read(byte[] b, int off, int len) throws IOException {
-        int bytesRead = 0;
-        int remainingInStack = outputStack.length - outputStackLocation;
-        if (remainingInStack > 0) {
-            int maxLength = Math.min(remainingInStack, len);
-            System.arraycopy(outputStack, outputStackLocation, b, off, maxLength);
-            outputStackLocation += maxLength;
-            off += maxLength;
-            len -= maxLength;
-            bytesRead += maxLength;
-        }
-        while (len > 0) {
-            int result = decompressNextSymbol();
-            if (result < 0) {
-                if (bytesRead > 0) {
-                    count(bytesRead);
-                    return bytesRead;
-                } else {
-                    return result;
-                }
-            }
-            remainingInStack = outputStack.length - outputStackLocation;
-            if (remainingInStack > 0) {
-                int maxLength = Math.min(remainingInStack, len);
-                System.arraycopy(outputStack, outputStackLocation, b, off, maxLength);
-                outputStackLocation += maxLength;
-                off += maxLength;
-                len -= maxLength;
-                bytesRead += maxLength;
-            }
+            return expandCodeToOutputStack(effectiveCode, addedUnfinishedEntry);
         }
-        count(bytesRead);
-        return bytesRead;
     }
 }

Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/z/AbstractLZWInputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/z/AbstractLZWInputStream.java?rev=1551026&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/z/AbstractLZWInputStream.java
(added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/z/AbstractLZWInputStream.java
Sun Dec 15 15:23:35 2013
@@ -0,0 +1,201 @@
+/*
+ * 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.compressors.z;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.compress.compressors.CompressorInputStream;
+
+/**
+ * Base-class for traditional Unix ".Z" compression and the
+ * Unshrinking method of ZIP archive.
+ * @NotThreadSafe
+ * @since 1.7
+ */
+public abstract class AbstractLZWInputStream extends CompressorInputStream {
+    private final byte[] oneByte = new byte[1];
+
+    protected final InputStream in;
+    protected int clearCode = -1;
+    protected int codeSize = 9;
+    protected int bitsCached = 0;
+    protected int bitsCachedSize = 0;
+    protected int previousCode = -1;
+    protected int tableSize = 0;
+    protected int[] prefixes;
+    protected byte[] characters;
+    private byte[] outputStack;
+    private int outputStackLocation;
+
+    public AbstractLZWInputStream(InputStream inputStream) throws IOException {
+        this.in = inputStream;
+    }
+
+    @Override
+    public void close() throws IOException {
+        in.close();
+    }
+    
+    @Override
+    public int read() throws IOException {
+        int ret;
+        while ((ret = read(oneByte)) == 0) { // NOPMD
+        }
+        if (ret < 0) {
+            return ret;
+        }
+        return 0xff & oneByte[0];
+    }
+    
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        int bytesRead = 0;
+        int remainingInStack = outputStack.length - outputStackLocation;
+        if (remainingInStack > 0) {
+            int maxLength = Math.min(remainingInStack, len);
+            System.arraycopy(outputStack, outputStackLocation, b, off, maxLength);
+            outputStackLocation += maxLength;
+            off += maxLength;
+            len -= maxLength;
+            bytesRead += maxLength;
+        }
+        while (len > 0) {
+            int result = decompressNextSymbol();
+            if (result < 0) {
+                if (bytesRead > 0) {
+                    count(bytesRead);
+                    return bytesRead;
+                } else {
+                    return result;
+                }
+            }
+            remainingInStack = outputStack.length - outputStackLocation;
+            if (remainingInStack > 0) {
+                int maxLength = Math.min(remainingInStack, len);
+                System.arraycopy(outputStack, outputStackLocation, b, off, maxLength);
+                outputStackLocation += maxLength;
+                off += maxLength;
+                len -= maxLength;
+                bytesRead += maxLength;
+            }
+        }
+        count(bytesRead);
+        return bytesRead;
+    }
+
+    /**
+     * Read the next code and expand it.
+     */
+    protected abstract int decompressNextSymbol() throws IOException;
+
+    /**
+     * Add a new entry to the dictionary.
+     */
+    protected abstract int addEntry(int previousCode, byte character)
+        throws IOException;
+
+    /**
+     * Sets the clear code based on the code size.
+     */
+    protected void setClearCode(int codeSize) {
+        clearCode = (1 << (codeSize - 1));
+    }
+
+    /**
+     * Initializes the arrays based on the maximum code size.
+     */
+    protected void initializeTables(int maxCodeSize) {
+        final int maxTableSize = 1 << maxCodeSize;
+        prefixes = new int[maxTableSize];
+        characters = new byte[maxTableSize];
+        outputStack = new byte[maxTableSize];
+        outputStackLocation = maxTableSize;
+        final int max = 1 << 8;
+        for (int i = 0; i < max; i++) {
+            prefixes[i] = -1;
+            characters[i] = (byte) i;
+        }
+    }
+
+    /**
+     * Reads the next code from the stream.
+     */
+    protected int readNextCode() throws IOException {
+        while (bitsCachedSize < codeSize) {
+            final int nextByte = in.read();
+            if (nextByte < 0) {
+                return nextByte;
+            }
+            bitsCached |= (nextByte << bitsCachedSize);
+            bitsCachedSize += 8;
+        }
+        final int mask = (1 << codeSize) - 1;
+        final int code = (bitsCached & mask);
+        bitsCached >>>= codeSize;
+        bitsCachedSize -= codeSize;
+        return code;
+    }
+    
+    /**
+     * Adds a new entry if the maximum table size hasn't been exceeded
+     * and returns the new index.
+     */
+    protected int addEntry(int previousCode, byte character, int maxTableSize) {
+        if (tableSize < maxTableSize) {
+            final int index = tableSize;
+            prefixes[tableSize] = previousCode;
+            characters[tableSize] = character;
+            tableSize++;
+            return index;
+        }
+        return -1;
+    }
+
+    /**
+     * Add entry for repeat of previousCode we haven't added, yet.
+     */
+    protected int addRepeatOfPreviousCode() throws IOException {
+        if (previousCode == -1) {
+            // can't have a repeat for the very first code
+            throw new IOException("The first code can't be a reference to its preceding code");
+        }
+        byte firstCharacter = 0;
+        for (int last = previousCode; last >= 0; last = prefixes[last]) {
+            firstCharacter = characters[last];
+        }
+        return addEntry(previousCode, firstCharacter);
+    }
+
+    /**
+     * Expands the entry with index code to the output stack and may
+     * create a new entry
+     */
+    protected int expandCodeToOutputStack(int code, boolean addedUnfinishedEntry)
+        throws IOException {
+        for (int entry = code; entry >= 0; entry = prefixes[entry]) {
+            outputStack[--outputStackLocation] = characters[entry];
+        }
+        if (previousCode != -1 && !addedUnfinishedEntry) {
+            addEntry(previousCode, outputStack[outputStackLocation]);
+        }
+        previousCode = code;
+        return outputStackLocation;
+    }
+}

Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/z/AbstractLZWInputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/z/ZCompressorInputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/z/ZCompressorInputStream.java?rev=1551026&r1=1551025&r2=1551026&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/z/ZCompressorInputStream.java
(original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/z/ZCompressorInputStream.java
Sun Dec 15 15:23:35 2013
@@ -21,35 +21,22 @@ package org.apache.commons.compress.comp
 import java.io.IOException;
 import java.io.InputStream;
 
-import org.apache.commons.compress.compressors.CompressorInputStream;
-
 /**
  * Input stream that decompresses .Z files.
  * @NotThreadSafe
  * @since 1.7
  */
-public class ZCompressorInputStream extends CompressorInputStream {
+public class ZCompressorInputStream extends AbstractLZWInputStream {
     private static final int MAGIC_1 = 0x1f;
     private static final int MAGIC_2 = 0x9d;
     private static final int BLOCK_MODE_MASK = 0x80;
     private static final int MAX_CODE_SIZE_MASK = 0x1f;
-    private final InputStream in;
     private final boolean blockMode;
-    private final int clearCode;
     private final int maxCodeSize;
-    private int codeSize = 9;
-    private int bitsCached = 0;
-    private int bitsCachedSize = 0;
     private long totalCodesRead = 0;
-    private int previousCode = -1;
-    private int tableSize = 0;
-    private final int[] prefixes;
-    private final byte[] characters;
-    private final byte[] outputStack;
-    private int outputStackLocation;
     
     public ZCompressorInputStream(InputStream inputStream) throws IOException {
-        this.in = inputStream;
+        super(inputStream);
         int firstByte = in.read();
         int secondByte = in.read();
         int thirdByte = in.read();
@@ -59,26 +46,12 @@ public class ZCompressorInputStream exte
         blockMode = ((thirdByte & BLOCK_MODE_MASK) != 0);
         maxCodeSize = thirdByte & MAX_CODE_SIZE_MASK;
         if (blockMode) {
-            clearCode = (1 << (codeSize - 1));
-        } else {
-            clearCode = -1; // unused
-        }
-        final int maxTableSize = 1 << maxCodeSize;
-        prefixes = new int[maxTableSize];
-        characters = new byte[maxTableSize];
-        outputStack = new byte[maxTableSize];
-        outputStackLocation = maxTableSize;
-        for (int i = 0; i < (1 << 8); i++) {
-            prefixes[i] = -1;
-            characters[i] = (byte)i;
+            setClearCode(codeSize);
         }
+        initializeTables(maxCodeSize);
         clearEntries();
     }
     
-    public void close() throws IOException {
-        in.close();
-    }
-    
     private void clearEntries() {
         tableSize = (1 << 8);
         if (blockMode) {
@@ -86,20 +59,12 @@ public class ZCompressorInputStream exte
         }
     }
 
-    private int readNextCode() throws IOException {
-        while (bitsCachedSize < codeSize) {
-            final int nextByte = in.read();
-            if (nextByte < 0) {
-                return nextByte;
-            }
-            bitsCached |= (nextByte << bitsCachedSize);
-            bitsCachedSize += 8;
+    @Override
+    protected int readNextCode() throws IOException {
+        int code = super.readNextCode();
+        if (code >= 0) {
+            ++totalCodesRead;
         }
-        final int mask = (1 << codeSize) - 1;
-        final int code = (bitsCached & mask);
-        bitsCached >>>= codeSize;
-        bitsCachedSize -= codeSize;
-        ++totalCodesRead;
         return code;
     }
     
@@ -119,22 +84,19 @@ public class ZCompressorInputStream exte
         bitsCachedSize = 0;
     }
     
-    private void addEntry(int previousCode, byte character) throws IOException {
+    @Override
+    protected int addEntry(int previousCode, byte character) throws IOException {
         final int maxTableSize = 1 << codeSize;
-        if (tableSize < maxTableSize) {
-            prefixes[tableSize] = previousCode;
-            characters[tableSize] = character;
-            tableSize++;
-        }
-        if (tableSize == maxTableSize) {
-            if (codeSize < maxCodeSize) {
-                reAlignReading();
-                codeSize++;
-            }
+        int r = addEntry(previousCode, character, maxTableSize);
+        if (tableSize == maxTableSize && codeSize < maxCodeSize) {
+            reAlignReading();
+            codeSize++;
         }
+        return r;
     }
 
-    private int decompressNextSymbol() throws IOException {
+    @Override
+    protected int decompressNextSymbol() throws IOException {
         //
         //                   table entry    table entry
         //                  _____________   _____
@@ -159,74 +121,13 @@ public class ZCompressorInputStream exte
         } else {
             boolean addedUnfinishedEntry = false;
             if (code == tableSize) {
-                // must be a repeat of the previous entry we haven't added yet
-                if (previousCode == -1) {
-                    // ... which isn't possible for the very first code
-                    throw new IOException("The first code can't be a reference to its preceding
code");
-                }
-                byte firstCharacter = 0;
-                for (int last = previousCode; last >= 0; last = prefixes[last]) {
-                    firstCharacter = characters[last];
-                }
-                addEntry(previousCode, firstCharacter);
+                addRepeatOfPreviousCode();
                 addedUnfinishedEntry = true;
             } else if (code > tableSize) {
                 throw new IOException(String.format("Invalid %d bit code 0x%x", codeSize,
code));
             }
-            for (int entry = code; entry >= 0; entry = prefixes[entry]) {
-                outputStack[--outputStackLocation] = characters[entry];
-            }
-            if (previousCode != -1 && !addedUnfinishedEntry) {
-                addEntry(previousCode, outputStack[outputStackLocation]);
-            }
-            previousCode = code;
-            return outputStackLocation;
-        }
-    }
-    
-    public int read() throws IOException {
-        byte[] b = new byte[1];
-        int ret;
-        while ((ret = read(b)) == 0) {
+            return expandCodeToOutputStack(code, addedUnfinishedEntry);
         }
-        if (ret < 0) {
-            return ret;
-        }
-        return 0xff & b[0];
     }
     
-    public int read(byte[] b, int off, int len) throws IOException {
-        int bytesRead = 0;
-        int remainingInStack = outputStack.length - outputStackLocation;
-        if (remainingInStack > 0) {
-            int maxLength = Math.min(remainingInStack, len);
-            System.arraycopy(outputStack, outputStackLocation, b, off, maxLength);
-            outputStackLocation += maxLength;
-            off += maxLength;
-            len -= maxLength;
-            bytesRead += maxLength;
-        }
-        while (len > 0) {
-            int result = decompressNextSymbol();
-            if (result < 0) {
-                if (bytesRead > 0) {
-                    count(bytesRead);
-                    return bytesRead;
-                } else {
-                    return result;
-                }
-            }
-            remainingInStack = outputStack.length - outputStackLocation;
-            if (remainingInStack > 0) {
-                int maxLength = Math.min(remainingInStack, len);
-                System.arraycopy(outputStack, outputStackLocation, b, off, maxLength);
-                outputStackLocation += maxLength;
-                off += maxLength;
-                len -= maxLength;
-                bytesRead += maxLength;
-            }
-        }
-        count(bytesRead);
-        return bytesRead;
-    }
 }



Mime
View raw message