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