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