Author: bodewig
Date: Fri Dec 20 12:13:11 2013
New Revision: 1552608

URL: http://svn.apache.org/r1552608
Log:
COMPRESS-252 off-by-one error writing bitsets that leads to corrupt 7z headers

Modified:
    
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZOutputFile.java
    
commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZOutputFileTest.java

Modified: 
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZOutputFile.java
URL: 
http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZOutputFile.java?rev=1552608&r1=1552607&r2=1552608&view=diff
==============================================================================
--- 
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZOutputFile.java
 (original)
+++ 
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZOutputFile.java
 Fri Dec 20 12:13:11 2013
@@ -636,14 +636,13 @@ public class SevenZOutputFile {
         int shift = 7;
         for (int i = 0; i < length; i++) {
             cache |= ((bits.get(i) ? 1 : 0) << shift);
-            --shift;
-            if (shift == 0) {
+            if (--shift < 0) {
                 header.write(cache);
                 shift = 7;
                 cache = 0;
             }
         }
-        if (length > 0 && shift > 0) {
+        if (shift != 7) {
             header.write(cache);
         }
     }

Modified: 
commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZOutputFileTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZOutputFileTest.java?rev=1552608&r1=1552607&r2=1552608&view=diff
==============================================================================
--- 
commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZOutputFileTest.java
 (original)
+++ 
commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZOutputFileTest.java
 Fri Dec 20 12:13:11 2013
@@ -171,4 +171,113 @@ public class SevenZOutputFileTest extend
         }
     }
 
+    public void testSixEmptyFiles() throws Exception {
+        testCompress252(6, 0);
+    }
+
+    public void testSixFilesSomeNotEmpty() throws Exception {
+        testCompress252(6, 2);
+    }
+
+    public void testSevenEmptyFiles() throws Exception {
+        testCompress252(7, 0);
+    }
+
+    public void testSevenFilesSomeNotEmpty() throws Exception {
+        testCompress252(7, 2);
+    }
+
+    public void testEightEmptyFiles() throws Exception {
+        testCompress252(8, 0);
+    }
+
+    public void testEightFilesSomeNotEmpty() throws Exception {
+        testCompress252(8, 2);
+    }
+
+    public void testNineEmptyFiles() throws Exception {
+        testCompress252(9, 0);
+    }
+
+    public void testNineFilesSomeNotEmpty() throws Exception {
+        testCompress252(9, 2);
+    }
+
+    private void testCompress252(int numberOfFiles, int numberOfNonEmptyFiles)
+        throws Exception {
+        int nonEmptyModulus = numberOfNonEmptyFiles != 0
+            ? numberOfFiles / numberOfNonEmptyFiles
+            : numberOfFiles + 1;
+        output = new File(dir, "COMPRESS252-" + numberOfFiles + "-" + 
numberOfNonEmptyFiles + ".7z");
+        SevenZOutputFile archive = new SevenZOutputFile(output);
+        try {
+            addDir(archive);
+            for (int i = 0; i < numberOfFiles; i++) {
+                addFile(archive, i, (i + 1) % nonEmptyModulus == 0);
+            }
+        } finally {
+            archive.close();
+        }
+        verifyCompress252(output, numberOfFiles, numberOfNonEmptyFiles);
+    }
+
+    private void verifyCompress252(File output, int numberOfFiles, int 
numberOfNonEmptyFiles)
+        throws Exception {
+        SevenZFile archive = new SevenZFile(output);
+        int filesFound = 0;
+        int nonEmptyFilesFound = 0;
+        try {
+            verifyDir(archive);
+            Boolean b = verifyFile(archive, filesFound++);
+            while (b != null) {
+                if (Boolean.TRUE.equals(b)) {
+                    nonEmptyFilesFound++;
+                }
+                b = verifyFile(archive, filesFound++);
+            }
+        } finally {
+            archive.close();
+        }
+        assertEquals(numberOfFiles + 1, filesFound);
+        assertEquals(numberOfNonEmptyFiles, nonEmptyFilesFound);
+    }
+
+    private void addDir(SevenZOutputFile archive) throws Exception {
+        SevenZArchiveEntry entry = archive.createArchiveEntry(dir, "foo/");
+        archive.putArchiveEntry(entry);
+        archive.closeArchiveEntry();
+    }
+
+    private void verifyDir(SevenZFile archive) throws Exception {
+        SevenZArchiveEntry entry = archive.getNextEntry();
+        assertNotNull(entry);
+        assertEquals("foo/", entry.getName());
+        assertTrue(entry.isDirectory());
+    }
+
+    private void addFile(SevenZOutputFile archive, int index, boolean nonEmpty)
+        throws Exception {
+        SevenZArchiveEntry entry = new SevenZArchiveEntry();
+        entry.setName("foo/" + index + ".txt");
+        archive.putArchiveEntry(entry);
+        archive.write(nonEmpty ? new byte[] { 17 } : new byte[0]);
+        archive.closeArchiveEntry();
+    }
+
+    private Boolean verifyFile(SevenZFile archive, int index) throws Exception 
{
+        SevenZArchiveEntry entry = archive.getNextEntry();
+        if (entry == null) {
+            return null;
+        }
+        assertEquals("foo/" + index + ".txt", entry.getName());
+        assertEquals(false, entry.isDirectory());
+        if (entry.getSize() == 0) {
+            return false;
+        }
+        assertEquals(1, entry.getSize());
+        assertEquals(17, archive.read());
+        assertEquals(-1, archive.read());
+        return true;
+    }
+
 }


Reply via email to