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