You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by da...@apache.org on 2013/05/16 21:20:23 UTC

svn commit: r1483525 - in /commons/proper/compress/trunk/src/main/java/org/apache/commons/compress: archivers/sevenz/SevenZFile.java utils/CRC32VerifyingInputStream.java

Author: damjan
Date: Thu May 16 19:20:23 2013
New Revision: 1483525

URL: http://svn.apache.org/r1483525
Log:
Add support for archive header decompression/decryption.
Streams that filter should extend FilterInputStream.


Modified:
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/utils/CRC32VerifyingInputStream.java

Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java?rev=1483525&r1=1483524&r2=1483525&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java (original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java Thu May 16 19:20:23 2013
@@ -21,6 +21,7 @@ import java.io.ByteArrayInputStream;
 import java.io.DataInput;
 import java.io.DataInputStream;
 import java.io.File;
+import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.RandomAccessFile;
@@ -39,13 +40,13 @@ import org.apache.commons.compress.utils
  * encryption types, but at the moment only
  * only Copy, LZMA2, BZIP2, and AES-256 + SHA-256
  * are supported, and archive header compression
- * (which always uses the unsupported LZMA
+ * (when it uses the unsupported LZMA
  * compression) isn't. So the only archives
  * that can be read are the following:
  * <pre>
- * 7z a -mhc=off -mx=0 [-ppassword] archive.7z files
- * 7z a -mhc=off -m0=LZMA2 [-ppassword] archive.7z files
- * 7z a -mhc=off -m0=BZIP2 [-ppassword] archive.7z files
+ * 7z a -mhc=off [-mhe=on] -mx=0 [-ppassword] archive.7z files
+ * 7z a -mhc=off [-mhe=on] -m0=LZMA2 [-ppassword] archive.7z files
+ * 7z a -mhc=off [-mhe=on] -m0=BZIP2 [-ppassword] archive.7z files
  * </pre>
  * <p>
  * The format is very Windows/Intel specific,
@@ -81,8 +82,9 @@ public class SevenZFile {
         (byte)'7', (byte)'z', (byte)0xBC, (byte)0xAF, (byte)0x27, (byte)0x1C
     };
     
-    public SevenZFile(final File filename) throws IOException {
+    public SevenZFile(final File filename, final String password) throws IOException {
         boolean succeeded = false;
+        this.password = password;
         this.file = new RandomAccessFile(filename, "r");
         try {
             archive = readHeaders();
@@ -94,9 +96,8 @@ public class SevenZFile {
         }
     }
     
-    public SevenZFile(final File filename, final String password) throws IOException {
-        this(filename);
-        this.password = password;
+    public SevenZFile(final File filename) throws IOException {
+        this(filename, null);
     }
 
     public void close() {
@@ -165,17 +166,21 @@ public class SevenZFile {
             throw new IOException("NextHeader CRC mismatch");
         }
         
-        final Archive archive = new Archive();
         final ByteArrayInputStream byteStream = new ByteArrayInputStream(nextHeader);
-        final DataInputStream nextHeaderInputStream = new DataInputStream(
+        DataInputStream nextHeaderInputStream = new DataInputStream(
                 byteStream);
+        Archive archive = new Archive();
         int nid = nextHeaderInputStream.readUnsignedByte();
         if (nid == NID.kEncodedHeader) {
-            readEncodedHeader(nextHeaderInputStream, archive);
+            nextHeaderInputStream = readEncodedHeader(nextHeaderInputStream, archive);
+            // Archive gets rebuilt with the new header
+            archive = new Archive();
             nid = nextHeaderInputStream.readUnsignedByte();
         }
         if (nid == NID.kHeader) {
             readHeader(nextHeaderInputStream, archive);
+        } else {
+            throw new IOException("Broken or unsupported archive: no Header");
         }
         return archive;
     }
@@ -240,14 +245,41 @@ public class SevenZFile {
         }
     }
     
-    private void readEncodedHeader(final DataInputStream header, final Archive archive) throws IOException {
+    private DataInputStream readEncodedHeader(final DataInputStream header, final Archive archive) throws IOException {
         debug("EncodedHeader");
 
         readStreamsInfo(header, archive);
         
-        // FIXME: and decompress it etc.
+        // FIXME: merge with buildDecodingStream()/buildDecoderStack() at some stage?
+        final Folder folder = archive.folders[0];
+        final int firstPackStreamIndex = 0;
+        final long folderOffset = SIGNATURE_HEADER_SIZE + archive.packPos +
+                0;
+        
+        file.seek(folderOffset);
+        InputStream inputStreamStack = new BoundedRandomAccessFileInputStream(file,
+                archive.packSizes[firstPackStreamIndex]);
+        for (final Coder coder : folder.coders) {
+            if (coder.numInStreams != 1 || coder.numOutStreams != 1) {
+                throw new IOException("Multi input/output stream coders are not yet supported");
+            }
+            inputStreamStack = Coders.addDecoder(inputStreamStack, coder, password);
+        }
+        if (folder.hasCrc) {
+            inputStreamStack = new CRC32VerifyingInputStream(inputStreamStack,
+                    folder.getUnpackSize(), folder.crc);
+        }
+        final byte[] nextHeader = new byte[(int)folder.getUnpackSize()];
+        final DataInputStream nextHeaderInputStream = new DataInputStream(inputStreamStack);
+        try {
+            nextHeaderInputStream.readFully(nextHeader);
+        } finally {
+            nextHeaderInputStream.close();
+        }
+        return new DataInputStream(new ByteArrayInputStream(nextHeader));
+
         
-        throw new IOException("LZMA compression unsupported, so files with compressed header cannot be read");
+        //throw new IOException("LZMA compression unsupported, so files with compressed header cannot be read");
         // FIXME: this extracts the header to an LZMA file which can then be
         // manually decompressed.
 //        long offset = SIGNATURE_HEADER_SIZE + archive.packPos;
@@ -895,12 +927,11 @@ public class SevenZFile {
         return value;
     }
     
-    private static class BoundedInputStream extends InputStream {
-        private InputStream is;
+    private static class BoundedInputStream extends FilterInputStream {
         private long bytesRemaining;
         
-        public BoundedInputStream(final InputStream is, final long size) {
-            this.is = is;
+        public BoundedInputStream(final InputStream in, final long size) {
+            super(in);
             bytesRemaining = size;
         }
         
@@ -908,7 +939,7 @@ public class SevenZFile {
         public int read() throws IOException {
             if (bytesRemaining > 0) {
                 --bytesRemaining;
-                return is.read();
+                return in.read();
             } else {
                 return -1;
             }
@@ -923,7 +954,7 @@ public class SevenZFile {
             if (bytesToRead > bytesRemaining) {
                 bytesToRead = (int) bytesRemaining;
             }
-            final int bytesRead = is.read(b, off, bytesToRead);
+            final int bytesRead = in.read(b, off, bytesToRead);
             if (bytesRead >= 0) {
                 bytesRemaining -= bytesRead;
             }

Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/utils/CRC32VerifyingInputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/utils/CRC32VerifyingInputStream.java?rev=1483525&r1=1483524&r2=1483525&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/utils/CRC32VerifyingInputStream.java (original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/utils/CRC32VerifyingInputStream.java Thu May 16 19:20:23 2013
@@ -17,18 +17,18 @@
  */
 package org.apache.commons.compress.utils;
 
+import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.zip.CRC32;
 
-public class CRC32VerifyingInputStream extends InputStream {
-    private final InputStream is;
+public class CRC32VerifyingInputStream extends FilterInputStream {
     private long bytesRemaining;
     private final int expectedCrc32;
     private final CRC32 crc32 = new CRC32();
     
-    public CRC32VerifyingInputStream(final InputStream is, final long size, final int expectedCrc32) {
-        this.is = is;
+    public CRC32VerifyingInputStream(final InputStream in, final long size, final int expectedCrc32) {
+        super(in);
         this.expectedCrc32 = expectedCrc32;
         this.bytesRemaining = size;
     }
@@ -38,7 +38,7 @@ public class CRC32VerifyingInputStream e
         if (bytesRemaining <= 0) {
             return -1;
         }
-        int ret = is.read();
+        int ret = in.read();
         if (ret >= 0) {
             crc32.update(ret);
             --bytesRemaining;
@@ -56,7 +56,7 @@ public class CRC32VerifyingInputStream e
 
     @Override
     public int read(byte[] b, int off, int len) throws IOException {
-        int ret = is.read(b, off, len);
+        int ret = in.read(b, off, len);
         if (ret >= 0) {
             crc32.update(b, off, ret);
             bytesRemaining -= ret;
@@ -79,6 +79,6 @@ public class CRC32VerifyingInputStream e
 
     @Override
     public void close() throws IOException {
-        is.close();
+        in.close();
     }
 }