Coverage Report

Created: 2025-07-11 06:33

/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