Skip to content

Commit 26aaeaf

Browse files
committed
Allow simple detection of mismatched values between local file header and central directory header
Provide docs explaining how to resolve the issue as well
1 parent 3bf9c17 commit 26aaeaf

File tree

5 files changed

+41
-15
lines changed

5 files changed

+41
-15
lines changed

src/main/java/software/coley/llzip/format/model/CentralDirectoryFileHeader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ public void setCrc32(int crc32) {
206206
* Be aware that these attributes can be falsified.
207207
* Different zip-parsing programs treat the files differently
208208
* and may not adhere to what you expect from the zip specification.
209-
* <br>
209+
* <p>
210210
* When in doubt, trust {@code data.length()} from {@link LocalFileHeader#getFileData()}.
211211
*
212212
* @return Compressed size of {@link LocalFileHeader#getFileData()}.

src/main/java/software/coley/llzip/format/model/LocalFileHeader.java

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package software.coley.llzip.format.model;
22

3-
import software.coley.llzip.format.compression.ZipCompressions;
43
import software.coley.llzip.format.compression.Decompressor;
4+
import software.coley.llzip.format.compression.ZipCompressions;
5+
import software.coley.llzip.format.read.ZipReaderStrategy;
56
import software.coley.llzip.util.ByteData;
67
import software.coley.llzip.util.ByteDataUtil;
78

@@ -63,10 +64,35 @@ public void read(ByteData data, long offset) {
6364
fileData = data.sliceOf(offset + 30 + fileNameLength + extraFieldLength, fileDataLength);
6465
}
6566

67+
/**
68+
* Checks if the contents do not match those described in {@link CentralDirectoryFileHeader}.
69+
* If this is the case you will probably want to change your ZIP reading configuration.
70+
* <p>
71+
* You can override the {@link ZipReaderStrategy#postProcessLocalFileHeader(LocalFileHeader)}
72+
* to call {@link #adoptLinkedCentralDirectoryValues()}. The implementations of {@link ZipReaderStrategy}
73+
* are non-final, so you can extend them to add the override.
74+
*
75+
* @return {@code true} when the contents of this file header do not match those outlined by the associated
76+
* {@link CentralDirectoryFileHeader}.
77+
*/
78+
public boolean hasDifferentValuesThanCentralDirectoryHeader() {
79+
if (linkedDirectoryFileHeader == null) return false;
80+
if (versionNeededToExtract != linkedDirectoryFileHeader.getVersionNeededToExtract()) return true;
81+
if (generalPurposeBitFlag != linkedDirectoryFileHeader.getGeneralPurposeBitFlag()) return true;
82+
if (compressionMethod != linkedDirectoryFileHeader.getCompressionMethod()) return true;
83+
if (lastModFileTime != linkedDirectoryFileHeader.getLastModFileTime()) return true;
84+
if (lastModFileDate != linkedDirectoryFileHeader.getLastModFileDate()) return true;
85+
if (crc32 != linkedDirectoryFileHeader.getCrc32()) return true;
86+
if (compressedSize != linkedDirectoryFileHeader.getCompressedSize()) return true;
87+
if (uncompressedSize != linkedDirectoryFileHeader.getUncompressedSize()) return true;
88+
if (fileNameLength != linkedDirectoryFileHeader.getFileNameLength()) return true;
89+
return !Objects.equals(getFileNameAsString(), linkedDirectoryFileHeader.getFileNameAsString());
90+
}
91+
6692
/**
6793
* When called before being {@link #freeze() frozen} values can be adopted from the linked
6894
* {@link #getLinkedDirectoryFileHeader() CentralDirectoryFileHeader}.
69-
* <br>
95+
* <p>
7096
* In some cases the {@link LocalFileHeader} file size may be 0, but the authoritative CEN states a non-0 value,
7197
* which you may want to adopt.
7298
*/
@@ -95,7 +121,7 @@ public void adoptLinkedCentralDirectoryValues() {
95121

96122
/**
97123
* Clears the reference to the source {@link ByteData}, preventing further modification.
98-
* <br>
124+
* <p>
99125
* Prevents usage of {@link #adoptLinkedCentralDirectoryValues()}.
100126
*/
101127
public void freeze() {
@@ -236,8 +262,8 @@ public void setCrc32(int crc32) {
236262
* Be aware that these attributes can be falsified.
237263
* Different zip-parsing programs treat the files differently
238264
* and may not adhere to what you expect from the zip specification.
239-
* <br>
240-
* When in doubt, trust {@code data.length()} from {@link #getFileData()}.
265+
* <p>
266+
* When in doubt, trust the length provided by the {@link #getLinkedDirectoryFileHeader()}.
241267
*
242268
* @return Compressed size of {@link #getFileData()}.
243269
*/
@@ -257,6 +283,9 @@ public void setCompressedSize(long compressedSize) {
257283
* Be aware that these attributes can be falsified.
258284
* Different zip-parsing programs treat the files differently
259285
* and may not adhere to what you expect from the zip specification.
286+
* <p>
287+
* When in doubt, trust the length provided by the {@link #getLinkedDirectoryFileHeader()} or
288+
* {@code data.length()} from {@link #getFileData()}.
260289
*
261290
* @return Uncompressed size after {@link #decompress(Decompressor)} is used on {@link #getFileData()}.
262291
*/

src/main/java/software/coley/llzip/format/read/ForwardScanZipReaderStrategy.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,4 @@ public void read(ZipArchive zip, ByteData data) throws IOException {
7070
// Sort based on order
7171
zip.getParts().sort(new OffsetComparator());
7272
}
73-
74-
protected void postProcessLocalFileHeader(LocalFileHeader file) {
75-
// no-op
76-
}
7773
}

src/main/java/software/coley/llzip/format/read/JvmZipReaderStrategy.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
/**
2121
* The JVM has some edge cases in how it parses zip/jar files.
2222
* It allows for some tricks that most tools do not support/expect.
23-
* <br>
23+
* <p>
2424
* The primary difference from {@link ForwardScanZipReaderStrategy} is that the {@link EndOfCentralDirectory}
2525
* is scanned from the back, rather than from the front.
2626
*
@@ -140,8 +140,4 @@ else if (ByteDataUtil.startsWith(data, jvmBaseFileOffset, ZipPatterns.CENTRAL_DI
140140
// Sort based on order
141141
zip.getParts().sort(new OffsetComparator());
142142
}
143-
144-
protected void postProcessLocalFileHeader(LocalFileHeader file) {
145-
// no-op
146-
}
147143
}

src/main/java/software/coley/llzip/format/read/ZipReaderStrategy.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package software.coley.llzip.format.read;
22

3+
import software.coley.llzip.format.model.LocalFileHeader;
34
import software.coley.llzip.format.model.ZipArchive;
45
import software.coley.llzip.util.ByteData;
56

@@ -21,4 +22,8 @@ public interface ZipReaderStrategy {
2122
* When the data cannot be read <i>(EOF, not matching expectations, etc)</i>
2223
*/
2324
void read(ZipArchive zip, ByteData buffer) throws IOException;
25+
26+
default void postProcessLocalFileHeader(LocalFileHeader file) {
27+
// no-op by default
28+
}
2429
}

0 commit comments

Comments
 (0)