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 757 : 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 757 : : GDALGroup(osParentName, osName), m_poShared(poShared),
61 : m_hGroup(hGroup), m_oSetParentIds(oSetParentIds),
62 757 : m_bIsEOSGridGroup(osParentName == "/HDFEOS/GRIDS"),
63 1514 : m_bIsEOSSwathGroup(osParentName == "/HDFEOS/SWATHS")
64 : {
65 757 : m_oSetParentIds.insert(std::pair(objIds[0], objIds[1]));
66 :
67 : // Force registration of EOS dimensions
68 757 : if (m_bIsEOSGridGroup || m_bIsEOSSwathGroup)
69 : {
70 6 : HDF5Group::GetDimensions();
71 : }
72 757 : }
73 :
74 : public:
75 757 : 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 757 : osParentName, osName, poShared, oSetParentIds, hGroup, objIds));
83 757 : poGroup->SetSelf(poGroup);
84 757 : return poGroup;
85 : }
86 :
87 1514 : ~HDF5Group() override
88 757 : {
89 757 : H5Gclose(m_hGroup);
90 1514 : }
91 :
92 177 : hid_t GetID() const
93 : {
94 177 : 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 29972 : BuildDataType(hid_t hDataType, bool &bHasString, bool &bNonNativeDataType,
143 : const std::vector<std::pair<std::string, hid_t>> &oTypes)
144 : {
145 29972 : const auto klass = H5Tget_class(hDataType);
146 29972 : GDALDataType eDT = ::HDF5Dataset::GetDataType(hDataType);
147 29972 : 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 22245 : return GDALExtendedDataType::Create(eDT);
157 : }
158 7727 : else if (klass == H5T_STRING)
159 : {
160 6520 : bHasString = true;
161 6520 : return GDALExtendedDataType::CreateString();
162 : }
163 1207 : else if (klass == H5T_COMPOUND)
164 : {
165 800 : const unsigned nMembers = H5Tget_nmembers(hDataType);
166 1600 : std::vector<std::unique_ptr<GDALEDTComponent>> components;
167 800 : size_t nOffset = 0;
168 3669 : for (unsigned i = 0; i < nMembers; i++)
169 : {
170 3081 : char *pszName = H5Tget_member_name(hDataType, i);
171 3081 : if (!pszName)
172 212 : return GDALExtendedDataType::Create(GDT_Unknown);
173 3081 : CPLString osCompName(pszName);
174 3081 : H5free_memory(pszName);
175 3081 : const auto hMemberType = H5Tget_member_type(hDataType, i);
176 3081 : if (hMemberType < 0)
177 0 : return GDALExtendedDataType::Create(GDT_Unknown);
178 : const hid_t hNativeMemberType =
179 3081 : H5Tget_native_type(hMemberType, H5T_DIR_ASCEND);
180 : auto memberDT = BuildDataType(hNativeMemberType, bHasString,
181 3081 : bNonNativeDataType, oTypes);
182 3081 : H5Tclose(hNativeMemberType);
183 3081 : H5Tclose(hMemberType);
184 5436 : if (memberDT.GetClass() == GEDTC_NUMERIC &&
185 2355 : memberDT.GetNumericDataType() == GDT_Unknown)
186 212 : return GDALExtendedDataType::Create(GDT_Unknown);
187 2869 : if ((nOffset % memberDT.GetSize()) != 0)
188 218 : nOffset += memberDT.GetSize() - (nOffset % memberDT.GetSize());
189 2869 : if (nOffset != H5Tget_member_offset(hDataType, i))
190 523 : bNonNativeDataType = true;
191 5738 : components.emplace_back(std::unique_ptr<GDALEDTComponent>(
192 5738 : new GDALEDTComponent(osCompName, nOffset, memberDT)));
193 2869 : nOffset += memberDT.GetSize();
194 : }
195 1176 : if (!components.empty() &&
196 588 : (nOffset % components[0]->GetType().GetSize()) != 0)
197 82 : nOffset += components[0]->GetType().GetSize() -
198 82 : (nOffset % components[0]->GetType().GetSize());
199 588 : if (nOffset != H5Tget_size(hDataType))
200 81 : bNonNativeDataType = true;
201 1176 : std::string osName("unnamed");
202 786 : 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 588 : 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 413 : GetDataTypesInGroup(hid_t hHDF5, const std::string &osGroupFullName,
239 : std::vector<std::pair<std::string, hid_t>> &oTypes)
240 : {
241 : struct Callback
242 : {
243 8828 : static herr_t f(hid_t hGroup, const char *pszObjName, void *user_data)
244 : {
245 8828 : auto *poTypes =
246 : static_cast<std::vector<std::pair<std::string, hid_t>> *>(
247 : user_data);
248 : H5G_stat_t oStatbuf;
249 :
250 8828 : if (H5Gget_objinfo(hGroup, pszObjName, FALSE, &oStatbuf) < 0)
251 0 : return -1;
252 :
253 8828 : if (oStatbuf.type == H5G_TYPE)
254 : {
255 1746 : poTypes->push_back(
256 3492 : std::pair(pszObjName, H5Topen(hGroup, pszObjName)));
257 : }
258 :
259 8828 : return 0;
260 : }
261 : };
262 :
263 413 : H5Giterate(hHDF5, osGroupFullName.c_str(), nullptr, &(Callback::f),
264 : &oTypes);
265 413 : }
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 1214 : 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 2428 : bSkipFullDimensionInstantiation)));
328 1791 : if (ar->m_dt.GetClass() == GEDTC_NUMERIC &&
329 577 : ar->m_dt.GetNumericDataType() == GDT_Unknown)
330 : {
331 0 : return nullptr;
332 : }
333 1214 : ar->SetSelf(ar);
334 1214 : return ar;
335 : }
336 :
337 58 : bool IsWritable() const override
338 : {
339 58 : return !m_poShared->IsReadOnly();
340 : }
341 :
342 552 : const std::string &GetFilename() const override
343 : {
344 552 : return m_poShared->GetFilename();
345 : }
346 :
347 : const std::vector<std::shared_ptr<GDALDimension>> &
348 1821 : GetDimensions() const override
349 : {
350 1821 : return m_dims;
351 : }
352 :
353 1274 : const GDALExtendedDataType &GetDataType() const override
354 : {
355 1274 : 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 80 : const void *GetRawNoDataValue() const override
369 : {
370 80 : 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 34 : std::shared_ptr<GDALGroup> GetRootGroup() const override
392 : {
393 34 : 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 25637 : 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 25637 : : GDALAbstractMDArray(osParentName, osName),
418 : GDALAttribute(osParentName, osName), m_poShared(poShared),
419 25637 : m_hAttribute(hAttribute), m_hDataSpace(H5Aget_space(hAttribute))
420 : {
421 25637 : const int nDims = H5Sget_simple_extent_ndims(m_hDataSpace);
422 51274 : std::vector<hsize_t> anDimSizes(nDims);
423 25637 : 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 25637 : const hid_t hDataType = H5Aget_type(hAttribute);
441 25637 : m_hNativeDT = H5Tget_native_type(hDataType, H5T_DIR_ASCEND);
442 25637 : H5Tclose(hDataType);
443 :
444 51274 : std::vector<std::pair<std::string, hid_t>> oTypes;
445 48277 : if (!osGroupFullName.empty() &&
446 22640 : H5Tget_class(m_hNativeDT) == H5T_COMPOUND)
447 : {
448 202 : GetDataTypesInGroup(m_poShared->GetHDF5(), osGroupFullName, oTypes);
449 : }
450 :
451 51274 : m_dt = BuildDataType(m_hNativeDT, m_bHasString, m_bHasNonNativeDataType,
452 25637 : oTypes);
453 27059 : for (auto &oPair : oTypes)
454 1422 : H5Tclose(oPair.second);
455 45529 : if (m_dt.GetClass() == GEDTC_NUMERIC &&
456 19892 : 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 25637 : }
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 25637 : 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 51274 : osGroupFullName, osParentName, osName, poShared, hAttribute)));
483 45529 : if (ar->m_dt.GetClass() == GEDTC_NUMERIC &&
484 19892 : ar->m_dt.GetNumericDataType() == GDT_Unknown)
485 : {
486 367 : return nullptr;
487 : }
488 25270 : return ar;
489 : }
490 :
491 : const std::vector<std::shared_ptr<GDALDimension>> &
492 3931 : GetDimensions() const override
493 : {
494 3931 : return m_dims;
495 : }
496 :
497 3361 : const GDALExtendedDataType &GetDataType() const override
498 : {
499 3361 : return m_dt;
500 : }
501 : };
502 :
503 : /************************************************************************/
504 : /* HDF5SharedResources() */
505 : /************************************************************************/
506 :
507 173 : HDF5SharedResources::HDF5SharedResources(const std::string &osFilename)
508 : : m_osFilename(osFilename),
509 173 : m_poPAM(std::make_shared<GDALPamMultiDim>(osFilename))
510 : {
511 173 : }
512 :
513 : /************************************************************************/
514 : /* ~HDF5SharedResources() */
515 : /************************************************************************/
516 :
517 173 : HDF5SharedResources::~HDF5SharedResources()
518 : {
519 : HDF5_GLOBAL_LOCK();
520 :
521 173 : if (m_hHDF5 > 0)
522 173 : H5Fclose(m_hHDF5);
523 173 : }
524 :
525 : /************************************************************************/
526 : /* Create() */
527 : /************************************************************************/
528 :
529 : std::shared_ptr<HDF5SharedResources>
530 173 : HDF5SharedResources::Create(const std::string &osFilename)
531 : {
532 : auto poSharedResources = std::shared_ptr<HDF5SharedResources>(
533 173 : new HDF5SharedResources(osFilename));
534 173 : poSharedResources->m_poSelf = poSharedResources;
535 173 : return poSharedResources;
536 : }
537 :
538 : /************************************************************************/
539 : /* GetRootGroup() */
540 : /************************************************************************/
541 :
542 238 : std::shared_ptr<HDF5Group> HDF5SharedResources::GetRootGroup()
543 : {
544 :
545 : H5G_stat_t oStatbuf;
546 238 : if (H5Gget_objinfo(m_hHDF5, "/", FALSE, &oStatbuf) < 0)
547 : {
548 0 : return nullptr;
549 : }
550 238 : auto hGroup = H5Gopen(m_hHDF5, "/");
551 238 : if (hGroup < 0)
552 : {
553 0 : return nullptr;
554 : }
555 :
556 238 : auto poSharedResources = m_poSelf.lock();
557 238 : CPLAssert(poSharedResources != nullptr);
558 476 : return HDF5Group::Create(std::string(), "/", poSharedResources, {}, hGroup,
559 714 : 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 1430 : herr_t HDF5Group::GetGroupNamesCallback(hid_t hGroup, const char *pszObjName,
838 : void *selfIn)
839 : {
840 1430 : HDF5Group *self = static_cast<HDF5Group *>(selfIn);
841 : H5G_stat_t oStatbuf;
842 :
843 1430 : if (H5Gget_objinfo(hGroup, pszObjName, FALSE, &oStatbuf) < 0)
844 0 : return -1;
845 :
846 1430 : if (oStatbuf.type == H5G_GROUP)
847 : {
848 624 : if (self->m_oSetParentIds.find(
849 624 : std::pair(oStatbuf.objno[0], oStatbuf.objno[1])) ==
850 1248 : self->m_oSetParentIds.end())
851 : {
852 624 : 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 1430 : return 0;
863 : }
864 :
865 : /************************************************************************/
866 : /* GetGroupNames() */
867 : /************************************************************************/
868 :
869 514 : std::vector<std::string> HDF5Group::GetGroupNames(CSLConstList) const
870 : {
871 : HDF5_GLOBAL_LOCK();
872 :
873 514 : m_osListSubGroups.clear();
874 514 : H5Giterate(m_poShared->GetHDF5(), GetFullName().c_str(), nullptr,
875 : GetGroupNamesCallback,
876 : const_cast<void *>(static_cast<const void *>(this)));
877 514 : return m_osListSubGroups;
878 : }
879 :
880 : /************************************************************************/
881 : /* OpenGroup() */
882 : /************************************************************************/
883 :
884 649 : std::shared_ptr<GDALGroup> HDF5Group::OpenGroup(const std::string &osName,
885 : CSLConstList) const
886 : {
887 : HDF5_GLOBAL_LOCK();
888 :
889 649 : if (m_osListSubGroups.empty())
890 473 : GetGroupNames(nullptr);
891 649 : if (std::find(m_osListSubGroups.begin(), m_osListSubGroups.end(), osName) ==
892 1298 : m_osListSubGroups.end())
893 : {
894 130 : return nullptr;
895 : }
896 :
897 : H5G_stat_t oStatbuf;
898 519 : if (H5Gget_objinfo(m_hGroup, osName.c_str(), FALSE, &oStatbuf) < 0)
899 0 : return nullptr;
900 :
901 519 : auto hSubGroup = H5Gopen(m_hGroup, osName.c_str());
902 519 : if (hSubGroup < 0)
903 : {
904 0 : return nullptr;
905 : }
906 1038 : return HDF5Group::Create(GetFullName(), osName, m_poShared, m_oSetParentIds,
907 519 : hSubGroup, oStatbuf.objno);
908 : }
909 :
910 : /************************************************************************/
911 : /* GetArrayNamesCallback() */
912 : /************************************************************************/
913 :
914 850 : herr_t HDF5Group::GetArrayNamesCallback(hid_t hGroup, const char *pszObjName,
915 : void *selfIn)
916 : {
917 850 : HDF5Group *self = static_cast<HDF5Group *>(selfIn);
918 : H5G_stat_t oStatbuf;
919 :
920 850 : if (H5Gget_objinfo(hGroup, pszObjName, FALSE, &oStatbuf) < 0)
921 0 : return -1;
922 :
923 850 : if (oStatbuf.type == H5G_DATASET)
924 : {
925 767 : auto hArray = H5Dopen(hGroup, pszObjName);
926 767 : if (hArray >= 0)
927 : {
928 1534 : auto ar(HDF5Array::Create(std::string(), pszObjName,
929 2301 : self->m_poShared, hArray, self, true));
930 767 : if (ar)
931 : {
932 1534 : auto attrNAME = ar->GetAttribute("NAME");
933 816 : 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 739 : self->m_osListArrays.push_back(pszObjName);
947 : }
948 822 : return 0;
949 : }
950 :
951 : /************************************************************************/
952 : /* GetMDArrayNames() */
953 : /************************************************************************/
954 :
955 192 : std::vector<std::string> HDF5Group::GetMDArrayNames(CSLConstList) const
956 : {
957 : HDF5_GLOBAL_LOCK();
958 :
959 192 : m_osListArrays.clear();
960 192 : H5Giterate(m_poShared->GetHDF5(), GetFullName().c_str(), nullptr,
961 : GetArrayNamesCallback,
962 : const_cast<void *>(static_cast<const void *>(this)));
963 :
964 192 : if (m_poXIndexingArray)
965 0 : m_osListArrays.push_back(m_poXIndexingArray->GetName());
966 192 : if (m_poYIndexingArray)
967 0 : m_osListArrays.push_back(m_poYIndexingArray->GetName());
968 :
969 192 : return m_osListArrays;
970 : }
971 :
972 : /************************************************************************/
973 : /* OpenMDArray() */
974 : /************************************************************************/
975 :
976 265 : std::shared_ptr<GDALMDArray> HDF5Group::OpenMDArray(const std::string &osName,
977 : CSLConstList) const
978 : {
979 : HDF5_GLOBAL_LOCK();
980 :
981 265 : if (m_osListArrays.empty())
982 158 : GetMDArrayNames(nullptr);
983 265 : if (std::find(m_osListArrays.begin(), m_osListArrays.end(), osName) ==
984 530 : m_osListArrays.end())
985 : {
986 12 : return nullptr;
987 : }
988 253 : if (m_poXIndexingArray && m_poXIndexingArray->GetName() == osName)
989 0 : return m_poXIndexingArray;
990 253 : if (m_poYIndexingArray && m_poYIndexingArray->GetName() == osName)
991 0 : return m_poYIndexingArray;
992 :
993 253 : auto hArray = H5Dopen(m_hGroup, osName.c_str());
994 253 : if (hArray < 0)
995 : {
996 0 : return nullptr;
997 : }
998 506 : return HDF5Array::Create(GetFullName(), osName, m_poShared, hArray, this,
999 253 : false);
1000 : }
1001 :
1002 : /************************************************************************/
1003 : /* GetAttributesCallback() */
1004 : /************************************************************************/
1005 :
1006 21633 : herr_t HDF5Group::GetAttributesCallback(hid_t hGroup, const char *pszObjName,
1007 : void *selfIn)
1008 : {
1009 21633 : HDF5Group *self = static_cast<HDF5Group *>(selfIn);
1010 21633 : if (self->m_bShowAllAttributes || (!EQUAL(pszObjName, "_Netcdf4Dimid") &&
1011 21633 : !EQUAL(pszObjName, "_NCProperties")))
1012 : {
1013 21632 : hid_t hAttr = H5Aopen_name(hGroup, pszObjName);
1014 21632 : if (hAttr > 0)
1015 : {
1016 : auto attr(HDF5Attribute::Create(self->GetFullName(),
1017 : self->GetFullName(), pszObjName,
1018 64896 : self->m_poShared, hAttr));
1019 21632 : if (attr)
1020 : {
1021 21632 : self->m_oListAttributes.emplace_back(attr);
1022 : }
1023 : }
1024 : }
1025 21633 : return 0;
1026 : }
1027 :
1028 : /************************************************************************/
1029 : /* GetAttributes() */
1030 : /************************************************************************/
1031 :
1032 : std::vector<std::shared_ptr<GDALAttribute>>
1033 2156 : HDF5Group::GetAttributes(CSLConstList papszOptions) const
1034 : {
1035 : HDF5_GLOBAL_LOCK();
1036 :
1037 2156 : m_oListAttributes.clear();
1038 2156 : m_bShowAllAttributes =
1039 2156 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SHOW_ALL", "NO"));
1040 2156 : H5Aiterate(m_hGroup, nullptr, GetAttributesCallback,
1041 : const_cast<void *>(static_cast<const void *>(this)));
1042 2156 : return m_oListAttributes;
1043 : }
1044 :
1045 : /************************************************************************/
1046 : /* ~HDF5Array() */
1047 : /************************************************************************/
1048 :
1049 2428 : HDF5Array::~HDF5Array()
1050 : {
1051 : HDF5_GLOBAL_LOCK();
1052 :
1053 1214 : if (m_hArray > 0)
1054 1214 : H5Dclose(m_hArray);
1055 1214 : if (m_hNativeDT > 0)
1056 1214 : H5Tclose(m_hNativeDT);
1057 1214 : if (m_hDataSpace > 0)
1058 1214 : H5Sclose(m_hDataSpace);
1059 2428 : }
1060 :
1061 : /************************************************************************/
1062 : /* HDF5Array() */
1063 : /************************************************************************/
1064 :
1065 1214 : 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 1214 : bool bSkipFullDimensionInstantiation)
1069 : : GDALAbstractMDArray(osParentName, osName),
1070 : GDALMDArray(osParentName, osName), m_osGroupFullname(osParentName),
1071 : m_poShared(poShared), m_hArray(hArray),
1072 1214 : m_hDataSpace(H5Dget_space(hArray)), m_nOffset(H5Dget_offset(hArray))
1073 : {
1074 1214 : const hid_t hDataType = H5Dget_type(hArray);
1075 1214 : m_hNativeDT = H5Tget_native_type(hDataType, H5T_DIR_ASCEND);
1076 1214 : H5Tclose(hDataType);
1077 :
1078 1214 : std::vector<std::pair<std::string, hid_t>> oTypes;
1079 1214 : if (!osParentName.empty() && H5Tget_class(m_hNativeDT) == H5T_COMPOUND)
1080 : {
1081 211 : GetDataTypesInGroup(m_poShared->GetHDF5(), osParentName, oTypes);
1082 : }
1083 :
1084 2428 : m_dt = BuildDataType(m_hNativeDT, m_bHasString, m_bHasNonNativeDataType,
1085 1214 : oTypes);
1086 1538 : for (auto &oPair : oTypes)
1087 324 : H5Tclose(oPair.second);
1088 :
1089 1791 : if (m_dt.GetClass() == GEDTC_NUMERIC &&
1090 577 : 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 1214 : HDF5Array::GetAttributes();
1098 :
1099 : // Special case for S102 nodata value that is typically at 1e6
1100 1214 : if (GetFullName() ==
1101 20 : "/BathymetryCoverage/BathymetryCoverage.01/Group_001/values" &&
1102 40 : m_dt.GetClass() == GEDTC_COMPOUND &&
1103 38 : (m_dt.GetComponents().size() == 1 ||
1104 18 : m_dt.GetComponents().size() == 2) &&
1105 40 : m_dt.GetSize() == m_dt.GetComponents().size() * sizeof(float) &&
1106 20 : m_dt.GetComponents()[0]->GetType().GetNumericDataType() ==
1107 1252 : GDT_Float32 &&
1108 38 : (m_dt.GetComponents().size() == 1 ||
1109 18 : m_dt.GetComponents()[1]->GetType().GetNumericDataType() ==
1110 : GDT_Float32))
1111 : {
1112 20 : m_abyNoData.resize(m_dt.GetSize());
1113 20 : float afNoData[2] = {1e6f, 1e6f};
1114 :
1115 40 : if (auto poRootGroup = HDF5Array::GetRootGroup())
1116 : {
1117 60 : if (const auto poGroupF = poRootGroup->OpenGroup("Group_F"))
1118 : {
1119 : const auto poGroupFArray =
1120 60 : poGroupF->OpenMDArray("BathymetryCoverage");
1121 20 : if (poGroupFArray &&
1122 60 : poGroupFArray->GetDataType().GetClass() == GEDTC_COMPOUND &&
1123 40 : poGroupFArray->GetDataType().GetComponents().size() == 8 &&
1124 20 : poGroupFArray->GetDataType()
1125 20 : .GetComponents()[0]
1126 40 : ->GetName() == "code" &&
1127 20 : poGroupFArray->GetDataType()
1128 20 : .GetComponents()[3]
1129 20 : ->GetName() == "fillValue" &&
1130 60 : poGroupFArray->GetDimensionCount() == 1 &&
1131 20 : poGroupFArray->GetDimensions()[0]->GetSize() ==
1132 20 : m_dt.GetComponents().size())
1133 : {
1134 : auto poFillValue =
1135 60 : poGroupFArray->GetView("[\"fillValue\"]");
1136 20 : if (poFillValue)
1137 : {
1138 20 : char *pszVal0 = nullptr;
1139 20 : char *pszVal1 = nullptr;
1140 20 : const GUInt64 anArrayStartIdx0[] = {0};
1141 20 : const GUInt64 anArrayStartIdx1[] = {1};
1142 20 : const size_t anCount[] = {1};
1143 20 : const GInt64 anArrayStep[] = {0};
1144 20 : const GPtrDiff_t anBufferStride[] = {0};
1145 40 : poFillValue->Read(anArrayStartIdx0, anCount,
1146 : anArrayStep, anBufferStride,
1147 40 : GDALExtendedDataType::CreateString(),
1148 : &pszVal0);
1149 20 : if (poGroupFArray->GetDimensions()[0]->GetSize() == 2)
1150 : {
1151 36 : poFillValue->Read(
1152 : anArrayStartIdx1, anCount, anArrayStep,
1153 : anBufferStride,
1154 36 : GDALExtendedDataType::CreateString(), &pszVal1);
1155 : }
1156 20 : if (pszVal0)
1157 : {
1158 20 : afNoData[0] = static_cast<float>(CPLAtof(pszVal0));
1159 20 : if (pszVal1)
1160 : {
1161 18 : afNoData[1] =
1162 18 : static_cast<float>(CPLAtof(pszVal1));
1163 : }
1164 : }
1165 20 : CPLFree(pszVal0);
1166 20 : CPLFree(pszVal1);
1167 : }
1168 : }
1169 : }
1170 : }
1171 :
1172 20 : m_abyNoData.resize(m_dt.GetSize());
1173 20 : 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 1214 : (GetFullName() ==
1179 : "/QualityOfSurvey/QualityOfSurvey.01/Group_001/values");
1180 : const bool bIsQualityOfBathymetryCoverage =
1181 1214 : (GetFullName() == "/QualityOfBathymetryCoverage/"
1182 : "QualityOfBathymetryCoverage.01/Group_001/values");
1183 1226 : if ((bIsQualityOfSurvey || bIsQualityOfBathymetryCoverage) &&
1184 10 : ((m_dt.GetClass() == GEDTC_NUMERIC &&
1185 6 : 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 12 : if (auto poRootGroup = HDF5Array::GetRootGroup())
1193 : {
1194 18 : if (const auto poGroupF = poRootGroup->OpenGroup("Group_F"))
1195 : {
1196 6 : const auto poGroupFArray = poGroupF->OpenMDArray(
1197 : bIsQualityOfSurvey ? "QualityOfSurvey"
1198 18 : : "QualityOfBathymetryCoverage");
1199 6 : if (poGroupFArray &&
1200 18 : poGroupFArray->GetDataType().GetClass() == GEDTC_COMPOUND &&
1201 12 : poGroupFArray->GetDataType().GetComponents().size() == 8 &&
1202 6 : poGroupFArray->GetDataType()
1203 6 : .GetComponents()[0]
1204 12 : ->GetName() == "code" &&
1205 6 : poGroupFArray->GetDataType()
1206 6 : .GetComponents()[3]
1207 6 : ->GetName() == "fillValue" &&
1208 18 : poGroupFArray->GetDimensionCount() == 1 &&
1209 6 : poGroupFArray->GetDimensions()[0]->GetSize() == 1)
1210 : {
1211 : auto poFillValue =
1212 18 : poGroupFArray->GetView("[\"fillValue\"]");
1213 6 : if (poFillValue)
1214 : {
1215 6 : char *pszVal0 = nullptr;
1216 6 : const GUInt64 anArrayStartIdx0[] = {0};
1217 6 : const size_t anCount[] = {1};
1218 6 : const GInt64 anArrayStep[] = {0};
1219 6 : const GPtrDiff_t anBufferStride[] = {0};
1220 12 : poFillValue->Read(anArrayStartIdx0, anCount,
1221 : anArrayStep, anBufferStride,
1222 12 : GDALExtendedDataType::CreateString(),
1223 : &pszVal0);
1224 6 : if (pszVal0)
1225 : {
1226 6 : const uint32_t nNoData = atoi(pszVal0);
1227 6 : m_abyNoData.resize(m_dt.GetSize());
1228 6 : memcpy(m_abyNoData.data(), &nNoData,
1229 : m_abyNoData.size());
1230 : }
1231 6 : CPLFree(pszVal0);
1232 : }
1233 : }
1234 : }
1235 : }
1236 : }
1237 :
1238 : // Special case for S104 nodata value that is typically -9999
1239 1218 : if (STARTS_WITH(GetFullName().c_str(), "/WaterLevel/WaterLevel.01/") &&
1240 8 : GetFullName().find("/values") != std::string::npos &&
1241 12 : m_dt.GetClass() == GEDTC_COMPOUND && m_dt.GetSize() == 8 &&
1242 8 : m_dt.GetComponents().size() == 2 &&
1243 4 : m_dt.GetComponents()[0]->GetType().GetNumericDataType() ==
1244 1218 : GDT_Float32 &&
1245 : // In theory should be Byte, but 104US00_ches_dcf2_20190606T12Z.h5 uses Int32
1246 4 : (m_dt.GetComponents()[1]->GetType().GetNumericDataType() == GDT_Byte ||
1247 0 : m_dt.GetComponents()[1]->GetType().GetNumericDataType() == GDT_Int32))
1248 : {
1249 4 : m_abyNoData.resize(m_dt.GetSize());
1250 4 : float fNoData = -9999.0f;
1251 :
1252 8 : if (auto poRootGroup = HDF5Array::GetRootGroup())
1253 : {
1254 12 : if (const auto poGroupF = poRootGroup->OpenGroup("Group_F"))
1255 : {
1256 12 : const auto poGroupFArray = poGroupF->OpenMDArray("WaterLevel");
1257 4 : if (poGroupFArray &&
1258 12 : poGroupFArray->GetDataType().GetClass() == GEDTC_COMPOUND &&
1259 8 : poGroupFArray->GetDataType().GetComponents().size() == 8 &&
1260 4 : poGroupFArray->GetDataType()
1261 4 : .GetComponents()[0]
1262 8 : ->GetName() == "code" &&
1263 4 : poGroupFArray->GetDataType()
1264 4 : .GetComponents()[3]
1265 4 : ->GetName() == "fillValue" &&
1266 12 : poGroupFArray->GetDimensionCount() == 1 &&
1267 4 : poGroupFArray->GetDimensions()[0]->GetSize() >= 2)
1268 : {
1269 : auto poFillValue =
1270 12 : poGroupFArray->GetView("[\"fillValue\"]");
1271 4 : if (poFillValue)
1272 : {
1273 4 : char *pszVal0 = nullptr;
1274 4 : const GUInt64 anArrayStartIdx0[] = {0};
1275 4 : const size_t anCount[] = {1};
1276 4 : const GInt64 anArrayStep[] = {0};
1277 4 : const GPtrDiff_t anBufferStride[] = {0};
1278 8 : poFillValue->Read(anArrayStartIdx0, anCount,
1279 : anArrayStep, anBufferStride,
1280 8 : GDALExtendedDataType::CreateString(),
1281 : &pszVal0);
1282 4 : if (pszVal0)
1283 : {
1284 4 : fNoData = static_cast<float>(CPLAtof(pszVal0));
1285 : }
1286 4 : CPLFree(pszVal0);
1287 : }
1288 : }
1289 : }
1290 : }
1291 :
1292 4 : memcpy(m_abyNoData.data(), &fNoData, sizeof(float));
1293 : }
1294 :
1295 : // Special case for S111 nodata value that is typically -9999
1296 1214 : if (STARTS_WITH(GetFullName().c_str(),
1297 5 : "/SurfaceCurrent/SurfaceCurrent.01/") &&
1298 9 : GetFullName().find("/values") != std::string::npos &&
1299 8 : m_dt.GetClass() == GEDTC_COMPOUND &&
1300 8 : m_dt.GetSize() == 2 * sizeof(float) &&
1301 8 : m_dt.GetComponents().size() == 2 &&
1302 4 : m_dt.GetComponents()[0]->GetType().GetNumericDataType() ==
1303 1219 : GDT_Float32 &&
1304 4 : m_dt.GetComponents()[1]->GetType().GetNumericDataType() == GDT_Float32)
1305 : {
1306 4 : float afNoData[2] = {-9999.0f, -9999.0f};
1307 :
1308 8 : if (auto poRootGroup = HDF5Array::GetRootGroup())
1309 : {
1310 12 : if (const auto poGroupF = poRootGroup->OpenGroup("Group_F"))
1311 : {
1312 : const auto poGroupFArray =
1313 12 : poGroupF->OpenMDArray("SurfaceCurrent");
1314 4 : if (poGroupFArray &&
1315 12 : poGroupFArray->GetDataType().GetClass() == GEDTC_COMPOUND &&
1316 8 : poGroupFArray->GetDataType().GetComponents().size() == 8 &&
1317 4 : poGroupFArray->GetDataType()
1318 4 : .GetComponents()[0]
1319 8 : ->GetName() == "code" &&
1320 4 : poGroupFArray->GetDataType()
1321 4 : .GetComponents()[3]
1322 4 : ->GetName() == "fillValue" &&
1323 12 : poGroupFArray->GetDimensionCount() == 1 &&
1324 4 : poGroupFArray->GetDimensions()[0]->GetSize() >= 2)
1325 : {
1326 : auto poFillValue =
1327 12 : poGroupFArray->GetView("[\"fillValue\"]");
1328 4 : if (poFillValue)
1329 : {
1330 4 : char *pszVal0 = nullptr;
1331 4 : char *pszVal1 = nullptr;
1332 4 : const GUInt64 anArrayStartIdx0[] = {0};
1333 4 : const GUInt64 anArrayStartIdx1[] = {1};
1334 4 : const size_t anCount[] = {1};
1335 4 : const GInt64 anArrayStep[] = {0};
1336 4 : const GPtrDiff_t anBufferStride[] = {0};
1337 8 : poFillValue->Read(anArrayStartIdx0, anCount,
1338 : anArrayStep, anBufferStride,
1339 8 : GDALExtendedDataType::CreateString(),
1340 : &pszVal0);
1341 8 : poFillValue->Read(anArrayStartIdx1, anCount,
1342 : anArrayStep, anBufferStride,
1343 8 : GDALExtendedDataType::CreateString(),
1344 : &pszVal1);
1345 4 : if (pszVal0 && pszVal1)
1346 : {
1347 4 : afNoData[0] = static_cast<float>(CPLAtof(pszVal0));
1348 4 : afNoData[1] = static_cast<float>(CPLAtof(pszVal1));
1349 : }
1350 4 : CPLFree(pszVal0);
1351 4 : CPLFree(pszVal1);
1352 : }
1353 : }
1354 : }
1355 : }
1356 :
1357 4 : m_abyNoData.resize(m_dt.GetSize());
1358 4 : memcpy(m_abyNoData.data(), afNoData, m_abyNoData.size());
1359 : }
1360 :
1361 1214 : if (bSkipFullDimensionInstantiation)
1362 : {
1363 947 : const int nDims = H5Sget_simple_extent_ndims(m_hDataSpace);
1364 1894 : std::vector<hsize_t> anDimSizes(nDims);
1365 947 : if (nDims)
1366 : {
1367 934 : H5Sget_simple_extent_dims(m_hDataSpace, &anDimSizes[0], nullptr);
1368 2492 : for (int i = 0; i < nDims; ++i)
1369 : {
1370 3116 : m_dims.emplace_back(std::make_shared<GDALDimension>(
1371 3116 : std::string(), CPLSPrintf("dim%d", i), std::string(),
1372 4674 : std::string(), anDimSizes[i]));
1373 : }
1374 : }
1375 : }
1376 : else
1377 : {
1378 267 : InstantiateDimensions(osParentName, poGroup);
1379 : }
1380 : }
1381 :
1382 : /************************************************************************/
1383 : /* InstantiateDimensions() */
1384 : /************************************************************************/
1385 :
1386 267 : void HDF5Array::InstantiateDimensions(const std::string &osParentName,
1387 : const HDF5Group *poGroup)
1388 : {
1389 267 : const int nDims = H5Sget_simple_extent_ndims(m_hDataSpace);
1390 267 : std::vector<hsize_t> anDimSizes(nDims);
1391 267 : if (nDims)
1392 : {
1393 266 : H5Sget_simple_extent_dims(m_hDataSpace, &anDimSizes[0], nullptr);
1394 : }
1395 :
1396 267 : if (nDims == 1)
1397 : {
1398 336 : auto attrCLASS = GetAttribute("CLASS");
1399 184 : 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 251 : std::map<size_t, std::string> mapDimIndexToDimFullName;
1430 :
1431 251 : 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 223 : 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 221 : HDF5EOSParser::GridDataFieldMetadata oGridDataFieldMetadata;
1503 221 : HDF5EOSParser::SwathDataFieldMetadata oSwathDataFieldMetadata;
1504 : HDF5EOSParser::SwathGeolocationFieldMetadata
1505 221 : oSwathGeolocationFieldMetadata;
1506 221 : const auto poHDF5EOSParser = m_poShared->GetHDF5EOSParser();
1507 : // Build a "classic" subdataset name from group and array names
1508 : const std::string osSubdatasetName(
1509 221 : "/" +
1510 221 : CPLString(osParentName)
1511 442 : .replaceAll("Data Fields", "Data_Fields")
1512 663 : .replaceAll("Geolocation Fields", "Geolocation_Fields") +
1513 442 : "/" + GetName());
1514 227 : if (poHDF5EOSParser &&
1515 6 : poHDF5EOSParser->GetGridDataFieldMetadata(osSubdatasetName.c_str(),
1516 227 : 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 221 : else if (poHDF5EOSParser &&
1561 3 : poHDF5EOSParser->GetSwathDataFieldMetadata(
1562 221 : 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 219 : else if (poHDF5EOSParser &&
1585 2 : poHDF5EOSParser->GetSwathGeolocationFieldMetadata(
1586 : osSubdatasetName.c_str(),
1587 219 : 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 30 : const auto SpecialCaseS100 = [&](const std::string &osCoverageName)
1611 : {
1612 60 : auto poRootGroup = m_poShared->GetRootGroup();
1613 30 : if (poRootGroup)
1614 : {
1615 30 : m_poSRS = std::make_shared<OGRSpatialReference>();
1616 30 : if (S100ReadSRS(poRootGroup.get(), *(m_poSRS.get())))
1617 : {
1618 30 : if (m_poSRS->GetDataAxisToSRSAxisMapping() ==
1619 60 : std::vector<int>{2, 1})
1620 30 : 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 30 : poRootGroup->OpenGroupFromFullname(osCoverageName);
1631 30 : if (poCoverage)
1632 : {
1633 30 : std::vector<std::shared_ptr<GDALMDArray>> apoIndexingVars;
1634 30 : if (S100GetDimensions(poCoverage.get(), m_dims,
1635 30 : apoIndexingVars) &&
1636 30 : m_dims.size() == 2 &&
1637 90 : m_dims[0]->GetSize() == anDimSizes[0] &&
1638 30 : m_dims[1]->GetSize() == anDimSizes[1])
1639 : {
1640 90 : for (const auto &poIndexingVar : apoIndexingVars)
1641 60 : m_poShared->KeepRef(poIndexingVar);
1642 30 : return true;
1643 : }
1644 : else
1645 : {
1646 0 : m_dims.clear();
1647 : }
1648 : }
1649 : }
1650 0 : return false;
1651 215 : };
1652 :
1653 274 : if (nDims == 2 &&
1654 59 : GetFullName() ==
1655 : "/BathymetryCoverage/BathymetryCoverage.01/Group_001/values")
1656 : {
1657 : // S102
1658 19 : if (SpecialCaseS100("/BathymetryCoverage/BathymetryCoverage.01"))
1659 19 : return;
1660 : }
1661 236 : else if (nDims == 2 &&
1662 40 : GetFullName() ==
1663 : "/QualityOfSurvey/QualityOfSurvey.01/Group_001/values")
1664 : {
1665 : // S102
1666 3 : if (SpecialCaseS100("/QualityOfSurvey/QualityOfSurvey.01"))
1667 3 : return;
1668 : }
1669 230 : else if (nDims == 2 &&
1670 37 : STARTS_WITH(GetFullName().c_str(),
1671 230 : "/WaterLevel/WaterLevel.01/") &&
1672 4 : GetFullName().find("/values"))
1673 : {
1674 : // S104
1675 4 : if (SpecialCaseS100("/WaterLevel/WaterLevel.01"))
1676 4 : return;
1677 : }
1678 222 : else if (nDims == 2 &&
1679 33 : STARTS_WITH(GetFullName().c_str(),
1680 222 : "/SurfaceCurrent/SurfaceCurrent.01/") &&
1681 4 : GetFullName().find("/values"))
1682 : {
1683 : // S111
1684 4 : if (SpecialCaseS100("/SurfaceCurrent/SurfaceCurrent.01"))
1685 4 : return;
1686 : }
1687 : }
1688 :
1689 430 : std::map<std::string, std::shared_ptr<GDALDimension>> oMapFullNameToDim;
1690 : // cppcheck-suppress knownConditionTrueFalse
1691 215 : 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 506 : for (int i = 0; i < nDims; ++i)
1701 : {
1702 291 : auto oIter = mapDimIndexToDimFullName.find(static_cast<size_t>(i));
1703 291 : 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 450 : m_dims.emplace_back(std::make_shared<GDALDimension>(
1733 450 : std::string(), CPLSPrintf("dim%d", i), std::string(),
1734 675 : 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 1075 : HDF5Array::GetAttribute(const std::string &osName) const
1911 : {
1912 1075 : const char *const apszOptions[] = {"SHOW_ALL=YES", nullptr};
1913 1075 : if (!m_bShowAllAttributes)
1914 990 : GetAttributes(apszOptions);
1915 2677 : for (const auto &attr : m_oListAttributes)
1916 : {
1917 1784 : if (attr->GetName() == osName)
1918 182 : return attr;
1919 : }
1920 893 : return nullptr;
1921 : }
1922 :
1923 : /************************************************************************/
1924 : /* GetAttributes() */
1925 : /************************************************************************/
1926 :
1927 : std::vector<std::shared_ptr<GDALAttribute>>
1928 2214 : HDF5Array::GetAttributes(CSLConstList papszOptions) const
1929 : {
1930 : HDF5_GLOBAL_LOCK();
1931 :
1932 2214 : m_oListAttributes.clear();
1933 2214 : m_bShowAllAttributes =
1934 2214 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SHOW_ALL", "NO"));
1935 2214 : H5Aiterate(m_hArray, nullptr, GetAttributesCallback,
1936 : const_cast<void *>(static_cast<const void *>(this)));
1937 2214 : return m_oListAttributes;
1938 : }
1939 :
1940 : /************************************************************************/
1941 : /* GetBlockSize() */
1942 : /************************************************************************/
1943 :
1944 72 : std::vector<GUInt64> HDF5Array::GetBlockSize() const
1945 : {
1946 : HDF5_GLOBAL_LOCK();
1947 :
1948 72 : const auto nDimCount = GetDimensionCount();
1949 72 : std::vector<GUInt64> res(nDimCount);
1950 72 : if (res.empty())
1951 0 : return res;
1952 :
1953 72 : const hid_t nListId = H5Dget_create_plist(m_hArray);
1954 72 : if (nListId > 0)
1955 : {
1956 72 : 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 72 : H5Pclose(nListId);
1971 : }
1972 :
1973 72 : 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 34 : 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 34 : const size_t nBufferDataTypeSize(bufferDataType.GetSize());
2029 68 : std::vector<size_t> anStackCount(nDims);
2030 68 : std::vector<GByte *> pabySrcBufferStack(nDims + 1);
2031 68 : std::vector<GByte *> pabyDstBufferStack(nDims + 1);
2032 68 : std::vector<GPtrDiff_t> anSrcStride(nDims);
2033 68 : std::vector<size_t> anSrcOffset(nDims + 1);
2034 34 : size_t nCurStride = nBufferDataTypeSize;
2035 103 : for (size_t i = nDims; i > 0;)
2036 : {
2037 69 : --i;
2038 69 : anSrcStride[i] = arrayStep[i] > 0
2039 69 : ? nCurStride
2040 44 : : -static_cast<GPtrDiff_t>(nCurStride);
2041 69 : anSrcOffset[i] = arrayStep[i] > 0 ? 0 : (count[i] - 1) * nCurStride;
2042 69 : nCurStride *= count[i];
2043 : }
2044 34 : pabySrcBufferStack[0] = pabySrc + anSrcOffset[0];
2045 34 : pabyDstBufferStack[0] = static_cast<GByte *>(pDstBuffer);
2046 34 : size_t iDim = 0;
2047 289 : lbl_next_depth:
2048 289 : if (iDim == nDims)
2049 : {
2050 192 : memcpy(pabyDstBufferStack[nDims], pabySrcBufferStack[nDims],
2051 : nBufferDataTypeSize);
2052 : }
2053 : else
2054 : {
2055 97 : anStackCount[iDim] = count[iDim];
2056 : while (true)
2057 : {
2058 255 : ++iDim;
2059 510 : pabySrcBufferStack[iDim] =
2060 255 : pabySrcBufferStack[iDim - 1] + anSrcOffset[iDim];
2061 255 : pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
2062 255 : goto lbl_next_depth;
2063 255 : lbl_return_to_caller_in_loop:
2064 255 : --iDim;
2065 255 : --anStackCount[iDim];
2066 255 : if (anStackCount[iDim] == 0)
2067 97 : break;
2068 158 : pabyDstBufferStack[iDim] +=
2069 158 : bufferStride[iDim] * nBufferDataTypeSize;
2070 158 : pabySrcBufferStack[iDim] += anSrcStride[iDim];
2071 : }
2072 : }
2073 289 : if (iDim > 0)
2074 255 : goto lbl_return_to_caller_in_loop;
2075 34 : }
2076 :
2077 : /************************************************************************/
2078 : /* ReadSlow() */
2079 : /************************************************************************/
2080 :
2081 39 : 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 39 : const size_t nBufferDataTypeSize(bufferDataType.GetSize());
2088 39 : if (nBufferDataTypeSize == 0)
2089 0 : return false;
2090 39 : const size_t nDims(m_dims.size());
2091 39 : size_t nEltCount = 1;
2092 118 : for (size_t i = 0; i < nDims; ++i)
2093 : {
2094 79 : nEltCount *= count[i];
2095 : }
2096 :
2097 : // Only for testing
2098 : const char *pszThreshold =
2099 39 : CPLGetConfigOption("GDAL_HDF5_TEMP_ARRAY_ALLOC_SIZE", "16777216");
2100 : const GUIntBig nThreshold =
2101 39 : CPLScanUIntBig(pszThreshold, static_cast<int>(strlen(pszThreshold)));
2102 39 : if (nEltCount == 1 || nEltCount <= nThreshold / nBufferDataTypeSize)
2103 : {
2104 34 : CPLDebug("HDF5", "Using slow path");
2105 68 : std::vector<GByte> abyTemp;
2106 : try
2107 : {
2108 34 : 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 68 : std::vector<GUInt64> anStart(nDims);
2116 68 : std::vector<GInt64> anStep(nDims);
2117 103 : for (size_t i = 0; i < nDims; i++)
2118 : {
2119 69 : if (arrayStep[i] >= 0)
2120 : {
2121 26 : anStart[i] = arrayStartIdx[i];
2122 26 : 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 86 : anStart[i] =
2130 43 : arrayStartIdx[i] - ((-arrayStep[i]) * (count[i] - 1));
2131 43 : anStep[i] = -arrayStep[i];
2132 : }
2133 : }
2134 68 : std::vector<GPtrDiff_t> anStride(nDims);
2135 34 : size_t nCurStride = 1;
2136 103 : for (size_t i = nDims; i > 0;)
2137 : {
2138 69 : --i;
2139 69 : anStride[i] = nCurStride;
2140 69 : nCurStride *= count[i];
2141 : }
2142 34 : if (!IRead(anStart.data(), count, anStep.data(), anStride.data(),
2143 34 : bufferDataType, &abyTemp[0]))
2144 : {
2145 0 : return false;
2146 : }
2147 34 : CopyBuffer(nDims, count, arrayStep, bufferStride, bufferDataType,
2148 34 : &abyTemp[0], pDstBuffer);
2149 34 : 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 1066 : GetHDF5DataTypeFromGDALDataType(const GDALExtendedDataType &dt, hid_t hNativeDT,
2300 : const GDALExtendedDataType &bufferDataType)
2301 : {
2302 1066 : hid_t hBufferType = H5I_INVALID_HID;
2303 1066 : 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 14 : case GDT_UInt32:
2318 14 : hBufferType = H5Tcopy(H5T_NATIVE_UINT);
2319 14 : break;
2320 499 : case GDT_Int32:
2321 499 : hBufferType = H5Tcopy(H5T_NATIVE_INT);
2322 499 : 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 494 : case GDT_Float64:
2340 494 : hBufferType = H5Tcopy(H5T_NATIVE_DOUBLE);
2341 494 : 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 1066 : return hBufferType;
2361 : }
2362 :
2363 : /************************************************************************/
2364 : /* FreeDynamicMemory() */
2365 : /************************************************************************/
2366 :
2367 692 : static void FreeDynamicMemory(GByte *pabyPtr, hid_t hDataType)
2368 : {
2369 692 : const auto klass = H5Tget_class(hDataType);
2370 692 : if (klass == H5T_STRING && H5Tis_variable_str(hDataType))
2371 : {
2372 44 : auto hDataSpace = H5Screate(H5S_SCALAR);
2373 44 : H5Dvlen_reclaim(hDataType, hDataSpace, H5P_DEFAULT, pabyPtr);
2374 44 : H5Sclose(hDataSpace);
2375 : }
2376 648 : else if (klass == H5T_COMPOUND)
2377 : {
2378 104 : const unsigned nMembers = H5Tget_nmembers(hDataType);
2379 692 : for (unsigned i = 0; i < nMembers; i++)
2380 : {
2381 588 : const auto nOffset = H5Tget_member_offset(hDataType, i);
2382 588 : auto hMemberType = H5Tget_member_type(hDataType, i);
2383 588 : if (hMemberType < 0)
2384 0 : continue;
2385 588 : FreeDynamicMemory(pabyPtr + nOffset, hMemberType);
2386 588 : H5Tclose(hMemberType);
2387 : }
2388 : }
2389 692 : }
2390 :
2391 : /************************************************************************/
2392 : /* CreateMapTargetComponentsToSrc() */
2393 : /************************************************************************/
2394 :
2395 : static std::vector<unsigned>
2396 142 : CreateMapTargetComponentsToSrc(hid_t hSrcDataType,
2397 : const GDALExtendedDataType &dstDataType)
2398 : {
2399 142 : CPLAssert(H5Tget_class(hSrcDataType) == H5T_COMPOUND);
2400 142 : CPLAssert(dstDataType.GetClass() == GEDTC_COMPOUND);
2401 :
2402 142 : const unsigned nMembers = H5Tget_nmembers(hSrcDataType);
2403 284 : std::map<std::string, unsigned> oMapSrcCompNameToIdx;
2404 801 : for (unsigned i = 0; i < nMembers; i++)
2405 : {
2406 659 : char *pszName = H5Tget_member_name(hSrcDataType, i);
2407 659 : if (pszName)
2408 : {
2409 659 : oMapSrcCompNameToIdx[pszName] = i;
2410 659 : H5free_memory(pszName);
2411 : }
2412 : }
2413 :
2414 142 : std::vector<unsigned> ret;
2415 142 : const auto &comps = dstDataType.GetComponents();
2416 142 : ret.reserve(comps.size());
2417 765 : for (const auto &comp : comps)
2418 : {
2419 623 : auto oIter = oMapSrcCompNameToIdx.find(comp->GetName());
2420 623 : CPLAssert(oIter != oMapSrcCompNameToIdx.end());
2421 623 : ret.emplace_back(oIter->second);
2422 : }
2423 284 : return ret;
2424 : }
2425 :
2426 : /************************************************************************/
2427 : /* CopyValue() */
2428 : /************************************************************************/
2429 :
2430 2532 : static void CopyValue(const GByte *pabySrcBuffer, hid_t hSrcDataType,
2431 : GByte *pabyDstBuffer,
2432 : const GDALExtendedDataType &dstDataType,
2433 : const std::vector<unsigned> &mapDstCompsToSrcComps)
2434 : {
2435 2532 : const auto klass = H5Tget_class(hSrcDataType);
2436 2532 : if (klass == H5T_STRING)
2437 : {
2438 1086 : if (H5Tis_variable_str(hSrcDataType))
2439 : {
2440 400 : GDALExtendedDataType::CopyValue(
2441 800 : 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 1446 : else if (klass == H5T_COMPOUND)
2460 : {
2461 106 : 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 103 : const auto &comps = dstDataType.GetComponents();
2511 103 : CPLAssert(comps.size() == mapDstCompsToSrcComps.size());
2512 687 : for (size_t iDst = 0; iDst < comps.size(); ++iDst)
2513 : {
2514 584 : const unsigned iSrc = mapDstCompsToSrcComps[iDst];
2515 584 : auto hMemberType = H5Tget_member_type(hSrcDataType, iSrc);
2516 : const std::vector<unsigned> mapDstSubCompsToSrcSubComps(
2517 584 : (H5Tget_class(hMemberType) == H5T_COMPOUND &&
2518 0 : comps[iDst]->GetType().GetClass() == GEDTC_COMPOUND)
2519 584 : ? CreateMapTargetComponentsToSrc(hMemberType,
2520 0 : comps[iDst]->GetType())
2521 1168 : : std::vector<unsigned>());
2522 584 : CopyValue(pabySrcBuffer +
2523 584 : H5Tget_member_offset(hSrcDataType, iSrc),
2524 584 : hMemberType, pabyDstBuffer + comps[iDst]->GetOffset(),
2525 584 : comps[iDst]->GetType(), mapDstSubCompsToSrcSubComps);
2526 584 : H5Tclose(hMemberType);
2527 : }
2528 : }
2529 : }
2530 1340 : 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 1338 : GDALDataType eDT = ::HDF5Dataset::GetDataType(hSrcDataType);
2552 1338 : GDALExtendedDataType::CopyValue(pabySrcBuffer,
2553 2676 : GDALExtendedDataType::Create(eDT),
2554 : pabyDstBuffer, dstDataType);
2555 : }
2556 2532 : }
2557 :
2558 : /************************************************************************/
2559 : /* CopyToFinalBuffer() */
2560 : /************************************************************************/
2561 :
2562 142 : 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 142 : const size_t nSrcDataTypeSize(H5Tget_size(hSrcDataType));
2569 284 : std::vector<size_t> anStackCount(nDims);
2570 284 : std::vector<GByte *> pabyDstBufferStack(nDims + 1);
2571 142 : const GByte *pabySrcBuffer = static_cast<const GByte *>(pTemp);
2572 142 : pabyDstBufferStack[0] = static_cast<GByte *>(pDstBuffer);
2573 142 : size_t iDim = 0;
2574 : const std::vector<unsigned> mapDstCompsToSrcComps(
2575 283 : (H5Tget_class(hSrcDataType) == H5T_COMPOUND &&
2576 141 : bufferDataType.GetClass() == GEDTC_COMPOUND)
2577 142 : ? CreateMapTargetComponentsToSrc(hSrcDataType, bufferDataType)
2578 284 : : std::vector<unsigned>());
2579 :
2580 142 : bool bFastCopyOfCompoundToSingleComponentCompound = false;
2581 142 : GDALDataType eSrcTypeComp = GDT_Unknown;
2582 142 : size_t nSrcOffset = 0;
2583 142 : GDALDataType eDstTypeComp = GDT_Unknown;
2584 142 : int bufferStrideLastDim = 0;
2585 183 : if (nDims > 0 && mapDstCompsToSrcComps.size() == 1 &&
2586 41 : bufferDataType.GetComponents()[0]->GetType().GetClass() ==
2587 : GEDTC_NUMERIC)
2588 : {
2589 : auto hMemberType =
2590 40 : H5Tget_member_type(hSrcDataType, mapDstCompsToSrcComps[0]);
2591 40 : eSrcTypeComp = HDF5Dataset::GetDataType(hMemberType);
2592 40 : if (eSrcTypeComp != GDT_Unknown)
2593 : {
2594 : nSrcOffset =
2595 40 : H5Tget_member_offset(hSrcDataType, mapDstCompsToSrcComps[0]);
2596 40 : eDstTypeComp = bufferDataType.GetComponents()[0]
2597 40 : ->GetType()
2598 40 : .GetNumericDataType();
2599 80 : bufferStrideLastDim = static_cast<int>(bufferStride[nDims - 1] *
2600 40 : bufferDataType.GetSize());
2601 40 : bFastCopyOfCompoundToSingleComponentCompound = true;
2602 : }
2603 : }
2604 :
2605 102 : lbl_next_depth:
2606 392 : if (bFastCopyOfCompoundToSingleComponentCompound && iDim == nDims - 1)
2607 : {
2608 69 : GDALCopyWords64(pabySrcBuffer + nSrcOffset, eSrcTypeComp,
2609 : static_cast<int>(nSrcDataTypeSize),
2610 69 : pabyDstBufferStack[iDim], eDstTypeComp,
2611 69 : static_cast<int>(bufferStrideLastDim), count[iDim]);
2612 69 : pabySrcBuffer += count[iDim] * nSrcDataTypeSize;
2613 : }
2614 323 : else if (iDim == nDims)
2615 : {
2616 162 : CopyValue(pabySrcBuffer, hSrcDataType, pabyDstBufferStack[nDims],
2617 : bufferDataType, mapDstCompsToSrcComps);
2618 162 : pabySrcBuffer += nSrcDataTypeSize;
2619 : }
2620 : else
2621 : {
2622 161 : anStackCount[iDim] = count[iDim];
2623 : while (true)
2624 : {
2625 250 : ++iDim;
2626 250 : pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
2627 250 : goto lbl_next_depth;
2628 250 : lbl_return_to_caller_in_loop:
2629 250 : --iDim;
2630 250 : --anStackCount[iDim];
2631 250 : if (anStackCount[iDim] == 0)
2632 161 : break;
2633 89 : pabyDstBufferStack[iDim] +=
2634 89 : bufferStride[iDim] * bufferDataType.GetSize();
2635 : }
2636 : }
2637 392 : if (iDim > 0)
2638 250 : goto lbl_return_to_caller_in_loop;
2639 142 : }
2640 :
2641 : /************************************************************************/
2642 : /* IRead() */
2643 : /************************************************************************/
2644 :
2645 364 : 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 364 : const size_t nDims(m_dims.size());
2653 728 : std::vector<H5OFFSET_TYPE> anOffset(nDims);
2654 728 : std::vector<hsize_t> anCount(nDims);
2655 728 : std::vector<hsize_t> anStep(nDims);
2656 :
2657 364 : size_t nEltCount = 1;
2658 813 : for (size_t i = 0; i < nDims; ++i)
2659 : {
2660 478 : if (count[i] != 1 && (arrayStep[i] < 0 || bufferStride[i] < 0))
2661 : {
2662 29 : return ReadSlow(arrayStartIdx, count, arrayStep, bufferStride,
2663 29 : bufferDataType, pDstBuffer);
2664 : }
2665 449 : anOffset[i] = static_cast<hsize_t>(arrayStartIdx[i]);
2666 449 : anCount[i] = static_cast<hsize_t>(count[i]);
2667 449 : anStep[i] = static_cast<hsize_t>(count[i] == 1 ? 1 : arrayStep[i]);
2668 449 : nEltCount *= count[i];
2669 : }
2670 :
2671 335 : if (IsTransposedRequest(count, bufferStride))
2672 : {
2673 118 : return ReadForTransposedRequest(arrayStartIdx, count, arrayStep,
2674 : bufferStride, bufferDataType,
2675 118 : pDstBuffer);
2676 : }
2677 :
2678 217 : bool strideOK = true;
2679 217 : GPtrDiff_t nExpectedBufferStride = 1;
2680 539 : for (size_t i = nDims; i != 0;)
2681 : {
2682 323 : --i;
2683 323 : if (count[i] != 1 && bufferStride[i] != nExpectedBufferStride)
2684 : {
2685 1 : strideOK = false;
2686 1 : break;
2687 : }
2688 322 : nExpectedBufferStride *= count[i];
2689 : }
2690 :
2691 217 : hid_t hBufferType = H5I_INVALID_HID;
2692 217 : GByte *pabyTemp = nullptr;
2693 217 : bool bUseTmpBuffer = false;
2694 217 : 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 275 : else if (strideOK && bufferDataType.GetClass() == GEDTC_NUMERIC &&
2711 60 : m_dt.GetClass() == GEDTC_NUMERIC &&
2712 486 : !GDALDataTypeIsComplex(m_dt.GetNumericDataType()) &&
2713 55 : !GDALDataTypeIsComplex(bufferDataType.GetNumericDataType()))
2714 : {
2715 : // Compatibility with older libhdf5 that doesn't like requesting
2716 : // an enum to an integer
2717 55 : 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 55 : if (hBufferType == H5I_INVALID_HID)
2738 : {
2739 55 : hBufferType = GetHDF5DataTypeFromGDALDataType(m_dt, m_hNativeDT,
2740 : bufferDataType);
2741 55 : if (hBufferType == H5I_INVALID_HID)
2742 : {
2743 0 : return false;
2744 : }
2745 : }
2746 : }
2747 161 : else if (strideOK)
2748 : {
2749 160 : hBufferType = H5Tcopy(m_hNativeDT);
2750 160 : if (m_dt != bufferDataType || m_bHasString || m_bHasNonNativeDataType)
2751 : {
2752 141 : bUseTmpBuffer = true;
2753 : }
2754 : }
2755 : else
2756 : {
2757 1 : hBufferType = H5Tcopy(m_hNativeDT);
2758 1 : bUseTmpBuffer = true;
2759 : }
2760 :
2761 217 : if (bUseTmpBuffer)
2762 : {
2763 142 : const size_t nDataTypeSize = H5Tget_size(hBufferType);
2764 : pabyTemp =
2765 142 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nDataTypeSize, nEltCount));
2766 142 : 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 217 : if (nDims)
2776 : {
2777 : status =
2778 215 : H5Sselect_hyperslab(m_hDataSpace, H5S_SELECT_SET, anOffset.data(),
2779 215 : anStep.data(), anCount.data(), nullptr);
2780 215 : 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 217 : ? H5Screate(H5S_SCALAR)
2791 215 : : H5Screate_simple(static_cast<int>(nDims),
2792 215 : anCount.data(), nullptr);
2793 217 : if (nDims)
2794 : {
2795 215 : std::vector<H5OFFSET_TYPE> anMemOffset(nDims);
2796 : status =
2797 215 : H5Sselect_hyperslab(hMemSpace, H5S_SELECT_SET, anMemOffset.data(),
2798 215 : nullptr, anCount.data(), nullptr);
2799 215 : if (status < 0)
2800 : {
2801 0 : H5Tclose(hBufferType);
2802 0 : H5Sclose(hMemSpace);
2803 0 : VSIFree(pabyTemp);
2804 0 : return false;
2805 : }
2806 : }
2807 :
2808 217 : status = H5Dread(m_hArray, hBufferType, hMemSpace, m_hDataSpace,
2809 : H5P_DEFAULT, pabyTemp ? pabyTemp : pDstBuffer);
2810 :
2811 217 : if (status >= 0)
2812 : {
2813 217 : if (H5Tis_variable_str(hBufferType))
2814 : {
2815 1 : IngestVariableStrings(pDstBuffer, hBufferType, nDims, count,
2816 : bufferStride);
2817 : }
2818 216 : else if (pabyTemp && bufferDataType.GetClass() == GEDTC_STRING)
2819 : {
2820 0 : IngestFixedLengthStrings(pDstBuffer, pabyTemp, hBufferType, nDims,
2821 : count, bufferStride);
2822 : }
2823 216 : else if (pabyTemp)
2824 : {
2825 142 : CopyToFinalBuffer(pDstBuffer, pabyTemp, nDims, count, bufferStride,
2826 142 : m_hNativeDT, bufferDataType);
2827 :
2828 142 : if (m_bHasString)
2829 : {
2830 102 : const size_t nBufferTypeSize = H5Tget_size(hBufferType);
2831 102 : GByte *pabyPtr = pabyTemp;
2832 206 : for (size_t i = 0; i < nEltCount; ++i)
2833 : {
2834 104 : FreeDynamicMemory(pabyPtr, hBufferType);
2835 104 : pabyPtr += nBufferTypeSize;
2836 : }
2837 : }
2838 : }
2839 : }
2840 :
2841 217 : H5Tclose(hBufferType);
2842 217 : H5Sclose(hMemSpace);
2843 217 : VSIFree(pabyTemp);
2844 :
2845 217 : return status >= 0;
2846 : }
2847 :
2848 : /************************************************************************/
2849 : /* ~HDF5Attribute() */
2850 : /************************************************************************/
2851 :
2852 51274 : HDF5Attribute::~HDF5Attribute()
2853 : {
2854 : HDF5_GLOBAL_LOCK();
2855 :
2856 25637 : if (m_hAttribute > 0)
2857 25637 : H5Aclose(m_hAttribute);
2858 25637 : if (m_hNativeDT > 0)
2859 25637 : H5Tclose(m_hNativeDT);
2860 25637 : if (m_hDataSpace > 0)
2861 25637 : H5Sclose(m_hDataSpace);
2862 51274 : }
2863 :
2864 : /************************************************************************/
2865 : /* CopyAllAttrValuesInto() */
2866 : /************************************************************************/
2867 :
2868 1758 : 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 1758 : const size_t nBufferDataTypeSize(bufferDataType.GetSize());
2876 1758 : const size_t nSrcDataTypeSize(H5Tget_size(hSrcBufferType));
2877 3516 : std::vector<size_t> anStackCount(nDims);
2878 3516 : std::vector<const GByte *> pabySrcBufferStack(nDims + 1);
2879 3516 : std::vector<GByte *> pabyDstBufferStack(nDims + 1);
2880 : const std::vector<unsigned> mapDstCompsToSrcComps(
2881 1762 : (H5Tget_class(hSrcBufferType) == H5T_COMPOUND &&
2882 4 : bufferDataType.GetClass() == GEDTC_COMPOUND)
2883 1758 : ? CreateMapTargetComponentsToSrc(hSrcBufferType, bufferDataType)
2884 3516 : : std::vector<unsigned>());
2885 :
2886 1758 : pabySrcBufferStack[0] = static_cast<const GByte *>(pabySrcBuffer);
2887 1758 : if (nDims > 0)
2888 25 : pabySrcBufferStack[0] += arrayStartIdx[0] * nSrcDataTypeSize;
2889 1758 : pabyDstBufferStack[0] = static_cast<GByte *>(pDstBuffer);
2890 1758 : size_t iDim = 0;
2891 1809 : lbl_next_depth:
2892 1809 : if (iDim == nDims)
2893 : {
2894 1784 : CopyValue(pabySrcBufferStack[nDims], hSrcBufferType,
2895 1784 : 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 1809 : if (iDim > 0)
2923 51 : goto lbl_return_to_caller_in_loop;
2924 1758 : }
2925 :
2926 : /************************************************************************/
2927 : /* IRead() */
2928 : /************************************************************************/
2929 :
2930 1758 : 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 1758 : const size_t nDims(m_dims.size());
2939 1758 : if (m_dt.GetClass() == GEDTC_STRING)
2940 : {
2941 585 : if (bufferDataType.GetClass() != GEDTC_STRING)
2942 : {
2943 0 : return false;
2944 : }
2945 :
2946 585 : 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 351 : void *pabyTemp = VSI_CALLOC_VERBOSE(sizeof(char *), m_nElements);
2967 351 : if (pabyTemp == nullptr)
2968 0 : return false;
2969 702 : if (H5Sget_simple_extent_type(m_hDataSpace) != H5S_NULL &&
2970 351 : H5Aread(m_hAttribute, m_hNativeDT, pabyTemp) < 0)
2971 : {
2972 0 : VSIFree(pabyTemp);
2973 0 : return false;
2974 : }
2975 351 : CopyAllAttrValuesInto(nDims, arrayStartIdx, count, arrayStep,
2976 : bufferStride, bufferDataType, pDstBuffer,
2977 351 : m_hNativeDT, pabyTemp);
2978 351 : H5Dvlen_reclaim(m_hNativeDT, m_hDataSpace, H5P_DEFAULT, pabyTemp);
2979 351 : VSIFree(pabyTemp);
2980 : }
2981 585 : return true;
2982 : }
2983 :
2984 1173 : hid_t hBufferType = H5I_INVALID_HID;
2985 2345 : if (m_dt.GetClass() == GEDTC_NUMERIC &&
2986 1172 : bufferDataType.GetClass() == GEDTC_NUMERIC &&
2987 3358 : !GDALDataTypeIsComplex(m_dt.GetNumericDataType()) &&
2988 1013 : !GDALDataTypeIsComplex(bufferDataType.GetNumericDataType()))
2989 : {
2990 : // Compatibility with older libhdf5 that doesn't like requesting
2991 : // an enum to an integer
2992 1013 : 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 1013 : if (hBufferType == H5I_INVALID_HID)
3009 : {
3010 1011 : hBufferType = GetHDF5DataTypeFromGDALDataType(m_dt, m_hNativeDT,
3011 : bufferDataType);
3012 : }
3013 : }
3014 : else
3015 : {
3016 160 : hBufferType = H5Tcopy(m_hNativeDT);
3017 : }
3018 :
3019 1173 : if (hBufferType == H5I_INVALID_HID)
3020 0 : return false;
3021 :
3022 1173 : const size_t nBufferTypeSize(H5Tget_size(hBufferType));
3023 : GByte *pabyTemp =
3024 1173 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBufferTypeSize, m_nElements));
3025 1173 : if (pabyTemp == nullptr)
3026 : {
3027 0 : H5Tclose(hBufferType);
3028 0 : return false;
3029 : }
3030 1173 : if (H5Aread(m_hAttribute, hBufferType, pabyTemp) < 0)
3031 : {
3032 0 : VSIFree(pabyTemp);
3033 0 : return false;
3034 : }
3035 1173 : CopyAllAttrValuesInto(nDims, arrayStartIdx, count, arrayStep, bufferStride,
3036 : bufferDataType, pDstBuffer, hBufferType, pabyTemp);
3037 1173 : 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 1173 : VSIFree(pabyTemp);
3047 1173 : H5Tclose(hBufferType);
3048 1173 : 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 173 : std::shared_ptr<GDALGroup> HDF5Dataset::OpenGroup(
3132 : const std::shared_ptr<GDAL::HDF5SharedResources> &poSharedResources)
3133 : {
3134 : HDF5_GLOBAL_LOCK();
3135 :
3136 346 : auto poGroup = poSharedResources->GetRootGroup();
3137 173 : if (!poGroup)
3138 0 : return nullptr;
3139 :
3140 173 : 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 173 : return poGroup;
3155 : }
|