Skip to content

Commit 3469ecf

Browse files
committed
refactor v2 code
1 parent ac431a4 commit 3469ecf

File tree

2 files changed

+70
-58
lines changed

2 files changed

+70
-58
lines changed

src/main/java/org/hdf5javalib/hdffile/dataobjects/messages/FilterPipelineMessage.java

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,23 @@
2222
*
2323
* <h2>Structure</h2>
2424
* <ul>
25-
* <li><b>Version (1 byte)</b>: The version of the fill value format.</li>
26-
* <li><b>Space Allocation Time (1 byte, version-dependent)</b>: When space for
27-
* fill values is allocated (Early, Late, or Incremental).</li>
28-
* <li><b>Fill Value Write Time (1 byte, version-dependent)</b>: When the fill
29-
* value is written (on creation or first write).</li>
30-
* <li><b>Fill Value Defined Flag (1 byte)</b>: Indicates if a user-defined fill
31-
* value is provided.</li>
32-
* <li><b>Fill Value Size (4 bytes, optional)</b>: The size of the fill value in bytes.</li>
33-
* <li><b>Fill Value Data (variable, optional)</b>: The actual fill value, matching
34-
* the dataset's datatype.</li>
25+
* <li><b>Version (1 byte)</b>: The version of the fill value format.</li>
26+
* <li><b>Space Allocation Time (1 byte, version-dependent)</b>: When space for
27+
* fill values is allocated (Early, Late, or Incremental).</li>
28+
* <li><b>Fill Value Write Time (1 byte, version-dependent)</b>: When the fill
29+
* value is written (on creation or first write).</li>
30+
* <li><b>Fill Value Defined Flag (1 byte)</b>: Indicates if a user-defined fill
31+
* value is provided.</li>
32+
* <li><b>Fill Value Size (4 bytes, optional)</b>: The size of the fill value in bytes.</li>
33+
* <li><b>Fill Value Data (variable, optional)</b>: The actual fill value, matching
34+
* the dataset's datatype.</li>
3535
* </ul>
3636
*
3737
* <h2>Usage</h2>
3838
* <ul>
39-
* <li>Defining default values for missing or newly allocated data.</li>
40-
* <li>Ensuring consistency when reading uninitialized portions of a dataset.</li>
41-
* <li>Improving dataset integrity in applications requiring structured default data.</li>
39+
* <li>Defining default values for missing or newly allocated data.</li>
40+
* <li>Ensuring consistency when reading uninitialized portions of a dataset.</li>
41+
* <li>Improving dataset integrity in applications requiring structured default data.</li>
4242
* </ul>
4343
*
4444
* @see HdfMessage
@@ -75,7 +75,7 @@ public FilterPipelineMessage(
7575
int flags,
7676
int sizeMessageData
7777
) {
78-
super(MessageType.FILL_VALUE_MESSAGE, sizeMessageData, flags);
78+
super(MessageType.FILTER_PIPELINE_MESSAGE, sizeMessageData, flags);
7979
this.version = version;
8080
this.numberOfFilters = numberOfFilters;
8181
this.filterDescriptions = filterDescriptions;
@@ -104,22 +104,23 @@ public ByteBufferDeflater getDeflater() {
104104
public static HdfMessage parseHeaderMessage(int flags, byte[] data, HdfDataFile hdfDataFile) {
105105
ByteBuffer buffer = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
106106

107-
// Parse the first 4 bytes
108107
int version = Byte.toUnsignedInt(buffer.get());
109108
int numberOfFilters = Byte.toUnsignedInt(buffer.get());
110-
buffer.position(buffer.position() + 2);
111-
buffer.position(buffer.position() + 4);
112109

113-
// Handle Version 2+ behavior and fillValueDefined flag
114110
if (version == 1) {
115-
List<FilterDescription> filterDescriptions = new ArrayList<>();
116-
for(int i = 0; i < numberOfFilters; i++) {
117-
filterDescriptions.add(FilterDescription.parseFilterDescription(buffer));
118-
}
119-
// Return a constructed instance of FillValueMessage
120-
return new FilterPipelineMessage(version, numberOfFilters, filterDescriptions, flags, data.length);
111+
// Skip 6 bytes of reserved space for V1
112+
buffer.position(buffer.position() + 6);
113+
} else if (version != 2) {
114+
// Version 2 has no extra header bytes to skip.
115+
throw new UnsupportedOperationException("Filter pipeline message version not supported: " + version);
116+
}
117+
118+
List<FilterDescription> filterDescriptions = new ArrayList<>();
119+
for (int i = 0; i < numberOfFilters; i++) {
120+
filterDescriptions.add(FilterDescription.parseFilterDescription(buffer, version));
121121
}
122-
throw new UnsupportedOperationException("Version not supported: " + version);
122+
123+
return new FilterPipelineMessage(version, numberOfFilters, filterDescriptions, flags, data.length);
123124
}
124125

125126
/**
@@ -173,21 +174,30 @@ public String toString() {
173174
'}';
174175
}
175176

176-
public static FilterDescription parseFilterDescription(ByteBuffer buffer) {
177+
public static FilterDescription parseFilterDescription(ByteBuffer buffer, int version) {
177178
int filterIndentification = Short.toUnsignedInt(buffer.getShort());
178-
int nameLength = Short.toUnsignedInt(buffer.getShort());
179+
int nameLength = 0;
180+
if ( version == 1 || (version == 2 && filterIndentification > 256)) {
181+
nameLength = Short.toUnsignedInt(buffer.getShort());
182+
}
179183
byte[] flagBytes = new byte[2];
180184
buffer.get(flagBytes);
181185
BitSet flags = BitSet.valueOf(flagBytes);
186+
182187
int numberOfValuesForClientData = Short.toUnsignedInt(buffer.getShort());
183-
byte[] nameBytes = new byte[nameLength];
184-
buffer.get(nameBytes);
185-
String name = new String(HdfReadUtils.trimZeroBytes(nameBytes));
188+
189+
String name = null;
190+
if( nameLength > 0) {
191+
byte[] nameBytes = new byte[nameLength];
192+
buffer.get(nameBytes);
193+
name = new String(HdfReadUtils.trimZeroBytes(nameBytes));
194+
}
195+
186196
int[] clientData = new int[numberOfValuesForClientData];
187197
for(int i = 0; i < numberOfValuesForClientData; i++) {
188198
clientData[i] = buffer.getInt();
189199
}
190-
if ( numberOfValuesForClientData%2 != 0) {
200+
if ( version == 1 && numberOfValuesForClientData%2 != 0) {
191201
int[] padding = new int[1];
192202
padding[0] = buffer.getInt();
193203
}

src/main/java/org/hdf5javalib/hdffile/infrastructure/fractalheap/FractalHeap.java

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,11 @@ public static FractalHeap read(SeekableByteChannel channel, long position, HdfDa
4343
filteredSize = header.filteredRootDirectSize;
4444
filterMask = header.filterMaskRoot;
4545
}
46-
long expectedBlockOffset = 0;
4746
Block root;
4847
if (nrows == 0) {
49-
root = readDirectBlock(channel, header, rootAddress, sizeOfOffset, expectedBlockOffset, filteredSize, filterMask);
48+
root = readDirectBlock(channel, header, rootAddress, sizeOfOffset, filteredSize, filterMask);
5049
} else {
51-
root = readIndirectBlock(channel, header, sizeOfOffset, sizeOfLength, rootAddress, expectedBlockOffset, -1, nrows);
50+
root = readIndirectBlock(channel, header, sizeOfOffset, sizeOfLength, rootAddress, -1, nrows);
5251
}
5352
FractalHeap heap = new FractalHeap();
5453
heap.header = header;
@@ -273,7 +272,7 @@ private static Filter parseV2Filter(ByteBuffer bb) {
273272
return f;
274273
}
275274

276-
private static Block readDirectBlock(SeekableByteChannel channel, FractalHeapHeader header, HdfFixedPoint address, FixedPointDatatype sizeOfOffset, long expectedBlockOffset, HdfFixedPoint filteredSize, long filterMask) throws IOException, InvocationTargetException, InstantiationException, IllegalAccessException {
275+
private static Block readDirectBlock(SeekableByteChannel channel, FractalHeapHeader header, HdfFixedPoint address, FixedPointDatatype sizeOfOffset, HdfFixedPoint filteredSize, long filterMask) throws IOException, InvocationTargetException, InstantiationException, IllegalAccessException {
277276
if (address.isUndefined()) {
278277
throw new IOException("Invalid direct block address");
279278
}
@@ -299,15 +298,12 @@ private static Block readDirectBlock(SeekableByteChannel channel, FractalHeapHea
299298
throw new IOException("Invalid heap header address in direct block");
300299
}
301300
HdfFixedPoint blockOffset = HdfReadUtils.readHdfFixedPointFromBuffer(header.offsetBytes, headerBuffer);
302-
if (blockOffset.getInstance(Long.class) != expectedBlockOffset) {
303-
throw new IOException("Block offset mismatch");
304-
}
305301
headerBuffer.position(4 + 1 + sizeOfOffset.getSize()+header.offsetBytes.getSize());
306302
long checksum = 0;
307303
if (header.checksumDirect) {
308304
checksum = Integer.toUnsignedLong(headerBuffer.getInt()); // checksum, not verifying
309305
}
310-
long blockSize = getBlockSize(header, expectedBlockOffset);
306+
long blockSize = getBlockSize(header, blockOffset.getInstance(Long.class));
311307
long dataSize;
312308
if (!filteredSize.isUndefined()) {
313309
dataSize = filteredSize.getInstance(Long.class);
@@ -317,16 +313,23 @@ private static Block readDirectBlock(SeekableByteChannel channel, FractalHeapHea
317313
if (dataSize < 0) {
318314
throw new IOException("Invalid data size in direct block");
319315
}
320-
headerBuffer = ByteBuffer.allocate((int) dataSize).order(ByteOrder.LITTLE_ENDIAN);
316+
// Determine the maximum number of bytes that can be read
317+
long fSize = channel.size();
318+
long fPosition = channel.position();
319+
long bytesRemainingInFile = fSize - fPosition;
320+
321+
// The actual size to read is the smaller of the two values
322+
long actualReadSize = Math.min(dataSize, bytesRemainingInFile);
323+
headerBuffer = ByteBuffer.allocate((int) actualReadSize).order(ByteOrder.LITTLE_ENDIAN);
321324
bytesRead = channel.read(headerBuffer);
322-
if ( bytesRead != dataSize)
325+
if ( bytesRead != actualReadSize)
323326
throw new IllegalStateException();
324327
headerBuffer.flip();
325328

326329
byte[] data = headerBuffer.array();
327330
DirectBlock db = new DirectBlock();
328331
db.blockOffset = blockOffset.getInstance(Long.class);
329-
db.blockSize = blockSize;
332+
db.blockSize = actualReadSize;
330333
db.data = data;
331334
db.filterMask = filterMask;
332335
db.checksum = checksum;
@@ -367,7 +370,7 @@ private static int calculateChildrenEntriesSize(FractalHeapHeader header, int nr
367370
return entriesSize;
368371
}
369372

370-
private static void readAndVerifyIndirectBlockHeader(ByteBuffer blockBuffer, long expectedBlockOffset, FixedPointDatatype sizeOfOffset, FixedPointDatatype offsetBytes) throws IOException, InvocationTargetException, InstantiationException, IllegalAccessException {
373+
private static long readAndVerifyIndirectBlockHeader(ByteBuffer blockBuffer, FixedPointDatatype sizeOfOffset, FixedPointDatatype offsetBytes) throws IOException, InvocationTargetException, InstantiationException, IllegalAccessException {
371374
byte[] signatureBytes = new byte[4];
372375
blockBuffer.get(signatureBytes);
373376
String sig = new String(signatureBytes, StandardCharsets.US_ASCII);
@@ -386,14 +389,13 @@ private static void readAndVerifyIndirectBlockHeader(ByteBuffer blockBuffer, lon
386389
}
387390

388391
HdfFixedPoint blockOffset = HdfReadUtils.readHdfFixedPointFromBuffer(offsetBytes, blockBuffer);
389-
if (blockOffset.getInstance(Long.class) != expectedBlockOffset) {
390-
throw new IOException("Block offset mismatch");
391-
}
392+
393+
return blockOffset.getInstance(Long.class);
392394
}
393395

394396
private static List<ChildInfo> parseChildInfos(ByteBuffer blockBuffer, FractalHeapHeader header, int nrows, long startOffset, FixedPointDatatype sizeOfOffset, FixedPointDatatype sizeOfLength) throws InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
395397
List<ChildInfo> childInfos = new ArrayList<>();
396-
long currentOffset = startOffset;
398+
// long currentOffset = startOffset;
397399
long startingBlockSize = header.startingBlockSize.getInstance(Long.class);
398400

399401
for (short r = 0; r < nrows; r++) {
@@ -410,9 +412,9 @@ private static List<ChildInfo> parseChildInfos(ByteBuffer blockBuffer, FractalHe
410412
}
411413

412414
if (!childAddress.isUndefined()) {
413-
childInfos.add(new ChildInfo(childAddress, currentOffset, isDirect, childFilteredSize, childFilterMask, rowBlockSize));
415+
childInfos.add(new ChildInfo(childAddress, isDirect, childFilteredSize, childFilterMask, rowBlockSize));
414416
}
415-
currentOffset += rowBlockSize;
417+
// currentOffset += rowBlockSize;
416418
}
417419
}
418420
return childInfos;
@@ -423,17 +425,17 @@ private static List<Block> readChildren(SeekableByteChannel channel, FractalHeap
423425
for (ChildInfo info : childInfos) {
424426
Block child;
425427
if (info.isDirect) {
426-
child = readDirectBlock(channel, header, info.address, sizeOfOffset, info.blockOffset, info.filteredSize, info.filterMask);
428+
child = readDirectBlock(channel, header, info.address, sizeOfOffset, info.filteredSize, info.filterMask);
427429
} else {
428-
child = readIndirectBlock(channel, header, sizeOfOffset, sizeOfLength, info.address, info.blockOffset, info.blockSize, 0);
430+
child = readIndirectBlock(channel, header, sizeOfOffset, sizeOfLength, info.address, info.blockSize, 0);
429431
}
430432
children.add(child);
431433
}
432434
return children;
433435
}
434436
//</editor-fold>
435437

436-
private static Block readIndirectBlock(SeekableByteChannel channel, FractalHeapHeader header, FixedPointDatatype sizeOfOffset, FixedPointDatatype sizeOfLength, HdfFixedPoint address, long expectedBlockOffset, long iblockSize, int passedNrows) throws IOException, InvocationTargetException, InstantiationException, IllegalAccessException {
438+
private static Block readIndirectBlock(SeekableByteChannel channel, FractalHeapHeader header, FixedPointDatatype sizeOfOffset, FixedPointDatatype sizeOfLength, HdfFixedPoint address, long iblockSize, int passedNrows) throws IOException, InvocationTargetException, InstantiationException, IllegalAccessException {
437439
if (address.isUndefined()) {
438440
throw new IOException("Invalid indirect block address");
439441
}
@@ -456,15 +458,15 @@ private static Block readIndirectBlock(SeekableByteChannel channel, FractalHeapH
456458
blockBuffer.flip();
457459

458460
// 4. Verify the block's header fields. The buffer position is advanced past the header.
459-
readAndVerifyIndirectBlockHeader(blockBuffer, expectedBlockOffset, sizeOfOffset, header.offsetBytes);
461+
long fileBlockOffset = readAndVerifyIndirectBlockHeader(blockBuffer, sizeOfOffset, header.offsetBytes);
460462

461463
// 5. Parse child information from the buffer. The buffer position is advanced past the entries.
462-
List<ChildInfo> childInfos = parseChildInfos(blockBuffer, header, nrows, expectedBlockOffset, sizeOfOffset, sizeOfLength);
464+
List<ChildInfo> childInfos = parseChildInfos(blockBuffer, header, nrows, fileBlockOffset, sizeOfOffset, sizeOfLength);
463465

464466
// 6. Create the block object and read the checksum from the end of the buffer.
465467
IndirectBlock ib = new IndirectBlock();
466468
ib.nrows = nrows;
467-
ib.blockOffset = expectedBlockOffset;
469+
ib.blockOffset = fileBlockOffset;
468470
ib.checksum = Integer.toUnsignedLong(blockBuffer.getInt());
469471

470472
// 7. Recursively read all children based on the parsed info.
@@ -575,15 +577,15 @@ public static class IndirectBlock extends Block {
575577

576578
private static class ChildInfo {
577579
HdfFixedPoint address;
578-
long blockOffset;
580+
// long blockOffset;
579581
boolean isDirect;
580582
HdfFixedPoint filteredSize;
581583
long filterMask;
582584
long blockSize;
583585

584-
public ChildInfo(HdfFixedPoint address, long blockOffset, boolean isDirect, HdfFixedPoint filteredSize, long filterMask, long blockSize) {
586+
public ChildInfo(HdfFixedPoint address, boolean isDirect, HdfFixedPoint filteredSize, long filterMask, long blockSize) {
585587
this.address = address;
586-
this.blockOffset = blockOffset;
588+
// this.blockOffset = blockOffset;
587589
this.isDirect = isDirect;
588590
this.filteredSize = filteredSize;
589591
this.filterMask = filterMask;

0 commit comments

Comments
 (0)