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