/src/bag/api/bag_georefmetadatalayer.cpp
Line | Count | Source |
1 | | |
2 | | #include "bag_georefmetadatalayer.h" |
3 | | #include "bag_metadataprofiles.h" |
4 | | #include "bag_georefmetadatalayerdescriptor.h" |
5 | | #include "bag_exceptions.h" |
6 | | #include "bag_hdfhelper.h" |
7 | | #include "bag_private.h" |
8 | | |
9 | | #include <array> |
10 | | #include <H5Cpp.h> |
11 | | #include <limits> |
12 | | #include <memory> |
13 | | #include <vector> |
14 | | |
15 | | |
16 | | namespace BAG { |
17 | | |
18 | | namespace { |
19 | | |
20 | | //! Helper function to find the maximum value of the specified DataType. |
21 | | /*! |
22 | | \param dataType |
23 | | The type of data. |
24 | | Supported types are: DT_UINT8, DT_UINT16, DT_UINT32, DT_UINT64. |
25 | | |
26 | | \return |
27 | | The maximum value the specified data type can hold. |
28 | | */ |
29 | | hsize_t getDataTypeMax( |
30 | | DataType dataType) |
31 | 0 | { |
32 | 0 | switch(dataType) |
33 | 0 | { |
34 | 0 | case DT_UINT8: |
35 | 0 | return std::numeric_limits<uint8_t>::max(); |
36 | 0 | case DT_UINT16: |
37 | 0 | return std::numeric_limits<uint16_t>::max(); |
38 | 0 | case DT_UINT32: |
39 | 0 | return std::numeric_limits<uint32_t>::max(); |
40 | 0 | case DT_UINT64: |
41 | 0 | return std::numeric_limits<uint64_t>::max(); |
42 | 0 | default: |
43 | 0 | throw UnsupportedDataType{}; |
44 | 0 | } |
45 | 0 | } |
46 | | |
47 | | } |
48 | | |
49 | | //! The constructor. |
50 | | /*! |
51 | | \param dataset |
52 | | The BAG Dataset this layer belongs to. |
53 | | \param descriptor |
54 | | The descriptor of this layer. |
55 | | \param pH5keyDataSet |
56 | | The HDF5 DataSet that will hold the single resolution keys. |
57 | | \param pH5vrKeyDataSet |
58 | | The HDF5 DataSet that will hold the variable resolution keys. |
59 | | \param pH5valueDataSet |
60 | | The HDF5 DataSet that will hold the spatial metadata values. |
61 | | */ |
62 | | GeorefMetadataLayer::GeorefMetadataLayer( |
63 | | Dataset& dataset, |
64 | | GeorefMetadataLayerDescriptor& descriptor, |
65 | | std::unique_ptr<::H5::DataSet, DeleteH5dataSet> pH5keyDataSet, |
66 | | std::unique_ptr<::H5::DataSet, DeleteH5dataSet> pH5vrKeyDataSet, |
67 | | std::unique_ptr<::H5::DataSet, DeleteH5dataSet> pH5valueDataSet) |
68 | 70 | : Layer(dataset, descriptor) |
69 | 70 | , m_pH5keyDataSet(std::move(pH5keyDataSet)) |
70 | 70 | , m_pH5vrKeyDataSet(std::move(pH5vrKeyDataSet)) |
71 | 70 | , m_pH5valueDataSet(std::move(pH5valueDataSet)) |
72 | 70 | { |
73 | 70 | } |
74 | | |
75 | | //! Create a georeferenced metadata layer. |
76 | | /*! |
77 | | \param keyType |
78 | | The type of key this layer will use. |
79 | | \param name |
80 | | The name of this georeferenced metadata layer. |
81 | | Must be a unique name among all georeferenced metadata layers in this BAG Dataset. |
82 | | \param dataset |
83 | | The BAG Dataset this georeferenced metadata layer will belong to. |
84 | | \param definition |
85 | | The list of fields describing a single record/value. |
86 | | \param chunkSize |
87 | | The chunk size the HDF5 DataSet will use. |
88 | | \param compressionLevel |
89 | | The compression level the HDF5 DataSet will use. |
90 | | |
91 | | \return |
92 | | The new georeferenced metadata layer. |
93 | | */ |
94 | | std::shared_ptr<GeorefMetadataLayer> GeorefMetadataLayer::create( |
95 | | DataType keyType, |
96 | | const std::string& name, |
97 | | GeorefMetadataProfile profile, |
98 | | Dataset& dataset, |
99 | | const RecordDefinition& definition, |
100 | | uint64_t chunkSize, |
101 | | int compressionLevel) |
102 | 0 | { |
103 | 0 | if (keyType != DT_UINT8 && keyType != DT_UINT16 && keyType != DT_UINT32 && |
104 | 0 | keyType != DT_UINT64) |
105 | 0 | throw InvalidKeyType{}; |
106 | | |
107 | | // The keys array should be the same dimensions as the mandatory elevation layer, so read |
108 | | // from the file global descriptor, and set. |
109 | 0 | uint32_t rows = 0, cols = 0; |
110 | 0 | std::tie<uint32_t, uint32_t>(rows, cols) = dataset.getDescriptor().getDims(); |
111 | 0 | auto pDescriptor = GeorefMetadataLayerDescriptor::create(dataset, name, profile, keyType, |
112 | 0 | definition, rows, cols, |
113 | 0 | chunkSize, compressionLevel); |
114 | | |
115 | | // Create the H5 Group to hold keys & values. |
116 | 0 | const auto& h5file = dataset.getH5file(); |
117 | 0 | h5file.createGroup(GEOREF_METADATA_PATH + name); |
118 | |
|
119 | 0 | auto h5keyDataSet = GeorefMetadataLayer::createH5keyDataSet(dataset, *pDescriptor); |
120 | | |
121 | | // create optional variable resolution keys. |
122 | 0 | std::unique_ptr<::H5::DataSet, DeleteH5dataSet> h5vrKeyDataSet{}; |
123 | |
|
124 | 0 | if (dataset.getVRMetadata()) |
125 | 0 | h5vrKeyDataSet = GeorefMetadataLayer::createH5vrKeyDataSet(dataset, *pDescriptor); |
126 | |
|
127 | 0 | auto h5valueDataSet = GeorefMetadataLayer::createH5valueDataSet(dataset, *pDescriptor); |
128 | |
|
129 | 0 | auto layer = std::make_shared<GeorefMetadataLayer>(dataset, |
130 | 0 | *pDescriptor, std::move(h5keyDataSet), |
131 | 0 | std::move(h5vrKeyDataSet), |
132 | 0 | std::move(h5valueDataSet)); |
133 | |
|
134 | 0 | layer->setValueTable(std::unique_ptr<ValueTable>(new ValueTable{*layer})); |
135 | |
|
136 | 0 | return layer; |
137 | 0 | } |
138 | | |
139 | | //! Open an existing georeferenced metadata layer. |
140 | | /*! |
141 | | \param dataset |
142 | | The BAG Dataset this layer belongs to. |
143 | | \param descriptor |
144 | | The descriptor of this layer. |
145 | | |
146 | | \return |
147 | | The georeferenced metadata layer read from dataset. |
148 | | */ |
149 | | std::shared_ptr<GeorefMetadataLayer> GeorefMetadataLayer::open( |
150 | | Dataset& dataset, |
151 | | GeorefMetadataLayerDescriptor& descriptor) |
152 | 73 | { |
153 | 73 | const auto& h5file = dataset.getH5file(); |
154 | 73 | const std::string& internalPath = descriptor.getInternalPath(); |
155 | 73 | auto h5keyDataSet = std::unique_ptr<::H5::DataSet, DeleteH5dataSet>( |
156 | 73 | new ::H5::DataSet{h5file.openDataSet(internalPath + COMPOUND_KEYS)}, |
157 | 73 | DeleteH5dataSet{}); |
158 | | |
159 | | // The keys array has the dimensions of the layer, so we can read and reset the |
160 | | // descriptor dimensions, in case they were inconsistent (or not set). |
161 | 73 | std::array<hsize_t, kRank> dims; |
162 | 73 | h5keyDataSet->getSpace().getSimpleExtentDims(dims.data(), nullptr); |
163 | 73 | descriptor.setDims(dims[0], dims[1]); |
164 | | |
165 | 73 | std::unique_ptr<::H5::DataSet, DeleteH5dataSet> h5vrKeyDataSet{}; |
166 | 73 | if (dataset.getVRMetadata()) |
167 | 0 | h5vrKeyDataSet = std::unique_ptr<::H5::DataSet, DeleteH5dataSet>( |
168 | 0 | new ::H5::DataSet{h5file.openDataSet(internalPath + COMPOUND_VR_KEYS)}, |
169 | 0 | DeleteH5dataSet{}); |
170 | | |
171 | 73 | auto h5valueDataSet = std::unique_ptr<::H5::DataSet, DeleteH5dataSet>( |
172 | 73 | new ::H5::DataSet{h5file.openDataSet(internalPath + COMPOUND_VALUES)}, |
173 | 73 | DeleteH5dataSet{}); |
174 | | |
175 | 73 | auto layer = std::make_shared<GeorefMetadataLayer>(dataset, |
176 | 73 | descriptor, |
177 | 73 | std::move(h5keyDataSet), |
178 | 73 | std::move(h5vrKeyDataSet), |
179 | 73 | std::move(h5valueDataSet)); |
180 | | |
181 | 73 | layer->setValueTable(std::unique_ptr<ValueTable>(new ValueTable{*layer})); |
182 | | |
183 | 73 | return layer; |
184 | 73 | } |
185 | | |
186 | | |
187 | | //! Create an HDF5 DataSet for the keys of a single resolution georeferenced metadata layer with details from the descriptor. |
188 | | /*! |
189 | | \param dataset |
190 | | The BAG Dataset this layer belongs to. |
191 | | \param descriptor |
192 | | The descriptor of this layer. |
193 | | |
194 | | \return |
195 | | The HDF5 DataSet containing the single resolution keys of a new georeferenced metadata layer. |
196 | | */ |
197 | | std::unique_ptr<::H5::DataSet, DeleteH5dataSet> |
198 | | GeorefMetadataLayer::createH5keyDataSet( |
199 | | const Dataset& dataset, |
200 | | const GeorefMetadataLayerDescriptor& descriptor) |
201 | 0 | { |
202 | 0 | std::unique_ptr<::H5::DataSet, DeleteH5dataSet> pH5dataSet; |
203 | |
|
204 | 0 | { |
205 | | // Use the dimensions from the descriptor. We could do this from the specific |
206 | | // descriptor for the layer, too, which should mirror the size of the file global |
207 | | // descriptor used here. |
208 | 0 | uint32_t dim0 = 0, dim1 = 0; |
209 | 0 | std::tie(dim0, dim1) = dataset.getDescriptor().getDims(); |
210 | 0 | const std::array<hsize_t, kRank> fileDims{dim0, dim1}; |
211 | | |
212 | | // Create the creation property list. |
213 | 0 | const ::H5::DSetCreatPropList h5createPropList{}; |
214 | 0 | h5createPropList.setFillTime(H5D_FILL_TIME_ALLOC); |
215 | |
|
216 | 0 | const auto dataType = descriptor.getDataType(); |
217 | 0 | const auto& memDataType = BAG::getH5memoryType(dataType); |
218 | |
|
219 | 0 | const std::vector<uint8_t> fillValue(Layer::getElementSize(dataType), 0); |
220 | 0 | h5createPropList.setFillValue(memDataType, fillValue.data()); |
221 | | |
222 | | // Use chunk size and compression level from the descriptor. |
223 | 0 | const auto compressionLevel = descriptor.getCompressionLevel(); |
224 | 0 | const auto chunkSize = descriptor.getChunkSize(); |
225 | 0 | if (chunkSize > 0) |
226 | 0 | { |
227 | 0 | const std::array<hsize_t, kRank> chunkDims{chunkSize, chunkSize}; |
228 | 0 | h5createPropList.setChunk(kRank, chunkDims.data()); |
229 | |
|
230 | 0 | if (compressionLevel > 0 && compressionLevel <= kMaxCompressionLevel) |
231 | 0 | h5createPropList.setDeflate(compressionLevel); |
232 | 0 | } |
233 | 0 | else if (compressionLevel > 0) |
234 | 0 | throw CompressionNeedsChunkingSet{}; |
235 | | |
236 | 0 | const ::H5::DataSpace fileDataSpace{kRank, fileDims.data(), fileDims.data()}; |
237 | |
|
238 | 0 | const auto& fileDataType = BAG::getH5fileType(dataType); |
239 | | |
240 | | // Create the DataSet using the above. |
241 | 0 | const auto& h5file = dataset.getH5file(); |
242 | |
|
243 | 0 | pH5dataSet = std::unique_ptr<::H5::DataSet, DeleteH5dataSet>( |
244 | 0 | new ::H5::DataSet{h5file.createDataSet( |
245 | 0 | descriptor.getInternalPath() + COMPOUND_KEYS, fileDataType, |
246 | 0 | fileDataSpace, h5createPropList)}, |
247 | 0 | DeleteH5dataSet{}); |
248 | 0 | } |
249 | | |
250 | | // Create the Record (value) Definition attribute. |
251 | 0 | { |
252 | 0 | const auto& definition = descriptor.getDefinition(); |
253 | 0 | const hsize_t dims = definition.size(); |
254 | 0 | const ::H5::DataSpace fileDataSpace{1, &dims, &dims}; |
255 | | |
256 | | // Create the compound type for the Record Definition. |
257 | 0 | const ::H5::StrType strType{::H5::PredType::C_S1, H5T_VARIABLE}; |
258 | | |
259 | | //works |
260 | 0 | const ::H5::CompType fileDataType{sizeof(FieldDefinition)}; |
261 | 0 | fileDataType.insertMember("name", HOFFSET(FieldDefinition, name), strType); |
262 | 0 | fileDataType.insertMember("type", HOFFSET(FieldDefinition, type), ::H5::PredType::NATIVE_UINT8); |
263 | | |
264 | | // Create the attribute. |
265 | 0 | const auto att = pH5dataSet->createAttribute(COMPOUND_RECORD_DEFINITION, |
266 | 0 | fileDataType, fileDataSpace); |
267 | | |
268 | | // Write metadata field definitions to the attribute. |
269 | 0 | att.write(fileDataType, definition.data()); |
270 | | |
271 | | // Specify a string attribute to indicate the metadata profile type |
272 | 0 | const auto profileAttType = ::H5::StrType{0, METADATA_PROFILE_LEN}; |
273 | 0 | const ::H5::DataSpace profileAttSpace{}; |
274 | 0 | const auto profileAttr = pH5dataSet->createAttribute(METADATA_PROFILE_TYPE, |
275 | 0 | profileAttType, profileAttSpace); |
276 | 0 | profileAttr.write(profileAttType, kGeorefMetadataProfileMapString.at(descriptor.m_profile).data()); |
277 | 0 | } |
278 | |
|
279 | 0 | return pH5dataSet; |
280 | 0 | } |
281 | | |
282 | | //! Create an HDF5 DataSet for the keys of a variable resolution georeferenced metadata layer with details from the descriptor. |
283 | | /*! |
284 | | \param dataset |
285 | | The BAG Dataset this layer belongs to. |
286 | | \param descriptor |
287 | | The descriptor of this layer. |
288 | | |
289 | | \return |
290 | | The HDF5 DataSet containing the variable resolution keys of a new georeferenced metadata layer. |
291 | | */ |
292 | | std::unique_ptr<::H5::DataSet, DeleteH5dataSet> |
293 | | GeorefMetadataLayer::createH5vrKeyDataSet( |
294 | | const Dataset& dataset, |
295 | | const GeorefMetadataLayerDescriptor& descriptor) |
296 | 0 | { |
297 | 0 | std::unique_ptr<::H5::DataSet, DeleteH5dataSet> pH5dataSet; |
298 | |
|
299 | 0 | { |
300 | 0 | const auto& h5file = dataset.getH5file(); |
301 | |
|
302 | 0 | const auto dataType = descriptor.getDataType(); |
303 | 0 | const auto& fileDataType = BAG::getH5fileType(dataType); |
304 | |
|
305 | 0 | constexpr hsize_t kFileLength = 0; |
306 | 0 | constexpr hsize_t kMaxFileLength = H5S_UNLIMITED; |
307 | 0 | const ::H5::DataSpace fileDataSpace{1, &kFileLength, &kMaxFileLength}; |
308 | | |
309 | | // Create the creation property list. |
310 | 0 | const ::H5::DSetCreatPropList h5createPropList{}; |
311 | 0 | h5createPropList.setFillTime(H5D_FILL_TIME_ALLOC); |
312 | | |
313 | | // Use chunk size and compression level from the layer descriptor. |
314 | 0 | const auto compressionLevel = descriptor.getCompressionLevel(); |
315 | 0 | const auto chunkSize = descriptor.getChunkSize(); |
316 | 0 | if (chunkSize > 0) |
317 | 0 | { |
318 | 0 | const auto chunk = static_cast<hsize_t>(chunkSize); |
319 | 0 | h5createPropList.setChunk(1, &chunk); |
320 | |
|
321 | 0 | if (compressionLevel > 0 && compressionLevel <= kMaxCompressionLevel) |
322 | 0 | h5createPropList.setDeflate(compressionLevel); |
323 | 0 | } |
324 | 0 | else if (compressionLevel > 0) |
325 | 0 | throw CompressionNeedsChunkingSet{}; |
326 | 0 | else |
327 | 0 | throw LayerRequiresChunkingSet{}; |
328 | | |
329 | | // Create the DataSet using the above. |
330 | 0 | pH5dataSet = std::unique_ptr<::H5::DataSet, DeleteH5dataSet>( |
331 | 0 | new ::H5::DataSet{h5file.createDataSet( |
332 | 0 | descriptor.getInternalPath() + COMPOUND_VR_KEYS, fileDataType, |
333 | 0 | fileDataSpace, h5createPropList)}, |
334 | 0 | DeleteH5dataSet{}); |
335 | 0 | } |
336 | | |
337 | 0 | return pH5dataSet; |
338 | 0 | } |
339 | | |
340 | | //! Create an HDF5 DataSet for the values of a georeferenced metadata layer with details from the descriptor. |
341 | | /*! |
342 | | \param dataset |
343 | | The BAG Dataset this layer belongs to. |
344 | | \param descriptor |
345 | | The descriptor of this layer. |
346 | | |
347 | | \return |
348 | | The HDF5 DataSet. |
349 | | */ |
350 | | std::unique_ptr<::H5::DataSet, DeleteH5dataSet> |
351 | | GeorefMetadataLayer::createH5valueDataSet( |
352 | | const Dataset& dataset, |
353 | | const GeorefMetadataLayerDescriptor& descriptor) |
354 | 0 | { |
355 | 0 | constexpr hsize_t numValues = 1; |
356 | 0 | const auto keyType = descriptor.getDataType(); |
357 | 0 | const hsize_t maxNumValues = getDataTypeMax(keyType); |
358 | |
|
359 | 0 | const ::H5::DataSpace fileDataSpace{1, &numValues, &maxNumValues}; |
360 | |
|
361 | 0 | const auto& definition = descriptor.getDefinition(); |
362 | 0 | const auto fileDataType = BAG::createH5fileCompType(definition); |
363 | | |
364 | | // Create the creation property list. |
365 | 0 | const ::H5::DSetCreatPropList h5createPropList{}; |
366 | 0 | h5createPropList.setFillTime(H5D_FILL_TIME_ALLOC); |
367 | |
|
368 | 0 | const std::vector<uint8_t> fillValue(BAG::getRecordSize(definition), 0); |
369 | 0 | h5createPropList.setFillValue(fileDataType, fillValue.data()); |
370 | |
|
371 | 0 | constexpr hsize_t kChunkSize = 100; |
372 | 0 | h5createPropList.setChunk(1, &kChunkSize); |
373 | | |
374 | | // Create the DataSet using the above. |
375 | 0 | const auto& h5file = dataset.getH5file(); |
376 | |
|
377 | 0 | auto pH5dataSet = std::unique_ptr<::H5::DataSet, DeleteH5dataSet>( |
378 | 0 | new ::H5::DataSet{h5file.createDataSet( |
379 | 0 | descriptor.getInternalPath() + COMPOUND_VALUES, fileDataType, |
380 | 0 | fileDataSpace, h5createPropList)}, |
381 | 0 | DeleteH5dataSet{}); |
382 | |
|
383 | 0 | return pH5dataSet; |
384 | 0 | } |
385 | | |
386 | | //! Retrieve the HDF5 DataSet containing the values. |
387 | | /*! |
388 | | \return |
389 | | The HDF5 DataSet containing the values. |
390 | | */ |
391 | | const ::H5::DataSet& GeorefMetadataLayer::getValueDataSet() const & |
392 | 70 | { |
393 | 70 | return *m_pH5valueDataSet; |
394 | 70 | } |
395 | | |
396 | | //! Retrieve the layer's descriptor. Note: this shadows BAG::Layer.getDescriptor() |
397 | | /*! |
398 | | \return |
399 | | The layer's descriptor. |
400 | | Will never be nullptr. |
401 | | */ |
402 | | std::shared_ptr<GeorefMetadataLayerDescriptor> GeorefMetadataLayer::getDescriptor() & noexcept |
403 | 0 | { |
404 | 0 | return std::dynamic_pointer_cast<GeorefMetadataLayerDescriptor>(Layer::getDescriptor()); |
405 | 0 | } |
406 | | |
407 | | //! Retrieve the layer's descriptor. Note: this shadows BAG::Layer.getDescriptor() |
408 | | /*! |
409 | | \return |
410 | | The layer's descriptor. |
411 | | Will never be nullptr. |
412 | | */ |
413 | 66 | std::shared_ptr<const GeorefMetadataLayerDescriptor> GeorefMetadataLayer::getDescriptor() const & noexcept { |
414 | 66 | return std::dynamic_pointer_cast<const GeorefMetadataLayerDescriptor>(Layer::getDescriptor()); |
415 | 66 | } |
416 | | |
417 | | //! Retrieve the value table. |
418 | | /*! |
419 | | \return |
420 | | The value table. |
421 | | */ |
422 | | ValueTable& GeorefMetadataLayer::getValueTable() & noexcept |
423 | 0 | { |
424 | 0 | return *m_pValueTable; |
425 | 0 | } |
426 | | |
427 | | //! Retrieve the value table. |
428 | | /*! |
429 | | \return |
430 | | The value table. |
431 | | */ |
432 | | const ValueTable& GeorefMetadataLayer::getValueTable() const & noexcept |
433 | 0 | { |
434 | 0 | return *m_pValueTable; |
435 | 0 | } |
436 | | |
437 | | //! \copydoc Layer::read |
438 | | UInt8Array GeorefMetadataLayer::readProxy( |
439 | | uint32_t rowStart, |
440 | | uint32_t columnStart, |
441 | | uint32_t rowEnd, |
442 | | uint32_t columnEnd) const |
443 | 0 | { |
444 | | // Query the file for the specified rows and columns. |
445 | 0 | const auto h5fileDataSpace = m_pH5keyDataSet->getSpace(); |
446 | | |
447 | | // Make sure the area being read from does not exceed the file dimensions. |
448 | 0 | const auto numDims = h5fileDataSpace.getSimpleExtentNdims(); |
449 | 0 | if (numDims != kRank) |
450 | 0 | throw InvalidReadSize{}; |
451 | | |
452 | 0 | std::array<hsize_t, kRank> fileDims{}; |
453 | 0 | h5fileDataSpace.getSimpleExtentDims(fileDims.data()); |
454 | |
|
455 | 0 | if ((rowEnd >= fileDims[0]) || (columnEnd >= fileDims[1])) |
456 | 0 | throw InvalidReadSize{}; |
457 | | |
458 | 0 | const auto rows = (rowEnd - rowStart) + 1; |
459 | 0 | const auto columns = (columnEnd - columnStart) + 1; |
460 | |
|
461 | 0 | const std::array<hsize_t, kRank> count{rows, columns}; |
462 | 0 | const std::array<hsize_t, kRank> offset{rowStart, columnStart}; |
463 | |
|
464 | 0 | h5fileDataSpace.selectHyperslab(H5S_SELECT_SET, count.data(), offset.data()); |
465 | | |
466 | | // Initialize the output buffer. |
467 | 0 | const auto bufferSize = this->getDescriptor()->getReadBufferSize(rows, |
468 | 0 | columns); |
469 | 0 | UInt8Array buffer{bufferSize}; |
470 | | |
471 | | // Prepare the memory space. |
472 | 0 | const ::H5::DataSpace h5memSpace{kRank, count.data(), count.data()}; |
473 | |
|
474 | 0 | m_pH5keyDataSet->read(buffer.data(), H5Dget_type(m_pH5keyDataSet->getId()), |
475 | 0 | h5memSpace, h5fileDataSpace); |
476 | |
|
477 | 0 | return buffer; |
478 | 0 | } |
479 | | |
480 | | //! Read the variable resolution metadata keys. |
481 | | /*! |
482 | | \param indexStart |
483 | | The starting index to read. |
484 | | Must be less than or equal to indexEnd. |
485 | | \param indexEnd |
486 | | The ending index to read. (inclusive) |
487 | | |
488 | | \return |
489 | | The specified keys. |
490 | | */ |
491 | | UInt8Array GeorefMetadataLayer::readVR( |
492 | | uint32_t indexStart, |
493 | | uint32_t indexEnd) const |
494 | 0 | { |
495 | | // Make sure the variable resolution key dataset is present. |
496 | 0 | if (!m_pH5vrKeyDataSet) |
497 | 0 | throw DatasetRequiresVariableResolution{}; |
498 | | |
499 | 0 | auto pDescriptor = std::dynamic_pointer_cast<const GeorefMetadataLayerDescriptor>( |
500 | 0 | this->getDescriptor()); |
501 | 0 | if (!pDescriptor) |
502 | 0 | throw InvalidLayerDescriptor{}; |
503 | | |
504 | | // Query the file for the specified rows and columns. |
505 | 0 | const auto h5fileDataSpace = m_pH5vrKeyDataSet->getSpace(); |
506 | | |
507 | | // Make sure the area being read from does not exceed the file dimensions. |
508 | 0 | const auto numDims = h5fileDataSpace.getSimpleExtentNdims(); |
509 | 0 | if (numDims != 1) |
510 | 0 | throw InvalidReadSize{}; |
511 | | |
512 | 0 | hsize_t fileLength = 0; |
513 | 0 | h5fileDataSpace.getSimpleExtentDims(&fileLength); |
514 | |
|
515 | 0 | if ((indexStart > indexEnd) || (indexEnd >= fileLength)) |
516 | 0 | throw InvalidReadSize{}; |
517 | | |
518 | | // Query the file. |
519 | 0 | const hsize_t count = (indexEnd - indexStart) + 1; |
520 | 0 | const hsize_t offset = indexStart; |
521 | |
|
522 | 0 | const auto fileDataSpace = m_pH5vrKeyDataSet->getSpace(); |
523 | 0 | fileDataSpace.selectHyperslab(H5S_SELECT_SET, &count, &offset); |
524 | | |
525 | | // Initialize the output buffer. |
526 | 0 | const auto bufferSize = pDescriptor->getReadBufferSize(1, |
527 | 0 | static_cast<uint32_t>(count)); |
528 | 0 | UInt8Array buffer{bufferSize}; |
529 | | |
530 | | // Prepare the memory space. |
531 | 0 | const ::H5::DataSpace memDataSpace{1, &count, &count}; |
532 | |
|
533 | 0 | m_pH5vrKeyDataSet->read(buffer.data(), |
534 | 0 | H5Dget_type(m_pH5vrKeyDataSet->getId()), memDataSpace, fileDataSpace); |
535 | |
|
536 | 0 | return buffer; |
537 | 0 | } |
538 | | |
539 | | //! Set the value table. |
540 | | /*! |
541 | | \param table |
542 | | The new value table. |
543 | | */ |
544 | | void GeorefMetadataLayer::setValueTable( |
545 | | std::unique_ptr<ValueTable> table) noexcept |
546 | 42 | { |
547 | 42 | m_pValueTable = std::move(table); |
548 | 42 | } |
549 | | |
550 | | //! \copydoc Layer::write |
551 | | void GeorefMetadataLayer::writeProxy( |
552 | | uint32_t rowStart, |
553 | | uint32_t columnStart, |
554 | | uint32_t rowEnd, |
555 | | uint32_t columnEnd, |
556 | | const uint8_t* buffer) |
557 | 0 | { |
558 | 0 | const auto h5fileDataSpace = m_pH5keyDataSet->getSpace(); |
559 | | |
560 | | // Make sure the area being written to does not exceed the file dimensions. |
561 | 0 | const auto numDims = h5fileDataSpace.getSimpleExtentNdims(); |
562 | 0 | if (numDims != kRank) |
563 | 0 | throw InvalidWriteSize{}; |
564 | | |
565 | 0 | std::array<hsize_t, kRank> fileDims{}; |
566 | 0 | h5fileDataSpace.getSimpleExtentDims(fileDims.data()); |
567 | |
|
568 | 0 | if ((rowEnd >= fileDims[0]) || (columnEnd >= fileDims[1])) |
569 | 0 | throw InvalidWriteSize{}; |
570 | | |
571 | 0 | const auto rows = (rowEnd - rowStart) + 1; |
572 | 0 | const auto columns = (columnEnd - columnStart) + 1; |
573 | 0 | const std::array<hsize_t, kRank> count{rows, columns}; |
574 | 0 | const std::array<hsize_t, kRank> offset{rowStart, columnStart}; |
575 | |
|
576 | 0 | h5fileDataSpace.selectHyperslab(H5S_SELECT_SET, count.data(), offset.data()); |
577 | | |
578 | | // Prepare the memory space. |
579 | 0 | const ::H5::DataSpace h5memDataSpace{kRank, count.data(), count.data()}; |
580 | |
|
581 | 0 | m_pH5keyDataSet->write(buffer, H5Dget_type(m_pH5keyDataSet->getId()), |
582 | 0 | h5memDataSpace, h5fileDataSpace); |
583 | 0 | } |
584 | | |
585 | | //! \copydoc Layer::writeAttributes |
586 | | void GeorefMetadataLayer::writeAttributesProxy() const |
587 | 0 | { |
588 | | // Nothing to be done. Attributes are not modified. |
589 | 0 | } |
590 | | |
591 | | //! Write the variable resolution metadata keys. |
592 | | /*! |
593 | | \param indexStart |
594 | | The starting index to write. |
595 | | Must be less than or equal to indexEnd. |
596 | | \param indexEnd |
597 | | The ending index to write. (inclusive) |
598 | | \param buffer |
599 | | The keys to be written. |
600 | | Must contain at least indexEnd - indexStart + 1 keys! |
601 | | */ |
602 | | void GeorefMetadataLayer::writeVR( |
603 | | uint32_t indexStart, |
604 | | uint32_t indexEnd, |
605 | | const uint8_t* buffer) |
606 | 0 | { |
607 | | // Make sure the dataset is available. |
608 | 0 | if (this->getDataset().expired()) |
609 | 0 | throw DatasetNotFound{}; |
610 | | |
611 | | // Make sure the variable resolution key dataset is present. |
612 | 0 | if (!m_pH5vrKeyDataSet) |
613 | 0 | throw DatasetRequiresVariableResolution{}; |
614 | | |
615 | | // Query the file for the specified rows and columns. |
616 | 0 | auto h5fileDataSpace = m_pH5vrKeyDataSet->getSpace(); |
617 | | |
618 | | // Make sure the area being read from does not exceed the file dimensions. |
619 | 0 | hsize_t fileLength = 0; |
620 | 0 | const auto numDims = h5fileDataSpace.getSimpleExtentDims(&fileLength); |
621 | 0 | if (numDims != 1) |
622 | 0 | throw InvalidWriteSize{}; |
623 | | |
624 | 0 | if (indexStart > indexEnd) |
625 | 0 | throw InvalidWriteSize{}; |
626 | | |
627 | 0 | auto pDescriptor = std::dynamic_pointer_cast<GeorefMetadataLayerDescriptor>( |
628 | 0 | this->getDescriptor()); |
629 | 0 | if (!pDescriptor) |
630 | 0 | throw InvalidLayerDescriptor{}; |
631 | | |
632 | 0 | const hsize_t count = (indexEnd - indexStart) + 1; |
633 | 0 | const hsize_t offset = indexStart; |
634 | 0 | const ::H5::DataSpace memDataSpace{1, &count, &count}; |
635 | | |
636 | | // Expand the file data space if needed. |
637 | 0 | if (fileLength < (indexEnd + 1)) |
638 | 0 | { |
639 | 0 | const auto newMaxLength = std::max<hsize_t>(fileLength, indexEnd + 1); |
640 | |
|
641 | 0 | m_pH5vrKeyDataSet->extend(&newMaxLength); |
642 | |
|
643 | 0 | h5fileDataSpace = m_pH5vrKeyDataSet->getSpace(); |
644 | | |
645 | | // Update the dataset's dimensions. |
646 | 0 | auto pDataset = this->getDataset().lock(); |
647 | 0 | pDataset->getDescriptor().setDims(1, static_cast<uint32_t>(newMaxLength)); |
648 | 0 | } |
649 | | |
650 | | // Write the specified data. |
651 | 0 | h5fileDataSpace.selectHyperslab(H5S_SELECT_SET, &count, &offset); |
652 | |
|
653 | 0 | m_pH5vrKeyDataSet->write(buffer, H5Dget_type(m_pH5vrKeyDataSet->getId()), |
654 | 0 | memDataSpace, h5fileDataSpace); |
655 | 0 | } |
656 | | |
657 | | } // namespace BAG |
658 | | |