Skip to content

Commit 808c4ad

Browse files
committed
fix: Improve detection of jvmBaseFileOffset in JvmZipReaderStrategy
1 parent af2549e commit 808c4ad

File tree

3 files changed

+43
-30
lines changed

3 files changed

+43
-30
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>software.coley</groupId>
88
<artifactId>lljzip</artifactId>
9-
<version>1.1.5</version>
9+
<version>1.1.6</version>
1010

1111
<properties>
1212
<junit.version>5.8.2</junit.version>

src/main/java/software/coley/llzip/part/CentralDirectoryFileHeader.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -453,9 +453,9 @@ public String toString() {
453453
", internalFileAttributes=" + internalFileAttributes +
454454
", externalFileAttributes=" + externalFileAttributes +
455455
", relativeOffsetOfLocalHeader=" + relativeOffsetOfLocalHeader +
456-
", fileName='" + fileName + '\'' +
456+
", fileName='" + ByteDataUtil.toString(fileName) + '\'' +
457457
", extraField=" + ByteDataUtil.toString(extraField) +
458-
", fileComment='" + fileComment + '\'' +
458+
", fileComment='" + ByteDataUtil.toString(fileComment) + '\'' +
459459
'}';
460460
}
461461

src/main/java/software/coley/llzip/strategy/JvmZipReaderStrategy.java

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -36,62 +36,75 @@ public void read(ZipArchive zip, ByteData data) throws IOException {
3636
long endOfCentralDirectoryOffset = ByteDataUtil.lastIndexOf(data, ZipPatterns.END_OF_CENTRAL_DIRECTORY);
3737
if (endOfCentralDirectoryOffset < 0L)
3838
throw new IOException("No Central-Directory-File-Header found!");
39+
// Read end header
40+
EndOfCentralDirectory end = new EndOfCentralDirectory();
41+
end.read(data, endOfCentralDirectoryOffset);
42+
zip.getParts().add(end);
43+
// Read central directories
44+
long len = data.length();
45+
long centralDirectoryOffset = len - ZipPatterns.CENTRAL_DIRECTORY_FILE_HEADER.length;
46+
while (centralDirectoryOffset > 0L) {
47+
centralDirectoryOffset = ByteDataUtil.lastIndexOf(data, centralDirectoryOffset - 1L, ZipPatterns.CENTRAL_DIRECTORY_FILE_HEADER);
48+
if (centralDirectoryOffset >= 0L) {
49+
CentralDirectoryFileHeader directory = new CentralDirectoryFileHeader();
50+
directory.read(data, centralDirectoryOffset);
51+
zip.getParts().add(directory);
52+
}
53+
}
3954
// Determine base offset for computing file header locations with.
4055
// - If there is a preceding block of another zip, start with that.
41-
long jvmBaseOffset;
56+
long jvmBaseFileOffset;
4257
long precedingEndOfCentralDirectory = ByteDataUtil.lastIndexOf(data, endOfCentralDirectoryOffset - 1, ZipPatterns.END_OF_CENTRAL_DIRECTORY);
4358
if (precedingEndOfCentralDirectory == endOfCentralDirectoryOffset) {
4459
// The prior end part match is target end part, so we can't use it as a base offset.
45-
jvmBaseOffset = 0L;
60+
jvmBaseFileOffset = 0L;
4661
} else if (precedingEndOfCentralDirectory == -1L) {
4762
// There was no match for a prior end part. We will seek forwards until finding a *VALID* PK starting header.
48-
jvmBaseOffset = ByteDataUtil.indexOf(data, ZipPatterns.PK);
49-
while (jvmBaseOffset >= 0L) {
63+
jvmBaseFileOffset = ByteDataUtil.indexOf(data, ZipPatterns.PK);
64+
while (jvmBaseFileOffset >= 0L) {
5065
// Check that the PK discovered represents a valid zip part
5166
try {
52-
if (ByteDataUtil.startsWith(data, jvmBaseOffset, ZipPatterns.LOCAL_FILE_HEADER))
53-
new LocalFileHeader().read(data, jvmBaseOffset);
54-
else if (ByteDataUtil.startsWith(data, jvmBaseOffset, ZipPatterns.CENTRAL_DIRECTORY_FILE_HEADER))
55-
new CentralDirectoryFileHeader().read(data, jvmBaseOffset);
67+
if (ByteDataUtil.startsWith(data, jvmBaseFileOffset, ZipPatterns.LOCAL_FILE_HEADER))
68+
new LocalFileHeader().read(data, jvmBaseFileOffset);
69+
else if (ByteDataUtil.startsWith(data, jvmBaseFileOffset, ZipPatterns.CENTRAL_DIRECTORY_FILE_HEADER))
70+
new CentralDirectoryFileHeader().read(data, jvmBaseFileOffset);
71+
else
72+
throw new IllegalStateException("No match for LocalFileHeader/CentralDirectoryFileHeader");
5673
// Valid, we're good to go
5774
break;
5875
} catch (Exception ex) {
5976
// Invalid, seek forward
60-
jvmBaseOffset = ByteDataUtil.indexOf(data, jvmBaseOffset+1L, ZipPatterns.PK);
77+
jvmBaseFileOffset = ByteDataUtil.indexOf(data, jvmBaseFileOffset + 1L, ZipPatterns.PK);
6178
}
6279
}
6380
} else {
81+
// TODO: Double check 'precedingEndOfCentralDirectory' points to a EndOfCentralDirectory that isn't bogus
82+
// like some shit defined as a fake comment in another ZipPart
83+
6484
// There was a prior end part, so we will seek past it's length and use that as the base offset.
65-
// 22 is the minimum possible size of an end part. It can be longer with comments applied, but there are almost never comments.
66-
jvmBaseOffset = precedingEndOfCentralDirectory + 22L;
67-
}
68-
// Read end header
69-
EndOfCentralDirectory end = new EndOfCentralDirectory();
70-
end.read(data, endOfCentralDirectoryOffset);
71-
zip.getParts().add(end);
72-
// Read central directories
73-
long len = data.length();
74-
long centralDirectoryOffset = len - ZipPatterns.CENTRAL_DIRECTORY_FILE_HEADER.length;
75-
while (centralDirectoryOffset > 0L) {
76-
centralDirectoryOffset = ByteDataUtil.lastIndexOf(data, centralDirectoryOffset - 1L, ZipPatterns.CENTRAL_DIRECTORY_FILE_HEADER);
77-
if (centralDirectoryOffset >= 0L) {
78-
CentralDirectoryFileHeader directory = new CentralDirectoryFileHeader();
79-
directory.read(data, centralDirectoryOffset);
80-
zip.getParts().add(directory);
85+
try {
86+
// Make sure it isn't bogus before we use it as a reference point
87+
EndOfCentralDirectory tempEnd = new EndOfCentralDirectory();
88+
tempEnd.read(data, precedingEndOfCentralDirectory);
89+
jvmBaseFileOffset = precedingEndOfCentralDirectory + tempEnd.length();
90+
} catch (Exception ex) {
91+
// It's bogus and the sig-match was a coincidence. Zero out the offset.
92+
jvmBaseFileOffset = 0;
8193
}
8294
}
8395
// Read local files
8496
// - Set to prevent duplicate file header entries for the same offset
8597
Set<Long> offsets = new HashSet<>();
8698
TreeSet<Long> lfhOffsets = new TreeSet<>();
8799
for (CentralDirectoryFileHeader directory : zip.getCentralDirectories()) {
88-
long offset = jvmBaseOffset + directory.getRelativeOffsetOfLocalHeader();
100+
long offset = jvmBaseFileOffset + directory.getRelativeOffsetOfLocalHeader();
89101
if (ByteDataUtil.startsWith(data, offset, ZipPatterns.LOCAL_FILE_HEADER)) {
90102
lfhOffsets.add(offset);
91103
}
92104
}
93105
for (CentralDirectoryFileHeader directory : zip.getCentralDirectories()) {
94-
long offset = jvmBaseOffset + directory.getRelativeOffsetOfLocalHeader();
106+
long relative = directory.getRelativeOffsetOfLocalHeader();
107+
long offset = jvmBaseFileOffset + relative;
95108
if (!offsets.contains(offset) && ByteDataUtil.startsWith(data, offset, ZipPatterns.LOCAL_FILE_HEADER)) {
96109
try {
97110
JvmLocalFileHeader file = new JvmLocalFileHeader(lfhOffsets);

0 commit comments

Comments
 (0)