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