Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: HDF5 read Driver
4 : * Author: Even Rouault <even.rouault at spatialys.com>
5 : *
6 : ******************************************************************************
7 : * Copyright (c) 2019, Even Rouault <even.rouault at spatialys.com>
8 : *
9 : * SPDX-License-Identifier: MIT
10 : ****************************************************************************/
11 :
12 : #include "hdf5dataset.h"
13 : #include "hdf5eosparser.h"
14 : #include "s100.h"
15 :
16 : #include "cpl_float.h"
17 :
18 : #include <algorithm>
19 : #include <limits>
20 : #include <set>
21 : #include <utility>
22 :
23 : namespace GDAL
24 : {
25 :
26 : /************************************************************************/
27 : /* HDF5Group */
28 : /************************************************************************/
29 :
30 : class HDF5Group final : public GDALGroup
31 : {
32 : std::shared_ptr<HDF5SharedResources> m_poShared;
33 : hid_t m_hGroup;
34 : std::set<std::pair<unsigned long, unsigned long>> m_oSetParentIds{};
35 : const bool m_bIsEOSGridGroup;
36 : const bool m_bIsEOSSwathGroup;
37 : mutable std::shared_ptr<GDALMDArray> m_poXIndexingArray{};
38 : mutable std::shared_ptr<GDALMDArray> m_poYIndexingArray{};
39 : mutable std::vector<std::string> m_osListSubGroups{};
40 : mutable std::vector<std::string> m_osListArrays{};
41 : mutable std::vector<std::shared_ptr<GDALAttribute>> m_oListAttributes{};
42 : mutable bool m_bShowAllAttributes = false;
43 : mutable bool m_bGotDims = false;
44 : mutable std::vector<std::shared_ptr<GDALDimension>> m_cachedDims{};
45 :
46 : static herr_t GetGroupNamesCallback(hid_t hGroup, const char *pszObjName,
47 : void *);
48 :
49 : static herr_t GetArrayNamesCallback(hid_t hGroup, const char *pszObjName,
50 : void *);
51 :
52 : static herr_t GetAttributesCallback(hid_t hGroup, const char *pszObjName,
53 : void *);
54 :
55 : protected:
56 1790 : HDF5Group(
57 : const std::string &osParentName, const std::string &osName,
58 : const std::shared_ptr<HDF5SharedResources> &poShared,
59 : const std::set<std::pair<unsigned long, unsigned long>> &oSetParentIds,
60 : hid_t hGroup, unsigned long objIds[2])
61 1790 : : GDALGroup(osParentName, osName), m_poShared(poShared),
62 : m_hGroup(hGroup), m_oSetParentIds(oSetParentIds),
63 1790 : m_bIsEOSGridGroup(osParentName == "/HDFEOS/GRIDS"),
64 3580 : m_bIsEOSSwathGroup(osParentName == "/HDFEOS/SWATHS")
65 : {
66 1790 : m_oSetParentIds.insert(std::pair(objIds[0], objIds[1]));
67 :
68 : // Force registration of EOS dimensions
69 1790 : if (m_bIsEOSGridGroup || m_bIsEOSSwathGroup)
70 : {
71 6 : HDF5Group::GetDimensions();
72 : }
73 1790 : }
74 :
75 : public:
76 1790 : static std::shared_ptr<HDF5Group> Create(
77 : const std::string &osParentName, const std::string &osName,
78 : const std::shared_ptr<HDF5SharedResources> &poShared,
79 : const std::set<std::pair<unsigned long, unsigned long>> &oSetParentIds,
80 : hid_t hGroup, unsigned long objIds[2])
81 : {
82 : auto poGroup = std::shared_ptr<HDF5Group>(new HDF5Group(
83 1790 : osParentName, osName, poShared, oSetParentIds, hGroup, objIds));
84 1790 : poGroup->SetSelf(poGroup);
85 1790 : return poGroup;
86 : }
87 :
88 3580 : ~HDF5Group() override
89 1790 : {
90 1790 : H5Gclose(m_hGroup);
91 3580 : }
92 :
93 349 : hid_t GetID() const
94 : {
95 349 : return m_hGroup;
96 : }
97 :
98 : std::vector<std::shared_ptr<GDALDimension>>
99 : GetDimensions(CSLConstList papszOptions = nullptr) const override;
100 :
101 : std::vector<std::string>
102 : GetGroupNames(CSLConstList papszOptions) const override;
103 : std::shared_ptr<GDALGroup> OpenGroup(const std::string &osName,
104 : CSLConstList) const override;
105 :
106 : std::vector<std::string>
107 : GetMDArrayNames(CSLConstList papszOptions) const override;
108 : std::shared_ptr<GDALMDArray>
109 : OpenMDArray(const std::string &osName,
110 : CSLConstList papszOptions) const override;
111 :
112 : std::vector<std::shared_ptr<GDALAttribute>>
113 : GetAttributes(CSLConstList papszOptions = nullptr) const override;
114 : };
115 :
116 : /************************************************************************/
117 : /* HDF5Dimension */
118 : /************************************************************************/
119 :
120 : class HDF5Dimension final : public GDALDimension
121 : {
122 : std::string m_osGroupFullname;
123 : std::shared_ptr<HDF5SharedResources> m_poShared;
124 :
125 : public:
126 38 : HDF5Dimension(const std::string &osParentName, const std::string &osName,
127 : const std::string &osType, const std::string &osDirection,
128 : GUInt64 nSize,
129 : const std::shared_ptr<HDF5SharedResources> &poShared)
130 38 : : GDALDimension(osParentName, osName, osType, osDirection, nSize),
131 38 : m_osGroupFullname(osParentName), m_poShared(poShared)
132 : {
133 38 : }
134 :
135 : std::shared_ptr<GDALMDArray> GetIndexingVariable() const override;
136 : };
137 :
138 : /************************************************************************/
139 : /* BuildDataType() */
140 : /************************************************************************/
141 :
142 : static GDALExtendedDataType
143 181526 : BuildDataType(hid_t hDataType, bool &bHasString, bool &bNonNativeDataType,
144 : const std::vector<std::pair<std::string, hid_t>> &oTypes)
145 : {
146 181526 : const auto klass = H5Tget_class(hDataType);
147 181526 : GDALDataType eDT = ::HDF5Dataset::GetDataType(hDataType);
148 181526 : if (eDT != GDT_Unknown)
149 : {
150 : #ifdef HDF5_HAVE_FLOAT16
151 : if (H5Tequal(hDataType, H5T_NATIVE_FLOAT16) ||
152 : HDF5Dataset::IsNativeCFloat16(hDataType))
153 : {
154 : bNonNativeDataType = true;
155 : }
156 : #endif
157 132153 : return GDALExtendedDataType::Create(eDT);
158 : }
159 49373 : else if (klass == H5T_STRING)
160 : {
161 31129 : bHasString = true;
162 31129 : return GDALExtendedDataType::CreateString();
163 : }
164 18244 : else if (klass == H5T_COMPOUND)
165 : {
166 1308 : const unsigned nMembers = H5Tget_nmembers(hDataType);
167 2616 : std::vector<std::unique_ptr<GDALEDTComponent>> components;
168 1308 : size_t nOffset = 0;
169 6191 : for (unsigned i = 0; i < nMembers; i++)
170 : {
171 5095 : char *pszName = H5Tget_member_name(hDataType, i);
172 5095 : if (!pszName)
173 212 : return GDALExtendedDataType::Create(GDT_Unknown);
174 5095 : CPLString osCompName(pszName);
175 5095 : H5free_memory(pszName);
176 5095 : const auto hMemberType = H5Tget_member_type(hDataType, i);
177 5095 : if (hMemberType < 0)
178 0 : return GDALExtendedDataType::Create(GDT_Unknown);
179 : const hid_t hNativeMemberType =
180 5095 : H5Tget_native_type(hMemberType, H5T_DIR_ASCEND);
181 : auto memberDT = BuildDataType(hNativeMemberType, bHasString,
182 5095 : bNonNativeDataType, oTypes);
183 5095 : H5Tclose(hNativeMemberType);
184 5095 : H5Tclose(hMemberType);
185 7940 : if (memberDT.GetClass() == GEDTC_NUMERIC &&
186 2845 : memberDT.GetNumericDataType() == GDT_Unknown)
187 212 : return GDALExtendedDataType::Create(GDT_Unknown);
188 4883 : if ((nOffset % memberDT.GetSize()) != 0)
189 224 : nOffset += memberDT.GetSize() - (nOffset % memberDT.GetSize());
190 4883 : if (nOffset != H5Tget_member_offset(hDataType, i))
191 523 : bNonNativeDataType = true;
192 9766 : components.emplace_back(std::unique_ptr<GDALEDTComponent>(
193 9766 : new GDALEDTComponent(osCompName, nOffset, memberDT)));
194 4883 : nOffset += memberDT.GetSize();
195 : }
196 2192 : if (!components.empty() &&
197 1096 : (nOffset % components[0]->GetType().GetSize()) != 0)
198 320 : nOffset += components[0]->GetType().GetSize() -
199 320 : (nOffset % components[0]->GetType().GetSize());
200 1096 : if (nOffset != H5Tget_size(hDataType))
201 85 : bNonNativeDataType = true;
202 2192 : std::string osName("unnamed");
203 1294 : for (const auto &oPair : oTypes)
204 : {
205 : const auto hPairNativeType =
206 242 : H5Tget_native_type(oPair.second, H5T_DIR_ASCEND);
207 242 : const auto matches = H5Tequal(hPairNativeType, hDataType);
208 242 : H5Tclose(hPairNativeType);
209 242 : if (matches)
210 : {
211 44 : osName = oPair.first;
212 44 : break;
213 : }
214 : }
215 : return GDALExtendedDataType::Create(osName, nOffset,
216 1096 : std::move(components));
217 : }
218 16936 : else if (klass == H5T_ENUM)
219 : {
220 16569 : const auto hParent = H5Tget_super(hDataType);
221 16569 : const hid_t hNativeParent = H5Tget_native_type(hParent, H5T_DIR_ASCEND);
222 : auto ret(BuildDataType(hNativeParent, bHasString, bNonNativeDataType,
223 33138 : oTypes));
224 16569 : H5Tclose(hNativeParent);
225 16569 : H5Tclose(hParent);
226 16569 : return ret;
227 : }
228 : else
229 : {
230 367 : return GDALExtendedDataType::Create(GDT_Unknown);
231 : }
232 : }
233 :
234 : /************************************************************************/
235 : /* GetDataTypesInGroup() */
236 : /************************************************************************/
237 :
238 : static void
239 657 : GetDataTypesInGroup(hid_t hHDF5, const std::string &osGroupFullName,
240 : std::vector<std::pair<std::string, hid_t>> &oTypes)
241 : {
242 : struct Callback
243 : {
244 9299 : static herr_t f(hid_t hGroup, const char *pszObjName, void *user_data)
245 : {
246 9299 : auto *poTypes =
247 : static_cast<std::vector<std::pair<std::string, hid_t>> *>(
248 : user_data);
249 : H5G_stat_t oStatbuf;
250 :
251 9299 : if (H5Gget_objinfo(hGroup, pszObjName, FALSE, &oStatbuf) < 0)
252 0 : return -1;
253 :
254 9299 : if (oStatbuf.type == H5G_TYPE)
255 : {
256 1746 : poTypes->push_back(
257 3492 : std::pair(pszObjName, H5Topen(hGroup, pszObjName)));
258 : }
259 :
260 9299 : return 0;
261 : }
262 : };
263 :
264 657 : H5Giterate(hHDF5, osGroupFullName.c_str(), nullptr, &(Callback::f),
265 : &oTypes);
266 657 : }
267 :
268 : /************************************************************************/
269 : /* HDF5Array */
270 : /************************************************************************/
271 :
272 : class HDF5Array final : public GDALMDArray
273 : {
274 : std::string m_osGroupFullname;
275 : std::shared_ptr<HDF5SharedResources> m_poShared;
276 : hid_t m_hArray;
277 : hid_t m_hDataSpace;
278 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
279 : GDALExtendedDataType m_dt = GDALExtendedDataType::Create(GDT_Unknown);
280 : hid_t m_hNativeDT = H5I_INVALID_HID;
281 : mutable std::vector<std::shared_ptr<GDALAttribute>> m_oListAttributes{};
282 : mutable bool m_bShowAllAttributes = false;
283 : bool m_bHasString = false;
284 : bool m_bHasNonNativeDataType = false;
285 : mutable bool m_bWarnedNoData = false;
286 : mutable std::vector<GByte> m_abyNoData{};
287 : mutable std::string m_osUnit{};
288 : mutable bool m_bHasDimensionList = false;
289 : mutable bool m_bHasDimensionLabels = false;
290 : std::shared_ptr<OGRSpatialReference> m_poSRS{};
291 : haddr_t m_nOffset;
292 : mutable CPLStringList m_aosStructuralInfo{};
293 :
294 : HDF5Array(const std::string &osParentName, const std::string &osName,
295 : const std::shared_ptr<HDF5SharedResources> &poShared,
296 : hid_t hArray, const HDF5Group *poGroup,
297 : bool bSkipFullDimensionInstantiation);
298 :
299 : void InstantiateDimensions(const std::string &osParentName,
300 : const HDF5Group *poGroup);
301 :
302 : bool ReadSlow(const GUInt64 *arrayStartIdx, const size_t *count,
303 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
304 : const GDALExtendedDataType &bufferDataType,
305 : void *pDstBuffer) const;
306 :
307 : static herr_t GetAttributesCallback(hid_t hArray, const char *pszObjName,
308 : void *);
309 :
310 : protected:
311 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
312 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
313 : const GDALExtendedDataType &bufferDataType,
314 : void *pDstBuffer) const override;
315 :
316 : public:
317 : ~HDF5Array() override;
318 :
319 : static std::shared_ptr<HDF5Array>
320 1808 : Create(const std::string &osParentName, const std::string &osName,
321 : const std::shared_ptr<HDF5SharedResources> &poShared, hid_t hArray,
322 : const HDF5Group *poGroup, bool bSkipFullDimensionInstantiation)
323 : {
324 : HDF5_GLOBAL_LOCK();
325 :
326 : auto ar(std::shared_ptr<HDF5Array>(
327 : new HDF5Array(osParentName, osName, poShared, hArray, poGroup,
328 3616 : bSkipFullDimensionInstantiation)));
329 2395 : if (ar->m_dt.GetClass() == GEDTC_NUMERIC &&
330 587 : ar->m_dt.GetNumericDataType() == GDT_Unknown)
331 : {
332 0 : return nullptr;
333 : }
334 1808 : ar->SetSelf(ar);
335 1808 : return ar;
336 : }
337 :
338 209 : bool IsWritable() const override
339 : {
340 209 : return !m_poShared->IsReadOnly();
341 : }
342 :
343 2013 : const std::string &GetFilename() const override
344 : {
345 2013 : return m_poShared->GetFilename();
346 : }
347 :
348 : const std::vector<std::shared_ptr<GDALDimension>> &
349 4024 : GetDimensions() const override
350 : {
351 4024 : return m_dims;
352 : }
353 :
354 3459 : const GDALExtendedDataType &GetDataType() const override
355 : {
356 3459 : return m_dt;
357 : }
358 :
359 : std::shared_ptr<GDALAttribute>
360 : GetAttribute(const std::string &osName) const override;
361 :
362 : std::vector<std::shared_ptr<GDALAttribute>>
363 : GetAttributes(CSLConstList papszOptions = nullptr) const override;
364 :
365 : std::vector<GUInt64> GetBlockSize() const override;
366 :
367 : CSLConstList GetStructuralInfo() const override;
368 :
369 123 : const void *GetRawNoDataValue() const override
370 : {
371 123 : return m_abyNoData.empty() ? nullptr : m_abyNoData.data();
372 : }
373 :
374 12 : const std::string &GetUnit() const override
375 : {
376 12 : return m_osUnit;
377 : }
378 :
379 : haddr_t GetFileOffset() const
380 : {
381 : return m_nOffset;
382 : }
383 :
384 10 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
385 : {
386 10 : return m_poSRS;
387 : }
388 :
389 : std::vector<std::shared_ptr<GDALMDArray>>
390 : GetCoordinateVariables() const override;
391 :
392 108 : std::shared_ptr<GDALGroup> GetRootGroup() const override
393 : {
394 108 : return m_poShared->GetRootGroup();
395 : }
396 :
397 : bool GetRawBlockInfo(const uint64_t *panBlockCoordinates,
398 : GDALMDArrayRawBlockInfo &info) const override;
399 : };
400 :
401 : /************************************************************************/
402 : /* HDF5Attribute */
403 : /************************************************************************/
404 :
405 : class HDF5Attribute final : public GDALAttribute
406 : {
407 : std::shared_ptr<HDF5SharedResources> m_poShared;
408 : hid_t m_hAttribute;
409 : hid_t m_hDataSpace;
410 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
411 : GDALExtendedDataType m_dt = GDALExtendedDataType::Create(GDT_Unknown);
412 : hid_t m_hNativeDT = H5I_INVALID_HID;
413 : size_t m_nElements = 1;
414 : bool m_bHasString = false;
415 : bool m_bHasNonNativeDataType = false;
416 :
417 158054 : HDF5Attribute(const std::string &osGroupFullName,
418 : const std::string &osParentName, const std::string &osName,
419 : const std::shared_ptr<HDF5SharedResources> &poShared,
420 : hid_t hAttribute)
421 158054 : : GDALAbstractMDArray(osParentName, osName),
422 : GDALAttribute(osParentName, osName), m_poShared(poShared),
423 158054 : m_hAttribute(hAttribute), m_hDataSpace(H5Aget_space(hAttribute))
424 : {
425 158054 : const int nDims = H5Sget_simple_extent_ndims(m_hDataSpace);
426 316108 : std::vector<hsize_t> anDimSizes(nDims);
427 158054 : if (nDims)
428 : {
429 1029 : H5Sget_simple_extent_dims(m_hDataSpace, &anDimSizes[0], nullptr);
430 1554 : for (int i = 0; i < nDims; ++i)
431 : {
432 1029 : m_nElements *= static_cast<size_t>(anDimSizes[i]);
433 1029 : if (nDims == 1 && m_nElements == 1)
434 : {
435 : // Expose 1-dim of size 1 as scalar
436 504 : break;
437 : }
438 1050 : m_dims.emplace_back(std::make_shared<GDALDimension>(
439 1050 : std::string(), CPLSPrintf("dim%d", i), std::string(),
440 1575 : std::string(), anDimSizes[i]));
441 : }
442 : }
443 :
444 158054 : const hid_t hDataType = H5Aget_type(hAttribute);
445 158054 : m_hNativeDT = H5Tget_native_type(hDataType, H5T_DIR_ASCEND);
446 158054 : H5Tclose(hDataType);
447 :
448 316108 : std::vector<std::pair<std::string, hid_t>> oTypes;
449 313111 : if (!osGroupFullName.empty() &&
450 155057 : H5Tget_class(m_hNativeDT) == H5T_COMPOUND)
451 : {
452 202 : GetDataTypesInGroup(m_poShared->GetHDF5(), osGroupFullName, oTypes);
453 : }
454 :
455 316108 : m_dt = BuildDataType(m_hNativeDT, m_bHasString, m_bHasNonNativeDataType,
456 158054 : oTypes);
457 159476 : for (auto &oPair : oTypes)
458 1422 : H5Tclose(oPair.second);
459 287354 : if (m_dt.GetClass() == GEDTC_NUMERIC &&
460 129300 : m_dt.GetNumericDataType() == GDT_Unknown)
461 : {
462 367 : CPLDebug("HDF5",
463 : "Cannot map data type of %s to a type handled by GDAL",
464 : osName.c_str());
465 : }
466 158054 : }
467 :
468 : protected:
469 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
470 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
471 : const GDALExtendedDataType &bufferDataType,
472 : void *pDstBuffer) const override;
473 :
474 : public:
475 : ~HDF5Attribute() override;
476 :
477 : static std::shared_ptr<HDF5Attribute>
478 158054 : Create(const std::string &osGroupFullName, const std::string &osParentName,
479 : const std::string &osName,
480 : const std::shared_ptr<HDF5SharedResources> &poShared,
481 : hid_t hAttribute)
482 : {
483 : HDF5_GLOBAL_LOCK();
484 :
485 : auto ar(std::shared_ptr<HDF5Attribute>(new HDF5Attribute(
486 316108 : osGroupFullName, osParentName, osName, poShared, hAttribute)));
487 287354 : if (ar->m_dt.GetClass() == GEDTC_NUMERIC &&
488 129300 : ar->m_dt.GetNumericDataType() == GDT_Unknown)
489 : {
490 367 : return nullptr;
491 : }
492 157687 : return ar;
493 : }
494 :
495 : const std::vector<std::shared_ptr<GDALDimension>> &
496 19949 : GetDimensions() const override
497 : {
498 19949 : return m_dims;
499 : }
500 :
501 17305 : const GDALExtendedDataType &GetDataType() const override
502 : {
503 17305 : return m_dt;
504 : }
505 : };
506 :
507 : /************************************************************************/
508 : /* HDF5SharedResources() */
509 : /************************************************************************/
510 :
511 345 : HDF5SharedResources::HDF5SharedResources(const std::string &osFilename)
512 : : m_osFilename(osFilename),
513 345 : m_poPAM(std::make_shared<GDALPamMultiDim>(osFilename))
514 : {
515 345 : }
516 :
517 : /************************************************************************/
518 : /* ~HDF5SharedResources() */
519 : /************************************************************************/
520 :
521 345 : HDF5SharedResources::~HDF5SharedResources()
522 : {
523 : HDF5_GLOBAL_LOCK();
524 :
525 345 : if (m_hHDF5 > 0)
526 345 : H5Fclose(m_hHDF5);
527 345 : }
528 :
529 : /************************************************************************/
530 : /* Create() */
531 : /************************************************************************/
532 :
533 : std::shared_ptr<HDF5SharedResources>
534 345 : HDF5SharedResources::Create(const std::string &osFilename)
535 : {
536 : auto poSharedResources = std::shared_ptr<HDF5SharedResources>(
537 345 : new HDF5SharedResources(osFilename));
538 345 : poSharedResources->m_poSelf = poSharedResources;
539 345 : return poSharedResources;
540 : }
541 :
542 : /************************************************************************/
543 : /* GetRootGroup() */
544 : /************************************************************************/
545 :
546 558 : std::shared_ptr<HDF5Group> HDF5SharedResources::GetRootGroup()
547 : {
548 :
549 : H5G_stat_t oStatbuf;
550 558 : if (H5Gget_objinfo(m_hHDF5, "/", FALSE, &oStatbuf) < 0)
551 : {
552 0 : return nullptr;
553 : }
554 558 : auto hGroup = H5Gopen(m_hHDF5, "/");
555 558 : if (hGroup < 0)
556 : {
557 0 : return nullptr;
558 : }
559 :
560 558 : auto poSharedResources = m_poSelf.lock();
561 558 : CPLAssert(poSharedResources != nullptr);
562 1116 : return HDF5Group::Create(std::string(), "/", poSharedResources, {}, hGroup,
563 1674 : oStatbuf.objno);
564 : }
565 :
566 : /************************************************************************/
567 : /* GetDimensions() */
568 : /************************************************************************/
569 :
570 : std::vector<std::shared_ptr<GDALDimension>>
571 44 : HDF5Group::GetDimensions(CSLConstList) const
572 : {
573 : HDF5_GLOBAL_LOCK();
574 :
575 44 : if (m_bGotDims)
576 21 : return m_cachedDims;
577 :
578 : struct CallbackData
579 : {
580 : std::shared_ptr<HDF5SharedResources> poShared{};
581 : std::string osFullName{};
582 : std::map<std::string, std::shared_ptr<GDALDimension>> oDimMap{};
583 : };
584 :
585 : struct Callback
586 : {
587 243 : static herr_t f(hid_t hGroup, const char *pszObjName, void *user_data)
588 : {
589 243 : CallbackData *data = static_cast<CallbackData *>(user_data);
590 : H5G_stat_t oStatbuf;
591 :
592 243 : if (H5Gget_objinfo(hGroup, pszObjName, FALSE, &oStatbuf) < 0)
593 0 : return -1;
594 :
595 243 : if (oStatbuf.type == H5G_DATASET)
596 : {
597 180 : auto hArray = H5Dopen(hGroup, pszObjName);
598 180 : if (hArray >= 0)
599 : {
600 180 : auto ar = HDF5Array::Create(data->osFullName, pszObjName,
601 180 : data->poShared, hArray, nullptr,
602 360 : true);
603 180 : if (ar && ar->GetDimensionCount() == 1)
604 : {
605 102 : auto attrCLASS = ar->GetAttribute("CLASS");
606 96 : if (attrCLASS && attrCLASS->GetDimensionCount() == 0 &&
607 45 : attrCLASS->GetDataType().GetClass() == GEDTC_STRING)
608 : {
609 45 : const char *pszStr = attrCLASS->ReadAsString();
610 45 : if (pszStr && EQUAL(pszStr, "DIMENSION_SCALE"))
611 : {
612 45 : std::string osType;
613 45 : if (strcmp(pszObjName, "XDim") == 0)
614 1 : osType = GDAL_DIM_TYPE_HORIZONTAL_X;
615 44 : else if (strcmp(pszObjName, "YDim") == 0)
616 1 : osType = GDAL_DIM_TYPE_HORIZONTAL_Y;
617 :
618 90 : auto attrNAME = ar->GetAttribute("NAME");
619 88 : if (attrNAME &&
620 88 : attrNAME->GetDimensionCount() == 0 &&
621 43 : attrNAME->GetDataType().GetClass() ==
622 : GEDTC_STRING)
623 : {
624 : const char *pszName =
625 43 : attrNAME->ReadAsString();
626 43 : if (pszName &&
627 43 : STARTS_WITH(
628 : pszName,
629 : "This is a netCDF dimension but "
630 : "not a netCDF variable"))
631 : {
632 48 : data->oDimMap[pszObjName] =
633 24 : std::make_shared<GDALDimension>(
634 24 : data->osFullName, pszObjName,
635 24 : osType, std::string(),
636 24 : ar->GetDimensions()[0]
637 48 : ->GetSize());
638 24 : return 0;
639 : }
640 : }
641 :
642 42 : data->oDimMap[pszObjName] =
643 21 : std::make_shared<HDF5Dimension>(
644 21 : data->osFullName, pszObjName, osType,
645 21 : std::string(),
646 42 : ar->GetDimensions()[0]->GetSize(),
647 42 : data->poShared);
648 : }
649 : }
650 : }
651 : }
652 : }
653 :
654 219 : return 0;
655 : }
656 : };
657 :
658 46 : CallbackData data;
659 23 : data.poShared = m_poShared;
660 23 : data.osFullName = GetFullName();
661 23 : H5Giterate(m_poShared->GetHDF5(), GetFullName().c_str(), nullptr,
662 : &(Callback::f), &data);
663 23 : m_bGotDims = true;
664 :
665 23 : if (m_bIsEOSGridGroup)
666 : {
667 3 : const auto poHDF5EOSParser = m_poShared->GetHDF5EOSParser();
668 3 : HDF5EOSParser::GridMetadata oGridMetadata;
669 6 : if (poHDF5EOSParser &&
670 3 : poHDF5EOSParser->GetGridMetadata(GetName(), oGridMetadata))
671 : {
672 3 : GDALGeoTransform gt;
673 : const bool bHasGT =
674 3 : oGridMetadata.GetGeoTransform(gt) && gt[2] == 0 && gt[4] == 0;
675 10 : for (auto &oDim : oGridMetadata.aoDimensions)
676 : {
677 7 : auto iterInDimMap = data.oDimMap.find(oDim.osName);
678 7 : if (iterInDimMap != data.oDimMap.end())
679 : {
680 : auto indexingVar =
681 4 : iterInDimMap->second->GetIndexingVariable();
682 2 : if (indexingVar != nullptr)
683 : {
684 3 : if (oDim.osName == "XDim" && bHasGT &&
685 1 : indexingVar->GetDimensions()[0]->GetSize() > 0)
686 : {
687 1 : const GUInt64 anArrayStartIdx0[] = {0};
688 1 : const size_t anCount[] = {1};
689 1 : const GInt64 anArrayStep[] = {0};
690 1 : const GPtrDiff_t anBufferStride[] = {0};
691 1 : double dfFirstVal = 0;
692 2 : if (indexingVar->Read(
693 : anArrayStartIdx0, anCount, anArrayStep,
694 : anBufferStride,
695 2 : GDALExtendedDataType::Create(GDT_Float64),
696 : &dfFirstVal))
697 : {
698 1 : CPLDebug(
699 : "HDF5",
700 : "XDim FirstX: (from XDim array:%.17g,) "
701 : "from HDF5EOS metadata:%.17g",
702 1 : dfFirstVal, gt[0]);
703 : }
704 :
705 : const GUInt64 anArrayStartIdx1[] = {
706 1 : indexingVar->GetDimensions()[0]->GetSize() - 1};
707 1 : double dfLastVal = 0;
708 2 : if (indexingVar->Read(
709 : anArrayStartIdx1, anCount, anArrayStep,
710 : anBufferStride,
711 2 : GDALExtendedDataType::Create(GDT_Float64),
712 : &dfLastVal))
713 : {
714 2 : CPLDebug("HDF5",
715 : "XDim LastX: (from XDim array:%.17g,) "
716 : "from HDF5EOS metadata:%.17g",
717 1 : dfLastVal, gt[0] + oDim.nSize * gt[1]);
718 : }
719 : }
720 2 : else if (oDim.osName == "YDim" && bHasGT &&
721 1 : indexingVar->GetDimensions()[0]->GetSize() > 0)
722 : {
723 1 : const GUInt64 anArrayStartIdx0[] = {0};
724 1 : const size_t anCount[] = {1};
725 1 : const GInt64 anArrayStep[] = {0};
726 1 : const GPtrDiff_t anBufferStride[] = {0};
727 1 : double dfFirstVal = 0;
728 2 : if (indexingVar->Read(
729 : anArrayStartIdx0, anCount, anArrayStep,
730 : anBufferStride,
731 2 : GDALExtendedDataType::Create(GDT_Float64),
732 : &dfFirstVal))
733 : {
734 1 : CPLDebug(
735 : "HDF5",
736 : "YDim FirstY: (from YDim array:%.17g,) "
737 : "from HDF5EOS metadata:%.17g",
738 1 : dfFirstVal, gt[3]);
739 : }
740 :
741 : const GUInt64 anArrayStartIdx1[] = {
742 1 : indexingVar->GetDimensions()[0]->GetSize() - 1};
743 1 : double dfLastVal = 0;
744 2 : if (indexingVar->Read(
745 : anArrayStartIdx1, anCount, anArrayStep,
746 : anBufferStride,
747 2 : GDALExtendedDataType::Create(GDT_Float64),
748 : &dfLastVal))
749 : {
750 2 : CPLDebug("HDF5",
751 : "YDim LastY: (from YDim array:%.17g,) "
752 : "from HDF5EOS metadata:%.17g",
753 1 : dfLastVal, gt[3] + oDim.nSize * gt[5]);
754 : }
755 : }
756 : }
757 : }
758 :
759 7 : if (oDim.osName == "XDim" && bHasGT)
760 : {
761 3 : if (iterInDimMap != data.oDimMap.end())
762 1 : data.oDimMap.erase(iterInDimMap);
763 : auto poDim = std::make_shared<GDALDimensionWeakIndexingVar>(
764 3 : GetFullName(), oDim.osName, GDAL_DIM_TYPE_HORIZONTAL_X,
765 9 : std::string(), oDim.nSize);
766 : auto poIndexingVar = GDALMDArrayRegularlySpaced::Create(
767 12 : GetFullName(), oDim.osName, poDim, gt[0] + gt[1] / 2,
768 6 : gt[1], 0);
769 3 : poDim->SetIndexingVariable(poIndexingVar);
770 3 : m_poXIndexingArray = poIndexingVar;
771 3 : m_poShared->KeepRef(poIndexingVar);
772 3 : m_cachedDims.emplace_back(poDim);
773 : }
774 4 : else if (oDim.osName == "YDim" && bHasGT)
775 : {
776 3 : if (iterInDimMap != data.oDimMap.end())
777 1 : data.oDimMap.erase(iterInDimMap);
778 : auto poDim = std::make_shared<GDALDimensionWeakIndexingVar>(
779 3 : GetFullName(), oDim.osName, GDAL_DIM_TYPE_HORIZONTAL_Y,
780 9 : std::string(), oDim.nSize);
781 : auto poIndexingVar = GDALMDArrayRegularlySpaced::Create(
782 12 : GetFullName(), oDim.osName, poDim, gt[3] + gt[5] / 2,
783 6 : gt[5], 0);
784 3 : poDim->SetIndexingVariable(poIndexingVar);
785 3 : m_poYIndexingArray = poIndexingVar;
786 3 : m_poShared->KeepRef(poIndexingVar);
787 3 : m_cachedDims.emplace_back(poDim);
788 : }
789 1 : else if (iterInDimMap == data.oDimMap.end())
790 : {
791 2 : m_cachedDims.emplace_back(std::make_shared<GDALDimension>(
792 2 : GetFullName(), oDim.osName, std::string(),
793 3 : std::string(), oDim.nSize));
794 : }
795 : }
796 3 : for (auto &iter : data.oDimMap)
797 0 : m_cachedDims.emplace_back(std::move(iter.second));
798 3 : m_poShared->RegisterEOSGridDimensions(GetName(), m_cachedDims);
799 3 : return m_cachedDims;
800 : }
801 : }
802 20 : else if (m_bIsEOSSwathGroup)
803 : {
804 3 : const auto poHDF5EOSParser = m_poShared->GetHDF5EOSParser();
805 3 : HDF5EOSParser::SwathMetadata oSwathMetadata;
806 6 : if (poHDF5EOSParser &&
807 3 : poHDF5EOSParser->GetSwathMetadata(GetName(), oSwathMetadata))
808 : {
809 12 : for (auto &oDim : oSwathMetadata.aoDimensions)
810 : {
811 9 : auto iterInDimMap = data.oDimMap.find(oDim.osName);
812 9 : if (iterInDimMap != data.oDimMap.end())
813 : {
814 0 : if (iterInDimMap->second->GetIndexingVariable() != nullptr)
815 : {
816 0 : continue;
817 : }
818 0 : data.oDimMap.erase(iterInDimMap);
819 : }
820 :
821 18 : m_cachedDims.emplace_back(std::make_shared<GDALDimension>(
822 18 : GetFullName(), oDim.osName, std::string(), std::string(),
823 18 : oDim.nSize));
824 : }
825 3 : for (auto &iter : data.oDimMap)
826 0 : m_cachedDims.emplace_back(std::move(iter.second));
827 3 : m_poShared->RegisterEOSSwathDimensions(GetName(), m_cachedDims);
828 3 : return m_cachedDims;
829 : }
830 : }
831 :
832 60 : for (auto &iter : data.oDimMap)
833 43 : m_cachedDims.emplace_back(std::move(iter.second));
834 17 : return m_cachedDims;
835 : }
836 :
837 : /************************************************************************/
838 : /* GetGroupNamesCallback() */
839 : /************************************************************************/
840 :
841 2866 : herr_t HDF5Group::GetGroupNamesCallback(hid_t hGroup, const char *pszObjName,
842 : void *selfIn)
843 : {
844 2866 : HDF5Group *self = static_cast<HDF5Group *>(selfIn);
845 : H5G_stat_t oStatbuf;
846 :
847 2866 : if (H5Gget_objinfo(hGroup, pszObjName, FALSE, &oStatbuf) < 0)
848 0 : return -1;
849 :
850 2866 : if (oStatbuf.type == H5G_GROUP)
851 : {
852 1699 : if (self->m_oSetParentIds.find(
853 1699 : std::pair(oStatbuf.objno[0], oStatbuf.objno[1])) ==
854 3398 : self->m_oSetParentIds.end())
855 : {
856 1699 : self->m_osListSubGroups.push_back(pszObjName);
857 : }
858 : else
859 : {
860 0 : CPLDebug("HDF5",
861 : "Group %s contains a link to group %s which is "
862 : "itself, or one of its ancestor.",
863 0 : self->GetFullName().c_str(), pszObjName);
864 : }
865 : }
866 2866 : return 0;
867 : }
868 :
869 : /************************************************************************/
870 : /* GetGroupNames() */
871 : /************************************************************************/
872 :
873 1223 : std::vector<std::string> HDF5Group::GetGroupNames(CSLConstList) const
874 : {
875 : HDF5_GLOBAL_LOCK();
876 :
877 1223 : m_osListSubGroups.clear();
878 1223 : H5Giterate(m_poShared->GetHDF5(), GetFullName().c_str(), nullptr,
879 : GetGroupNamesCallback,
880 : const_cast<void *>(static_cast<const void *>(this)));
881 1223 : return m_osListSubGroups;
882 : }
883 :
884 : /************************************************************************/
885 : /* OpenGroup() */
886 : /************************************************************************/
887 :
888 1414 : std::shared_ptr<GDALGroup> HDF5Group::OpenGroup(const std::string &osName,
889 : CSLConstList) const
890 : {
891 : HDF5_GLOBAL_LOCK();
892 :
893 1414 : if (m_osListSubGroups.empty())
894 1098 : GetGroupNames(nullptr);
895 1414 : if (std::find(m_osListSubGroups.begin(), m_osListSubGroups.end(), osName) ==
896 2828 : m_osListSubGroups.end())
897 : {
898 182 : return nullptr;
899 : }
900 :
901 : H5G_stat_t oStatbuf;
902 1232 : if (H5Gget_objinfo(m_hGroup, osName.c_str(), FALSE, &oStatbuf) < 0)
903 0 : return nullptr;
904 :
905 1232 : auto hSubGroup = H5Gopen(m_hGroup, osName.c_str());
906 1232 : if (hSubGroup < 0)
907 : {
908 0 : return nullptr;
909 : }
910 2464 : return HDF5Group::Create(GetFullName(), osName, m_poShared, m_oSetParentIds,
911 1232 : hSubGroup, oStatbuf.objno);
912 : }
913 :
914 : /************************************************************************/
915 : /* GetArrayNamesCallback() */
916 : /************************************************************************/
917 :
918 1336 : herr_t HDF5Group::GetArrayNamesCallback(hid_t hGroup, const char *pszObjName,
919 : void *selfIn)
920 : {
921 1336 : HDF5Group *self = static_cast<HDF5Group *>(selfIn);
922 : H5G_stat_t oStatbuf;
923 :
924 1336 : if (H5Gget_objinfo(hGroup, pszObjName, FALSE, &oStatbuf) < 0)
925 0 : return -1;
926 :
927 1336 : if (oStatbuf.type == H5G_DATASET)
928 : {
929 1112 : auto hArray = H5Dopen(hGroup, pszObjName);
930 1112 : if (hArray >= 0)
931 : {
932 2224 : auto ar(HDF5Array::Create(std::string(), pszObjName,
933 3336 : self->m_poShared, hArray, self, true));
934 1112 : if (ar)
935 : {
936 2224 : auto attrNAME = ar->GetAttribute("NAME");
937 1161 : if (attrNAME && attrNAME->GetDimensionCount() == 0 &&
938 49 : attrNAME->GetDataType().GetClass() == GEDTC_STRING)
939 : {
940 49 : const char *pszName = attrNAME->ReadAsString();
941 49 : if (pszName &&
942 49 : STARTS_WITH(pszName, "This is a netCDF dimension but "
943 : "not a netCDF variable"))
944 : {
945 28 : return 0;
946 : }
947 : }
948 : }
949 : }
950 1084 : self->m_osListArrays.push_back(pszObjName);
951 : }
952 1308 : return 0;
953 : }
954 :
955 : /************************************************************************/
956 : /* GetMDArrayNames() */
957 : /************************************************************************/
958 :
959 453 : std::vector<std::string> HDF5Group::GetMDArrayNames(CSLConstList) const
960 : {
961 : HDF5_GLOBAL_LOCK();
962 :
963 453 : m_osListArrays.clear();
964 453 : H5Giterate(m_poShared->GetHDF5(), GetFullName().c_str(), nullptr,
965 : GetArrayNamesCallback,
966 : const_cast<void *>(static_cast<const void *>(this)));
967 :
968 453 : if (m_poXIndexingArray)
969 0 : m_osListArrays.push_back(m_poXIndexingArray->GetName());
970 453 : if (m_poYIndexingArray)
971 0 : m_osListArrays.push_back(m_poYIndexingArray->GetName());
972 :
973 453 : return m_osListArrays;
974 : }
975 :
976 : /************************************************************************/
977 : /* OpenMDArray() */
978 : /************************************************************************/
979 :
980 526 : std::shared_ptr<GDALMDArray> HDF5Group::OpenMDArray(const std::string &osName,
981 : CSLConstList) const
982 : {
983 : HDF5_GLOBAL_LOCK();
984 :
985 526 : if (m_osListArrays.empty())
986 419 : GetMDArrayNames(nullptr);
987 526 : if (std::find(m_osListArrays.begin(), m_osListArrays.end(), osName) ==
988 1052 : m_osListArrays.end())
989 : {
990 24 : return nullptr;
991 : }
992 502 : if (m_poXIndexingArray && m_poXIndexingArray->GetName() == osName)
993 0 : return m_poXIndexingArray;
994 502 : if (m_poYIndexingArray && m_poYIndexingArray->GetName() == osName)
995 0 : return m_poYIndexingArray;
996 :
997 502 : auto hArray = H5Dopen(m_hGroup, osName.c_str());
998 502 : if (hArray < 0)
999 : {
1000 0 : return nullptr;
1001 : }
1002 1004 : return HDF5Array::Create(GetFullName(), osName, m_poShared, hArray, this,
1003 502 : false);
1004 : }
1005 :
1006 : /************************************************************************/
1007 : /* GetAttributesCallback() */
1008 : /************************************************************************/
1009 :
1010 154050 : herr_t HDF5Group::GetAttributesCallback(hid_t hGroup, const char *pszObjName,
1011 : void *selfIn)
1012 : {
1013 154050 : HDF5Group *self = static_cast<HDF5Group *>(selfIn);
1014 154050 : if (self->m_bShowAllAttributes || (!EQUAL(pszObjName, "_Netcdf4Dimid") &&
1015 154050 : !EQUAL(pszObjName, "_NCProperties")))
1016 : {
1017 154049 : hid_t hAttr = H5Aopen_name(hGroup, pszObjName);
1018 154049 : if (hAttr > 0)
1019 : {
1020 : auto attr(HDF5Attribute::Create(self->GetFullName(),
1021 : self->GetFullName(), pszObjName,
1022 462147 : self->m_poShared, hAttr));
1023 154049 : if (attr)
1024 : {
1025 154049 : self->m_oListAttributes.emplace_back(attr);
1026 : }
1027 : }
1028 : }
1029 154050 : return 0;
1030 : }
1031 :
1032 : /************************************************************************/
1033 : /* GetAttributes() */
1034 : /************************************************************************/
1035 :
1036 : std::vector<std::shared_ptr<GDALAttribute>>
1037 10918 : HDF5Group::GetAttributes(CSLConstList papszOptions) const
1038 : {
1039 : HDF5_GLOBAL_LOCK();
1040 :
1041 10918 : m_oListAttributes.clear();
1042 10918 : m_bShowAllAttributes =
1043 10918 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SHOW_ALL", "NO"));
1044 10918 : H5Aiterate(m_hGroup, nullptr, GetAttributesCallback,
1045 : const_cast<void *>(static_cast<const void *>(this)));
1046 10918 : return m_oListAttributes;
1047 : }
1048 :
1049 : /************************************************************************/
1050 : /* ~HDF5Array() */
1051 : /************************************************************************/
1052 :
1053 3616 : HDF5Array::~HDF5Array()
1054 : {
1055 : HDF5_GLOBAL_LOCK();
1056 :
1057 1808 : if (m_hArray > 0)
1058 1808 : H5Dclose(m_hArray);
1059 1808 : if (m_hNativeDT > 0)
1060 1808 : H5Tclose(m_hNativeDT);
1061 1808 : if (m_hDataSpace > 0)
1062 1808 : H5Sclose(m_hDataSpace);
1063 3616 : }
1064 :
1065 : /************************************************************************/
1066 : /* HDF5Array() */
1067 : /************************************************************************/
1068 :
1069 1808 : HDF5Array::HDF5Array(const std::string &osParentName, const std::string &osName,
1070 : const std::shared_ptr<HDF5SharedResources> &poShared,
1071 : hid_t hArray, const HDF5Group *poGroup,
1072 1808 : bool bSkipFullDimensionInstantiation)
1073 : : GDALAbstractMDArray(osParentName, osName),
1074 : GDALMDArray(osParentName, osName), m_osGroupFullname(osParentName),
1075 : m_poShared(poShared), m_hArray(hArray),
1076 1808 : m_hDataSpace(H5Dget_space(hArray)), m_nOffset(H5Dget_offset(hArray))
1077 : {
1078 1808 : const hid_t hDataType = H5Dget_type(hArray);
1079 1808 : m_hNativeDT = H5Tget_native_type(hDataType, H5T_DIR_ASCEND);
1080 1808 : H5Tclose(hDataType);
1081 :
1082 1808 : std::vector<std::pair<std::string, hid_t>> oTypes;
1083 1808 : if (!osParentName.empty() && H5Tget_class(m_hNativeDT) == H5T_COMPOUND)
1084 : {
1085 455 : GetDataTypesInGroup(m_poShared->GetHDF5(), osParentName, oTypes);
1086 : }
1087 :
1088 3616 : m_dt = BuildDataType(m_hNativeDT, m_bHasString, m_bHasNonNativeDataType,
1089 1808 : oTypes);
1090 2132 : for (auto &oPair : oTypes)
1091 324 : H5Tclose(oPair.second);
1092 :
1093 2395 : if (m_dt.GetClass() == GEDTC_NUMERIC &&
1094 587 : m_dt.GetNumericDataType() == GDT_Unknown)
1095 : {
1096 0 : CPLDebug("HDF5", "Cannot map data type of %s to a type handled by GDAL",
1097 : osName.c_str());
1098 0 : return;
1099 : }
1100 :
1101 1808 : HDF5Array::GetAttributes();
1102 :
1103 : // Special case for S102 nodata value that is typically at 1e6
1104 1808 : if (GetFullName() ==
1105 38 : "/BathymetryCoverage/BathymetryCoverage.01/Group_001/values" &&
1106 76 : m_dt.GetClass() == GEDTC_COMPOUND &&
1107 59 : (m_dt.GetComponents().size() == 1 ||
1108 21 : m_dt.GetComponents().size() == 2) &&
1109 76 : m_dt.GetSize() == m_dt.GetComponents().size() * sizeof(float) &&
1110 38 : m_dt.GetComponents()[0]->GetType().GetNumericDataType() ==
1111 1867 : GDT_Float32 &&
1112 59 : (m_dt.GetComponents().size() == 1 ||
1113 21 : m_dt.GetComponents()[1]->GetType().GetNumericDataType() ==
1114 : GDT_Float32))
1115 : {
1116 38 : m_abyNoData.resize(m_dt.GetSize());
1117 38 : float afNoData[2] = {1e6f, 1e6f};
1118 :
1119 76 : if (auto poRootGroup = HDF5Array::GetRootGroup())
1120 : {
1121 114 : if (const auto poGroupF = poRootGroup->OpenGroup("Group_F"))
1122 : {
1123 : const auto poGroupFArray =
1124 114 : poGroupF->OpenMDArray("BathymetryCoverage");
1125 38 : if (poGroupFArray &&
1126 114 : poGroupFArray->GetDataType().GetClass() == GEDTC_COMPOUND &&
1127 76 : poGroupFArray->GetDataType().GetComponents().size() == 8 &&
1128 38 : poGroupFArray->GetDataType()
1129 38 : .GetComponents()[0]
1130 76 : ->GetName() == "code" &&
1131 38 : poGroupFArray->GetDataType()
1132 38 : .GetComponents()[3]
1133 38 : ->GetName() == "fillValue" &&
1134 114 : poGroupFArray->GetDimensionCount() == 1 &&
1135 38 : poGroupFArray->GetDimensions()[0]->GetSize() ==
1136 38 : m_dt.GetComponents().size())
1137 : {
1138 : auto poFillValue =
1139 114 : poGroupFArray->GetView("[\"fillValue\"]");
1140 38 : if (poFillValue)
1141 : {
1142 38 : char *pszVal0 = nullptr;
1143 38 : char *pszVal1 = nullptr;
1144 38 : const GUInt64 anArrayStartIdx0[] = {0};
1145 38 : const GUInt64 anArrayStartIdx1[] = {1};
1146 38 : const size_t anCount[] = {1};
1147 38 : const GInt64 anArrayStep[] = {0};
1148 38 : const GPtrDiff_t anBufferStride[] = {0};
1149 76 : poFillValue->Read(anArrayStartIdx0, anCount,
1150 : anArrayStep, anBufferStride,
1151 76 : GDALExtendedDataType::CreateString(),
1152 : &pszVal0);
1153 38 : if (poGroupFArray->GetDimensions()[0]->GetSize() == 2)
1154 : {
1155 42 : poFillValue->Read(
1156 : anArrayStartIdx1, anCount, anArrayStep,
1157 : anBufferStride,
1158 42 : GDALExtendedDataType::CreateString(), &pszVal1);
1159 : }
1160 38 : if (pszVal0)
1161 : {
1162 38 : afNoData[0] = static_cast<float>(CPLAtof(pszVal0));
1163 38 : if (pszVal1)
1164 : {
1165 21 : afNoData[1] =
1166 21 : static_cast<float>(CPLAtof(pszVal1));
1167 : }
1168 : }
1169 38 : CPLFree(pszVal0);
1170 38 : CPLFree(pszVal1);
1171 : }
1172 : }
1173 : }
1174 : }
1175 :
1176 38 : m_abyNoData.resize(m_dt.GetSize());
1177 38 : memcpy(m_abyNoData.data(), afNoData, m_abyNoData.size());
1178 : }
1179 :
1180 : // Special case for S102 QualityOfSurvey nodata value that is typically at 0
1181 : const bool bIsQualityOfSurvey =
1182 1808 : (GetFullName() ==
1183 : "/QualityOfSurvey/QualityOfSurvey.01/Group_001/values");
1184 : const bool bIsQualityOfBathymetryCoverage =
1185 1808 : (GetFullName() == "/QualityOfBathymetryCoverage/"
1186 : "QualityOfBathymetryCoverage.01/Group_001/values");
1187 1824 : if ((bIsQualityOfSurvey || bIsQualityOfBathymetryCoverage) &&
1188 14 : ((m_dt.GetClass() == GEDTC_NUMERIC &&
1189 8 : m_dt.GetNumericDataType() == GDT_UInt32) ||
1190 4 : (m_dt.GetClass() == GEDTC_COMPOUND &&
1191 4 : m_dt.GetComponents().size() == 1 &&
1192 4 : m_dt.GetComponents()[0]->GetType().GetClass() == GEDTC_NUMERIC &&
1193 2 : m_dt.GetComponents()[0]->GetType().GetNumericDataType() ==
1194 : GDT_UInt32)))
1195 : {
1196 16 : if (auto poRootGroup = HDF5Array::GetRootGroup())
1197 : {
1198 24 : if (const auto poGroupF = poRootGroup->OpenGroup("Group_F"))
1199 : {
1200 8 : const auto poGroupFArray = poGroupF->OpenMDArray(
1201 : bIsQualityOfSurvey ? "QualityOfSurvey"
1202 24 : : "QualityOfBathymetryCoverage");
1203 8 : if (poGroupFArray &&
1204 24 : poGroupFArray->GetDataType().GetClass() == GEDTC_COMPOUND &&
1205 16 : poGroupFArray->GetDataType().GetComponents().size() == 8 &&
1206 8 : poGroupFArray->GetDataType()
1207 8 : .GetComponents()[0]
1208 16 : ->GetName() == "code" &&
1209 8 : poGroupFArray->GetDataType()
1210 8 : .GetComponents()[3]
1211 8 : ->GetName() == "fillValue" &&
1212 24 : poGroupFArray->GetDimensionCount() == 1 &&
1213 8 : poGroupFArray->GetDimensions()[0]->GetSize() == 1)
1214 : {
1215 : auto poFillValue =
1216 24 : poGroupFArray->GetView("[\"fillValue\"]");
1217 8 : if (poFillValue)
1218 : {
1219 8 : char *pszVal0 = nullptr;
1220 8 : const GUInt64 anArrayStartIdx0[] = {0};
1221 8 : const size_t anCount[] = {1};
1222 8 : const GInt64 anArrayStep[] = {0};
1223 8 : const GPtrDiff_t anBufferStride[] = {0};
1224 16 : poFillValue->Read(anArrayStartIdx0, anCount,
1225 : anArrayStep, anBufferStride,
1226 16 : GDALExtendedDataType::CreateString(),
1227 : &pszVal0);
1228 8 : if (pszVal0)
1229 : {
1230 8 : const uint32_t nNoData = atoi(pszVal0);
1231 8 : m_abyNoData.resize(m_dt.GetSize());
1232 8 : memcpy(m_abyNoData.data(), &nNoData,
1233 : m_abyNoData.size());
1234 : }
1235 8 : CPLFree(pszVal0);
1236 : }
1237 : }
1238 : }
1239 : }
1240 : }
1241 :
1242 : // Special case for S104 nodata value that is typically -9999
1243 1867 : if (STARTS_WITH(GetFullName().c_str(), "/WaterLevel/WaterLevel.01/") &&
1244 91 : GetFullName().find("/values") != std::string::npos &&
1245 95 : m_dt.GetClass() == GEDTC_COMPOUND && m_dt.GetSize() == 8 &&
1246 62 : m_dt.GetComponents().size() == 2 &&
1247 31 : m_dt.GetComponents()[0]->GetType().GetNumericDataType() ==
1248 1867 : GDT_Float32 &&
1249 : // In theory should be Byte, but 104US00_ches_dcf2_20190606T12Z.h5 uses Int32
1250 31 : (m_dt.GetComponents()[1]->GetType().GetNumericDataType() == GDT_UInt8 ||
1251 0 : m_dt.GetComponents()[1]->GetType().GetNumericDataType() == GDT_Int32))
1252 : {
1253 31 : m_abyNoData.resize(m_dt.GetSize());
1254 31 : float fNoData = -9999.0f;
1255 :
1256 62 : if (auto poRootGroup = HDF5Array::GetRootGroup())
1257 : {
1258 93 : if (const auto poGroupF = poRootGroup->OpenGroup("Group_F"))
1259 : {
1260 93 : const auto poGroupFArray = poGroupF->OpenMDArray("WaterLevel");
1261 31 : if (poGroupFArray &&
1262 93 : poGroupFArray->GetDataType().GetClass() == GEDTC_COMPOUND &&
1263 62 : poGroupFArray->GetDataType().GetComponents().size() == 8 &&
1264 31 : poGroupFArray->GetDataType()
1265 31 : .GetComponents()[0]
1266 62 : ->GetName() == "code" &&
1267 31 : poGroupFArray->GetDataType()
1268 31 : .GetComponents()[3]
1269 31 : ->GetName() == "fillValue" &&
1270 93 : poGroupFArray->GetDimensionCount() == 1 &&
1271 31 : poGroupFArray->GetDimensions()[0]->GetSize() >= 2)
1272 : {
1273 : auto poFillValue =
1274 93 : poGroupFArray->GetView("[\"fillValue\"]");
1275 31 : if (poFillValue)
1276 : {
1277 31 : char *pszVal0 = nullptr;
1278 31 : const GUInt64 anArrayStartIdx0[] = {0};
1279 31 : const size_t anCount[] = {1};
1280 31 : const GInt64 anArrayStep[] = {0};
1281 31 : const GPtrDiff_t anBufferStride[] = {0};
1282 62 : poFillValue->Read(anArrayStartIdx0, anCount,
1283 : anArrayStep, anBufferStride,
1284 62 : GDALExtendedDataType::CreateString(),
1285 : &pszVal0);
1286 31 : if (pszVal0)
1287 : {
1288 31 : fNoData = static_cast<float>(CPLAtof(pszVal0));
1289 : }
1290 31 : CPLFree(pszVal0);
1291 : }
1292 : }
1293 : }
1294 : }
1295 :
1296 31 : memcpy(m_abyNoData.data(), &fNoData, sizeof(float));
1297 : }
1298 :
1299 : // Special case for S111 nodata value that is typically -9999
1300 1808 : if (STARTS_WITH(GetFullName().c_str(),
1301 87 : "/SurfaceCurrent/SurfaceCurrent.01/") &&
1302 119 : GetFullName().find("/values") != std::string::npos &&
1303 64 : m_dt.GetClass() == GEDTC_COMPOUND &&
1304 63 : m_dt.GetSize() == 2 * sizeof(float) &&
1305 62 : m_dt.GetComponents().size() == 2 &&
1306 31 : m_dt.GetComponents()[0]->GetType().GetNumericDataType() ==
1307 1895 : GDT_Float32 &&
1308 31 : m_dt.GetComponents()[1]->GetType().GetNumericDataType() == GDT_Float32)
1309 : {
1310 31 : float afNoData[2] = {-9999.0f, -9999.0f};
1311 :
1312 62 : if (auto poRootGroup = HDF5Array::GetRootGroup())
1313 : {
1314 93 : if (const auto poGroupF = poRootGroup->OpenGroup("Group_F"))
1315 : {
1316 : const auto poGroupFArray =
1317 93 : poGroupF->OpenMDArray("SurfaceCurrent");
1318 31 : if (poGroupFArray &&
1319 93 : poGroupFArray->GetDataType().GetClass() == GEDTC_COMPOUND &&
1320 62 : poGroupFArray->GetDataType().GetComponents().size() == 8 &&
1321 31 : poGroupFArray->GetDataType()
1322 31 : .GetComponents()[0]
1323 62 : ->GetName() == "code" &&
1324 31 : poGroupFArray->GetDataType()
1325 31 : .GetComponents()[3]
1326 31 : ->GetName() == "fillValue" &&
1327 93 : poGroupFArray->GetDimensionCount() == 1 &&
1328 31 : poGroupFArray->GetDimensions()[0]->GetSize() >= 2)
1329 : {
1330 : auto poFillValue =
1331 93 : poGroupFArray->GetView("[\"fillValue\"]");
1332 31 : if (poFillValue)
1333 : {
1334 31 : char *pszVal0 = nullptr;
1335 31 : char *pszVal1 = nullptr;
1336 31 : const GUInt64 anArrayStartIdx0[] = {0};
1337 31 : const GUInt64 anArrayStartIdx1[] = {1};
1338 31 : const size_t anCount[] = {1};
1339 31 : const GInt64 anArrayStep[] = {0};
1340 31 : const GPtrDiff_t anBufferStride[] = {0};
1341 62 : poFillValue->Read(anArrayStartIdx0, anCount,
1342 : anArrayStep, anBufferStride,
1343 62 : GDALExtendedDataType::CreateString(),
1344 : &pszVal0);
1345 62 : poFillValue->Read(anArrayStartIdx1, anCount,
1346 : anArrayStep, anBufferStride,
1347 62 : GDALExtendedDataType::CreateString(),
1348 : &pszVal1);
1349 31 : if (pszVal0 && pszVal1)
1350 : {
1351 31 : afNoData[0] = static_cast<float>(CPLAtof(pszVal0));
1352 31 : afNoData[1] = static_cast<float>(CPLAtof(pszVal1));
1353 : }
1354 31 : CPLFree(pszVal0);
1355 31 : CPLFree(pszVal1);
1356 : }
1357 : }
1358 : }
1359 : }
1360 :
1361 31 : m_abyNoData.resize(m_dt.GetSize());
1362 31 : memcpy(m_abyNoData.data(), afNoData, m_abyNoData.size());
1363 : }
1364 :
1365 1808 : if (bSkipFullDimensionInstantiation)
1366 : {
1367 1292 : const int nDims = H5Sget_simple_extent_ndims(m_hDataSpace);
1368 2584 : std::vector<hsize_t> anDimSizes(nDims);
1369 1292 : if (nDims)
1370 : {
1371 1279 : H5Sget_simple_extent_dims(m_hDataSpace, &anDimSizes[0], nullptr);
1372 3268 : for (int i = 0; i < nDims; ++i)
1373 : {
1374 3978 : m_dims.emplace_back(std::make_shared<GDALDimension>(
1375 3978 : std::string(), CPLSPrintf("dim%d", i), std::string(),
1376 5967 : std::string(), anDimSizes[i]));
1377 : }
1378 : }
1379 : }
1380 : else
1381 : {
1382 516 : InstantiateDimensions(osParentName, poGroup);
1383 : }
1384 : }
1385 :
1386 : /************************************************************************/
1387 : /* InstantiateDimensions() */
1388 : /************************************************************************/
1389 :
1390 516 : void HDF5Array::InstantiateDimensions(const std::string &osParentName,
1391 : const HDF5Group *poGroup)
1392 : {
1393 516 : const int nDims = H5Sget_simple_extent_ndims(m_hDataSpace);
1394 516 : std::vector<hsize_t> anDimSizes(nDims);
1395 516 : if (nDims)
1396 : {
1397 515 : H5Sget_simple_extent_dims(m_hDataSpace, &anDimSizes[0], nullptr);
1398 : }
1399 :
1400 516 : if (nDims == 1)
1401 : {
1402 662 : auto attrCLASS = GetAttribute("CLASS");
1403 347 : if (attrCLASS && attrCLASS->GetDimensionCount() == 0 &&
1404 16 : attrCLASS->GetDataType().GetClass() == GEDTC_STRING)
1405 : {
1406 16 : const char *pszStr = attrCLASS->ReadAsString();
1407 16 : if (pszStr && EQUAL(pszStr, "DIMENSION_SCALE"))
1408 : {
1409 48 : auto attrName = GetAttribute("NAME");
1410 30 : if (attrName &&
1411 30 : attrName->GetDataType().GetClass() == GEDTC_STRING)
1412 : {
1413 14 : const char *pszName = attrName->ReadAsString();
1414 14 : if (pszName &&
1415 14 : STARTS_WITH(pszName, "This is a netCDF dimension but "
1416 : "not a netCDF variable"))
1417 : {
1418 0 : m_dims.emplace_back(std::make_shared<GDALDimension>(
1419 0 : std::string(), GetName(), std::string(),
1420 0 : std::string(), anDimSizes[0]));
1421 0 : return;
1422 : }
1423 : }
1424 :
1425 32 : m_dims.emplace_back(std::make_shared<HDF5Dimension>(
1426 32 : osParentName, GetName(), std::string(), std::string(),
1427 32 : anDimSizes[0], m_poShared));
1428 16 : return;
1429 : }
1430 : }
1431 : }
1432 :
1433 500 : std::map<size_t, std::string> mapDimIndexToDimFullName;
1434 :
1435 500 : if (m_bHasDimensionList)
1436 : {
1437 28 : hid_t hAttr = H5Aopen_name(m_hArray, "DIMENSION_LIST");
1438 28 : const hid_t hAttrDataType = H5Aget_type(hAttr);
1439 28 : const hid_t hAttrSpace = H5Aget_space(hAttr);
1440 56 : if (H5Tget_class(hAttrDataType) == H5T_VLEN &&
1441 28 : H5Sget_simple_extent_ndims(hAttrSpace) == 1)
1442 : {
1443 28 : const hid_t hBaseType = H5Tget_super(hAttrDataType);
1444 28 : if (H5Tget_class(hBaseType) == H5T_REFERENCE)
1445 : {
1446 28 : hsize_t nSize = 0;
1447 28 : H5Sget_simple_extent_dims(hAttrSpace, &nSize, nullptr);
1448 28 : if (nSize == static_cast<hsize_t>(nDims))
1449 : {
1450 56 : std::vector<hvl_t> aHvl(static_cast<size_t>(nSize));
1451 28 : H5Aread(hAttr, hAttrDataType, &aHvl[0]);
1452 92 : for (size_t i = 0; i < nSize; i++)
1453 : {
1454 128 : if (aHvl[i].len == 1 &&
1455 64 : H5Rget_obj_type(m_hArray, H5R_OBJECT, aHvl[i].p) ==
1456 : H5G_DATASET)
1457 : {
1458 128 : std::string referenceName;
1459 64 : referenceName.resize(256);
1460 128 : auto ret = H5Rget_name(
1461 64 : m_poShared->GetHDF5(), H5R_OBJECT, aHvl[i].p,
1462 64 : &referenceName[0], referenceName.size());
1463 64 : if (ret > 0)
1464 : {
1465 64 : referenceName.resize(ret);
1466 64 : mapDimIndexToDimFullName[i] =
1467 128 : std::move(referenceName);
1468 : }
1469 : }
1470 : }
1471 28 : H5Dvlen_reclaim(hAttrDataType, hAttrSpace, H5P_DEFAULT,
1472 28 : &aHvl[0]);
1473 : }
1474 : }
1475 28 : H5Tclose(hBaseType);
1476 : }
1477 28 : H5Tclose(hAttrDataType);
1478 28 : H5Sclose(hAttrSpace);
1479 28 : H5Aclose(hAttr);
1480 : }
1481 472 : else if (m_bHasDimensionLabels)
1482 : {
1483 2 : hid_t hAttr = H5Aopen_name(m_hArray, "DIMENSION_LABELS");
1484 2 : auto attr(HDF5Attribute::Create(m_osGroupFullname, GetFullName(),
1485 6 : "DIMENSION_LABELS", m_poShared, hAttr));
1486 4 : if (attr && attr->GetDimensionCount() == 1 &&
1487 2 : attr->GetDataType().GetClass() == GEDTC_STRING)
1488 : {
1489 4 : auto aosList = attr->ReadAsStringArray();
1490 2 : if (aosList.size() == nDims)
1491 : {
1492 8 : for (int i = 0; i < nDims; ++i)
1493 : {
1494 6 : if (aosList[i][0] != '\0')
1495 : {
1496 2 : mapDimIndexToDimFullName[i] = aosList[i];
1497 : }
1498 : }
1499 : }
1500 : }
1501 : }
1502 : else
1503 : {
1504 : // Use HDF-EOS5 metadata if available to create dimensions
1505 :
1506 470 : HDF5EOSParser::GridDataFieldMetadata oGridDataFieldMetadata;
1507 470 : HDF5EOSParser::SwathFieldMetadata oSwathFieldMetadata;
1508 470 : const auto poHDF5EOSParser = m_poShared->GetHDF5EOSParser();
1509 : // Build a "classic" subdataset name from group and array names
1510 : const std::string osSubdatasetName(
1511 470 : "/" +
1512 470 : CPLString(osParentName)
1513 940 : .replaceAll("Data Fields", "Data_Fields")
1514 1410 : .replaceAll("Geolocation Fields", "Geolocation_Fields") +
1515 940 : "/" + GetName());
1516 476 : if (poHDF5EOSParser &&
1517 6 : poHDF5EOSParser->GetGridDataFieldMetadata(osSubdatasetName.c_str(),
1518 476 : oGridDataFieldMetadata) &&
1519 3 : oGridDataFieldMetadata.aoDimensions.size() ==
1520 3 : static_cast<size_t>(nDims))
1521 : {
1522 6 : std::map<std::string, std::shared_ptr<GDALDimension>> oMap;
1523 3 : const auto groupDims = m_poShared->GetEOSGridDimensions(
1524 6 : oGridDataFieldMetadata.poGridMetadata->osGridName);
1525 10 : for (const auto &dim : groupDims)
1526 : {
1527 7 : oMap[dim->GetName()] = dim;
1528 : }
1529 3 : int iDimX = 0;
1530 3 : int iDimY = 0;
1531 3 : int iCount = 1;
1532 9 : for (const auto &oDim : oGridDataFieldMetadata.aoDimensions)
1533 : {
1534 6 : auto oIter = oMap.find(oDim.osName);
1535 : // HDF5EOSParser guarantees that
1536 6 : CPLAssert(oIter != oMap.end());
1537 6 : const auto &poDim = oIter->second;
1538 6 : if (poDim->GetType() == GDAL_DIM_TYPE_HORIZONTAL_X)
1539 3 : iDimX = iCount;
1540 3 : else if (poDim->GetType() == GDAL_DIM_TYPE_HORIZONTAL_Y)
1541 3 : iDimY = iCount;
1542 6 : ++iCount;
1543 6 : m_dims.emplace_back(poDim);
1544 : }
1545 :
1546 3 : auto poSRS = oGridDataFieldMetadata.poGridMetadata->GetSRS();
1547 3 : if (poSRS)
1548 : {
1549 3 : m_poSRS = std::shared_ptr<OGRSpatialReference>(poSRS->Clone());
1550 3 : if (iDimX > 0 && iDimY > 0)
1551 : {
1552 3 : if (m_poSRS->GetDataAxisToSRSAxisMapping() ==
1553 6 : std::vector<int>{2, 1})
1554 1 : m_poSRS->SetDataAxisToSRSAxisMapping({iDimY, iDimX});
1555 : else
1556 2 : m_poSRS->SetDataAxisToSRSAxisMapping({iDimX, iDimY});
1557 : }
1558 : }
1559 :
1560 3 : return;
1561 : }
1562 470 : else if (poHDF5EOSParser &&
1563 3 : poHDF5EOSParser->GetSwathFieldMetadata(
1564 470 : osSubdatasetName.c_str(), oSwathFieldMetadata) &&
1565 3 : oSwathFieldMetadata.aoDimensions.size() ==
1566 3 : static_cast<size_t>(nDims))
1567 : {
1568 6 : std::map<std::string, std::shared_ptr<GDALDimension>> oMap;
1569 3 : const auto groupDims = m_poShared->GetEOSSwathDimensions(
1570 3 : oSwathFieldMetadata.poSwathMetadata->osSwathName);
1571 12 : for (const auto &dim : groupDims)
1572 : {
1573 9 : oMap[dim->GetName()] = dim;
1574 : }
1575 10 : for (const auto &oDim : oSwathFieldMetadata.aoDimensions)
1576 : {
1577 7 : auto oIter = oMap.find(oDim.osName);
1578 : // HDF5EOSParser guarantees that
1579 7 : CPLAssert(oIter != oMap.end());
1580 7 : const auto &poDim = oIter->second;
1581 7 : m_dims.emplace_back(poDim);
1582 : }
1583 :
1584 3 : return;
1585 : }
1586 :
1587 : // Special case for S100-family of products (S102, S104, S111)
1588 104 : const auto SpecialCaseS100 = [&](const std::string &osCoverageName)
1589 : {
1590 208 : auto poRootGroup = m_poShared->GetRootGroup();
1591 104 : if (poRootGroup)
1592 : {
1593 104 : m_poSRS = std::make_shared<OGRSpatialReference>();
1594 104 : if (S100ReadSRS(poRootGroup.get(), *(m_poSRS.get())))
1595 : {
1596 104 : if (m_poSRS->GetDataAxisToSRSAxisMapping() ==
1597 208 : std::vector<int>{2, 1})
1598 32 : m_poSRS->SetDataAxisToSRSAxisMapping({1, 2});
1599 : else
1600 72 : m_poSRS->SetDataAxisToSRSAxisMapping({2, 1});
1601 : }
1602 : else
1603 : {
1604 0 : m_poSRS.reset();
1605 : }
1606 :
1607 : auto poCoverage =
1608 104 : poRootGroup->OpenGroupFromFullname(osCoverageName);
1609 104 : if (poCoverage)
1610 : {
1611 104 : std::vector<std::shared_ptr<GDALMDArray>> apoIndexingVars;
1612 104 : if (S100GetDimensions(poCoverage.get(), m_dims,
1613 104 : apoIndexingVars) &&
1614 104 : m_dims.size() == 2 &&
1615 312 : m_dims[0]->GetSize() == anDimSizes[0] &&
1616 104 : m_dims[1]->GetSize() == anDimSizes[1])
1617 : {
1618 312 : for (const auto &poIndexingVar : apoIndexingVars)
1619 208 : m_poShared->KeepRef(poIndexingVar);
1620 104 : return true;
1621 : }
1622 : else
1623 : {
1624 0 : m_dims.clear();
1625 : }
1626 : }
1627 : }
1628 0 : return false;
1629 464 : };
1630 :
1631 609 : if (nDims == 2 &&
1632 145 : GetFullName() ==
1633 : "/BathymetryCoverage/BathymetryCoverage.01/Group_001/values")
1634 : {
1635 : // S102
1636 37 : if (SpecialCaseS100("/BathymetryCoverage/BathymetryCoverage.01"))
1637 37 : return;
1638 : }
1639 535 : else if (nDims == 2 &&
1640 108 : GetFullName() ==
1641 : "/QualityOfSurvey/QualityOfSurvey.01/Group_001/values")
1642 : {
1643 : // S102
1644 3 : if (SpecialCaseS100("/QualityOfSurvey/QualityOfSurvey.01"))
1645 3 : return;
1646 : }
1647 529 : else if (nDims == 2 &&
1648 105 : STARTS_WITH(GetFullName().c_str(),
1649 529 : "/WaterLevel/WaterLevel.01/") &&
1650 32 : GetFullName().find("/values"))
1651 : {
1652 : // S104
1653 32 : if (SpecialCaseS100("/WaterLevel/WaterLevel.01"))
1654 32 : return;
1655 : }
1656 465 : else if (nDims == 2 &&
1657 73 : STARTS_WITH(GetFullName().c_str(),
1658 465 : "/SurfaceCurrent/SurfaceCurrent.01/") &&
1659 32 : GetFullName().find("/values"))
1660 : {
1661 : // S111
1662 32 : if (SpecialCaseS100("/SurfaceCurrent/SurfaceCurrent.01"))
1663 32 : return;
1664 : }
1665 : }
1666 :
1667 780 : std::map<std::string, std::shared_ptr<GDALDimension>> oMapFullNameToDim;
1668 : // cppcheck-suppress knownConditionTrueFalse
1669 390 : if (poGroup && !mapDimIndexToDimFullName.empty())
1670 : {
1671 60 : auto groupDims = poGroup->GetDimensions();
1672 181 : for (const auto &dim : groupDims)
1673 : {
1674 151 : oMapFullNameToDim[dim->GetFullName()] = dim;
1675 : }
1676 : }
1677 :
1678 868 : for (int i = 0; i < nDims; ++i)
1679 : {
1680 478 : auto oIter = mapDimIndexToDimFullName.find(static_cast<size_t>(i));
1681 478 : if (oIter != mapDimIndexToDimFullName.end())
1682 : {
1683 66 : auto oIter2 = oMapFullNameToDim.find(oIter->second);
1684 66 : if (oIter2 != oMapFullNameToDim.end())
1685 : {
1686 63 : m_dims.emplace_back(oIter2->second);
1687 63 : continue;
1688 : }
1689 :
1690 6 : std::string osDimName(oIter->second);
1691 3 : auto nPos = osDimName.rfind('/');
1692 3 : if (nPos != std::string::npos)
1693 : {
1694 1 : const std::string osDimParentName(osDimName.substr(0, nPos));
1695 1 : osDimName = osDimName.substr(nPos + 1);
1696 :
1697 2 : m_dims.emplace_back(std::make_shared<HDF5Dimension>(
1698 2 : osDimParentName.empty() ? "/" : osDimParentName, osDimName,
1699 3 : std::string(), std::string(), anDimSizes[i], m_poShared));
1700 : }
1701 : else
1702 : {
1703 4 : m_dims.emplace_back(std::make_shared<GDALDimension>(
1704 4 : std::string(), osDimName, std::string(), std::string(),
1705 4 : anDimSizes[i]));
1706 : }
1707 : }
1708 : else
1709 : {
1710 824 : m_dims.emplace_back(std::make_shared<GDALDimension>(
1711 824 : std::string(), CPLSPrintf("dim%d", i), std::string(),
1712 1236 : std::string(), anDimSizes[i]));
1713 : }
1714 : }
1715 : }
1716 :
1717 : /************************************************************************/
1718 : /* GetCoordinateVariables() */
1719 : /************************************************************************/
1720 :
1721 : std::vector<std::shared_ptr<GDALMDArray>>
1722 3 : HDF5Array::GetCoordinateVariables() const
1723 : {
1724 3 : std::vector<std::shared_ptr<GDALMDArray>> ret;
1725 :
1726 6 : HDF5EOSParser::SwathFieldMetadata oSwathFieldMetadata;
1727 3 : const auto poHDF5EOSParser = m_poShared->GetHDF5EOSParser();
1728 : // Build a "classic" subdataset name from group and array names
1729 : const std::string osSubdatasetName(
1730 3 : "/" + CPLString(GetFullName())
1731 6 : .replaceAll("Data Fields", "Data_Fields")
1732 9 : .replaceAll("Geolocation Fields", "Geolocation_Fields"));
1733 6 : if (poHDF5EOSParser &&
1734 3 : poHDF5EOSParser->GetSwathFieldMetadata(osSubdatasetName.c_str(),
1735 6 : oSwathFieldMetadata) &&
1736 1 : oSwathFieldMetadata.aoDimensions.size() == GetDimensionCount())
1737 : {
1738 1 : if (!oSwathFieldMetadata.osLongitudeSubdataset.empty() &&
1739 1 : oSwathFieldMetadata.nPixelOffset == 0 &&
1740 1 : oSwathFieldMetadata.nLineOffset == 0 &&
1741 3 : oSwathFieldMetadata.nPixelStep == 1 &&
1742 1 : oSwathFieldMetadata.nLineStep == 1)
1743 : {
1744 2 : auto poRootGroup = m_poShared->GetRootGroup();
1745 1 : if (poRootGroup)
1746 : {
1747 1 : auto poLongitude = poRootGroup->OpenMDArrayFromFullname(
1748 2 : CPLString(
1749 0 : oSwathFieldMetadata.osLongitudeSubdataset.substr(1))
1750 : .replaceAll("Geolocation_Fields",
1751 4 : "Geolocation Fields"));
1752 1 : auto poLatitude = poRootGroup->OpenMDArrayFromFullname(
1753 2 : CPLString(
1754 0 : oSwathFieldMetadata.osLatitudeSubdataset.substr(1))
1755 : .replaceAll("Geolocation_Fields",
1756 4 : "Geolocation Fields"));
1757 1 : if (poLongitude && poLatitude)
1758 : {
1759 1 : ret.push_back(std::move(poLongitude));
1760 1 : ret.push_back(std::move(poLatitude));
1761 : }
1762 : }
1763 : }
1764 : }
1765 :
1766 6 : return ret;
1767 : }
1768 :
1769 : /************************************************************************/
1770 : /* GetFilterInfo() */
1771 : /************************************************************************/
1772 :
1773 6 : static CPLStringList GetFilterInfo(hid_t hArray, unsigned nFilterMask)
1774 : {
1775 : static const struct
1776 : {
1777 : int nFilterId;
1778 : const char *pszName;
1779 : } gasHDF5Filters[] = {
1780 : // { H5Z_FILTER_DEFLATE, "DEFLATE" },
1781 : {H5Z_FILTER_SHUFFLE, "SHUFFLE"},
1782 : {H5Z_FILTER_FLETCHER32, "FLETCHER32"},
1783 : // { H5Z_FILTER_SZIP, "SZIP" },
1784 : {H5Z_FILTER_NBIT, "NBIT"},
1785 : {H5Z_FILTER_SCALEOFFSET, "SCALEOFFSET"},
1786 : // Below from netcdf_filter.h
1787 : {/*H5Z_FILTER_ZSTD */ 32015, "ZSTD"},
1788 : {/*H5Z_FILTER_BZIP2 */ 307, "BZIP2"},
1789 : {/*H5Z_FILTER_BLOSC */ 32001, "BLOSC"},
1790 : };
1791 :
1792 6 : CPLStringList aosInfo;
1793 6 : const hid_t nListId = H5Dget_create_plist(hArray);
1794 6 : if (nListId > 0)
1795 : {
1796 6 : const int nFilters = H5Pget_nfilters(nListId);
1797 6 : const char *pszCompression = nullptr;
1798 12 : std::string osFilters;
1799 8 : for (int i = 0; i < nFilters; ++i)
1800 : {
1801 2 : unsigned int flags = 0;
1802 2 : size_t cd_nelmts = 0;
1803 2 : char szName[64 + 1] = {0};
1804 : const auto eFilter =
1805 2 : H5Pget_filter(nListId, i, &flags, &cd_nelmts, nullptr,
1806 : sizeof(szName) - 1, szName);
1807 2 : if ((flags & nFilterMask) == 0)
1808 : {
1809 2 : if (eFilter == H5Z_FILTER_DEFLATE)
1810 : {
1811 1 : pszCompression = "DEFLATE";
1812 : }
1813 1 : else if (eFilter == H5Z_FILTER_SZIP)
1814 : {
1815 0 : pszCompression = "SZIP";
1816 : }
1817 : else
1818 : {
1819 1 : bool bFound = false;
1820 1 : if (!osFilters.empty())
1821 0 : osFilters += ',';
1822 1 : for (const auto &sFilterInfo : gasHDF5Filters)
1823 : {
1824 1 : if (sFilterInfo.nFilterId == eFilter)
1825 : {
1826 1 : bFound = true;
1827 1 : osFilters += sFilterInfo.pszName;
1828 1 : break;
1829 : }
1830 : }
1831 1 : if (!bFound)
1832 0 : osFilters += szName;
1833 : }
1834 : }
1835 : }
1836 6 : H5Pclose(nListId);
1837 6 : if (pszCompression)
1838 1 : aosInfo.SetNameValue("COMPRESSION", pszCompression);
1839 6 : if (!osFilters.empty())
1840 1 : aosInfo.SetNameValue("FILTER", osFilters.c_str());
1841 : }
1842 6 : return aosInfo;
1843 : }
1844 :
1845 : /************************************************************************/
1846 : /* HDF5Array::GetRawBlockInfo() */
1847 : /************************************************************************/
1848 :
1849 4 : bool HDF5Array::GetRawBlockInfo(const uint64_t *panBlockCoordinates,
1850 : GDALMDArrayRawBlockInfo &info) const
1851 : {
1852 4 : info.clear();
1853 :
1854 8 : const auto anBlockSize = GetBlockSize();
1855 4 : CPLAssert(anBlockSize.size() == m_dims.size());
1856 :
1857 7 : const auto AddExtraInfo = [this, &info]()
1858 : {
1859 3 : if (m_dt.GetSize() > 1)
1860 : {
1861 2 : const hid_t hDataType = H5Dget_type(m_hArray);
1862 2 : switch (H5Tget_order(hDataType))
1863 : {
1864 1 : case H5T_ORDER_LE:
1865 1 : info.papszInfo =
1866 1 : CSLSetNameValue(info.papszInfo, "ENDIANNESS", "LITTLE");
1867 1 : break;
1868 1 : case H5T_ORDER_BE:
1869 1 : info.papszInfo =
1870 1 : CSLSetNameValue(info.papszInfo, "ENDIANNESS", "BIG");
1871 1 : break;
1872 0 : case H5T_ORDER_VAX:
1873 0 : info.papszInfo =
1874 0 : CSLSetNameValue(info.papszInfo, "ENDIANNESS", "VAX");
1875 0 : break;
1876 0 : case H5T_ORDER_MIXED:
1877 0 : info.papszInfo =
1878 0 : CSLSetNameValue(info.papszInfo, "ENDIANNESS", "MIXED");
1879 0 : break;
1880 0 : case H5T_ORDER_NONE:
1881 : case H5T_ORDER_ERROR:
1882 0 : break;
1883 : }
1884 2 : H5Tclose(hDataType);
1885 : }
1886 7 : };
1887 :
1888 4 : if (!anBlockSize.empty() && anBlockSize[0] == 0)
1889 : {
1890 : HDF5_GLOBAL_LOCK();
1891 4 : const auto nOffset = H5Dget_offset(m_hArray);
1892 4 : if (nOffset != HADDR_UNDEF)
1893 : {
1894 4 : bool bAllZeroes = true;
1895 12 : for (size_t i = 0; i < m_dims.size() && bAllZeroes; ++i)
1896 8 : bAllZeroes = panBlockCoordinates[i] == 0;
1897 4 : if (bAllZeroes)
1898 : {
1899 3 : info.pszFilename = CPLStrdup(m_poShared->GetFilename().c_str());
1900 3 : info.nOffset = nOffset;
1901 3 : info.nSize = H5Dget_storage_size(m_hArray);
1902 3 : info.papszInfo =
1903 3 : GetFilterInfo(m_hArray, /* nFilterMask = */ 0).StealList();
1904 3 : AddExtraInfo();
1905 3 : return true;
1906 : }
1907 : else
1908 : {
1909 1 : CPLError(CE_Failure, CPLE_AppDefined,
1910 : "GetRawBlockInfo() failed: invalid block coordinates. "
1911 : "Should be all 0");
1912 1 : return false;
1913 : }
1914 : }
1915 : else
1916 : {
1917 0 : CPLError(CE_Failure, CPLE_AppDefined,
1918 : "GetRawBlockInfo() failed: array %s is not chunked or "
1919 : "contiguous",
1920 0 : GetName().c_str());
1921 0 : return false;
1922 : }
1923 : }
1924 :
1925 : #if (defined(H5_VERS_MAJOR) && \
1926 : (H5_VERS_MAJOR >= 2 || (H5_VERS_MAJOR == 1 && H5_VERS_MINOR > 10) || \
1927 : (H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 10 && H5_VERS_RELEASE >= 5)))
1928 : // Compute the block index from the coordinates
1929 : hsize_t nBlockIdx = 0;
1930 : hsize_t nMult = 1;
1931 : for (size_t nDimIdx = anBlockSize.size(); nDimIdx > 0;)
1932 : {
1933 : --nDimIdx;
1934 : const auto nBlockSize = anBlockSize[nDimIdx];
1935 : const auto nBlockCount =
1936 : cpl::div_round_up(m_dims[nDimIdx]->GetSize(), nBlockSize);
1937 : if (panBlockCoordinates[nDimIdx] >= nBlockCount)
1938 : {
1939 : CPLError(CE_Failure, CPLE_AppDefined,
1940 : "GetRawBlockInfo() failed: array %s: "
1941 : "invalid block coordinate (%u) for dimension %u",
1942 : GetName().c_str(),
1943 : static_cast<unsigned>(panBlockCoordinates[nDimIdx]),
1944 : static_cast<unsigned>(nDimIdx));
1945 : return false;
1946 : }
1947 : nBlockIdx += panBlockCoordinates[nDimIdx] * nMult;
1948 : nMult *= nBlockCount;
1949 : }
1950 :
1951 : HDF5_GLOBAL_LOCK();
1952 : std::vector<hsize_t> anOffset(GetDimensionCount());
1953 : unsigned nFilterMask = 0;
1954 : haddr_t nChunkOffset = 0;
1955 : hsize_t nChunkSize = 0;
1956 : if (H5Dget_chunk_info(m_hArray, m_hDataSpace, nBlockIdx, anOffset.data(),
1957 : &nFilterMask, &nChunkOffset, &nChunkSize) < 0)
1958 : {
1959 : CPLError(
1960 : CE_Failure, CPLE_AppDefined,
1961 : "GetRawBlockInfo() failed: array %s: H5Dget_chunk_info() failed",
1962 : GetName().c_str());
1963 : return false;
1964 : }
1965 :
1966 : info.pszFilename = CPLStrdup(m_poShared->GetFilename().c_str());
1967 : info.nOffset = nChunkOffset == HADDR_UNDEF ? 0 : nChunkOffset;
1968 :
1969 : #if !(defined(H5_VERS_MAJOR) && \
1970 : (H5_VERS_MAJOR >= 2 || \
1971 : (H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 14 && H5_VERS_RELEASE >= 4)))
1972 : // Before HDF5 1.14.4, H5Dget_chunk_info() doesn't take into account the
1973 : // user block
1974 : const hid_t nListId = H5Fget_create_plist(m_poShared->GetHDF5());
1975 : if (nListId > 0)
1976 : {
1977 : hsize_t nUserBlockSize = 0;
1978 : if (H5Pget_userblock(nListId, &nUserBlockSize) >= 0)
1979 : {
1980 : info.nOffset += nUserBlockSize;
1981 : }
1982 : H5Pclose(nListId);
1983 : }
1984 : #endif
1985 :
1986 : info.nSize = nChunkSize;
1987 : info.papszInfo = GetFilterInfo(m_hArray, nFilterMask).StealList();
1988 : AddExtraInfo();
1989 :
1990 : return true;
1991 : #else
1992 0 : CPLDebug("HDF5", "H5Dget_chunk_info() only available in HDF5 >= 1.10.5");
1993 0 : return false;
1994 : #endif
1995 : }
1996 :
1997 : /************************************************************************/
1998 : /* GetAttributesCallback() */
1999 : /************************************************************************/
2000 :
2001 4901 : herr_t HDF5Array::GetAttributesCallback(hid_t hArray, const char *pszObjName,
2002 : void *selfIn)
2003 : {
2004 4901 : HDF5Array *self = static_cast<HDF5Array *>(selfIn);
2005 4901 : if (self->m_bShowAllAttributes ||
2006 2807 : (strcmp(pszObjName, "_Netcdf4Dimid") != 0 &&
2007 2437 : strcmp(pszObjName, "_Netcdf4Coordinates") != 0 &&
2008 2434 : strcmp(pszObjName, "CLASS") != 0 && strcmp(pszObjName, "NAME") != 0))
2009 : {
2010 4312 : if (EQUAL(pszObjName, "DIMENSION_LIST"))
2011 : {
2012 458 : self->m_bHasDimensionList = true;
2013 458 : if (!self->m_bShowAllAttributes)
2014 303 : return 0;
2015 : }
2016 4009 : if (EQUAL(pszObjName, "DIMENSION_LABELS"))
2017 : {
2018 9 : self->m_bHasDimensionLabels = true;
2019 9 : if (!self->m_bShowAllAttributes)
2020 6 : return 0;
2021 : }
2022 :
2023 4003 : hid_t hAttr = H5Aopen_name(hArray, pszObjName);
2024 4003 : if (hAttr > 0)
2025 : {
2026 4003 : auto attr(HDF5Attribute::Create(self->m_osGroupFullname,
2027 : self->GetFullName(), pszObjName,
2028 8006 : self->m_poShared, hAttr));
2029 4003 : if (attr)
2030 : {
2031 : // Used by HDF5-EOS products
2032 24 : if (EQUAL(pszObjName, "_FillValue") &&
2033 48 : self->GetDataType().GetClass() == GEDTC_NUMERIC &&
2034 3684 : attr->GetDataType().GetClass() == GEDTC_NUMERIC &&
2035 24 : attr->GetDimensionCount() == 0)
2036 : {
2037 24 : auto oRawResult(attr->ReadAsRaw());
2038 24 : if (oRawResult.data())
2039 : {
2040 : // Round-trip attribute value to target data type and back
2041 : // to attribute data type to ensure there is no loss
2042 : // Normally _FillValue data type should be the same
2043 : // as the array one, but this is not always the case.
2044 : // For example NASA GEDI L2B products have Float64
2045 : // _FillValue for Float32 variables.
2046 24 : self->m_abyNoData.resize(self->GetDataType().GetSize());
2047 72 : GDALExtendedDataType::CopyValue(
2048 24 : oRawResult.data(), attr->GetDataType(),
2049 24 : self->m_abyNoData.data(), self->GetDataType());
2050 : std::vector<GByte> abyTmp(
2051 24 : attr->GetDataType().GetSize());
2052 72 : GDALExtendedDataType::CopyValue(
2053 24 : self->m_abyNoData.data(), self->GetDataType(),
2054 24 : abyTmp.data(), attr->GetDataType());
2055 24 : std::vector<GByte> abyOri;
2056 24 : abyOri.assign(oRawResult.data(),
2057 24 : oRawResult.data() + oRawResult.size());
2058 24 : if (abyOri == abyTmp)
2059 : {
2060 20 : if (!self->m_bShowAllAttributes)
2061 14 : return 0;
2062 : }
2063 : else
2064 : {
2065 4 : self->m_abyNoData.clear();
2066 4 : if (!self->m_bWarnedNoData)
2067 : {
2068 2 : self->m_bWarnedNoData = true;
2069 2 : char *pszVal = nullptr;
2070 4 : GDALExtendedDataType::CopyValue(
2071 2 : oRawResult.data(), attr->GetDataType(),
2072 : &pszVal,
2073 4 : GDALExtendedDataType::CreateString());
2074 6 : CPLError(CE_Warning, CPLE_AppDefined,
2075 : "Array %s: %s attribute value (%s) is "
2076 : "not in "
2077 : "the range of the "
2078 : "array data type (%s)",
2079 2 : self->GetName().c_str(), pszObjName,
2080 2 : pszVal ? pszVal : "(null)",
2081 : GDALGetDataTypeName(
2082 2 : self->GetDataType()
2083 : .GetNumericDataType()));
2084 2 : CPLFree(pszVal);
2085 : }
2086 : }
2087 : }
2088 : }
2089 :
2090 54 : if (EQUAL(pszObjName, "units") &&
2091 3676 : attr->GetDataType().GetClass() == GEDTC_STRING &&
2092 54 : attr->GetDimensionCount() == 0)
2093 : {
2094 54 : const char *pszStr = attr->ReadAsString();
2095 54 : if (pszStr)
2096 : {
2097 54 : self->m_osUnit = pszStr;
2098 54 : if (!self->m_bShowAllAttributes)
2099 27 : return 0;
2100 : }
2101 : }
2102 :
2103 3595 : self->m_oListAttributes.emplace_back(attr);
2104 : }
2105 : }
2106 : }
2107 4551 : return 0;
2108 : }
2109 :
2110 : /************************************************************************/
2111 : /* GetAttributeFromAttributes() */
2112 : /************************************************************************/
2113 :
2114 : /** Possible fallback implementation for GetAttribute() using GetAttributes().
2115 : */
2116 : std::shared_ptr<GDALAttribute>
2117 1591 : HDF5Array::GetAttribute(const std::string &osName) const
2118 : {
2119 1591 : const char *const apszOptions[] = {"SHOW_ALL=YES", nullptr};
2120 1591 : if (!m_bShowAllAttributes)
2121 1500 : GetAttributes(apszOptions);
2122 3193 : for (const auto &attr : m_oListAttributes)
2123 : {
2124 1784 : if (attr->GetName() == osName)
2125 182 : return attr;
2126 : }
2127 1409 : return nullptr;
2128 : }
2129 :
2130 : /************************************************************************/
2131 : /* GetAttributes() */
2132 : /************************************************************************/
2133 :
2134 : std::vector<std::shared_ptr<GDALAttribute>>
2135 3320 : HDF5Array::GetAttributes(CSLConstList papszOptions) const
2136 : {
2137 : HDF5_GLOBAL_LOCK();
2138 :
2139 3320 : m_oListAttributes.clear();
2140 3320 : m_bShowAllAttributes =
2141 3320 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SHOW_ALL", "NO"));
2142 3320 : H5Aiterate(m_hArray, nullptr, GetAttributesCallback,
2143 : const_cast<void *>(static_cast<const void *>(this)));
2144 3320 : return m_oListAttributes;
2145 : }
2146 :
2147 : /************************************************************************/
2148 : /* GetBlockSize() */
2149 : /************************************************************************/
2150 :
2151 227 : std::vector<GUInt64> HDF5Array::GetBlockSize() const
2152 : {
2153 : HDF5_GLOBAL_LOCK();
2154 :
2155 227 : const auto nDimCount = GetDimensionCount();
2156 227 : std::vector<GUInt64> res(nDimCount);
2157 227 : if (res.empty())
2158 0 : return res;
2159 :
2160 227 : const hid_t nListId = H5Dget_create_plist(m_hArray);
2161 227 : if (nListId > 0)
2162 : {
2163 227 : if (H5Pget_layout(nListId) == H5D_CHUNKED)
2164 : {
2165 306 : std::vector<hsize_t> anChunkDims(nDimCount);
2166 153 : const int nDimSize = H5Pget_chunk(
2167 153 : nListId, static_cast<int>(nDimCount), &anChunkDims[0]);
2168 153 : if (static_cast<size_t>(nDimSize) == nDimCount)
2169 : {
2170 459 : for (size_t i = 0; i < nDimCount; ++i)
2171 : {
2172 306 : res[i] = anChunkDims[i];
2173 : }
2174 : }
2175 : }
2176 :
2177 227 : H5Pclose(nListId);
2178 : }
2179 :
2180 227 : return res;
2181 : }
2182 :
2183 : /************************************************************************/
2184 : /* GetStructuralInfo() */
2185 : /************************************************************************/
2186 :
2187 3 : CSLConstList HDF5Array::GetStructuralInfo() const
2188 : {
2189 3 : if (m_aosStructuralInfo.empty())
2190 : {
2191 : HDF5_GLOBAL_LOCK();
2192 3 : m_aosStructuralInfo = GetFilterInfo(m_hArray, /* nFilterMask = */ 0);
2193 : }
2194 3 : return m_aosStructuralInfo.List();
2195 : }
2196 :
2197 : /************************************************************************/
2198 : /* CopyBuffer() */
2199 : /************************************************************************/
2200 :
2201 95 : static void CopyBuffer(size_t nDims, const size_t *count,
2202 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
2203 : const GDALExtendedDataType &bufferDataType,
2204 : GByte *pabySrc, void *pDstBuffer)
2205 : {
2206 95 : const size_t nBufferDataTypeSize(bufferDataType.GetSize());
2207 190 : std::vector<size_t> anStackCount(nDims);
2208 190 : std::vector<GByte *> pabySrcBufferStack(nDims + 1);
2209 190 : std::vector<GByte *> pabyDstBufferStack(nDims + 1);
2210 190 : std::vector<GPtrDiff_t> anSrcStride(nDims);
2211 190 : std::vector<size_t> anSrcOffset(nDims + 1);
2212 95 : size_t nCurStride = nBufferDataTypeSize;
2213 286 : for (size_t i = nDims; i > 0;)
2214 : {
2215 191 : --i;
2216 191 : anSrcStride[i] = arrayStep[i] > 0
2217 191 : ? nCurStride
2218 105 : : -static_cast<GPtrDiff_t>(nCurStride);
2219 191 : anSrcOffset[i] = arrayStep[i] > 0 ? 0 : (count[i] - 1) * nCurStride;
2220 191 : nCurStride *= count[i];
2221 : }
2222 95 : pabySrcBufferStack[0] = pabySrc + anSrcOffset[0];
2223 95 : pabyDstBufferStack[0] = static_cast<GByte *>(pDstBuffer);
2224 95 : size_t iDim = 0;
2225 1469 : lbl_next_depth:
2226 1469 : if (iDim == nDims)
2227 : {
2228 1113 : memcpy(pabyDstBufferStack[nDims], pabySrcBufferStack[nDims],
2229 : nBufferDataTypeSize);
2230 : }
2231 : else
2232 : {
2233 356 : anStackCount[iDim] = count[iDim];
2234 : while (true)
2235 : {
2236 1374 : ++iDim;
2237 2748 : pabySrcBufferStack[iDim] =
2238 1374 : pabySrcBufferStack[iDim - 1] + anSrcOffset[iDim];
2239 1374 : pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
2240 1374 : goto lbl_next_depth;
2241 1374 : lbl_return_to_caller_in_loop:
2242 1374 : --iDim;
2243 1374 : --anStackCount[iDim];
2244 1374 : if (anStackCount[iDim] == 0)
2245 356 : break;
2246 1018 : if (bufferStride[iDim] >= 0)
2247 978 : pabyDstBufferStack[iDim] +=
2248 978 : bufferStride[iDim] * nBufferDataTypeSize;
2249 : else
2250 40 : pabyDstBufferStack[iDim] -=
2251 40 : (-bufferStride[iDim]) * nBufferDataTypeSize;
2252 1018 : pabySrcBufferStack[iDim] += anSrcStride[iDim];
2253 : }
2254 : }
2255 1469 : if (iDim > 0)
2256 1374 : goto lbl_return_to_caller_in_loop;
2257 95 : }
2258 :
2259 : /************************************************************************/
2260 : /* ReadSlow() */
2261 : /************************************************************************/
2262 :
2263 100 : bool HDF5Array::ReadSlow(const GUInt64 *arrayStartIdx, const size_t *count,
2264 : const GInt64 *arrayStep,
2265 : const GPtrDiff_t *bufferStride,
2266 : const GDALExtendedDataType &bufferDataType,
2267 : void *pDstBuffer) const
2268 : {
2269 100 : const size_t nBufferDataTypeSize(bufferDataType.GetSize());
2270 100 : if (nBufferDataTypeSize == 0)
2271 0 : return false;
2272 100 : const size_t nDims(m_dims.size());
2273 100 : size_t nEltCount = 1;
2274 301 : for (size_t i = 0; i < nDims; ++i)
2275 : {
2276 201 : nEltCount *= count[i];
2277 : }
2278 :
2279 : // Only for testing
2280 : const char *pszThreshold =
2281 100 : CPLGetConfigOption("GDAL_HDF5_TEMP_ARRAY_ALLOC_SIZE", "16777216");
2282 : const GUIntBig nThreshold =
2283 100 : CPLScanUIntBig(pszThreshold, static_cast<int>(strlen(pszThreshold)));
2284 100 : if (nEltCount == 1 || nEltCount <= nThreshold / nBufferDataTypeSize)
2285 : {
2286 95 : CPLDebug("HDF5", "Using slow path");
2287 190 : std::vector<GByte> abyTemp;
2288 : try
2289 : {
2290 95 : abyTemp.resize(nEltCount * nBufferDataTypeSize);
2291 : }
2292 0 : catch (const std::exception &e)
2293 : {
2294 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
2295 0 : return false;
2296 : }
2297 190 : std::vector<GUInt64> anStart(nDims);
2298 190 : std::vector<GInt64> anStep(nDims);
2299 286 : for (size_t i = 0; i < nDims; i++)
2300 : {
2301 191 : if (arrayStep[i] >= 0)
2302 : {
2303 87 : anStart[i] = arrayStartIdx[i];
2304 87 : anStep[i] = arrayStep[i];
2305 : }
2306 : else
2307 : {
2308 : // Use double negation so that operations occur only on
2309 : // positive quantities to avoid an artificial negative signed
2310 : // integer to unsigned conversion.
2311 208 : anStart[i] =
2312 104 : arrayStartIdx[i] - ((-arrayStep[i]) * (count[i] - 1));
2313 104 : anStep[i] = -arrayStep[i];
2314 : }
2315 : }
2316 190 : std::vector<GPtrDiff_t> anStride(nDims);
2317 95 : size_t nCurStride = 1;
2318 286 : for (size_t i = nDims; i > 0;)
2319 : {
2320 191 : --i;
2321 191 : anStride[i] = nCurStride;
2322 191 : nCurStride *= count[i];
2323 : }
2324 95 : if (!IRead(anStart.data(), count, anStep.data(), anStride.data(),
2325 95 : bufferDataType, &abyTemp[0]))
2326 : {
2327 0 : return false;
2328 : }
2329 95 : CopyBuffer(nDims, count, arrayStep, bufferStride, bufferDataType,
2330 95 : &abyTemp[0], pDstBuffer);
2331 95 : return true;
2332 : }
2333 :
2334 10 : std::vector<GUInt64> arrayStartIdxHalf;
2335 10 : std::vector<size_t> countHalf;
2336 5 : size_t iDimToSplit = nDims;
2337 : // Find the first dimension that has at least 2 elements, to split along
2338 : // it
2339 15 : for (size_t i = 0; i < nDims; ++i)
2340 : {
2341 10 : arrayStartIdxHalf.push_back(arrayStartIdx[i]);
2342 10 : countHalf.push_back(count[i]);
2343 10 : if (count[i] >= 2 && iDimToSplit == nDims)
2344 : {
2345 5 : iDimToSplit = i;
2346 : }
2347 : }
2348 :
2349 5 : CPLAssert(iDimToSplit != nDims);
2350 :
2351 5 : countHalf[iDimToSplit] /= 2;
2352 5 : if (!ReadSlow(arrayStartIdxHalf.data(), countHalf.data(), arrayStep,
2353 : bufferStride, bufferDataType, pDstBuffer))
2354 : {
2355 0 : return false;
2356 : }
2357 5 : arrayStartIdxHalf[iDimToSplit] = static_cast<GUInt64>(
2358 5 : arrayStep[iDimToSplit] > 0
2359 0 : ? arrayStartIdx[iDimToSplit] +
2360 0 : arrayStep[iDimToSplit] * countHalf[iDimToSplit]
2361 5 : : arrayStartIdx[iDimToSplit] -
2362 5 : (-arrayStep[iDimToSplit]) * countHalf[iDimToSplit]);
2363 : GByte *pOtherHalfDstBuffer =
2364 10 : static_cast<GByte *>(pDstBuffer) + bufferStride[iDimToSplit] *
2365 5 : countHalf[iDimToSplit] *
2366 5 : nBufferDataTypeSize;
2367 5 : countHalf[iDimToSplit] = count[iDimToSplit] - countHalf[iDimToSplit];
2368 5 : return ReadSlow(arrayStartIdxHalf.data(), countHalf.data(), arrayStep,
2369 5 : bufferStride, bufferDataType, pOtherHalfDstBuffer);
2370 : }
2371 :
2372 : /************************************************************************/
2373 : /* IngestVariableStrings() */
2374 : /************************************************************************/
2375 :
2376 1 : static void IngestVariableStrings(void *pDstBuffer, hid_t hBufferType,
2377 : size_t nDims, const size_t *count,
2378 : const GPtrDiff_t *bufferStride)
2379 : {
2380 2 : std::vector<hsize_t> anCountOne(nDims, 1);
2381 : const hid_t hMemSpaceOne =
2382 1 : nDims == 0 ? H5Screate(H5S_SCALAR)
2383 1 : : H5Screate_simple(static_cast<int>(nDims),
2384 1 : anCountOne.data(), nullptr);
2385 2 : std::vector<size_t> anStackCount(nDims);
2386 2 : std::vector<GByte *> pabyDstBufferStack(nDims + 1);
2387 1 : pabyDstBufferStack[0] = static_cast<GByte *>(pDstBuffer);
2388 1 : size_t iDim = 0;
2389 4 : lbl_next_depth:
2390 4 : if (iDim == nDims)
2391 : {
2392 2 : void *old_ptr = pabyDstBufferStack[nDims];
2393 2 : const char *pszSrcStr = *static_cast<char **>(old_ptr);
2394 2 : char *pszNewStr = pszSrcStr ? VSIStrdup(pszSrcStr) : nullptr;
2395 2 : H5Dvlen_reclaim(hBufferType, hMemSpaceOne, H5P_DEFAULT, old_ptr);
2396 2 : *static_cast<char **>(old_ptr) = pszNewStr;
2397 : }
2398 : else
2399 : {
2400 2 : anStackCount[iDim] = count[iDim];
2401 : while (true)
2402 : {
2403 3 : ++iDim;
2404 3 : pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
2405 3 : goto lbl_next_depth;
2406 3 : lbl_return_to_caller_in_loop:
2407 3 : --iDim;
2408 3 : --anStackCount[iDim];
2409 3 : if (anStackCount[iDim] == 0)
2410 2 : break;
2411 1 : pabyDstBufferStack[iDim] += bufferStride[iDim] * sizeof(char *);
2412 : }
2413 : }
2414 4 : if (iDim > 0)
2415 3 : goto lbl_return_to_caller_in_loop;
2416 1 : H5Sclose(hMemSpaceOne);
2417 1 : }
2418 :
2419 : /************************************************************************/
2420 : /* IngestFixedLengthStrings() */
2421 : /************************************************************************/
2422 :
2423 0 : static void IngestFixedLengthStrings(void *pDstBuffer, const void *pTemp,
2424 : hid_t hBufferType, size_t nDims,
2425 : const size_t *count,
2426 : const GPtrDiff_t *bufferStride)
2427 : {
2428 0 : const size_t nStringSize = H5Tget_size(hBufferType);
2429 0 : std::vector<size_t> anStackCount(nDims);
2430 0 : std::vector<GByte *> pabyDstBufferStack(nDims + 1);
2431 0 : const GByte *pabySrcBuffer = static_cast<const GByte *>(pTemp);
2432 0 : pabyDstBufferStack[0] = static_cast<GByte *>(pDstBuffer);
2433 0 : size_t iDim = 0;
2434 0 : const bool bSpacePad = H5Tget_strpad(hBufferType) == H5T_STR_SPACEPAD;
2435 0 : lbl_next_depth:
2436 0 : if (iDim == nDims)
2437 : {
2438 0 : char *pszStr = static_cast<char *>(VSIMalloc(nStringSize + 1));
2439 0 : if (pszStr)
2440 : {
2441 0 : memcpy(pszStr, pabySrcBuffer, nStringSize);
2442 0 : size_t nIter = nStringSize;
2443 0 : if (bSpacePad)
2444 : {
2445 0 : while (nIter >= 1 && pszStr[nIter - 1] == ' ')
2446 : {
2447 0 : nIter--;
2448 : }
2449 : }
2450 0 : pszStr[nIter] = 0;
2451 : }
2452 0 : void *ptr = pabyDstBufferStack[nDims];
2453 0 : *static_cast<char **>(ptr) = pszStr;
2454 : }
2455 : else
2456 : {
2457 0 : anStackCount[iDim] = count[iDim];
2458 : while (true)
2459 : {
2460 0 : ++iDim;
2461 0 : pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
2462 0 : goto lbl_next_depth;
2463 0 : lbl_return_to_caller_in_loop:
2464 0 : --iDim;
2465 0 : --anStackCount[iDim];
2466 0 : if (anStackCount[iDim] == 0)
2467 0 : break;
2468 0 : pabyDstBufferStack[iDim] += bufferStride[iDim] * sizeof(char *);
2469 0 : pabySrcBuffer += nStringSize;
2470 : }
2471 : }
2472 0 : if (iDim > 0)
2473 0 : goto lbl_return_to_caller_in_loop;
2474 0 : }
2475 :
2476 : /************************************************************************/
2477 : /* GetHDF5DataTypeFromGDALDataType() */
2478 : /************************************************************************/
2479 :
2480 : static hid_t
2481 6089 : GetHDF5DataTypeFromGDALDataType(const GDALExtendedDataType &dt, hid_t hNativeDT,
2482 : const GDALExtendedDataType &bufferDataType)
2483 : {
2484 6089 : hid_t hBufferType = H5I_INVALID_HID;
2485 6089 : switch (bufferDataType.GetNumericDataType())
2486 : {
2487 18 : case GDT_UInt8:
2488 18 : hBufferType = H5Tcopy(H5T_NATIVE_UCHAR);
2489 18 : break;
2490 0 : case GDT_Int8:
2491 0 : hBufferType = H5Tcopy(H5T_NATIVE_SCHAR);
2492 0 : break;
2493 17 : case GDT_UInt16:
2494 17 : hBufferType = H5Tcopy(H5T_NATIVE_USHORT);
2495 17 : break;
2496 2 : case GDT_Int16:
2497 2 : hBufferType = H5Tcopy(H5T_NATIVE_SHORT);
2498 2 : break;
2499 14 : case GDT_UInt32:
2500 14 : hBufferType = H5Tcopy(H5T_NATIVE_UINT);
2501 14 : break;
2502 2082 : case GDT_Int32:
2503 2082 : hBufferType = H5Tcopy(H5T_NATIVE_INT);
2504 2082 : break;
2505 1 : case GDT_UInt64:
2506 1 : hBufferType = H5Tcopy(H5T_NATIVE_UINT64);
2507 1 : break;
2508 2 : case GDT_Int64:
2509 2 : hBufferType = H5Tcopy(H5T_NATIVE_INT64);
2510 2 : break;
2511 0 : case GDT_Float16:
2512 : #ifdef HDF5_HAVE_FLOAT16
2513 : hBufferType = H5Tcopy(H5T_NATIVE_FLOAT16);
2514 : break;
2515 : #else
2516 0 : return H5I_INVALID_HID;
2517 : #endif
2518 19 : case GDT_Float32:
2519 19 : hBufferType = H5Tcopy(H5T_NATIVE_FLOAT);
2520 19 : break;
2521 3934 : case GDT_Float64:
2522 3934 : hBufferType = H5Tcopy(H5T_NATIVE_DOUBLE);
2523 3934 : break;
2524 0 : case GDT_CInt16:
2525 : case GDT_CInt32:
2526 : case GDT_CFloat16:
2527 : case GDT_CFloat32:
2528 : case GDT_CFloat64:
2529 0 : if (bufferDataType != dt)
2530 : {
2531 0 : return H5I_INVALID_HID;
2532 : }
2533 : else
2534 : {
2535 0 : hBufferType = H5Tcopy(hNativeDT);
2536 0 : break;
2537 : }
2538 0 : case GDT_Unknown:
2539 : case GDT_TypeCount:
2540 0 : return H5I_INVALID_HID;
2541 : }
2542 6089 : return hBufferType;
2543 : }
2544 :
2545 : /************************************************************************/
2546 : /* FreeDynamicMemory() */
2547 : /************************************************************************/
2548 :
2549 2424 : static void FreeDynamicMemory(GByte *pabyPtr, hid_t hDataType)
2550 : {
2551 2424 : const auto klass = H5Tget_class(hDataType);
2552 2424 : if (klass == H5T_STRING && H5Tis_variable_str(hDataType))
2553 : {
2554 1139 : auto hDataSpace = H5Screate(H5S_SCALAR);
2555 1139 : H5Dvlen_reclaim(hDataType, hDataSpace, H5P_DEFAULT, pabyPtr);
2556 1139 : H5Sclose(hDataSpace);
2557 : }
2558 1285 : else if (klass == H5T_COMPOUND)
2559 : {
2560 469 : const unsigned nMembers = H5Tget_nmembers(hDataType);
2561 2424 : for (unsigned i = 0; i < nMembers; i++)
2562 : {
2563 1955 : const auto nOffset = H5Tget_member_offset(hDataType, i);
2564 1955 : auto hMemberType = H5Tget_member_type(hDataType, i);
2565 1955 : if (hMemberType < 0)
2566 0 : continue;
2567 1955 : FreeDynamicMemory(pabyPtr + nOffset, hMemberType);
2568 1955 : H5Tclose(hMemberType);
2569 : }
2570 : }
2571 2424 : }
2572 :
2573 : /************************************************************************/
2574 : /* CreateMapTargetComponentsToSrc() */
2575 : /************************************************************************/
2576 :
2577 : static std::vector<unsigned>
2578 454 : CreateMapTargetComponentsToSrc(hid_t hSrcDataType,
2579 : const GDALExtendedDataType &dstDataType)
2580 : {
2581 454 : CPLAssert(H5Tget_class(hSrcDataType) == H5T_COMPOUND);
2582 454 : CPLAssert(dstDataType.GetClass() == GEDTC_COMPOUND);
2583 :
2584 454 : const unsigned nMembers = H5Tget_nmembers(hSrcDataType);
2585 908 : std::map<std::string, unsigned> oMapSrcCompNameToIdx;
2586 2381 : for (unsigned i = 0; i < nMembers; i++)
2587 : {
2588 1927 : char *pszName = H5Tget_member_name(hSrcDataType, i);
2589 1927 : if (pszName)
2590 : {
2591 1927 : oMapSrcCompNameToIdx[pszName] = i;
2592 1927 : H5free_memory(pszName);
2593 : }
2594 : }
2595 :
2596 454 : std::vector<unsigned> ret;
2597 454 : const auto &comps = dstDataType.GetComponents();
2598 454 : ret.reserve(comps.size());
2599 2163 : for (const auto &comp : comps)
2600 : {
2601 1709 : auto oIter = oMapSrcCompNameToIdx.find(comp->GetName());
2602 1709 : CPLAssert(oIter != oMapSrcCompNameToIdx.end());
2603 1709 : ret.emplace_back(oIter->second);
2604 : }
2605 908 : return ret;
2606 : }
2607 :
2608 : /************************************************************************/
2609 : /* CopyValue() */
2610 : /************************************************************************/
2611 :
2612 13503 : static void CopyValue(const GByte *pabySrcBuffer, hid_t hSrcDataType,
2613 : GByte *pabyDstBuffer,
2614 : const GDALExtendedDataType &dstDataType,
2615 : const std::vector<unsigned> &mapDstCompsToSrcComps)
2616 : {
2617 13503 : const auto klass = H5Tget_class(hSrcDataType);
2618 13503 : if (klass == H5T_STRING)
2619 : {
2620 3027 : if (H5Tis_variable_str(hSrcDataType))
2621 : {
2622 2341 : GDALExtendedDataType::CopyValue(
2623 4682 : pabySrcBuffer, GDALExtendedDataType::CreateString(),
2624 : pabyDstBuffer, dstDataType);
2625 : }
2626 : else
2627 : {
2628 686 : size_t nStringSize = H5Tget_size(hSrcDataType);
2629 686 : char *pszStr = static_cast<char *>(VSIMalloc(nStringSize + 1));
2630 686 : if (pszStr)
2631 : {
2632 686 : memcpy(pszStr, pabySrcBuffer, nStringSize);
2633 686 : pszStr[nStringSize] = 0;
2634 : }
2635 686 : GDALExtendedDataType::CopyValue(
2636 1372 : &pszStr, GDALExtendedDataType::CreateString(), pabyDstBuffer,
2637 : dstDataType);
2638 686 : CPLFree(pszStr);
2639 : }
2640 : }
2641 10476 : else if (klass == H5T_COMPOUND)
2642 : {
2643 474 : if (dstDataType.GetClass() != GEDTC_COMPOUND)
2644 : {
2645 3 : const auto eSrcDataType = ::HDF5Dataset::GetDataType(hSrcDataType);
2646 : // Typically source is complex data type
2647 : #ifdef HDF5_HAVE_FLOAT16
2648 : if (eSrcDataType == GDT_CFloat32 &&
2649 : ::HDF5Dataset::IsNativeCFloat16(hSrcDataType))
2650 : {
2651 : if (dstDataType.GetNumericDataType() == GDT_CFloat32)
2652 : {
2653 : for (int j = 0; j <= 1; ++j)
2654 : {
2655 : uint16_t nVal16;
2656 : memcpy(&nVal16, pabySrcBuffer + j * sizeof(nVal16),
2657 : sizeof(nVal16));
2658 : const uint32_t nVal32 = CPLHalfToFloat(nVal16);
2659 : memcpy(pabyDstBuffer + j * sizeof(float), &nVal32,
2660 : sizeof(nVal32));
2661 : }
2662 : }
2663 : else if (dstDataType.GetNumericDataType() == GDT_CFloat64)
2664 : {
2665 : for (int j = 0; j <= 1; ++j)
2666 : {
2667 : uint16_t nVal16;
2668 : memcpy(&nVal16, pabySrcBuffer + j * sizeof(nVal16),
2669 : sizeof(nVal16));
2670 : const uint32_t nVal32 = CPLHalfToFloat(nVal16);
2671 : float fVal;
2672 : memcpy(&fVal, &nVal32, sizeof(fVal));
2673 : double dfVal = fVal;
2674 : memcpy(pabyDstBuffer + j * sizeof(double), &dfVal,
2675 : sizeof(dfVal));
2676 : }
2677 : }
2678 : return;
2679 : }
2680 :
2681 : #endif
2682 6 : auto srcDataType(GDALExtendedDataType::Create(eSrcDataType));
2683 6 : if (srcDataType.GetClass() == GEDTC_NUMERIC &&
2684 3 : srcDataType.GetNumericDataType() != GDT_Unknown)
2685 : {
2686 3 : GDALExtendedDataType::CopyValue(pabySrcBuffer, srcDataType,
2687 : pabyDstBuffer, dstDataType);
2688 : }
2689 : }
2690 : else
2691 : {
2692 471 : const auto &comps = dstDataType.GetComponents();
2693 471 : CPLAssert(comps.size() == mapDstCompsToSrcComps.size());
2694 2197 : for (size_t iDst = 0; iDst < comps.size(); ++iDst)
2695 : {
2696 1726 : const unsigned iSrc = mapDstCompsToSrcComps[iDst];
2697 1726 : auto hMemberType = H5Tget_member_type(hSrcDataType, iSrc);
2698 : const std::vector<unsigned> mapDstSubCompsToSrcSubComps(
2699 1726 : (H5Tget_class(hMemberType) == H5T_COMPOUND &&
2700 0 : comps[iDst]->GetType().GetClass() == GEDTC_COMPOUND)
2701 1726 : ? CreateMapTargetComponentsToSrc(hMemberType,
2702 0 : comps[iDst]->GetType())
2703 3452 : : std::vector<unsigned>());
2704 1726 : CopyValue(pabySrcBuffer +
2705 1726 : H5Tget_member_offset(hSrcDataType, iSrc),
2706 1726 : hMemberType, pabyDstBuffer + comps[iDst]->GetOffset(),
2707 1726 : comps[iDst]->GetType(), mapDstSubCompsToSrcSubComps);
2708 1726 : H5Tclose(hMemberType);
2709 : }
2710 : }
2711 : }
2712 10002 : else if (klass == H5T_ENUM)
2713 : {
2714 1454 : auto hParent = H5Tget_super(hSrcDataType);
2715 1454 : CopyValue(pabySrcBuffer, hParent, pabyDstBuffer, dstDataType, {});
2716 1454 : H5Tclose(hParent);
2717 : }
2718 : #ifdef HDF5_HAVE_FLOAT16
2719 : else if (H5Tequal(hSrcDataType, H5T_NATIVE_FLOAT16))
2720 : {
2721 : uint16_t nVal16;
2722 : memcpy(&nVal16, pabySrcBuffer, sizeof(nVal16));
2723 : const uint32_t nVal32 = CPLHalfToFloat(nVal16);
2724 : float fVal;
2725 : memcpy(&fVal, &nVal32, sizeof(fVal));
2726 : GDALExtendedDataType::CopyValue(
2727 : &fVal, GDALExtendedDataType::Create(GDT_Float32), pabyDstBuffer,
2728 : dstDataType);
2729 : }
2730 : #endif
2731 : else
2732 : {
2733 8548 : GDALDataType eDT = ::HDF5Dataset::GetDataType(hSrcDataType);
2734 8548 : GDALExtendedDataType::CopyValue(pabySrcBuffer,
2735 17096 : GDALExtendedDataType::Create(eDT),
2736 : pabyDstBuffer, dstDataType);
2737 : }
2738 13503 : }
2739 :
2740 : /************************************************************************/
2741 : /* CopyToFinalBuffer() */
2742 : /************************************************************************/
2743 :
2744 454 : static void CopyToFinalBuffer(void *pDstBuffer, const void *pTemp, size_t nDims,
2745 : const size_t *count,
2746 : const GPtrDiff_t *bufferStride,
2747 : hid_t hSrcDataType,
2748 : const GDALExtendedDataType &bufferDataType)
2749 : {
2750 454 : const size_t nSrcDataTypeSize(H5Tget_size(hSrcDataType));
2751 908 : std::vector<size_t> anStackCount(nDims);
2752 908 : std::vector<GByte *> pabyDstBufferStack(nDims + 1);
2753 454 : const GByte *pabySrcBuffer = static_cast<const GByte *>(pTemp);
2754 454 : pabyDstBufferStack[0] = static_cast<GByte *>(pDstBuffer);
2755 454 : size_t iDim = 0;
2756 : const std::vector<unsigned> mapDstCompsToSrcComps(
2757 907 : (H5Tget_class(hSrcDataType) == H5T_COMPOUND &&
2758 453 : bufferDataType.GetClass() == GEDTC_COMPOUND)
2759 454 : ? CreateMapTargetComponentsToSrc(hSrcDataType, bufferDataType)
2760 908 : : std::vector<unsigned>());
2761 :
2762 454 : bool bFastCopyOfCompoundToSingleComponentCompound = false;
2763 454 : GDALDataType eSrcTypeComp = GDT_Unknown;
2764 454 : size_t nSrcOffset = 0;
2765 454 : GDALDataType eDstTypeComp = GDT_Unknown;
2766 454 : int bufferStrideLastDim = 0;
2767 670 : if (nDims > 0 && mapDstCompsToSrcComps.size() == 1 &&
2768 216 : bufferDataType.GetComponents()[0]->GetType().GetClass() ==
2769 : GEDTC_NUMERIC)
2770 : {
2771 : auto hMemberType =
2772 158 : H5Tget_member_type(hSrcDataType, mapDstCompsToSrcComps[0]);
2773 158 : eSrcTypeComp = HDF5Dataset::GetDataType(hMemberType);
2774 158 : if (eSrcTypeComp != GDT_Unknown)
2775 : {
2776 : nSrcOffset =
2777 145 : H5Tget_member_offset(hSrcDataType, mapDstCompsToSrcComps[0]);
2778 145 : eDstTypeComp = bufferDataType.GetComponents()[0]
2779 145 : ->GetType()
2780 145 : .GetNumericDataType();
2781 290 : bufferStrideLastDim = static_cast<int>(bufferStride[nDims - 1] *
2782 145 : bufferDataType.GetSize());
2783 145 : bFastCopyOfCompoundToSingleComponentCompound = true;
2784 : }
2785 : }
2786 :
2787 296 : lbl_next_depth:
2788 1270 : if (bFastCopyOfCompoundToSingleComponentCompound && iDim == nDims - 1)
2789 : {
2790 285 : GDALCopyWords64(pabySrcBuffer + nSrcOffset, eSrcTypeComp,
2791 : static_cast<int>(nSrcDataTypeSize),
2792 285 : pabyDstBufferStack[iDim], eDstTypeComp,
2793 285 : static_cast<int>(bufferStrideLastDim), count[iDim]);
2794 285 : pabySrcBuffer += count[iDim] * nSrcDataTypeSize;
2795 : }
2796 985 : else if (iDim == nDims)
2797 : {
2798 530 : CopyValue(pabySrcBuffer, hSrcDataType, pabyDstBufferStack[nDims],
2799 : bufferDataType, mapDstCompsToSrcComps);
2800 530 : pabySrcBuffer += nSrcDataTypeSize;
2801 : }
2802 : else
2803 : {
2804 455 : anStackCount[iDim] = count[iDim];
2805 : while (true)
2806 : {
2807 816 : ++iDim;
2808 816 : pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
2809 816 : goto lbl_next_depth;
2810 816 : lbl_return_to_caller_in_loop:
2811 816 : --iDim;
2812 816 : --anStackCount[iDim];
2813 816 : if (anStackCount[iDim] == 0)
2814 455 : break;
2815 361 : pabyDstBufferStack[iDim] +=
2816 361 : bufferStride[iDim] * bufferDataType.GetSize();
2817 : }
2818 : }
2819 1270 : if (iDim > 0)
2820 816 : goto lbl_return_to_caller_in_loop;
2821 454 : }
2822 :
2823 : /************************************************************************/
2824 : /* IRead() */
2825 : /************************************************************************/
2826 :
2827 874 : bool HDF5Array::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
2828 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
2829 : const GDALExtendedDataType &bufferDataType,
2830 : void *pDstBuffer) const
2831 : {
2832 : HDF5_GLOBAL_LOCK();
2833 :
2834 874 : const size_t nDims(m_dims.size());
2835 1748 : std::vector<H5OFFSET_TYPE> anOffset(nDims);
2836 1748 : std::vector<hsize_t> anCount(nDims);
2837 1748 : std::vector<hsize_t> anStep(nDims);
2838 :
2839 874 : size_t nEltCount = 1;
2840 1833 : for (size_t i = 0; i < nDims; ++i)
2841 : {
2842 1049 : if (count[i] != 1 && (arrayStep[i] < 0 || bufferStride[i] < 0))
2843 : {
2844 90 : return ReadSlow(arrayStartIdx, count, arrayStep, bufferStride,
2845 90 : bufferDataType, pDstBuffer);
2846 : }
2847 959 : anOffset[i] = static_cast<hsize_t>(arrayStartIdx[i]);
2848 959 : anCount[i] = static_cast<hsize_t>(count[i]);
2849 959 : anStep[i] = static_cast<hsize_t>(count[i] == 1 ? 1 : arrayStep[i]);
2850 959 : nEltCount *= count[i];
2851 : }
2852 :
2853 784 : if (IsTransposedRequest(count, bufferStride))
2854 : {
2855 255 : return ReadForTransposedRequest(arrayStartIdx, count, arrayStep,
2856 : bufferStride, bufferDataType,
2857 255 : pDstBuffer);
2858 : }
2859 :
2860 529 : bool strideOK = true;
2861 529 : GPtrDiff_t nExpectedBufferStride = 1;
2862 1224 : for (size_t i = nDims; i != 0;)
2863 : {
2864 696 : --i;
2865 696 : if (count[i] != 1 && bufferStride[i] != nExpectedBufferStride)
2866 : {
2867 1 : strideOK = false;
2868 1 : break;
2869 : }
2870 695 : nExpectedBufferStride *= count[i];
2871 : }
2872 :
2873 529 : hid_t hBufferType = H5I_INVALID_HID;
2874 529 : GByte *pabyTemp = nullptr;
2875 529 : bool bUseTmpBuffer = false;
2876 529 : if (m_dt.GetClass() == GEDTC_STRING)
2877 : {
2878 1 : if (bufferDataType.GetClass() != GEDTC_STRING)
2879 : {
2880 0 : return false;
2881 : }
2882 1 : hBufferType = H5Tcopy(m_hNativeDT);
2883 1 : if (!H5Tis_variable_str(m_hNativeDT))
2884 : {
2885 0 : const size_t nStringSize = H5Tget_size(m_hNativeDT);
2886 : pabyTemp = static_cast<GByte *>(
2887 0 : VSI_MALLOC2_VERBOSE(nStringSize, nEltCount));
2888 0 : if (pabyTemp == nullptr)
2889 0 : return false;
2890 : }
2891 : }
2892 587 : else if (strideOK && bufferDataType.GetClass() == GEDTC_NUMERIC &&
2893 60 : m_dt.GetClass() == GEDTC_NUMERIC &&
2894 1110 : !GDALDataTypeIsComplex(m_dt.GetNumericDataType()) &&
2895 55 : !GDALDataTypeIsComplex(bufferDataType.GetNumericDataType()))
2896 : {
2897 : // Compatibility with older libhdf5 that doesn't like requesting
2898 : // an enum to an integer
2899 55 : if (H5Tget_class(m_hNativeDT) == H5T_ENUM)
2900 : {
2901 0 : auto hParent = H5Tget_super(m_hNativeDT);
2902 0 : if (H5Tequal(hParent, H5T_NATIVE_UCHAR) ||
2903 0 : H5Tequal(hParent, H5T_NATIVE_SCHAR) ||
2904 0 : H5Tequal(hParent, H5T_NATIVE_USHORT) ||
2905 0 : H5Tequal(hParent, H5T_NATIVE_SHORT) ||
2906 0 : H5Tequal(hParent, H5T_NATIVE_UINT) ||
2907 0 : H5Tequal(hParent, H5T_NATIVE_INT) ||
2908 0 : H5Tequal(hParent, H5T_NATIVE_UINT64) ||
2909 0 : H5Tequal(hParent, H5T_NATIVE_INT64))
2910 : {
2911 0 : hBufferType = H5Tcopy(m_hNativeDT);
2912 0 : if (m_dt != bufferDataType)
2913 : {
2914 0 : bUseTmpBuffer = true;
2915 : }
2916 : }
2917 0 : H5Tclose(hParent);
2918 : }
2919 55 : if (hBufferType == H5I_INVALID_HID)
2920 : {
2921 55 : hBufferType = GetHDF5DataTypeFromGDALDataType(m_dt, m_hNativeDT,
2922 : bufferDataType);
2923 55 : if (hBufferType == H5I_INVALID_HID)
2924 : {
2925 0 : return false;
2926 : }
2927 : }
2928 : }
2929 473 : else if (strideOK)
2930 : {
2931 472 : hBufferType = H5Tcopy(m_hNativeDT);
2932 472 : if (m_dt != bufferDataType || m_bHasString || m_bHasNonNativeDataType)
2933 : {
2934 453 : bUseTmpBuffer = true;
2935 : }
2936 : }
2937 : else
2938 : {
2939 1 : hBufferType = H5Tcopy(m_hNativeDT);
2940 1 : bUseTmpBuffer = true;
2941 : }
2942 :
2943 529 : if (bUseTmpBuffer)
2944 : {
2945 454 : const size_t nDataTypeSize = H5Tget_size(hBufferType);
2946 : pabyTemp =
2947 454 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nDataTypeSize, nEltCount));
2948 454 : if (pabyTemp == nullptr)
2949 : {
2950 0 : H5Tclose(hBufferType);
2951 0 : return false;
2952 : }
2953 : }
2954 :
2955 : // Select block from file space.
2956 : herr_t status;
2957 529 : if (nDims)
2958 : {
2959 : status =
2960 527 : H5Sselect_hyperslab(m_hDataSpace, H5S_SELECT_SET, anOffset.data(),
2961 527 : anStep.data(), anCount.data(), nullptr);
2962 527 : if (status < 0)
2963 : {
2964 0 : H5Tclose(hBufferType);
2965 0 : VSIFree(pabyTemp);
2966 0 : return false;
2967 : }
2968 : }
2969 :
2970 : // Create memory data space
2971 : const hid_t hMemSpace = nDims == 0
2972 529 : ? H5Screate(H5S_SCALAR)
2973 527 : : H5Screate_simple(static_cast<int>(nDims),
2974 527 : anCount.data(), nullptr);
2975 529 : if (nDims)
2976 : {
2977 527 : std::vector<H5OFFSET_TYPE> anMemOffset(nDims);
2978 : status =
2979 527 : H5Sselect_hyperslab(hMemSpace, H5S_SELECT_SET, anMemOffset.data(),
2980 527 : nullptr, anCount.data(), nullptr);
2981 527 : if (status < 0)
2982 : {
2983 0 : H5Tclose(hBufferType);
2984 0 : H5Sclose(hMemSpace);
2985 0 : VSIFree(pabyTemp);
2986 0 : return false;
2987 : }
2988 : }
2989 :
2990 529 : status = H5Dread(m_hArray, hBufferType, hMemSpace, m_hDataSpace,
2991 : H5P_DEFAULT, pabyTemp ? pabyTemp : pDstBuffer);
2992 :
2993 529 : if (status >= 0)
2994 : {
2995 529 : if (H5Tis_variable_str(hBufferType))
2996 : {
2997 1 : IngestVariableStrings(pDstBuffer, hBufferType, nDims, count,
2998 : bufferStride);
2999 : }
3000 528 : else if (pabyTemp && bufferDataType.GetClass() == GEDTC_STRING)
3001 : {
3002 0 : IngestFixedLengthStrings(pDstBuffer, pabyTemp, hBufferType, nDims,
3003 : count, bufferStride);
3004 : }
3005 528 : else if (pabyTemp)
3006 : {
3007 454 : CopyToFinalBuffer(pDstBuffer, pabyTemp, nDims, count, bufferStride,
3008 454 : m_hNativeDT, bufferDataType);
3009 :
3010 454 : if (m_bHasString)
3011 : {
3012 353 : const size_t nBufferTypeSize = H5Tget_size(hBufferType);
3013 353 : GByte *pabyPtr = pabyTemp;
3014 822 : for (size_t i = 0; i < nEltCount; ++i)
3015 : {
3016 469 : FreeDynamicMemory(pabyPtr, hBufferType);
3017 469 : pabyPtr += nBufferTypeSize;
3018 : }
3019 : }
3020 : }
3021 : }
3022 :
3023 529 : H5Tclose(hBufferType);
3024 529 : H5Sclose(hMemSpace);
3025 529 : VSIFree(pabyTemp);
3026 :
3027 529 : return status >= 0;
3028 : }
3029 :
3030 : /************************************************************************/
3031 : /* ~HDF5Attribute() */
3032 : /************************************************************************/
3033 :
3034 316108 : HDF5Attribute::~HDF5Attribute()
3035 : {
3036 : HDF5_GLOBAL_LOCK();
3037 :
3038 158054 : if (m_hAttribute > 0)
3039 158054 : H5Aclose(m_hAttribute);
3040 158054 : if (m_hNativeDT > 0)
3041 158054 : H5Tclose(m_hNativeDT);
3042 158054 : if (m_hDataSpace > 0)
3043 158054 : H5Sclose(m_hDataSpace);
3044 316108 : }
3045 :
3046 : /************************************************************************/
3047 : /* CopyAllAttrValuesInto() */
3048 : /************************************************************************/
3049 :
3050 9767 : static void CopyAllAttrValuesInto(size_t nDims, const GUInt64 *arrayStartIdx,
3051 : const size_t *count, const GInt64 *arrayStep,
3052 : const GPtrDiff_t *bufferStride,
3053 : const GDALExtendedDataType &bufferDataType,
3054 : void *pDstBuffer, hid_t hSrcBufferType,
3055 : const void *pabySrcBuffer)
3056 : {
3057 9767 : const size_t nBufferDataTypeSize(bufferDataType.GetSize());
3058 9767 : const size_t nSrcDataTypeSize(H5Tget_size(hSrcBufferType));
3059 19534 : std::vector<size_t> anStackCount(nDims);
3060 19534 : std::vector<const GByte *> pabySrcBufferStack(nDims + 1);
3061 19534 : std::vector<GByte *> pabyDstBufferStack(nDims + 1);
3062 : const std::vector<unsigned> mapDstCompsToSrcComps(
3063 9771 : (H5Tget_class(hSrcBufferType) == H5T_COMPOUND &&
3064 4 : bufferDataType.GetClass() == GEDTC_COMPOUND)
3065 9767 : ? CreateMapTargetComponentsToSrc(hSrcBufferType, bufferDataType)
3066 19534 : : std::vector<unsigned>());
3067 :
3068 9767 : pabySrcBufferStack[0] = static_cast<const GByte *>(pabySrcBuffer);
3069 9767 : if (nDims > 0)
3070 25 : pabySrcBufferStack[0] += arrayStartIdx[0] * nSrcDataTypeSize;
3071 9767 : pabyDstBufferStack[0] = static_cast<GByte *>(pDstBuffer);
3072 9767 : size_t iDim = 0;
3073 9818 : lbl_next_depth:
3074 9818 : if (iDim == nDims)
3075 : {
3076 9793 : CopyValue(pabySrcBufferStack[nDims], hSrcBufferType,
3077 9793 : pabyDstBufferStack[nDims], bufferDataType,
3078 : mapDstCompsToSrcComps);
3079 : }
3080 : else
3081 : {
3082 25 : anStackCount[iDim] = count[iDim];
3083 : while (true)
3084 : {
3085 51 : ++iDim;
3086 51 : pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
3087 51 : pabySrcBufferStack[iDim] = pabySrcBufferStack[iDim - 1];
3088 51 : if (iDim < nDims)
3089 : {
3090 0 : pabySrcBufferStack[iDim] +=
3091 0 : arrayStartIdx[iDim] * nSrcDataTypeSize;
3092 : }
3093 51 : goto lbl_next_depth;
3094 51 : lbl_return_to_caller_in_loop:
3095 51 : --iDim;
3096 51 : --anStackCount[iDim];
3097 51 : if (anStackCount[iDim] == 0)
3098 25 : break;
3099 26 : pabyDstBufferStack[iDim] +=
3100 26 : bufferStride[iDim] * nBufferDataTypeSize;
3101 26 : pabySrcBufferStack[iDim] += arrayStep[iDim] * nSrcDataTypeSize;
3102 : }
3103 : }
3104 9818 : if (iDim > 0)
3105 51 : goto lbl_return_to_caller_in_loop;
3106 9767 : }
3107 :
3108 : /************************************************************************/
3109 : /* IRead() */
3110 : /************************************************************************/
3111 :
3112 9767 : bool HDF5Attribute::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
3113 : const GInt64 *arrayStep,
3114 : const GPtrDiff_t *bufferStride,
3115 : const GDALExtendedDataType &bufferDataType,
3116 : void *pDstBuffer) const
3117 : {
3118 : HDF5_GLOBAL_LOCK();
3119 :
3120 9767 : const size_t nDims(m_dims.size());
3121 9767 : if (m_dt.GetClass() == GEDTC_STRING)
3122 : {
3123 1545 : if (bufferDataType.GetClass() != GEDTC_STRING)
3124 : {
3125 0 : return false;
3126 : }
3127 :
3128 1545 : if (!H5Tis_variable_str(m_hNativeDT))
3129 : {
3130 234 : const size_t nStringSize = H5Tget_size(m_hNativeDT);
3131 : GByte *pabyTemp = static_cast<GByte *>(
3132 234 : VSI_CALLOC_VERBOSE(nStringSize, m_nElements));
3133 234 : if (pabyTemp == nullptr)
3134 0 : return false;
3135 468 : if (H5Sget_simple_extent_type(m_hDataSpace) != H5S_NULL &&
3136 234 : H5Aread(m_hAttribute, m_hNativeDT, pabyTemp) < 0)
3137 : {
3138 0 : VSIFree(pabyTemp);
3139 0 : return false;
3140 : }
3141 234 : CopyAllAttrValuesInto(nDims, arrayStartIdx, count, arrayStep,
3142 : bufferStride, bufferDataType, pDstBuffer,
3143 234 : m_hNativeDT, pabyTemp);
3144 234 : VSIFree(pabyTemp);
3145 : }
3146 : else
3147 : {
3148 1311 : void *pabyTemp = VSI_CALLOC_VERBOSE(sizeof(char *), m_nElements);
3149 1311 : if (pabyTemp == nullptr)
3150 0 : return false;
3151 2622 : if (H5Sget_simple_extent_type(m_hDataSpace) != H5S_NULL &&
3152 1311 : H5Aread(m_hAttribute, m_hNativeDT, pabyTemp) < 0)
3153 : {
3154 0 : VSIFree(pabyTemp);
3155 0 : return false;
3156 : }
3157 1311 : CopyAllAttrValuesInto(nDims, arrayStartIdx, count, arrayStep,
3158 : bufferStride, bufferDataType, pDstBuffer,
3159 1311 : m_hNativeDT, pabyTemp);
3160 1311 : H5Dvlen_reclaim(m_hNativeDT, m_hDataSpace, H5P_DEFAULT, pabyTemp);
3161 1311 : VSIFree(pabyTemp);
3162 : }
3163 1545 : return true;
3164 : }
3165 :
3166 8222 : hid_t hBufferType = H5I_INVALID_HID;
3167 16443 : if (m_dt.GetClass() == GEDTC_NUMERIC &&
3168 8221 : bufferDataType.GetClass() == GEDTC_NUMERIC &&
3169 23281 : !GDALDataTypeIsComplex(m_dt.GetNumericDataType()) &&
3170 6838 : !GDALDataTypeIsComplex(bufferDataType.GetNumericDataType()))
3171 : {
3172 : // Compatibility with older libhdf5 that doesn't like requesting
3173 : // an enum to an integer
3174 6838 : if (H5Tget_class(m_hNativeDT) == H5T_ENUM)
3175 : {
3176 804 : auto hParent = H5Tget_super(m_hNativeDT);
3177 804 : if (H5Tequal(hParent, H5T_NATIVE_UCHAR) ||
3178 1 : H5Tequal(hParent, H5T_NATIVE_SCHAR) ||
3179 1 : H5Tequal(hParent, H5T_NATIVE_USHORT) ||
3180 1 : H5Tequal(hParent, H5T_NATIVE_SHORT) ||
3181 1 : H5Tequal(hParent, H5T_NATIVE_UINT) ||
3182 1 : H5Tequal(hParent, H5T_NATIVE_INT) ||
3183 805 : H5Tequal(hParent, H5T_NATIVE_UINT64) ||
3184 0 : H5Tequal(hParent, H5T_NATIVE_INT64))
3185 : {
3186 804 : hBufferType = H5Tcopy(m_hNativeDT);
3187 : }
3188 804 : H5Tclose(hParent);
3189 : }
3190 6838 : if (hBufferType == H5I_INVALID_HID)
3191 : {
3192 6034 : hBufferType = GetHDF5DataTypeFromGDALDataType(m_dt, m_hNativeDT,
3193 : bufferDataType);
3194 : }
3195 : }
3196 : else
3197 : {
3198 1384 : hBufferType = H5Tcopy(m_hNativeDT);
3199 : }
3200 :
3201 8222 : if (hBufferType == H5I_INVALID_HID)
3202 0 : return false;
3203 :
3204 8222 : const size_t nBufferTypeSize(H5Tget_size(hBufferType));
3205 : GByte *pabyTemp =
3206 8222 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBufferTypeSize, m_nElements));
3207 8222 : if (pabyTemp == nullptr)
3208 : {
3209 0 : H5Tclose(hBufferType);
3210 0 : return false;
3211 : }
3212 8222 : if (H5Aread(m_hAttribute, hBufferType, pabyTemp) < 0)
3213 : {
3214 0 : VSIFree(pabyTemp);
3215 0 : return false;
3216 : }
3217 8222 : CopyAllAttrValuesInto(nDims, arrayStartIdx, count, arrayStep, bufferStride,
3218 : bufferDataType, pDstBuffer, hBufferType, pabyTemp);
3219 8222 : if (bufferDataType.GetClass() == GEDTC_COMPOUND && m_bHasString)
3220 : {
3221 0 : GByte *pabyPtr = pabyTemp;
3222 0 : for (size_t i = 0; i < m_nElements; ++i)
3223 : {
3224 0 : FreeDynamicMemory(pabyPtr, hBufferType);
3225 0 : pabyPtr += nBufferTypeSize;
3226 : }
3227 : }
3228 8222 : VSIFree(pabyTemp);
3229 8222 : H5Tclose(hBufferType);
3230 8222 : return true;
3231 : }
3232 :
3233 : /************************************************************************/
3234 : /* GetIndexingVariable() */
3235 : /************************************************************************/
3236 :
3237 14 : std::shared_ptr<GDALMDArray> HDF5Dimension::GetIndexingVariable() const
3238 : {
3239 : HDF5_GLOBAL_LOCK();
3240 :
3241 14 : auto hGroup = H5Gopen(m_poShared->GetHDF5(), m_osGroupFullname.c_str());
3242 14 : if (hGroup >= 0)
3243 : {
3244 14 : auto hArray = H5Dopen(hGroup, GetName().c_str());
3245 14 : H5Gclose(hGroup);
3246 14 : if (hArray >= 0)
3247 : {
3248 28 : auto ar(HDF5Array::Create(m_osGroupFullname, GetName(), m_poShared,
3249 28 : hArray, nullptr, false));
3250 42 : auto attrName = ar->GetAttribute("NAME");
3251 14 : if (attrName && attrName->GetDataType().GetClass() == GEDTC_STRING)
3252 : {
3253 12 : const char *pszName = attrName->ReadAsString();
3254 12 : if (pszName &&
3255 12 : STARTS_WITH(
3256 : pszName,
3257 : "This is a netCDF dimension but not a netCDF variable"))
3258 : {
3259 0 : return nullptr;
3260 : }
3261 : }
3262 14 : return ar;
3263 : }
3264 : }
3265 0 : return nullptr;
3266 : }
3267 :
3268 : } // namespace GDAL
3269 :
3270 : /************************************************************************/
3271 : /* OpenMultiDim() */
3272 : /************************************************************************/
3273 :
3274 33 : GDALDataset *HDF5Dataset::OpenMultiDim(GDALOpenInfo *poOpenInfo)
3275 : {
3276 : HDF5_GLOBAL_LOCK();
3277 :
3278 33 : const char *pszFilename = STARTS_WITH(poOpenInfo->pszFilename, "HDF5:")
3279 8 : ? poOpenInfo->pszFilename + strlen("HDF5:")
3280 : : poOpenInfo->pszFilename;
3281 :
3282 : // Try opening the dataset.
3283 33 : auto hHDF5 = GDAL_HDF5Open(pszFilename);
3284 33 : if (hHDF5 < 0)
3285 : {
3286 1 : return nullptr;
3287 : }
3288 :
3289 96 : auto poSharedResources = GDAL::HDF5SharedResources::Create(pszFilename);
3290 32 : poSharedResources->m_hHDF5 = hHDF5;
3291 :
3292 64 : auto poGroup(OpenGroup(poSharedResources));
3293 32 : if (poGroup == nullptr)
3294 : {
3295 0 : return nullptr;
3296 : }
3297 :
3298 32 : auto poDS(new HDF5Dataset());
3299 32 : poDS->m_poRootGroup = std::move(poGroup);
3300 :
3301 32 : poDS->SetDescription(poOpenInfo->pszFilename);
3302 :
3303 : // Setup/check for pam .aux.xml.
3304 32 : poDS->TryLoadXML();
3305 :
3306 32 : return poDS;
3307 : }
3308 :
3309 : /************************************************************************/
3310 : /* OpenGroup() */
3311 : /************************************************************************/
3312 :
3313 345 : std::shared_ptr<GDALGroup> HDF5Dataset::OpenGroup(
3314 : const std::shared_ptr<GDAL::HDF5SharedResources> &poSharedResources)
3315 : {
3316 : HDF5_GLOBAL_LOCK();
3317 :
3318 690 : auto poGroup = poSharedResources->GetRootGroup();
3319 345 : if (!poGroup)
3320 0 : return nullptr;
3321 :
3322 345 : if (HDF5EOSParser::HasHDFEOS(poGroup->GetID()))
3323 : {
3324 4 : poSharedResources->m_poHDF5EOSParser =
3325 8 : std::make_unique<HDF5EOSParser>();
3326 4 : if (poSharedResources->m_poHDF5EOSParser->Parse(poGroup->GetID()))
3327 : {
3328 4 : CPLDebug("HDF5", "Successfully parsed HDFEOS metadata");
3329 : }
3330 : else
3331 : {
3332 0 : poSharedResources->m_poHDF5EOSParser.reset();
3333 : }
3334 : }
3335 :
3336 345 : return poGroup;
3337 : }
|