44import ucar .ma2 .Section ;
55import ucar .nc2 .Dimension ;
66import ucar .nc2 .Variable ;
7+ import ucar .nc2 .filter .Filter ;
78import ucar .nc2 .iosp .LayoutBB ;
89import ucar .nc2 .iosp .LayoutBBTiled ;
910import ucar .unidata .io .RandomAccessFile ;
1213import java .nio .*;
1314import java .util .ArrayList ;
1415import java .util .List ;
16+ import java .util .Map ;
1517import java .util .Set ;
1618
1719/**
18- * A tiled layout for Zarr formats that accommodates uncompressing anf filtering data before returning
20+ * A tiled layout for Zarr formats that accommodates uncompressing and filtering data before returning
1921 */
2022public class ZarrLayoutBB implements LayoutBB {
2123
@@ -27,39 +29,35 @@ public class ZarrLayoutBB implements LayoutBB {
2729 private final Section want ;
2830
2931 private int [] chunkSize ; // number of elements per chunks
30- private int elemSize ; // size of eelements in bytes
32+ private int elemSize ; // size of elements in bytes
3133 private int nChunks []; // number of chunks per dimension
32- private int nBytes ; // number of bytes per chunk
3334 private int totalNChunks ; // total number of chunks
34- private int totalChunkSize ; // total number of elements per chunk
3535 private boolean F_order = false ; // F order storage?
36- private Set <Integer > initializedChunks ; // set of chunks that exist as files
37-
38- // offset to start of data
39- private static final int ZARR_COMPRESSOR_OFFSET = 16 ;
40- private int data_bytes_offset ;
36+ private Map <Integer , Long > initializedChunks ; // set of chunks that exist as files and their compressed size
37+ private Filter compressor ;
38+ private List <Filter > filters ;
4139
4240 public ZarrLayoutBB (Variable v2 , Section wantSection , RandomAccessFile raf ) {
4341 // var data info
4442 this .raf = raf ;
4543 ZarrHeader .VInfo vinfo = (ZarrHeader .VInfo ) v2 .getSPobject ();
4644 this .byteOrder = vinfo .getByteOrder ();
4745 this .varOffset = vinfo .getOffset ();
48- this .data_bytes_offset = vinfo .getCompressor () == null ? 0 : ZARR_COMPRESSOR_OFFSET ;
46+ this .compressor = vinfo .getCompressor ();
47+ this .filters = vinfo .getFilters ();
48+
4949
5050 // fill in chunk info
5151 this .chunkSize = vinfo .getChunks ();
5252 int ndims = this .chunkSize .length ;
5353 this .initializedChunks = vinfo .getInitializedChunks ();
5454 this .nChunks = new int [ndims ];
5555 this .totalNChunks = 1 ;
56- this .totalChunkSize = 1 ;
5756 for (int i = 0 ; i < ndims ; i ++) {
5857 Dimension dim = v2 .getDimension (i );
5958 // round up nchunks if not evenly divisible by chunk size
6059 this .nChunks [i ] = (int ) Math .ceil (dim .getLength () / this .chunkSize [i ]);
6160 this .totalNChunks *= nChunks [i ];
62- this .totalChunkSize *= chunkSize [i ];
6361 }
6462
6563 // transpose wantsSection and chunk shape if F order
@@ -79,7 +77,6 @@ public ZarrLayoutBB(Variable v2, Section wantSection, RandomAccessFile raf) {
7977 }
8078
8179 this .elemSize = v2 .getDataType ().getSize ();
82- this .nBytes = totalChunkSize * elemSize ;
8380
8481 // create delegate and chunk iterator
8582 ZarrLayoutBB .DataChunkIterator iter = new ZarrLayoutBB .DataChunkIterator ();
@@ -110,18 +107,21 @@ private class DataChunkIterator implements LayoutBBTiled.DataChunkIterator {
110107
111108 private int [] currChunk ; // current chunk in subscript coords
112109 private int chunkNum ; // current chunk as flat index
110+ private long currOffset ; // byte position of current chunk
111+
113112
114113 DataChunkIterator () {
115114 this .currChunk = new int [chunkSize .length ];
116115 this .chunkNum = 0 ;
116+ this .currOffset = varOffset ; // start at start of variable data
117117 }
118118
119119 public boolean hasNext () {
120120 return this .chunkNum < totalNChunks ;
121121 }
122122
123123 public LayoutBBTiled .DataChunk next () {
124- DataChunk chunk = new ZarrLayoutBB .DataChunk (this .currChunk , this .chunkNum );
124+ DataChunk chunk = new ZarrLayoutBB .DataChunk (this .currChunk , this .chunkNum , this . currOffset );
125125 incrementChunk ();
126126 return chunk ;
127127 }
@@ -134,6 +134,7 @@ private void incrementChunk() {
134134 i --;
135135 }
136136 this .currChunk [i ]++;
137+ this .currOffset += initializedChunks .getOrDefault (this .chunkNum , (long ) 0 );
137138 this .chunkNum = ZarrUtils .subscriptsToIndex (this .currChunk , nChunks );
138139 }
139140 }
@@ -144,9 +145,9 @@ private class DataChunk implements LayoutBBTiled.DataChunk {
144145 private long rafOffset ; // start position of chunk in bytes
145146 private int chunkNum ;
146147
147- DataChunk (int [] index , int chunkNum ) {
148+ DataChunk (int [] index , int chunkNum , long rafOffset ) {
149+ this .rafOffset = rafOffset ;
148150 this .offset = new int [index .length ];
149- this .rafOffset = varOffset + (chunkNum * (nBytes + data_bytes_offset )) + data_bytes_offset ;
150151 for (int i = 0 ; i < index .length ; i ++) {
151152 int j = F_order ? index .length - i - 1 : i ;
152153 this .offset [i ] = index [j ] * chunkSize [i ];
@@ -162,14 +163,23 @@ public ByteBuffer getByteBuffer() throws IOException {
162163 // read the data
163164 byte [] data ;
164165 // if chunk does not exist as file, return empty buffer
165- if (!initializedChunks .contains (chunkNum )) {
166- data = new byte [0 ];
167- } else {
168- data = new byte [nBytes ];
169- raf .seek (this .rafOffset );
170- raf .readFully (data );
171-
172- // TODO: apply filters in reverse order
166+ long dataLength = initializedChunks .getOrDefault (chunkNum , (long ) 0 );
167+ if (dataLength == 0 ) {
168+ ByteBuffer result = ByteBuffer .wrap (new byte [0 ]);
169+ result .order (byteOrder );
170+ return result ;
171+ }
172+
173+ data = new byte [(int ) dataLength ];
174+ raf .seek (this .rafOffset );
175+ // raf.read(data, 0, (int)dataLength);
176+ raf .readFully (data );
177+
178+ // apply compressor
179+ data = compressor .decode (data );
180+ // apply filters in reverse order
181+ for (int i = filters .size () - 1 ; i >= 0 ; i --) {
182+ data = filters .get (i ).decode (data );
173183 }
174184
175185 ByteBuffer result = ByteBuffer .wrap (data );
0 commit comments