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