Daniel Trebbien
Daniel Trebbien

Reputation: 39208

Is it possible for ZipEntry.getCrc() to be incorrect without an exception occurring?

I am using Java's ZIP archive APIs in the java.util.zip package. Some code that I am looking at in Apache NetBeans' source repository calculates the CRC32 of every entry in a ZIP archive being read using the following routine:

private long computeCRC32(InputStream is) throws IOException {
    byte[] buf = new byte[4096];
    CRC32 crc32 = new CRC32();
    int read;
    while ((read = is.read(buf)) != -1) {
        crc32.update(buf, 0, read);
    }
    return crc32.getValue();
}

This routine is called once for each ZIP entry:

File f = new File("a.zip");
try (ZipFile zipFile = new ZipFile(f)) {
    Enumeration<? extends ZipEntry> entries = zipFile.entries();
    while (entries.hasMoreElements()) {
        ZipEntry entry = entries.nextElement();
        long crc;
        try (InputStream is = zipFile.getInputStream(entry)) {
            crc = computeCRC32(is);
        }
        // do something with `crc'
    }
}

I am wondering if it would be better to simply call ZipEntry.getCrc() (if it returns something other than -1) rather than call computeCRC32().

One concern I have is that if the ZIP archive is malformed, getCrc() might return an incorrect value.

Is it possible for ZipEntry.getCrc() to return a value other than -1, and other than what computeCRC32() would calculate, for some ZIP entry, and to fully read through the malformed ZIP archive without any exception occurring?

UPDATE I used a hex editor to alter the CRC32 stored in a local file header of a test ZIP archive. Running my test program, I did not observe an exception, but getCrc() returned the correct CRC32 rather than the altered value.

For reference, here is my test program:

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

public class ZipCrcTest {

    public static void main(String[] args) throws IOException {
        File f = new File("a.zip");
        try (ZipFile zipFile = new ZipFile(f)) {
            Enumeration<? extends ZipEntry> entries = zipFile.entries();
            while (entries.hasMoreElements()) {
                ZipEntry entry = entries.nextElement();
                long crc;
                try (InputStream is = zipFile.getInputStream(entry)) {
                    crc = computeCRC32(is);
                }
                System.out.printf("%s %x (computed %x)\n", entry.getName(), entry.getCrc(), crc);
                if (entry.getCrc() != -1L && entry.getCrc() != crc) {
                    System.err.printf("Crc different for %s!\n", entry.getName());
                }
            }
        }
    }

    private static long computeCRC32(InputStream is) throws IOException {
        byte[] buf = new byte[4096];
        CRC32 crc32 = new CRC32();
        int read;
        while ((read = is.read(buf)) != -1) {
            crc32.update(buf, 0, read);
        }
        return crc32.getValue();
    }
}

Upvotes: 0

Views: 538

Answers (1)

Daniel Trebbien
Daniel Trebbien

Reputation: 39208

It turns out that the answer is "Yes".

When I similarly altered the copy of the zip entry's CRC32 in the central directory portion of the ZIP archive, getCrc() returned the altered value and no exception was thrown.

Upvotes: 1

Related Questions