1

I've been debugging some jar-update snippets and I came across a zip/unzip combination that should be reversing the other, but when I tried it on a jar it failed even though all the files are present. Can anyone figure out where this is going wrong?

SSCCE (no need to compile): Download here!

package jarsscce;

import java.io.*;
import java.util.*;
import java.util.jar.*;
import java.util.zip.*;

public class JarSSCCE {

    public static void main(String[] args) throws IOException {
        File testJar = new File("test.jar");
        File testDir = new File("test");
        File jarPack = new File("packed_test.jar");

        unpack(testJar, testDir);
        jar(testDir, jarPack);
    }

    public static void jar(File directory, File zip) throws IOException {
        try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(zip))) {
            jar(directory, directory, jos);
        }
    }

    private static void jar(File directory, File base, JarOutputStream jos) throws IOException {
        File[] files = directory.listFiles();
        byte[] buffer = new byte[1 << 12];

        if (files.length == 0) {
            JarEntry entry = new JarEntry(directory.getPath().substring(base.getPath().length() + 1) + File.separator);
            jos.putNextEntry(entry);
        } else {

            for (int i = 0, n = files.length; i < n; i++) {
                if (files[i].isDirectory()) {
                    jar(files[i], base, jos);
                } else {
                    try (FileInputStream in = new FileInputStream(files[i])) {
                        JarEntry entry = new JarEntry(files[i].getPath().substring(base.getPath().length() + 1));
                        jos.putNextEntry(entry);

                        int read;
                        while ((read = in.read(buffer, 0, buffer.length)) != -1) {
                            jos.write(buffer, 0, read);
                        }
                        jos.closeEntry();
                    }
                }
            }
        }
    }

    public static void unpack(File zip, File extractTo) throws IOException {
        try (ZipFile archive = new ZipFile(zip)) {
            Enumeration e = archive.entries();
            while (e.hasMoreElements()) {
                ZipEntry entry = (ZipEntry) e.nextElement();
                File file = new File(extractTo, entry.getName());
                if (entry.isDirectory() && !file.exists()) {
                    file.mkdirs();
                } else {
                    if (!file.getParentFile().exists()) {
                        file.getParentFile().mkdirs();
                    }
                    try (InputStream in = archive.getInputStream(entry)) {
                        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
                        byte[] buffer = new byte[1 << 13];
                        int read;
                        while ((read = in.read(buffer)) != -1) {
                            out.write(buffer, 0, read);
                        }
                        out.close();
                    }
                }
            }
        }
    }
}

EDIT: Looking at the archive information via Winrar, I can see that the test.jar created by Netbeans is not compressed at all, and the one created by the program is. Also the "Host OS" and "Version to extract" values are different. Though I can't see how any of that would be significant.

rtheunissen
  • 7,347
  • 5
  • 34
  • 65

1 Answers1

2

I think I've found the problem, have a peak at this link: http://viralpatel.net/blogs/creating-zip-and-jar-files-in-java/. it talks about using entry.setMethod(ZipEntry.STORED) however we then have to create our own checksums etc but its all explained in the link.

Addendum:

Got it working by using a different zip() method:

import java.io.*;
import java.net.URI;
import java.util.Deque;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

public class Main {

    public static void main(String[] args) throws IOException {
        File testJar = new File("test.jar");
        File testDir = new File("test");
        File jarPack = new File("packed_test.jar");

        unpack(testJar, testDir);
        jar(testDir, jarPack);
    }

    public static void jar(File directory, File zipfile) throws IOException {
        URI base = directory.toURI();
        Deque<File> queue = new LinkedList<>();
        queue.push(directory);
        OutputStream out = new FileOutputStream(zipfile);
        Closeable res = out;
        try {
            ZipOutputStream zout = new ZipOutputStream(out);
            res = zout;
            while (!queue.isEmpty()) {
                directory = queue.pop();
                for (File kid : directory.listFiles()) {
                    String name = base.relativize(kid.toURI()).getPath();
                    if (kid.isDirectory()) {
                        queue.push(kid);
                        name = name.endsWith("/") ? name : name + "/";
                        zout.putNextEntry(new ZipEntry(name));
                    } else {
                        zout.putNextEntry(new ZipEntry(name));
                        copy(kid, zout);
                        zout.closeEntry();
                    }
                }
            }
        } finally {
            res.close();
        }
    }

    private static void copy(File file, OutputStream out) throws IOException {
        try (InputStream in = new FileInputStream(file)) {
            byte[] buffer = new byte[1024];
            while (true) {
                int readCount = in.read(buffer);
                if (readCount < 0) {
                    break;
                }
                out.write(buffer, 0, readCount);
            }
        }
    }

    public static void unpack(File zip, File extractTo) throws IOException {
        ZipFile archive = new ZipFile(zip);
        Enumeration e = archive.entries();
        while (e.hasMoreElements()) {
            ZipEntry entry = (ZipEntry) e.nextElement();
            File file = new File(extractTo, entry.getName());
            if (entry.isDirectory() && !file.exists()) {
                file.mkdirs();
            } else {
                if (!file.getParentFile().exists()) {
                    file.getParentFile().mkdirs();
                }
                BufferedOutputStream out;
                try (InputStream in = archive.getInputStream(entry)) {
                    out = new BufferedOutputStream(
                            new FileOutputStream(file));
                    byte[] buffer = new byte[8192];
                    int read;
                    while (-1 != (read = in.read(buffer))) {
                        out.write(buffer, 0, read);
                    }
                }
                out.close();
            }
        }
    }
}

All thanks to this question I found :) java.util.zip - Recreating directory structure

Community
  • 1
  • 1
David Kroukamp
  • 36,155
  • 13
  • 81
  • 138
  • That's my problem exactly - I must be missing some very small detail in the packaging using `JarOutputStream` that would allow a created jar to work. It annoys me how it's such a simple task and yet I'm sitting here for hours trying to figure it out. >. – rtheunissen Jul 27 '12 at 19:48
  • 1
    @paranoid-android Lol I know. Look at the output of the 2 jars in a text editor... They vary greatly in format. The zip method is doing something funny. I had a project of the same type a while back trying to find its code now – David Kroukamp Jul 27 '12 at 19:50
  • Cool thanks, let me know what you can find. I've been googling this for hours - can't believe I didn't find that post you linked. Though I just had an idea to create a wrapper around using the java jar tools, ie. `jar cf jarfile` etc. – rtheunissen Jul 27 '12 at 20:07
  • 1
    You're an absolute legend, David! This does however leave me wondering what went wrong with the other zip method? But I like this one and I think I'll keep it. Thanks again. +1 – rtheunissen Jul 28 '12 at 02:47
  • @paranoid-android :) Thanks and to be honest it must have been the format it was using to save it, maybe somehow that `JarOutputStream` was affecting it? Im not 100% positive though – David Kroukamp Jul 28 '12 at 14:57