Skip to content

Commit 822cb24

Browse files
authored
Merge pull request #28 from xxDark/jdk22
Bump minimum required JDK to 22, migrate API to MemorySegment
2 parents b2555f6 + 99db173 commit 822cb24

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+437
-1191
lines changed

.github/workflows/build.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
fail-fast: false
2424
matrix:
2525
os: [ ubuntu-latest ]
26-
java-version: [ 17 ]
26+
java-version: [ 22 ]
2727
runs-on: ubuntu-latest
2828
timeout-minutes: 10
2929
steps:
@@ -33,7 +33,7 @@ jobs:
3333
uses: actions/setup-java@v3
3434
with:
3535
distribution: temurin
36-
java-version: 17
36+
java-version: 22
3737
check-latest: true
3838
# The project version extract NEEDS to have the maven wrapper already downloaded.
3939
# So we have a dummy step here just to initialize it.
@@ -90,7 +90,7 @@ jobs:
9090
uses: actions/setup-java@v3
9191
with:
9292
distribution: temurin
93-
java-version: 17
93+
java-version: 22
9494
# The project version extract NEEDS to have the maven wrapper already downloaded.
9595
# So we have a dummy step here just to initialize it.
9696
- name: Download Maven wrapper

README.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@ But that's not all it does. That's just what that one comment says. Some other f
2525

2626
## Additional features
2727

28-
- Reads ZIP files using `Unsafe` backed mapped files.
29-
- Using `FileChannel.map` yields `MappedByteBuffer` which uses `int` values, limiting files up to about 2GB
30-
- Our `UnsafeMappedFile` implementation uses `long` which far exceeds the GB file size range
28+
- Reads ZIP files using `MemorySegment` backed mapped files.
3129
- Highly configurable, offering 3 ZIP reading strategies out of the box _(See `ZipIO` for convenience calls)_
3230
- Std / Forward scanning: Scans for `EndOfCentralDirectory` from the front of the file, like many other tools
3331
- Naive: Scans only for `LocalFileHeader` values from the front of the file, the fastest implementation, but obviously naive

jreleaser.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ project:
1010
inceptionYear: 2022
1111
stereotype: none
1212
java:
13-
version: 11
13+
version: 22
1414
groupId: software.coley
1515
artifactId: lljzip
1616

pom.xml

+3-7
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.3.0</version>
9+
<version>2.4.0</version>
1010

1111
<name>LL Java ZIP</name>
1212
<description>Lower level ZIP support for Java</description>
@@ -97,13 +97,9 @@
9797
<plugin>
9898
<groupId>org.apache.maven.plugins</groupId>
9999
<artifactId>maven-compiler-plugin</artifactId>
100-
<!-- When attempting to compile on higher Java versions, you may encounter
101-
some issues with Unsafe. In Intellij unset the 'use -release' under the
102-
javac compiler page and it'll happily compile once again
103-
-->
100+
<version>3.13.0</version>
104101
<configuration>
105-
<source>1.8</source>
106-
<target>1.8</target>
102+
<release>22</release>
107103
</configuration>
108104
</plugin>
109105
<plugin>

src/main/java/software/coley/lljzip/ZipIO.java

+29-13
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
import software.coley.lljzip.format.model.EndOfCentralDirectory;
55
import software.coley.lljzip.format.model.ZipArchive;
66
import software.coley.lljzip.format.read.*;
7-
import software.coley.lljzip.util.BufferData;
8-
import software.coley.lljzip.util.ByteData;
9-
import software.coley.lljzip.util.FileMapUtil;
107

118
import java.io.FileNotFoundException;
129
import java.io.IOException;
10+
import java.lang.foreign.Arena;
11+
import java.lang.foreign.MemorySegment;
12+
import java.nio.channels.FileChannel;
1313
import java.nio.file.Files;
1414
import java.nio.file.Path;
1515
import java.util.zip.ZipFile;
@@ -21,7 +21,7 @@
2121
* <li>For regular ZIP files use {@link ForwardScanZipReader}.</li>
2222
* <li>For ZIP files without {@link CentralDirectoryFileHeader} or {@link EndOfCentralDirectory} items, use {@link NaiveLocalFileZipReader}</li>
2323
* </ul>
24-
* You can fully control zip parsing via {@link #read(ByteData, ZipReader)} by passing a customized reader implementation.
24+
* You can fully control zip parsing via {@link #read(MemorySegment, ZipReader)} by passing a customized reader implementation.
2525
*
2626
* @author Matt Coley
2727
*/
@@ -37,7 +37,7 @@ public class ZipIO {
3737
* @throws IOException
3838
* When the archive bytes cannot be read from, usually indicating a malformed zip.
3939
*/
40-
public static ZipArchive readStandard(ByteData data) throws IOException {
40+
public static ZipArchive readStandard(MemorySegment data) throws IOException {
4141
return read(data, new ForwardScanZipReader());
4242
}
4343

@@ -82,7 +82,7 @@ public static ZipArchive readStandard(Path data) throws IOException {
8282
* @throws IOException
8383
* When the archive bytes cannot be read from, usually indicating a malformed zip.
8484
*/
85-
public static ZipArchive readNaive(ByteData data) throws IOException {
85+
public static ZipArchive readNaive(MemorySegment data) throws IOException {
8686
return read(data, new NaiveLocalFileZipReader());
8787
}
8888

@@ -128,7 +128,7 @@ public static ZipArchive readNaive(Path data) throws IOException {
128128
* @throws IOException
129129
* When the archive bytes cannot be read from, usually indicating a malformed zip.
130130
*/
131-
public static ZipArchive readJvm(ByteData data) throws IOException {
131+
public static ZipArchive readJvm(MemorySegment data) throws IOException {
132132
return read(data, new JvmZipReader());
133133
}
134134

@@ -172,7 +172,7 @@ public static ZipArchive readJvm(Path path) throws IOException {
172172
*
173173
* @return Archive from path.
174174
*
175-
* @throws IOException
175+
* @throws IOException When the archive cannot be read.
176176
*/
177177
public static ZipArchive readAdaptingIO(Path path) throws IOException {
178178
ZipArchive archive = new ZipArchive();
@@ -194,7 +194,7 @@ public static ZipArchive readAdaptingIO(Path path) throws IOException {
194194
public static ZipArchive read(byte[] data, ZipReader strategy) throws IOException {
195195
if (data == null)
196196
throw new IOException("Data is null!");
197-
return read(BufferData.wrap(data), strategy);
197+
return read(MemorySegment.ofArray(data), strategy);
198198
}
199199

200200
/**
@@ -213,7 +213,23 @@ public static ZipArchive read(Path path, ZipReader strategy) throws IOException
213213
throw new IOException("Data is null!");
214214
if (!Files.isRegularFile(path))
215215
throw new FileNotFoundException(path.toString());
216-
return read(FileMapUtil.map(path), strategy);
216+
FileChannel fc = FileChannel.open(path);
217+
try {
218+
long size = fc.size();
219+
// The fixed size elements of a CDFH is 22 bytes (plus the variable size bits which can be 0)
220+
// - Even if we only want to read local/central file entries, those are even larger at a minimum
221+
if (size < 22)
222+
throw new IOException("Not enough bytes to read Central-Directory-File-Header, minimum=22");
223+
224+
ZipArchive zip = new ZipArchive(fc);
225+
strategy.read(zip, fc.map(FileChannel.MapMode.READ_ONLY, 0L, size, Arena.ofAuto()));
226+
fc = null;
227+
return zip;
228+
} finally {
229+
if (fc != null) {
230+
fc.close();
231+
}
232+
}
217233
}
218234

219235
/**
@@ -227,17 +243,17 @@ public static ZipArchive read(Path path, ZipReader strategy) throws IOException
227243
* @throws IOException
228244
* When the archive bytes cannot be read from, usually indicating a malformed zip.
229245
*/
230-
public static ZipArchive read(ByteData data, ZipReader strategy) throws IOException {
246+
public static ZipArchive read(MemorySegment data, ZipReader strategy) throws IOException {
231247
if (data == null)
232248
throw new IOException("Data is null!");
233249

234250
// The fixed size elements of a CDFH is 22 bytes (plus the variable size bits which can be 0)
235251
// - Even if we only want to read local/central file entries, those are even larger at a minimum
236-
if (data.length() < 22)
252+
if (data.byteSize() < 22)
237253
throw new IOException("Not enough bytes to read Central-Directory-File-Header, minimum=22");
238254

239255
// Create instance
240-
ZipArchive zip = new ZipArchive(data);
256+
ZipArchive zip = new ZipArchive();
241257
strategy.read(zip, data);
242258
return zip;
243259
}

src/main/java/software/coley/lljzip/format/ZipPatterns.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
import software.coley.lljzip.format.model.CentralDirectoryFileHeader;
44
import software.coley.lljzip.format.model.EndOfCentralDirectory;
55
import software.coley.lljzip.format.model.LocalFileHeader;
6-
import software.coley.lljzip.util.ByteDataUtil;
6+
import software.coley.lljzip.util.MemorySegmentUtil;
77

88
/**
9-
* Patterns for usage in {@link ByteDataUtil} methods.
9+
* Patterns for usage in {@link MemorySegmentUtil} methods.
1010
*
1111
* @author Matt Coley
1212
*/

src/main/java/software/coley/lljzip/format/compression/Decompressor.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package software.coley.lljzip.format.compression;
22

33
import software.coley.lljzip.format.model.LocalFileHeader;
4-
import software.coley.lljzip.util.ByteData;
54

65
import java.io.IOException;
6+
import java.lang.foreign.MemorySegment;
77

88
/**
99
* Outlines decompression of {@link LocalFileHeader#getFileData()}.
@@ -22,5 +22,5 @@ public interface Decompressor {
2222
* @throws IOException
2323
* Decompression failure.
2424
*/
25-
ByteData decompress(LocalFileHeader header, ByteData bytes) throws IOException;
25+
MemorySegment decompress(LocalFileHeader header, MemorySegment bytes) throws IOException;
2626
}

src/main/java/software/coley/lljzip/format/compression/DeflateDecompressor.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package software.coley.lljzip.format.compression;
22

33
import software.coley.lljzip.format.model.LocalFileHeader;
4-
import software.coley.lljzip.util.ByteData;
54
import software.coley.lljzip.util.FastWrapOutputStream;
65

76
import java.io.IOException;
7+
import java.lang.foreign.MemorySegment;
88
import java.util.zip.DataFormatException;
99
import java.util.zip.Inflater;
1010
import java.util.zip.ZipException;
@@ -22,23 +22,24 @@ private DeflateDecompressor() {
2222
}
2323

2424
@Override
25-
public ByteData decompress(LocalFileHeader header, ByteData data) throws IOException {
25+
public MemorySegment decompress(LocalFileHeader header, MemorySegment data) throws IOException {
2626
if (header.getCompressionMethod() != ZipCompressions.DEFLATED)
2727
throw new IOException("LocalFileHeader contents not using 'Deflated'!");
2828
Inflater inflater = new Inflater(true);
2929
FastWrapOutputStream out = new FastWrapOutputStream();
3030
try {
3131
byte[] output = new byte[1024];
3232
byte[] buffer = new byte[1024];
33+
MemorySegment bufferSegment = MemorySegment.ofArray(buffer);
3334
long position = 0L;
34-
long length = data.length();
35+
long length = data.byteSize();
3536
do {
3637
if (inflater.needsInput()) {
3738
int remaining = (int) Math.min(buffer.length, length);
3839
if (remaining == 0) {
3940
break;
4041
}
41-
data.get(position, buffer, 0, remaining);
42+
MemorySegment.copy(data, position, bufferSegment, 0, remaining);
4243
length -= remaining;
4344
position += remaining;
4445
inflater.setInput(buffer, 0, remaining);

src/main/java/software/coley/lljzip/format/compression/UnsafeDeflateDecompressor.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package software.coley.lljzip.format.compression;
22

33
import software.coley.lljzip.format.model.LocalFileHeader;
4-
import software.coley.lljzip.util.ByteData;
54
import software.coley.lljzip.util.FastWrapOutputStream;
65
import software.coley.lljzip.util.InflaterHackery;
76

87
import java.io.IOException;
8+
import java.lang.foreign.MemorySegment;
99
import java.util.ArrayDeque;
1010
import java.util.Deque;
1111
import java.util.zip.DataFormatException;
@@ -38,7 +38,7 @@ private UnsafeDeflateDecompressor() {
3838
}
3939

4040
@Override
41-
public ByteData decompress(LocalFileHeader header, ByteData data) throws IOException {
41+
public MemorySegment decompress(LocalFileHeader header, MemorySegment data) throws IOException {
4242
if (header.getCompressionMethod() != ZipCompressions.DEFLATED)
4343
throw new IOException("LocalFileHeader contents not using 'Deflated'!");
4444
FastWrapOutputStream out = new FastWrapOutputStream();
@@ -55,16 +55,17 @@ public ByteData decompress(LocalFileHeader header, ByteData data) throws IOExcep
5555
try {
5656
byte[] output = entry.decompress;
5757
byte[] buffer = entry.buffer;
58+
MemorySegment bufferSegment = MemorySegment.ofArray(buffer);
5859
Inflater inflater = entry.inflater;
5960
long position = 0L;
60-
long length = data.length();
61+
long length = data.byteSize();
6162
int remaining = 0;
6263
boolean needsInput = true;
6364
do {
6465
if (needsInput) {
6566
remaining = (int) Math.min(buffer.length, length);
6667
if (remaining != 0) {
67-
data.get(position, buffer, 0, remaining);
68+
MemorySegment.copy(data, position, bufferSegment, 0, remaining);
6869
length -= remaining;
6970
position += remaining;
7071
inflater.setInput(buffer, 0, remaining);

0 commit comments

Comments
 (0)