Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #1843 (java.util.zip.ZipException in HttpZipLocator) #1842

Merged
merged 4 commits into from
Aug 15, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import java.util.HashMap;
Expand Down Expand Up @@ -80,14 +80,9 @@ public class HttpZipLocator implements AssetLocator {
private int tableLength;
private HashMap<String, ZipEntry2> entries;

private static final ByteBuffer byteBuf = ByteBuffer.allocate(250);
private static final CharBuffer charBuf = CharBuffer.allocate(250);
private static final CharsetDecoder utf8Decoder;

static {
Charset utf8 = Charset.forName("UTF-8");
utf8Decoder = utf8.newDecoder();
}
private final ByteBuffer byteBuf = ByteBuffer.allocate(250);
private final CharBuffer charBuf = CharBuffer.allocate(250);
private final CharsetDecoder utf8Decoder = StandardCharsets.UTF_8.newDecoder();

private static class ZipEntry2 {
String name;
Expand All @@ -96,6 +91,10 @@ private static class ZipEntry2 {
int compSize;
long crc;
boolean deflate;
// These fields will be fetched later from local file header,
// once asset requested.
Integer nameLength;
Integer extraLength;

@Override
public String toString(){
Expand Down Expand Up @@ -125,7 +124,7 @@ private static long getu32(byte[] b, int off) throws IOException{
(((long)(b[off]&0xff)) << 24);
}

private static String getUTF8String(byte[] b, int off, int len) throws CharacterCodingException {
private String getUTF8String(byte[] b, int off, int len) throws CharacterCodingException {
StringBuilder sb = new StringBuilder();

int read = 0;
Expand All @@ -143,7 +142,7 @@ private static String getUTF8String(byte[] b, int off, int len) throws Character
byteBuf.flip();

// decode data in byteBuf
CoderResult result = utf8Decoder.decode(byteBuf, charBuf, endOfInput);
CoderResult result = utf8Decoder.decode(byteBuf, charBuf, endOfInput);

// If the result is not an underflow, it's an error
// that cannot be handled.
Expand Down Expand Up @@ -234,10 +233,6 @@ private int readTableEntry(byte[] table, int offset) throws IOException{
entry.compSize = get32(table, offset + ZipEntry.CENSIZ);
entry.offset = get32(table, offset + ZipEntry.CENOFF);

// We want the offset in the file data:
// move the offset forward to skip the LOC header.
entry.offset += ZipEntry.LOCHDR + nameLen + extraLen;

entries.put(entry.name, entry);

return newOffset;
Expand All @@ -256,16 +251,15 @@ private void fillByteArray(byte[] array, InputStream source) throws IOException{
}

private void readCentralDirectory() throws IOException{
InputStream in = readData(tableOffset, tableLength);
byte[] header = new byte[tableLength];

// Fix for "PK12 bug in town.zip": sometimes
// not entire byte array will be read with InputStream.read()
// (especially for big headers)
fillByteArray(header, in);
try (InputStream in = readData(tableOffset, tableLength)) {
// Fix for "PK12 bug in town.zip": sometimes
// not entire byte array will be read with InputStream.read()
// (especially for big headers)
fillByteArray(header, in);

// in.read(header);
in.close();
}

entries = new HashMap<String, ZipEntry2>(numEntries);
int offset = 0;
Expand All @@ -292,10 +286,10 @@ private void readEndHeader() throws IOException{
// In that case, we have to search for it.
// Increase search space to 200 bytes

InputStream in = readData(Integer.MAX_VALUE, 200);
byte[] header = new byte[200];
fillByteArray(header, in);
in.close();
try (InputStream in = readData(Integer.MAX_VALUE, 200)) {
fillByteArray(header, in);
}

int offset = -1;
for (int i = 200 - 22; i >= 0; i--){
Expand Down Expand Up @@ -323,9 +317,23 @@ public void load(URL url) throws IOException {
readCentralDirectory();
}

private InputStream openStream(ZipEntry2 entry) throws IOException{
InputStream in = readData(entry.offset, entry.compSize);
if (entry.deflate){
private InputStream openStream(ZipEntry2 entry) throws IOException {
if (entry.nameLength == null && entry.extraLength == null) {
// Need to fetch local file header to obtain file name length
// and extra field length.
try (InputStream in = readData(entry.offset, ZipEntry.LOCHDR)) {
byte[] localHeader = new byte[ZipEntry.LOCHDR];
in.read(localHeader);
entry.nameLength = get16(localHeader, ZipEntry.LOCNAM);
entry.extraLength = get16(localHeader, ZipEntry.LOCEXT);
}
}

// We want the offset in the file data:
// move the offset forward to skip the LOC header.
int fileDataOffset = entry.offset + ZipEntry.LOCHDR + entry.nameLength + entry.extraLength;
InputStream in = readData(fileDataOffset, entry.compSize);
if (entry.deflate) {
return new InflaterInputStream(in, new Inflater(true));
}
return in;
Expand Down