Backport alternative class reading method for invalid class CRCs
@@ -6,6 +6,7 @@ import java.io.*;
import java.nio.file.Path;
import java.util.*;
import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
@@ -34,22 +35,50 @@ public class JarResource extends ArchiveResource {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
EntryLoader loader = getEntryLoader();
+
+ try {
ZipInputStream zis = new ZipInputStream(new FileInputStream(getPath().toFile()));
ZipEntry entry;
+
while ((entry = zis.getNextEntry()) != null) {
// verify entries are classes and valid files
// - skip intentional garbage / zip file abnormalities
if (shouldSkip(entry.getName()))
continue;
- if (loader.isValidClassEntry(entry)) {
+ if (!loader.isValidClassEntry(entry))
+ continue;
+
out.reset();
byte[] in = IOUtil.toByteArray(zis, out, buffer);
+
// There is no possible way a "class" under 30 bytes is valid
if (in.length < 30)
continue;
+
+ loader.onClass(entry.getName(), in);
+ }
+ } catch (ZipException e) {
+ if (e.getMessage().contains("invalid entry CRC")) {
+ // "ZipFile"/"JarFile" reads the entire ZIP file structure before letting us do any entry parsing.
+ // This may not always be ideal, but this way has one major bonus. It totally ignores CRC validity.
+ // It also ignores a few other zip entry values.
+ // Since somebody can intentionally write bogus data there to crash "ZipInputStream" this way works.
+ ZipFile zf = new ZipFile(getPath().toString());
+ Enumeration<? extends ZipEntry> entries = zf.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+
+ if (shouldSkip(entry.getName()))
+ continue;
+ if (!loader.isValidClassEntry(entry))
+ continue;
+
+ InputStream zis = zf.getInputStream(entry);
+ byte[] in = IOUtil.toByteArray(zis);
loader.onClass(entry.getName(), in);
}
}
+ }
loader.finishClasses();
return loader.getClasses();
}
