Commit d125357b authored by Phillip Webb's avatar Phillip Webb

Protect against JARs with different local headers

Fix JarEntryData to re-read the local header, rather than relying on
the central directory record.

This protects against the situation where a JAR file is written with an
'Extra Field Length' that is different in the local header to the
central directory header.

This appears to be the case with aspectj 1.7.4 which contains the
following central directory file header for ProceedingJoinPoint:

	50 4B 01 02     signature
	14 03           version made by
	0A 00           version required
	00 00           general
	08 00           compress methods
	0E 40 59 43     last modified
	2D 59 20 70     crc
	EC 00 00 00     csize
	8D 01 00 00     size
	2A 00           fname len
	00 00           ext field len
	00 00           file comment len
	00 00           disk num
	00 00           int file att
	00 00 A4 81     ext file att
	97 F3 00 00     relative offset of the local file header
	...             file name

and the following local header:

	50 4B 03 04     signature
	0A 00           version required
	00 00           general
	08 00           compress method
	0E 40 59 43     last modified
	2D 59 20 70     crc
	EC 00 00 00     csize
	8D 01 00 00     size
	2A 00           fname len
	14 00           ext field len
	...             file name
	...             extra field

Note that the 'ext field len' is 0x00 in the central record but 0x14 in
the local record.

Fixes gh-203
parent 47da8a81
......@@ -47,7 +47,7 @@ public final class JarEntryData {
private final AsciiBytes comment;
private long dataOffset;
private long localHeaderOffset;
private RandomAccessData data;
......@@ -66,10 +66,7 @@ public final class JarEntryData {
this.extra = Bytes.get(inputStream, extraLength);
this.comment = new AsciiBytes(Bytes.get(inputStream, commentLength));
this.dataOffset = Bytes.littleEndianValue(header, 42, 4);
this.dataOffset += LOCAL_FILE_HEADER_SIZE;
this.dataOffset += this.name.length();
this.dataOffset += this.extra.length;
this.localHeaderOffset = Bytes.littleEndianValue(header, 42, 4);
}
void setName(AsciiBytes name) {
......@@ -88,10 +85,18 @@ public final class JarEntryData {
return inputStream;
}
RandomAccessData getData() {
RandomAccessData getData() throws IOException {
if (this.data == null) {
this.data = this.source.getData().getSubsection(this.dataOffset,
getCompressedSize());
// aspectjrt-1.7.4.jar has a different ext bytes length in the
// local directory to the central directory. We need to re-read
// here to skip them
byte[] localHeader = Bytes.get(this.source.getData().getSubsection(
this.localHeaderOffset, LOCAL_FILE_HEADER_SIZE));
long nameLength = Bytes.littleEndianValue(localHeader, 26, 2);
long extraLength = Bytes.littleEndianValue(localHeader, 28, 2);
this.data = this.source.getData().getSubsection(
this.localHeaderOffset + LOCAL_FILE_HEADER_SIZE + nameLength
+ extraLength, getCompressedSize());
}
return this.data;
}
......
......@@ -35,7 +35,7 @@ class ZipInflaterInputStream extends InflaterInputStream {
private int available;
public ZipInflaterInputStream(InputStream inputStream, int size) {
super(inputStream, new Inflater(true), 512);
super(inputStream, new Inflater(true), getInflaterBufferSize(size));
this.available = size;
}
......@@ -72,4 +72,11 @@ class ZipInflaterInputStream extends InflaterInputStream {
}
}
private static int getInflaterBufferSize(long size) {
size += 2; // inflater likes some space
size = (size > 65536 ? 8192 : size);
size = (size <= 0 ? 4096 : size);
return (int) size;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment