Coverage Report

Created: 2026-02-26 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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