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