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