Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: HDF4 read Driver
4 : * Author: Even Rouault <even.rouault at spatialys.com>
5 : *
6 : ******************************************************************************
7 : * Copyright (c) 2019, Even Rouault <even.rouault at spatialys.com>
8 : *
9 : * SPDX-License-Identifier: MIT
10 : ****************************************************************************/
11 :
12 : #include "cpl_multiproc.h"
13 : #include "hdf4dataset.h"
14 :
15 : #include "hdf.h"
16 : #include "mfhdf.h"
17 :
18 : #include "HdfEosDef.h"
19 :
20 : #include "cpl_string.h"
21 : #include "gdal_pam_multidim.h"
22 :
23 : #include <algorithm>
24 : #include <map>
25 : #include <set>
26 :
27 : #if defined(__clang__) || defined(_MSC_VER)
28 : #define COMPILER_WARNS_ABOUT_ABSTRACT_VBASE_INIT
29 : #endif
30 :
31 : extern CPLMutex *hHDF4Mutex;
32 : extern const char *const pszGDALSignature;
33 :
34 : /************************************************************************/
35 : /* HDF4SharedResources */
36 : /************************************************************************/
37 :
38 : class HDF4SharedResources
39 : {
40 : friend class ::HDF4Dataset;
41 : int32 m_hSD = -1;
42 : std::string m_osFilename{};
43 : CPLStringList m_aosOpenOptions{};
44 : std::shared_ptr<GDALPamMultiDim> m_poPAM{};
45 :
46 : public:
47 : explicit HDF4SharedResources(const std::string &osFilename);
48 : ~HDF4SharedResources();
49 :
50 89 : int32 GetSDHandle() const
51 : {
52 89 : return m_hSD;
53 : }
54 :
55 88 : const std::string &GetFilename() const
56 : {
57 88 : return m_osFilename;
58 : }
59 :
60 10 : const char *FetchOpenOption(const char *pszName,
61 : const char *pszDefault) const
62 : {
63 10 : return m_aosOpenOptions.FetchNameValueDef(pszName, pszDefault);
64 : }
65 :
66 11 : const std::shared_ptr<GDALPamMultiDim> &GetPAM()
67 : {
68 11 : return m_poPAM;
69 : }
70 : };
71 :
72 : /************************************************************************/
73 : /* HDF4Group */
74 : /************************************************************************/
75 :
76 : class HDF4SDSGroup;
77 :
78 : class HDF4Group final : public GDALGroup
79 : {
80 : std::shared_ptr<HDF4SharedResources> m_poShared;
81 : std::shared_ptr<HDF4SDSGroup> m_poGDALGroup{};
82 :
83 : protected:
84 : HDF4Group(const std::string &osParentName, const std::string &osName,
85 : const std::shared_ptr<HDF4SharedResources> &poShared);
86 :
87 : public:
88 : static std::shared_ptr<HDF4Group>
89 12 : Create(const std::string &osParentName, const std::string &osName,
90 : const std::shared_ptr<HDF4SharedResources> &poShared)
91 : {
92 : auto poGroup = std::shared_ptr<HDF4Group>(
93 12 : new HDF4Group(osParentName, osName, poShared));
94 12 : poGroup->SetSelf(poGroup);
95 12 : return poGroup;
96 : }
97 :
98 : std::vector<std::shared_ptr<GDALAttribute>>
99 : GetAttributes(CSLConstList papszOptions = nullptr) const override;
100 :
101 : std::vector<std::string>
102 : GetGroupNames(CSLConstList papszOptions) const override;
103 : std::shared_ptr<GDALGroup> OpenGroup(const std::string &osName,
104 : CSLConstList) const override;
105 :
106 : std::vector<std::shared_ptr<GDALDimension>>
107 : GetDimensions(CSLConstList papszOptions = nullptr) const override;
108 :
109 : std::vector<std::string>
110 : GetMDArrayNames(CSLConstList papszOptions) const override;
111 : std::shared_ptr<GDALMDArray>
112 : OpenMDArray(const std::string &osName,
113 : CSLConstList papszOptions) const override;
114 : };
115 :
116 : /************************************************************************/
117 : /* HDF4AbstractAttribute */
118 : /************************************************************************/
119 :
120 : class HDF4AbstractAttribute /* non final */ : public GDALAttribute
121 : {
122 : std::shared_ptr<HDF4SharedResources> m_poShared;
123 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
124 : GDALExtendedDataType m_dt = GDALExtendedDataType::Create(GDT_Unknown);
125 : int32 m_nValues = 0;
126 :
127 : protected:
128 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
129 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
130 : const GDALExtendedDataType &bufferDataType,
131 : void *pDstBuffer) const override;
132 :
133 : public:
134 : HDF4AbstractAttribute(const std::string &osParentName,
135 : const std::string &osName,
136 : const std::shared_ptr<HDF4SharedResources> &poShared,
137 : int32 iNumType, int32 nValues);
138 :
139 : const std::vector<std::shared_ptr<GDALDimension>> &
140 35 : GetDimensions() const override
141 : {
142 35 : return m_dims;
143 : }
144 :
145 26 : const GDALExtendedDataType &GetDataType() const override
146 : {
147 26 : return m_dt;
148 : }
149 :
150 : virtual void ReadData(void *pDstBuffer) const = 0;
151 : };
152 :
153 : /************************************************************************/
154 : /* HDF4SwathsHandle */
155 : /************************************************************************/
156 :
157 : struct HDF4SwathsHandle
158 : {
159 : int32 m_handle;
160 :
161 3 : explicit HDF4SwathsHandle(int32 handle) : m_handle(handle)
162 : {
163 3 : }
164 :
165 3 : ~HDF4SwathsHandle()
166 3 : {
167 6 : CPLMutexHolderD(&hHDF4Mutex);
168 3 : SWclose(m_handle);
169 3 : }
170 : };
171 :
172 : /************************************************************************/
173 : /* HDF4SwathHandle */
174 : /************************************************************************/
175 :
176 : struct HDF4SwathHandle
177 : {
178 : std::shared_ptr<HDF4SwathsHandle> m_poSwathsHandle;
179 : int32 m_handle;
180 :
181 3 : explicit HDF4SwathHandle(
182 : const std::shared_ptr<HDF4SwathsHandle> &poSwathsHandle, int32 handle)
183 3 : : m_poSwathsHandle(poSwathsHandle), m_handle(handle)
184 : {
185 3 : }
186 :
187 3 : ~HDF4SwathHandle()
188 3 : {
189 6 : CPLMutexHolderD(&hHDF4Mutex);
190 3 : SWdetach(m_handle);
191 3 : }
192 : };
193 :
194 : /************************************************************************/
195 : /* HDF4SwathsGroup */
196 : /************************************************************************/
197 :
198 : class HDF4SwathsGroup final : public GDALGroup
199 : {
200 : std::shared_ptr<HDF4SharedResources> m_poShared;
201 : std::shared_ptr<HDF4SwathsHandle> m_poSwathsHandle;
202 :
203 : public:
204 3 : HDF4SwathsGroup(const std::string &osParentName, const std::string &osName,
205 : const std::shared_ptr<HDF4SharedResources> &poShared,
206 : const std::shared_ptr<HDF4SwathsHandle> &poSwathsHandle)
207 3 : : GDALGroup(osParentName, osName), m_poShared(poShared),
208 3 : m_poSwathsHandle(poSwathsHandle)
209 : {
210 3 : }
211 :
212 : std::vector<std::string>
213 : GetGroupNames(CSLConstList papszOptions) const override;
214 : std::shared_ptr<GDALGroup> OpenGroup(const std::string &osName,
215 : CSLConstList) const override;
216 : };
217 :
218 : /************************************************************************/
219 : /* HDF4SwathGroup */
220 : /************************************************************************/
221 :
222 : class HDF4SwathGroup final : public GDALGroup
223 : {
224 : std::shared_ptr<HDF4SharedResources> m_poShared;
225 : std::shared_ptr<HDF4SwathHandle> m_poSwathHandle;
226 : mutable std::vector<std::shared_ptr<GDALDimension>> m_dims{};
227 :
228 : public:
229 3 : HDF4SwathGroup(const std::string &osParentName, const std::string &osName,
230 : const std::shared_ptr<HDF4SharedResources> &poShared,
231 : const std::shared_ptr<HDF4SwathHandle> &poSwathHandle)
232 3 : : GDALGroup(osParentName, osName), m_poShared(poShared),
233 3 : m_poSwathHandle(poSwathHandle)
234 : {
235 3 : }
236 :
237 : std::vector<std::shared_ptr<GDALDimension>>
238 : GetDimensions(CSLConstList papszOptions = nullptr) const override;
239 :
240 : std::vector<std::shared_ptr<GDALAttribute>>
241 : GetAttributes(CSLConstList papszOptions = nullptr) const override;
242 :
243 : std::vector<std::string>
244 : GetGroupNames(CSLConstList papszOptions) const override;
245 : std::shared_ptr<GDALGroup> OpenGroup(const std::string &osName,
246 : CSLConstList) const override;
247 : };
248 :
249 : /************************************************************************/
250 : /* HDF4SwathSubGroup */
251 : /************************************************************************/
252 :
253 : class HDF4SwathSubGroup final : public GDALGroup
254 : {
255 : std::shared_ptr<HDF4SharedResources> m_poShared;
256 : std::shared_ptr<HDF4SwathHandle> m_poSwathHandle;
257 : int32 m_entryType;
258 : std::vector<std::shared_ptr<GDALDimension>> m_groupDims{};
259 :
260 : public:
261 6 : HDF4SwathSubGroup(
262 : const std::string &osParentName, const std::string &osName,
263 : const std::shared_ptr<HDF4SharedResources> &poShared,
264 : const std::shared_ptr<HDF4SwathHandle> &poSwathHandle, int32 entryType,
265 : const std::vector<std::shared_ptr<GDALDimension>> &groupDims)
266 6 : : GDALGroup(osParentName, osName), m_poShared(poShared),
267 : m_poSwathHandle(poSwathHandle), m_entryType(entryType),
268 6 : m_groupDims(groupDims)
269 : {
270 6 : }
271 :
272 : std::vector<std::string>
273 : GetMDArrayNames(CSLConstList papszOptions) const override;
274 : std::shared_ptr<GDALMDArray>
275 : OpenMDArray(const std::string &osName,
276 : CSLConstList papszOptions) const override;
277 : };
278 :
279 : /************************************************************************/
280 : /* HDF4SwathArray */
281 : /************************************************************************/
282 :
283 : class HDF4SwathArray final : public GDALPamMDArray
284 : {
285 : std::shared_ptr<HDF4SharedResources> m_poShared;
286 : std::shared_ptr<HDF4SwathHandle> m_poSwathHandle;
287 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
288 : GDALExtendedDataType m_dt = GDALExtendedDataType::Create(GDT_Unknown);
289 : mutable std::vector<GByte> m_abyNoData{};
290 :
291 : protected:
292 : HDF4SwathArray(
293 : const std::string &osParentName, const std::string &osName,
294 : const std::shared_ptr<HDF4SharedResources> &poShared,
295 : const std::shared_ptr<HDF4SwathHandle> &poSwathHandle,
296 : const std::vector<int32> &aiDimSizes, const std::string &dimNames,
297 : int32 iNumType,
298 : const std::vector<std::shared_ptr<GDALDimension>> &groupDims);
299 :
300 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
301 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
302 : const GDALExtendedDataType &bufferDataType,
303 : void *pDstBuffer) const override;
304 :
305 : public:
306 : static std::shared_ptr<HDF4SwathArray>
307 0 : Create(const std::string &osParentName, const std::string &osName,
308 : const std::shared_ptr<HDF4SharedResources> &poShared,
309 : const std::shared_ptr<HDF4SwathHandle> &poSwathHandle,
310 : const std::vector<int32> &aiDimSizes, const std::string &dimNames,
311 : int32 iNumType,
312 : const std::vector<std::shared_ptr<GDALDimension>> &groupDims)
313 : {
314 : auto ar(std::shared_ptr<HDF4SwathArray>(
315 : new HDF4SwathArray(osParentName, osName, poShared, poSwathHandle,
316 0 : aiDimSizes, dimNames, iNumType, groupDims)));
317 0 : ar->SetSelf(ar);
318 0 : return ar;
319 : }
320 :
321 0 : bool IsWritable() const override
322 : {
323 0 : return false;
324 : }
325 :
326 0 : const std::string &GetFilename() const override
327 : {
328 0 : return m_poShared->GetFilename();
329 : }
330 :
331 : const std::vector<std::shared_ptr<GDALDimension>> &
332 0 : GetDimensions() const override
333 : {
334 0 : return m_dims;
335 : }
336 :
337 0 : const GDALExtendedDataType &GetDataType() const override
338 : {
339 0 : return m_dt;
340 : }
341 :
342 : std::vector<std::shared_ptr<GDALAttribute>>
343 : GetAttributes(CSLConstList papszOptions = nullptr) const override;
344 :
345 : const void *GetRawNoDataValue() const override;
346 : };
347 :
348 : /************************************************************************/
349 : /* HDF4SDAttribute */
350 : /************************************************************************/
351 :
352 : class HDF4SwathAttribute final : public HDF4AbstractAttribute
353 : {
354 : std::shared_ptr<HDF4SwathHandle> m_poSwathHandle;
355 :
356 : public:
357 0 : HDF4SwathAttribute(const std::string &osParentName,
358 : const std::string &osName,
359 : const std::shared_ptr<HDF4SharedResources> &poShared,
360 : const std::shared_ptr<HDF4SwathHandle> &poSwathHandle,
361 : int32 iNumType, int32 nValues)
362 0 : : GDALAbstractMDArray(osParentName, osName),
363 : HDF4AbstractAttribute(osParentName, osName, poShared, iNumType,
364 : nValues),
365 0 : m_poSwathHandle(poSwathHandle)
366 : {
367 0 : }
368 :
369 : void ReadData(void *pDstBuffer) const override;
370 : };
371 :
372 0 : void HDF4SwathAttribute::ReadData(void *pDstBuffer) const
373 : {
374 0 : SWreadattr(m_poSwathHandle->m_handle, GetName().c_str(), pDstBuffer);
375 0 : }
376 :
377 : /************************************************************************/
378 : /* HDF4GDsHandle */
379 : /************************************************************************/
380 :
381 : struct HDF4GDsHandle
382 : {
383 : int32 m_handle;
384 :
385 3 : explicit HDF4GDsHandle(int32 handle) : m_handle(handle)
386 : {
387 3 : }
388 :
389 3 : ~HDF4GDsHandle()
390 3 : {
391 6 : CPLMutexHolderD(&hHDF4Mutex);
392 3 : GDclose(m_handle);
393 3 : }
394 : };
395 :
396 : /************************************************************************/
397 : /* HDF4GDHandle */
398 : /************************************************************************/
399 :
400 : struct HDF4GDHandle
401 : {
402 : std::shared_ptr<HDF4GDsHandle> m_poGDsHandle;
403 : int32 m_handle;
404 :
405 3 : explicit HDF4GDHandle(const std::shared_ptr<HDF4GDsHandle> &poGDsHandle,
406 : int32 handle)
407 3 : : m_poGDsHandle(poGDsHandle), m_handle(handle)
408 : {
409 3 : }
410 :
411 3 : ~HDF4GDHandle()
412 3 : {
413 6 : CPLMutexHolderD(&hHDF4Mutex);
414 3 : GDdetach(m_handle);
415 3 : }
416 : };
417 :
418 : /************************************************************************/
419 : /* HDF4EOSGridsGroup */
420 : /************************************************************************/
421 :
422 : class HDF4EOSGridsGroup final : public GDALGroup
423 : {
424 : std::shared_ptr<HDF4SharedResources> m_poShared;
425 : std::shared_ptr<HDF4GDsHandle> m_poGDsHandle;
426 :
427 : public:
428 3 : HDF4EOSGridsGroup(const std::string &osParentName,
429 : const std::string &osName,
430 : const std::shared_ptr<HDF4SharedResources> &poShared,
431 : const std::shared_ptr<HDF4GDsHandle> &poGDsHandle)
432 3 : : GDALGroup(osParentName, osName), m_poShared(poShared),
433 3 : m_poGDsHandle(poGDsHandle)
434 : {
435 3 : }
436 :
437 : std::vector<std::string>
438 : GetGroupNames(CSLConstList papszOptions) const override;
439 : std::shared_ptr<GDALGroup> OpenGroup(const std::string &osName,
440 : CSLConstList) const override;
441 : };
442 :
443 : /************************************************************************/
444 : /* HDF4EOSGridGroup */
445 : /************************************************************************/
446 :
447 : class HDF4EOSGridGroup final : public GDALGroup
448 : {
449 : std::shared_ptr<HDF4SharedResources> m_poShared;
450 : std::shared_ptr<HDF4GDHandle> m_poGDHandle;
451 : mutable std::vector<std::shared_ptr<GDALDimension>> m_dims{};
452 : mutable std::shared_ptr<GDALMDArray> m_varX{};
453 : mutable std::shared_ptr<GDALMDArray> m_varY{};
454 :
455 : public:
456 3 : HDF4EOSGridGroup(const std::string &osParentName, const std::string &osName,
457 : const std::shared_ptr<HDF4SharedResources> &poShared,
458 : const std::shared_ptr<HDF4GDHandle> &poGDHandle)
459 3 : : GDALGroup(osParentName, osName), m_poShared(poShared),
460 3 : m_poGDHandle(poGDHandle)
461 : {
462 3 : }
463 :
464 : std::vector<std::shared_ptr<GDALDimension>>
465 : GetDimensions(CSLConstList papszOptions = nullptr) const override;
466 :
467 : std::vector<std::string>
468 : GetMDArrayNames(CSLConstList papszOptions) const override;
469 : std::shared_ptr<GDALMDArray>
470 : OpenMDArray(const std::string &osName,
471 : CSLConstList papszOptions) const override;
472 :
473 : std::vector<std::string>
474 : GetGroupNames(CSLConstList papszOptions) const override;
475 : std::shared_ptr<GDALGroup> OpenGroup(const std::string &osName,
476 : CSLConstList) const override;
477 :
478 : std::vector<std::shared_ptr<GDALAttribute>>
479 : GetAttributes(CSLConstList papszOptions = nullptr) const override;
480 : };
481 :
482 : /************************************************************************/
483 : /* HDF4EOSGridSubGroup */
484 : /************************************************************************/
485 :
486 : class HDF4EOSGridSubGroup final : public GDALGroup
487 : {
488 : std::shared_ptr<HDF4SharedResources> m_poShared;
489 : std::shared_ptr<HDF4GDHandle> m_poGDHandle;
490 : int32 m_entryType;
491 : std::vector<std::shared_ptr<GDALDimension>> m_groupDims{};
492 :
493 : public:
494 3 : HDF4EOSGridSubGroup(
495 : const std::string &osParentName, const std::string &osName,
496 : const std::shared_ptr<HDF4SharedResources> &poShared,
497 : const std::shared_ptr<HDF4GDHandle> &poGDHandle, int32 entryType,
498 : const std::vector<std::shared_ptr<GDALDimension>> &groupDims)
499 3 : : GDALGroup(osParentName, osName), m_poShared(poShared),
500 : m_poGDHandle(poGDHandle), m_entryType(entryType),
501 3 : m_groupDims(groupDims)
502 : {
503 3 : }
504 :
505 : std::vector<std::string>
506 : GetMDArrayNames(CSLConstList papszOptions) const override;
507 : std::shared_ptr<GDALMDArray>
508 : OpenMDArray(const std::string &osName,
509 : CSLConstList papszOptions) const override;
510 : };
511 :
512 : /************************************************************************/
513 : /* HDF4EOSGridArray */
514 : /************************************************************************/
515 :
516 : class HDF4EOSGridArray final : public GDALPamMDArray
517 : {
518 : std::shared_ptr<HDF4SharedResources> m_poShared;
519 : std::shared_ptr<HDF4GDHandle> m_poGDHandle;
520 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
521 : GDALExtendedDataType m_dt = GDALExtendedDataType::Create(GDT_Unknown);
522 : mutable std::vector<GByte> m_abyNoData{};
523 : mutable std::string m_osUnit{};
524 :
525 : protected:
526 : HDF4EOSGridArray(
527 : const std::string &osParentName, const std::string &osName,
528 : const std::shared_ptr<HDF4SharedResources> &poShared,
529 : const std::shared_ptr<HDF4GDHandle> &poGDHandle,
530 : const std::vector<int32> &aiDimSizes, const std::string &dimNames,
531 : int32 iNumType,
532 : const std::vector<std::shared_ptr<GDALDimension>> &groupDims);
533 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
534 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
535 : const GDALExtendedDataType &bufferDataType,
536 : void *pDstBuffer) const override;
537 :
538 : public:
539 : static std::shared_ptr<HDF4EOSGridArray>
540 1 : Create(const std::string &osParentName, const std::string &osName,
541 : const std::shared_ptr<HDF4SharedResources> &poShared,
542 : const std::shared_ptr<HDF4GDHandle> &poGDHandle,
543 : const std::vector<int32> &aiDimSizes, const std::string &dimNames,
544 : int32 iNumType,
545 : const std::vector<std::shared_ptr<GDALDimension>> &groupDims)
546 : {
547 : auto ar(std::shared_ptr<HDF4EOSGridArray>(
548 : new HDF4EOSGridArray(osParentName, osName, poShared, poGDHandle,
549 1 : aiDimSizes, dimNames, iNumType, groupDims)));
550 1 : ar->SetSelf(ar);
551 1 : return ar;
552 : }
553 :
554 0 : bool IsWritable() const override
555 : {
556 0 : return false;
557 : }
558 :
559 0 : const std::string &GetFilename() const override
560 : {
561 0 : return m_poShared->GetFilename();
562 : }
563 :
564 : const std::vector<std::shared_ptr<GDALDimension>> &
565 2 : GetDimensions() const override
566 : {
567 2 : return m_dims;
568 : }
569 :
570 2 : const GDALExtendedDataType &GetDataType() const override
571 : {
572 2 : return m_dt;
573 : }
574 :
575 : std::vector<std::shared_ptr<GDALAttribute>>
576 : GetAttributes(CSLConstList papszOptions = nullptr) const override;
577 :
578 : const void *GetRawNoDataValue() const override;
579 :
580 : double GetOffset(bool *pbHasOffset = nullptr,
581 : GDALDataType *peStorageType = nullptr) const override;
582 :
583 : double GetScale(bool *pbHasScale = nullptr,
584 : GDALDataType *peStorageType = nullptr) const override;
585 :
586 : const std::string &GetUnit() const override;
587 :
588 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override;
589 :
590 0 : std::shared_ptr<GDALGroup> GetRootGroup() const override
591 : {
592 0 : return HDF4Group::Create(std::string(), "/", m_poShared);
593 : }
594 : };
595 :
596 : /************************************************************************/
597 : /* HDF4EOSGridAttribute */
598 : /************************************************************************/
599 :
600 : class HDF4EOSGridAttribute final : public HDF4AbstractAttribute
601 : {
602 : std::shared_ptr<HDF4GDHandle> m_poGDHandle;
603 :
604 : public:
605 0 : HDF4EOSGridAttribute(const std::string &osParentName,
606 : const std::string &osName,
607 : const std::shared_ptr<HDF4SharedResources> &poShared,
608 : const std::shared_ptr<HDF4GDHandle> &poGDHandle,
609 : int32 iNumType, int32 nValues)
610 0 : : GDALAbstractMDArray(osParentName, osName),
611 : HDF4AbstractAttribute(osParentName, osName, poShared, iNumType,
612 : nValues),
613 0 : m_poGDHandle(poGDHandle)
614 : {
615 0 : }
616 :
617 : void ReadData(void *pDstBuffer) const override;
618 : };
619 :
620 0 : void HDF4EOSGridAttribute::ReadData(void *pDstBuffer) const
621 : {
622 0 : GDreadattr(m_poGDHandle->m_handle, GetName().c_str(), pDstBuffer);
623 0 : }
624 :
625 : /************************************************************************/
626 : /* HDF4SDSGroup */
627 : /************************************************************************/
628 :
629 : class HDF4SDSGroup final : public GDALGroup
630 : {
631 : std::shared_ptr<HDF4SharedResources> m_poShared;
632 : mutable std::map<std::string, int> m_oMapNameToSDSIdx{};
633 : mutable std::vector<std::shared_ptr<GDALDimension>> m_dims{};
634 : mutable std::vector<std::shared_ptr<GDALMDArray>> m_oSetIndexingVariables{};
635 : mutable bool m_bInGetDimensions = false;
636 : bool m_bIsGDALDataset = false;
637 : std::vector<std::shared_ptr<GDALAttribute>> m_oGlobalAttributes{};
638 : mutable std::shared_ptr<GDALMDArray> m_varX{};
639 : mutable std::shared_ptr<GDALMDArray> m_varY{};
640 :
641 : public:
642 4 : HDF4SDSGroup(const std::string &osParentName, const std::string &osName,
643 : const std::shared_ptr<HDF4SharedResources> &poShared)
644 4 : : GDALGroup(osParentName, osName), m_poShared(poShared)
645 : {
646 4 : }
647 :
648 2 : void SetIsGDALDataset()
649 : {
650 2 : m_bIsGDALDataset = true;
651 2 : }
652 :
653 2 : void SetGlobalAttributes(
654 : const std::vector<std::shared_ptr<GDALAttribute>> &attrs)
655 : {
656 2 : m_oGlobalAttributes = attrs;
657 2 : }
658 :
659 : std::vector<std::shared_ptr<GDALDimension>>
660 : GetDimensions(CSLConstList papszOptions = nullptr) const override;
661 :
662 : std::vector<std::string>
663 : GetMDArrayNames(CSLConstList papszOptions) const override;
664 : std::shared_ptr<GDALMDArray>
665 : OpenMDArray(const std::string &osName,
666 : CSLConstList papszOptions) const override;
667 : };
668 :
669 : /************************************************************************/
670 : /* HDF4SDSArray */
671 : /************************************************************************/
672 :
673 : class HDF4SDSArray final : public GDALPamMDArray
674 : {
675 : std::shared_ptr<HDF4SharedResources> m_poShared;
676 : int32 m_iSDS;
677 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
678 : GDALExtendedDataType m_dt = GDALExtendedDataType::Create(GDT_Unknown);
679 : int32 m_nAttributes;
680 : mutable std::string m_osUnit{};
681 : std::vector<std::shared_ptr<GDALAttribute>> m_oGlobalAttributes{};
682 : bool m_bIsGDALDataset;
683 : mutable std::vector<GByte> m_abyNoData{};
684 :
685 : protected:
686 : HDF4SDSArray(const std::string &osParentName, const std::string &osName,
687 : const std::shared_ptr<HDF4SharedResources> &poShared,
688 : int32 iSDS, const std::vector<int32> &aiDimSizes,
689 : const std::vector<std::shared_ptr<GDALDimension>> &groupDims,
690 : int32 iNumType, int32 nAttrs, bool bIsGDALDS);
691 :
692 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
693 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
694 : const GDALExtendedDataType &bufferDataType,
695 : void *pDstBuffer) const override;
696 :
697 : public:
698 : static std::shared_ptr<HDF4SDSArray>
699 8 : Create(const std::string &osParentName, const std::string &osName,
700 : const std::shared_ptr<HDF4SharedResources> &poShared, int32 iSDS,
701 : const std::vector<int32> &aiDimSizes,
702 : const std::vector<std::shared_ptr<GDALDimension>> &groupDims,
703 : int32 iNumType, int32 nAttrs, bool bIsGDALDS)
704 : {
705 : auto ar(std::shared_ptr<HDF4SDSArray>(
706 : new HDF4SDSArray(osParentName, osName, poShared, iSDS, aiDimSizes,
707 8 : groupDims, iNumType, nAttrs, bIsGDALDS)));
708 8 : ar->SetSelf(ar);
709 8 : return ar;
710 : }
711 :
712 : ~HDF4SDSArray() override;
713 :
714 2 : void SetGlobalAttributes(
715 : const std::vector<std::shared_ptr<GDALAttribute>> &attrs)
716 : {
717 2 : m_oGlobalAttributes = attrs;
718 2 : }
719 :
720 0 : bool IsWritable() const override
721 : {
722 0 : return false;
723 : }
724 :
725 8 : const std::string &GetFilename() const override
726 : {
727 8 : return m_poShared->GetFilename();
728 : }
729 :
730 : const std::vector<std::shared_ptr<GDALDimension>> &
731 28 : GetDimensions() const override
732 : {
733 28 : return m_dims;
734 : }
735 :
736 17 : const GDALExtendedDataType &GetDataType() const override
737 : {
738 17 : return m_dt;
739 : }
740 :
741 : std::vector<std::shared_ptr<GDALAttribute>>
742 : GetAttributes(CSLConstList papszOptions = nullptr) const override;
743 :
744 : const void *GetRawNoDataValue() const override;
745 :
746 : double GetOffset(bool *pbHasOffset = nullptr,
747 : GDALDataType *peStorageType = nullptr) const override;
748 :
749 : double GetScale(bool *pbHasScale = nullptr,
750 : GDALDataType *peStorageType = nullptr) const override;
751 :
752 : const std::string &GetUnit() const override;
753 :
754 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override;
755 :
756 0 : std::shared_ptr<GDALGroup> GetRootGroup() const override
757 : {
758 0 : return HDF4Group::Create(std::string(), "/", m_poShared);
759 : }
760 : };
761 :
762 : /************************************************************************/
763 : /* HDF4GRsHandle */
764 : /************************************************************************/
765 :
766 : struct HDF4GRsHandle
767 : {
768 : int32 m_hHandle;
769 : int32 m_grHandle;
770 :
771 2 : explicit HDF4GRsHandle(int32 hHandle, int32 grHandle)
772 2 : : m_hHandle(hHandle), m_grHandle(grHandle)
773 : {
774 2 : }
775 :
776 2 : ~HDF4GRsHandle()
777 2 : {
778 4 : CPLMutexHolderD(&hHDF4Mutex);
779 2 : GRend(m_grHandle);
780 2 : Hclose(m_hHandle);
781 2 : }
782 : };
783 :
784 : /************************************************************************/
785 : /* HDF4GRHandle */
786 : /************************************************************************/
787 :
788 : struct HDF4GRHandle
789 : {
790 : std::shared_ptr<HDF4GRsHandle> m_poGRsHandle;
791 : int32 m_iGR;
792 :
793 2 : explicit HDF4GRHandle(const std::shared_ptr<HDF4GRsHandle> &poGRsHandle,
794 : int32 iGR)
795 2 : : m_poGRsHandle(poGRsHandle), m_iGR(iGR)
796 : {
797 2 : }
798 :
799 2 : ~HDF4GRHandle()
800 2 : {
801 4 : CPLMutexHolderD(&hHDF4Mutex);
802 2 : GRendaccess(m_iGR);
803 2 : }
804 : };
805 :
806 : /************************************************************************/
807 : /* HDF4GRsGroup */
808 : /************************************************************************/
809 :
810 : class HDF4GRsGroup final : public GDALGroup
811 : {
812 : std::shared_ptr<HDF4SharedResources> m_poShared;
813 : std::shared_ptr<HDF4GRsHandle> m_poGRsHandle;
814 : mutable std::map<std::string, int> m_oMapNameToGRIdx{};
815 :
816 : public:
817 2 : HDF4GRsGroup(const std::string &osParentName, const std::string &osName,
818 : const std::shared_ptr<HDF4SharedResources> &poShared,
819 : const std::shared_ptr<HDF4GRsHandle> &poGRsHandle)
820 2 : : GDALGroup(osParentName, osName), m_poShared(poShared),
821 2 : m_poGRsHandle(poGRsHandle)
822 : {
823 2 : }
824 :
825 : std::vector<std::string>
826 : GetMDArrayNames(CSLConstList papszOptions) const override;
827 : std::shared_ptr<GDALMDArray>
828 : OpenMDArray(const std::string &osName,
829 : CSLConstList papszOptions) const override;
830 :
831 : std::vector<std::shared_ptr<GDALAttribute>>
832 : GetAttributes(CSLConstList papszOptions = nullptr) const override;
833 : };
834 :
835 : /************************************************************************/
836 : /* HDF4GRArray */
837 : /************************************************************************/
838 :
839 : class HDF4GRArray final : public GDALPamMDArray
840 : {
841 : std::shared_ptr<HDF4SharedResources> m_poShared;
842 : std::shared_ptr<HDF4GRHandle> m_poGRHandle;
843 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
844 : GDALExtendedDataType m_dt = GDALExtendedDataType::Create(GDT_Unknown);
845 : int32 m_nAttributes;
846 :
847 : protected:
848 : HDF4GRArray(const std::string &osParentName, const std::string &osName,
849 : const std::shared_ptr<HDF4SharedResources> &poShared,
850 : const std::shared_ptr<HDF4GRHandle> &poGRHandle, int32 nBands,
851 : const std::vector<int32> &aiDimSizes, int32 iNumType,
852 : int32 nAttrs);
853 :
854 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
855 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
856 : const GDALExtendedDataType &bufferDataType,
857 : void *pDstBuffer) const override;
858 :
859 : public:
860 : static std::shared_ptr<HDF4GRArray>
861 2 : Create(const std::string &osParentName, const std::string &osName,
862 : const std::shared_ptr<HDF4SharedResources> &poShared,
863 : const std::shared_ptr<HDF4GRHandle> &poGRHandle, int32 nBands,
864 : const std::vector<int32> &aiDimSizes, int32 iNumType, int32 nAttrs)
865 : {
866 : auto ar(std::shared_ptr<HDF4GRArray>(
867 : new HDF4GRArray(osParentName, osName, poShared, poGRHandle, nBands,
868 2 : aiDimSizes, iNumType, nAttrs)));
869 2 : ar->SetSelf(ar);
870 2 : return ar;
871 : }
872 :
873 : bool IsWritable() const override;
874 :
875 2 : const std::string &GetFilename() const override
876 : {
877 2 : return m_poShared->GetFilename();
878 : }
879 :
880 : const std::vector<std::shared_ptr<GDALDimension>> &
881 20 : GetDimensions() const override
882 : {
883 20 : return m_dims;
884 : }
885 :
886 12 : const GDALExtendedDataType &GetDataType() const override
887 : {
888 12 : return m_dt;
889 : }
890 :
891 : std::vector<std::shared_ptr<GDALAttribute>>
892 : GetAttributes(CSLConstList papszOptions = nullptr) const override;
893 :
894 0 : std::shared_ptr<GDALGroup> GetRootGroup() const override
895 : {
896 0 : return HDF4Group::Create(std::string(), "/", m_poShared);
897 : }
898 : };
899 :
900 0 : bool HDF4GRArray::IsWritable() const
901 : {
902 0 : return false;
903 : }
904 :
905 : /************************************************************************/
906 : /* HDF4SDAttribute */
907 : /************************************************************************/
908 :
909 : class HDF4SDAttribute final : public HDF4AbstractAttribute
910 : {
911 : std::shared_ptr<HDF4SwathHandle> m_poSwathHandle;
912 : std::shared_ptr<HDF4GDHandle> m_poGDHandle;
913 : int32 m_sdHandle = 0;
914 : int32 m_iAttribute = 0;
915 :
916 : public:
917 18 : HDF4SDAttribute(const std::string &osParentName, const std::string &osName,
918 : const std::shared_ptr<HDF4SharedResources> &poShared,
919 : const std::shared_ptr<HDF4SwathHandle> &poSwathHandle,
920 : const std::shared_ptr<HDF4GDHandle> &poGDHandle,
921 : int32 sdHandle, int32 iAttribute, int32 iNumType,
922 : int32 nValues)
923 18 : : GDALAbstractMDArray(osParentName, osName),
924 : HDF4AbstractAttribute(osParentName, osName, poShared, iNumType,
925 : nValues),
926 : m_poSwathHandle(poSwathHandle), m_poGDHandle(poGDHandle),
927 18 : m_sdHandle(sdHandle), m_iAttribute(iAttribute)
928 : {
929 18 : }
930 :
931 : void ReadData(void *pDstBuffer) const override;
932 : };
933 :
934 10 : void HDF4SDAttribute::ReadData(void *pDstBuffer) const
935 : {
936 10 : SDreadattr(m_sdHandle, m_iAttribute, pDstBuffer);
937 10 : }
938 :
939 : /************************************************************************/
940 : /* HDF4GRAttribute */
941 : /************************************************************************/
942 :
943 : class HDF4GRAttribute final : public HDF4AbstractAttribute
944 : {
945 : std::shared_ptr<HDF4GRsHandle> m_poGRsHandle;
946 : std::shared_ptr<HDF4GRHandle> m_poGRHandle;
947 : int32 m_grHandle = 0;
948 : int32 m_iAttribute = 0;
949 :
950 : public:
951 10 : HDF4GRAttribute(const std::string &osParentName, const std::string &osName,
952 : const std::shared_ptr<HDF4SharedResources> &poShared,
953 : const std::shared_ptr<HDF4GRsHandle> &poGRsHandle,
954 : const std::shared_ptr<HDF4GRHandle> &poGRHandle,
955 : int32 iGRHandle, int32 iAttribute, int32 iNumType,
956 : int32 nValues)
957 10 : : GDALAbstractMDArray(osParentName, osName),
958 : HDF4AbstractAttribute(osParentName, osName, poShared, iNumType,
959 : nValues),
960 : m_poGRsHandle(poGRsHandle), m_poGRHandle(poGRHandle),
961 10 : m_grHandle(iGRHandle), m_iAttribute(iAttribute)
962 : {
963 10 : }
964 :
965 : void ReadData(void *pDstBuffer) const override;
966 : };
967 :
968 3 : void HDF4GRAttribute::ReadData(void *pDstBuffer) const
969 : {
970 3 : GRgetattr(m_grHandle, m_iAttribute, pDstBuffer);
971 3 : }
972 :
973 : /************************************************************************/
974 : /* HDF4GRPalette */
975 : /************************************************************************/
976 :
977 : class HDF4GRPalette final : public GDALAttribute
978 : {
979 : std::shared_ptr<HDF4SharedResources> m_poShared;
980 : std::shared_ptr<HDF4GRHandle> m_poGRHandle;
981 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
982 : GDALExtendedDataType m_dt = GDALExtendedDataType::Create(GDT_UInt8);
983 : int32 m_iPal = 0;
984 : int32 m_nValues = 0;
985 :
986 : protected:
987 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
988 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
989 : const GDALExtendedDataType &bufferDataType,
990 : void *pDstBuffer) const override;
991 :
992 : public:
993 : HDF4GRPalette(const std::string &osParentName, const std::string &osName,
994 : const std::shared_ptr<HDF4SharedResources> &poShared,
995 : const std::shared_ptr<HDF4GRHandle> &poGRHandle, int32 iPal,
996 : int32 nValues);
997 :
998 : const std::vector<std::shared_ptr<GDALDimension>> &
999 : GetDimensions() const override;
1000 :
1001 2 : const GDALExtendedDataType &GetDataType() const override
1002 : {
1003 2 : return m_dt;
1004 : }
1005 : };
1006 :
1007 : const std::vector<std::shared_ptr<GDALDimension>> &
1008 5 : HDF4GRPalette::GetDimensions() const
1009 : {
1010 5 : return m_dims;
1011 : }
1012 :
1013 : /************************************************************************/
1014 : /* HDF4SharedResources() */
1015 : /************************************************************************/
1016 :
1017 12 : HDF4SharedResources::HDF4SharedResources(const std::string &osFilename)
1018 : : m_osFilename(osFilename),
1019 12 : m_poPAM(std::make_shared<GDALPamMultiDim>(osFilename))
1020 : {
1021 12 : }
1022 :
1023 : /************************************************************************/
1024 : /* ~HDF4SharedResources() */
1025 : /************************************************************************/
1026 :
1027 12 : HDF4SharedResources::~HDF4SharedResources()
1028 : {
1029 24 : CPLMutexHolderD(&hHDF4Mutex);
1030 :
1031 12 : if (m_hSD)
1032 12 : SDend(m_hSD);
1033 12 : }
1034 :
1035 : /************************************************************************/
1036 : /* HDF4Group() */
1037 : /************************************************************************/
1038 :
1039 12 : HDF4Group::HDF4Group(const std::string &osParentName, const std::string &osName,
1040 12 : const std::shared_ptr<HDF4SharedResources> &poShared)
1041 12 : : GDALGroup(osParentName, osName), m_poShared(poShared)
1042 : {
1043 12 : bool bIsGDALDS = false;
1044 36 : auto poAttr = GetAttribute("Signature");
1045 12 : if (poAttr && poAttr->GetDataType().GetClass() == GEDTC_STRING)
1046 : {
1047 2 : const char *pszVal = poAttr->ReadAsString();
1048 2 : if (pszVal && EQUAL(pszVal, pszGDALSignature))
1049 : {
1050 2 : bIsGDALDS = true;
1051 : }
1052 : }
1053 12 : if (bIsGDALDS)
1054 : {
1055 : m_poGDALGroup =
1056 2 : std::make_shared<HDF4SDSGroup>(std::string(), "/", m_poShared);
1057 2 : m_poGDALGroup->SetIsGDALDataset();
1058 2 : m_poGDALGroup->SetGlobalAttributes(GetAttributes(nullptr));
1059 : }
1060 12 : }
1061 :
1062 : /************************************************************************/
1063 : /* GetAttributes() */
1064 : /************************************************************************/
1065 :
1066 : std::vector<std::shared_ptr<GDALAttribute>>
1067 21 : HDF4Group::GetAttributes(CSLConstList) const
1068 : {
1069 42 : CPLMutexHolderD(&hHDF4Mutex);
1070 21 : std::vector<std::shared_ptr<GDALAttribute>> ret;
1071 21 : int32 nDatasets = 0;
1072 21 : int32 nAttributes = 0;
1073 21 : if (SDfileinfo(m_poShared->GetSDHandle(), &nDatasets, &nAttributes) != 0)
1074 0 : return ret;
1075 :
1076 42 : std::map<CPLString, std::shared_ptr<GDALAttribute>> oMapAttrs;
1077 : const auto AddAttribute =
1078 56 : [&ret, &oMapAttrs](const std::shared_ptr<GDALAttribute> &poNewAttr)
1079 : {
1080 14 : auto oIter = oMapAttrs.find(poNewAttr->GetName());
1081 14 : if (oIter != oMapAttrs.end())
1082 : {
1083 0 : const char *pszOldVal = oIter->second->ReadAsString();
1084 0 : const char *pszNewVal = poNewAttr->ReadAsString();
1085 : // As found in MOD35_L2.A2017161.1525.061.2017315035809.hdf
1086 : // product of https://github.com/OSGeo/gdal/issues/2848,
1087 : // the identifier_product_doi attribute is found in a
1088 : // HDF4EOS attribute bundle, as well as a standalone attribute
1089 0 : if (pszOldVal && pszNewVal && strcmp(pszOldVal, pszNewVal) == 0)
1090 0 : return;
1091 : // TODO
1092 0 : CPLDebug("HDF4",
1093 : "Attribute with same name (%s) found, but different value",
1094 0 : poNewAttr->GetName().c_str());
1095 : }
1096 : // cppcheck-suppress unreadVariable
1097 14 : oMapAttrs[poNewAttr->GetName()] = poNewAttr;
1098 14 : ret.emplace_back(poNewAttr);
1099 21 : };
1100 :
1101 47 : for (int32 iAttribute = 0; iAttribute < nAttributes; iAttribute++)
1102 : {
1103 26 : int32 iNumType = 0;
1104 26 : int32 nValues = 0;
1105 :
1106 26 : std::string osAttrName;
1107 26 : osAttrName.resize(H4_MAX_NC_NAME);
1108 26 : SDattrinfo(m_poShared->GetSDHandle(), iAttribute, &osAttrName[0],
1109 : &iNumType, &nValues);
1110 26 : osAttrName.resize(strlen(osAttrName.c_str()));
1111 :
1112 26 : if (STARTS_WITH_CI(osAttrName.c_str(), "coremetadata") ||
1113 26 : STARTS_WITH_CI(osAttrName.c_str(), "archivemetadata.") ||
1114 26 : STARTS_WITH_CI(osAttrName.c_str(), "productmetadata.") ||
1115 26 : STARTS_WITH_CI(osAttrName.c_str(), "badpixelinformation") ||
1116 26 : STARTS_WITH_CI(osAttrName.c_str(), "product_summary") ||
1117 26 : STARTS_WITH_CI(osAttrName.c_str(), "dem_specific") ||
1118 26 : STARTS_WITH_CI(osAttrName.c_str(), "bts_specific") ||
1119 26 : STARTS_WITH_CI(osAttrName.c_str(), "etse_specific") ||
1120 26 : STARTS_WITH_CI(osAttrName.c_str(), "dst_specific") ||
1121 26 : STARTS_WITH_CI(osAttrName.c_str(), "acv_specific") ||
1122 26 : STARTS_WITH_CI(osAttrName.c_str(), "act_specific") ||
1123 78 : STARTS_WITH_CI(osAttrName.c_str(), "etst_specific") ||
1124 26 : STARTS_WITH_CI(osAttrName.c_str(), "level_1_carryover"))
1125 : {
1126 0 : char **papszMD = HDF4Dataset::TranslateHDF4EOSAttributes(
1127 0 : m_poShared->GetSDHandle(), iAttribute, nValues, nullptr);
1128 0 : for (char **iter = papszMD; iter && *iter; ++iter)
1129 : {
1130 0 : char *pszKey = nullptr;
1131 0 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
1132 0 : if (pszKey && pszValue)
1133 : {
1134 0 : AddAttribute(std::make_shared<GDALAttributeString>(
1135 0 : GetFullName(), pszKey, pszValue));
1136 : }
1137 0 : CPLFree(pszKey);
1138 : }
1139 0 : CSLDestroy(papszMD);
1140 : }
1141 :
1142 : // Skip "StructMetadata.N" records. We will fetch information
1143 : // from them using HDF-EOS API
1144 26 : else if (STARTS_WITH_CI(osAttrName.c_str(), "structmetadata."))
1145 : {
1146 12 : continue;
1147 : }
1148 : else
1149 : {
1150 14 : AddAttribute(std::make_shared<HDF4SDAttribute>(
1151 0 : GetFullName(), osAttrName, m_poShared, nullptr, nullptr,
1152 28 : m_poShared->GetSDHandle(), iAttribute, iNumType, nValues));
1153 : }
1154 : }
1155 21 : return ret;
1156 : }
1157 :
1158 : /************************************************************************/
1159 : /* GetGroupNames() */
1160 : /************************************************************************/
1161 :
1162 12 : std::vector<std::string> HDF4Group::GetGroupNames(CSLConstList) const
1163 : {
1164 12 : if (m_poGDALGroup)
1165 2 : return {};
1166 :
1167 20 : CPLMutexHolderD(&hHDF4Mutex);
1168 20 : std::vector<std::string> res;
1169 10 : auto sw_handle = SWopen(m_poShared->GetFilename().c_str(), DFACC_READ);
1170 10 : if (sw_handle >= 0)
1171 : {
1172 10 : int32 nStrBufSize = 0;
1173 10 : int32 nSubDatasets = SWinqswath(m_poShared->GetFilename().c_str(),
1174 : nullptr, &nStrBufSize);
1175 10 : if (nSubDatasets > 0)
1176 : {
1177 3 : res.emplace_back("swaths");
1178 : }
1179 10 : SWclose(sw_handle);
1180 : }
1181 :
1182 10 : auto gd_handle = GDopen(m_poShared->GetFilename().c_str(), DFACC_READ);
1183 10 : if (gd_handle >= 0)
1184 : {
1185 10 : int32 nStrBufSize = 0;
1186 : int32 nSubDatasets =
1187 10 : GDinqgrid(m_poShared->GetFilename().c_str(), nullptr, &nStrBufSize);
1188 10 : if (nSubDatasets > 0)
1189 : {
1190 3 : res.emplace_back("eos_grids");
1191 : }
1192 10 : GDclose(gd_handle);
1193 : }
1194 :
1195 10 : const char *pszListSDS = m_poShared->FetchOpenOption("LIST_SDS", "AUTO");
1196 16 : if ((res.empty() && EQUAL(pszListSDS, "AUTO")) ||
1197 6 : (!EQUAL(pszListSDS, "AUTO") && CPLTestBool(pszListSDS)))
1198 : {
1199 4 : int32 nDatasets = 0;
1200 4 : int32 nAttrs = 0;
1201 8 : if (SDfileinfo(m_poShared->GetSDHandle(), &nDatasets, &nAttrs) == 0 &&
1202 4 : nDatasets > 0)
1203 : {
1204 2 : res.emplace_back("scientific_datasets");
1205 : }
1206 : }
1207 :
1208 10 : auto hHandle = Hopen(m_poShared->GetFilename().c_str(), DFACC_READ, 0);
1209 10 : if (hHandle >= 0)
1210 : {
1211 10 : auto grHandle = GRstart(hHandle);
1212 10 : if (grHandle >= 0)
1213 : {
1214 10 : int32 nImages = 0;
1215 10 : int32 nAttrs = 0;
1216 10 : if (GRfileinfo(grHandle, &nImages, &nAttrs) == 0 && nImages > 0)
1217 : {
1218 2 : res.emplace_back("general_rasters");
1219 : }
1220 10 : GRend(grHandle);
1221 : }
1222 10 : Hclose(hHandle);
1223 : }
1224 :
1225 10 : return res;
1226 : }
1227 :
1228 : /************************************************************************/
1229 : /* OpenGroup() */
1230 : /************************************************************************/
1231 :
1232 13 : std::shared_ptr<GDALGroup> HDF4Group::OpenGroup(const std::string &osName,
1233 : CSLConstList) const
1234 : {
1235 13 : if (m_poGDALGroup)
1236 2 : return nullptr;
1237 :
1238 22 : CPLMutexHolderD(&hHDF4Mutex);
1239 11 : if (osName == "swaths")
1240 : {
1241 3 : auto handle = SWopen(m_poShared->GetFilename().c_str(), DFACC_READ);
1242 3 : if (handle >= 0)
1243 6 : return std::make_shared<HDF4SwathsGroup>(
1244 3 : GetFullName(), osName, m_poShared,
1245 9 : std::make_shared<HDF4SwathsHandle>(handle));
1246 : }
1247 8 : if (osName == "eos_grids")
1248 : {
1249 3 : auto handle = GDopen(m_poShared->GetFilename().c_str(), DFACC_READ);
1250 3 : if (handle >= 0)
1251 6 : return std::make_shared<HDF4EOSGridsGroup>(
1252 3 : GetFullName(), osName, m_poShared,
1253 9 : std::make_shared<HDF4GDsHandle>(handle));
1254 : }
1255 5 : if (osName == "scientific_datasets")
1256 : {
1257 4 : return std::make_shared<HDF4SDSGroup>(GetFullName(), osName,
1258 4 : m_poShared);
1259 : }
1260 3 : if (osName == "general_rasters")
1261 : {
1262 2 : auto hHandle = Hopen(m_poShared->GetFilename().c_str(), DFACC_READ, 0);
1263 2 : if (hHandle >= 0)
1264 : {
1265 2 : auto grHandle = GRstart(hHandle);
1266 2 : if (grHandle >= 0)
1267 : {
1268 4 : return std::make_shared<HDF4GRsGroup>(
1269 2 : GetFullName(), osName, m_poShared,
1270 6 : std::make_shared<HDF4GRsHandle>(hHandle, grHandle));
1271 : }
1272 : else
1273 : {
1274 0 : Hclose(hHandle);
1275 : }
1276 : }
1277 : }
1278 1 : return nullptr;
1279 : }
1280 :
1281 : /************************************************************************/
1282 : /* GetMDArrayNames() */
1283 : /************************************************************************/
1284 :
1285 9 : std::vector<std::string> HDF4Group::GetMDArrayNames(CSLConstList) const
1286 : {
1287 9 : if (m_poGDALGroup)
1288 2 : return m_poGDALGroup->GetMDArrayNames(nullptr);
1289 7 : return {};
1290 : }
1291 :
1292 : /************************************************************************/
1293 : /* OpenMDArray() */
1294 : /************************************************************************/
1295 :
1296 11 : std::shared_ptr<GDALMDArray> HDF4Group::OpenMDArray(const std::string &osName,
1297 : CSLConstList) const
1298 : {
1299 11 : if (m_poGDALGroup)
1300 4 : return m_poGDALGroup->OpenMDArray(osName, nullptr);
1301 7 : return nullptr;
1302 : }
1303 :
1304 : /************************************************************************/
1305 : /* GetDimensions() */
1306 : /************************************************************************/
1307 :
1308 : std::vector<std::shared_ptr<GDALDimension>>
1309 8 : HDF4Group::GetDimensions(CSLConstList) const
1310 : {
1311 8 : if (m_poGDALGroup)
1312 2 : return m_poGDALGroup->GetDimensions(nullptr);
1313 6 : return {};
1314 : }
1315 :
1316 : /************************************************************************/
1317 : /* GetGroupNames() */
1318 : /************************************************************************/
1319 :
1320 3 : std::vector<std::string> HDF4SwathsGroup::GetGroupNames(CSLConstList) const
1321 : {
1322 6 : CPLMutexHolderD(&hHDF4Mutex);
1323 3 : std::vector<std::string> res;
1324 :
1325 3 : int32 nStrBufSize = 0;
1326 3 : SWinqswath(m_poShared->GetFilename().c_str(), nullptr, &nStrBufSize);
1327 :
1328 6 : std::string osSwathList;
1329 3 : osSwathList.resize(nStrBufSize);
1330 3 : SWinqswath(m_poShared->GetFilename().c_str(), &osSwathList[0],
1331 : &nStrBufSize);
1332 :
1333 : CPLStringList aosSwaths(
1334 6 : CSLTokenizeString2(osSwathList.c_str(), ",", CSLT_HONOURSTRINGS));
1335 6 : for (int i = 0; i < aosSwaths.size(); i++)
1336 3 : res.push_back(aosSwaths[i]);
1337 :
1338 6 : return res;
1339 : }
1340 :
1341 : /************************************************************************/
1342 : /* OpenGroup() */
1343 : /************************************************************************/
1344 :
1345 3 : std::shared_ptr<GDALGroup> HDF4SwathsGroup::OpenGroup(const std::string &osName,
1346 : CSLConstList) const
1347 : {
1348 6 : CPLMutexHolderD(&hHDF4Mutex);
1349 :
1350 3 : int32 swathHandle = SWattach(m_poSwathsHandle->m_handle, osName.c_str());
1351 3 : if (swathHandle < 0)
1352 : {
1353 0 : return nullptr;
1354 : }
1355 :
1356 6 : return std::make_shared<HDF4SwathGroup>(
1357 3 : GetFullName(), osName, m_poShared,
1358 9 : std::make_shared<HDF4SwathHandle>(m_poSwathsHandle, swathHandle));
1359 : }
1360 :
1361 : /************************************************************************/
1362 : /* GetMDArrayNames() */
1363 : /************************************************************************/
1364 :
1365 6 : std::vector<std::string> HDF4SwathSubGroup::GetMDArrayNames(CSLConstList) const
1366 : {
1367 12 : CPLMutexHolderD(&hHDF4Mutex);
1368 6 : std::vector<std::string> ret;
1369 :
1370 6 : int32 nStrBufSize = 0;
1371 : const int32 nFields =
1372 6 : SWnentries(m_poSwathHandle->m_handle, m_entryType, &nStrBufSize);
1373 12 : std::string osFieldList;
1374 6 : osFieldList.resize(nStrBufSize);
1375 12 : std::vector<int32> ranks(nFields);
1376 12 : std::vector<int32> numberTypes(nFields);
1377 :
1378 6 : if (m_entryType == HDFE_NENTDFLD)
1379 3 : SWinqdatafields(m_poSwathHandle->m_handle, &osFieldList[0], &ranks[0],
1380 3 : &numberTypes[0]);
1381 : else
1382 3 : SWinqgeofields(m_poSwathHandle->m_handle, &osFieldList[0], &ranks[0],
1383 3 : &numberTypes[0]);
1384 :
1385 : CPLStringList aosFields(
1386 12 : CSLTokenizeString2(osFieldList.c_str(), ",", CSLT_HONOURSTRINGS));
1387 8 : for (int i = 0; i < aosFields.size(); i++)
1388 2 : ret.push_back(aosFields[i]);
1389 :
1390 12 : return ret;
1391 : }
1392 :
1393 : /************************************************************************/
1394 : /* OpenMDArray() */
1395 : /************************************************************************/
1396 :
1397 : std::shared_ptr<GDALMDArray>
1398 2 : HDF4SwathSubGroup::OpenMDArray(const std::string &osName, CSLConstList) const
1399 : {
1400 4 : CPLMutexHolderD(&hHDF4Mutex);
1401 :
1402 : int32 iRank;
1403 : int32 iNumType;
1404 4 : std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
1405 4 : std::string dimNames;
1406 :
1407 2 : int32 nStrBufSize = 0;
1408 4 : if (SWnentries(m_poSwathHandle->m_handle, HDFE_NENTDIM, &nStrBufSize) < 0 ||
1409 2 : nStrBufSize <= 0)
1410 : {
1411 0 : return nullptr;
1412 : }
1413 2 : dimNames.resize(nStrBufSize);
1414 2 : if (SWfieldinfo(m_poSwathHandle->m_handle, osName.c_str(), &iRank,
1415 2 : &aiDimSizes[0], &iNumType, &dimNames[0],
1416 4 : nStrBufSize + 1) < 0)
1417 : {
1418 2 : return nullptr;
1419 : }
1420 0 : aiDimSizes.resize(iRank);
1421 :
1422 0 : return HDF4SwathArray::Create(GetFullName(), osName, m_poShared,
1423 0 : m_poSwathHandle, aiDimSizes, dimNames,
1424 0 : iNumType, m_groupDims);
1425 : }
1426 :
1427 : /************************************************************************/
1428 : /* GetGroupNames() */
1429 : /************************************************************************/
1430 :
1431 3 : std::vector<std::string> HDF4SwathGroup::GetGroupNames(CSLConstList) const
1432 : {
1433 3 : std::vector<std::string> res;
1434 3 : res.push_back("Data Fields");
1435 3 : res.push_back("Geolocation Fields");
1436 3 : return res;
1437 : }
1438 :
1439 : /************************************************************************/
1440 : /* OpenGroup() */
1441 : /************************************************************************/
1442 :
1443 6 : std::shared_ptr<GDALGroup> HDF4SwathGroup::OpenGroup(const std::string &osName,
1444 : CSLConstList) const
1445 : {
1446 6 : if (osName == "Data Fields")
1447 : {
1448 6 : return std::make_shared<HDF4SwathSubGroup>(
1449 3 : GetFullName(), osName, m_poShared, m_poSwathHandle, HDFE_NENTDFLD,
1450 9 : GetDimensions());
1451 : }
1452 3 : if (osName == "Geolocation Fields")
1453 : {
1454 6 : return std::make_shared<HDF4SwathSubGroup>(
1455 3 : GetFullName(), osName, m_poShared, m_poSwathHandle, HDFE_NENTGFLD,
1456 9 : GetDimensions());
1457 : }
1458 0 : return nullptr;
1459 : }
1460 :
1461 : /************************************************************************/
1462 : /* GetDimensions() */
1463 : /************************************************************************/
1464 :
1465 : std::vector<std::shared_ptr<GDALDimension>>
1466 9 : HDF4SwathGroup::GetDimensions(CSLConstList) const
1467 : {
1468 9 : if (!m_dims.empty())
1469 6 : return m_dims;
1470 6 : std::string dimNames;
1471 3 : int32 nStrBufSize = 0;
1472 6 : if (SWnentries(m_poSwathHandle->m_handle, HDFE_NENTDIM, &nStrBufSize) < 0 ||
1473 3 : nStrBufSize <= 0)
1474 : {
1475 0 : return m_dims;
1476 : }
1477 3 : dimNames.resize(nStrBufSize);
1478 3 : int32 nDims = SWinqdims(m_poSwathHandle->m_handle, &dimNames[0], nullptr);
1479 6 : std::vector<int32> aiDimSizes(nDims);
1480 3 : SWinqdims(m_poSwathHandle->m_handle, &dimNames[0], &aiDimSizes[0]);
1481 : CPLStringList aosDimNames(
1482 6 : CSLTokenizeString2(dimNames.c_str(), ",", CSLT_HONOURSTRINGS));
1483 3 : if (static_cast<size_t>(aosDimNames.size()) == aiDimSizes.size())
1484 : {
1485 56 : for (int i = 0; i < aosDimNames.size(); i++)
1486 : {
1487 53 : m_dims.push_back(std::make_shared<GDALDimension>(
1488 106 : GetFullName(), aosDimNames[i], std::string(), std::string(),
1489 53 : aiDimSizes[i]));
1490 : }
1491 : }
1492 3 : return m_dims;
1493 : }
1494 :
1495 : /************************************************************************/
1496 : /* GetAttributes() */
1497 : /************************************************************************/
1498 :
1499 : std::vector<std::shared_ptr<GDALAttribute>>
1500 3 : HDF4SwathGroup::GetAttributes(CSLConstList) const
1501 : {
1502 6 : CPLMutexHolderD(&hHDF4Mutex);
1503 3 : std::vector<std::shared_ptr<GDALAttribute>> ret;
1504 3 : int32 nStrBufSize = 0;
1505 3 : if (SWinqattrs(m_poSwathHandle->m_handle, nullptr, &nStrBufSize) <= 0 ||
1506 0 : nStrBufSize <= 0)
1507 : {
1508 3 : return ret;
1509 : }
1510 0 : std::string osAttrs;
1511 0 : osAttrs.resize(nStrBufSize);
1512 0 : SWinqattrs(m_poSwathHandle->m_handle, &osAttrs[0], &nStrBufSize);
1513 :
1514 : CPLStringList aosAttrs(
1515 0 : CSLTokenizeString2(osAttrs.c_str(), ",", CSLT_HONOURSTRINGS));
1516 0 : for (int i = 0; i < aosAttrs.size(); i++)
1517 : {
1518 0 : int32 iNumType = 0;
1519 0 : int32 nSize = 0;
1520 :
1521 0 : const auto &osAttrName = aosAttrs[i];
1522 0 : if (SWattrinfo(m_poSwathHandle->m_handle, osAttrName, &iNumType,
1523 0 : &nSize) < 0)
1524 0 : continue;
1525 0 : const int nDataTypeSize = HDF4Dataset::GetDataTypeSize(iNumType);
1526 0 : if (nDataTypeSize == 0)
1527 0 : continue;
1528 :
1529 0 : ret.emplace_back(std::make_shared<HDF4SwathAttribute>(
1530 0 : GetFullName(), osAttrName, m_poShared, m_poSwathHandle, iNumType,
1531 0 : nSize / nDataTypeSize));
1532 : }
1533 0 : return ret;
1534 : }
1535 :
1536 : /************************************************************************/
1537 : /* HDF4SwathArray() */
1538 : /************************************************************************/
1539 :
1540 0 : HDF4SwathArray::HDF4SwathArray(
1541 : const std::string &osParentName, const std::string &osName,
1542 : const std::shared_ptr<HDF4SharedResources> &poShared,
1543 : const std::shared_ptr<HDF4SwathHandle> &poSwathHandle,
1544 : const std::vector<int32> &aiDimSizes, const std::string &dimNames,
1545 : int32 iNumType,
1546 0 : const std::vector<std::shared_ptr<GDALDimension>> &groupDims)
1547 : : GDALAbstractMDArray(osParentName, osName),
1548 : GDALPamMDArray(osParentName, osName, poShared->GetPAM()),
1549 : m_poShared(poShared), m_poSwathHandle(poSwathHandle),
1550 : m_dt(iNumType == DFNT_CHAR8 ? GDALExtendedDataType::CreateString()
1551 : : GDALExtendedDataType::Create(
1552 0 : HDF4Dataset::GetDataType(iNumType)))
1553 : {
1554 : CPLStringList aosDimNames(
1555 0 : CSLTokenizeString2(dimNames.c_str(), ",", CSLT_HONOURSTRINGS));
1556 0 : if (static_cast<size_t>(aosDimNames.size()) == aiDimSizes.size())
1557 : {
1558 0 : for (int i = 0; i < aosDimNames.size(); i++)
1559 : {
1560 0 : bool bFound = false;
1561 0 : for (const auto &poDim : groupDims)
1562 : {
1563 0 : if (poDim->GetName() == aosDimNames[i] &&
1564 0 : poDim->GetSize() == static_cast<GUInt64>(aiDimSizes[i]))
1565 : {
1566 0 : bFound = true;
1567 0 : m_dims.push_back(poDim);
1568 0 : break;
1569 : }
1570 : }
1571 0 : if (!bFound)
1572 : {
1573 0 : m_dims.push_back(std::make_shared<GDALDimension>(
1574 0 : std::string(), aosDimNames[i], std::string(), std::string(),
1575 0 : aiDimSizes[i]));
1576 : }
1577 : }
1578 : }
1579 0 : }
1580 :
1581 : /************************************************************************/
1582 : /* GetAttributes() */
1583 : /************************************************************************/
1584 :
1585 : std::vector<std::shared_ptr<GDALAttribute>>
1586 0 : HDF4SwathArray::GetAttributes(CSLConstList) const
1587 : {
1588 0 : CPLMutexHolderD(&hHDF4Mutex);
1589 0 : std::vector<std::shared_ptr<GDALAttribute>> ret;
1590 0 : int32 iSDS = 0;
1591 0 : if (SWsdid(m_poSwathHandle->m_handle, GetName().c_str(), &iSDS) != -1)
1592 : {
1593 0 : int32 iRank = 0;
1594 0 : int32 iNumType = 0;
1595 0 : int32 nAttrs = 0;
1596 0 : std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
1597 :
1598 0 : if (SDgetinfo(iSDS, nullptr, &iRank, &aiDimSizes[0], &iNumType,
1599 0 : &nAttrs) == 0)
1600 : {
1601 0 : for (int32 iAttribute = 0; iAttribute < nAttrs; iAttribute++)
1602 : {
1603 0 : std::string osAttrName;
1604 0 : osAttrName.resize(H4_MAX_NC_NAME);
1605 0 : iNumType = 0;
1606 0 : int32 nValues = 0;
1607 0 : SDattrinfo(iSDS, iAttribute, &osAttrName[0], &iNumType,
1608 : &nValues);
1609 0 : osAttrName.resize(strlen(osAttrName.c_str()));
1610 0 : ret.emplace_back(std::make_shared<HDF4SDAttribute>(
1611 0 : GetFullName(), osAttrName, m_poShared, m_poSwathHandle,
1612 0 : nullptr, iSDS, iAttribute, iNumType, nValues));
1613 : }
1614 : }
1615 : }
1616 0 : return ret;
1617 : }
1618 :
1619 : /************************************************************************/
1620 : /* ReadPixels() */
1621 : /************************************************************************/
1622 :
1623 : union ReadFunc
1624 : {
1625 : intn (*pReadField)(int32, const char *, int32[], int32[], int32[], VOIDP);
1626 : intn (*pReadData)(int32, int32[], int32[], int32[], VOIDP);
1627 : };
1628 :
1629 24 : static inline void IncrPointer(GByte *&ptr, GPtrDiff_t nInc, size_t nIncSize)
1630 : {
1631 24 : if (nInc < 0)
1632 6 : ptr -= (-nInc) * nIncSize;
1633 : else
1634 18 : ptr += nInc * nIncSize;
1635 24 : }
1636 :
1637 4 : static bool ReadPixels(const GUInt64 *arrayStartIdx, const size_t *count,
1638 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
1639 : const GDALExtendedDataType &bufferDataType,
1640 : void *pDstBuffer,
1641 : const std::shared_ptr<HDF4SharedResources> &poShared,
1642 : const GDALExtendedDataType &dt,
1643 : const std::vector<std::shared_ptr<GDALDimension>> &dims,
1644 : int32 handle, const char *pszFieldName,
1645 : ReadFunc readFunc)
1646 : {
1647 8 : CPLMutexHolderD(&hHDF4Mutex);
1648 : /* -------------------------------------------------------------------- */
1649 : /* HDF files with external data files, such as some landsat */
1650 : /* products (eg. data/hdf/L1G) need to be told what directory */
1651 : /* to look in to find the external files. Normally this is the */
1652 : /* directory holding the hdf file. */
1653 : /* -------------------------------------------------------------------- */
1654 4 : HXsetdir(CPLGetPathSafe(poShared->GetFilename().c_str()).c_str());
1655 :
1656 4 : const size_t nDims(dims.size());
1657 8 : std::vector<int32> sw_start(nDims);
1658 8 : std::vector<int32> sw_stride(nDims);
1659 8 : std::vector<int32> sw_edge(nDims);
1660 8 : std::vector<GPtrDiff_t> newBufferStride(nDims);
1661 4 : GByte *pabyDstBuffer = static_cast<GByte *>(pDstBuffer);
1662 4 : const size_t nBufferDataTypeSize = bufferDataType.GetSize();
1663 14 : for (size_t i = 0; i < nDims; i++)
1664 : {
1665 10 : sw_start[i] = static_cast<int>(arrayStartIdx[i]);
1666 10 : sw_stride[i] = static_cast<int>(arrayStep[i]);
1667 10 : sw_edge[i] = static_cast<int>(count[i]);
1668 10 : newBufferStride[i] = bufferStride[i];
1669 10 : if (sw_stride[i] < 0)
1670 : {
1671 : // SWreadfield() doesn't like negative step / array stride, so
1672 : // transform the request to a classic "left-to-right" one
1673 0 : sw_start[i] += sw_stride[i] * (sw_edge[i] - 1);
1674 0 : sw_stride[i] = -sw_stride[i];
1675 0 : pabyDstBuffer +=
1676 0 : (sw_edge[i] - 1) * newBufferStride[i] * nBufferDataTypeSize;
1677 0 : newBufferStride[i] = -newBufferStride[i];
1678 : }
1679 : }
1680 4 : size_t nExpectedStride = 1;
1681 4 : bool bContiguousStride = true;
1682 14 : for (size_t i = nDims; i > 0;)
1683 : {
1684 10 : --i;
1685 10 : if (newBufferStride[i] != static_cast<GPtrDiff_t>(nExpectedStride))
1686 : {
1687 3 : bContiguousStride = false;
1688 : }
1689 10 : nExpectedStride *= count[i];
1690 : }
1691 4 : if (bufferDataType == dt && bContiguousStride)
1692 : {
1693 : auto status =
1694 : pszFieldName
1695 3 : ? readFunc.pReadField(handle, pszFieldName, &sw_start[0],
1696 0 : &sw_stride[0], &sw_edge[0], pabyDstBuffer)
1697 3 : : readFunc.pReadData(handle, &sw_start[0], &sw_stride[0],
1698 3 : &sw_edge[0], pabyDstBuffer);
1699 3 : return status == 0;
1700 : }
1701 : auto pabyTemp = static_cast<GByte *>(
1702 1 : VSI_MALLOC2_VERBOSE(dt.GetSize(), nExpectedStride));
1703 1 : if (pabyTemp == nullptr)
1704 0 : return false;
1705 : auto status =
1706 1 : pszFieldName ? readFunc.pReadField(handle, pszFieldName, &sw_start[0],
1707 0 : &sw_stride[0], &sw_edge[0], pabyTemp)
1708 1 : : readFunc.pReadData(handle, &sw_start[0], &sw_stride[0],
1709 1 : &sw_edge[0], pabyTemp);
1710 1 : if (status != 0)
1711 : {
1712 0 : VSIFree(pabyTemp);
1713 0 : return false;
1714 : }
1715 :
1716 1 : const size_t nSrcDataTypeSize = dt.GetSize();
1717 2 : std::vector<size_t> anStackCount(nDims);
1718 1 : GByte *pabySrc = pabyTemp;
1719 1 : std::vector<GByte *> pabyDstBufferStack(nDims + 1);
1720 1 : pabyDstBufferStack[0] = pabyDstBuffer;
1721 1 : size_t iDim = 0;
1722 11 : lbl_next_depth:
1723 11 : if (iDim == nDims)
1724 : {
1725 4 : GDALExtendedDataType::CopyValue(pabySrc, dt, pabyDstBufferStack[nDims],
1726 : bufferDataType);
1727 4 : pabySrc += nSrcDataTypeSize;
1728 : }
1729 : else
1730 : {
1731 7 : anStackCount[iDim] = count[iDim];
1732 : while (true)
1733 : {
1734 10 : ++iDim;
1735 10 : pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
1736 10 : goto lbl_next_depth;
1737 10 : lbl_return_to_caller_in_loop:
1738 10 : --iDim;
1739 10 : --anStackCount[iDim];
1740 10 : if (anStackCount[iDim] == 0)
1741 7 : break;
1742 3 : IncrPointer(pabyDstBufferStack[iDim], newBufferStride[iDim],
1743 : nBufferDataTypeSize);
1744 : }
1745 : }
1746 11 : if (iDim > 0)
1747 10 : goto lbl_return_to_caller_in_loop;
1748 :
1749 1 : VSIFree(pabyTemp);
1750 1 : return true;
1751 : }
1752 :
1753 : /************************************************************************/
1754 : /* IRead() */
1755 : /************************************************************************/
1756 :
1757 0 : bool HDF4SwathArray::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
1758 : const GInt64 *arrayStep,
1759 : const GPtrDiff_t *bufferStride,
1760 : const GDALExtendedDataType &bufferDataType,
1761 : void *pDstBuffer) const
1762 : {
1763 : ReadFunc readFunc;
1764 0 : readFunc.pReadField = SWreadfield;
1765 0 : return ReadPixels(arrayStartIdx, count, arrayStep, bufferStride,
1766 0 : bufferDataType, pDstBuffer, m_poShared, m_dt, m_dims,
1767 0 : m_poSwathHandle->m_handle, GetName().c_str(), readFunc);
1768 : }
1769 :
1770 : /************************************************************************/
1771 : /* GetRawNoDataValue() */
1772 : /************************************************************************/
1773 :
1774 0 : const void *HDF4SwathArray::GetRawNoDataValue() const
1775 : {
1776 0 : if (!m_abyNoData.empty())
1777 0 : return m_abyNoData.data();
1778 0 : m_abyNoData.resize(GetDataType().GetSize());
1779 :
1780 0 : auto poAttr = GetAttribute("_FillValue");
1781 0 : if (poAttr)
1782 : {
1783 0 : const double dfVal = poAttr->ReadAsDouble();
1784 0 : GDALExtendedDataType::CopyValue(
1785 0 : &dfVal, GDALExtendedDataType::Create(GDT_Float64), &m_abyNoData[0],
1786 : GetDataType());
1787 0 : return m_abyNoData.data();
1788 : }
1789 :
1790 0 : CPLMutexHolderD(&hHDF4Mutex);
1791 0 : if (SWgetfillvalue(m_poSwathHandle->m_handle, GetName().c_str(),
1792 0 : &m_abyNoData[0]) != -1)
1793 : {
1794 0 : return m_abyNoData.data();
1795 : }
1796 :
1797 0 : m_abyNoData.clear();
1798 0 : return nullptr;
1799 : }
1800 :
1801 : /************************************************************************/
1802 : /* HDF4AbstractAttribute() */
1803 : /************************************************************************/
1804 :
1805 28 : HDF4AbstractAttribute::HDF4AbstractAttribute(
1806 : const std::string &osParentName, const std::string &osName,
1807 : const std::shared_ptr<HDF4SharedResources> &poShared, int32 iNumType,
1808 0 : int32 nValues)
1809 : :
1810 : #if !defined(COMPILER_WARNS_ABOUT_ABSTRACT_VBASE_INIT)
1811 : GDALAbstractMDArray(osParentName, osName),
1812 : #endif
1813 : GDALAttribute(osParentName, osName), m_poShared(poShared),
1814 : m_dt(iNumType == DFNT_CHAR8 ? GDALExtendedDataType::CreateString()
1815 : : GDALExtendedDataType::Create(
1816 : HDF4Dataset::GetDataType(iNumType))),
1817 28 : m_nValues(nValues)
1818 : {
1819 28 : if (m_dt.GetClass() != GEDTC_STRING && m_nValues > 1)
1820 : {
1821 12 : m_dims.emplace_back(std::make_shared<GDALDimension>(
1822 18 : std::string(), "dim", std::string(), std::string(), nValues));
1823 : }
1824 28 : }
1825 :
1826 : /************************************************************************/
1827 : /* IRead() */
1828 : /************************************************************************/
1829 :
1830 13 : bool HDF4AbstractAttribute::IRead(const GUInt64 *arrayStartIdx,
1831 : const size_t *count, const GInt64 *arrayStep,
1832 : const GPtrDiff_t *bufferStride,
1833 : const GDALExtendedDataType &bufferDataType,
1834 : void *pDstBuffer) const
1835 : {
1836 26 : CPLMutexHolderD(&hHDF4Mutex);
1837 13 : if (m_dt.GetClass() == GEDTC_STRING)
1838 : {
1839 11 : if (bufferDataType.GetClass() != GEDTC_STRING)
1840 0 : return false;
1841 11 : char *pszStr = static_cast<char *>(VSIMalloc(m_nValues + 1));
1842 11 : if (pszStr == nullptr)
1843 0 : return false;
1844 11 : ReadData(pszStr);
1845 11 : pszStr[m_nValues] = 0;
1846 11 : *static_cast<char **>(pDstBuffer) = pszStr;
1847 11 : return true;
1848 : }
1849 :
1850 2 : std::vector<GByte> abyTemp(m_nValues * m_dt.GetSize());
1851 2 : ReadData(&abyTemp[0]);
1852 2 : GByte *pabyDstBuffer = static_cast<GByte *>(pDstBuffer);
1853 10 : for (size_t i = 0; i < (m_dims.empty() ? 1 : count[0]); ++i)
1854 : {
1855 : const size_t idx =
1856 8 : m_dims.empty()
1857 8 : ? 0
1858 8 : : static_cast<size_t>(arrayStartIdx[0] + i * arrayStep[0]);
1859 8 : GDALExtendedDataType::CopyValue(&abyTemp[0] + idx * m_dt.GetSize(),
1860 8 : m_dt, pabyDstBuffer, bufferDataType);
1861 8 : if (!m_dims.empty())
1862 8 : pabyDstBuffer += bufferStride[0] * bufferDataType.GetSize();
1863 : }
1864 :
1865 2 : return true;
1866 : }
1867 :
1868 : /************************************************************************/
1869 : /* GetGroupNames() */
1870 : /************************************************************************/
1871 :
1872 3 : std::vector<std::string> HDF4EOSGridsGroup::GetGroupNames(CSLConstList) const
1873 : {
1874 6 : CPLMutexHolderD(&hHDF4Mutex);
1875 3 : std::vector<std::string> res;
1876 :
1877 3 : int32 nStrBufSize = 0;
1878 3 : GDinqgrid(m_poShared->GetFilename().c_str(), nullptr, &nStrBufSize);
1879 :
1880 6 : std::string osGridList;
1881 3 : osGridList.resize(nStrBufSize);
1882 3 : GDinqgrid(m_poShared->GetFilename().c_str(), &osGridList[0], &nStrBufSize);
1883 :
1884 : CPLStringList aosGrids(
1885 6 : CSLTokenizeString2(osGridList.c_str(), ",", CSLT_HONOURSTRINGS));
1886 6 : for (int i = 0; i < aosGrids.size(); i++)
1887 3 : res.push_back(aosGrids[i]);
1888 :
1889 6 : return res;
1890 : }
1891 :
1892 : /************************************************************************/
1893 : /* OpenGroup() */
1894 : /************************************************************************/
1895 :
1896 : std::shared_ptr<GDALGroup>
1897 3 : HDF4EOSGridsGroup::OpenGroup(const std::string &osName, CSLConstList) const
1898 : {
1899 6 : CPLMutexHolderD(&hHDF4Mutex);
1900 :
1901 3 : int32 gdHandle = GDattach(m_poGDsHandle->m_handle, osName.c_str());
1902 3 : if (gdHandle < 0)
1903 : {
1904 0 : return nullptr;
1905 : }
1906 :
1907 6 : return std::make_shared<HDF4EOSGridGroup>(
1908 3 : GetFullName(), osName, m_poShared,
1909 9 : std::make_shared<HDF4GDHandle>(m_poGDsHandle, gdHandle));
1910 : }
1911 :
1912 : /************************************************************************/
1913 : /* GetDimensions() */
1914 : /************************************************************************/
1915 :
1916 : std::vector<std::shared_ptr<GDALDimension>>
1917 9 : HDF4EOSGridGroup::GetDimensions(CSLConstList) const
1918 : {
1919 9 : if (!m_dims.empty())
1920 6 : return m_dims;
1921 :
1922 3 : int32 iProjCode = 0;
1923 3 : int32 iZoneCode = 0;
1924 3 : int32 iSphereCode = 0;
1925 : double adfProjParams[15];
1926 :
1927 3 : GDprojinfo(m_poGDHandle->m_handle, &iProjCode, &iZoneCode, &iSphereCode,
1928 : adfProjParams);
1929 :
1930 3 : int32 nXSize = 0;
1931 3 : int32 nYSize = 0;
1932 : double adfUpLeft[2];
1933 : double adfLowRight[2];
1934 3 : const bool bGotGridInfo = GDgridinfo(m_poGDHandle->m_handle, &nXSize,
1935 3 : &nYSize, adfUpLeft, adfLowRight) >= 0;
1936 3 : if (bGotGridInfo)
1937 : {
1938 15 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
1939 3 : GetFullName(), "YDim", GDAL_DIM_TYPE_HORIZONTAL_Y,
1940 : "NORTH", nYSize),
1941 6 : std::make_shared<GDALDimensionWeakIndexingVar>(
1942 3 : GetFullName(), "XDim", GDAL_DIM_TYPE_HORIZONTAL_X, "EAST",
1943 9 : nXSize)};
1944 :
1945 3 : if (iProjCode == 0)
1946 : {
1947 3 : adfLowRight[0] = CPLPackedDMSToDec(adfLowRight[0]);
1948 3 : adfLowRight[1] = CPLPackedDMSToDec(adfLowRight[1]);
1949 3 : adfUpLeft[0] = CPLPackedDMSToDec(adfUpLeft[0]);
1950 3 : adfUpLeft[1] = CPLPackedDMSToDec(adfUpLeft[1]);
1951 : }
1952 :
1953 6 : m_varX = GDALMDArrayRegularlySpaced::Create(
1954 3 : GetFullName(), m_dims[1]->GetName(), m_dims[1], adfUpLeft[0],
1955 6 : (adfLowRight[0] - adfUpLeft[0]) / nXSize, 0.5);
1956 3 : m_dims[1]->SetIndexingVariable(m_varX);
1957 :
1958 6 : m_varY = GDALMDArrayRegularlySpaced::Create(
1959 3 : GetFullName(), m_dims[0]->GetName(), m_dims[0], adfUpLeft[1],
1960 6 : (adfLowRight[1] - adfUpLeft[1]) / nYSize, 0.5);
1961 3 : m_dims[0]->SetIndexingVariable(m_varY);
1962 : }
1963 :
1964 : #if 0
1965 : // Dimensions seem to be never defined properly on eos_grids datasets.
1966 :
1967 : std::string dimNames;
1968 : int32 nStrBufSize = 0;
1969 : if( GDnentries( m_poGDHandle->m_handle, HDFE_NENTDIM, &nStrBufSize ) < 0
1970 : || nStrBufSize <= 0 )
1971 : {
1972 : return m_dims;
1973 : }
1974 : dimNames.resize(nStrBufSize);
1975 : int32 nDims = GDinqdims(m_poGDHandle->m_handle, &dimNames[0], nullptr);
1976 : std::vector<int32> aiDimSizes(nDims);
1977 : GDinqdims(m_poGDHandle->m_handle, &dimNames[0], &aiDimSizes[0]);
1978 : CPLStringList aosDimNames(CSLTokenizeString2(
1979 : dimNames.c_str(), ",", CSLT_HONOURSTRINGS ));
1980 : if( static_cast<size_t>(aosDimNames.size()) == aiDimSizes.size() )
1981 : {
1982 : for( int i = 0; i < aosDimNames.size(); i++ )
1983 : {
1984 : m_dims.push_back(std::make_shared<GDALDimension>(GetFullName(),
1985 : aosDimNames[i],
1986 : std::string(),
1987 : std::string(),
1988 : aiDimSizes[i]));
1989 : }
1990 : }
1991 : #endif
1992 3 : return m_dims;
1993 : }
1994 :
1995 : /************************************************************************/
1996 : /* GetMDArrayNames() */
1997 : /************************************************************************/
1998 :
1999 3 : std::vector<std::string> HDF4EOSGridGroup::GetMDArrayNames(CSLConstList) const
2000 : {
2001 3 : GetDimensions();
2002 3 : std::vector<std::string> ret;
2003 3 : if (m_varX && m_varY)
2004 : {
2005 3 : ret.push_back(m_varY->GetName());
2006 3 : ret.push_back(m_varX->GetName());
2007 : }
2008 3 : return ret;
2009 : }
2010 :
2011 : /************************************************************************/
2012 : /* OpenMDArray() */
2013 : /************************************************************************/
2014 :
2015 : std::shared_ptr<GDALMDArray>
2016 6 : HDF4EOSGridGroup::OpenMDArray(const std::string &osName, CSLConstList) const
2017 : {
2018 6 : if (m_varX && osName == m_varX->GetName())
2019 3 : return m_varX;
2020 3 : if (m_varY && osName == m_varY->GetName())
2021 3 : return m_varY;
2022 0 : return nullptr;
2023 : }
2024 :
2025 : /************************************************************************/
2026 : /* GetGroupNames() */
2027 : /************************************************************************/
2028 :
2029 3 : std::vector<std::string> HDF4EOSGridGroup::GetGroupNames(CSLConstList) const
2030 : {
2031 3 : std::vector<std::string> res;
2032 3 : res.push_back("Data Fields");
2033 3 : return res;
2034 : }
2035 :
2036 : /************************************************************************/
2037 : /* OpenGroup() */
2038 : /************************************************************************/
2039 :
2040 : std::shared_ptr<GDALGroup>
2041 3 : HDF4EOSGridGroup::OpenGroup(const std::string &osName, CSLConstList) const
2042 : {
2043 3 : if (osName == "Data Fields")
2044 : {
2045 6 : return std::make_shared<HDF4EOSGridSubGroup>(
2046 3 : GetFullName(), osName, m_poShared, m_poGDHandle, HDFE_NENTDFLD,
2047 9 : GetDimensions());
2048 : }
2049 0 : return nullptr;
2050 : }
2051 :
2052 : /************************************************************************/
2053 : /* GetAttributes() */
2054 : /************************************************************************/
2055 :
2056 : std::vector<std::shared_ptr<GDALAttribute>>
2057 3 : HDF4EOSGridGroup::GetAttributes(CSLConstList) const
2058 : {
2059 6 : CPLMutexHolderD(&hHDF4Mutex);
2060 3 : std::vector<std::shared_ptr<GDALAttribute>> ret;
2061 3 : int32 nStrBufSize = 0;
2062 3 : if (GDinqattrs(m_poGDHandle->m_handle, nullptr, &nStrBufSize) <= 0 ||
2063 0 : nStrBufSize <= 0)
2064 : {
2065 3 : return ret;
2066 : }
2067 0 : std::string osAttrs;
2068 0 : osAttrs.resize(nStrBufSize);
2069 0 : GDinqattrs(m_poGDHandle->m_handle, &osAttrs[0], &nStrBufSize);
2070 :
2071 : CPLStringList aosAttrs(
2072 0 : CSLTokenizeString2(osAttrs.c_str(), ",", CSLT_HONOURSTRINGS));
2073 0 : for (int i = 0; i < aosAttrs.size(); i++)
2074 : {
2075 0 : int32 iNumType = 0;
2076 0 : int32 nSize = 0;
2077 :
2078 0 : if (GDattrinfo(m_poGDHandle->m_handle, aosAttrs[i], &iNumType, &nSize) <
2079 : 0)
2080 0 : continue;
2081 0 : const int nDataTypeSize = HDF4Dataset::GetDataTypeSize(iNumType);
2082 0 : if (nDataTypeSize == 0)
2083 0 : continue;
2084 :
2085 0 : ret.emplace_back(std::make_shared<HDF4EOSGridAttribute>(
2086 0 : GetFullName(), aosAttrs[i], m_poShared, m_poGDHandle, iNumType,
2087 0 : nSize / nDataTypeSize));
2088 : }
2089 0 : return ret;
2090 : }
2091 :
2092 : /************************************************************************/
2093 : /* GetMDArrayNames() */
2094 : /************************************************************************/
2095 :
2096 : std::vector<std::string>
2097 3 : HDF4EOSGridSubGroup::GetMDArrayNames(CSLConstList) const
2098 : {
2099 3 : std::vector<std::string> ret;
2100 :
2101 3 : int32 nStrBufSize = 0;
2102 : const int32 nFields =
2103 3 : GDnentries(m_poGDHandle->m_handle, m_entryType, &nStrBufSize);
2104 6 : std::string osFieldList;
2105 3 : osFieldList.resize(nStrBufSize);
2106 6 : std::vector<int32> ranks(nFields);
2107 6 : std::vector<int32> numberTypes(nFields);
2108 :
2109 3 : CPLAssert(m_entryType == HDFE_NENTDFLD);
2110 3 : GDinqfields(m_poGDHandle->m_handle, &osFieldList[0], &ranks[0],
2111 3 : &numberTypes[0]);
2112 :
2113 : CPLStringList aosFields(
2114 6 : CSLTokenizeString2(osFieldList.c_str(), ",", CSLT_HONOURSTRINGS));
2115 55 : for (int i = 0; i < aosFields.size(); i++)
2116 52 : ret.push_back(aosFields[i]);
2117 :
2118 6 : return ret;
2119 : }
2120 :
2121 : /************************************************************************/
2122 : /* OpenMDArray() */
2123 : /************************************************************************/
2124 :
2125 : std::shared_ptr<GDALMDArray>
2126 52 : HDF4EOSGridSubGroup::OpenMDArray(const std::string &osName, CSLConstList) const
2127 : {
2128 104 : CPLMutexHolderD(&hHDF4Mutex);
2129 :
2130 : int32 iRank;
2131 : int32 iNumType;
2132 104 : std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
2133 104 : std::string dimNames;
2134 :
2135 52 : int32 nStrBufSize = 0;
2136 52 : GDnentries(m_poGDHandle->m_handle, HDFE_NENTDIM, &nStrBufSize);
2137 52 : if (nStrBufSize <= 0)
2138 51 : dimNames.resize(HDFE_DIMBUFSIZE);
2139 : else
2140 1 : dimNames.resize(nStrBufSize);
2141 52 : if (GDfieldinfo(m_poGDHandle->m_handle, osName.c_str(), &iRank,
2142 104 : &aiDimSizes[0], &iNumType, &dimNames[0]) < 0)
2143 : {
2144 51 : return nullptr;
2145 : }
2146 1 : aiDimSizes.resize(iRank);
2147 1 : dimNames.resize(strlen(dimNames.c_str()));
2148 :
2149 2 : return HDF4EOSGridArray::Create(GetFullName(), osName, m_poShared,
2150 1 : m_poGDHandle, aiDimSizes, dimNames,
2151 2 : iNumType, m_groupDims);
2152 : }
2153 :
2154 : /************************************************************************/
2155 : /* HDF4EOSGridArray() */
2156 : /************************************************************************/
2157 :
2158 1 : HDF4EOSGridArray::HDF4EOSGridArray(
2159 : const std::string &osParentName, const std::string &osName,
2160 : const std::shared_ptr<HDF4SharedResources> &poShared,
2161 : const std::shared_ptr<HDF4GDHandle> &poGDHandle,
2162 : const std::vector<int32> &aiDimSizes, const std::string &dimNames,
2163 : int32 iNumType,
2164 1 : const std::vector<std::shared_ptr<GDALDimension>> &groupDims)
2165 : : GDALAbstractMDArray(osParentName, osName),
2166 : GDALPamMDArray(osParentName, osName, poShared->GetPAM()),
2167 : m_poShared(poShared), m_poGDHandle(poGDHandle),
2168 : m_dt(iNumType == DFNT_CHAR8 ? GDALExtendedDataType::CreateString()
2169 : : GDALExtendedDataType::Create(
2170 1 : HDF4Dataset::GetDataType(iNumType)))
2171 : {
2172 : CPLStringList aosDimNames(
2173 2 : CSLTokenizeString2(dimNames.c_str(), ",", CSLT_HONOURSTRINGS));
2174 1 : if (static_cast<size_t>(aosDimNames.size()) == aiDimSizes.size())
2175 : {
2176 1 : for (int i = 0; i < aosDimNames.size(); i++)
2177 : {
2178 0 : bool bFound = false;
2179 0 : for (const auto &poDim : groupDims)
2180 : {
2181 0 : if (poDim->GetName() == aosDimNames[i] &&
2182 0 : poDim->GetSize() == static_cast<GUInt64>(aiDimSizes[i]))
2183 : {
2184 0 : bFound = true;
2185 0 : m_dims.push_back(poDim);
2186 0 : break;
2187 : }
2188 : }
2189 0 : if (!bFound)
2190 : {
2191 0 : m_dims.push_back(std::make_shared<GDALDimension>(
2192 0 : std::string(), aosDimNames[i], std::string(), std::string(),
2193 0 : aiDimSizes[i]));
2194 : }
2195 : }
2196 : }
2197 1 : }
2198 :
2199 : /************************************************************************/
2200 : /* GetAttributes() */
2201 : /************************************************************************/
2202 :
2203 : std::vector<std::shared_ptr<GDALAttribute>>
2204 5 : HDF4EOSGridArray::GetAttributes(CSLConstList) const
2205 : {
2206 10 : CPLMutexHolderD(&hHDF4Mutex);
2207 5 : std::vector<std::shared_ptr<GDALAttribute>> ret;
2208 5 : int32 iSDS = 0;
2209 5 : if (GDsdid(m_poGDHandle->m_handle, GetName().c_str(), &iSDS) != -1)
2210 : {
2211 0 : int32 iRank = 0;
2212 0 : int32 iNumType = 0;
2213 0 : int32 nAttrs = 0;
2214 0 : std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
2215 :
2216 0 : if (SDgetinfo(iSDS, nullptr, &iRank, &aiDimSizes[0], &iNumType,
2217 0 : &nAttrs) == 0)
2218 : {
2219 0 : for (int32 iAttribute = 0; iAttribute < nAttrs; iAttribute++)
2220 : {
2221 0 : std::string osAttrName;
2222 0 : osAttrName.resize(H4_MAX_NC_NAME);
2223 0 : iNumType = 0;
2224 0 : int32 nValues = 0;
2225 0 : SDattrinfo(iSDS, iAttribute, &osAttrName[0], &iNumType,
2226 : &nValues);
2227 0 : osAttrName.resize(strlen(osAttrName.c_str()));
2228 0 : ret.emplace_back(std::make_shared<HDF4SDAttribute>(
2229 0 : GetFullName(), osAttrName, m_poShared, nullptr,
2230 0 : m_poGDHandle, iSDS, iAttribute, iNumType, nValues));
2231 : }
2232 : }
2233 : }
2234 10 : return ret;
2235 : }
2236 :
2237 : /************************************************************************/
2238 : /* GetRawNoDataValue() */
2239 : /************************************************************************/
2240 :
2241 1 : const void *HDF4EOSGridArray::GetRawNoDataValue() const
2242 : {
2243 1 : if (!m_abyNoData.empty())
2244 0 : return m_abyNoData.data();
2245 1 : m_abyNoData.resize(GetDataType().GetSize());
2246 :
2247 3 : auto poAttr = GetAttribute("_FillValue");
2248 1 : if (poAttr)
2249 : {
2250 0 : const double dfVal = poAttr->ReadAsDouble();
2251 0 : GDALExtendedDataType::CopyValue(
2252 0 : &dfVal, GDALExtendedDataType::Create(GDT_Float64), &m_abyNoData[0],
2253 : GetDataType());
2254 0 : return m_abyNoData.data();
2255 : }
2256 :
2257 2 : CPLMutexHolderD(&hHDF4Mutex);
2258 1 : if (GDgetfillvalue(m_poGDHandle->m_handle, GetName().c_str(),
2259 2 : &m_abyNoData[0]) != -1)
2260 : {
2261 0 : return m_abyNoData.data();
2262 : }
2263 1 : m_abyNoData.clear();
2264 1 : return nullptr;
2265 : }
2266 :
2267 : /************************************************************************/
2268 : /* GetOffsetOrScale() */
2269 : /************************************************************************/
2270 :
2271 4 : static double GetOffsetOrScale(const GDALMDArray *poArray,
2272 : const char *pszAttrName, double dfDefaultValue,
2273 : bool *pbHasVal, GDALDataType *peStorageType)
2274 : {
2275 12 : auto poAttr = poArray->GetAttribute(pszAttrName);
2276 4 : if (poAttr && (poAttr->GetDataType().GetNumericDataType() == GDT_Float32 ||
2277 4 : poAttr->GetDataType().GetNumericDataType() == GDT_Float64))
2278 : {
2279 0 : if (pbHasVal)
2280 0 : *pbHasVal = true;
2281 0 : if (peStorageType)
2282 0 : *peStorageType = poAttr->GetDataType().GetNumericDataType();
2283 0 : return poAttr->ReadAsDouble();
2284 : }
2285 4 : if (pbHasVal)
2286 4 : *pbHasVal = false;
2287 4 : return dfDefaultValue;
2288 : }
2289 :
2290 : /************************************************************************/
2291 : /* GetOffset() */
2292 : /************************************************************************/
2293 :
2294 2 : static double GetOffset(const GDALMDArray *poArray, bool *pbHasOffset,
2295 : GDALDataType *peStorageType)
2296 : {
2297 2 : return GetOffsetOrScale(poArray, "add_offset", 0, pbHasOffset,
2298 2 : peStorageType);
2299 : }
2300 :
2301 : /************************************************************************/
2302 : /* GetOffset() */
2303 : /************************************************************************/
2304 :
2305 1 : double HDF4EOSGridArray::GetOffset(bool *pbHasOffset,
2306 : GDALDataType *peStorageType) const
2307 : {
2308 1 : return ::GetOffset(this, pbHasOffset, peStorageType);
2309 : }
2310 :
2311 : /************************************************************************/
2312 : /* GetScale() */
2313 : /************************************************************************/
2314 :
2315 2 : static double GetScale(const GDALMDArray *poArray, bool *pbHasScale,
2316 : GDALDataType *peStorageType)
2317 : {
2318 2 : return GetOffsetOrScale(poArray, "scale_factor", 1, pbHasScale,
2319 2 : peStorageType);
2320 : }
2321 :
2322 : /************************************************************************/
2323 : /* GetScale() */
2324 : /************************************************************************/
2325 :
2326 1 : double HDF4EOSGridArray::GetScale(bool *pbHasScale,
2327 : GDALDataType *peStorageType) const
2328 : {
2329 1 : return ::GetScale(this, pbHasScale, peStorageType);
2330 : }
2331 :
2332 : /************************************************************************/
2333 : /* GetUnit() */
2334 : /************************************************************************/
2335 :
2336 1 : const std::string &HDF4EOSGridArray::GetUnit() const
2337 : {
2338 2 : auto poAttr = GetAttribute("units");
2339 1 : if (poAttr && poAttr->GetDataType().GetClass() == GEDTC_STRING)
2340 : {
2341 0 : const char *pszVal = poAttr->ReadAsString();
2342 0 : if (pszVal)
2343 0 : m_osUnit = pszVal;
2344 : }
2345 2 : return m_osUnit;
2346 : }
2347 :
2348 : /************************************************************************/
2349 : /* GetSpatialRef() */
2350 : /************************************************************************/
2351 :
2352 1 : std::shared_ptr<OGRSpatialReference> HDF4EOSGridArray::GetSpatialRef() const
2353 : {
2354 2 : CPLMutexHolderD(&hHDF4Mutex);
2355 1 : int32 iProjCode = 0;
2356 1 : int32 iZoneCode = 0;
2357 1 : int32 iSphereCode = 0;
2358 : double adfProjParams[15];
2359 :
2360 1 : if (GDprojinfo(m_poGDHandle->m_handle, &iProjCode, &iZoneCode, &iSphereCode,
2361 1 : adfProjParams) >= 0)
2362 : {
2363 2 : auto poSRS(std::make_shared<OGRSpatialReference>());
2364 1 : poSRS->importFromUSGS(iProjCode, iZoneCode, adfProjParams, iSphereCode,
2365 : USGS_ANGLE_RADIANS);
2366 1 : int iDimY = -1;
2367 1 : int iDimX = -1;
2368 1 : if (m_dims.size() >= 2)
2369 : {
2370 0 : iDimY = 1 + static_cast<int>(m_dims.size() - 2);
2371 0 : iDimX = 1 + static_cast<int>(m_dims.size() - 1);
2372 : }
2373 1 : if (iDimX > 0 && iDimY > 0)
2374 : {
2375 0 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2376 0 : if (poSRS->GetDataAxisToSRSAxisMapping() == std::vector<int>{2, 1})
2377 0 : poSRS->SetDataAxisToSRSAxisMapping({iDimY, iDimX});
2378 : else
2379 0 : poSRS->SetDataAxisToSRSAxisMapping({iDimX, iDimY});
2380 : }
2381 1 : return poSRS;
2382 : }
2383 0 : return nullptr;
2384 : }
2385 :
2386 : /************************************************************************/
2387 : /* IRead() */
2388 : /************************************************************************/
2389 :
2390 0 : bool HDF4EOSGridArray::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
2391 : const GInt64 *arrayStep,
2392 : const GPtrDiff_t *bufferStride,
2393 : const GDALExtendedDataType &bufferDataType,
2394 : void *pDstBuffer) const
2395 : {
2396 : ReadFunc readFunc;
2397 0 : readFunc.pReadField = GDreadfield;
2398 0 : return ReadPixels(arrayStartIdx, count, arrayStep, bufferStride,
2399 0 : bufferDataType, pDstBuffer, m_poShared, m_dt, m_dims,
2400 0 : m_poGDHandle->m_handle, GetName().c_str(), readFunc);
2401 : }
2402 :
2403 : /************************************************************************/
2404 : /* GetMDArrayNames() */
2405 : /************************************************************************/
2406 :
2407 4 : std::vector<std::string> HDF4SDSGroup::GetMDArrayNames(CSLConstList) const
2408 : {
2409 8 : CPLMutexHolderD(&hHDF4Mutex);
2410 4 : std::vector<std::string> ret;
2411 :
2412 4 : int32 nDatasets = 0;
2413 4 : int32 nAttrs = 0;
2414 4 : if (SDfileinfo(m_poShared->GetSDHandle(), &nDatasets, &nAttrs) != 0)
2415 0 : return ret;
2416 :
2417 8 : std::set<std::string> oSetNames;
2418 10 : for (int32 i = 0; i < nDatasets; i++)
2419 : {
2420 6 : const int32 iSDS = SDselect(m_poShared->GetSDHandle(), i);
2421 12 : std::string osName;
2422 6 : osName.resize(VSNAMELENMAX);
2423 6 : int32 iRank = 0;
2424 6 : int32 iNumType = 0;
2425 12 : std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
2426 6 : if (SDgetinfo(iSDS, &osName[0], &iRank, &aiDimSizes[0], &iNumType,
2427 6 : &nAttrs) == 0)
2428 : {
2429 6 : osName.resize(strlen(osName.c_str()));
2430 6 : int counter = 2;
2431 6 : std::string osRadix(osName);
2432 6 : while (oSetNames.find(osName) != oSetNames.end())
2433 : {
2434 0 : osName = osRadix + CPLSPrintf("_%d", counter);
2435 0 : counter++;
2436 : }
2437 6 : ret.push_back(osName);
2438 6 : m_oMapNameToSDSIdx[osName] = i;
2439 : }
2440 6 : SDendaccess(iSDS);
2441 : }
2442 :
2443 4 : if (m_bIsGDALDataset)
2444 : {
2445 2 : GetDimensions();
2446 2 : if (m_varX && m_varY)
2447 : {
2448 2 : ret.push_back(m_varX->GetName());
2449 2 : ret.push_back(m_varY->GetName());
2450 : }
2451 : }
2452 :
2453 4 : return ret;
2454 : }
2455 :
2456 : /************************************************************************/
2457 : /* OpenMDArray() */
2458 : /************************************************************************/
2459 :
2460 : std::shared_ptr<GDALMDArray>
2461 10 : HDF4SDSGroup::OpenMDArray(const std::string &osName, CSLConstList) const
2462 : {
2463 20 : CPLMutexHolderD(&hHDF4Mutex);
2464 10 : if (m_oMapNameToSDSIdx.empty())
2465 : {
2466 0 : GetMDArrayNames(nullptr);
2467 : }
2468 10 : auto oIter = m_oMapNameToSDSIdx.find(osName);
2469 10 : if (oIter == m_oMapNameToSDSIdx.end())
2470 : {
2471 2 : if (m_bIsGDALDataset)
2472 : {
2473 2 : GetDimensions();
2474 2 : if (m_varX && m_varX->GetName() == osName)
2475 : {
2476 1 : return m_varX;
2477 : }
2478 1 : if (m_varY && m_varY->GetName() == osName)
2479 : {
2480 1 : return m_varY;
2481 : }
2482 : }
2483 0 : return nullptr;
2484 : }
2485 8 : const int32 iSDS = SDselect(m_poShared->GetSDHandle(), oIter->second);
2486 :
2487 8 : int32 iRank = 0;
2488 8 : int32 iNumType = 0;
2489 8 : int32 nAttrs = 0;
2490 16 : std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
2491 8 : SDgetinfo(iSDS, nullptr, &iRank, &aiDimSizes[0], &iNumType, &nAttrs);
2492 8 : aiDimSizes.resize(iRank);
2493 :
2494 8 : auto ar = HDF4SDSArray::Create(GetFullName(), osName, m_poShared, iSDS,
2495 0 : aiDimSizes, GetDimensions(), iNumType,
2496 16 : nAttrs, m_bIsGDALDataset);
2497 8 : if (m_bIsGDALDataset)
2498 2 : ar->SetGlobalAttributes(m_oGlobalAttributes);
2499 8 : return ar;
2500 : }
2501 :
2502 : /************************************************************************/
2503 : /* GetDimensions() */
2504 : /************************************************************************/
2505 :
2506 : std::vector<std::shared_ptr<GDALDimension>>
2507 16 : HDF4SDSGroup::GetDimensions(CSLConstList) const
2508 : {
2509 32 : CPLMutexHolderD(&hHDF4Mutex);
2510 16 : if (m_bInGetDimensions)
2511 2 : return {};
2512 14 : if (!m_dims.empty())
2513 10 : return m_dims;
2514 4 : if (m_oMapNameToSDSIdx.empty())
2515 : {
2516 1 : m_bInGetDimensions = true;
2517 1 : GetMDArrayNames(nullptr);
2518 1 : m_bInGetDimensions = false;
2519 : }
2520 :
2521 8 : std::string osProjection;
2522 8 : std::string osTransformationMatrix;
2523 4 : if (m_bIsGDALDataset)
2524 : {
2525 8 : for (const auto &poAttr : m_oGlobalAttributes)
2526 : {
2527 8 : if (poAttr->GetName() == "Projection" &&
2528 2 : poAttr->GetDataType().GetClass() == GEDTC_STRING)
2529 : {
2530 2 : const char *pszVal = poAttr->ReadAsString();
2531 2 : if (pszVal)
2532 2 : osProjection = pszVal;
2533 : }
2534 6 : else if (poAttr->GetName() == "TransformationMatrix" &&
2535 2 : poAttr->GetDataType().GetClass() == GEDTC_STRING)
2536 : {
2537 2 : const char *pszVal = poAttr->ReadAsString();
2538 2 : if (pszVal)
2539 2 : osTransformationMatrix = pszVal;
2540 : }
2541 : }
2542 : }
2543 :
2544 : // First collect all dimension ids referenced by all datasets
2545 8 : std::map<int32, int32> oMapDimIdToDimSize;
2546 8 : std::set<std::string> oSetArrayNames;
2547 10 : for (const auto &oIter : m_oMapNameToSDSIdx)
2548 : {
2549 6 : const int32 iSDS = SDselect(m_poShared->GetSDHandle(), oIter.second);
2550 6 : int32 iRank = 0;
2551 6 : int32 iNumType = 0;
2552 6 : int32 nAttrs = 0;
2553 12 : std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
2554 6 : SDgetinfo(iSDS, nullptr, &iRank, &aiDimSizes[0], &iNumType, &nAttrs);
2555 17 : for (int i = 0; i < iRank; i++)
2556 : {
2557 11 : const auto dimId = SDgetdimid(iSDS, i);
2558 11 : oMapDimIdToDimSize[dimId] =
2559 11 : std::max(oMapDimIdToDimSize[dimId], aiDimSizes[i]);
2560 : }
2561 6 : oSetArrayNames.insert(oIter.first);
2562 6 : SDendaccess(iSDS);
2563 : }
2564 :
2565 : // Instantiate dimensions
2566 : std::set<std::shared_ptr<GDALDimensionWeakIndexingVar>>
2567 8 : oSetDimsWithVariable;
2568 13 : for (const auto &iter : oMapDimIdToDimSize)
2569 : {
2570 18 : std::string osName;
2571 9 : osName.resize(VSNAMELENMAX);
2572 9 : int32 iSize = 0; // can be 0 for unlimited dimension
2573 9 : int32 iNumType = 0;
2574 9 : int32 nAttrs = 0;
2575 9 : SDdiminfo(iter.first, &osName[0], &iSize, &iNumType, &nAttrs);
2576 9 : osName.resize(strlen(osName.c_str()));
2577 :
2578 18 : std::string osType;
2579 18 : std::string osDirection;
2580 9 : bool bIsIndexedDim = false;
2581 9 : if (iNumType > 0 && oSetArrayNames.find(osName) != oSetArrayNames.end())
2582 : {
2583 2 : bIsIndexedDim = true;
2584 2 : m_bInGetDimensions = true;
2585 4 : auto poArray(OpenMDArray(osName, nullptr));
2586 2 : m_bInGetDimensions = false;
2587 2 : if (poArray)
2588 : {
2589 6 : auto poAxis = poArray->GetAttribute("axis");
2590 2 : if (poAxis && poAxis->GetDataType().GetClass() == GEDTC_STRING)
2591 : {
2592 0 : const char *pszVal = poAxis->ReadAsString();
2593 0 : if (pszVal && EQUAL(pszVal, "X"))
2594 0 : osType = GDAL_DIM_TYPE_HORIZONTAL_X;
2595 0 : else if (pszVal && EQUAL(pszVal, "Y"))
2596 0 : osType = GDAL_DIM_TYPE_HORIZONTAL_Y;
2597 : }
2598 : }
2599 : }
2600 :
2601 : // Do not trust iSize which can be 0 for a unlimited dimension, but
2602 : // the size actually taken by the array(s)
2603 : auto poDim(std::make_shared<GDALDimensionWeakIndexingVar>(
2604 9 : GetFullName(), osName, osType, osDirection, iter.second));
2605 : // cppcheck-suppress knownConditionTrueFalse
2606 9 : if (bIsIndexedDim)
2607 : {
2608 2 : oSetDimsWithVariable.insert(poDim);
2609 : }
2610 9 : m_dims.push_back(poDim);
2611 : }
2612 :
2613 2 : if (m_bIsGDALDataset && (m_dims.size() == 2 || m_dims.size() == 3) &&
2614 6 : !osProjection.empty() && !osTransformationMatrix.empty())
2615 : {
2616 : CPLStringList aosCoeffs(
2617 4 : CSLTokenizeString2(osTransformationMatrix.c_str(), ",", 0));
2618 4 : if (aosCoeffs.size() == 6 && CPLAtof(aosCoeffs[2]) == 0 &&
2619 2 : CPLAtof(aosCoeffs[4]) == 0)
2620 : {
2621 : auto newDims = std::vector<std::shared_ptr<GDALDimension>>{
2622 4 : std::make_shared<GDALDimensionWeakIndexingVar>(
2623 2 : GetFullName(), "Y", GDAL_DIM_TYPE_HORIZONTAL_Y,
2624 2 : std::string(), m_dims[0]->GetSize()),
2625 4 : std::make_shared<GDALDimensionWeakIndexingVar>(
2626 2 : GetFullName(), "X", GDAL_DIM_TYPE_HORIZONTAL_X,
2627 14 : std::string(), m_dims[1]->GetSize())};
2628 2 : if (m_dims.size() == 3)
2629 : {
2630 1 : newDims.push_back(
2631 2 : std::make_shared<GDALDimensionWeakIndexingVar>(
2632 2 : GetFullName(), "Band", std::string(), std::string(),
2633 2 : m_dims[2]->GetSize()));
2634 : }
2635 2 : m_dims = std::move(newDims);
2636 :
2637 4 : m_varX = GDALMDArrayRegularlySpaced::Create(
2638 2 : GetFullName(), m_dims[1]->GetName(), m_dims[1],
2639 4 : CPLAtof(aosCoeffs[0]), CPLAtof(aosCoeffs[1]), 0.5);
2640 2 : m_dims[1]->SetIndexingVariable(m_varX);
2641 :
2642 4 : m_varY = GDALMDArrayRegularlySpaced::Create(
2643 2 : GetFullName(), m_dims[0]->GetName(), m_dims[0],
2644 4 : CPLAtof(aosCoeffs[3]), CPLAtof(aosCoeffs[5]), 0.5);
2645 2 : m_dims[0]->SetIndexingVariable(m_varY);
2646 : }
2647 : }
2648 :
2649 : // Now that we have eatablished all dimensions, we can link them to
2650 : // variables
2651 6 : for (auto &poDim : oSetDimsWithVariable)
2652 : {
2653 4 : auto poArray(OpenMDArray(poDim->GetName(), nullptr));
2654 2 : if (poArray)
2655 : {
2656 2 : m_oSetIndexingVariables.push_back(poArray);
2657 2 : poDim->SetIndexingVariable(std::move(poArray));
2658 : }
2659 : }
2660 :
2661 4 : return m_dims;
2662 : }
2663 :
2664 : /************************************************************************/
2665 : /* HDF4SDSArray() */
2666 : /************************************************************************/
2667 :
2668 8 : HDF4SDSArray::HDF4SDSArray(
2669 : const std::string &osParentName, const std::string &osName,
2670 : const std::shared_ptr<HDF4SharedResources> &poShared, int32 iSDS,
2671 : const std::vector<int32> &aiDimSizes,
2672 : const std::vector<std::shared_ptr<GDALDimension>> &groupDims,
2673 8 : int32 iNumType, int32 nAttrs, bool bIsGDALDS)
2674 : : GDALAbstractMDArray(osParentName, osName),
2675 : GDALPamMDArray(osParentName, osName, poShared->GetPAM()),
2676 : m_poShared(poShared), m_iSDS(iSDS),
2677 : m_dt(iNumType == DFNT_CHAR8 ? GDALExtendedDataType::CreateString()
2678 : : GDALExtendedDataType::Create(
2679 : HDF4Dataset::GetDataType(iNumType))),
2680 8 : m_nAttributes(nAttrs), m_bIsGDALDataset(bIsGDALDS)
2681 : {
2682 21 : for (int i = 0; i < static_cast<int>(aiDimSizes.size()); i++)
2683 : {
2684 26 : std::string osDimName;
2685 13 : osDimName.resize(VSNAMELENMAX);
2686 13 : int32 iSize = 0;
2687 13 : int32 iDimNumType = 0;
2688 13 : int32 nDimAttrs = 0;
2689 13 : int32 dimId = SDgetdimid(iSDS, i);
2690 13 : SDdiminfo(dimId, &osDimName[0], &iSize, &iDimNumType, &nDimAttrs);
2691 13 : osDimName.resize(strlen(osDimName.c_str()));
2692 13 : bool bFound = false;
2693 20 : for (const auto &poDim : groupDims)
2694 : {
2695 30 : if (poDim->GetName() == osDimName ||
2696 12 : (bIsGDALDS && i == 0 && poDim->GetName() == "Y") ||
2697 35 : (bIsGDALDS && i == 1 && poDim->GetName() == "X") ||
2698 5 : (bIsGDALDS && i == 2 && poDim->GetName() == "Band"))
2699 : {
2700 11 : bFound = true;
2701 11 : m_dims.push_back(poDim);
2702 11 : break;
2703 : }
2704 : }
2705 13 : if (!bFound)
2706 : {
2707 2 : m_dims.push_back(std::make_shared<GDALDimension>(
2708 4 : std::string(), CPLSPrintf("dim%d", i), std::string(),
2709 4 : std::string(), aiDimSizes[i]));
2710 : }
2711 : }
2712 8 : }
2713 :
2714 : /************************************************************************/
2715 : /* ~HDF4SDSArray() */
2716 : /************************************************************************/
2717 :
2718 16 : HDF4SDSArray::~HDF4SDSArray()
2719 : {
2720 16 : CPLMutexHolderD(&hHDF4Mutex);
2721 8 : SDendaccess(m_iSDS);
2722 16 : }
2723 :
2724 : /************************************************************************/
2725 : /* GetRawNoDataValue() */
2726 : /************************************************************************/
2727 :
2728 1 : const void *HDF4SDSArray::GetRawNoDataValue() const
2729 : {
2730 1 : if (!m_abyNoData.empty())
2731 0 : return m_abyNoData.data();
2732 1 : m_abyNoData.resize(GetDataType().GetSize());
2733 :
2734 3 : auto poAttr = GetAttribute("_FillValue");
2735 1 : if (poAttr)
2736 : {
2737 0 : const double dfVal = poAttr->ReadAsDouble();
2738 0 : GDALExtendedDataType::CopyValue(
2739 0 : &dfVal, GDALExtendedDataType::Create(GDT_Float64), &m_abyNoData[0],
2740 : GetDataType());
2741 0 : return m_abyNoData.data();
2742 : }
2743 :
2744 2 : CPLMutexHolderD(&hHDF4Mutex);
2745 1 : if (SDgetfillvalue(m_iSDS, &m_abyNoData[0]) != -1)
2746 : {
2747 0 : return m_abyNoData.data();
2748 : }
2749 :
2750 1 : m_abyNoData.clear();
2751 1 : return nullptr;
2752 : }
2753 :
2754 : /************************************************************************/
2755 : /* GetAttributes() */
2756 : /************************************************************************/
2757 :
2758 : std::vector<std::shared_ptr<GDALAttribute>>
2759 9 : HDF4SDSArray::GetAttributes(CSLConstList) const
2760 : {
2761 18 : CPLMutexHolderD(&hHDF4Mutex);
2762 9 : std::vector<std::shared_ptr<GDALAttribute>> ret;
2763 :
2764 13 : for (int32 iAttribute = 0; iAttribute < m_nAttributes; iAttribute++)
2765 : {
2766 4 : std::string osAttrName;
2767 4 : osAttrName.resize(H4_MAX_NC_NAME);
2768 4 : int32 iNumType = 0;
2769 4 : int32 nValues = 0;
2770 4 : SDattrinfo(m_iSDS, iAttribute, &osAttrName[0], &iNumType, &nValues);
2771 4 : osAttrName.resize(strlen(osAttrName.c_str()));
2772 8 : ret.emplace_back(std::make_shared<HDF4SDAttribute>(
2773 8 : GetFullName(), osAttrName, m_poShared, nullptr, nullptr, m_iSDS,
2774 4 : iAttribute, iNumType, nValues));
2775 : }
2776 :
2777 18 : return ret;
2778 : }
2779 :
2780 : /************************************************************************/
2781 : /* GetOffset() */
2782 : /************************************************************************/
2783 :
2784 1 : double HDF4SDSArray::GetOffset(bool *pbHasOffset,
2785 : GDALDataType *peStorageType) const
2786 : {
2787 1 : return ::GetOffset(this, pbHasOffset, peStorageType);
2788 : }
2789 :
2790 : /************************************************************************/
2791 : /* GetScale() */
2792 : /************************************************************************/
2793 :
2794 1 : double HDF4SDSArray::GetScale(bool *pbHasScale,
2795 : GDALDataType *peStorageType) const
2796 : {
2797 1 : return ::GetScale(this, pbHasScale, peStorageType);
2798 : }
2799 :
2800 : /************************************************************************/
2801 : /* GetUnit() */
2802 : /************************************************************************/
2803 :
2804 2 : const std::string &HDF4SDSArray::GetUnit() const
2805 : {
2806 4 : auto poAttr = GetAttribute("units");
2807 2 : if (poAttr && poAttr->GetDataType().GetClass() == GEDTC_STRING)
2808 : {
2809 0 : const char *pszVal = poAttr->ReadAsString();
2810 0 : if (pszVal)
2811 0 : m_osUnit = pszVal;
2812 : }
2813 4 : return m_osUnit;
2814 : }
2815 :
2816 : /************************************************************************/
2817 : /* GetSpatialRef() */
2818 : /************************************************************************/
2819 :
2820 3 : std::shared_ptr<OGRSpatialReference> HDF4SDSArray::GetSpatialRef() const
2821 : {
2822 3 : if (m_bIsGDALDataset)
2823 : {
2824 2 : std::string osProjection;
2825 6 : for (const auto &poAttr : m_oGlobalAttributes)
2826 : {
2827 8 : if (poAttr->GetName() == "Projection" &&
2828 2 : poAttr->GetDataType().GetClass() == GEDTC_STRING)
2829 : {
2830 2 : const char *pszVal = poAttr->ReadAsString();
2831 2 : if (pszVal)
2832 2 : osProjection = pszVal;
2833 2 : break;
2834 : }
2835 : }
2836 2 : if (!osProjection.empty())
2837 : {
2838 4 : auto poSRS(std::make_shared<OGRSpatialReference>());
2839 2 : poSRS->SetFromUserInput(
2840 : osProjection.c_str(),
2841 : OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get());
2842 2 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2843 2 : if (poSRS->GetDataAxisToSRSAxisMapping() == std::vector<int>{2, 1})
2844 0 : poSRS->SetDataAxisToSRSAxisMapping({1, 2});
2845 : else
2846 2 : poSRS->SetDataAxisToSRSAxisMapping({2, 1});
2847 2 : return poSRS;
2848 : }
2849 : }
2850 1 : return nullptr;
2851 : }
2852 :
2853 : /************************************************************************/
2854 : /* IRead() */
2855 : /************************************************************************/
2856 :
2857 4 : bool HDF4SDSArray::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
2858 : const GInt64 *arrayStep,
2859 : const GPtrDiff_t *bufferStride,
2860 : const GDALExtendedDataType &bufferDataType,
2861 : void *pDstBuffer) const
2862 : {
2863 : ReadFunc readFunc;
2864 4 : readFunc.pReadData = SDreaddata;
2865 8 : return ReadPixels(arrayStartIdx, count, arrayStep, bufferStride,
2866 4 : bufferDataType, pDstBuffer, m_poShared, m_dt, m_dims,
2867 8 : m_iSDS, nullptr, readFunc);
2868 : }
2869 :
2870 : /************************************************************************/
2871 : /* GetMDArrayNames() */
2872 : /************************************************************************/
2873 :
2874 2 : std::vector<std::string> HDF4GRsGroup::GetMDArrayNames(CSLConstList) const
2875 : {
2876 4 : CPLMutexHolderD(&hHDF4Mutex);
2877 2 : std::vector<std::string> res;
2878 :
2879 2 : int32 nImages = 0;
2880 2 : int32 nAttrs = 0;
2881 2 : GRfileinfo(m_poGRsHandle->m_grHandle, &nImages, &nAttrs);
2882 4 : for (int32 i = 0; i < nImages; i++)
2883 : {
2884 2 : const int32 iGR = GRselect(m_poGRsHandle->m_grHandle, i);
2885 :
2886 4 : std::string osName;
2887 2 : osName.resize(VSNAMELENMAX);
2888 2 : int32 nBands = 0;
2889 2 : int32 iNumType = 0;
2890 2 : int32 iInterlaceMode = 0;
2891 4 : std::vector<int32> aiDimSizes(2);
2892 2 : if (GRgetiminfo(iGR, &osName[0], &nBands, &iNumType, &iInterlaceMode,
2893 4 : &aiDimSizes[0], &nAttrs) == 0)
2894 : {
2895 2 : osName.resize(strlen(osName.c_str()));
2896 2 : m_oMapNameToGRIdx[osName] = i;
2897 2 : res.push_back(std::move(osName));
2898 : }
2899 :
2900 2 : GRendaccess(iGR);
2901 : }
2902 4 : return res;
2903 : }
2904 :
2905 : /************************************************************************/
2906 : /* GetAttributes() */
2907 : /************************************************************************/
2908 :
2909 : std::vector<std::shared_ptr<GDALAttribute>>
2910 2 : HDF4GRsGroup::GetAttributes(CSLConstList) const
2911 : {
2912 4 : CPLMutexHolderD(&hHDF4Mutex);
2913 2 : std::vector<std::shared_ptr<GDALAttribute>> ret;
2914 2 : int32 nDatasets = 0;
2915 2 : int32 nAttributes = 0;
2916 2 : if (GRfileinfo(m_poGRsHandle->m_grHandle, &nDatasets, &nAttributes) != 0)
2917 0 : return ret;
2918 6 : for (int32 iAttribute = 0; iAttribute < nAttributes; iAttribute++)
2919 : {
2920 4 : int32 iNumType = 0;
2921 4 : int32 nValues = 0;
2922 :
2923 4 : std::string osAttrName;
2924 4 : osAttrName.resize(H4_MAX_NC_NAME);
2925 4 : GRattrinfo(m_poGRsHandle->m_grHandle, iAttribute, &osAttrName[0],
2926 : &iNumType, &nValues);
2927 4 : osAttrName.resize(strlen(osAttrName.c_str()));
2928 :
2929 8 : ret.emplace_back(std::make_shared<HDF4GRAttribute>(
2930 4 : GetFullName(), osAttrName, m_poShared, m_poGRsHandle, nullptr,
2931 8 : m_poGRsHandle->m_grHandle, iAttribute, iNumType, nValues));
2932 : }
2933 2 : return ret;
2934 : }
2935 :
2936 : /************************************************************************/
2937 : /* OpenMDArray() */
2938 : /************************************************************************/
2939 :
2940 : std::shared_ptr<GDALMDArray>
2941 3 : HDF4GRsGroup::OpenMDArray(const std::string &osName, CSLConstList) const
2942 : {
2943 6 : CPLMutexHolderD(&hHDF4Mutex);
2944 3 : if (m_oMapNameToGRIdx.empty())
2945 : {
2946 1 : GetMDArrayNames(nullptr);
2947 : }
2948 3 : auto oIter = m_oMapNameToGRIdx.find(osName);
2949 3 : if (oIter == m_oMapNameToGRIdx.end())
2950 : {
2951 1 : return nullptr;
2952 : }
2953 2 : const int32 iGR = GRselect(m_poGRsHandle->m_grHandle, oIter->second);
2954 :
2955 2 : int32 nBands = 0;
2956 2 : int32 iNumType = 0;
2957 2 : int32 iInterlaceMode = 0;
2958 2 : std::vector<int32> aiDimSizes(2);
2959 : int32 nAttrs;
2960 2 : GRgetiminfo(iGR, nullptr, &nBands, &iNumType, &iInterlaceMode,
2961 2 : &aiDimSizes[0], &nAttrs);
2962 :
2963 4 : return HDF4GRArray::Create(
2964 2 : GetFullName(), osName, m_poShared,
2965 4 : std::make_shared<HDF4GRHandle>(m_poGRsHandle, iGR), nBands, aiDimSizes,
2966 2 : iNumType, nAttrs);
2967 : }
2968 :
2969 : /************************************************************************/
2970 : /* HDF4GRArray() */
2971 : /************************************************************************/
2972 :
2973 2 : HDF4GRArray::HDF4GRArray(const std::string &osParentName,
2974 : const std::string &osName,
2975 : const std::shared_ptr<HDF4SharedResources> &poShared,
2976 : const std::shared_ptr<HDF4GRHandle> &poGRHandle,
2977 : int32 nBands, const std::vector<int32> &aiDimSizes,
2978 2 : int32 iNumType, int32 nAttrs)
2979 : : GDALAbstractMDArray(osParentName, osName),
2980 : GDALPamMDArray(osParentName, osName, poShared->GetPAM()),
2981 : m_poShared(poShared), m_poGRHandle(poGRHandle),
2982 : m_dt(iNumType == DFNT_CHAR8 ? GDALExtendedDataType::CreateString()
2983 : : GDALExtendedDataType::Create(
2984 : HDF4Dataset::GetDataType(iNumType))),
2985 2 : m_nAttributes(nAttrs)
2986 : {
2987 6 : for (int i = 0; i < static_cast<int>(aiDimSizes.size()); i++)
2988 : {
2989 8 : m_dims.push_back(std::make_shared<GDALDimension>(
2990 12 : std::string(), i == 0 ? "y" : "x", std::string(), std::string(),
2991 4 : aiDimSizes[i]));
2992 : }
2993 2 : m_dims.push_back(std::make_shared<GDALDimension>(
2994 4 : std::string(), "bands", std::string(), std::string(), nBands));
2995 2 : }
2996 :
2997 : /************************************************************************/
2998 : /* GetAttributes() */
2999 : /************************************************************************/
3000 :
3001 : std::vector<std::shared_ptr<GDALAttribute>>
3002 4 : HDF4GRArray::GetAttributes(CSLConstList) const
3003 : {
3004 8 : CPLMutexHolderD(&hHDF4Mutex);
3005 4 : std::vector<std::shared_ptr<GDALAttribute>> ret;
3006 10 : for (int32 iAttribute = 0; iAttribute < m_nAttributes; iAttribute++)
3007 : {
3008 6 : int32 iNumType = 0;
3009 6 : int32 nValues = 0;
3010 :
3011 6 : std::string osAttrName;
3012 6 : osAttrName.resize(H4_MAX_NC_NAME);
3013 6 : GRattrinfo(m_poGRHandle->m_iGR, iAttribute, &osAttrName[0], &iNumType,
3014 : &nValues);
3015 6 : osAttrName.resize(strlen(osAttrName.c_str()));
3016 :
3017 12 : ret.emplace_back(std::make_shared<HDF4GRAttribute>(
3018 6 : GetFullName(), osAttrName, m_poShared, nullptr, m_poGRHandle,
3019 12 : m_poGRHandle->m_iGR, iAttribute, iNumType, nValues));
3020 : }
3021 :
3022 4 : auto iPal = GRgetlutid(m_poGRHandle->m_iGR, 0);
3023 4 : if (iPal != -1)
3024 : {
3025 4 : int32 nComps = 0;
3026 4 : int32 iPalDataType = 0;
3027 4 : int32 iPalInterlaceMode = 0;
3028 4 : int32 nPalEntries = 0;
3029 4 : GRgetlutinfo(iPal, &nComps, &iPalDataType, &iPalInterlaceMode,
3030 : &nPalEntries);
3031 1 : if (nPalEntries && nComps == 3 &&
3032 1 : GDALGetDataTypeSizeBytes(HDF4Dataset::GetDataType(iPalDataType)) ==
3033 5 : 1 &&
3034 1 : nPalEntries <= 256)
3035 : {
3036 2 : ret.emplace_back(std::make_shared<HDF4GRPalette>(
3037 1 : GetFullName(), "lut", m_poShared, m_poGRHandle, iPal,
3038 1 : nPalEntries));
3039 : }
3040 : }
3041 :
3042 8 : return ret;
3043 : }
3044 :
3045 : /************************************************************************/
3046 : /* IRead() */
3047 : /************************************************************************/
3048 :
3049 4 : bool HDF4GRArray::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
3050 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
3051 : const GDALExtendedDataType &bufferDataType,
3052 : void *pDstBuffer) const
3053 : {
3054 8 : CPLMutexHolderD(&hHDF4Mutex);
3055 : /* -------------------------------------------------------------------- */
3056 : /* HDF files with external data files, such as some landsat */
3057 : /* products (eg. data/hdf/L1G) need to be told what directory */
3058 : /* to look in to find the external files. Normally this is the */
3059 : /* directory holding the hdf file. */
3060 : /* -------------------------------------------------------------------- */
3061 4 : HXsetdir(CPLGetPathSafe(m_poShared->GetFilename().c_str()).c_str());
3062 :
3063 4 : const size_t nDims(m_dims.size());
3064 8 : std::vector<int32> sw_start(nDims);
3065 8 : std::vector<int32> sw_stride(nDims);
3066 8 : std::vector<int32> sw_edge(nDims);
3067 8 : std::vector<GPtrDiff_t> newBufferStride(nDims);
3068 4 : GByte *pabyDstBuffer = static_cast<GByte *>(pDstBuffer);
3069 4 : const size_t nBufferDataTypeSize = bufferDataType.GetSize();
3070 16 : for (size_t i = 0; i < nDims; i++)
3071 : {
3072 12 : sw_start[i] = static_cast<int>(arrayStartIdx[i]);
3073 12 : sw_stride[i] = static_cast<int>(arrayStep[i]);
3074 12 : sw_edge[i] = static_cast<int>(count[i]);
3075 12 : newBufferStride[i] = bufferStride[i];
3076 12 : if (sw_stride[i] < 0)
3077 : {
3078 : // GRreadimage() doesn't like negative step / array stride, so
3079 : // transform the request to a classic "left-to-right" one
3080 1 : sw_start[i] += sw_stride[i] * (sw_edge[i] - 1);
3081 1 : sw_stride[i] = -sw_stride[i];
3082 1 : pabyDstBuffer +=
3083 1 : (sw_edge[i] - 1) * newBufferStride[i] * nBufferDataTypeSize;
3084 1 : newBufferStride[i] = -newBufferStride[i];
3085 : }
3086 : }
3087 4 : size_t nExpectedStride = 1;
3088 4 : bool bContiguousStride = true;
3089 13 : for (size_t i = nDims; i > 0;)
3090 : {
3091 10 : --i;
3092 10 : if (newBufferStride[i] != static_cast<GPtrDiff_t>(nExpectedStride))
3093 : {
3094 1 : bContiguousStride = false;
3095 1 : break;
3096 : }
3097 9 : nExpectedStride *= count[i];
3098 : }
3099 10 : if (bufferDataType == m_dt && bContiguousStride && arrayStartIdx[2] == 0 &&
3100 10 : count[2] == m_dims[2]->GetSize() && arrayStep[2] == 1)
3101 : {
3102 1 : auto status = GRreadimage(m_poGRHandle->m_iGR, &sw_start[0],
3103 1 : &sw_stride[0], &sw_edge[0], pabyDstBuffer);
3104 1 : return status >= 0;
3105 : }
3106 3 : auto pabyTemp = static_cast<GByte *>(VSI_MALLOC2_VERBOSE(
3107 : m_dt.GetSize(),
3108 : count[0] * count[1] * static_cast<size_t>(m_dims[2]->GetSize())));
3109 3 : if (pabyTemp == nullptr)
3110 0 : return false;
3111 3 : auto status = GRreadimage(m_poGRHandle->m_iGR, &sw_start[0], &sw_stride[0],
3112 3 : &sw_edge[0], pabyTemp);
3113 3 : if (status < 0)
3114 : {
3115 0 : VSIFree(pabyTemp);
3116 0 : return false;
3117 : }
3118 :
3119 3 : const size_t nSrcDataTypeSize = m_dt.GetSize();
3120 6 : std::vector<size_t> anStackCount(nDims);
3121 3 : GByte *pabySrc = pabyTemp + nSrcDataTypeSize * sw_start[2];
3122 3 : std::vector<GByte *> pabyDstBufferStack(nDims + 1);
3123 3 : pabyDstBufferStack[0] = pabyDstBuffer;
3124 3 : size_t iDim = 0;
3125 54 : lbl_next_depth:
3126 54 : if (iDim == nDims)
3127 : {
3128 24 : GDALExtendedDataType::CopyValue(
3129 24 : pabySrc, m_dt, pabyDstBufferStack[nDims], bufferDataType);
3130 24 : pabySrc += nSrcDataTypeSize * sw_stride[2];
3131 : }
3132 : else
3133 : {
3134 30 : anStackCount[iDim] = count[iDim];
3135 : while (true)
3136 : {
3137 51 : ++iDim;
3138 51 : pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
3139 51 : goto lbl_next_depth;
3140 51 : lbl_return_to_caller_in_loop:
3141 51 : --iDim;
3142 51 : --anStackCount[iDim];
3143 51 : if (anStackCount[iDim] == 0)
3144 30 : break;
3145 21 : IncrPointer(pabyDstBufferStack[iDim], newBufferStride[iDim],
3146 : nBufferDataTypeSize);
3147 : }
3148 30 : if (iDim == 2)
3149 18 : pabySrc +=
3150 18 : nSrcDataTypeSize * static_cast<size_t>(m_dims[2]->GetSize() -
3151 18 : count[2] * sw_stride[2]);
3152 : }
3153 54 : if (iDim > 0)
3154 51 : goto lbl_return_to_caller_in_loop;
3155 :
3156 3 : VSIFree(pabyTemp);
3157 3 : return true;
3158 : }
3159 :
3160 : /************************************************************************/
3161 : /* HDF4GRPalette() */
3162 : /************************************************************************/
3163 :
3164 1 : HDF4GRPalette::HDF4GRPalette(
3165 : const std::string &osParentName, const std::string &osName,
3166 : const std::shared_ptr<HDF4SharedResources> &poShared,
3167 1 : const std::shared_ptr<HDF4GRHandle> &poGRHandle, int32 iPal, int32 nValues)
3168 : : GDALAbstractMDArray(osParentName, osName),
3169 : GDALAttribute(osParentName, osName), m_poShared(poShared),
3170 1 : m_poGRHandle(poGRHandle), m_iPal(iPal), m_nValues(nValues)
3171 : {
3172 1 : m_dims.push_back(std::make_shared<GDALDimension>(
3173 2 : std::string(), "index", std::string(), std::string(), nValues));
3174 1 : m_dims.push_back(std::make_shared<GDALDimension>(
3175 2 : std::string(), "component", std::string(), std::string(), 3));
3176 1 : }
3177 :
3178 : /************************************************************************/
3179 : /* IRead() */
3180 : /************************************************************************/
3181 :
3182 1 : bool HDF4GRPalette::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
3183 : const GInt64 *arrayStep,
3184 : const GPtrDiff_t *bufferStride,
3185 : const GDALExtendedDataType &bufferDataType,
3186 : void *pDstBuffer) const
3187 : {
3188 2 : CPLMutexHolderD(&hHDF4Mutex);
3189 :
3190 2 : std::vector<GByte> abyValues(3 * m_nValues);
3191 1 : GRreadlut(m_iPal, &abyValues[0]);
3192 :
3193 1 : GByte *pabyDstBuffer = static_cast<GByte *>(pDstBuffer);
3194 1 : const size_t nBufferDataTypeSize = bufferDataType.GetSize();
3195 1 : const auto srcDt(GDALExtendedDataType::Create(GDT_UInt8));
3196 257 : for (size_t i = 0; i < count[0]; ++i)
3197 : {
3198 256 : size_t idx = static_cast<size_t>(arrayStartIdx[0] + i * arrayStep[0]);
3199 1024 : for (size_t j = 0; j < count[1]; ++j)
3200 : {
3201 768 : size_t comp =
3202 768 : static_cast<size_t>(arrayStartIdx[1] + j * arrayStep[1]);
3203 768 : GByte *pDst =
3204 768 : pabyDstBuffer + (i * bufferStride[0] + j * bufferStride[1]) *
3205 : nBufferDataTypeSize;
3206 768 : GDALExtendedDataType::CopyValue(&abyValues[3 * idx + comp], srcDt,
3207 : pDst, bufferDataType);
3208 : }
3209 : }
3210 :
3211 2 : return true;
3212 : }
3213 :
3214 : /************************************************************************/
3215 : /* OpenMultiDim() */
3216 : /************************************************************************/
3217 :
3218 12 : void HDF4Dataset::OpenMultiDim(const char *pszFilename,
3219 : CSLConstList papszOpenOptionsIn)
3220 : {
3221 : // under hHDF4Mutex
3222 :
3223 24 : auto poShared = std::make_shared<HDF4SharedResources>(pszFilename);
3224 12 : poShared->m_hSD = hSD;
3225 12 : poShared->m_aosOpenOptions = papszOpenOptionsIn;
3226 :
3227 12 : hSD = -1;
3228 :
3229 12 : m_poRootGroup = HDF4Group::Create(std::string(), "/", poShared);
3230 :
3231 12 : SetDescription(pszFilename);
3232 :
3233 : // Setup/check for pam .aux.xml.
3234 12 : TryLoadXML();
3235 12 : }
|