Skip to content

Commit db57be7

Browse files
committed
fix ReadOnlyZipStore for zips with
1. leading slashes in paths 2. no sizes in entry headers
1 parent dbc559c commit db57be7

File tree

1 file changed

+27
-15
lines changed

1 file changed

+27
-15
lines changed

src/main/java/dev/zarr/zarrjava/store/ReadOnlyZipStore.java

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515

1616
import static dev.zarr.zarrjava.utils.ZipUtils.getZipCommentFromBuffer;
1717

18+
19+
/** A Store implementation that provides read-only access to a zip archive stored in an underlying Store.
20+
* Compared to BufferedZipStore, this implementation reads directly from the zip archive without parsing
21+
* its contents into a buffer store first making it more efficient for read-only access to large zip archives.
22+
*/
1823
public class ReadOnlyZipStore implements Store, Store.ListableStore {
1924

2025
private final StoreHandle underlyingStore;
@@ -69,21 +74,24 @@ public ByteBuffer get(String[] keys, long start, long end) {
6974
try (ZipArchiveInputStream zis = new ZipArchiveInputStream(new ByteBufferBackedInputStream(buffer))) {
7075
ZipArchiveEntry entry;
7176
while ((entry = zis.getNextEntry()) != null) {
72-
if (entry.isDirectory() || !entry.getName().equals(resolveKeys(keys))) {
73-
continue;
74-
}
75-
ByteArrayOutputStream baos = new ByteArrayOutputStream();
76-
if (end == -1) {
77-
end = entry.getSize();
77+
String entryName = entry.getName();
78+
79+
if (entryName.startsWith("/")) {
80+
entryName = entryName.substring(1);
7881
}
79-
if (start > end) {
80-
throw new IllegalArgumentException("Start position can not be larger than end position. Got start=" + start + ", end=" + end);
82+
if (entry.isDirectory() || !entryName.equals(resolveKeys(keys))) {
83+
continue;
8184
}
82-
if (start < 0 || end > entry.getSize()) {
83-
throw new IllegalArgumentException("Start and end positions must be within the bounds of the zip entry size. Entry size=" + entry.getSize() + ", got start=" + start + ", end=" + end);
85+
86+
if (zis.skip(start) != start) {
87+
throw new IOException("Failed to skip to start position " + start + " in zip entry " + entryName);
8488
}
85-
zis.skip(start);
86-
long bytesToRead = end - start;
89+
90+
long bytesToRead;
91+
if (end != -1) bytesToRead = end - start;
92+
else bytesToRead = Long.MAX_VALUE;
93+
94+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
8795
byte[] bufferArray = new byte[8192];
8896
int len;
8997
while (bytesToRead > 0 && (len = zis.read(bufferArray, 0, (int) Math.min(bufferArray.length, bytesToRead))) != -1) {
@@ -144,11 +152,15 @@ public Stream<String[]> list(String[] keys) {
144152
ZipArchiveEntry entry;
145153
String prefix = resolveKeys(keys);
146154
while ((entry = zis.getNextEntry()) != null) {
147-
String entryKey = entry.getName();
148-
if (!entryKey.startsWith(prefix) || entryKey.equals(prefix)) {
155+
String entryName = entry.getName();
156+
if (entryName.startsWith("/")) {
157+
entryName = entryName.substring(1);
158+
}
159+
160+
if (!entryName.startsWith(prefix) || entryName.equals(prefix)) {
149161
continue;
150162
}
151-
String[] entryKeys = resolveEntryKeys(entryKey.substring(prefix.length()));
163+
String[] entryKeys = resolveEntryKeys(entryName.substring(prefix.length()));
152164
builder.add(entryKeys);
153165
}
154166
} catch (IOException e) {

0 commit comments

Comments
 (0)