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