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 94 : const std::string &GetFilename() const
56 : {
57 94 : 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 9 : explicit HDF4GDsHandle(int32 handle) : m_handle(handle)
386 : {
387 9 : }
388 :
389 9 : ~HDF4GDsHandle()
390 9 : {
391 18 : CPLMutexHolderD(&hHDF4Mutex);
392 9 : GDclose(m_handle);
393 9 : }
394 : };
395 :
396 : /************************************************************************/
397 : /* HDF4GDHandle */
398 : /************************************************************************/
399 :
400 : struct HDF4GDHandle
401 : {
402 : std::shared_ptr<HDF4GDsHandle> m_poGDsHandle;
403 : int32 m_handle;
404 :
405 9 : explicit HDF4GDHandle(const std::shared_ptr<HDF4GDsHandle> &poGDsHandle,
406 : int32 handle)
407 9 : : m_poGDsHandle(poGDsHandle), m_handle(handle)
408 : {
409 9 : }
410 :
411 9 : ~HDF4GDHandle()
412 9 : {
413 18 : CPLMutexHolderD(&hHDF4Mutex);
414 9 : GDdetach(m_handle);
415 9 : }
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 9 : 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 9 : : GDALGroup(osParentName, osName), m_poShared(poShared),
433 9 : m_poGDsHandle(poGDsHandle)
434 : {
435 9 : }
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 9 : HDF4EOSGridGroup(const std::string &osParentName, const std::string &osName,
457 : const std::shared_ptr<HDF4SharedResources> &poShared,
458 : const std::shared_ptr<HDF4GDHandle> &poGDHandle)
459 9 : : GDALGroup(osParentName, osName), m_poShared(poShared),
460 9 : m_poGDHandle(poGDHandle)
461 : {
462 9 : }
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 19 : std::shared_ptr<GDALGroup> HDF4Group::OpenGroup(const std::string &osName,
1233 : CSLConstList) const
1234 : {
1235 19 : if (m_poGDALGroup)
1236 2 : return nullptr;
1237 :
1238 34 : CPLMutexHolderD(&hHDF4Mutex);
1239 17 : 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 14 : if (osName == "eos_grids")
1248 : {
1249 9 : auto handle = GDopen(m_poShared->GetFilename().c_str(), DFACC_READ);
1250 9 : if (handle >= 0)
1251 18 : return std::make_shared<HDF4EOSGridsGroup>(
1252 9 : GetFullName(), osName, m_poShared,
1253 27 : 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 5 : std::shared_ptr<GDALMDArray> HDF4Group::OpenMDArray(const std::string &osName,
1297 : CSLConstList) const
1298 : {
1299 5 : if (m_poGDALGroup)
1300 4 : return m_poGDALGroup->OpenMDArray(osName, nullptr);
1301 1 : 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 9 : HDF4EOSGridsGroup::OpenGroup(const std::string &osName, CSLConstList) const
1898 : {
1899 18 : CPLMutexHolderD(&hHDF4Mutex);
1900 :
1901 9 : int32 gdHandle = GDattach(m_poGDsHandle->m_handle, osName.c_str());
1902 9 : if (gdHandle < 0)
1903 : {
1904 0 : return nullptr;
1905 : }
1906 :
1907 18 : return std::make_shared<HDF4EOSGridGroup>(
1908 9 : GetFullName(), osName, m_poShared,
1909 27 : 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 12 : HDF4EOSGridGroup::OpenMDArray(const std::string &osName, CSLConstList) const
2017 : {
2018 12 : if (m_varX && osName == m_varX->GetName())
2019 3 : return m_varX;
2020 9 : if (m_varY && osName == m_varY->GetName())
2021 3 : return m_varY;
2022 6 : 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 : dimNames.resize(HDFE_DIMBUFSIZE);
2136 52 : if (GDfieldinfo(m_poGDHandle->m_handle, osName.c_str(), &iRank,
2137 104 : &aiDimSizes[0], &iNumType, &dimNames[0]) < 0)
2138 : {
2139 51 : return nullptr;
2140 : }
2141 1 : aiDimSizes.resize(iRank);
2142 1 : dimNames.resize(strlen(dimNames.c_str()));
2143 :
2144 2 : return HDF4EOSGridArray::Create(GetFullName(), osName, m_poShared,
2145 1 : m_poGDHandle, aiDimSizes, dimNames,
2146 2 : iNumType, m_groupDims);
2147 : }
2148 :
2149 : /************************************************************************/
2150 : /* HDF4EOSGridArray() */
2151 : /************************************************************************/
2152 :
2153 1 : HDF4EOSGridArray::HDF4EOSGridArray(
2154 : const std::string &osParentName, const std::string &osName,
2155 : const std::shared_ptr<HDF4SharedResources> &poShared,
2156 : const std::shared_ptr<HDF4GDHandle> &poGDHandle,
2157 : const std::vector<int32> &aiDimSizes, const std::string &dimNames,
2158 : int32 iNumType,
2159 1 : const std::vector<std::shared_ptr<GDALDimension>> &groupDims)
2160 : : GDALAbstractMDArray(osParentName, osName),
2161 : GDALPamMDArray(osParentName, osName, poShared->GetPAM()),
2162 : m_poShared(poShared), m_poGDHandle(poGDHandle),
2163 : m_dt(iNumType == DFNT_CHAR8 ? GDALExtendedDataType::CreateString()
2164 : : GDALExtendedDataType::Create(
2165 1 : HDF4Dataset::GetDataType(iNumType)))
2166 : {
2167 : CPLStringList aosDimNames(
2168 2 : CSLTokenizeString2(dimNames.c_str(), ",", CSLT_HONOURSTRINGS));
2169 1 : if (static_cast<size_t>(aosDimNames.size()) == aiDimSizes.size())
2170 : {
2171 1 : for (int i = 0; i < aosDimNames.size(); i++)
2172 : {
2173 0 : bool bFound = false;
2174 0 : for (const auto &poDim : groupDims)
2175 : {
2176 0 : if (poDim->GetName() == aosDimNames[i] &&
2177 0 : poDim->GetSize() == static_cast<GUInt64>(aiDimSizes[i]))
2178 : {
2179 0 : bFound = true;
2180 0 : m_dims.push_back(poDim);
2181 0 : break;
2182 : }
2183 : }
2184 0 : if (!bFound)
2185 : {
2186 0 : m_dims.push_back(std::make_shared<GDALDimension>(
2187 0 : std::string(), aosDimNames[i], std::string(), std::string(),
2188 0 : aiDimSizes[i]));
2189 : }
2190 : }
2191 : }
2192 1 : }
2193 :
2194 : /************************************************************************/
2195 : /* GetAttributes() */
2196 : /************************************************************************/
2197 :
2198 : std::vector<std::shared_ptr<GDALAttribute>>
2199 5 : HDF4EOSGridArray::GetAttributes(CSLConstList) const
2200 : {
2201 10 : CPLMutexHolderD(&hHDF4Mutex);
2202 5 : std::vector<std::shared_ptr<GDALAttribute>> ret;
2203 5 : int32 iSDS = 0;
2204 5 : if (GDsdid(m_poGDHandle->m_handle, GetName().c_str(), &iSDS) != -1)
2205 : {
2206 0 : int32 iRank = 0;
2207 0 : int32 iNumType = 0;
2208 0 : int32 nAttrs = 0;
2209 0 : std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
2210 :
2211 0 : if (SDgetinfo(iSDS, nullptr, &iRank, &aiDimSizes[0], &iNumType,
2212 0 : &nAttrs) == 0)
2213 : {
2214 0 : for (int32 iAttribute = 0; iAttribute < nAttrs; iAttribute++)
2215 : {
2216 0 : std::string osAttrName;
2217 0 : osAttrName.resize(H4_MAX_NC_NAME);
2218 0 : iNumType = 0;
2219 0 : int32 nValues = 0;
2220 0 : SDattrinfo(iSDS, iAttribute, &osAttrName[0], &iNumType,
2221 : &nValues);
2222 0 : osAttrName.resize(strlen(osAttrName.c_str()));
2223 0 : ret.emplace_back(std::make_shared<HDF4SDAttribute>(
2224 0 : GetFullName(), osAttrName, m_poShared, nullptr,
2225 0 : m_poGDHandle, iSDS, iAttribute, iNumType, nValues));
2226 : }
2227 : }
2228 : }
2229 10 : return ret;
2230 : }
2231 :
2232 : /************************************************************************/
2233 : /* GetRawNoDataValue() */
2234 : /************************************************************************/
2235 :
2236 1 : const void *HDF4EOSGridArray::GetRawNoDataValue() const
2237 : {
2238 1 : if (!m_abyNoData.empty())
2239 0 : return m_abyNoData.data();
2240 1 : m_abyNoData.resize(GetDataType().GetSize());
2241 :
2242 3 : auto poAttr = GetAttribute("_FillValue");
2243 1 : if (poAttr)
2244 : {
2245 0 : const double dfVal = poAttr->ReadAsDouble();
2246 0 : GDALExtendedDataType::CopyValue(
2247 0 : &dfVal, GDALExtendedDataType::Create(GDT_Float64), &m_abyNoData[0],
2248 : GetDataType());
2249 0 : return m_abyNoData.data();
2250 : }
2251 :
2252 2 : CPLMutexHolderD(&hHDF4Mutex);
2253 1 : if (GDgetfillvalue(m_poGDHandle->m_handle, GetName().c_str(),
2254 2 : &m_abyNoData[0]) != -1)
2255 : {
2256 0 : return m_abyNoData.data();
2257 : }
2258 1 : m_abyNoData.clear();
2259 1 : return nullptr;
2260 : }
2261 :
2262 : /************************************************************************/
2263 : /* GetOffsetOrScale() */
2264 : /************************************************************************/
2265 :
2266 4 : static double GetOffsetOrScale(const GDALMDArray *poArray,
2267 : const char *pszAttrName, double dfDefaultValue,
2268 : bool *pbHasVal, GDALDataType *peStorageType)
2269 : {
2270 12 : auto poAttr = poArray->GetAttribute(pszAttrName);
2271 4 : if (poAttr && (poAttr->GetDataType().GetNumericDataType() == GDT_Float32 ||
2272 4 : poAttr->GetDataType().GetNumericDataType() == GDT_Float64))
2273 : {
2274 0 : if (pbHasVal)
2275 0 : *pbHasVal = true;
2276 0 : if (peStorageType)
2277 0 : *peStorageType = poAttr->GetDataType().GetNumericDataType();
2278 0 : return poAttr->ReadAsDouble();
2279 : }
2280 4 : if (pbHasVal)
2281 4 : *pbHasVal = false;
2282 4 : return dfDefaultValue;
2283 : }
2284 :
2285 : /************************************************************************/
2286 : /* GetOffset() */
2287 : /************************************************************************/
2288 :
2289 2 : static double GetOffset(const GDALMDArray *poArray, bool *pbHasOffset,
2290 : GDALDataType *peStorageType)
2291 : {
2292 2 : return GetOffsetOrScale(poArray, "add_offset", 0, pbHasOffset,
2293 2 : peStorageType);
2294 : }
2295 :
2296 : /************************************************************************/
2297 : /* GetOffset() */
2298 : /************************************************************************/
2299 :
2300 1 : double HDF4EOSGridArray::GetOffset(bool *pbHasOffset,
2301 : GDALDataType *peStorageType) const
2302 : {
2303 1 : return ::GetOffset(this, pbHasOffset, peStorageType);
2304 : }
2305 :
2306 : /************************************************************************/
2307 : /* GetScale() */
2308 : /************************************************************************/
2309 :
2310 2 : static double GetScale(const GDALMDArray *poArray, bool *pbHasScale,
2311 : GDALDataType *peStorageType)
2312 : {
2313 2 : return GetOffsetOrScale(poArray, "scale_factor", 1, pbHasScale,
2314 2 : peStorageType);
2315 : }
2316 :
2317 : /************************************************************************/
2318 : /* GetScale() */
2319 : /************************************************************************/
2320 :
2321 1 : double HDF4EOSGridArray::GetScale(bool *pbHasScale,
2322 : GDALDataType *peStorageType) const
2323 : {
2324 1 : return ::GetScale(this, pbHasScale, peStorageType);
2325 : }
2326 :
2327 : /************************************************************************/
2328 : /* GetUnit() */
2329 : /************************************************************************/
2330 :
2331 1 : const std::string &HDF4EOSGridArray::GetUnit() const
2332 : {
2333 2 : auto poAttr = GetAttribute("units");
2334 1 : if (poAttr && poAttr->GetDataType().GetClass() == GEDTC_STRING)
2335 : {
2336 0 : const char *pszVal = poAttr->ReadAsString();
2337 0 : if (pszVal)
2338 0 : m_osUnit = pszVal;
2339 : }
2340 2 : return m_osUnit;
2341 : }
2342 :
2343 : /************************************************************************/
2344 : /* GetSpatialRef() */
2345 : /************************************************************************/
2346 :
2347 1 : std::shared_ptr<OGRSpatialReference> HDF4EOSGridArray::GetSpatialRef() const
2348 : {
2349 2 : CPLMutexHolderD(&hHDF4Mutex);
2350 1 : int32 iProjCode = 0;
2351 1 : int32 iZoneCode = 0;
2352 1 : int32 iSphereCode = 0;
2353 : double adfProjParams[15];
2354 :
2355 1 : if (GDprojinfo(m_poGDHandle->m_handle, &iProjCode, &iZoneCode, &iSphereCode,
2356 1 : adfProjParams) >= 0)
2357 : {
2358 2 : auto poSRS(std::make_shared<OGRSpatialReference>());
2359 1 : poSRS->importFromUSGS(iProjCode, iZoneCode, adfProjParams, iSphereCode,
2360 : USGS_ANGLE_RADIANS);
2361 1 : int iDimY = -1;
2362 1 : int iDimX = -1;
2363 1 : if (m_dims.size() >= 2)
2364 : {
2365 0 : iDimY = 1 + static_cast<int>(m_dims.size() - 2);
2366 0 : iDimX = 1 + static_cast<int>(m_dims.size() - 1);
2367 : }
2368 1 : if (iDimX > 0 && iDimY > 0)
2369 : {
2370 0 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2371 0 : if (poSRS->GetDataAxisToSRSAxisMapping() == std::vector<int>{2, 1})
2372 0 : poSRS->SetDataAxisToSRSAxisMapping({iDimY, iDimX});
2373 : else
2374 0 : poSRS->SetDataAxisToSRSAxisMapping({iDimX, iDimY});
2375 : }
2376 1 : return poSRS;
2377 : }
2378 0 : return nullptr;
2379 : }
2380 :
2381 : /************************************************************************/
2382 : /* IRead() */
2383 : /************************************************************************/
2384 :
2385 0 : bool HDF4EOSGridArray::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
2386 : const GInt64 *arrayStep,
2387 : const GPtrDiff_t *bufferStride,
2388 : const GDALExtendedDataType &bufferDataType,
2389 : void *pDstBuffer) const
2390 : {
2391 : ReadFunc readFunc;
2392 0 : readFunc.pReadField = GDreadfield;
2393 0 : return ReadPixels(arrayStartIdx, count, arrayStep, bufferStride,
2394 0 : bufferDataType, pDstBuffer, m_poShared, m_dt, m_dims,
2395 0 : m_poGDHandle->m_handle, GetName().c_str(), readFunc);
2396 : }
2397 :
2398 : /************************************************************************/
2399 : /* GetMDArrayNames() */
2400 : /************************************************************************/
2401 :
2402 4 : std::vector<std::string> HDF4SDSGroup::GetMDArrayNames(CSLConstList) const
2403 : {
2404 8 : CPLMutexHolderD(&hHDF4Mutex);
2405 4 : std::vector<std::string> ret;
2406 :
2407 4 : int32 nDatasets = 0;
2408 4 : int32 nAttrs = 0;
2409 4 : if (SDfileinfo(m_poShared->GetSDHandle(), &nDatasets, &nAttrs) != 0)
2410 0 : return ret;
2411 :
2412 8 : std::set<std::string> oSetNames;
2413 10 : for (int32 i = 0; i < nDatasets; i++)
2414 : {
2415 6 : const int32 iSDS = SDselect(m_poShared->GetSDHandle(), i);
2416 12 : std::string osName;
2417 6 : osName.resize(VSNAMELENMAX);
2418 6 : int32 iRank = 0;
2419 6 : int32 iNumType = 0;
2420 12 : std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
2421 6 : if (SDgetinfo(iSDS, &osName[0], &iRank, &aiDimSizes[0], &iNumType,
2422 6 : &nAttrs) == 0)
2423 : {
2424 6 : osName.resize(strlen(osName.c_str()));
2425 6 : int counter = 2;
2426 6 : std::string osRadix(osName);
2427 6 : while (oSetNames.find(osName) != oSetNames.end())
2428 : {
2429 0 : osName = osRadix + CPLSPrintf("_%d", counter);
2430 0 : counter++;
2431 : }
2432 6 : ret.push_back(osName);
2433 6 : m_oMapNameToSDSIdx[osName] = i;
2434 : }
2435 6 : SDendaccess(iSDS);
2436 : }
2437 :
2438 4 : if (m_bIsGDALDataset)
2439 : {
2440 2 : GetDimensions();
2441 2 : if (m_varX && m_varY)
2442 : {
2443 2 : ret.push_back(m_varX->GetName());
2444 2 : ret.push_back(m_varY->GetName());
2445 : }
2446 : }
2447 :
2448 4 : return ret;
2449 : }
2450 :
2451 : /************************************************************************/
2452 : /* OpenMDArray() */
2453 : /************************************************************************/
2454 :
2455 : std::shared_ptr<GDALMDArray>
2456 10 : HDF4SDSGroup::OpenMDArray(const std::string &osName, CSLConstList) const
2457 : {
2458 20 : CPLMutexHolderD(&hHDF4Mutex);
2459 10 : if (m_oMapNameToSDSIdx.empty())
2460 : {
2461 0 : GetMDArrayNames(nullptr);
2462 : }
2463 10 : auto oIter = m_oMapNameToSDSIdx.find(osName);
2464 10 : if (oIter == m_oMapNameToSDSIdx.end())
2465 : {
2466 2 : if (m_bIsGDALDataset)
2467 : {
2468 2 : GetDimensions();
2469 2 : if (m_varX && m_varX->GetName() == osName)
2470 : {
2471 1 : return m_varX;
2472 : }
2473 1 : if (m_varY && m_varY->GetName() == osName)
2474 : {
2475 1 : return m_varY;
2476 : }
2477 : }
2478 0 : return nullptr;
2479 : }
2480 8 : const int32 iSDS = SDselect(m_poShared->GetSDHandle(), oIter->second);
2481 :
2482 8 : int32 iRank = 0;
2483 8 : int32 iNumType = 0;
2484 8 : int32 nAttrs = 0;
2485 16 : std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
2486 8 : SDgetinfo(iSDS, nullptr, &iRank, &aiDimSizes[0], &iNumType, &nAttrs);
2487 8 : aiDimSizes.resize(iRank);
2488 :
2489 8 : auto ar = HDF4SDSArray::Create(GetFullName(), osName, m_poShared, iSDS,
2490 0 : aiDimSizes, GetDimensions(), iNumType,
2491 16 : nAttrs, m_bIsGDALDataset);
2492 8 : if (m_bIsGDALDataset)
2493 2 : ar->SetGlobalAttributes(m_oGlobalAttributes);
2494 8 : return ar;
2495 : }
2496 :
2497 : /************************************************************************/
2498 : /* GetDimensions() */
2499 : /************************************************************************/
2500 :
2501 : std::vector<std::shared_ptr<GDALDimension>>
2502 16 : HDF4SDSGroup::GetDimensions(CSLConstList) const
2503 : {
2504 32 : CPLMutexHolderD(&hHDF4Mutex);
2505 16 : if (m_bInGetDimensions)
2506 2 : return {};
2507 14 : if (!m_dims.empty())
2508 10 : return m_dims;
2509 4 : if (m_oMapNameToSDSIdx.empty())
2510 : {
2511 1 : m_bInGetDimensions = true;
2512 1 : GetMDArrayNames(nullptr);
2513 1 : m_bInGetDimensions = false;
2514 : }
2515 :
2516 8 : std::string osProjection;
2517 8 : std::string osTransformationMatrix;
2518 4 : if (m_bIsGDALDataset)
2519 : {
2520 8 : for (const auto &poAttr : m_oGlobalAttributes)
2521 : {
2522 8 : if (poAttr->GetName() == "Projection" &&
2523 2 : poAttr->GetDataType().GetClass() == GEDTC_STRING)
2524 : {
2525 2 : const char *pszVal = poAttr->ReadAsString();
2526 2 : if (pszVal)
2527 2 : osProjection = pszVal;
2528 : }
2529 6 : else if (poAttr->GetName() == "TransformationMatrix" &&
2530 2 : poAttr->GetDataType().GetClass() == GEDTC_STRING)
2531 : {
2532 2 : const char *pszVal = poAttr->ReadAsString();
2533 2 : if (pszVal)
2534 2 : osTransformationMatrix = pszVal;
2535 : }
2536 : }
2537 : }
2538 :
2539 : // First collect all dimension ids referenced by all datasets
2540 8 : std::map<int32, int32> oMapDimIdToDimSize;
2541 8 : std::set<std::string> oSetArrayNames;
2542 10 : for (const auto &oIter : m_oMapNameToSDSIdx)
2543 : {
2544 6 : const int32 iSDS = SDselect(m_poShared->GetSDHandle(), oIter.second);
2545 6 : int32 iRank = 0;
2546 6 : int32 iNumType = 0;
2547 6 : int32 nAttrs = 0;
2548 12 : std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
2549 6 : SDgetinfo(iSDS, nullptr, &iRank, &aiDimSizes[0], &iNumType, &nAttrs);
2550 17 : for (int i = 0; i < iRank; i++)
2551 : {
2552 11 : const auto dimId = SDgetdimid(iSDS, i);
2553 11 : oMapDimIdToDimSize[dimId] =
2554 11 : std::max(oMapDimIdToDimSize[dimId], aiDimSizes[i]);
2555 : }
2556 6 : oSetArrayNames.insert(oIter.first);
2557 6 : SDendaccess(iSDS);
2558 : }
2559 :
2560 : // Instantiate dimensions
2561 : std::set<std::shared_ptr<GDALDimensionWeakIndexingVar>>
2562 8 : oSetDimsWithVariable;
2563 13 : for (const auto &iter : oMapDimIdToDimSize)
2564 : {
2565 18 : std::string osName;
2566 9 : osName.resize(VSNAMELENMAX);
2567 9 : int32 iSize = 0; // can be 0 for unlimited dimension
2568 9 : int32 iNumType = 0;
2569 9 : int32 nAttrs = 0;
2570 9 : SDdiminfo(iter.first, &osName[0], &iSize, &iNumType, &nAttrs);
2571 9 : osName.resize(strlen(osName.c_str()));
2572 :
2573 18 : std::string osType;
2574 18 : std::string osDirection;
2575 9 : bool bIsIndexedDim = false;
2576 9 : if (iNumType > 0 && oSetArrayNames.find(osName) != oSetArrayNames.end())
2577 : {
2578 2 : bIsIndexedDim = true;
2579 2 : m_bInGetDimensions = true;
2580 4 : auto poArray(OpenMDArray(osName, nullptr));
2581 2 : m_bInGetDimensions = false;
2582 2 : if (poArray)
2583 : {
2584 6 : auto poAxis = poArray->GetAttribute("axis");
2585 2 : if (poAxis && poAxis->GetDataType().GetClass() == GEDTC_STRING)
2586 : {
2587 0 : const char *pszVal = poAxis->ReadAsString();
2588 0 : if (pszVal && EQUAL(pszVal, "X"))
2589 0 : osType = GDAL_DIM_TYPE_HORIZONTAL_X;
2590 0 : else if (pszVal && EQUAL(pszVal, "Y"))
2591 0 : osType = GDAL_DIM_TYPE_HORIZONTAL_Y;
2592 : }
2593 : }
2594 : }
2595 :
2596 : // Do not trust iSize which can be 0 for a unlimited dimension, but
2597 : // the size actually taken by the array(s)
2598 : auto poDim(std::make_shared<GDALDimensionWeakIndexingVar>(
2599 9 : GetFullName(), osName, osType, osDirection, iter.second));
2600 : // cppcheck-suppress knownConditionTrueFalse
2601 9 : if (bIsIndexedDim)
2602 : {
2603 2 : oSetDimsWithVariable.insert(poDim);
2604 : }
2605 9 : m_dims.push_back(poDim);
2606 : }
2607 :
2608 2 : if (m_bIsGDALDataset && (m_dims.size() == 2 || m_dims.size() == 3) &&
2609 6 : !osProjection.empty() && !osTransformationMatrix.empty())
2610 : {
2611 : CPLStringList aosCoeffs(
2612 4 : CSLTokenizeString2(osTransformationMatrix.c_str(), ",", 0));
2613 4 : if (aosCoeffs.size() == 6 && CPLAtof(aosCoeffs[2]) == 0 &&
2614 2 : CPLAtof(aosCoeffs[4]) == 0)
2615 : {
2616 : auto newDims = std::vector<std::shared_ptr<GDALDimension>>{
2617 4 : std::make_shared<GDALDimensionWeakIndexingVar>(
2618 2 : GetFullName(), "Y", GDAL_DIM_TYPE_HORIZONTAL_Y,
2619 2 : std::string(), m_dims[0]->GetSize()),
2620 4 : std::make_shared<GDALDimensionWeakIndexingVar>(
2621 2 : GetFullName(), "X", GDAL_DIM_TYPE_HORIZONTAL_X,
2622 14 : std::string(), m_dims[1]->GetSize())};
2623 2 : if (m_dims.size() == 3)
2624 : {
2625 1 : newDims.push_back(
2626 2 : std::make_shared<GDALDimensionWeakIndexingVar>(
2627 2 : GetFullName(), "Band", std::string(), std::string(),
2628 2 : m_dims[2]->GetSize()));
2629 : }
2630 2 : m_dims = std::move(newDims);
2631 :
2632 4 : m_varX = GDALMDArrayRegularlySpaced::Create(
2633 2 : GetFullName(), m_dims[1]->GetName(), m_dims[1],
2634 4 : CPLAtof(aosCoeffs[0]), CPLAtof(aosCoeffs[1]), 0.5);
2635 2 : m_dims[1]->SetIndexingVariable(m_varX);
2636 :
2637 4 : m_varY = GDALMDArrayRegularlySpaced::Create(
2638 2 : GetFullName(), m_dims[0]->GetName(), m_dims[0],
2639 4 : CPLAtof(aosCoeffs[3]), CPLAtof(aosCoeffs[5]), 0.5);
2640 2 : m_dims[0]->SetIndexingVariable(m_varY);
2641 : }
2642 : }
2643 :
2644 : // Now that we have eatablished all dimensions, we can link them to
2645 : // variables
2646 6 : for (auto &poDim : oSetDimsWithVariable)
2647 : {
2648 4 : auto poArray(OpenMDArray(poDim->GetName(), nullptr));
2649 2 : if (poArray)
2650 : {
2651 2 : m_oSetIndexingVariables.push_back(poArray);
2652 2 : poDim->SetIndexingVariable(std::move(poArray));
2653 : }
2654 : }
2655 :
2656 4 : return m_dims;
2657 : }
2658 :
2659 : /************************************************************************/
2660 : /* HDF4SDSArray() */
2661 : /************************************************************************/
2662 :
2663 8 : HDF4SDSArray::HDF4SDSArray(
2664 : const std::string &osParentName, const std::string &osName,
2665 : const std::shared_ptr<HDF4SharedResources> &poShared, int32 iSDS,
2666 : const std::vector<int32> &aiDimSizes,
2667 : const std::vector<std::shared_ptr<GDALDimension>> &groupDims,
2668 8 : int32 iNumType, int32 nAttrs, bool bIsGDALDS)
2669 : : GDALAbstractMDArray(osParentName, osName),
2670 : GDALPamMDArray(osParentName, osName, poShared->GetPAM()),
2671 : m_poShared(poShared), m_iSDS(iSDS),
2672 : m_dt(iNumType == DFNT_CHAR8 ? GDALExtendedDataType::CreateString()
2673 : : GDALExtendedDataType::Create(
2674 : HDF4Dataset::GetDataType(iNumType))),
2675 8 : m_nAttributes(nAttrs), m_bIsGDALDataset(bIsGDALDS)
2676 : {
2677 21 : for (int i = 0; i < static_cast<int>(aiDimSizes.size()); i++)
2678 : {
2679 26 : std::string osDimName;
2680 13 : osDimName.resize(VSNAMELENMAX);
2681 13 : int32 iSize = 0;
2682 13 : int32 iDimNumType = 0;
2683 13 : int32 nDimAttrs = 0;
2684 13 : int32 dimId = SDgetdimid(iSDS, i);
2685 13 : SDdiminfo(dimId, &osDimName[0], &iSize, &iDimNumType, &nDimAttrs);
2686 13 : osDimName.resize(strlen(osDimName.c_str()));
2687 13 : bool bFound = false;
2688 20 : for (const auto &poDim : groupDims)
2689 : {
2690 30 : if (poDim->GetName() == osDimName ||
2691 12 : (bIsGDALDS && i == 0 && poDim->GetName() == "Y") ||
2692 35 : (bIsGDALDS && i == 1 && poDim->GetName() == "X") ||
2693 5 : (bIsGDALDS && i == 2 && poDim->GetName() == "Band"))
2694 : {
2695 11 : bFound = true;
2696 11 : m_dims.push_back(poDim);
2697 11 : break;
2698 : }
2699 : }
2700 13 : if (!bFound)
2701 : {
2702 2 : m_dims.push_back(std::make_shared<GDALDimension>(
2703 4 : std::string(), CPLSPrintf("dim%d", i), std::string(),
2704 4 : std::string(), aiDimSizes[i]));
2705 : }
2706 : }
2707 8 : }
2708 :
2709 : /************************************************************************/
2710 : /* ~HDF4SDSArray() */
2711 : /************************************************************************/
2712 :
2713 16 : HDF4SDSArray::~HDF4SDSArray()
2714 : {
2715 16 : CPLMutexHolderD(&hHDF4Mutex);
2716 8 : SDendaccess(m_iSDS);
2717 16 : }
2718 :
2719 : /************************************************************************/
2720 : /* GetRawNoDataValue() */
2721 : /************************************************************************/
2722 :
2723 1 : const void *HDF4SDSArray::GetRawNoDataValue() const
2724 : {
2725 1 : if (!m_abyNoData.empty())
2726 0 : return m_abyNoData.data();
2727 1 : m_abyNoData.resize(GetDataType().GetSize());
2728 :
2729 3 : auto poAttr = GetAttribute("_FillValue");
2730 1 : if (poAttr)
2731 : {
2732 0 : const double dfVal = poAttr->ReadAsDouble();
2733 0 : GDALExtendedDataType::CopyValue(
2734 0 : &dfVal, GDALExtendedDataType::Create(GDT_Float64), &m_abyNoData[0],
2735 : GetDataType());
2736 0 : return m_abyNoData.data();
2737 : }
2738 :
2739 2 : CPLMutexHolderD(&hHDF4Mutex);
2740 1 : if (SDgetfillvalue(m_iSDS, &m_abyNoData[0]) != -1)
2741 : {
2742 0 : return m_abyNoData.data();
2743 : }
2744 :
2745 1 : m_abyNoData.clear();
2746 1 : return nullptr;
2747 : }
2748 :
2749 : /************************************************************************/
2750 : /* GetAttributes() */
2751 : /************************************************************************/
2752 :
2753 : std::vector<std::shared_ptr<GDALAttribute>>
2754 9 : HDF4SDSArray::GetAttributes(CSLConstList) const
2755 : {
2756 18 : CPLMutexHolderD(&hHDF4Mutex);
2757 9 : std::vector<std::shared_ptr<GDALAttribute>> ret;
2758 :
2759 13 : for (int32 iAttribute = 0; iAttribute < m_nAttributes; iAttribute++)
2760 : {
2761 4 : std::string osAttrName;
2762 4 : osAttrName.resize(H4_MAX_NC_NAME);
2763 4 : int32 iNumType = 0;
2764 4 : int32 nValues = 0;
2765 4 : SDattrinfo(m_iSDS, iAttribute, &osAttrName[0], &iNumType, &nValues);
2766 4 : osAttrName.resize(strlen(osAttrName.c_str()));
2767 8 : ret.emplace_back(std::make_shared<HDF4SDAttribute>(
2768 8 : GetFullName(), osAttrName, m_poShared, nullptr, nullptr, m_iSDS,
2769 4 : iAttribute, iNumType, nValues));
2770 : }
2771 :
2772 18 : return ret;
2773 : }
2774 :
2775 : /************************************************************************/
2776 : /* GetOffset() */
2777 : /************************************************************************/
2778 :
2779 1 : double HDF4SDSArray::GetOffset(bool *pbHasOffset,
2780 : GDALDataType *peStorageType) const
2781 : {
2782 1 : return ::GetOffset(this, pbHasOffset, peStorageType);
2783 : }
2784 :
2785 : /************************************************************************/
2786 : /* GetScale() */
2787 : /************************************************************************/
2788 :
2789 1 : double HDF4SDSArray::GetScale(bool *pbHasScale,
2790 : GDALDataType *peStorageType) const
2791 : {
2792 1 : return ::GetScale(this, pbHasScale, peStorageType);
2793 : }
2794 :
2795 : /************************************************************************/
2796 : /* GetUnit() */
2797 : /************************************************************************/
2798 :
2799 2 : const std::string &HDF4SDSArray::GetUnit() const
2800 : {
2801 4 : auto poAttr = GetAttribute("units");
2802 2 : if (poAttr && poAttr->GetDataType().GetClass() == GEDTC_STRING)
2803 : {
2804 0 : const char *pszVal = poAttr->ReadAsString();
2805 0 : if (pszVal)
2806 0 : m_osUnit = pszVal;
2807 : }
2808 4 : return m_osUnit;
2809 : }
2810 :
2811 : /************************************************************************/
2812 : /* GetSpatialRef() */
2813 : /************************************************************************/
2814 :
2815 3 : std::shared_ptr<OGRSpatialReference> HDF4SDSArray::GetSpatialRef() const
2816 : {
2817 3 : if (m_bIsGDALDataset)
2818 : {
2819 2 : std::string osProjection;
2820 6 : for (const auto &poAttr : m_oGlobalAttributes)
2821 : {
2822 8 : if (poAttr->GetName() == "Projection" &&
2823 2 : poAttr->GetDataType().GetClass() == GEDTC_STRING)
2824 : {
2825 2 : const char *pszVal = poAttr->ReadAsString();
2826 2 : if (pszVal)
2827 2 : osProjection = pszVal;
2828 2 : break;
2829 : }
2830 : }
2831 2 : if (!osProjection.empty())
2832 : {
2833 4 : auto poSRS(std::make_shared<OGRSpatialReference>());
2834 2 : poSRS->SetFromUserInput(
2835 : osProjection.c_str(),
2836 : OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get());
2837 2 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2838 2 : if (poSRS->GetDataAxisToSRSAxisMapping() == std::vector<int>{2, 1})
2839 0 : poSRS->SetDataAxisToSRSAxisMapping({1, 2});
2840 : else
2841 2 : poSRS->SetDataAxisToSRSAxisMapping({2, 1});
2842 2 : return poSRS;
2843 : }
2844 : }
2845 1 : return nullptr;
2846 : }
2847 :
2848 : /************************************************************************/
2849 : /* IRead() */
2850 : /************************************************************************/
2851 :
2852 4 : bool HDF4SDSArray::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
2853 : const GInt64 *arrayStep,
2854 : const GPtrDiff_t *bufferStride,
2855 : const GDALExtendedDataType &bufferDataType,
2856 : void *pDstBuffer) const
2857 : {
2858 : ReadFunc readFunc;
2859 4 : readFunc.pReadData = SDreaddata;
2860 8 : return ReadPixels(arrayStartIdx, count, arrayStep, bufferStride,
2861 4 : bufferDataType, pDstBuffer, m_poShared, m_dt, m_dims,
2862 8 : m_iSDS, nullptr, readFunc);
2863 : }
2864 :
2865 : /************************************************************************/
2866 : /* GetMDArrayNames() */
2867 : /************************************************************************/
2868 :
2869 2 : std::vector<std::string> HDF4GRsGroup::GetMDArrayNames(CSLConstList) const
2870 : {
2871 4 : CPLMutexHolderD(&hHDF4Mutex);
2872 2 : std::vector<std::string> res;
2873 :
2874 2 : int32 nImages = 0;
2875 2 : int32 nAttrs = 0;
2876 2 : GRfileinfo(m_poGRsHandle->m_grHandle, &nImages, &nAttrs);
2877 4 : for (int32 i = 0; i < nImages; i++)
2878 : {
2879 2 : const int32 iGR = GRselect(m_poGRsHandle->m_grHandle, i);
2880 :
2881 4 : std::string osName;
2882 2 : osName.resize(VSNAMELENMAX);
2883 2 : int32 nBands = 0;
2884 2 : int32 iNumType = 0;
2885 2 : int32 iInterlaceMode = 0;
2886 4 : std::vector<int32> aiDimSizes(2);
2887 2 : if (GRgetiminfo(iGR, &osName[0], &nBands, &iNumType, &iInterlaceMode,
2888 4 : &aiDimSizes[0], &nAttrs) == 0)
2889 : {
2890 2 : osName.resize(strlen(osName.c_str()));
2891 2 : m_oMapNameToGRIdx[osName] = i;
2892 2 : res.push_back(std::move(osName));
2893 : }
2894 :
2895 2 : GRendaccess(iGR);
2896 : }
2897 4 : return res;
2898 : }
2899 :
2900 : /************************************************************************/
2901 : /* GetAttributes() */
2902 : /************************************************************************/
2903 :
2904 : std::vector<std::shared_ptr<GDALAttribute>>
2905 2 : HDF4GRsGroup::GetAttributes(CSLConstList) const
2906 : {
2907 4 : CPLMutexHolderD(&hHDF4Mutex);
2908 2 : std::vector<std::shared_ptr<GDALAttribute>> ret;
2909 2 : int32 nDatasets = 0;
2910 2 : int32 nAttributes = 0;
2911 2 : if (GRfileinfo(m_poGRsHandle->m_grHandle, &nDatasets, &nAttributes) != 0)
2912 0 : return ret;
2913 6 : for (int32 iAttribute = 0; iAttribute < nAttributes; iAttribute++)
2914 : {
2915 4 : int32 iNumType = 0;
2916 4 : int32 nValues = 0;
2917 :
2918 4 : std::string osAttrName;
2919 4 : osAttrName.resize(H4_MAX_NC_NAME);
2920 4 : GRattrinfo(m_poGRsHandle->m_grHandle, iAttribute, &osAttrName[0],
2921 : &iNumType, &nValues);
2922 4 : osAttrName.resize(strlen(osAttrName.c_str()));
2923 :
2924 8 : ret.emplace_back(std::make_shared<HDF4GRAttribute>(
2925 4 : GetFullName(), osAttrName, m_poShared, m_poGRsHandle, nullptr,
2926 8 : m_poGRsHandle->m_grHandle, iAttribute, iNumType, nValues));
2927 : }
2928 2 : return ret;
2929 : }
2930 :
2931 : /************************************************************************/
2932 : /* OpenMDArray() */
2933 : /************************************************************************/
2934 :
2935 : std::shared_ptr<GDALMDArray>
2936 3 : HDF4GRsGroup::OpenMDArray(const std::string &osName, CSLConstList) const
2937 : {
2938 6 : CPLMutexHolderD(&hHDF4Mutex);
2939 3 : if (m_oMapNameToGRIdx.empty())
2940 : {
2941 1 : GetMDArrayNames(nullptr);
2942 : }
2943 3 : auto oIter = m_oMapNameToGRIdx.find(osName);
2944 3 : if (oIter == m_oMapNameToGRIdx.end())
2945 : {
2946 1 : return nullptr;
2947 : }
2948 2 : const int32 iGR = GRselect(m_poGRsHandle->m_grHandle, oIter->second);
2949 :
2950 2 : int32 nBands = 0;
2951 2 : int32 iNumType = 0;
2952 2 : int32 iInterlaceMode = 0;
2953 2 : std::vector<int32> aiDimSizes(2);
2954 : int32 nAttrs;
2955 2 : GRgetiminfo(iGR, nullptr, &nBands, &iNumType, &iInterlaceMode,
2956 2 : &aiDimSizes[0], &nAttrs);
2957 :
2958 4 : return HDF4GRArray::Create(
2959 2 : GetFullName(), osName, m_poShared,
2960 4 : std::make_shared<HDF4GRHandle>(m_poGRsHandle, iGR), nBands, aiDimSizes,
2961 2 : iNumType, nAttrs);
2962 : }
2963 :
2964 : /************************************************************************/
2965 : /* HDF4GRArray() */
2966 : /************************************************************************/
2967 :
2968 2 : HDF4GRArray::HDF4GRArray(const std::string &osParentName,
2969 : const std::string &osName,
2970 : const std::shared_ptr<HDF4SharedResources> &poShared,
2971 : const std::shared_ptr<HDF4GRHandle> &poGRHandle,
2972 : int32 nBands, const std::vector<int32> &aiDimSizes,
2973 2 : int32 iNumType, int32 nAttrs)
2974 : : GDALAbstractMDArray(osParentName, osName),
2975 : GDALPamMDArray(osParentName, osName, poShared->GetPAM()),
2976 : m_poShared(poShared), m_poGRHandle(poGRHandle),
2977 : m_dt(iNumType == DFNT_CHAR8 ? GDALExtendedDataType::CreateString()
2978 : : GDALExtendedDataType::Create(
2979 : HDF4Dataset::GetDataType(iNumType))),
2980 2 : m_nAttributes(nAttrs)
2981 : {
2982 6 : for (int i = 0; i < static_cast<int>(aiDimSizes.size()); i++)
2983 : {
2984 8 : m_dims.push_back(std::make_shared<GDALDimension>(
2985 12 : std::string(), i == 0 ? "y" : "x", std::string(), std::string(),
2986 4 : aiDimSizes[i]));
2987 : }
2988 2 : m_dims.push_back(std::make_shared<GDALDimension>(
2989 4 : std::string(), "bands", std::string(), std::string(), nBands));
2990 2 : }
2991 :
2992 : /************************************************************************/
2993 : /* GetAttributes() */
2994 : /************************************************************************/
2995 :
2996 : std::vector<std::shared_ptr<GDALAttribute>>
2997 4 : HDF4GRArray::GetAttributes(CSLConstList) const
2998 : {
2999 8 : CPLMutexHolderD(&hHDF4Mutex);
3000 4 : std::vector<std::shared_ptr<GDALAttribute>> ret;
3001 10 : for (int32 iAttribute = 0; iAttribute < m_nAttributes; iAttribute++)
3002 : {
3003 6 : int32 iNumType = 0;
3004 6 : int32 nValues = 0;
3005 :
3006 6 : std::string osAttrName;
3007 6 : osAttrName.resize(H4_MAX_NC_NAME);
3008 6 : GRattrinfo(m_poGRHandle->m_iGR, iAttribute, &osAttrName[0], &iNumType,
3009 : &nValues);
3010 6 : osAttrName.resize(strlen(osAttrName.c_str()));
3011 :
3012 12 : ret.emplace_back(std::make_shared<HDF4GRAttribute>(
3013 6 : GetFullName(), osAttrName, m_poShared, nullptr, m_poGRHandle,
3014 12 : m_poGRHandle->m_iGR, iAttribute, iNumType, nValues));
3015 : }
3016 :
3017 4 : auto iPal = GRgetlutid(m_poGRHandle->m_iGR, 0);
3018 4 : if (iPal != -1)
3019 : {
3020 4 : int32 nComps = 0;
3021 4 : int32 iPalDataType = 0;
3022 4 : int32 iPalInterlaceMode = 0;
3023 4 : int32 nPalEntries = 0;
3024 4 : GRgetlutinfo(iPal, &nComps, &iPalDataType, &iPalInterlaceMode,
3025 : &nPalEntries);
3026 1 : if (nPalEntries && nComps == 3 &&
3027 1 : GDALGetDataTypeSizeBytes(HDF4Dataset::GetDataType(iPalDataType)) ==
3028 5 : 1 &&
3029 1 : nPalEntries <= 256)
3030 : {
3031 2 : ret.emplace_back(std::make_shared<HDF4GRPalette>(
3032 1 : GetFullName(), "lut", m_poShared, m_poGRHandle, iPal,
3033 1 : nPalEntries));
3034 : }
3035 : }
3036 :
3037 8 : return ret;
3038 : }
3039 :
3040 : /************************************************************************/
3041 : /* IRead() */
3042 : /************************************************************************/
3043 :
3044 4 : bool HDF4GRArray::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
3045 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
3046 : const GDALExtendedDataType &bufferDataType,
3047 : void *pDstBuffer) const
3048 : {
3049 8 : CPLMutexHolderD(&hHDF4Mutex);
3050 : /* -------------------------------------------------------------------- */
3051 : /* HDF files with external data files, such as some landsat */
3052 : /* products (eg. data/hdf/L1G) need to be told what directory */
3053 : /* to look in to find the external files. Normally this is the */
3054 : /* directory holding the hdf file. */
3055 : /* -------------------------------------------------------------------- */
3056 4 : HXsetdir(CPLGetPathSafe(m_poShared->GetFilename().c_str()).c_str());
3057 :
3058 4 : const size_t nDims(m_dims.size());
3059 8 : std::vector<int32> sw_start(nDims);
3060 8 : std::vector<int32> sw_stride(nDims);
3061 8 : std::vector<int32> sw_edge(nDims);
3062 8 : std::vector<GPtrDiff_t> newBufferStride(nDims);
3063 4 : GByte *pabyDstBuffer = static_cast<GByte *>(pDstBuffer);
3064 4 : const size_t nBufferDataTypeSize = bufferDataType.GetSize();
3065 16 : for (size_t i = 0; i < nDims; i++)
3066 : {
3067 12 : sw_start[i] = static_cast<int>(arrayStartIdx[i]);
3068 12 : sw_stride[i] = static_cast<int>(arrayStep[i]);
3069 12 : sw_edge[i] = static_cast<int>(count[i]);
3070 12 : newBufferStride[i] = bufferStride[i];
3071 12 : if (sw_stride[i] < 0)
3072 : {
3073 : // GRreadimage() doesn't like negative step / array stride, so
3074 : // transform the request to a classic "left-to-right" one
3075 1 : sw_start[i] += sw_stride[i] * (sw_edge[i] - 1);
3076 1 : sw_stride[i] = -sw_stride[i];
3077 1 : pabyDstBuffer +=
3078 1 : (sw_edge[i] - 1) * newBufferStride[i] * nBufferDataTypeSize;
3079 1 : newBufferStride[i] = -newBufferStride[i];
3080 : }
3081 : }
3082 4 : size_t nExpectedStride = 1;
3083 4 : bool bContiguousStride = true;
3084 13 : for (size_t i = nDims; i > 0;)
3085 : {
3086 10 : --i;
3087 10 : if (newBufferStride[i] != static_cast<GPtrDiff_t>(nExpectedStride))
3088 : {
3089 1 : bContiguousStride = false;
3090 1 : break;
3091 : }
3092 9 : nExpectedStride *= count[i];
3093 : }
3094 10 : if (bufferDataType == m_dt && bContiguousStride && arrayStartIdx[2] == 0 &&
3095 10 : count[2] == m_dims[2]->GetSize() && arrayStep[2] == 1)
3096 : {
3097 1 : auto status = GRreadimage(m_poGRHandle->m_iGR, &sw_start[0],
3098 1 : &sw_stride[0], &sw_edge[0], pabyDstBuffer);
3099 1 : return status >= 0;
3100 : }
3101 3 : auto pabyTemp = static_cast<GByte *>(VSI_MALLOC2_VERBOSE(
3102 : m_dt.GetSize(),
3103 : count[0] * count[1] * static_cast<size_t>(m_dims[2]->GetSize())));
3104 3 : if (pabyTemp == nullptr)
3105 0 : return false;
3106 3 : auto status = GRreadimage(m_poGRHandle->m_iGR, &sw_start[0], &sw_stride[0],
3107 3 : &sw_edge[0], pabyTemp);
3108 3 : if (status < 0)
3109 : {
3110 0 : VSIFree(pabyTemp);
3111 0 : return false;
3112 : }
3113 :
3114 3 : const size_t nSrcDataTypeSize = m_dt.GetSize();
3115 6 : std::vector<size_t> anStackCount(nDims);
3116 3 : GByte *pabySrc = pabyTemp + nSrcDataTypeSize * sw_start[2];
3117 3 : std::vector<GByte *> pabyDstBufferStack(nDims + 1);
3118 3 : pabyDstBufferStack[0] = pabyDstBuffer;
3119 3 : size_t iDim = 0;
3120 54 : lbl_next_depth:
3121 54 : if (iDim == nDims)
3122 : {
3123 24 : GDALExtendedDataType::CopyValue(
3124 24 : pabySrc, m_dt, pabyDstBufferStack[nDims], bufferDataType);
3125 24 : pabySrc += nSrcDataTypeSize * sw_stride[2];
3126 : }
3127 : else
3128 : {
3129 30 : anStackCount[iDim] = count[iDim];
3130 : while (true)
3131 : {
3132 51 : ++iDim;
3133 51 : pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
3134 51 : goto lbl_next_depth;
3135 51 : lbl_return_to_caller_in_loop:
3136 51 : --iDim;
3137 51 : --anStackCount[iDim];
3138 51 : if (anStackCount[iDim] == 0)
3139 30 : break;
3140 21 : IncrPointer(pabyDstBufferStack[iDim], newBufferStride[iDim],
3141 : nBufferDataTypeSize);
3142 : }
3143 30 : if (iDim == 2)
3144 18 : pabySrc +=
3145 18 : nSrcDataTypeSize * static_cast<size_t>(m_dims[2]->GetSize() -
3146 18 : count[2] * sw_stride[2]);
3147 : }
3148 54 : if (iDim > 0)
3149 51 : goto lbl_return_to_caller_in_loop;
3150 :
3151 3 : VSIFree(pabyTemp);
3152 3 : return true;
3153 : }
3154 :
3155 : /************************************************************************/
3156 : /* HDF4GRPalette() */
3157 : /************************************************************************/
3158 :
3159 1 : HDF4GRPalette::HDF4GRPalette(
3160 : const std::string &osParentName, const std::string &osName,
3161 : const std::shared_ptr<HDF4SharedResources> &poShared,
3162 1 : const std::shared_ptr<HDF4GRHandle> &poGRHandle, int32 iPal, int32 nValues)
3163 : : GDALAbstractMDArray(osParentName, osName),
3164 : GDALAttribute(osParentName, osName), m_poShared(poShared),
3165 1 : m_poGRHandle(poGRHandle), m_iPal(iPal), m_nValues(nValues)
3166 : {
3167 1 : m_dims.push_back(std::make_shared<GDALDimension>(
3168 2 : std::string(), "index", std::string(), std::string(), nValues));
3169 1 : m_dims.push_back(std::make_shared<GDALDimension>(
3170 2 : std::string(), "component", std::string(), std::string(), 3));
3171 1 : }
3172 :
3173 : /************************************************************************/
3174 : /* IRead() */
3175 : /************************************************************************/
3176 :
3177 1 : bool HDF4GRPalette::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
3178 : const GInt64 *arrayStep,
3179 : const GPtrDiff_t *bufferStride,
3180 : const GDALExtendedDataType &bufferDataType,
3181 : void *pDstBuffer) const
3182 : {
3183 2 : CPLMutexHolderD(&hHDF4Mutex);
3184 :
3185 2 : std::vector<GByte> abyValues(3 * m_nValues);
3186 1 : GRreadlut(m_iPal, &abyValues[0]);
3187 :
3188 1 : GByte *pabyDstBuffer = static_cast<GByte *>(pDstBuffer);
3189 1 : const size_t nBufferDataTypeSize = bufferDataType.GetSize();
3190 1 : const auto srcDt(GDALExtendedDataType::Create(GDT_UInt8));
3191 257 : for (size_t i = 0; i < count[0]; ++i)
3192 : {
3193 256 : size_t idx = static_cast<size_t>(arrayStartIdx[0] + i * arrayStep[0]);
3194 1024 : for (size_t j = 0; j < count[1]; ++j)
3195 : {
3196 768 : size_t comp =
3197 768 : static_cast<size_t>(arrayStartIdx[1] + j * arrayStep[1]);
3198 768 : GByte *pDst =
3199 768 : pabyDstBuffer + (i * bufferStride[0] + j * bufferStride[1]) *
3200 : nBufferDataTypeSize;
3201 768 : GDALExtendedDataType::CopyValue(&abyValues[3 * idx + comp], srcDt,
3202 : pDst, bufferDataType);
3203 : }
3204 : }
3205 :
3206 2 : return true;
3207 : }
3208 :
3209 : /************************************************************************/
3210 : /* OpenMultiDim() */
3211 : /************************************************************************/
3212 :
3213 12 : void HDF4Dataset::OpenMultiDim(const char *pszFilename,
3214 : CSLConstList papszOpenOptionsIn)
3215 : {
3216 : // under hHDF4Mutex
3217 :
3218 24 : auto poShared = std::make_shared<HDF4SharedResources>(pszFilename);
3219 12 : poShared->m_hSD = hSD;
3220 12 : poShared->m_aosOpenOptions = papszOpenOptionsIn;
3221 :
3222 12 : hSD = -1;
3223 :
3224 12 : m_poRootGroup = HDF4Group::Create(std::string(), "/", poShared);
3225 :
3226 12 : SetDescription(pszFilename);
3227 :
3228 : // Setup/check for pam .aux.xml.
3229 12 : TryLoadXML();
3230 12 : }
|