Allow ZipPackIndex to work with any byte channel

This commit is contained in:
embeddedt 2026-06-04 20:57:13 -04:00
parent 0ecee529d7
commit f1492cc829
No known key found for this signature in database
GPG Key ID: A69433EC199B5613

View File

@ -13,7 +13,9 @@ import java.io.InputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import java.nio.channels.SeekableByteChannel;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardOpenOption; import java.nio.file.StandardOpenOption;
import java.util.*; import java.util.*;
@ -106,8 +108,16 @@ public class ZipPackIndex {
this.root = buildTree(); this.root = buildTree();
} }
private static SeekableByteChannel obtainChannel(Path filePath) throws IOException {
try {
return FileChannel.open(filePath, StandardOpenOption.READ);
} catch (Exception e) {
return Files.newByteChannel(filePath);
}
}
private static ByteBuffer readCentralDirectory(Path filePath) throws IOException { private static ByteBuffer readCentralDirectory(Path filePath) throws IOException {
try (FileChannel channel = FileChannel.open(filePath, StandardOpenOption.READ)) { try (SeekableByteChannel channel = obtainChannel(filePath)) {
long fileSize = channel.size(); long fileSize = channel.size();
if (fileSize < EOCD_SIZE) return null; if (fileSize < EOCD_SIZE) return null;
@ -117,7 +127,8 @@ public class ZipPackIndex {
long tailStart = fileSize - tailSize; long tailStart = fileSize - tailSize;
while (tail.hasRemaining()) { while (tail.hasRemaining()) {
int n = channel.read(tail, tailStart + tail.position()); channel.position(tailStart + tail.position());
int n = channel.read(tail);
if (n < 0) { if (n < 0) {
break; break;
} }
@ -151,19 +162,22 @@ public class ZipPackIndex {
} }
// Try memory-mapping first; fall back to a heap copy if the OS refuses. // Try memory-mapping first; fall back to a heap copy if the OS refuses.
try { if (channel instanceof FileChannel fc) {
ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, cdOffset, cdSize); try {
buf.order(ByteOrder.LITTLE_ENDIAN); ByteBuffer buf = fc.map(FileChannel.MapMode.READ_ONLY, cdOffset, cdSize);
return buf; buf.order(ByteOrder.LITTLE_ENDIAN);
} catch (Exception ignored) { return buf;
// mmap unavailable (e.g. some Linux mount flags, container restrictions); } catch (Exception ignored) {
// read the central directory into a heap buffer instead. // mmap unavailable (e.g. some Linux mount flags, container restrictions);
// read the central directory into a heap buffer instead.
}
} }
ByteBuffer buf = ByteBuffer.allocate((int) cdSize); ByteBuffer buf = ByteBuffer.allocate((int) cdSize);
buf.order(ByteOrder.LITTLE_ENDIAN); buf.order(ByteOrder.LITTLE_ENDIAN);
while (buf.hasRemaining()) { while (buf.hasRemaining()) {
int n = channel.read(buf, cdOffset + buf.position()); channel.position(cdOffset + buf.position());
int n = channel.read(buf);
if (n < 0) throw new IOException("Truncated central directory during heap read"); if (n < 0) throw new IOException("Truncated central directory during heap read");
} }
buf.flip(); buf.flip();