Skip to content

Commit 5cd1b48

Browse files
committed
Pull FileData segment reading out to separate method for LFH
Allows library consumers to handle edge cases more easily
1 parent 5894ae7 commit 5cd1b48

File tree

5 files changed

+59
-20
lines changed

5 files changed

+59
-20
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>2.7.2</version>
9+
<version>2.8.0</version>
1010

1111
<name>LL Java ZIP</name>
1212
<description>Lower level ZIP support for Java</description>

src/main/java/software/coley/lljzip/format/model/JvmLocalFileHeader.java

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,9 @@ public void setOffsets(@Nonnull NavigableSet<Long> offsets) {
3131
this.offsets = offsets;
3232
}
3333

34+
@Nonnull
3435
@Override
35-
public void read(@Nonnull MemorySegment data, long offset) throws ZipParseException {
36-
try {
37-
super.read(data, offset);
38-
} catch (ZipParseException ex) {
39-
// If the error was that the data couldn't be read, that's OK because we're going to try reading
40-
// that in a slightly different way below.
41-
if (ex.getType() != ZipParseException.Type.IOOBE_FILE_DATA)
42-
throw ex;
43-
}
44-
36+
protected MemorySegmentData readFileData(@Nonnull MemorySegment data, long headerOffset) {
4537
// JVM file data reading does NOT use the compressed/uncompressed fields.
4638
// Instead, it scans data until the next header.
4739
long relativeDataOffsetStart = MIN_FIXED_SIZE + getFileNameLength() + getExtraFieldLength();
@@ -86,13 +78,7 @@ public void read(@Nonnull MemorySegment data, long offset) throws ZipParseExcept
8678
this.relativeDataOffsetEnd = relativeDataOffsetEnd;
8779
long fileDataLength = relativeDataOffsetEnd - relativeDataOffsetStart;
8880

89-
try {
90-
fileData = MemorySegmentData.of(MemorySegmentUtil.readLongSlice(data, offset, relativeDataOffsetStart, fileDataLength));
91-
} catch (IndexOutOfBoundsException ex) {
92-
throw new ZipParseException(ex, ZipParseException.Type.IOOBE_FILE_DATA);
93-
} catch (Throwable t) {
94-
throw new ZipParseException(t, ZipParseException.Type.OTHER);
95-
}
81+
fileData = MemorySegmentData.of(MemorySegmentUtil.readLongSlice(data, offset, relativeDataOffsetStart, fileDataLength));
9682

9783
// Update sizes where possible
9884
if (getCompressionMethod() == ZipCompressions.STORED) {
@@ -105,6 +91,7 @@ public void read(@Nonnull MemorySegment data, long offset) throws ZipParseExcept
10591
// If we have a size, we can assume we found some data.
10692
// Whether its valid, who really knows?
10793
foundData = fileDataLength != 0;
94+
return fileData;
10895
}
10996

11097
@Override

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,16 +101,32 @@ public void read(@Nonnull MemorySegment data, long offset) throws ZipParseExcept
101101
} catch (Throwable t) {
102102
throw new ZipParseException(t, ZipParseException.Type.OTHER);
103103
}
104-
long fileDataLength = (compressionMethod == STORED) ? uncompressedSize : compressedSize;
105104
try {
106-
fileData = MemorySegmentData.of(readLongSlice(data, offset, MIN_FIXED_SIZE + fileNameLength + extraFieldLength, fileDataLength));
105+
fileData = readFileData(data, offset);
107106
} catch (IndexOutOfBoundsException ex) {
108107
throw new ZipParseException(ex, ZipParseException.Type.IOOBE_FILE_DATA);
109108
} catch (Throwable t) {
110109
throw new ZipParseException(t, ZipParseException.Type.OTHER);
111110
}
112111
}
113112

113+
/**
114+
* @param data
115+
* Data to read from.
116+
* @param headerOffset
117+
* Initial offset in data to where the local file header starts at.
118+
*
119+
* @return File data segment.
120+
*/
121+
@Nonnull
122+
protected MemorySegmentData readFileData(@Nonnull MemorySegment data, long headerOffset) {
123+
long localOffset = MIN_FIXED_SIZE + getFileNameLength() + getExtraFieldLength();
124+
long fileDataLength = (compressionMethod == STORED) ? uncompressedSize : compressedSize;
125+
if (localOffset + fileDataLength > data.byteSize())
126+
throw new IndexOutOfBoundsException("LFH FileData: Reads beyond file bounds");
127+
return MemorySegmentData.of(readLongSlice(data, headerOffset, localOffset, fileDataLength));
128+
}
129+
114130
/**
115131
* Should match {@link CentralDirectoryFileHeader#getFileNameLength()} but is not a strict requirement.
116132
* If they do not match, the central directory file name length should be trusted instead.

src/test/java/software/coley/lljzip/PatchingTests.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,30 @@
33
import org.junit.jupiter.api.Test;
44
import org.junit.jupiter.params.ParameterizedTest;
55
import org.junit.jupiter.params.provider.ValueSource;
6+
import software.coley.lljzip.format.ZipPatterns;
7+
import software.coley.lljzip.format.model.LocalFileHeader;
68
import software.coley.lljzip.format.model.ZipArchive;
9+
import software.coley.lljzip.format.read.NaiveLocalFileZipReader;
10+
import software.coley.lljzip.format.read.SimpleZipPartAllocator;
711
import software.coley.lljzip.format.transform.IdentityZipPartMapper;
812
import software.coley.lljzip.format.transform.JvmClassDirectoryMapper;
913
import software.coley.lljzip.format.write.ZipOutputStreamZipWriter;
14+
import software.coley.lljzip.util.MemorySegmentUtil;
15+
import software.coley.lljzip.util.data.MemorySegmentData;
1016

17+
import javax.annotation.Nonnull;
1118
import java.io.ByteArrayInputStream;
1219
import java.io.ByteArrayOutputStream;
1320
import java.io.IOException;
21+
import java.lang.foreign.MemorySegment;
1422
import java.nio.file.Files;
1523
import java.nio.file.Path;
1624
import java.nio.file.Paths;
1725
import java.util.zip.ZipEntry;
1826
import java.util.zip.ZipInputStream;
1927

2028
import static org.junit.jupiter.api.Assertions.*;
29+
import static software.coley.lljzip.util.MemorySegmentUtil.readLongSlice;
2130

2231
/**
2332
* Tests for patching the <i>"trick"</i> jars, and making them compatible with standard Java ZIP apis.
@@ -85,6 +94,33 @@ public void testTrickJarPatched(String name) {
8594
}
8695
}
8796

97+
@Test
98+
@SuppressWarnings("resource")
99+
public void testNaiveWithForwardScanningData() {
100+
NaiveLocalFileZipReader strategy = new NaiveLocalFileZipReader(new SimpleZipPartAllocator() {
101+
@Nonnull
102+
@Override
103+
public LocalFileHeader newLocalFileHeader() {
104+
return new LocalFileHeader() {
105+
@Nonnull
106+
@Override
107+
protected MemorySegmentData readFileData(@Nonnull MemorySegment data, long headerOffset) {
108+
long localOffset = MIN_FIXED_SIZE + getFileNameLength() + getExtraFieldLength();
109+
long nextStart = MemorySegmentUtil.indexOfQuad(data, headerOffset + localOffset, ZipPatterns.LOCAL_FILE_HEADER_QUAD);
110+
long fileDataLength = nextStart > headerOffset ?
111+
nextStart - (headerOffset + localOffset) :
112+
data.byteSize() - (headerOffset + localOffset);
113+
return MemorySegmentData.of(readLongSlice(data, headerOffset, localOffset, fileDataLength));
114+
}
115+
};
116+
}
117+
});
118+
119+
Path path = Paths.get("src/test/resources/resource-pack-trick-data-ioobe-no-end.zip");
120+
ZipArchive zip = assertDoesNotThrow(() -> ZipIO.read(path, strategy));
121+
assertNotNull(zip.getLocalFileByName("pack.mcmeta"), "IOOBE not patched");
122+
}
123+
88124
@Test
89125
@SuppressWarnings("resource")
90126
public void testTrailingSlashTransform() {
6.79 KB
Binary file not shown.

0 commit comments

Comments
 (0)