Skip to content

Commit 1bd5dba

Browse files
committed
Unsigned handling of quads:
- Longs are now used where appropriate - note: other quads are not changed as their sign is not relevant.
1 parent 8ab737e commit 1bd5dba

File tree

7 files changed

+83
-69
lines changed

7 files changed

+83
-69
lines changed

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

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ public class CentralDirectoryFileHeader implements ZipPart, ZipRead {
2323
private int lastModFileTime;
2424
private int lastModFileDate;
2525
private int crc32;
26-
private int compressedSize;
27-
private int uncompressedSize;
26+
private long compressedSize;
27+
private long uncompressedSize;
2828
private int fileNameLength;
2929
private int extraFieldLength;
3030
private int fileCommentLength;
3131
private int diskNumberStart;
3232
private int internalFileAttributes;
3333
private int externalFileAttributes;
34-
private int relativeOffsetOfLocalHeader;
34+
private long relativeOffsetOfLocalHeader;
3535
private ByteData fileName;
3636
private ByteData extraField;
3737
private ByteData fileComment;
@@ -49,23 +49,23 @@ public void read(ByteData data, long offset) {
4949
lastModFileTime = ByteDataUtil.readWord(data, offset + 12);
5050
lastModFileDate = ByteDataUtil.readWord(data, offset + 14);
5151
crc32 = ByteDataUtil.readQuad(data, offset + 16);
52-
compressedSize = ByteDataUtil.readQuad(data, offset + 20);
53-
uncompressedSize = ByteDataUtil.readQuad(data, offset + 24);
52+
setCompressedSize(ByteDataUtil.readQuad(data, offset + 20));
53+
setUncompressedSize(ByteDataUtil.readQuad(data, offset + 24));
5454
setFileNameLength(ByteDataUtil.readWord(data, offset + 28));
5555
setExtraFieldLength(ByteDataUtil.readWord(data, offset + 30));
5656
setFileCommentLength(ByteDataUtil.readWord(data, offset + 32));
5757
diskNumberStart = ByteDataUtil.readWord(data, offset + 34);
5858
internalFileAttributes = ByteDataUtil.readWord(data, offset + 36);
5959
externalFileAttributes = ByteDataUtil.readQuad(data, offset + 38);
60-
relativeOffsetOfLocalHeader = ByteDataUtil.readQuad(data, offset + 42);
60+
setRelativeOffsetOfLocalHeader(ByteDataUtil.readQuad(data, offset + 42));
6161
fileName = data.sliceOf(offset + 46, fileNameLength);
6262
extraField = data.sliceOf(offset + 46 + fileNameLength, extraFieldLength);
6363
fileComment = data.sliceOf(offset + 46 + fileNameLength + extraFieldLength, fileCommentLength);
6464
}
6565

6666
@Override
67-
public int length() {
68-
return 46 + (int) fileName.length() + (int) extraField.length() + (int) fileComment.length();
67+
public long length() {
68+
return 46L + fileName.length() + extraField.length() + fileComment.length();
6969
}
7070

7171
@Override
@@ -211,16 +211,16 @@ public void setCrc32(int crc32) {
211211
*
212212
* @return Compressed size of {@link LocalFileHeader#getFileData()}.
213213
*/
214-
public int getCompressedSize() {
214+
public long getCompressedSize() {
215215
return compressedSize;
216216
}
217217

218218
/**
219219
* @param compressedSize
220220
* Compressed size of {@link LocalFileHeader#getFileData()}.
221221
*/
222-
public void setCompressedSize(int compressedSize) {
223-
this.compressedSize = compressedSize;
222+
public void setCompressedSize(long compressedSize) {
223+
this.compressedSize = compressedSize & 0xffffffffL;
224224
}
225225

226226
/**
@@ -230,16 +230,16 @@ public void setCompressedSize(int compressedSize) {
230230
*
231231
* @return Uncompressed size after {@link LocalFileHeader#decompress(Decompressor)} is used on {@link LocalFileHeader#getFileData()}.
232232
*/
233-
public int getUncompressedSize() {
233+
public long getUncompressedSize() {
234234
return uncompressedSize;
235235
}
236236

237237
/**
238238
* @param uncompressedSize
239239
* Uncompressed size after {@link LocalFileHeader#decompress(Decompressor)} is used on {@link LocalFileHeader#getFileData()}.
240240
*/
241-
public void setUncompressedSize(int uncompressedSize) {
242-
this.uncompressedSize = uncompressedSize;
241+
public void setUncompressedSize(long uncompressedSize) {
242+
this.uncompressedSize = uncompressedSize & 0xffffffffL;
243243
}
244244

245245
/**
@@ -347,7 +347,7 @@ public void setExternalFileAttributes(int externalFileAttributes) {
347347
* @return Offset from the start of the {@link #getDiskNumberStart() first disk} where the file appears.
348348
* This should also be where the {@link LocalFileHeader} is located. Or {@code 0xFFFFFFFF} for ZIP64.
349349
*/
350-
public int getRelativeOffsetOfLocalHeader() {
350+
public long getRelativeOffsetOfLocalHeader() {
351351
return relativeOffsetOfLocalHeader;
352352
}
353353

@@ -356,8 +356,8 @@ public int getRelativeOffsetOfLocalHeader() {
356356
* Offset from the start of the {@link #getDiskNumberStart() first disk} where the file appears.
357357
* This should also be where the {@link LocalFileHeader} is located. Or {@code 0xFFFFFFFF} for ZIP64.
358358
*/
359-
public void setRelativeOffsetOfLocalHeader(int relativeOffsetOfLocalHeader) {
360-
this.relativeOffsetOfLocalHeader = relativeOffsetOfLocalHeader;
359+
public void setRelativeOffsetOfLocalHeader(long relativeOffsetOfLocalHeader) {
360+
this.relativeOffsetOfLocalHeader = relativeOffsetOfLocalHeader & 0xffffffffL;
361361
}
362362

363363
/**

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ public class EndOfCentralDirectory implements ZipPart, ZipRead {
1919
private int centralDirectoryStartDisk;
2020
private int centralDirectoryStartOffset; // TODO: spec and wikipedia articles disagree about purpose?
2121
private int numEntries;
22-
private int centralDirectorySize;
23-
private int centralDirectoryOffset;
22+
private long centralDirectorySize;
23+
private long centralDirectoryOffset;
2424
private int zipCommentLength;
2525
private ByteData zipComment;
2626
private transient String zipCommentCache;
@@ -32,15 +32,15 @@ public void read(ByteData data, long offset) {
3232
centralDirectoryStartDisk = ByteDataUtil.readWord(data, offset + 6);
3333
centralDirectoryStartOffset = ByteDataUtil.readWord(data, offset + 8);
3434
numEntries = ByteDataUtil.readWord(data, offset + 10);
35-
centralDirectorySize = ByteDataUtil.readQuad(data, offset + 12);
36-
centralDirectoryOffset = ByteDataUtil.readQuad(data, offset + 16);
35+
setCentralDirectorySize(ByteDataUtil.readQuad(data, offset + 12));
36+
setCentralDirectoryOffset(ByteDataUtil.readQuad(data, offset + 16));
3737
setZipCommentLength(ByteDataUtil.readWord(data, offset + 20));
3838
zipComment = data.sliceOf(offset + 22, zipCommentLength);
3939
}
4040

4141
@Override
42-
public int length() {
43-
return 22 + (int) zipComment.length();
42+
public long length() {
43+
return 22L + zipComment.length();
4444
}
4545

4646
@Override
@@ -116,23 +116,23 @@ public void setNumEntries(int numEntries) {
116116
/**
117117
* @return Size of central directory in bytes or {@code 0xFFFFFFFF} for ZIP64.
118118
*/
119-
public int getCentralDirectorySize() {
119+
public long getCentralDirectorySize() {
120120
return centralDirectorySize;
121121
}
122122

123123
/**
124124
* @param centralDirectorySize
125125
* Size of central directory in bytes, or {@code 0xFFFFFFFF} for ZIP64.
126126
*/
127-
public void setCentralDirectorySize(int centralDirectorySize) {
128-
this.centralDirectorySize = centralDirectorySize;
127+
public void setCentralDirectorySize(long centralDirectorySize) {
128+
this.centralDirectorySize = centralDirectorySize & 0xffffffffL;
129129
}
130130

131131
/**
132132
* @return Offset of first {@link CentralDirectoryFileHeader} with respect to
133133
* {@link #getCentralDirectoryStartDisk() starting disk number}, or {@code 0xFFFFFFFF} for ZIP64.
134134
*/
135-
public int getCentralDirectoryOffset() {
135+
public long getCentralDirectoryOffset() {
136136
return centralDirectoryOffset;
137137
}
138138

@@ -141,8 +141,8 @@ public int getCentralDirectoryOffset() {
141141
* Offset of first {@link CentralDirectoryFileHeader} with respect to
142142
* {@link #getCentralDirectoryStartDisk() starting disk number}, or {@code 0xFFFFFFFF} for ZIP64.
143143
*/
144-
public void setCentralDirectoryOffset(int centralDirectoryOffset) {
145-
this.centralDirectoryOffset = centralDirectoryOffset;
144+
public void setCentralDirectoryOffset(long centralDirectoryOffset) {
145+
this.centralDirectoryOffset = centralDirectoryOffset & 0xffffffffL;
146146
}
147147

148148
/**

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

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ public class LocalFileHeader implements ZipPart, ZipRead {
2525
private int lastModFileTime;
2626
private int lastModFileDate;
2727
private int crc32;
28-
private int compressedSize;
29-
private int uncompressedSize;
28+
private long compressedSize;
29+
private long uncompressedSize;
3030
private int fileNameLength;
3131
private int extraFieldLength;
3232
private ByteData fileName;
@@ -44,25 +44,24 @@ public void read(ByteData data, long offset) {
4444
lastModFileTime = ByteDataUtil.readWord(data, offset + 10);
4545
lastModFileDate = ByteDataUtil.readWord(data, offset + 12);
4646
crc32 = ByteDataUtil.readQuad(data, offset + 14);
47-
compressedSize = ByteDataUtil.readQuad(data, offset + 18);
48-
uncompressedSize = ByteDataUtil.readQuad(data, offset + 22);
49-
// Reading these to ints so ensure they act as unsigned shorts
47+
setCompressedSize(ByteDataUtil.readQuad(data, offset + 18));
48+
setUncompressedSize(ByteDataUtil.readQuad(data, offset + 22));
5049
setFileNameLength(ByteDataUtil.readWord(data, offset + 26));
5150
setExtraFieldLength(ByteDataUtil.readWord(data, offset + 28));
5251
fileName = data.sliceOf(offset + 30, fileNameLength);
5352
extraField = data.sliceOf(offset + 30 + fileNameLength, extraFieldLength);
5453
long fileDataLength;
5554
if (compressionMethod == STORED) {
56-
fileDataLength = uncompressedSize & 0xffffffffL;
55+
fileDataLength = uncompressedSize;
5756
} else {
58-
fileDataLength = compressedSize & 0xffffffffL;
57+
fileDataLength = compressedSize;
5958
}
6059
fileData = data.sliceOf(offset + 30 + fileNameLength + extraFieldLength, fileDataLength);
6160
}
6261

6362
@Override
64-
public int length() {
65-
return MIN_FIXED_SIZE + (int) fileName.length() + (int) extraField.length() + (int) fileData.length();
63+
public long length() {
64+
return MIN_FIXED_SIZE + fileName.length() + extraField.length() + fileData.length();
6665
}
6766

6867
@Override
@@ -199,16 +198,16 @@ public void setCrc32(int crc32) {
199198
*
200199
* @return Compressed size of {@link #getFileData()}.
201200
*/
202-
public int getCompressedSize() {
201+
public long getCompressedSize() {
203202
return compressedSize;
204203
}
205204

206205
/**
207206
* @param compressedSize
208207
* Compressed size of {@link #getFileData()}.
209208
*/
210-
public void setCompressedSize(int compressedSize) {
211-
this.compressedSize = compressedSize;
209+
public void setCompressedSize(long compressedSize) {
210+
this.compressedSize = compressedSize & 0xffffffffL;
212211
}
213212

214213
/**
@@ -218,16 +217,16 @@ public void setCompressedSize(int compressedSize) {
218217
*
219218
* @return Uncompressed size after {@link #decompress(Decompressor)} is used on {@link #getFileData()}.
220219
*/
221-
public int getUncompressedSize() {
220+
public long getUncompressedSize() {
222221
return uncompressedSize;
223222
}
224223

225224
/**
226225
* @param uncompressedSize
227226
* Uncompressed size after {@link #decompress(Decompressor)} is used on {@link #getFileData()}.
228227
*/
229-
public void setUncompressedSize(int uncompressedSize) {
230-
this.uncompressedSize = uncompressedSize;
228+
public void setUncompressedSize(long uncompressedSize) {
229+
this.uncompressedSize = uncompressedSize & 0xffffffffL;
231230
}
232231

233232
/**

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public interface ZipPart {
1212
/**
1313
* @return Length of current content.
1414
*/
15-
int length();
15+
long length();
1616

1717
/**
1818
* @return Implementation type.

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@ public void read(ZipArchive zip, ByteData data) throws IOException {
3939
while (centralDirectoryOffset < len && ByteDataUtil.startsWith(data, centralDirectoryOffset, ZipPatterns.CENTRAL_DIRECTORY_FILE_HEADER)) {
4040
CentralDirectoryFileHeader directory = new CentralDirectoryFileHeader();
4141
directory.read(data, centralDirectoryOffset);
42-
centralDirectoryOffset += directory.length() & 0xffffffffL; // FIXME: Could still be a lossy cast
42+
centralDirectoryOffset += directory.length();
4343
zip.getParts().add(directory);
4444
}
4545
// Read local files
4646
// - Set to prevent duplicate file header entries for the same offset
47-
Set<Integer> offsets = new HashSet<>();
47+
Set<Long> offsets = new HashSet<>();
4848
for (CentralDirectoryFileHeader directory : zip.getCentralDirectories()) {
49-
int offset = directory.getRelativeOffsetOfLocalHeader();
49+
long offset = directory.getRelativeOffsetOfLocalHeader();
5050
if (!offsets.contains(offset) && ByteDataUtil.startsWith(data, offset, ZipPatterns.LOCAL_FILE_HEADER)) {
5151
LocalFileHeader file = new LocalFileHeader();
5252
file.read(data, offset);

src/test/java/software/coley/llzip/LargeStringTests.java

Lines changed: 0 additions & 21 deletions
This file was deleted.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package software.coley.llzip;
2+
3+
import org.junit.jupiter.api.Assertions;
4+
import org.junit.jupiter.api.Test;
5+
6+
import java.io.IOException;
7+
import java.nio.file.Paths;
8+
9+
/**
10+
* Tests that reading larger strings from zip files works correctly.
11+
*/
12+
public class LargeZipTests {
13+
14+
@Test
15+
public void testLargeStrings() {
16+
try {
17+
ZipIO.readStandard(Paths.get("src/test/resources/large-strings.zip"));
18+
} catch (IOException error) {
19+
Assertions.fail(error);
20+
}
21+
}
22+
23+
// Left this test out for obvious reasons, all you need to run it is a zip file containing a single file >2.1GB
24+
/*
25+
@Test
26+
public void testLargeFiles() {
27+
try {
28+
ZipArchive zip = ZipIO.readStandard(Paths.get("src/test/resources/large.zip"));
29+
// Just need a file bigger than 2.1GB to validate this test works
30+
Assertions.assertTrue(zip.getLocalFiles().get(0).getFileData().length() > 0x80000000L);
31+
} catch (IOException error) {
32+
Assertions.fail(error);
33+
}
34+
}
35+
*/
36+
}

0 commit comments

Comments
 (0)