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