Skip to content

Commit

Permalink
Bump minimum required JDK to 22, migrate API to MemorySegment
Browse files Browse the repository at this point in the history
  • Loading branch information
xxDark committed Apr 11, 2024
1 parent b2555f6 commit 005749b
Show file tree
Hide file tree
Showing 35 changed files with 293 additions and 978 deletions.
8 changes: 2 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,9 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<!-- When attempting to compile on higher Java versions, you may encounter
some issues with Unsafe. In Intellij unset the 'use -release' under the
javac compiler page and it'll happily compile once again
-->
<configuration>
<source>1.8</source>
<target>1.8</target>
<source>22</source>
<target>22</target>
</configuration>
</plugin>
<plugin>
Expand Down
40 changes: 28 additions & 12 deletions src/main/java/software/coley/lljzip/ZipIO.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
import software.coley.lljzip.format.model.EndOfCentralDirectory;
import software.coley.lljzip.format.model.ZipArchive;
import software.coley.lljzip.format.read.*;
import software.coley.lljzip.util.BufferData;
import software.coley.lljzip.util.ByteData;
import software.coley.lljzip.util.FileMapUtil;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.zip.ZipFile;
Expand All @@ -21,7 +21,7 @@
* <li>For regular ZIP files use {@link ForwardScanZipReader}.</li>
* <li>For ZIP files without {@link CentralDirectoryFileHeader} or {@link EndOfCentralDirectory} items, use {@link NaiveLocalFileZipReader}</li>
* </ul>
* You can fully control zip parsing via {@link #read(ByteData, ZipReader)} by passing a customized reader implementation.
* You can fully control zip parsing via {@link #read(MemorySegment, ZipReader)} by passing a customized reader implementation.
*
* @author Matt Coley
*/
Expand All @@ -37,7 +37,7 @@ public class ZipIO {
* @throws IOException
* When the archive bytes cannot be read from, usually indicating a malformed zip.
*/
public static ZipArchive readStandard(ByteData data) throws IOException {
public static ZipArchive readStandard(MemorySegment data) throws IOException {
return read(data, new ForwardScanZipReader());
}

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

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

Expand Down Expand Up @@ -194,7 +194,7 @@ public static ZipArchive readAdaptingIO(Path path) throws IOException {
public static ZipArchive read(byte[] data, ZipReader strategy) throws IOException {
if (data == null)
throw new IOException("Data is null!");
return read(BufferData.wrap(data), strategy);
return read(MemorySegment.ofArray(data), strategy);
}

/**
Expand All @@ -213,7 +213,23 @@ public static ZipArchive read(Path path, ZipReader strategy) throws IOException
throw new IOException("Data is null!");
if (!Files.isRegularFile(path))
throw new FileNotFoundException(path.toString());
return read(FileMapUtil.map(path), strategy);
FileChannel fc = FileChannel.open(path);
try {
long size = fc.size();
// The fixed size elements of a CDFH is 22 bytes (plus the variable size bits which can be 0)
// - Even if we only want to read local/central file entries, those are even larger at a minimum
if (size < 22)
throw new IOException("Not enough bytes to read Central-Directory-File-Header, minimum=22");

ZipArchive zip = new ZipArchive(fc);
strategy.read(zip, fc.map(FileChannel.MapMode.READ_ONLY, 0L, size, Arena.ofAuto()));
fc = null;
return zip;
} finally {
if (fc != null) {
fc.close();
}
}
}

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

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

// Create instance
ZipArchive zip = new ZipArchive(data);
ZipArchive zip = new ZipArchive();
strategy.read(zip, data);
return zip;
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/software/coley/lljzip/format/ZipPatterns.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import software.coley.lljzip.format.model.CentralDirectoryFileHeader;
import software.coley.lljzip.format.model.EndOfCentralDirectory;
import software.coley.lljzip.format.model.LocalFileHeader;
import software.coley.lljzip.util.ByteDataUtil;
import software.coley.lljzip.util.MemorySegmentUtil;

/**
* Patterns for usage in {@link ByteDataUtil} methods.
* Patterns for usage in {@link MemorySegmentUtil} methods.
*
* @author Matt Coley
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package software.coley.lljzip.format.compression;

import software.coley.lljzip.format.model.LocalFileHeader;
import software.coley.lljzip.util.ByteData;

import java.io.IOException;
import java.lang.foreign.MemorySegment;

/**
* Outlines decompression of {@link LocalFileHeader#getFileData()}.
Expand All @@ -22,5 +22,5 @@ public interface Decompressor {
* @throws IOException
* Decompression failure.
*/
ByteData decompress(LocalFileHeader header, ByteData bytes) throws IOException;
MemorySegment decompress(LocalFileHeader header, MemorySegment bytes) throws IOException;
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package software.coley.lljzip.format.compression;

import software.coley.lljzip.format.model.LocalFileHeader;
import software.coley.lljzip.util.ByteData;
import software.coley.lljzip.util.FastWrapOutputStream;

import java.io.IOException;
import java.lang.foreign.MemorySegment;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
import java.util.zip.ZipException;
Expand All @@ -22,23 +22,24 @@ private DeflateDecompressor() {
}

@Override
public ByteData decompress(LocalFileHeader header, ByteData data) throws IOException {
public MemorySegment decompress(LocalFileHeader header, MemorySegment data) throws IOException {
if (header.getCompressionMethod() != ZipCompressions.DEFLATED)
throw new IOException("LocalFileHeader contents not using 'Deflated'!");
Inflater inflater = new Inflater(true);
FastWrapOutputStream out = new FastWrapOutputStream();
try {
byte[] output = new byte[1024];
byte[] buffer = new byte[1024];
MemorySegment bufferSegment = MemorySegment.ofArray(buffer);
long position = 0L;
long length = data.length();
long length = data.byteSize();
do {
if (inflater.needsInput()) {
int remaining = (int) Math.min(buffer.length, length);
if (remaining == 0) {
break;
}
data.get(position, buffer, 0, remaining);
MemorySegment.copy(data, position, bufferSegment, 0, remaining);
length -= remaining;
position += remaining;
inflater.setInput(buffer, 0, remaining);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package software.coley.lljzip.format.compression;

import software.coley.lljzip.format.model.LocalFileHeader;
import software.coley.lljzip.util.ByteData;
import software.coley.lljzip.util.FastWrapOutputStream;
import software.coley.lljzip.util.InflaterHackery;

import java.io.IOException;
import java.lang.foreign.MemorySegment;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.zip.DataFormatException;
Expand Down Expand Up @@ -38,7 +38,7 @@ private UnsafeDeflateDecompressor() {
}

@Override
public ByteData decompress(LocalFileHeader header, ByteData data) throws IOException {
public MemorySegment decompress(LocalFileHeader header, MemorySegment data) throws IOException {
if (header.getCompressionMethod() != ZipCompressions.DEFLATED)
throw new IOException("LocalFileHeader contents not using 'Deflated'!");
FastWrapOutputStream out = new FastWrapOutputStream();
Expand All @@ -55,16 +55,17 @@ public ByteData decompress(LocalFileHeader header, ByteData data) throws IOExcep
try {
byte[] output = entry.decompress;
byte[] buffer = entry.buffer;
MemorySegment bufferSegment = MemorySegment.ofArray(buffer);
Inflater inflater = entry.inflater;
long position = 0L;
long length = data.length();
long length = data.byteSize();
int remaining = 0;
boolean needsInput = true;
do {
if (needsInput) {
remaining = (int) Math.min(buffer.length, length);
if (remaining != 0) {
data.get(position, buffer, 0, remaining);
MemorySegment.copy(data, position, bufferSegment, 0, remaining);
length -= remaining;
position += remaining;
inflater.setInput(buffer, 0, remaining);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package software.coley.lljzip.format.compression;

import software.coley.lljzip.format.model.LocalFileHeader;
import software.coley.lljzip.util.ByteData;

import java.io.IOException;
import java.lang.foreign.MemorySegment;

/**
* Constants for {@link LocalFileHeader#getCompressionMethod()}.
Expand Down Expand Up @@ -202,7 +202,7 @@ static String getName(int method) {
* @throws IOException
* When the decompression failed.
*/
static ByteData decompress(LocalFileHeader header) throws IOException {
static MemorySegment decompress(LocalFileHeader header) throws IOException {
int method = header.getCompressionMethod();
switch (method) {
case STORED:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

import software.coley.lljzip.format.compression.Decompressor;
import software.coley.lljzip.format.compression.ZipCompressions;
import software.coley.lljzip.util.ByteData;
import software.coley.lljzip.util.ByteDataUtil;
import software.coley.lljzip.util.MemorySegmentUtil;
import software.coley.lljzip.util.lazy.LazyByteData;
import software.coley.lljzip.util.lazy.LazyInt;
import software.coley.lljzip.util.lazy.LazyLong;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.foreign.MemorySegment;

/**
* Common base for shared elements of {@link CentralDirectoryFileHeader} and {@link LocalFileHeader}.
Expand All @@ -35,7 +35,7 @@ public abstract class AbstractZipFileHeader implements ZipPart, ZipRead {
protected transient long offset = -1L;

// Data source that contents were read from.
protected transient ByteData data;
protected transient MemorySegment data;

// String cache values
private transient String fileNameCache;
Expand All @@ -45,7 +45,7 @@ public abstract class AbstractZipFileHeader implements ZipPart, ZipRead {
* @return The associated backing data that this file header was read from.
*/
@Nullable
public ByteData getBackingData() {
public MemorySegment getBackingData() {
return data;
}

Expand All @@ -55,7 +55,7 @@ public long offset() {
}

@Override
public void read(@Nonnull ByteData data, long offset) {
public void read(@Nonnull MemorySegment data, long offset) {
this.data = data;
this.offset = offset;
}
Expand Down Expand Up @@ -230,15 +230,15 @@ public void setExtraFieldLength(int extraFieldLength) {
*
* @return File name.
*/
public ByteData getFileName() {
public MemorySegment getFileName() {
return fileName.get();
}

/**
* @param fileName
* File name.
*/
public void setFileName(ByteData fileName) {
public void setFileName(MemorySegment fileName) {
this.fileName.set(fileName);
fileNameCache = null;
}
Expand All @@ -252,7 +252,7 @@ public void setFileName(ByteData fileName) {
public String getFileNameAsString() {
String fileNameCache = this.fileNameCache;
if (fileNameCache == null && fileName != null) {
return this.fileNameCache = ByteDataUtil.toString(fileName.get());
return this.fileNameCache = MemorySegmentUtil.toString(fileName.get());
}
return fileNameCache;
}
Expand All @@ -261,15 +261,15 @@ public String getFileNameAsString() {
* @return May be used for extra compression information,
* depending on the {@link #getCompressionMethod() compression method} used.
*/
public ByteData getExtraField() {
public MemorySegment getExtraField() {
return extraField.get();
}

/**
* @param extraField
* Extra field bytes.
*/
public void setExtraField(ByteData extraField) {
public void setExtraField(MemorySegment extraField) {
this.extraField.set(extraField);
}

Expand All @@ -279,7 +279,7 @@ public void setExtraField(ByteData extraField) {
public String getExtraFieldAsString() {
String fileCommentCache = this.extraFieldCache;
if (fileCommentCache == null && extraField != null) {
return this.extraFieldCache = ByteDataUtil.toString(extraField.get());
return this.extraFieldCache = MemorySegmentUtil.toString(extraField.get());
}
return fileCommentCache;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package software.coley.lljzip.format.model;

import software.coley.lljzip.util.BufferData;
import software.coley.lljzip.util.NoopByteData;
import software.coley.lljzip.util.lazy.LazyByteData;
import software.coley.lljzip.util.lazy.LazyInt;
import software.coley.lljzip.util.lazy.LazyLong;
Expand All @@ -10,6 +8,7 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.foreign.MemorySegment;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

Expand Down Expand Up @@ -45,20 +44,20 @@ public AdaptingLocalFileHeader(@Nonnull ZipFile archive, @Nonnull ZipEntry entry
lastModFileTime = new LazyInt(() -> 0);
lastModFileDate = new LazyInt(() -> 0);
fileNameLength = new LazyInt(entryName::length);
fileName = new LazyByteData(() -> BufferData.wrap(entryName.getBytes()));
fileName = new LazyByteData(() -> MemorySegment.ofArray(entryName.getBytes()));
fileDataLength = new LazyLong(() -> entryData.length);
fileData = new LazyByteData(() -> BufferData.wrap(entryData));
fileData = new LazyByteData(() -> MemorySegment.ofArray(entryData));
compressionMethod = new LazyInt(() -> 0);
uncompressedSize = new LazyLong(() -> entryData.length);
compressedSize = new LazyLong(() -> entryData.length);
crc32 = new LazyInt(() -> (int) entry.getCrc());
if (extra != null) {
extraFieldLength = new LazyInt(() -> extra.length);
extraField = new LazyByteData(() -> BufferData.wrap(extra));
extraField = new LazyByteData(() -> MemorySegment.ofArray(extra));
} else {
extraFieldLength = new LazyInt(() -> 0);
extraField = new LazyByteData(() -> NoopByteData.INSTANCE);
extraField = new LazyByteData(() -> MemorySegment.ofArray(new byte[0]));
}
data = NoopByteData.INSTANCE;
data = MemorySegment.ofArray(new byte[0]);
}
}
Loading

0 comments on commit 005749b

Please sign in to comment.