Skip to content

Commit ee240e0

Browse files
authored
Merge pull request #95 from jamesmudd/compound
Add Compound Dataset and Array Data type support
2 parents 9dfe8c6 + dca1c90 commit ee240e0

16 files changed

+468
-150
lines changed

Diff for: jhdf/src/main/java/io/jhdf/api/Dataset.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ public interface Dataset extends Node {
5555
*/
5656
boolean isEmpty();
5757

58+
59+
/**
60+
* Checks if this dataset is a compound dataset. i.e. it contains several named datasets.
61+
*
62+
* @return <code>true</code> if this is a compount dataset, <code>false</code> otherwise
63+
*/
64+
boolean isCompound();
65+
5866
/**
5967
* Gets the max size of this dataset. If not specified this will be equal to
6068
* {@link #getDimensions()}
@@ -80,7 +88,8 @@ public interface Dataset extends Node {
8088
* <li>A Java array of dimensions of the dataset as returned by
8189
* {@link #getDimensions()}. The type of the array will be the return value of
8290
* {@link #getJavaType()}.</li>
83-
* <li><code>null</code> if the dataset if empty ({@link #isEmpty()}).</li>
91+
* <li>A Java {@link java.util.Map} if {@link #isCompound()} returns <code>true</code></li>
92+
* <li><code>null</code> if the dataset is empty ({@link #isEmpty()}).</li>
8493
* </ul>
8594
*
8695
* @return the data in the dataset as a Java object or <code>null</code> if the
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*******************************************************************************
2+
* This file is part of jHDF. A pure Java library for accessing HDF5 files.
3+
*
4+
* http://jhdf.io
5+
*
6+
* Copyright 2019 James Mudd
7+
*
8+
* MIT License see 'LICENSE' file
9+
******************************************************************************/
10+
package io.jhdf.dataset;
11+
12+
import io.jhdf.object.datatype.CompoundDataType;
13+
import io.jhdf.object.datatype.CompoundDataType.CompoundDataMember;
14+
15+
import java.nio.ByteBuffer;
16+
import java.util.LinkedHashMap;
17+
import java.util.List;
18+
import java.util.Map;
19+
20+
import static java.lang.Math.toIntExact;
21+
22+
public final class CompoundDatasetReader {
23+
24+
/** No instances */
25+
private CompoundDatasetReader() {
26+
}
27+
28+
public static Map<String, Object> readDataset(CompoundDataType type, ByteBuffer buffer, long size, int[] dimensions) {
29+
final int sizeAsInt = toIntExact(size);
30+
31+
final List<CompoundDataMember> members = type.getMembers();
32+
33+
final Map<String, Object> data = new LinkedHashMap<>(members.size());
34+
35+
for (CompoundDataMember member : members) {
36+
final byte[] memberBytes = new byte[member.getDataType().getSize()];
37+
final ByteBuffer memberBuffer = ByteBuffer.allocate(member.getDataType().getSize() * sizeAsInt);
38+
39+
// Loop through the date buffer extracting the bytes for this member
40+
for (int i = 0; i < sizeAsInt; i++) {
41+
buffer.position(type.getSize() * i + member.getOffset());
42+
buffer.get(memberBytes, 0, memberBytes.length);
43+
memberBuffer.put(memberBytes);
44+
}
45+
46+
// Now read this member
47+
memberBuffer.rewind();
48+
final Object memberData = DatasetReader.readDataset(member.getDataType(), memberBuffer, dimensions);
49+
data.put(member.getName(), memberData);
50+
}
51+
52+
return data;
53+
}
54+
}

Diff for: jhdf/src/main/java/io/jhdf/dataset/DatasetBase.java

+6
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import java.nio.ByteBuffer;
1616
import java.nio.ByteOrder;
1717

18+
import io.jhdf.object.datatype.CompoundDataType;
1819
import org.slf4j.Logger;
1920
import org.slf4j.LoggerFactory;
2021

@@ -128,6 +129,8 @@ public Object getData() {
128129
if (type instanceof VariableLength) {
129130
return VariableLengthDatasetReader.readDataset((VariableLength) type, bb,
130131
getDimensions(), hdfFc);
132+
} else if(type instanceof CompoundDataType) {
133+
return CompoundDatasetReader.readDataset((CompoundDataType) type, bb, getSize(), getDimensions());
131134
} else {
132135
return DatasetReader.readDataset(type, bb, getDimensions());
133136
}
@@ -143,6 +146,9 @@ public boolean isEmpty() {
143146
return getDiskSize() == 0;
144147
}
145148

149+
@Override
150+
public boolean isCompound() { return getDataType() instanceof CompoundDataType; }
151+
146152
/**
147153
* Gets the buffer that holds this datasets data. The returned buffer will be of
148154
* the correct order (endiness).

Diff for: jhdf/src/main/java/io/jhdf/dataset/DatasetReader.java

+54-41
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import io.jhdf.object.datatype.FixedPoint;
3030
import io.jhdf.object.datatype.FloatingPoint;
3131
import io.jhdf.object.datatype.StringData;
32+
import io.jhdf.object.datatype.ArrayDataType;
3233

3334
/**
3435
* <p>
@@ -66,7 +67,7 @@ public static Object readDataset(DataType type, ByteBuffer buffer, int[] dimensi
6667
// Scalar dataset
6768
data = Array.newInstance(javaType, 1);
6869
isScalar = true;
69-
dimensions = new int[] { 1 }; // Fake the dimensions
70+
dimensions = new int[]{1}; // Fake the dimensions
7071
} else {
7172
data = Array.newInstance(javaType, dimensions);
7273
isScalar = false;
@@ -77,60 +78,72 @@ public static Object readDataset(DataType type, ByteBuffer buffer, int[] dimensi
7778
ByteOrder byteOrder = fixedPoint.getByteOrder();
7879
if (fixedPoint.isSigned()) {
7980
switch (fixedPoint.getSize()) {
80-
case 1:
81-
fillData(data, dimensions, buffer.order(byteOrder));
82-
break;
83-
case 2:
84-
fillData(data, dimensions, buffer.order(byteOrder).asShortBuffer());
85-
break;
86-
case 4:
87-
fillData(data, dimensions, buffer.order(byteOrder).asIntBuffer());
88-
break;
89-
case 8:
90-
fillData(data, dimensions, buffer.order(byteOrder).asLongBuffer());
91-
break;
92-
default:
93-
throw new HdfTypeException(
94-
"Unsupported signed integer type size " + fixedPoint.getSize() + " bytes");
81+
case 1:
82+
fillData(data, dimensions, buffer.order(byteOrder));
83+
break;
84+
case 2:
85+
fillData(data, dimensions, buffer.order(byteOrder).asShortBuffer());
86+
break;
87+
case 4:
88+
fillData(data, dimensions, buffer.order(byteOrder).asIntBuffer());
89+
break;
90+
case 8:
91+
fillData(data, dimensions, buffer.order(byteOrder).asLongBuffer());
92+
break;
93+
default:
94+
throw new HdfTypeException(
95+
"Unsupported signed integer type size " + fixedPoint.getSize() + " bytes");
9596
}
9697
} else { // Unsigned
9798
switch (fixedPoint.getSize()) {
98-
case 1:
99-
fillDataUnsigned(data, dimensions, buffer.order(byteOrder));
100-
break;
101-
case 2:
102-
fillDataUnsigned(data, dimensions, buffer.order(byteOrder).asShortBuffer());
103-
break;
104-
case 4:
105-
fillDataUnsigned(data, dimensions, buffer.order(byteOrder).asIntBuffer());
106-
break;
107-
case 8:
108-
fillDataUnsigned(data, dimensions, buffer.order(byteOrder).asLongBuffer());
109-
break;
110-
default:
111-
throw new HdfTypeException(
112-
"Unsupported signed integer type size " + fixedPoint.getSize() + " bytes");
99+
case 1:
100+
fillDataUnsigned(data, dimensions, buffer.order(byteOrder));
101+
break;
102+
case 2:
103+
fillDataUnsigned(data, dimensions, buffer.order(byteOrder).asShortBuffer());
104+
break;
105+
case 4:
106+
fillDataUnsigned(data, dimensions, buffer.order(byteOrder).asIntBuffer());
107+
break;
108+
case 8:
109+
fillDataUnsigned(data, dimensions, buffer.order(byteOrder).asLongBuffer());
110+
break;
111+
default:
112+
throw new HdfTypeException(
113+
"Unsupported signed integer type size " + fixedPoint.getSize() + " bytes");
113114
}
114115
}
115116
} else if (type instanceof FloatingPoint) {
116117
FloatingPoint floatingPoint = (FloatingPoint) type;
117118
ByteOrder byteOrder = floatingPoint.getByteOrder();
118119

119120
switch (floatingPoint.getSize()) {
120-
case 4:
121-
fillData(data, dimensions, buffer.order(byteOrder).asFloatBuffer());
122-
break;
123-
case 8:
124-
fillData(data, dimensions, buffer.order(byteOrder).asDoubleBuffer());
125-
break;
126-
default:
127-
throw new HdfTypeException(
128-
"Unsupported floating point type size " + floatingPoint.getSize() + " bytes");
121+
case 4:
122+
fillData(data, dimensions, buffer.order(byteOrder).asFloatBuffer());
123+
break;
124+
case 8:
125+
fillData(data, dimensions, buffer.order(byteOrder).asDoubleBuffer());
126+
break;
127+
default:
128+
throw new HdfTypeException(
129+
"Unsupported floating point type size " + floatingPoint.getSize() + " bytes");
129130
}
130131
} else if (type instanceof StringData) {
131132
int stringLength = type.getSize();
132133
fillFixedLengthStringData(data, dimensions, buffer, stringLength);
133-
} else {
134+
} else if (type instanceof ArrayDataType) {
135+
final ArrayDataType arrayType = (ArrayDataType) type;
136+
if (dimensions.length !=1) {
137+
throw new HdfException("Multi dimension array data types are not supported");
138+
}
139+
140+
for (int i = 0; i < dimensions[0]; i++) {
141+
// Need to position the buffer ready for the read
142+
buffer.position(i * arrayType.getBaseType().getSize() * arrayType.getDimensions()[0]);
143+
Object elementDataset = readDataset(arrayType.getBaseType(), buffer, arrayType.getDimensions());
144+
Array.set(data, i, elementDataset);
145+
}
146+
}else {
134147
throw new HdfException(
135148
"DatasetReader was passed a type it cant fill. Type: " + type.getClass().getCanonicalName());
136149
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*******************************************************************************
2+
* This file is part of jHDF. A pure Java library for accessing HDF5 files.
3+
*
4+
* http://jhdf.io
5+
*
6+
* Copyright 2019 James Mudd
7+
*
8+
* MIT License see 'LICENSE' file
9+
******************************************************************************/
10+
package io.jhdf.object.datatype;
11+
12+
import java.lang.reflect.Array;
13+
import java.nio.ByteBuffer;
14+
15+
import static io.jhdf.Utils.readBytesAsUnsignedInt;
16+
17+
/**
18+
* Class for reading array data type messages.
19+
*/
20+
public class ArrayDataType extends DataType {
21+
22+
private final DataType baseType;
23+
private final int[] dimensions;
24+
25+
26+
public ArrayDataType(ByteBuffer bb) {
27+
super(bb);
28+
29+
final int dimensionsSize = readBytesAsUnsignedInt(bb, 1);
30+
dimensions = new int[dimensionsSize];
31+
32+
if(getVersion() == 2) {
33+
// Skip 3 bytes
34+
bb.position(bb.position() + 3);
35+
}
36+
37+
for (int i = 0; i < dimensions.length; i++) {
38+
dimensions[i] = readBytesAsUnsignedInt(bb, 4);
39+
40+
if(getVersion() == 2) {
41+
// Skip Permutation Index not supported anyway
42+
bb.position(bb.position() + 4);
43+
}
44+
}
45+
46+
baseType = DataType.readDataType(bb);
47+
}
48+
49+
@Override
50+
public Class<?> getJavaType() {
51+
return Array.newInstance(baseType.getJavaType(), 0).getClass();
52+
}
53+
54+
public DataType getBaseType() {
55+
return baseType;
56+
}
57+
58+
public int[] getDimensions() {
59+
return dimensions;
60+
}
61+
}

0 commit comments

Comments
 (0)