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