Skip to content

Commit

Permalink
Support tracking prefix data in front of archives
Browse files Browse the repository at this point in the history
  • Loading branch information
Col-E committed Apr 27, 2024
1 parent 6046eb9 commit 5595347
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 9 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>software.coley</groupId>
<artifactId>lljzip</artifactId>
<version>2.4.1</version>
<version>2.5.0</version>

<name>LL Java ZIP</name>
<description>Lower level ZIP support for Java</description>
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/software/coley/lljzip/format/model/ZipArchive.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package software.coley.lljzip.format.model;

import software.coley.lljzip.format.read.ZipReader;
import software.coley.lljzip.format.transform.ZipPartMapper;
import software.coley.lljzip.util.OffsetComparator;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.Closeable;
import java.io.IOException;
import java.lang.foreign.MemorySegment;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
Expand All @@ -19,6 +21,7 @@
public class ZipArchive implements AutoCloseable, Iterable<ZipPart> {
private final List<ZipPart> parts = new ArrayList<>();
private final Closeable closableBackingResource;
private MemorySegment prefixData;

/**
* New zip archive without any backing resource.
Expand All @@ -37,6 +40,28 @@ public ZipArchive(@Nonnull Closeable closableBackingResource) {
this.closableBackingResource = closableBackingResource;
}

/**
* If the {@link ZipReader} used to read this archive supports tracking such information this will return
* any data not contained in the archive that was found at the front of the input content.
* <p/>
* Some applications like Jar2Exe will prepend a loader executable in front of the jar, in which case this content
* would be that executable. It can be any kind of arbitrary data though.
*
* @return Data at the front of the archive.
*/
@Nullable
public MemorySegment getPrefixData() {
return prefixData;
}

/**
* @param prefixData
* Data at the front of the archive.
*/
public void setPrefixData(@Nullable MemorySegment prefixData) {
this.prefixData = prefixData;
}

/**
* @param mapper
* Part mapper to manipulate contained zip parts.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
import javax.annotation.Nonnull;
import java.io.IOException;
import java.lang.foreign.MemorySegment;
import java.util.HashSet;
import java.util.Set;
import java.util.*;

/**
* The standard read strategy that should work with standard zip archives.
Expand Down Expand Up @@ -67,7 +66,7 @@ public void read(@Nonnull ZipArchive zip, @Nonnull MemorySegment data) throws IO

// Read local files
// - Set to prevent duplicate file header entries for the same offset
Set<Long> offsets = new HashSet<>();
NavigableSet<Long> offsets = new TreeSet<>();
for (CentralDirectoryFileHeader directory : zip.getCentralDirectories()) {
long offset = zipStart + directory.getRelativeOffsetOfLocalHeader();
if (!offsets.contains(offset) && MemorySegmentUtil.readQuad(data, offset) == ZipPatterns.LOCAL_FILE_HEADER_QUAD) {
Expand All @@ -83,6 +82,12 @@ public void read(@Nonnull ZipArchive zip, @Nonnull MemorySegment data) throws IO
}
}

// Record any data appearing at the front of the file not associated with the ZIP file contents.
if (!offsets.isEmpty()) {
long firstOffset = offsets.first();
zip.setPrefixData(data.asSlice(0, firstOffset));
}

// Sort based on order
zip.sortParts(new OffsetComparator());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public JvmZipReader() {
*
* @param skipRevisitedCenToLocalLinks
* Flag to skip creating duplicate {@link LocalFileHeader} entries if multiple
* {@link CentralDirectoryFileHeader} point to the same location.
* {@link CentralDirectoryFileHeader} point to the same location.
*/
public JvmZipReader(boolean skipRevisitedCenToLocalLinks) {
this(new JvmZipPartAllocator(), skipRevisitedCenToLocalLinks);
Expand All @@ -53,7 +53,7 @@ public JvmZipReader(boolean skipRevisitedCenToLocalLinks) {
* Allocator to use.
* @param skipRevisitedCenToLocalLinks
* Flag to skip creating duplicate {@link LocalFileHeader} entries if multiple
* {@link CentralDirectoryFileHeader} point to the same location.
* {@link CentralDirectoryFileHeader} point to the same location.
*/
public JvmZipReader(@Nonnull ZipPartAllocator allocator, boolean skipRevisitedCenToLocalLinks) {
super(allocator);
Expand Down Expand Up @@ -203,6 +203,12 @@ else if (MemorySegmentUtil.readQuad(data, jvmBaseFileOffset) == ZipPatterns.CENT
}
}

// Record any data appearing at the front of the file not associated with the ZIP file contents.
if (!entryOffsets.isEmpty()) {
long firstOffset = entryOffsets.first();
zip.setPrefixData(data.asSlice(0, firstOffset));
}

// Sort based on order
zip.sortParts(new OffsetComparator());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,18 @@ public NaiveLocalFileZipReader(@Nonnull ZipPartAllocator allocator) {

@Override
public void read(@Nonnull ZipArchive zip, @Nonnull MemorySegment data) throws IOException {
long localFileOffset = -1;
while ((localFileOffset = MemorySegmentUtil.indexOfQuad(data, localFileOffset + 1, ZipPatterns.LOCAL_FILE_HEADER_QUAD)) >= 0) {
long localFileOffset = MemorySegmentUtil.indexOfQuad(data, 0, ZipPatterns.LOCAL_FILE_HEADER_QUAD);
if (localFileOffset < 0) return;
if (localFileOffset > 0) {
// The first offset containing archive data is not at the first byte.
// Record whatever content is at the front.
zip.setPrefixData(data.asSlice(0, localFileOffset));
}
do {
LocalFileHeader file = newLocalFileHeader();
file.read(data, localFileOffset);
zip.addPart(file);
postProcessLocalFileHeader(file);
}
} while ((localFileOffset = MemorySegmentUtil.indexOfQuad(data, localFileOffset + 1, ZipPatterns.LOCAL_FILE_HEADER_QUAD)) >= 0);
}
}

0 comments on commit 5595347

Please sign in to comment.