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