Reputation: 39208
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
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