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 65 : int32 GetSDHandle() const
51 : {
52 65 : return m_hSD;
53 : }
54 :
55 40 : const std::string &GetFilename() const
56 : {
57 40 : return m_osFilename;
58 : }
59 :
60 4 : const char *FetchOpenOption(const char *pszName,
61 : const char *pszDefault) const
62 : {
63 4 : return m_aosOpenOptions.FetchNameValueDef(pszName, pszDefault);
64 : }
65 :
66 10 : const std::shared_ptr<GDALPamMultiDim> &GetPAM()
67 : {
68 10 : 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 6 : 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 6 : new HDF4Group(osParentName, osName, poShared));
94 6 : poGroup->SetSelf(poGroup);
95 6 : 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 0 : explicit HDF4SwathsHandle(int32 handle) : m_handle(handle)
162 : {
163 0 : }
164 :
165 0 : ~HDF4SwathsHandle()
166 0 : {
167 0 : CPLMutexHolderD(&hHDF4Mutex);
168 0 : SWclose(m_handle);
169 0 : }
170 : };
171 :
172 : /************************************************************************/
173 : /* HDF4SwathHandle */
174 : /************************************************************************/
175 :
176 : struct HDF4SwathHandle
177 : {
178 : std::shared_ptr<HDF4SwathsHandle> m_poSwathsHandle;
179 : int32 m_handle;
180 :
181 0 : explicit HDF4SwathHandle(
182 : const std::shared_ptr<HDF4SwathsHandle> &poSwathsHandle, int32 handle)
183 0 : : m_poSwathsHandle(poSwathsHandle), m_handle(handle)
184 : {
185 0 : }
186 :
187 0 : ~HDF4SwathHandle()
188 0 : {
189 0 : CPLMutexHolderD(&hHDF4Mutex);
190 0 : SWdetach(m_handle);
191 0 : }
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 0 : HDF4SwathsGroup(const std::string &osParentName, const std::string &osName,
205 : const std::shared_ptr<HDF4SharedResources> &poShared,
206 : const std::shared_ptr<HDF4SwathsHandle> &poSwathsHandle)
207 0 : : GDALGroup(osParentName, osName), m_poShared(poShared),
208 0 : m_poSwathsHandle(poSwathsHandle)
209 : {
210 0 : }
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 0 : HDF4SwathGroup(const std::string &osParentName, const std::string &osName,
230 : const std::shared_ptr<HDF4SharedResources> &poShared,
231 : const std::shared_ptr<HDF4SwathHandle> &poSwathHandle)
232 0 : : GDALGroup(osParentName, osName), m_poShared(poShared),
233 0 : m_poSwathHandle(poSwathHandle)
234 : {
235 0 : }
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 0 : 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 0 : : GDALGroup(osParentName, osName), m_poShared(poShared),
267 : m_poSwathHandle(poSwathHandle), m_entryType(entryType),
268 0 : m_groupDims(groupDims)
269 : {
270 0 : }
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 0 : explicit HDF4GDsHandle(int32 handle) : m_handle(handle)
386 : {
387 0 : }
388 :
389 0 : ~HDF4GDsHandle()
390 0 : {
391 0 : CPLMutexHolderD(&hHDF4Mutex);
392 0 : GDclose(m_handle);
393 0 : }
394 : };
395 :
396 : /************************************************************************/
397 : /* HDF4GDHandle */
398 : /************************************************************************/
399 :
400 : struct HDF4GDHandle
401 : {
402 : std::shared_ptr<HDF4GDsHandle> m_poGDsHandle;
403 : int32 m_handle;
404 :
405 0 : explicit HDF4GDHandle(const std::shared_ptr<HDF4GDsHandle> &poGDsHandle,
406 : int32 handle)
407 0 : : m_poGDsHandle(poGDsHandle), m_handle(handle)
408 : {
409 0 : }
410 :
411 0 : ~HDF4GDHandle()
412 0 : {
413 0 : CPLMutexHolderD(&hHDF4Mutex);
414 0 : GDdetach(m_handle);
415 0 : }
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 0 : 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 0 : : GDALGroup(osParentName, osName), m_poShared(poShared),
433 0 : m_poGDsHandle(poGDsHandle)
434 : {
435 0 : }
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 0 : HDF4EOSGridGroup(const std::string &osParentName, const std::string &osName,
457 : const std::shared_ptr<HDF4SharedResources> &poShared,
458 : const std::shared_ptr<HDF4GDHandle> &poGDHandle)
459 0 : : GDALGroup(osParentName, osName), m_poShared(poShared),
460 0 : m_poGDHandle(poGDHandle)
461 : {
462 0 : }
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 0 : 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 0 : : GDALGroup(osParentName, osName), m_poShared(poShared),
500 : m_poGDHandle(poGDHandle), m_entryType(entryType),
501 0 : m_groupDims(groupDims)
502 : {
503 0 : }
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 0 : 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 0 : aiDimSizes, dimNames, iNumType, groupDims)));
550 0 : ar->SetSelf(ar);
551 0 : 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 0 : GetDimensions() const override
566 : {
567 0 : return m_dims;
568 : }
569 :
570 0 : const GDALExtendedDataType &GetDataType() const override
571 : {
572 0 : 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_Byte);
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 6 : HDF4SharedResources::HDF4SharedResources(const std::string &osFilename)
1018 : : m_osFilename(osFilename),
1019 6 : m_poPAM(std::make_shared<GDALPamMultiDim>(osFilename))
1020 : {
1021 6 : }
1022 :
1023 : /************************************************************************/
1024 : /* ~HDF4SharedResources() */
1025 : /************************************************************************/
1026 :
1027 6 : HDF4SharedResources::~HDF4SharedResources()
1028 : {
1029 12 : CPLMutexHolderD(&hHDF4Mutex);
1030 :
1031 6 : if (m_hSD)
1032 6 : SDend(m_hSD);
1033 6 : }
1034 :
1035 : /************************************************************************/
1036 : /* HDF4Group() */
1037 : /************************************************************************/
1038 :
1039 6 : HDF4Group::HDF4Group(const std::string &osParentName, const std::string &osName,
1040 6 : const std::shared_ptr<HDF4SharedResources> &poShared)
1041 6 : : GDALGroup(osParentName, osName), m_poShared(poShared)
1042 : {
1043 6 : bool bIsGDALDS = false;
1044 18 : auto poAttr = GetAttribute("Signature");
1045 6 : 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 6 : 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 6 : }
1061 :
1062 : /************************************************************************/
1063 : /* GetAttributes() */
1064 : /************************************************************************/
1065 :
1066 : std::vector<std::shared_ptr<GDALAttribute>>
1067 9 : HDF4Group::GetAttributes(CSLConstList) const
1068 : {
1069 18 : CPLMutexHolderD(&hHDF4Mutex);
1070 9 : std::vector<std::shared_ptr<GDALAttribute>> ret;
1071 9 : int32 nDatasets = 0;
1072 9 : int32 nAttributes = 0;
1073 9 : if (SDfileinfo(m_poShared->GetSDHandle(), &nDatasets, &nAttributes) != 0)
1074 0 : return ret;
1075 :
1076 18 : 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 9 : };
1100 :
1101 23 : for (int32 iAttribute = 0; iAttribute < nAttributes; iAttribute++)
1102 : {
1103 14 : int32 iNumType = 0;
1104 14 : int32 nValues = 0;
1105 :
1106 14 : std::string osAttrName;
1107 14 : osAttrName.resize(H4_MAX_NC_NAME);
1108 14 : SDattrinfo(m_poShared->GetSDHandle(), iAttribute, &osAttrName[0],
1109 : &iNumType, &nValues);
1110 14 : osAttrName.resize(strlen(osAttrName.c_str()));
1111 :
1112 14 : if (STARTS_WITH_CI(osAttrName.c_str(), "coremetadata") ||
1113 14 : STARTS_WITH_CI(osAttrName.c_str(), "archivemetadata.") ||
1114 14 : STARTS_WITH_CI(osAttrName.c_str(), "productmetadata.") ||
1115 14 : STARTS_WITH_CI(osAttrName.c_str(), "badpixelinformation") ||
1116 14 : STARTS_WITH_CI(osAttrName.c_str(), "product_summary") ||
1117 14 : STARTS_WITH_CI(osAttrName.c_str(), "dem_specific") ||
1118 14 : STARTS_WITH_CI(osAttrName.c_str(), "bts_specific") ||
1119 14 : STARTS_WITH_CI(osAttrName.c_str(), "etse_specific") ||
1120 14 : STARTS_WITH_CI(osAttrName.c_str(), "dst_specific") ||
1121 14 : STARTS_WITH_CI(osAttrName.c_str(), "acv_specific") ||
1122 14 : STARTS_WITH_CI(osAttrName.c_str(), "act_specific") ||
1123 42 : STARTS_WITH_CI(osAttrName.c_str(), "etst_specific") ||
1124 14 : 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 14 : else if (STARTS_WITH_CI(osAttrName.c_str(), "structmetadata."))
1145 : {
1146 0 : 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 9 : return ret;
1156 : }
1157 :
1158 : /************************************************************************/
1159 : /* GetGroupNames() */
1160 : /************************************************************************/
1161 :
1162 6 : std::vector<std::string> HDF4Group::GetGroupNames(CSLConstList) const
1163 : {
1164 6 : if (m_poGDALGroup)
1165 2 : return {};
1166 :
1167 8 : CPLMutexHolderD(&hHDF4Mutex);
1168 8 : std::vector<std::string> res;
1169 4 : auto sw_handle = SWopen(m_poShared->GetFilename().c_str(), DFACC_READ);
1170 4 : if (sw_handle >= 0)
1171 : {
1172 4 : int32 nStrBufSize = 0;
1173 4 : int32 nSubDatasets = SWinqswath(m_poShared->GetFilename().c_str(),
1174 : nullptr, &nStrBufSize);
1175 4 : if (nSubDatasets > 0)
1176 : {
1177 0 : res.emplace_back("swaths");
1178 : }
1179 4 : SWclose(sw_handle);
1180 : }
1181 :
1182 4 : auto gd_handle = GDopen(m_poShared->GetFilename().c_str(), DFACC_READ);
1183 4 : if (gd_handle >= 0)
1184 : {
1185 4 : int32 nStrBufSize = 0;
1186 : int32 nSubDatasets =
1187 4 : GDinqgrid(m_poShared->GetFilename().c_str(), nullptr, &nStrBufSize);
1188 4 : if (nSubDatasets > 0)
1189 : {
1190 0 : res.emplace_back("eos_grids");
1191 : }
1192 4 : GDclose(gd_handle);
1193 : }
1194 :
1195 4 : const char *pszListSDS = m_poShared->FetchOpenOption("LIST_SDS", "AUTO");
1196 4 : if ((res.empty() && EQUAL(pszListSDS, "AUTO")) ||
1197 0 : (!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 4 : auto hHandle = Hopen(m_poShared->GetFilename().c_str(), DFACC_READ, 0);
1209 4 : if (hHandle >= 0)
1210 : {
1211 4 : auto grHandle = GRstart(hHandle);
1212 4 : if (grHandle >= 0)
1213 : {
1214 4 : int32 nImages = 0;
1215 4 : int32 nAttrs = 0;
1216 4 : if (GRfileinfo(grHandle, &nImages, &nAttrs) == 0 && nImages > 0)
1217 : {
1218 2 : res.emplace_back("general_rasters");
1219 : }
1220 4 : GRend(grHandle);
1221 : }
1222 4 : Hclose(hHandle);
1223 : }
1224 :
1225 4 : return res;
1226 : }
1227 :
1228 : /************************************************************************/
1229 : /* OpenGroup() */
1230 : /************************************************************************/
1231 :
1232 7 : std::shared_ptr<GDALGroup> HDF4Group::OpenGroup(const std::string &osName,
1233 : CSLConstList) const
1234 : {
1235 7 : if (m_poGDALGroup)
1236 2 : return nullptr;
1237 :
1238 10 : CPLMutexHolderD(&hHDF4Mutex);
1239 5 : if (osName == "swaths")
1240 : {
1241 0 : auto handle = SWopen(m_poShared->GetFilename().c_str(), DFACC_READ);
1242 0 : if (handle >= 0)
1243 0 : return std::make_shared<HDF4SwathsGroup>(
1244 0 : GetFullName(), osName, m_poShared,
1245 0 : std::make_shared<HDF4SwathsHandle>(handle));
1246 : }
1247 5 : if (osName == "eos_grids")
1248 : {
1249 0 : auto handle = GDopen(m_poShared->GetFilename().c_str(), DFACC_READ);
1250 0 : if (handle >= 0)
1251 0 : return std::make_shared<HDF4EOSGridsGroup>(
1252 0 : GetFullName(), osName, m_poShared,
1253 0 : 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 3 : std::vector<std::string> HDF4Group::GetMDArrayNames(CSLConstList) const
1286 : {
1287 3 : if (m_poGDALGroup)
1288 2 : return m_poGDALGroup->GetMDArrayNames(nullptr);
1289 1 : 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 2 : HDF4Group::GetDimensions(CSLConstList) const
1310 : {
1311 2 : if (m_poGDALGroup)
1312 2 : return m_poGDALGroup->GetDimensions(nullptr);
1313 0 : return {};
1314 : }
1315 :
1316 : /************************************************************************/
1317 : /* GetGroupNames() */
1318 : /************************************************************************/
1319 :
1320 0 : std::vector<std::string> HDF4SwathsGroup::GetGroupNames(CSLConstList) const
1321 : {
1322 0 : CPLMutexHolderD(&hHDF4Mutex);
1323 0 : std::vector<std::string> res;
1324 :
1325 0 : int32 nStrBufSize = 0;
1326 0 : SWinqswath(m_poShared->GetFilename().c_str(), nullptr, &nStrBufSize);
1327 :
1328 0 : std::string osSwathList;
1329 0 : osSwathList.resize(nStrBufSize);
1330 0 : SWinqswath(m_poShared->GetFilename().c_str(), &osSwathList[0],
1331 : &nStrBufSize);
1332 :
1333 : CPLStringList aosSwaths(
1334 0 : CSLTokenizeString2(osSwathList.c_str(), ",", CSLT_HONOURSTRINGS));
1335 0 : for (int i = 0; i < aosSwaths.size(); i++)
1336 0 : res.push_back(aosSwaths[i]);
1337 :
1338 0 : return res;
1339 : }
1340 :
1341 : /************************************************************************/
1342 : /* OpenGroup() */
1343 : /************************************************************************/
1344 :
1345 0 : std::shared_ptr<GDALGroup> HDF4SwathsGroup::OpenGroup(const std::string &osName,
1346 : CSLConstList) const
1347 : {
1348 0 : CPLMutexHolderD(&hHDF4Mutex);
1349 :
1350 0 : int32 swathHandle = SWattach(m_poSwathsHandle->m_handle, osName.c_str());
1351 0 : if (swathHandle < 0)
1352 : {
1353 0 : return nullptr;
1354 : }
1355 :
1356 0 : return std::make_shared<HDF4SwathGroup>(
1357 0 : GetFullName(), osName, m_poShared,
1358 0 : std::make_shared<HDF4SwathHandle>(m_poSwathsHandle, swathHandle));
1359 : }
1360 :
1361 : /************************************************************************/
1362 : /* GetMDArrayNames() */
1363 : /************************************************************************/
1364 :
1365 0 : std::vector<std::string> HDF4SwathSubGroup::GetMDArrayNames(CSLConstList) const
1366 : {
1367 0 : CPLMutexHolderD(&hHDF4Mutex);
1368 0 : std::vector<std::string> ret;
1369 :
1370 0 : int32 nStrBufSize = 0;
1371 : const int32 nFields =
1372 0 : SWnentries(m_poSwathHandle->m_handle, m_entryType, &nStrBufSize);
1373 0 : std::string osFieldList;
1374 0 : osFieldList.resize(nStrBufSize);
1375 0 : std::vector<int32> ranks(nFields);
1376 0 : std::vector<int32> numberTypes(nFields);
1377 :
1378 0 : if (m_entryType == HDFE_NENTDFLD)
1379 0 : SWinqdatafields(m_poSwathHandle->m_handle, &osFieldList[0], &ranks[0],
1380 0 : &numberTypes[0]);
1381 : else
1382 0 : SWinqgeofields(m_poSwathHandle->m_handle, &osFieldList[0], &ranks[0],
1383 0 : &numberTypes[0]);
1384 :
1385 : CPLStringList aosFields(
1386 0 : CSLTokenizeString2(osFieldList.c_str(), ",", CSLT_HONOURSTRINGS));
1387 0 : for (int i = 0; i < aosFields.size(); i++)
1388 0 : ret.push_back(aosFields[i]);
1389 :
1390 0 : return ret;
1391 : }
1392 :
1393 : /************************************************************************/
1394 : /* OpenMDArray() */
1395 : /************************************************************************/
1396 :
1397 : std::shared_ptr<GDALMDArray>
1398 0 : HDF4SwathSubGroup::OpenMDArray(const std::string &osName, CSLConstList) const
1399 : {
1400 0 : CPLMutexHolderD(&hHDF4Mutex);
1401 :
1402 : int32 iRank;
1403 : int32 iNumType;
1404 0 : std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
1405 0 : std::string dimNames;
1406 :
1407 0 : int32 nStrBufSize = 0;
1408 0 : if (SWnentries(m_poSwathHandle->m_handle, HDFE_NENTDIM, &nStrBufSize) < 0 ||
1409 0 : nStrBufSize <= 0)
1410 : {
1411 0 : return nullptr;
1412 : }
1413 0 : dimNames.resize(nStrBufSize);
1414 0 : if (SWfieldinfo(m_poSwathHandle->m_handle, osName.c_str(), &iRank,
1415 0 : &aiDimSizes[0], &iNumType, &dimNames[0]) < 0)
1416 : {
1417 0 : return nullptr;
1418 : }
1419 0 : aiDimSizes.resize(iRank);
1420 :
1421 0 : return HDF4SwathArray::Create(GetFullName(), osName, m_poShared,
1422 0 : m_poSwathHandle, aiDimSizes, dimNames,
1423 0 : iNumType, m_groupDims);
1424 : }
1425 :
1426 : /************************************************************************/
1427 : /* GetGroupNames() */
1428 : /************************************************************************/
1429 :
1430 0 : std::vector<std::string> HDF4SwathGroup::GetGroupNames(CSLConstList) const
1431 : {
1432 0 : std::vector<std::string> res;
1433 0 : res.push_back("Data Fields");
1434 0 : res.push_back("Geolocation Fields");
1435 0 : return res;
1436 : }
1437 :
1438 : /************************************************************************/
1439 : /* OpenGroup() */
1440 : /************************************************************************/
1441 :
1442 0 : std::shared_ptr<GDALGroup> HDF4SwathGroup::OpenGroup(const std::string &osName,
1443 : CSLConstList) const
1444 : {
1445 0 : if (osName == "Data Fields")
1446 : {
1447 0 : return std::make_shared<HDF4SwathSubGroup>(
1448 0 : GetFullName(), osName, m_poShared, m_poSwathHandle, HDFE_NENTDFLD,
1449 0 : GetDimensions());
1450 : }
1451 0 : if (osName == "Geolocation Fields")
1452 : {
1453 0 : return std::make_shared<HDF4SwathSubGroup>(
1454 0 : GetFullName(), osName, m_poShared, m_poSwathHandle, HDFE_NENTGFLD,
1455 0 : GetDimensions());
1456 : }
1457 0 : return nullptr;
1458 : }
1459 :
1460 : /************************************************************************/
1461 : /* GetDimensions() */
1462 : /************************************************************************/
1463 :
1464 : std::vector<std::shared_ptr<GDALDimension>>
1465 0 : HDF4SwathGroup::GetDimensions(CSLConstList) const
1466 : {
1467 0 : if (!m_dims.empty())
1468 0 : return m_dims;
1469 0 : std::string dimNames;
1470 0 : int32 nStrBufSize = 0;
1471 0 : if (SWnentries(m_poSwathHandle->m_handle, HDFE_NENTDIM, &nStrBufSize) < 0 ||
1472 0 : nStrBufSize <= 0)
1473 : {
1474 0 : return m_dims;
1475 : }
1476 0 : dimNames.resize(nStrBufSize);
1477 0 : int32 nDims = SWinqdims(m_poSwathHandle->m_handle, &dimNames[0], nullptr);
1478 0 : std::vector<int32> aiDimSizes(nDims);
1479 0 : SWinqdims(m_poSwathHandle->m_handle, &dimNames[0], &aiDimSizes[0]);
1480 : CPLStringList aosDimNames(
1481 0 : CSLTokenizeString2(dimNames.c_str(), ",", CSLT_HONOURSTRINGS));
1482 0 : if (static_cast<size_t>(aosDimNames.size()) == aiDimSizes.size())
1483 : {
1484 0 : for (int i = 0; i < aosDimNames.size(); i++)
1485 : {
1486 0 : m_dims.push_back(std::make_shared<GDALDimension>(
1487 0 : GetFullName(), aosDimNames[i], std::string(), std::string(),
1488 0 : aiDimSizes[i]));
1489 : }
1490 : }
1491 0 : return m_dims;
1492 : }
1493 :
1494 : /************************************************************************/
1495 : /* GetAttributes() */
1496 : /************************************************************************/
1497 :
1498 : std::vector<std::shared_ptr<GDALAttribute>>
1499 0 : HDF4SwathGroup::GetAttributes(CSLConstList) const
1500 : {
1501 0 : CPLMutexHolderD(&hHDF4Mutex);
1502 0 : std::vector<std::shared_ptr<GDALAttribute>> ret;
1503 0 : int32 nStrBufSize = 0;
1504 0 : if (SWinqattrs(m_poSwathHandle->m_handle, nullptr, &nStrBufSize) <= 0 ||
1505 0 : nStrBufSize <= 0)
1506 : {
1507 0 : return ret;
1508 : }
1509 0 : std::string osAttrs;
1510 0 : osAttrs.resize(nStrBufSize);
1511 0 : SWinqattrs(m_poSwathHandle->m_handle, &osAttrs[0], &nStrBufSize);
1512 :
1513 : CPLStringList aosAttrs(
1514 0 : CSLTokenizeString2(osAttrs.c_str(), ",", CSLT_HONOURSTRINGS));
1515 0 : for (int i = 0; i < aosAttrs.size(); i++)
1516 : {
1517 0 : int32 iNumType = 0;
1518 0 : int32 nSize = 0;
1519 :
1520 0 : const auto &osAttrName = aosAttrs[i];
1521 0 : if (SWattrinfo(m_poSwathHandle->m_handle, osAttrName, &iNumType,
1522 0 : &nSize) < 0)
1523 0 : continue;
1524 0 : const int nDataTypeSize = HDF4Dataset::GetDataTypeSize(iNumType);
1525 0 : if (nDataTypeSize == 0)
1526 0 : continue;
1527 :
1528 0 : ret.emplace_back(std::make_shared<HDF4SwathAttribute>(
1529 0 : GetFullName(), osAttrName, m_poShared, m_poSwathHandle, iNumType,
1530 0 : nSize / nDataTypeSize));
1531 : }
1532 0 : return ret;
1533 : }
1534 :
1535 : /************************************************************************/
1536 : /* HDF4SwathArray() */
1537 : /************************************************************************/
1538 :
1539 0 : HDF4SwathArray::HDF4SwathArray(
1540 : const std::string &osParentName, const std::string &osName,
1541 : const std::shared_ptr<HDF4SharedResources> &poShared,
1542 : const std::shared_ptr<HDF4SwathHandle> &poSwathHandle,
1543 : const std::vector<int32> &aiDimSizes, const std::string &dimNames,
1544 : int32 iNumType,
1545 0 : const std::vector<std::shared_ptr<GDALDimension>> &groupDims)
1546 : : GDALAbstractMDArray(osParentName, osName),
1547 : GDALPamMDArray(osParentName, osName, poShared->GetPAM()),
1548 : m_poShared(poShared), m_poSwathHandle(poSwathHandle),
1549 : m_dt(iNumType == DFNT_CHAR8 ? GDALExtendedDataType::CreateString()
1550 : : GDALExtendedDataType::Create(
1551 0 : HDF4Dataset::GetDataType(iNumType)))
1552 : {
1553 : CPLStringList aosDimNames(
1554 0 : CSLTokenizeString2(dimNames.c_str(), ",", CSLT_HONOURSTRINGS));
1555 0 : if (static_cast<size_t>(aosDimNames.size()) == aiDimSizes.size())
1556 : {
1557 0 : for (int i = 0; i < aosDimNames.size(); i++)
1558 : {
1559 0 : bool bFound = false;
1560 0 : for (const auto &poDim : groupDims)
1561 : {
1562 0 : if (poDim->GetName() == aosDimNames[i] &&
1563 0 : poDim->GetSize() == static_cast<GUInt64>(aiDimSizes[i]))
1564 : {
1565 0 : bFound = true;
1566 0 : m_dims.push_back(poDim);
1567 0 : break;
1568 : }
1569 : }
1570 0 : if (!bFound)
1571 : {
1572 0 : m_dims.push_back(std::make_shared<GDALDimension>(
1573 0 : std::string(), aosDimNames[i], std::string(), std::string(),
1574 0 : aiDimSizes[i]));
1575 : }
1576 : }
1577 : }
1578 0 : }
1579 :
1580 : /************************************************************************/
1581 : /* GetAttributes() */
1582 : /************************************************************************/
1583 :
1584 : std::vector<std::shared_ptr<GDALAttribute>>
1585 0 : HDF4SwathArray::GetAttributes(CSLConstList) const
1586 : {
1587 0 : CPLMutexHolderD(&hHDF4Mutex);
1588 0 : std::vector<std::shared_ptr<GDALAttribute>> ret;
1589 0 : int32 iSDS = 0;
1590 0 : if (SWsdid(m_poSwathHandle->m_handle, GetName().c_str(), &iSDS) != -1)
1591 : {
1592 0 : int32 iRank = 0;
1593 0 : int32 iNumType = 0;
1594 0 : int32 nAttrs = 0;
1595 0 : std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
1596 :
1597 0 : if (SDgetinfo(iSDS, nullptr, &iRank, &aiDimSizes[0], &iNumType,
1598 0 : &nAttrs) == 0)
1599 : {
1600 0 : for (int32 iAttribute = 0; iAttribute < nAttrs; iAttribute++)
1601 : {
1602 0 : std::string osAttrName;
1603 0 : osAttrName.resize(H4_MAX_NC_NAME);
1604 0 : iNumType = 0;
1605 0 : int32 nValues = 0;
1606 0 : SDattrinfo(iSDS, iAttribute, &osAttrName[0], &iNumType,
1607 : &nValues);
1608 0 : osAttrName.resize(strlen(osAttrName.c_str()));
1609 0 : ret.emplace_back(std::make_shared<HDF4SDAttribute>(
1610 0 : GetFullName(), osAttrName, m_poShared, m_poSwathHandle,
1611 0 : nullptr, iSDS, iAttribute, iNumType, nValues));
1612 : }
1613 : }
1614 : }
1615 0 : return ret;
1616 : }
1617 :
1618 : /************************************************************************/
1619 : /* ReadPixels() */
1620 : /************************************************************************/
1621 :
1622 : union ReadFunc
1623 : {
1624 : intn (*pReadField)(int32, const char *, int32[], int32[], int32[], VOIDP);
1625 : intn (*pReadData)(int32, int32[], int32[], int32[], VOIDP);
1626 : };
1627 :
1628 24 : static inline void IncrPointer(GByte *&ptr, GPtrDiff_t nInc, size_t nIncSize)
1629 : {
1630 24 : if (nInc < 0)
1631 6 : ptr -= (-nInc) * nIncSize;
1632 : else
1633 18 : ptr += nInc * nIncSize;
1634 24 : }
1635 :
1636 4 : static bool ReadPixels(const GUInt64 *arrayStartIdx, const size_t *count,
1637 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
1638 : const GDALExtendedDataType &bufferDataType,
1639 : void *pDstBuffer,
1640 : const std::shared_ptr<HDF4SharedResources> &poShared,
1641 : const GDALExtendedDataType &dt,
1642 : const std::vector<std::shared_ptr<GDALDimension>> &dims,
1643 : int32 handle, const char *pszFieldName,
1644 : ReadFunc readFunc)
1645 : {
1646 8 : CPLMutexHolderD(&hHDF4Mutex);
1647 : /* -------------------------------------------------------------------- */
1648 : /* HDF files with external data files, such as some landsat */
1649 : /* products (eg. data/hdf/L1G) need to be told what directory */
1650 : /* to look in to find the external files. Normally this is the */
1651 : /* directory holding the hdf file. */
1652 : /* -------------------------------------------------------------------- */
1653 4 : HXsetdir(CPLGetPathSafe(poShared->GetFilename().c_str()).c_str());
1654 :
1655 4 : const size_t nDims(dims.size());
1656 8 : std::vector<int32> sw_start(nDims);
1657 8 : std::vector<int32> sw_stride(nDims);
1658 8 : std::vector<int32> sw_edge(nDims);
1659 8 : std::vector<GPtrDiff_t> newBufferStride(nDims);
1660 4 : GByte *pabyDstBuffer = static_cast<GByte *>(pDstBuffer);
1661 4 : const size_t nBufferDataTypeSize = bufferDataType.GetSize();
1662 14 : for (size_t i = 0; i < nDims; i++)
1663 : {
1664 10 : sw_start[i] = static_cast<int>(arrayStartIdx[i]);
1665 10 : sw_stride[i] = static_cast<int>(arrayStep[i]);
1666 10 : sw_edge[i] = static_cast<int>(count[i]);
1667 10 : newBufferStride[i] = bufferStride[i];
1668 10 : if (sw_stride[i] < 0)
1669 : {
1670 : // SWreadfield() doesn't like negative step / array stride, so
1671 : // transform the request to a classic "left-to-right" one
1672 0 : sw_start[i] += sw_stride[i] * (sw_edge[i] - 1);
1673 0 : sw_stride[i] = -sw_stride[i];
1674 0 : pabyDstBuffer +=
1675 0 : (sw_edge[i] - 1) * newBufferStride[i] * nBufferDataTypeSize;
1676 0 : newBufferStride[i] = -newBufferStride[i];
1677 : }
1678 : }
1679 4 : size_t nExpectedStride = 1;
1680 4 : bool bContiguousStride = true;
1681 14 : for (size_t i = nDims; i > 0;)
1682 : {
1683 10 : --i;
1684 10 : if (newBufferStride[i] != static_cast<GPtrDiff_t>(nExpectedStride))
1685 : {
1686 3 : bContiguousStride = false;
1687 : }
1688 10 : nExpectedStride *= count[i];
1689 : }
1690 4 : if (bufferDataType == dt && bContiguousStride)
1691 : {
1692 : auto status =
1693 : pszFieldName
1694 3 : ? readFunc.pReadField(handle, pszFieldName, &sw_start[0],
1695 0 : &sw_stride[0], &sw_edge[0], pabyDstBuffer)
1696 3 : : readFunc.pReadData(handle, &sw_start[0], &sw_stride[0],
1697 3 : &sw_edge[0], pabyDstBuffer);
1698 3 : return status == 0;
1699 : }
1700 : auto pabyTemp = static_cast<GByte *>(
1701 1 : VSI_MALLOC2_VERBOSE(dt.GetSize(), nExpectedStride));
1702 1 : if (pabyTemp == nullptr)
1703 0 : return false;
1704 : auto status =
1705 1 : pszFieldName ? readFunc.pReadField(handle, pszFieldName, &sw_start[0],
1706 0 : &sw_stride[0], &sw_edge[0], pabyTemp)
1707 1 : : readFunc.pReadData(handle, &sw_start[0], &sw_stride[0],
1708 1 : &sw_edge[0], pabyTemp);
1709 1 : if (status != 0)
1710 : {
1711 0 : VSIFree(pabyTemp);
1712 0 : return false;
1713 : }
1714 :
1715 1 : const size_t nSrcDataTypeSize = dt.GetSize();
1716 2 : std::vector<size_t> anStackCount(nDims);
1717 1 : GByte *pabySrc = pabyTemp;
1718 1 : std::vector<GByte *> pabyDstBufferStack(nDims + 1);
1719 1 : pabyDstBufferStack[0] = pabyDstBuffer;
1720 1 : size_t iDim = 0;
1721 11 : lbl_next_depth:
1722 11 : if (iDim == nDims)
1723 : {
1724 4 : GDALExtendedDataType::CopyValue(pabySrc, dt, pabyDstBufferStack[nDims],
1725 : bufferDataType);
1726 4 : pabySrc += nSrcDataTypeSize;
1727 : }
1728 : else
1729 : {
1730 7 : anStackCount[iDim] = count[iDim];
1731 : while (true)
1732 : {
1733 10 : ++iDim;
1734 10 : pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
1735 10 : goto lbl_next_depth;
1736 10 : lbl_return_to_caller_in_loop:
1737 10 : --iDim;
1738 10 : --anStackCount[iDim];
1739 10 : if (anStackCount[iDim] == 0)
1740 7 : break;
1741 3 : IncrPointer(pabyDstBufferStack[iDim], newBufferStride[iDim],
1742 : nBufferDataTypeSize);
1743 : }
1744 : }
1745 11 : if (iDim > 0)
1746 10 : goto lbl_return_to_caller_in_loop;
1747 :
1748 1 : VSIFree(pabyTemp);
1749 1 : return true;
1750 : }
1751 :
1752 : /************************************************************************/
1753 : /* IRead() */
1754 : /************************************************************************/
1755 :
1756 0 : bool HDF4SwathArray::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
1757 : const GInt64 *arrayStep,
1758 : const GPtrDiff_t *bufferStride,
1759 : const GDALExtendedDataType &bufferDataType,
1760 : void *pDstBuffer) const
1761 : {
1762 : ReadFunc readFunc;
1763 0 : readFunc.pReadField = SWreadfield;
1764 0 : return ReadPixels(arrayStartIdx, count, arrayStep, bufferStride,
1765 0 : bufferDataType, pDstBuffer, m_poShared, m_dt, m_dims,
1766 0 : m_poSwathHandle->m_handle, GetName().c_str(), readFunc);
1767 : }
1768 :
1769 : /************************************************************************/
1770 : /* GetRawNoDataValue() */
1771 : /************************************************************************/
1772 :
1773 0 : const void *HDF4SwathArray::GetRawNoDataValue() const
1774 : {
1775 0 : if (!m_abyNoData.empty())
1776 0 : return m_abyNoData.data();
1777 0 : m_abyNoData.resize(GetDataType().GetSize());
1778 :
1779 0 : auto poAttr = GetAttribute("_FillValue");
1780 0 : if (poAttr)
1781 : {
1782 0 : const double dfVal = poAttr->ReadAsDouble();
1783 0 : GDALExtendedDataType::CopyValue(
1784 0 : &dfVal, GDALExtendedDataType::Create(GDT_Float64), &m_abyNoData[0],
1785 : GetDataType());
1786 0 : return m_abyNoData.data();
1787 : }
1788 :
1789 0 : CPLMutexHolderD(&hHDF4Mutex);
1790 0 : if (SWgetfillvalue(m_poSwathHandle->m_handle, GetName().c_str(),
1791 0 : &m_abyNoData[0]) != -1)
1792 : {
1793 0 : return m_abyNoData.data();
1794 : }
1795 :
1796 0 : m_abyNoData.clear();
1797 0 : return nullptr;
1798 : }
1799 :
1800 : /************************************************************************/
1801 : /* HDF4AbstractAttribute() */
1802 : /************************************************************************/
1803 :
1804 28 : HDF4AbstractAttribute::HDF4AbstractAttribute(
1805 : const std::string &osParentName, const std::string &osName,
1806 : const std::shared_ptr<HDF4SharedResources> &poShared, int32 iNumType,
1807 0 : int32 nValues)
1808 : :
1809 : #if !defined(COMPILER_WARNS_ABOUT_ABSTRACT_VBASE_INIT)
1810 : GDALAbstractMDArray(osParentName, osName),
1811 : #endif
1812 : GDALAttribute(osParentName, osName), m_poShared(poShared),
1813 : m_dt(iNumType == DFNT_CHAR8 ? GDALExtendedDataType::CreateString()
1814 : : GDALExtendedDataType::Create(
1815 : HDF4Dataset::GetDataType(iNumType))),
1816 28 : m_nValues(nValues)
1817 : {
1818 28 : if (m_dt.GetClass() != GEDTC_STRING && m_nValues > 1)
1819 : {
1820 12 : m_dims.emplace_back(std::make_shared<GDALDimension>(
1821 18 : std::string(), "dim", std::string(), std::string(), nValues));
1822 : }
1823 28 : }
1824 :
1825 : /************************************************************************/
1826 : /* IRead() */
1827 : /************************************************************************/
1828 :
1829 13 : bool HDF4AbstractAttribute::IRead(const GUInt64 *arrayStartIdx,
1830 : const size_t *count, const GInt64 *arrayStep,
1831 : const GPtrDiff_t *bufferStride,
1832 : const GDALExtendedDataType &bufferDataType,
1833 : void *pDstBuffer) const
1834 : {
1835 26 : CPLMutexHolderD(&hHDF4Mutex);
1836 13 : if (m_dt.GetClass() == GEDTC_STRING)
1837 : {
1838 11 : if (bufferDataType.GetClass() != GEDTC_STRING)
1839 0 : return false;
1840 11 : char *pszStr = static_cast<char *>(VSIMalloc(m_nValues + 1));
1841 11 : if (pszStr == nullptr)
1842 0 : return false;
1843 11 : ReadData(pszStr);
1844 11 : pszStr[m_nValues] = 0;
1845 11 : *static_cast<char **>(pDstBuffer) = pszStr;
1846 11 : return true;
1847 : }
1848 :
1849 2 : std::vector<GByte> abyTemp(m_nValues * m_dt.GetSize());
1850 2 : ReadData(&abyTemp[0]);
1851 2 : GByte *pabyDstBuffer = static_cast<GByte *>(pDstBuffer);
1852 10 : for (size_t i = 0; i < (m_dims.empty() ? 1 : count[0]); ++i)
1853 : {
1854 : const size_t idx =
1855 8 : m_dims.empty()
1856 8 : ? 0
1857 8 : : static_cast<size_t>(arrayStartIdx[0] + i * arrayStep[0]);
1858 8 : GDALExtendedDataType::CopyValue(&abyTemp[0] + idx * m_dt.GetSize(),
1859 8 : m_dt, pabyDstBuffer, bufferDataType);
1860 8 : if (!m_dims.empty())
1861 8 : pabyDstBuffer += bufferStride[0] * bufferDataType.GetSize();
1862 : }
1863 :
1864 2 : return true;
1865 : }
1866 :
1867 : /************************************************************************/
1868 : /* GetGroupNames() */
1869 : /************************************************************************/
1870 :
1871 0 : std::vector<std::string> HDF4EOSGridsGroup::GetGroupNames(CSLConstList) const
1872 : {
1873 0 : CPLMutexHolderD(&hHDF4Mutex);
1874 0 : std::vector<std::string> res;
1875 :
1876 0 : int32 nStrBufSize = 0;
1877 0 : GDinqgrid(m_poShared->GetFilename().c_str(), nullptr, &nStrBufSize);
1878 :
1879 0 : std::string osGridList;
1880 0 : osGridList.resize(nStrBufSize);
1881 0 : GDinqgrid(m_poShared->GetFilename().c_str(), &osGridList[0], &nStrBufSize);
1882 :
1883 : CPLStringList aosGrids(
1884 0 : CSLTokenizeString2(osGridList.c_str(), ",", CSLT_HONOURSTRINGS));
1885 0 : for (int i = 0; i < aosGrids.size(); i++)
1886 0 : res.push_back(aosGrids[i]);
1887 :
1888 0 : return res;
1889 : }
1890 :
1891 : /************************************************************************/
1892 : /* OpenGroup() */
1893 : /************************************************************************/
1894 :
1895 : std::shared_ptr<GDALGroup>
1896 0 : HDF4EOSGridsGroup::OpenGroup(const std::string &osName, CSLConstList) const
1897 : {
1898 0 : CPLMutexHolderD(&hHDF4Mutex);
1899 :
1900 0 : int32 gdHandle = GDattach(m_poGDsHandle->m_handle, osName.c_str());
1901 0 : if (gdHandle < 0)
1902 : {
1903 0 : return nullptr;
1904 : }
1905 :
1906 0 : return std::make_shared<HDF4EOSGridGroup>(
1907 0 : GetFullName(), osName, m_poShared,
1908 0 : std::make_shared<HDF4GDHandle>(m_poGDsHandle, gdHandle));
1909 : }
1910 :
1911 : /************************************************************************/
1912 : /* GetDimensions() */
1913 : /************************************************************************/
1914 :
1915 : std::vector<std::shared_ptr<GDALDimension>>
1916 0 : HDF4EOSGridGroup::GetDimensions(CSLConstList) const
1917 : {
1918 0 : if (!m_dims.empty())
1919 0 : return m_dims;
1920 :
1921 0 : int32 iProjCode = 0;
1922 0 : int32 iZoneCode = 0;
1923 0 : int32 iSphereCode = 0;
1924 : double adfProjParams[15];
1925 :
1926 0 : GDprojinfo(m_poGDHandle->m_handle, &iProjCode, &iZoneCode, &iSphereCode,
1927 : adfProjParams);
1928 :
1929 0 : int32 nXSize = 0;
1930 0 : int32 nYSize = 0;
1931 : double adfUpLeft[2];
1932 : double adfLowRight[2];
1933 0 : const bool bGotGridInfo = GDgridinfo(m_poGDHandle->m_handle, &nXSize,
1934 0 : &nYSize, adfUpLeft, adfLowRight) >= 0;
1935 0 : if (bGotGridInfo)
1936 : {
1937 0 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
1938 0 : GetFullName(), "YDim", GDAL_DIM_TYPE_HORIZONTAL_Y,
1939 : "NORTH", nYSize),
1940 0 : std::make_shared<GDALDimensionWeakIndexingVar>(
1941 0 : GetFullName(), "XDim", GDAL_DIM_TYPE_HORIZONTAL_X, "EAST",
1942 0 : nXSize)};
1943 :
1944 0 : if (iProjCode == 0)
1945 : {
1946 0 : adfLowRight[0] = CPLPackedDMSToDec(adfLowRight[0]);
1947 0 : adfLowRight[1] = CPLPackedDMSToDec(adfLowRight[1]);
1948 0 : adfUpLeft[0] = CPLPackedDMSToDec(adfUpLeft[0]);
1949 0 : adfUpLeft[1] = CPLPackedDMSToDec(adfUpLeft[1]);
1950 : }
1951 :
1952 0 : m_varX = GDALMDArrayRegularlySpaced::Create(
1953 0 : GetFullName(), m_dims[1]->GetName(), m_dims[1], adfUpLeft[0],
1954 0 : (adfLowRight[0] - adfUpLeft[0]) / nXSize, 0.5);
1955 0 : m_dims[1]->SetIndexingVariable(m_varX);
1956 :
1957 0 : m_varY = GDALMDArrayRegularlySpaced::Create(
1958 0 : GetFullName(), m_dims[0]->GetName(), m_dims[0], adfUpLeft[1],
1959 0 : (adfLowRight[1] - adfUpLeft[1]) / nYSize, 0.5);
1960 0 : m_dims[0]->SetIndexingVariable(m_varY);
1961 : }
1962 :
1963 : #if 0
1964 : // Dimensions seem to be never defined properly on eos_grids datasets.
1965 :
1966 : std::string dimNames;
1967 : int32 nStrBufSize = 0;
1968 : if( GDnentries( m_poGDHandle->m_handle, HDFE_NENTDIM, &nStrBufSize ) < 0
1969 : || nStrBufSize <= 0 )
1970 : {
1971 : return m_dims;
1972 : }
1973 : dimNames.resize(nStrBufSize);
1974 : int32 nDims = GDinqdims(m_poGDHandle->m_handle, &dimNames[0], nullptr);
1975 : std::vector<int32> aiDimSizes(nDims);
1976 : GDinqdims(m_poGDHandle->m_handle, &dimNames[0], &aiDimSizes[0]);
1977 : CPLStringList aosDimNames(CSLTokenizeString2(
1978 : dimNames.c_str(), ",", CSLT_HONOURSTRINGS ));
1979 : if( static_cast<size_t>(aosDimNames.size()) == aiDimSizes.size() )
1980 : {
1981 : for( int i = 0; i < aosDimNames.size(); i++ )
1982 : {
1983 : m_dims.push_back(std::make_shared<GDALDimension>(GetFullName(),
1984 : aosDimNames[i],
1985 : std::string(),
1986 : std::string(),
1987 : aiDimSizes[i]));
1988 : }
1989 : }
1990 : #endif
1991 0 : return m_dims;
1992 : }
1993 :
1994 : /************************************************************************/
1995 : /* GetMDArrayNames() */
1996 : /************************************************************************/
1997 :
1998 0 : std::vector<std::string> HDF4EOSGridGroup::GetMDArrayNames(CSLConstList) const
1999 : {
2000 0 : GetDimensions();
2001 0 : std::vector<std::string> ret;
2002 0 : if (m_varX && m_varY)
2003 : {
2004 0 : ret.push_back(m_varY->GetName());
2005 0 : ret.push_back(m_varX->GetName());
2006 : }
2007 0 : return ret;
2008 : }
2009 :
2010 : /************************************************************************/
2011 : /* OpenMDArray() */
2012 : /************************************************************************/
2013 :
2014 : std::shared_ptr<GDALMDArray>
2015 0 : HDF4EOSGridGroup::OpenMDArray(const std::string &osName, CSLConstList) const
2016 : {
2017 0 : if (m_varX && osName == m_varX->GetName())
2018 0 : return m_varX;
2019 0 : if (m_varY && osName == m_varY->GetName())
2020 0 : return m_varY;
2021 0 : return nullptr;
2022 : }
2023 :
2024 : /************************************************************************/
2025 : /* GetGroupNames() */
2026 : /************************************************************************/
2027 :
2028 0 : std::vector<std::string> HDF4EOSGridGroup::GetGroupNames(CSLConstList) const
2029 : {
2030 0 : std::vector<std::string> res;
2031 0 : res.push_back("Data Fields");
2032 0 : return res;
2033 : }
2034 :
2035 : /************************************************************************/
2036 : /* OpenGroup() */
2037 : /************************************************************************/
2038 :
2039 : std::shared_ptr<GDALGroup>
2040 0 : HDF4EOSGridGroup::OpenGroup(const std::string &osName, CSLConstList) const
2041 : {
2042 0 : if (osName == "Data Fields")
2043 : {
2044 0 : return std::make_shared<HDF4EOSGridSubGroup>(
2045 0 : GetFullName(), osName, m_poShared, m_poGDHandle, HDFE_NENTDFLD,
2046 0 : GetDimensions());
2047 : }
2048 0 : return nullptr;
2049 : }
2050 :
2051 : /************************************************************************/
2052 : /* GetAttributes() */
2053 : /************************************************************************/
2054 :
2055 : std::vector<std::shared_ptr<GDALAttribute>>
2056 0 : HDF4EOSGridGroup::GetAttributes(CSLConstList) const
2057 : {
2058 0 : CPLMutexHolderD(&hHDF4Mutex);
2059 0 : std::vector<std::shared_ptr<GDALAttribute>> ret;
2060 0 : int32 nStrBufSize = 0;
2061 0 : if (GDinqattrs(m_poGDHandle->m_handle, nullptr, &nStrBufSize) <= 0 ||
2062 0 : nStrBufSize <= 0)
2063 : {
2064 0 : return ret;
2065 : }
2066 0 : std::string osAttrs;
2067 0 : osAttrs.resize(nStrBufSize);
2068 0 : GDinqattrs(m_poGDHandle->m_handle, &osAttrs[0], &nStrBufSize);
2069 :
2070 : CPLStringList aosAttrs(
2071 0 : CSLTokenizeString2(osAttrs.c_str(), ",", CSLT_HONOURSTRINGS));
2072 0 : for (int i = 0; i < aosAttrs.size(); i++)
2073 : {
2074 0 : int32 iNumType = 0;
2075 0 : int32 nSize = 0;
2076 :
2077 0 : if (GDattrinfo(m_poGDHandle->m_handle, aosAttrs[i], &iNumType, &nSize) <
2078 : 0)
2079 0 : continue;
2080 0 : const int nDataTypeSize = HDF4Dataset::GetDataTypeSize(iNumType);
2081 0 : if (nDataTypeSize == 0)
2082 0 : continue;
2083 :
2084 0 : ret.emplace_back(std::make_shared<HDF4EOSGridAttribute>(
2085 0 : GetFullName(), aosAttrs[i], m_poShared, m_poGDHandle, iNumType,
2086 0 : nSize / nDataTypeSize));
2087 : }
2088 0 : return ret;
2089 : }
2090 :
2091 : /************************************************************************/
2092 : /* GetMDArrayNames() */
2093 : /************************************************************************/
2094 :
2095 : std::vector<std::string>
2096 0 : HDF4EOSGridSubGroup::GetMDArrayNames(CSLConstList) const
2097 : {
2098 0 : std::vector<std::string> ret;
2099 :
2100 0 : int32 nStrBufSize = 0;
2101 : const int32 nFields =
2102 0 : GDnentries(m_poGDHandle->m_handle, m_entryType, &nStrBufSize);
2103 0 : std::string osFieldList;
2104 0 : osFieldList.resize(nStrBufSize);
2105 0 : std::vector<int32> ranks(nFields);
2106 0 : std::vector<int32> numberTypes(nFields);
2107 :
2108 0 : CPLAssert(m_entryType == HDFE_NENTDFLD);
2109 0 : GDinqfields(m_poGDHandle->m_handle, &osFieldList[0], &ranks[0],
2110 0 : &numberTypes[0]);
2111 :
2112 : CPLStringList aosFields(
2113 0 : CSLTokenizeString2(osFieldList.c_str(), ",", CSLT_HONOURSTRINGS));
2114 0 : for (int i = 0; i < aosFields.size(); i++)
2115 0 : ret.push_back(aosFields[i]);
2116 :
2117 0 : return ret;
2118 : }
2119 :
2120 : /************************************************************************/
2121 : /* OpenMDArray() */
2122 : /************************************************************************/
2123 :
2124 : std::shared_ptr<GDALMDArray>
2125 0 : HDF4EOSGridSubGroup::OpenMDArray(const std::string &osName, CSLConstList) const
2126 : {
2127 0 : CPLMutexHolderD(&hHDF4Mutex);
2128 :
2129 : int32 iRank;
2130 : int32 iNumType;
2131 0 : std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
2132 0 : std::string dimNames;
2133 :
2134 0 : int32 nStrBufSize = 0;
2135 0 : GDnentries(m_poGDHandle->m_handle, HDFE_NENTDIM, &nStrBufSize);
2136 0 : if (nStrBufSize <= 0)
2137 0 : dimNames.resize(HDFE_DIMBUFSIZE);
2138 : else
2139 0 : dimNames.resize(nStrBufSize);
2140 0 : if (GDfieldinfo(m_poGDHandle->m_handle, osName.c_str(), &iRank,
2141 0 : &aiDimSizes[0], &iNumType, &dimNames[0]) < 0)
2142 : {
2143 0 : return nullptr;
2144 : }
2145 0 : aiDimSizes.resize(iRank);
2146 0 : dimNames.resize(strlen(dimNames.c_str()));
2147 :
2148 0 : return HDF4EOSGridArray::Create(GetFullName(), osName, m_poShared,
2149 0 : m_poGDHandle, aiDimSizes, dimNames,
2150 0 : iNumType, m_groupDims);
2151 : }
2152 :
2153 : /************************************************************************/
2154 : /* HDF4EOSGridArray() */
2155 : /************************************************************************/
2156 :
2157 0 : HDF4EOSGridArray::HDF4EOSGridArray(
2158 : const std::string &osParentName, const std::string &osName,
2159 : const std::shared_ptr<HDF4SharedResources> &poShared,
2160 : const std::shared_ptr<HDF4GDHandle> &poGDHandle,
2161 : const std::vector<int32> &aiDimSizes, const std::string &dimNames,
2162 : int32 iNumType,
2163 0 : const std::vector<std::shared_ptr<GDALDimension>> &groupDims)
2164 : : GDALAbstractMDArray(osParentName, osName),
2165 : GDALPamMDArray(osParentName, osName, poShared->GetPAM()),
2166 : m_poShared(poShared), m_poGDHandle(poGDHandle),
2167 : m_dt(iNumType == DFNT_CHAR8 ? GDALExtendedDataType::CreateString()
2168 : : GDALExtendedDataType::Create(
2169 0 : HDF4Dataset::GetDataType(iNumType)))
2170 : {
2171 : CPLStringList aosDimNames(
2172 0 : CSLTokenizeString2(dimNames.c_str(), ",", CSLT_HONOURSTRINGS));
2173 0 : if (static_cast<size_t>(aosDimNames.size()) == aiDimSizes.size())
2174 : {
2175 0 : for (int i = 0; i < aosDimNames.size(); i++)
2176 : {
2177 0 : bool bFound = false;
2178 0 : for (const auto &poDim : groupDims)
2179 : {
2180 0 : if (poDim->GetName() == aosDimNames[i] &&
2181 0 : poDim->GetSize() == static_cast<GUInt64>(aiDimSizes[i]))
2182 : {
2183 0 : bFound = true;
2184 0 : m_dims.push_back(poDim);
2185 0 : break;
2186 : }
2187 : }
2188 0 : if (!bFound)
2189 : {
2190 0 : m_dims.push_back(std::make_shared<GDALDimension>(
2191 0 : std::string(), aosDimNames[i], std::string(), std::string(),
2192 0 : aiDimSizes[i]));
2193 : }
2194 : }
2195 : }
2196 0 : }
2197 :
2198 : /************************************************************************/
2199 : /* GetAttributes() */
2200 : /************************************************************************/
2201 :
2202 : std::vector<std::shared_ptr<GDALAttribute>>
2203 0 : HDF4EOSGridArray::GetAttributes(CSLConstList) const
2204 : {
2205 0 : CPLMutexHolderD(&hHDF4Mutex);
2206 0 : std::vector<std::shared_ptr<GDALAttribute>> ret;
2207 0 : int32 iSDS = 0;
2208 0 : if (GDsdid(m_poGDHandle->m_handle, GetName().c_str(), &iSDS) != -1)
2209 : {
2210 0 : int32 iRank = 0;
2211 0 : int32 iNumType = 0;
2212 0 : int32 nAttrs = 0;
2213 0 : std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
2214 :
2215 0 : if (SDgetinfo(iSDS, nullptr, &iRank, &aiDimSizes[0], &iNumType,
2216 0 : &nAttrs) == 0)
2217 : {
2218 0 : for (int32 iAttribute = 0; iAttribute < nAttrs; iAttribute++)
2219 : {
2220 0 : std::string osAttrName;
2221 0 : osAttrName.resize(H4_MAX_NC_NAME);
2222 0 : iNumType = 0;
2223 0 : int32 nValues = 0;
2224 0 : SDattrinfo(iSDS, iAttribute, &osAttrName[0], &iNumType,
2225 : &nValues);
2226 0 : osAttrName.resize(strlen(osAttrName.c_str()));
2227 0 : ret.emplace_back(std::make_shared<HDF4SDAttribute>(
2228 0 : GetFullName(), osAttrName, m_poShared, nullptr,
2229 0 : m_poGDHandle, iSDS, iAttribute, iNumType, nValues));
2230 : }
2231 : }
2232 : }
2233 0 : return ret;
2234 : }
2235 :
2236 : /************************************************************************/
2237 : /* GetRawNoDataValue() */
2238 : /************************************************************************/
2239 :
2240 0 : const void *HDF4EOSGridArray::GetRawNoDataValue() const
2241 : {
2242 0 : if (!m_abyNoData.empty())
2243 0 : return m_abyNoData.data();
2244 0 : m_abyNoData.resize(GetDataType().GetSize());
2245 :
2246 0 : auto poAttr = GetAttribute("_FillValue");
2247 0 : if (poAttr)
2248 : {
2249 0 : const double dfVal = poAttr->ReadAsDouble();
2250 0 : GDALExtendedDataType::CopyValue(
2251 0 : &dfVal, GDALExtendedDataType::Create(GDT_Float64), &m_abyNoData[0],
2252 : GetDataType());
2253 0 : return m_abyNoData.data();
2254 : }
2255 :
2256 0 : CPLMutexHolderD(&hHDF4Mutex);
2257 0 : if (GDgetfillvalue(m_poGDHandle->m_handle, GetName().c_str(),
2258 0 : &m_abyNoData[0]) != -1)
2259 : {
2260 0 : return m_abyNoData.data();
2261 : }
2262 0 : m_abyNoData.clear();
2263 0 : return nullptr;
2264 : }
2265 :
2266 : /************************************************************************/
2267 : /* GetOffsetOrScale() */
2268 : /************************************************************************/
2269 :
2270 2 : static double GetOffsetOrScale(const GDALMDArray *poArray,
2271 : const char *pszAttrName, double dfDefaultValue,
2272 : bool *pbHasVal, GDALDataType *peStorageType)
2273 : {
2274 6 : auto poAttr = poArray->GetAttribute(pszAttrName);
2275 2 : if (poAttr && (poAttr->GetDataType().GetNumericDataType() == GDT_Float32 ||
2276 2 : poAttr->GetDataType().GetNumericDataType() == GDT_Float64))
2277 : {
2278 0 : if (pbHasVal)
2279 0 : *pbHasVal = true;
2280 0 : if (peStorageType)
2281 0 : *peStorageType = poAttr->GetDataType().GetNumericDataType();
2282 0 : return poAttr->ReadAsDouble();
2283 : }
2284 2 : if (pbHasVal)
2285 2 : *pbHasVal = false;
2286 2 : return dfDefaultValue;
2287 : }
2288 :
2289 : /************************************************************************/
2290 : /* GetOffset() */
2291 : /************************************************************************/
2292 :
2293 1 : static double GetOffset(const GDALMDArray *poArray, bool *pbHasOffset,
2294 : GDALDataType *peStorageType)
2295 : {
2296 1 : return GetOffsetOrScale(poArray, "add_offset", 0, pbHasOffset,
2297 1 : peStorageType);
2298 : }
2299 :
2300 : /************************************************************************/
2301 : /* GetOffset() */
2302 : /************************************************************************/
2303 :
2304 0 : double HDF4EOSGridArray::GetOffset(bool *pbHasOffset,
2305 : GDALDataType *peStorageType) const
2306 : {
2307 0 : return ::GetOffset(this, pbHasOffset, peStorageType);
2308 : }
2309 :
2310 : /************************************************************************/
2311 : /* GetScale() */
2312 : /************************************************************************/
2313 :
2314 1 : static double GetScale(const GDALMDArray *poArray, bool *pbHasScale,
2315 : GDALDataType *peStorageType)
2316 : {
2317 1 : return GetOffsetOrScale(poArray, "scale_factor", 1, pbHasScale,
2318 1 : peStorageType);
2319 : }
2320 :
2321 : /************************************************************************/
2322 : /* GetScale() */
2323 : /************************************************************************/
2324 :
2325 0 : double HDF4EOSGridArray::GetScale(bool *pbHasScale,
2326 : GDALDataType *peStorageType) const
2327 : {
2328 0 : return ::GetScale(this, pbHasScale, peStorageType);
2329 : }
2330 :
2331 : /************************************************************************/
2332 : /* GetUnit() */
2333 : /************************************************************************/
2334 :
2335 0 : const std::string &HDF4EOSGridArray::GetUnit() const
2336 : {
2337 0 : auto poAttr = GetAttribute("units");
2338 0 : if (poAttr && poAttr->GetDataType().GetClass() == GEDTC_STRING)
2339 : {
2340 0 : const char *pszVal = poAttr->ReadAsString();
2341 0 : if (pszVal)
2342 0 : m_osUnit = pszVal;
2343 : }
2344 0 : return m_osUnit;
2345 : }
2346 :
2347 : /************************************************************************/
2348 : /* GetSpatialRef() */
2349 : /************************************************************************/
2350 :
2351 0 : std::shared_ptr<OGRSpatialReference> HDF4EOSGridArray::GetSpatialRef() const
2352 : {
2353 0 : CPLMutexHolderD(&hHDF4Mutex);
2354 0 : int32 iProjCode = 0;
2355 0 : int32 iZoneCode = 0;
2356 0 : int32 iSphereCode = 0;
2357 : double adfProjParams[15];
2358 :
2359 0 : if (GDprojinfo(m_poGDHandle->m_handle, &iProjCode, &iZoneCode, &iSphereCode,
2360 0 : adfProjParams) >= 0)
2361 : {
2362 0 : auto poSRS(std::make_shared<OGRSpatialReference>());
2363 0 : poSRS->importFromUSGS(iProjCode, iZoneCode, adfProjParams, iSphereCode,
2364 : USGS_ANGLE_RADIANS);
2365 0 : int iDimY = -1;
2366 0 : int iDimX = -1;
2367 0 : if (m_dims.size() >= 2)
2368 : {
2369 0 : iDimY = 1 + static_cast<int>(m_dims.size() - 2);
2370 0 : iDimX = 1 + static_cast<int>(m_dims.size() - 1);
2371 : }
2372 0 : if (iDimX > 0 && iDimY > 0)
2373 : {
2374 0 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2375 0 : if (poSRS->GetDataAxisToSRSAxisMapping() == std::vector<int>{2, 1})
2376 0 : poSRS->SetDataAxisToSRSAxisMapping({iDimY, iDimX});
2377 : else
2378 0 : poSRS->SetDataAxisToSRSAxisMapping({iDimX, iDimY});
2379 : }
2380 0 : return poSRS;
2381 : }
2382 0 : return nullptr;
2383 : }
2384 :
2385 : /************************************************************************/
2386 : /* IRead() */
2387 : /************************************************************************/
2388 :
2389 0 : bool HDF4EOSGridArray::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
2390 : const GInt64 *arrayStep,
2391 : const GPtrDiff_t *bufferStride,
2392 : const GDALExtendedDataType &bufferDataType,
2393 : void *pDstBuffer) const
2394 : {
2395 : ReadFunc readFunc;
2396 0 : readFunc.pReadField = GDreadfield;
2397 0 : return ReadPixels(arrayStartIdx, count, arrayStep, bufferStride,
2398 0 : bufferDataType, pDstBuffer, m_poShared, m_dt, m_dims,
2399 0 : m_poGDHandle->m_handle, GetName().c_str(), readFunc);
2400 : }
2401 :
2402 : /************************************************************************/
2403 : /* GetMDArrayNames() */
2404 : /************************************************************************/
2405 :
2406 4 : std::vector<std::string> HDF4SDSGroup::GetMDArrayNames(CSLConstList) const
2407 : {
2408 8 : CPLMutexHolderD(&hHDF4Mutex);
2409 4 : std::vector<std::string> ret;
2410 :
2411 4 : int32 nDatasets = 0;
2412 4 : int32 nAttrs = 0;
2413 4 : if (SDfileinfo(m_poShared->GetSDHandle(), &nDatasets, &nAttrs) != 0)
2414 0 : return ret;
2415 :
2416 8 : std::set<std::string> oSetNames;
2417 10 : for (int32 i = 0; i < nDatasets; i++)
2418 : {
2419 6 : const int32 iSDS = SDselect(m_poShared->GetSDHandle(), i);
2420 12 : std::string osName;
2421 6 : osName.resize(VSNAMELENMAX);
2422 6 : int32 iRank = 0;
2423 6 : int32 iNumType = 0;
2424 12 : std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
2425 6 : if (SDgetinfo(iSDS, &osName[0], &iRank, &aiDimSizes[0], &iNumType,
2426 6 : &nAttrs) == 0)
2427 : {
2428 6 : osName.resize(strlen(osName.c_str()));
2429 6 : int counter = 2;
2430 6 : std::string osRadix(osName);
2431 6 : while (oSetNames.find(osName) != oSetNames.end())
2432 : {
2433 0 : osName = osRadix + CPLSPrintf("_%d", counter);
2434 0 : counter++;
2435 : }
2436 6 : ret.push_back(osName);
2437 6 : m_oMapNameToSDSIdx[osName] = i;
2438 : }
2439 6 : SDendaccess(iSDS);
2440 : }
2441 :
2442 4 : if (m_bIsGDALDataset)
2443 : {
2444 2 : GetDimensions();
2445 2 : if (m_varX && m_varY)
2446 : {
2447 2 : ret.push_back(m_varX->GetName());
2448 2 : ret.push_back(m_varY->GetName());
2449 : }
2450 : }
2451 :
2452 4 : return ret;
2453 : }
2454 :
2455 : /************************************************************************/
2456 : /* OpenMDArray() */
2457 : /************************************************************************/
2458 :
2459 : std::shared_ptr<GDALMDArray>
2460 10 : HDF4SDSGroup::OpenMDArray(const std::string &osName, CSLConstList) const
2461 : {
2462 20 : CPLMutexHolderD(&hHDF4Mutex);
2463 10 : if (m_oMapNameToSDSIdx.empty())
2464 : {
2465 0 : GetMDArrayNames(nullptr);
2466 : }
2467 10 : auto oIter = m_oMapNameToSDSIdx.find(osName);
2468 10 : if (oIter == m_oMapNameToSDSIdx.end())
2469 : {
2470 2 : if (m_bIsGDALDataset)
2471 : {
2472 2 : GetDimensions();
2473 2 : if (m_varX && m_varX->GetName() == osName)
2474 : {
2475 1 : return m_varX;
2476 : }
2477 1 : if (m_varY && m_varY->GetName() == osName)
2478 : {
2479 1 : return m_varY;
2480 : }
2481 : }
2482 0 : return nullptr;
2483 : }
2484 8 : const int32 iSDS = SDselect(m_poShared->GetSDHandle(), oIter->second);
2485 :
2486 8 : int32 iRank = 0;
2487 8 : int32 iNumType = 0;
2488 8 : int32 nAttrs = 0;
2489 16 : std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
2490 8 : SDgetinfo(iSDS, nullptr, &iRank, &aiDimSizes[0], &iNumType, &nAttrs);
2491 8 : aiDimSizes.resize(iRank);
2492 :
2493 8 : auto ar = HDF4SDSArray::Create(GetFullName(), osName, m_poShared, iSDS,
2494 0 : aiDimSizes, GetDimensions(), iNumType,
2495 16 : nAttrs, m_bIsGDALDataset);
2496 8 : if (m_bIsGDALDataset)
2497 2 : ar->SetGlobalAttributes(m_oGlobalAttributes);
2498 8 : return ar;
2499 : }
2500 :
2501 : /************************************************************************/
2502 : /* GetDimensions() */
2503 : /************************************************************************/
2504 :
2505 : std::vector<std::shared_ptr<GDALDimension>>
2506 16 : HDF4SDSGroup::GetDimensions(CSLConstList) const
2507 : {
2508 32 : CPLMutexHolderD(&hHDF4Mutex);
2509 16 : if (m_bInGetDimensions)
2510 2 : return {};
2511 14 : if (!m_dims.empty())
2512 10 : return m_dims;
2513 4 : if (m_oMapNameToSDSIdx.empty())
2514 : {
2515 1 : m_bInGetDimensions = true;
2516 1 : GetMDArrayNames(nullptr);
2517 1 : m_bInGetDimensions = false;
2518 : }
2519 :
2520 8 : std::string osProjection;
2521 8 : std::string osTransformationMatrix;
2522 4 : if (m_bIsGDALDataset)
2523 : {
2524 8 : for (const auto &poAttr : m_oGlobalAttributes)
2525 : {
2526 8 : if (poAttr->GetName() == "Projection" &&
2527 2 : poAttr->GetDataType().GetClass() == GEDTC_STRING)
2528 : {
2529 2 : const char *pszVal = poAttr->ReadAsString();
2530 2 : if (pszVal)
2531 2 : osProjection = pszVal;
2532 : }
2533 6 : else if (poAttr->GetName() == "TransformationMatrix" &&
2534 2 : poAttr->GetDataType().GetClass() == GEDTC_STRING)
2535 : {
2536 2 : const char *pszVal = poAttr->ReadAsString();
2537 2 : if (pszVal)
2538 2 : osTransformationMatrix = pszVal;
2539 : }
2540 : }
2541 : }
2542 :
2543 : // First collect all dimension ids referenced by all datasets
2544 8 : std::map<int32, int32> oMapDimIdToDimSize;
2545 8 : std::set<std::string> oSetArrayNames;
2546 10 : for (const auto &oIter : m_oMapNameToSDSIdx)
2547 : {
2548 6 : const int32 iSDS = SDselect(m_poShared->GetSDHandle(), oIter.second);
2549 6 : int32 iRank = 0;
2550 6 : int32 iNumType = 0;
2551 6 : int32 nAttrs = 0;
2552 12 : std::vector<int32> aiDimSizes(H4_MAX_VAR_DIMS);
2553 6 : SDgetinfo(iSDS, nullptr, &iRank, &aiDimSizes[0], &iNumType, &nAttrs);
2554 17 : for (int i = 0; i < iRank; i++)
2555 : {
2556 11 : const auto dimId = SDgetdimid(iSDS, i);
2557 11 : oMapDimIdToDimSize[dimId] =
2558 11 : std::max(oMapDimIdToDimSize[dimId], aiDimSizes[i]);
2559 : }
2560 6 : oSetArrayNames.insert(oIter.first);
2561 6 : SDendaccess(iSDS);
2562 : }
2563 :
2564 : // Instantiate dimensions
2565 : std::set<std::shared_ptr<GDALDimensionWeakIndexingVar>>
2566 8 : oSetDimsWithVariable;
2567 13 : for (const auto &iter : oMapDimIdToDimSize)
2568 : {
2569 18 : std::string osName;
2570 9 : osName.resize(VSNAMELENMAX);
2571 9 : int32 iSize = 0; // can be 0 for unlimited dimension
2572 9 : int32 iNumType = 0;
2573 9 : int32 nAttrs = 0;
2574 9 : SDdiminfo(iter.first, &osName[0], &iSize, &iNumType, &nAttrs);
2575 9 : osName.resize(strlen(osName.c_str()));
2576 :
2577 18 : std::string osType;
2578 18 : std::string osDirection;
2579 9 : bool bIsIndexedDim = false;
2580 9 : if (iNumType > 0 && oSetArrayNames.find(osName) != oSetArrayNames.end())
2581 : {
2582 2 : bIsIndexedDim = true;
2583 2 : m_bInGetDimensions = true;
2584 4 : auto poArray(OpenMDArray(osName, nullptr));
2585 2 : m_bInGetDimensions = false;
2586 2 : if (poArray)
2587 : {
2588 6 : auto poAxis = poArray->GetAttribute("axis");
2589 2 : if (poAxis && poAxis->GetDataType().GetClass() == GEDTC_STRING)
2590 : {
2591 0 : const char *pszVal = poAxis->ReadAsString();
2592 0 : if (pszVal && EQUAL(pszVal, "X"))
2593 0 : osType = GDAL_DIM_TYPE_HORIZONTAL_X;
2594 0 : else if (pszVal && EQUAL(pszVal, "Y"))
2595 0 : osType = GDAL_DIM_TYPE_HORIZONTAL_Y;
2596 : }
2597 : }
2598 : }
2599 :
2600 : // Do not trust iSize which can be 0 for a unlimited dimension, but
2601 : // the size actually taken by the array(s)
2602 : auto poDim(std::make_shared<GDALDimensionWeakIndexingVar>(
2603 9 : GetFullName(), osName, osType, osDirection, iter.second));
2604 : // cppcheck-suppress knownConditionTrueFalse
2605 9 : if (bIsIndexedDim)
2606 : {
2607 2 : oSetDimsWithVariable.insert(poDim);
2608 : }
2609 9 : m_dims.push_back(poDim);
2610 : }
2611 :
2612 2 : if (m_bIsGDALDataset && (m_dims.size() == 2 || m_dims.size() == 3) &&
2613 6 : !osProjection.empty() && !osTransformationMatrix.empty())
2614 : {
2615 : CPLStringList aosCoeffs(
2616 4 : CSLTokenizeString2(osTransformationMatrix.c_str(), ",", 0));
2617 4 : if (aosCoeffs.size() == 6 && CPLAtof(aosCoeffs[2]) == 0 &&
2618 2 : CPLAtof(aosCoeffs[4]) == 0)
2619 : {
2620 : auto newDims = std::vector<std::shared_ptr<GDALDimension>>{
2621 4 : std::make_shared<GDALDimensionWeakIndexingVar>(
2622 2 : GetFullName(), "Y", GDAL_DIM_TYPE_HORIZONTAL_Y,
2623 2 : std::string(), m_dims[0]->GetSize()),
2624 4 : std::make_shared<GDALDimensionWeakIndexingVar>(
2625 2 : GetFullName(), "X", GDAL_DIM_TYPE_HORIZONTAL_X,
2626 14 : std::string(), m_dims[1]->GetSize())};
2627 2 : if (m_dims.size() == 3)
2628 : {
2629 1 : newDims.push_back(
2630 2 : std::make_shared<GDALDimensionWeakIndexingVar>(
2631 2 : GetFullName(), "Band", std::string(), std::string(),
2632 2 : m_dims[2]->GetSize()));
2633 : }
2634 2 : m_dims = std::move(newDims);
2635 :
2636 4 : m_varX = GDALMDArrayRegularlySpaced::Create(
2637 2 : GetFullName(), m_dims[1]->GetName(), m_dims[1],
2638 4 : CPLAtof(aosCoeffs[0]), CPLAtof(aosCoeffs[1]), 0.5);
2639 2 : m_dims[1]->SetIndexingVariable(m_varX);
2640 :
2641 4 : m_varY = GDALMDArrayRegularlySpaced::Create(
2642 2 : GetFullName(), m_dims[0]->GetName(), m_dims[0],
2643 4 : CPLAtof(aosCoeffs[3]), CPLAtof(aosCoeffs[5]), 0.5);
2644 2 : m_dims[0]->SetIndexingVariable(m_varY);
2645 : }
2646 : }
2647 :
2648 : // Now that we have eatablished all dimensions, we can link them to
2649 : // variables
2650 6 : for (auto &poDim : oSetDimsWithVariable)
2651 : {
2652 4 : auto poArray(OpenMDArray(poDim->GetName(), nullptr));
2653 2 : if (poArray)
2654 : {
2655 2 : m_oSetIndexingVariables.push_back(poArray);
2656 2 : poDim->SetIndexingVariable(std::move(poArray));
2657 : }
2658 : }
2659 :
2660 4 : return m_dims;
2661 : }
2662 :
2663 : /************************************************************************/
2664 : /* HDF4SDSArray() */
2665 : /************************************************************************/
2666 :
2667 8 : HDF4SDSArray::HDF4SDSArray(
2668 : const std::string &osParentName, const std::string &osName,
2669 : const std::shared_ptr<HDF4SharedResources> &poShared, int32 iSDS,
2670 : const std::vector<int32> &aiDimSizes,
2671 : const std::vector<std::shared_ptr<GDALDimension>> &groupDims,
2672 8 : int32 iNumType, int32 nAttrs, bool bIsGDALDS)
2673 : : GDALAbstractMDArray(osParentName, osName),
2674 : GDALPamMDArray(osParentName, osName, poShared->GetPAM()),
2675 : m_poShared(poShared), m_iSDS(iSDS),
2676 : m_dt(iNumType == DFNT_CHAR8 ? GDALExtendedDataType::CreateString()
2677 : : GDALExtendedDataType::Create(
2678 : HDF4Dataset::GetDataType(iNumType))),
2679 8 : m_nAttributes(nAttrs), m_bIsGDALDataset(bIsGDALDS)
2680 : {
2681 21 : for (int i = 0; i < static_cast<int>(aiDimSizes.size()); i++)
2682 : {
2683 26 : std::string osDimName;
2684 13 : osDimName.resize(VSNAMELENMAX);
2685 13 : int32 iSize = 0;
2686 13 : int32 iDimNumType = 0;
2687 13 : int32 nDimAttrs = 0;
2688 13 : int32 dimId = SDgetdimid(iSDS, i);
2689 13 : SDdiminfo(dimId, &osDimName[0], &iSize, &iDimNumType, &nDimAttrs);
2690 13 : osDimName.resize(strlen(osDimName.c_str()));
2691 13 : bool bFound = false;
2692 20 : for (const auto &poDim : groupDims)
2693 : {
2694 30 : if (poDim->GetName() == osDimName ||
2695 12 : (bIsGDALDS && i == 0 && poDim->GetName() == "Y") ||
2696 35 : (bIsGDALDS && i == 1 && poDim->GetName() == "X") ||
2697 5 : (bIsGDALDS && i == 2 && poDim->GetName() == "Band"))
2698 : {
2699 11 : bFound = true;
2700 11 : m_dims.push_back(poDim);
2701 11 : break;
2702 : }
2703 : }
2704 13 : if (!bFound)
2705 : {
2706 2 : m_dims.push_back(std::make_shared<GDALDimension>(
2707 4 : std::string(), CPLSPrintf("dim%d", i), std::string(),
2708 4 : std::string(), aiDimSizes[i]));
2709 : }
2710 : }
2711 8 : }
2712 :
2713 : /************************************************************************/
2714 : /* ~HDF4SDSArray() */
2715 : /************************************************************************/
2716 :
2717 16 : HDF4SDSArray::~HDF4SDSArray()
2718 : {
2719 16 : CPLMutexHolderD(&hHDF4Mutex);
2720 8 : SDendaccess(m_iSDS);
2721 16 : }
2722 :
2723 : /************************************************************************/
2724 : /* GetRawNoDataValue() */
2725 : /************************************************************************/
2726 :
2727 1 : const void *HDF4SDSArray::GetRawNoDataValue() const
2728 : {
2729 1 : if (!m_abyNoData.empty())
2730 0 : return m_abyNoData.data();
2731 1 : m_abyNoData.resize(GetDataType().GetSize());
2732 :
2733 3 : auto poAttr = GetAttribute("_FillValue");
2734 1 : if (poAttr)
2735 : {
2736 0 : const double dfVal = poAttr->ReadAsDouble();
2737 0 : GDALExtendedDataType::CopyValue(
2738 0 : &dfVal, GDALExtendedDataType::Create(GDT_Float64), &m_abyNoData[0],
2739 : GetDataType());
2740 0 : return m_abyNoData.data();
2741 : }
2742 :
2743 2 : CPLMutexHolderD(&hHDF4Mutex);
2744 1 : if (SDgetfillvalue(m_iSDS, &m_abyNoData[0]) != -1)
2745 : {
2746 0 : return m_abyNoData.data();
2747 : }
2748 :
2749 1 : m_abyNoData.clear();
2750 1 : return nullptr;
2751 : }
2752 :
2753 : /************************************************************************/
2754 : /* GetAttributes() */
2755 : /************************************************************************/
2756 :
2757 : std::vector<std::shared_ptr<GDALAttribute>>
2758 9 : HDF4SDSArray::GetAttributes(CSLConstList) const
2759 : {
2760 18 : CPLMutexHolderD(&hHDF4Mutex);
2761 9 : std::vector<std::shared_ptr<GDALAttribute>> ret;
2762 :
2763 13 : for (int32 iAttribute = 0; iAttribute < m_nAttributes; iAttribute++)
2764 : {
2765 4 : std::string osAttrName;
2766 4 : osAttrName.resize(H4_MAX_NC_NAME);
2767 4 : int32 iNumType = 0;
2768 4 : int32 nValues = 0;
2769 4 : SDattrinfo(m_iSDS, iAttribute, &osAttrName[0], &iNumType, &nValues);
2770 4 : osAttrName.resize(strlen(osAttrName.c_str()));
2771 8 : ret.emplace_back(std::make_shared<HDF4SDAttribute>(
2772 8 : GetFullName(), osAttrName, m_poShared, nullptr, nullptr, m_iSDS,
2773 4 : iAttribute, iNumType, nValues));
2774 : }
2775 :
2776 18 : return ret;
2777 : }
2778 :
2779 : /************************************************************************/
2780 : /* GetOffset() */
2781 : /************************************************************************/
2782 :
2783 1 : double HDF4SDSArray::GetOffset(bool *pbHasOffset,
2784 : GDALDataType *peStorageType) const
2785 : {
2786 1 : return ::GetOffset(this, pbHasOffset, peStorageType);
2787 : }
2788 :
2789 : /************************************************************************/
2790 : /* GetScale() */
2791 : /************************************************************************/
2792 :
2793 1 : double HDF4SDSArray::GetScale(bool *pbHasScale,
2794 : GDALDataType *peStorageType) const
2795 : {
2796 1 : return ::GetScale(this, pbHasScale, peStorageType);
2797 : }
2798 :
2799 : /************************************************************************/
2800 : /* GetUnit() */
2801 : /************************************************************************/
2802 :
2803 2 : const std::string &HDF4SDSArray::GetUnit() const
2804 : {
2805 4 : auto poAttr = GetAttribute("units");
2806 2 : if (poAttr && poAttr->GetDataType().GetClass() == GEDTC_STRING)
2807 : {
2808 0 : const char *pszVal = poAttr->ReadAsString();
2809 0 : if (pszVal)
2810 0 : m_osUnit = pszVal;
2811 : }
2812 4 : return m_osUnit;
2813 : }
2814 :
2815 : /************************************************************************/
2816 : /* GetSpatialRef() */
2817 : /************************************************************************/
2818 :
2819 3 : std::shared_ptr<OGRSpatialReference> HDF4SDSArray::GetSpatialRef() const
2820 : {
2821 3 : if (m_bIsGDALDataset)
2822 : {
2823 2 : std::string osProjection;
2824 6 : for (const auto &poAttr : m_oGlobalAttributes)
2825 : {
2826 8 : if (poAttr->GetName() == "Projection" &&
2827 2 : poAttr->GetDataType().GetClass() == GEDTC_STRING)
2828 : {
2829 2 : const char *pszVal = poAttr->ReadAsString();
2830 2 : if (pszVal)
2831 2 : osProjection = pszVal;
2832 2 : break;
2833 : }
2834 : }
2835 2 : if (!osProjection.empty())
2836 : {
2837 4 : auto poSRS(std::make_shared<OGRSpatialReference>());
2838 2 : poSRS->SetFromUserInput(
2839 : osProjection.c_str(),
2840 : OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get());
2841 2 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2842 2 : if (poSRS->GetDataAxisToSRSAxisMapping() == std::vector<int>{2, 1})
2843 0 : poSRS->SetDataAxisToSRSAxisMapping({1, 2});
2844 : else
2845 2 : poSRS->SetDataAxisToSRSAxisMapping({2, 1});
2846 2 : return poSRS;
2847 : }
2848 : }
2849 1 : return nullptr;
2850 : }
2851 :
2852 : /************************************************************************/
2853 : /* IRead() */
2854 : /************************************************************************/
2855 :
2856 4 : bool HDF4SDSArray::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
2857 : const GInt64 *arrayStep,
2858 : const GPtrDiff_t *bufferStride,
2859 : const GDALExtendedDataType &bufferDataType,
2860 : void *pDstBuffer) const
2861 : {
2862 : ReadFunc readFunc;
2863 4 : readFunc.pReadData = SDreaddata;
2864 8 : return ReadPixels(arrayStartIdx, count, arrayStep, bufferStride,
2865 4 : bufferDataType, pDstBuffer, m_poShared, m_dt, m_dims,
2866 8 : m_iSDS, nullptr, readFunc);
2867 : }
2868 :
2869 : /************************************************************************/
2870 : /* GetMDArrayNames() */
2871 : /************************************************************************/
2872 :
2873 2 : std::vector<std::string> HDF4GRsGroup::GetMDArrayNames(CSLConstList) const
2874 : {
2875 4 : CPLMutexHolderD(&hHDF4Mutex);
2876 2 : std::vector<std::string> res;
2877 :
2878 2 : int32 nImages = 0;
2879 2 : int32 nAttrs = 0;
2880 2 : GRfileinfo(m_poGRsHandle->m_grHandle, &nImages, &nAttrs);
2881 4 : for (int32 i = 0; i < nImages; i++)
2882 : {
2883 2 : const int32 iGR = GRselect(m_poGRsHandle->m_grHandle, i);
2884 :
2885 4 : std::string osName;
2886 2 : osName.resize(VSNAMELENMAX);
2887 2 : int32 nBands = 0;
2888 2 : int32 iNumType = 0;
2889 2 : int32 iInterlaceMode = 0;
2890 4 : std::vector<int32> aiDimSizes(2);
2891 2 : if (GRgetiminfo(iGR, &osName[0], &nBands, &iNumType, &iInterlaceMode,
2892 4 : &aiDimSizes[0], &nAttrs) == 0)
2893 : {
2894 2 : osName.resize(strlen(osName.c_str()));
2895 2 : m_oMapNameToGRIdx[osName] = i;
2896 2 : res.push_back(std::move(osName));
2897 : }
2898 :
2899 2 : GRendaccess(iGR);
2900 : }
2901 4 : return res;
2902 : }
2903 :
2904 : /************************************************************************/
2905 : /* GetAttributes() */
2906 : /************************************************************************/
2907 :
2908 : std::vector<std::shared_ptr<GDALAttribute>>
2909 2 : HDF4GRsGroup::GetAttributes(CSLConstList) const
2910 : {
2911 4 : CPLMutexHolderD(&hHDF4Mutex);
2912 2 : std::vector<std::shared_ptr<GDALAttribute>> ret;
2913 2 : int32 nDatasets = 0;
2914 2 : int32 nAttributes = 0;
2915 2 : if (GRfileinfo(m_poGRsHandle->m_grHandle, &nDatasets, &nAttributes) != 0)
2916 0 : return ret;
2917 6 : for (int32 iAttribute = 0; iAttribute < nAttributes; iAttribute++)
2918 : {
2919 4 : int32 iNumType = 0;
2920 4 : int32 nValues = 0;
2921 :
2922 4 : std::string osAttrName;
2923 4 : osAttrName.resize(H4_MAX_NC_NAME);
2924 4 : GRattrinfo(m_poGRsHandle->m_grHandle, iAttribute, &osAttrName[0],
2925 : &iNumType, &nValues);
2926 4 : osAttrName.resize(strlen(osAttrName.c_str()));
2927 :
2928 8 : ret.emplace_back(std::make_shared<HDF4GRAttribute>(
2929 4 : GetFullName(), osAttrName, m_poShared, m_poGRsHandle, nullptr,
2930 8 : m_poGRsHandle->m_grHandle, iAttribute, iNumType, nValues));
2931 : }
2932 2 : return ret;
2933 : }
2934 :
2935 : /************************************************************************/
2936 : /* OpenMDArray() */
2937 : /************************************************************************/
2938 :
2939 : std::shared_ptr<GDALMDArray>
2940 3 : HDF4GRsGroup::OpenMDArray(const std::string &osName, CSLConstList) const
2941 : {
2942 6 : CPLMutexHolderD(&hHDF4Mutex);
2943 3 : if (m_oMapNameToGRIdx.empty())
2944 : {
2945 1 : GetMDArrayNames(nullptr);
2946 : }
2947 3 : auto oIter = m_oMapNameToGRIdx.find(osName);
2948 3 : if (oIter == m_oMapNameToGRIdx.end())
2949 : {
2950 1 : return nullptr;
2951 : }
2952 2 : const int32 iGR = GRselect(m_poGRsHandle->m_grHandle, oIter->second);
2953 :
2954 2 : int32 nBands = 0;
2955 2 : int32 iNumType = 0;
2956 2 : int32 iInterlaceMode = 0;
2957 2 : std::vector<int32> aiDimSizes(2);
2958 : int32 nAttrs;
2959 2 : GRgetiminfo(iGR, nullptr, &nBands, &iNumType, &iInterlaceMode,
2960 2 : &aiDimSizes[0], &nAttrs);
2961 :
2962 4 : return HDF4GRArray::Create(
2963 2 : GetFullName(), osName, m_poShared,
2964 4 : std::make_shared<HDF4GRHandle>(m_poGRsHandle, iGR), nBands, aiDimSizes,
2965 2 : iNumType, nAttrs);
2966 : }
2967 :
2968 : /************************************************************************/
2969 : /* HDF4GRArray() */
2970 : /************************************************************************/
2971 :
2972 2 : HDF4GRArray::HDF4GRArray(const std::string &osParentName,
2973 : const std::string &osName,
2974 : const std::shared_ptr<HDF4SharedResources> &poShared,
2975 : const std::shared_ptr<HDF4GRHandle> &poGRHandle,
2976 : int32 nBands, const std::vector<int32> &aiDimSizes,
2977 2 : int32 iNumType, int32 nAttrs)
2978 : : GDALAbstractMDArray(osParentName, osName),
2979 : GDALPamMDArray(osParentName, osName, poShared->GetPAM()),
2980 : m_poShared(poShared), m_poGRHandle(poGRHandle),
2981 : m_dt(iNumType == DFNT_CHAR8 ? GDALExtendedDataType::CreateString()
2982 : : GDALExtendedDataType::Create(
2983 : HDF4Dataset::GetDataType(iNumType))),
2984 2 : m_nAttributes(nAttrs)
2985 : {
2986 6 : for (int i = 0; i < static_cast<int>(aiDimSizes.size()); i++)
2987 : {
2988 8 : m_dims.push_back(std::make_shared<GDALDimension>(
2989 12 : std::string(), i == 0 ? "y" : "x", std::string(), std::string(),
2990 4 : aiDimSizes[i]));
2991 : }
2992 2 : m_dims.push_back(std::make_shared<GDALDimension>(
2993 4 : std::string(), "bands", std::string(), std::string(), nBands));
2994 2 : }
2995 :
2996 : /************************************************************************/
2997 : /* GetAttributes() */
2998 : /************************************************************************/
2999 :
3000 : std::vector<std::shared_ptr<GDALAttribute>>
3001 4 : HDF4GRArray::GetAttributes(CSLConstList) const
3002 : {
3003 8 : CPLMutexHolderD(&hHDF4Mutex);
3004 4 : std::vector<std::shared_ptr<GDALAttribute>> ret;
3005 10 : for (int32 iAttribute = 0; iAttribute < m_nAttributes; iAttribute++)
3006 : {
3007 6 : int32 iNumType = 0;
3008 6 : int32 nValues = 0;
3009 :
3010 6 : std::string osAttrName;
3011 6 : osAttrName.resize(H4_MAX_NC_NAME);
3012 6 : GRattrinfo(m_poGRHandle->m_iGR, iAttribute, &osAttrName[0], &iNumType,
3013 : &nValues);
3014 6 : osAttrName.resize(strlen(osAttrName.c_str()));
3015 :
3016 12 : ret.emplace_back(std::make_shared<HDF4GRAttribute>(
3017 6 : GetFullName(), osAttrName, m_poShared, nullptr, m_poGRHandle,
3018 12 : m_poGRHandle->m_iGR, iAttribute, iNumType, nValues));
3019 : }
3020 :
3021 4 : auto iPal = GRgetlutid(m_poGRHandle->m_iGR, 0);
3022 4 : if (iPal != -1)
3023 : {
3024 4 : int32 nComps = 0;
3025 4 : int32 iPalDataType = 0;
3026 4 : int32 iPalInterlaceMode = 0;
3027 4 : int32 nPalEntries = 0;
3028 4 : GRgetlutinfo(iPal, &nComps, &iPalDataType, &iPalInterlaceMode,
3029 : &nPalEntries);
3030 1 : if (nPalEntries && nComps == 3 &&
3031 1 : GDALGetDataTypeSizeBytes(HDF4Dataset::GetDataType(iPalDataType)) ==
3032 5 : 1 &&
3033 1 : nPalEntries <= 256)
3034 : {
3035 2 : ret.emplace_back(std::make_shared<HDF4GRPalette>(
3036 1 : GetFullName(), "lut", m_poShared, m_poGRHandle, iPal,
3037 1 : nPalEntries));
3038 : }
3039 : }
3040 :
3041 8 : return ret;
3042 : }
3043 :
3044 : /************************************************************************/
3045 : /* IRead() */
3046 : /************************************************************************/
3047 :
3048 4 : bool HDF4GRArray::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
3049 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
3050 : const GDALExtendedDataType &bufferDataType,
3051 : void *pDstBuffer) const
3052 : {
3053 8 : CPLMutexHolderD(&hHDF4Mutex);
3054 : /* -------------------------------------------------------------------- */
3055 : /* HDF files with external data files, such as some landsat */
3056 : /* products (eg. data/hdf/L1G) need to be told what directory */
3057 : /* to look in to find the external files. Normally this is the */
3058 : /* directory holding the hdf file. */
3059 : /* -------------------------------------------------------------------- */
3060 4 : HXsetdir(CPLGetPathSafe(m_poShared->GetFilename().c_str()).c_str());
3061 :
3062 4 : const size_t nDims(m_dims.size());
3063 8 : std::vector<int32> sw_start(nDims);
3064 8 : std::vector<int32> sw_stride(nDims);
3065 8 : std::vector<int32> sw_edge(nDims);
3066 8 : std::vector<GPtrDiff_t> newBufferStride(nDims);
3067 4 : GByte *pabyDstBuffer = static_cast<GByte *>(pDstBuffer);
3068 4 : const size_t nBufferDataTypeSize = bufferDataType.GetSize();
3069 16 : for (size_t i = 0; i < nDims; i++)
3070 : {
3071 12 : sw_start[i] = static_cast<int>(arrayStartIdx[i]);
3072 12 : sw_stride[i] = static_cast<int>(arrayStep[i]);
3073 12 : sw_edge[i] = static_cast<int>(count[i]);
3074 12 : newBufferStride[i] = bufferStride[i];
3075 12 : if (sw_stride[i] < 0)
3076 : {
3077 : // GRreadimage() doesn't like negative step / array stride, so
3078 : // transform the request to a classic "left-to-right" one
3079 1 : sw_start[i] += sw_stride[i] * (sw_edge[i] - 1);
3080 1 : sw_stride[i] = -sw_stride[i];
3081 1 : pabyDstBuffer +=
3082 1 : (sw_edge[i] - 1) * newBufferStride[i] * nBufferDataTypeSize;
3083 1 : newBufferStride[i] = -newBufferStride[i];
3084 : }
3085 : }
3086 4 : size_t nExpectedStride = 1;
3087 4 : bool bContiguousStride = true;
3088 13 : for (size_t i = nDims; i > 0;)
3089 : {
3090 10 : --i;
3091 10 : if (newBufferStride[i] != static_cast<GPtrDiff_t>(nExpectedStride))
3092 : {
3093 1 : bContiguousStride = false;
3094 1 : break;
3095 : }
3096 9 : nExpectedStride *= count[i];
3097 : }
3098 10 : if (bufferDataType == m_dt && bContiguousStride && arrayStartIdx[2] == 0 &&
3099 10 : count[2] == m_dims[2]->GetSize() && arrayStep[2] == 1)
3100 : {
3101 1 : auto status = GRreadimage(m_poGRHandle->m_iGR, &sw_start[0],
3102 1 : &sw_stride[0], &sw_edge[0], pabyDstBuffer);
3103 1 : return status >= 0;
3104 : }
3105 3 : auto pabyTemp = static_cast<GByte *>(VSI_MALLOC2_VERBOSE(
3106 : m_dt.GetSize(),
3107 : count[0] * count[1] * static_cast<size_t>(m_dims[2]->GetSize())));
3108 3 : if (pabyTemp == nullptr)
3109 0 : return false;
3110 3 : auto status = GRreadimage(m_poGRHandle->m_iGR, &sw_start[0], &sw_stride[0],
3111 3 : &sw_edge[0], pabyTemp);
3112 3 : if (status < 0)
3113 : {
3114 0 : VSIFree(pabyTemp);
3115 0 : return false;
3116 : }
3117 :
3118 3 : const size_t nSrcDataTypeSize = m_dt.GetSize();
3119 6 : std::vector<size_t> anStackCount(nDims);
3120 3 : GByte *pabySrc = pabyTemp + nSrcDataTypeSize * sw_start[2];
3121 3 : std::vector<GByte *> pabyDstBufferStack(nDims + 1);
3122 3 : pabyDstBufferStack[0] = pabyDstBuffer;
3123 3 : size_t iDim = 0;
3124 54 : lbl_next_depth:
3125 54 : if (iDim == nDims)
3126 : {
3127 24 : GDALExtendedDataType::CopyValue(
3128 24 : pabySrc, m_dt, pabyDstBufferStack[nDims], bufferDataType);
3129 24 : pabySrc += nSrcDataTypeSize * sw_stride[2];
3130 : }
3131 : else
3132 : {
3133 30 : anStackCount[iDim] = count[iDim];
3134 : while (true)
3135 : {
3136 51 : ++iDim;
3137 51 : pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
3138 51 : goto lbl_next_depth;
3139 51 : lbl_return_to_caller_in_loop:
3140 51 : --iDim;
3141 51 : --anStackCount[iDim];
3142 51 : if (anStackCount[iDim] == 0)
3143 30 : break;
3144 21 : IncrPointer(pabyDstBufferStack[iDim], newBufferStride[iDim],
3145 : nBufferDataTypeSize);
3146 : }
3147 30 : if (iDim == 2)
3148 18 : pabySrc +=
3149 18 : nSrcDataTypeSize * static_cast<size_t>(m_dims[2]->GetSize() -
3150 18 : count[2] * sw_stride[2]);
3151 : }
3152 54 : if (iDim > 0)
3153 51 : goto lbl_return_to_caller_in_loop;
3154 :
3155 3 : VSIFree(pabyTemp);
3156 3 : return true;
3157 : }
3158 :
3159 : /************************************************************************/
3160 : /* HDF4GRPalette() */
3161 : /************************************************************************/
3162 :
3163 1 : HDF4GRPalette::HDF4GRPalette(
3164 : const std::string &osParentName, const std::string &osName,
3165 : const std::shared_ptr<HDF4SharedResources> &poShared,
3166 1 : const std::shared_ptr<HDF4GRHandle> &poGRHandle, int32 iPal, int32 nValues)
3167 : : GDALAbstractMDArray(osParentName, osName),
3168 : GDALAttribute(osParentName, osName), m_poShared(poShared),
3169 1 : m_poGRHandle(poGRHandle), m_iPal(iPal), m_nValues(nValues)
3170 : {
3171 1 : m_dims.push_back(std::make_shared<GDALDimension>(
3172 2 : std::string(), "index", std::string(), std::string(), nValues));
3173 1 : m_dims.push_back(std::make_shared<GDALDimension>(
3174 2 : std::string(), "component", std::string(), std::string(), 3));
3175 1 : }
3176 :
3177 : /************************************************************************/
3178 : /* IRead() */
3179 : /************************************************************************/
3180 :
3181 1 : bool HDF4GRPalette::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
3182 : const GInt64 *arrayStep,
3183 : const GPtrDiff_t *bufferStride,
3184 : const GDALExtendedDataType &bufferDataType,
3185 : void *pDstBuffer) const
3186 : {
3187 2 : CPLMutexHolderD(&hHDF4Mutex);
3188 :
3189 2 : std::vector<GByte> abyValues(3 * m_nValues);
3190 1 : GRreadlut(m_iPal, &abyValues[0]);
3191 :
3192 1 : GByte *pabyDstBuffer = static_cast<GByte *>(pDstBuffer);
3193 1 : const size_t nBufferDataTypeSize = bufferDataType.GetSize();
3194 1 : const auto srcDt(GDALExtendedDataType::Create(GDT_Byte));
3195 257 : for (size_t i = 0; i < count[0]; ++i)
3196 : {
3197 256 : size_t idx = static_cast<size_t>(arrayStartIdx[0] + i * arrayStep[0]);
3198 1024 : for (size_t j = 0; j < count[1]; ++j)
3199 : {
3200 768 : size_t comp =
3201 768 : static_cast<size_t>(arrayStartIdx[1] + j * arrayStep[1]);
3202 768 : GByte *pDst =
3203 768 : pabyDstBuffer + (i * bufferStride[0] + j * bufferStride[1]) *
3204 : nBufferDataTypeSize;
3205 768 : GDALExtendedDataType::CopyValue(&abyValues[3 * idx + comp], srcDt,
3206 : pDst, bufferDataType);
3207 : }
3208 : }
3209 :
3210 2 : return true;
3211 : }
3212 :
3213 : /************************************************************************/
3214 : /* OpenMultiDim() */
3215 : /************************************************************************/
3216 :
3217 6 : void HDF4Dataset::OpenMultiDim(const char *pszFilename,
3218 : CSLConstList papszOpenOptionsIn)
3219 : {
3220 : // under hHDF4Mutex
3221 :
3222 12 : auto poShared = std::make_shared<HDF4SharedResources>(pszFilename);
3223 6 : poShared->m_hSD = hSD;
3224 6 : poShared->m_aosOpenOptions = papszOpenOptionsIn;
3225 :
3226 6 : hSD = -1;
3227 :
3228 6 : m_poRootGroup = HDF4Group::Create(std::string(), "/", poShared);
3229 :
3230 6 : SetDescription(pszFilename);
3231 :
3232 : // Setup/check for pam .aux.xml.
3233 6 : TryLoadXML();
3234 6 : }
|