2

I'm trying to create a method that melds several zip archives into eachother in just one step. The code is looking very good and it should work. But when I run it I get a really strange exception:

java.lang.RuntimeException: Unexpected java.util.zip.ZipException ("invalid entry compressed size (expected 1506 but got 1507 bytes)")
(only duplicate entry execptions are expected!)
    at io.brainstone.github.installer.FileUtils.makeNewZipFromInputStreamList(FileUtils.java:309)
    at io.brainstone.github.installer.Main.startInstalling(Main.java:224)
    at io.brainstone.github.installer.Window$3$1.run(Window.java:183)
Caused by: java.util.zip.ZipException: invalid entry compressed size (expected 1506 but got 1507 bytes)
    at java.util.zip.ZipOutputStream.closeEntry(Unknown Source)
    at java.util.zip.ZipOutputStream.putNextEntry(Unknown Source)
    at io.brainstone.github.installer.FileUtils.makeNewZipFromInputStreamList(FileUtils.java:300)
    ... 2 more

The exception is thrown by my own code. This tells me that an unexpected exception occured. Only duplicate entry exceptions are expected. (This is a trick I use for my entry override. Meaning the archive that is last in the list has the highest priority owning a file)

To clear things up, this is my code:

    public static void makeNewZipFromInputStreamList(File outputFile,
            ArrayList<InputStream> inputStreamList,
            ArrayList<String> includeList, ArrayList<String> excludeList)
            throws IOException, IllegalArgumentException {
        final int sizeOfLists[] = new int[] { inputStreamList.size(),
                includeList.size(), excludeList.size() };

        if ((sizeOfLists[0] != sizeOfLists[1])
                || (sizeOfLists[0] != sizeOfLists[2])
                || (sizeOfLists[1] != sizeOfLists[2]))
            throw new IllegalArgumentException(
                    "The ArrayLists do not have the same size ("
                            + sizeOfLists[0] + ", " + sizeOfLists[1] + ", "
                            + sizeOfLists[2] + ")");

        final ZipOutputStream zipOutputFile = new ZipOutputStream(
                new FileOutputStream(outputFile));

        final int size = sizeOfLists[0];
        final InputStream inputStreamTempArray[] = inputStreamList
                .toArray(new InputStream[size]);
        final String includeArray[] = includeList.toArray(new String[size]);
        final String excludeArray[] = excludeList.toArray(new String[size]);
        final ZipInputStream inputStreamArray[] = new ZipInputStream[size];

        HashMap<String, Object[]> tmp;

        int i, j;
        String fileName;
        ZipEntry entry;

        for (i = size - 1; i >= 0; i--) {
            inputStreamArray[i] = new ZipInputStream(inputStreamTempArray[i]);

            if (includeArray[i] == null) {
                includeArray[i] = "";
            }

            if (excludeArray[i] == null) {
                excludeArray[i] = "";
            }

            while ((entry = inputStreamArray[i].getNextEntry()) != null) {
                fileName = entry.getName();

                if (fileName.matches(includeArray[i])
                        || !fileName.matches(excludeArray[i])) {
                    try {
                        zipOutputFile.putNextEntry(entry); // Here is the inital exception thrown!

                        if (!entry.isDirectory()) {
                            copyStream(inputStreamArray[i], zipOutputFile,
                                    false, false);
                        }
                    } catch (ZipException ex) {
                        if (!ex.getMessage()
                                .matches("duplicate entry: .*\\..*")) {
                            throw new RuntimeException(
                                    "Unexpected "
                                            + ex.getClass().getName()
                                            + " (\""
                                            + ex.getMessage()
                                            + "\")\n(only duplicate entry execptions are expected!)",
                                    ex);
                        }
                    }
                }
            }

            inputStreamArray[i].close();
        }

        zipOutputFile.close();
    }
BrainStone
  • 3,028
  • 6
  • 32
  • 59
  • Does this happen for a some specific entry or all of them? – Miserable Variable Aug 06 '13 at 17:29
  • I happens for the most enrties. Which is some kind of strange. (If I would not throw the exception here it would just do it for most of the other files) – BrainStone Aug 06 '13 at 17:31
  • @JimGarrison This solution does not work for me. This guy is using JarEntry. I am using ZipEntry. When I use `new ZipEntry(entry.getName())` I get a `NullPointerException` caused by that line! – BrainStone Aug 06 '13 at 17:47
  • Consider to use Automatic Resource Management to close your streams. – Puce Aug 06 '13 at 17:57
  • If most but not all entries get the error you might be able to identify the difference between them that causes this behavior. – Miserable Variable Aug 06 '13 at 18:07
  • That will be a different problem. If you debug to that point can you figure out what's null? Is it the name? If so the input zip has a problem. – Jim Garrison Aug 06 '13 at 18:59
  • @JimGarrison It worked! I just haddn't thought about that `getNextEntry()` will return null at some point! – BrainStone Aug 06 '13 at 19:46
  • @BrainStone - You should re-examine your implementation. You have a lot of unnecessary copying of list data to arrays going on, and I'm not sure your "include" and "exclude" lists will work the way you seem to think they will. You should probably be using `Map`s for those. – Jim Garrison Aug 06 '13 at 20:27

1 Answers1

1

If you're using Java SE 7, consider to use the NIO.2 File API.

Note, that I've written some utility methods to copy directories to and from Zip files using the NIO.2 File API (the library is Open Source):

Maven:

<dependency>  
    <groupId>org.softsmithy.lib</groupId>  
    <artifactId>softsmithy-lib-core</artifactId>  
    <version>0.3</version>  
</dependency>  

Tutorial:

http://softsmithy.sourceforge.net/lib/current/docs/tutorial/nio-file/index.html

Puce
  • 37,247
  • 13
  • 80
  • 152
  • I'm not adding directories to the inital zip. I add other zips. But I will have a look at it once a quick solution is not in sight since besides that error everything else works! – BrainStone Aug 06 '13 at 17:31
  • My point is, in terms of the NIO.2 API, the root of a zip file is also a directory. A Zip is just another FileSystem: http://docs.oracle.com/javase/7/docs/api/java/nio/file/FileSystem.html#getRootDirectories%28%29 – Puce Aug 06 '13 at 17:43