1 /******************************************************************************
2 * $Id: gdalmultidim.cpp 5f249867c4bbe5a64ddcbc483c76b612119d85d4 2021-04-29 11:57:20 +0200 Even Rouault $
3 *
4 * Name: gdalmultidim.cpp
5 * Project: GDAL Core
6 * Purpose: GDAL Core C++/Private implementation for multidimensional support
7 * Author: Even Rouault <even.rouault at spatialys.com>
8 *
9 ******************************************************************************
10 * Copyright (c) 2019, Even Rouault <even.rouault at spatialys.com>
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 * DEALINGS IN THE SOFTWARE.
29 ****************************************************************************/
30
31 #include <assert.h>
32 #include <algorithm>
33 #include <queue>
34 #include <set>
35
36 #include "gdal_priv.h"
37 #include "gdal_pam.h"
38 #include "cpl_safemaths.hpp"
39
40 #if defined(__clang__) || defined(_MSC_VER)
41 #define COMPILER_WARNS_ABOUT_ABSTRACT_VBASE_INIT
42 #endif
43
44 /************************************************************************/
45 /* GDALMDArrayUnscaled */
46 /************************************************************************/
47
48 class GDALMDArrayUnscaled final: public GDALMDArray
49 {
50 private:
51 std::shared_ptr<GDALMDArray> m_poParent{};
52 GDALExtendedDataType m_dt;
53 bool m_bHasNoData;
54 double m_adfNoData[2]{ std::numeric_limits<double>::quiet_NaN(),
55 std::numeric_limits<double>::quiet_NaN() };
56
57 protected:
GDALMDArrayUnscaled(const std::shared_ptr<GDALMDArray> & poParent)58 explicit GDALMDArrayUnscaled(const std::shared_ptr<GDALMDArray>& poParent):
59 GDALAbstractMDArray(std::string(), "Unscaled view of " + poParent->GetFullName()),
60 GDALMDArray(std::string(), "Unscaled view of " + poParent->GetFullName()),
61 m_poParent(std::move(poParent)),
62 m_dt(GDALExtendedDataType::Create(GDALDataTypeIsComplex(
63 m_poParent->GetDataType().GetNumericDataType()) ?
64 GDT_CFloat64 : GDT_Float64)),
65 m_bHasNoData( m_poParent->GetRawNoDataValue() != nullptr )
66 {
67 }
68
69 bool IRead(const GUInt64* arrayStartIdx,
70 const size_t* count,
71 const GInt64* arrayStep,
72 const GPtrDiff_t* bufferStride,
73 const GDALExtendedDataType& bufferDataType,
74 void* pDstBuffer) const override;
75
76 bool IWrite(const GUInt64* arrayStartIdx,
77 const size_t* count,
78 const GInt64* arrayStep,
79 const GPtrDiff_t* bufferStride,
80 const GDALExtendedDataType& bufferDataType,
81 const void* pSrcBuffer) override;
82
IAdviseRead(const GUInt64 * arrayStartIdx,const size_t * count) const83 bool IAdviseRead(const GUInt64* arrayStartIdx,
84 const size_t* count) const override
85 { return m_poParent->AdviseRead(arrayStartIdx, count); }
86
87 public:
Create(const std::shared_ptr<GDALMDArray> & poParent)88 static std::shared_ptr<GDALMDArrayUnscaled> Create(
89 const std::shared_ptr<GDALMDArray>& poParent)
90 {
91 auto newAr(std::shared_ptr<GDALMDArrayUnscaled>(new GDALMDArrayUnscaled(
92 poParent)));
93 newAr->SetSelf(newAr);
94 return newAr;
95 }
96
IsWritable() const97 bool IsWritable() const override { return m_poParent->IsWritable(); }
98
GetDimensions() const99 const std::vector<std::shared_ptr<GDALDimension>>& GetDimensions() const override { return m_poParent->GetDimensions(); }
100
GetDataType() const101 const GDALExtendedDataType &GetDataType() const override { return m_dt; }
102
GetUnit() const103 const std::string& GetUnit() const override { return m_poParent->GetUnit(); }
104
GetSpatialRef() const105 std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override { return m_poParent->GetSpatialRef(); }
106
GetRawNoDataValue() const107 const void* GetRawNoDataValue() const override { return m_bHasNoData ? &m_adfNoData[0] : nullptr; }
108
SetRawNoDataValue(const void * pRawNoData)109 bool SetRawNoDataValue(const void* pRawNoData) override {
110 m_bHasNoData = true; memcpy(m_adfNoData, pRawNoData, m_dt.GetSize()); return true; }
111
GetBlockSize() const112 std::vector<GUInt64> GetBlockSize() const override { return m_poParent->GetBlockSize(); }
113
GetAttribute(const std::string & osName) const114 std::shared_ptr<GDALAttribute> GetAttribute(const std::string& osName) const override
115 { return m_poParent->GetAttribute(osName); }
116
GetAttributes(CSLConstList papszOptions=nullptr) const117 std::vector<std::shared_ptr<GDALAttribute>> GetAttributes(CSLConstList papszOptions = nullptr) const override
118 { return m_poParent->GetAttributes(papszOptions); }
119
SetUnit(const std::string & osUnit)120 bool SetUnit(const std::string& osUnit) override { return m_poParent->SetUnit(osUnit); }
121
SetSpatialRef(const OGRSpatialReference * poSRS)122 bool SetSpatialRef(const OGRSpatialReference* poSRS) override { return m_poParent->SetSpatialRef(poSRS); }
123
CreateAttribute(const std::string & osName,const std::vector<GUInt64> & anDimensions,const GDALExtendedDataType & oDataType,CSLConstList papszOptions=nullptr)124 std::shared_ptr<GDALAttribute> CreateAttribute(
125 const std::string& osName,
126 const std::vector<GUInt64>& anDimensions,
127 const GDALExtendedDataType& oDataType,
128 CSLConstList papszOptions = nullptr) override {return m_poParent->CreateAttribute(osName, anDimensions, oDataType, papszOptions); }
129 };
130
131 /************************************************************************/
132 /* ~GDALIHasAttribute() */
133 /************************************************************************/
134
135 GDALIHasAttribute::~GDALIHasAttribute() = default;
136
137 /************************************************************************/
138 /* GetAttribute() */
139 /************************************************************************/
140
141 /** Return an attribute by its name.
142 *
143 * If the attribute does not exist, nullptr should be silently returned.
144 *
145 * @note Driver implementation: this method will fallback to
146 * GetAttributeFromAttributes() is not explicitly implemented
147 *
148 * Drivers known to implement it for groups and arrays: MEM, netCDF.
149 *
150 * This is the same as the C function GDALGroupGetAttribute() or
151 * GDALMDArrayGetAttribute().
152 *
153 * @param osName Attribute name
154 * @return the attribute, or nullptr if it does not exist or an error occurred.
155 */
GetAttribute(const std::string & osName) const156 std::shared_ptr<GDALAttribute> GDALIHasAttribute::GetAttribute(
157 const std::string& osName) const
158 {
159 return GetAttributeFromAttributes(osName);
160 }
161
162 /************************************************************************/
163 /* GetAttributeFromAttributes() */
164 /************************************************************************/
165
166 /** Possible fallback implementation for GetAttribute() using GetAttributes().
167 */
GetAttributeFromAttributes(const std::string & osName) const168 std::shared_ptr<GDALAttribute> GDALIHasAttribute::GetAttributeFromAttributes(
169 const std::string& osName) const
170 {
171 auto attrs(GetAttributes());
172 for( const auto& attr: attrs )
173 {
174 if( attr->GetName() == osName )
175 return attr;
176 }
177 return nullptr;
178 }
179
180
181 /************************************************************************/
182 /* GetAttributes() */
183 /************************************************************************/
184
185 /** Return the list of attributes contained in a GDALMDArray or GDALGroup.
186 *
187 * If the attribute does not exist, nullptr should be silently returned.
188 *
189 * @note Driver implementation: optionally implemented. If implemented,
190 * GetAttribute() should also be implemented.
191 *
192 * Drivers known to implement it for groups and arrays: MEM, netCDF.
193 *
194 * This is the same as the C function GDALGroupGetAttributes() or
195 * GDALMDArrayGetAttributes().
196
197 * @param papszOptions Driver specific options determining how attributes
198 * should be retrieved. Pass nullptr for default behavior.
199 *
200 * @return the attributes.
201 */
202 std::vector<std::shared_ptr<GDALAttribute>>
GetAttributes(CPL_UNUSED CSLConstList papszOptions) const203 GDALIHasAttribute::GetAttributes(CPL_UNUSED CSLConstList papszOptions) const
204 {
205 return {};
206 }
207
208 /************************************************************************/
209 /* CreateAttribute() */
210 /************************************************************************/
211
212 /** Create an attribute within a GDALMDArray or GDALGroup.
213 *
214 * The attribute might not be "physically" created until a value is written
215 * into it.
216 *
217 * Optionally implemented.
218 *
219 * Drivers known to implement it: MEM, netCDF
220 *
221 * This is the same as the C function GDALGroupCreateAttribute() or
222 * GDALMDArrayCreateAttribute()
223 *
224 * @param osName Attribute name.
225 * @param anDimensions List of dimension sizes, ordered from the slowest varying
226 * dimension first to the fastest varying dimension last.
227 * Empty for a scalar attribute (common case)
228 * @param oDataType Attribute data type.
229 * @param papszOptions Driver specific options determining how the attribute.
230 * should be created.
231 *
232 * @return the new attribute, or nullptr if case of error
233 */
CreateAttribute(CPL_UNUSED const std::string & osName,CPL_UNUSED const std::vector<GUInt64> & anDimensions,CPL_UNUSED const GDALExtendedDataType & oDataType,CPL_UNUSED CSLConstList papszOptions)234 std::shared_ptr<GDALAttribute> GDALIHasAttribute::CreateAttribute(
235 CPL_UNUSED const std::string& osName,
236 CPL_UNUSED const std::vector<GUInt64>& anDimensions,
237 CPL_UNUSED const GDALExtendedDataType& oDataType,
238 CPL_UNUSED CSLConstList papszOptions)
239 {
240 CPLError(CE_Failure, CPLE_NotSupported, "CreateAttribute() not implemented");
241 return nullptr;
242 }
243
244 /************************************************************************/
245 /* GDALGroup() */
246 /************************************************************************/
247
248 //! @cond Doxygen_Suppress
GDALGroup(const std::string & osParentName,const std::string & osName)249 GDALGroup::GDALGroup(const std::string& osParentName, const std::string& osName):
250 m_osName(osParentName.empty() ? "/" : osName),
251 m_osFullName(!osParentName.empty() ? ((osParentName == "/" ? "/" : osParentName + "/") + osName) : "/")
252 {}
253 //! @endcond
254
255 /************************************************************************/
256 /* ~GDALGroup() */
257 /************************************************************************/
258
259 GDALGroup::~GDALGroup() = default;
260
261 /************************************************************************/
262 /* GetMDArrayNames() */
263 /************************************************************************/
264
265 /** Return the list of multidimensional array names contained in this group.
266 *
267 * @note Driver implementation: optionally implemented. If implemented,
268 * OpenMDArray() should also be implemented.
269 *
270 * Drivers known to implement it: MEM, netCDF.
271 *
272 * This is the same as the C function GDALGroupGetMDArrayNames().
273 *
274 * @param papszOptions Driver specific options determining how arrays
275 * should be retrieved. Pass nullptr for default behavior.
276 *
277 * @return the array names.
278 */
279 std::vector<std::string>
GetMDArrayNames(CPL_UNUSED CSLConstList papszOptions) const280 GDALGroup::GetMDArrayNames(CPL_UNUSED CSLConstList papszOptions) const
281 {
282 return {};
283 }
284
285 /************************************************************************/
286 /* OpenMDArray() */
287 /************************************************************************/
288
289 /** Open and return a multidimensional array.
290 *
291 * @note Driver implementation: optionally implemented. If implemented,
292 * GetMDArrayNames() should also be implemented.
293 *
294 * Drivers known to implement it: MEM, netCDF.
295 *
296 * This is the same as the C function GDALGroupOpenMDArray().
297 *
298 * @param osName Array name.
299 * @param papszOptions Driver specific options determining how the array should
300 * be opened. Pass nullptr for default behavior.
301 *
302 * @return the array, or nullptr.
303 */
OpenMDArray(CPL_UNUSED const std::string & osName,CPL_UNUSED CSLConstList papszOptions) const304 std::shared_ptr<GDALMDArray> GDALGroup::OpenMDArray(CPL_UNUSED const std::string& osName,
305 CPL_UNUSED CSLConstList papszOptions) const
306 {
307 return nullptr;
308 }
309
310 /************************************************************************/
311 /* GetGroupNames() */
312 /************************************************************************/
313
314 /** Return the list of sub-groups contained in this group.
315 *
316 * @note Driver implementation: optionally implemented. If implemented,
317 * OpenGroup() should also be implemented.
318 *
319 * Drivers known to implement it: MEM, netCDF.
320 *
321 * This is the same as the C function GDALGroupGetGroupNames().
322 *
323 * @param papszOptions Driver specific options determining how groups
324 * should be retrieved. Pass nullptr for default behavior.
325 *
326 * @return the group names.
327 */
GetGroupNames(CPL_UNUSED CSLConstList papszOptions) const328 std::vector<std::string> GDALGroup::GetGroupNames(CPL_UNUSED CSLConstList papszOptions) const
329 {
330 return {};
331 }
332
333 /************************************************************************/
334 /* OpenGroup() */
335 /************************************************************************/
336
337 /** Open and return a sub-group.
338 *
339 * @note Driver implementation: optionally implemented. If implemented,
340 * GetGroupNames() should also be implemented.
341 *
342 * Drivers known to implement it: MEM, netCDF.
343 *
344 * This is the same as the C function GDALGroupOpenGroup().
345 *
346 * @param osName Sub-group name.
347 * @param papszOptions Driver specific options determining how the sub-group should
348 * be opened. Pass nullptr for default behavior.
349 *
350 * @return the group, or nullptr.
351 */
OpenGroup(CPL_UNUSED const std::string & osName,CPL_UNUSED CSLConstList papszOptions) const352 std::shared_ptr<GDALGroup> GDALGroup::OpenGroup(CPL_UNUSED const std::string& osName,
353 CPL_UNUSED CSLConstList papszOptions) const
354 {
355 return nullptr;
356 }
357
358 /************************************************************************/
359 /* GetDimensions() */
360 /************************************************************************/
361
362 /** Return the list of dimensions contained in this group and used by its
363 * arrays.
364 *
365 * This is for dimensions that can potentially be used by several arrays.
366 * Not all drivers might implement this. To retrieve the dimensions used by
367 * a specific array, use GDALMDArray::GetDimensions().
368 *
369 * Drivers known to implement it: MEM, netCDF
370 *
371 * This is the same as the C function GDALGroupGetDimensions().
372 *
373 * @param papszOptions Driver specific options determining how groups
374 * should be retrieved. Pass nullptr for default behavior.
375 *
376 * @return the dimensions.
377 */
GetDimensions(CPL_UNUSED CSLConstList papszOptions) const378 std::vector<std::shared_ptr<GDALDimension>> GDALGroup::GetDimensions(
379 CPL_UNUSED CSLConstList papszOptions) const
380 {
381 return {};
382 }
383
384 /************************************************************************/
385 /* GetStructuralInfo() */
386 /************************************************************************/
387
388 /** Return structural information on the group.
389 *
390 * This may be the compression, etc..
391 *
392 * The return value should not be freed and is valid until GDALGroup is
393 * released or this function called again.
394 *
395 * This is the same as the C function GDALGroupGetStruturalInfo().
396 */
GetStructuralInfo() const397 CSLConstList GDALGroup::GetStructuralInfo() const
398 {
399 return nullptr;
400 }
401
402 /************************************************************************/
403 /* CreateGroup() */
404 /************************************************************************/
405
406 /** Create a sub-group within a group.
407 *
408 * Optionally implemented by drivers.
409 *
410 * Drivers known to implement it: MEM, netCDF
411 *
412 * This is the same as the C function GDALGroupCreateGroup().
413 *
414 * @param osName Sub-group name.
415 * @param papszOptions Driver specific options determining how the sub-group
416 * should be created.
417 *
418 * @return the new sub-group, or nullptr in case of error.
419 */
CreateGroup(CPL_UNUSED const std::string & osName,CPL_UNUSED CSLConstList papszOptions)420 std::shared_ptr<GDALGroup> GDALGroup::CreateGroup(CPL_UNUSED const std::string& osName,
421 CPL_UNUSED CSLConstList papszOptions)
422 {
423 CPLError(CE_Failure, CPLE_NotSupported, "CreateGroup() not implemented");
424 return nullptr;
425 }
426
427 /************************************************************************/
428 /* CreateDimension() */
429 /************************************************************************/
430
431 /** Create a dimension within a group.
432 *
433 * @note Driver implementation: drivers supporting CreateDimension() should implement
434 * this method, but do not have necessarily to implement GDALGroup::GetDimensions().
435 *
436 * Drivers known to implement it: MEM, netCDF
437 *
438 * This is the same as the C function GDALGroupCreateDimension().
439 *
440 * @param osName Dimension name.
441 * @param osType Dimension type (might be empty, and ignored by drivers)
442 * @param osDirection Dimension direction (might be empty, and ignored by drivers)
443 * @param nSize Number of values indexed by this dimension. Should be > 0.
444 * @param papszOptions Driver specific options determining how the dimension
445 * should be created.
446 *
447 * @return the new dimension, or nullptr if case of error
448 */
CreateDimension(CPL_UNUSED const std::string & osName,CPL_UNUSED const std::string & osType,CPL_UNUSED const std::string & osDirection,CPL_UNUSED GUInt64 nSize,CPL_UNUSED CSLConstList papszOptions)449 std::shared_ptr<GDALDimension> GDALGroup::CreateDimension(CPL_UNUSED const std::string& osName,
450 CPL_UNUSED const std::string& osType,
451 CPL_UNUSED const std::string& osDirection,
452 CPL_UNUSED GUInt64 nSize,
453 CPL_UNUSED CSLConstList papszOptions)
454 {
455 CPLError(CE_Failure, CPLE_NotSupported, "CreateDimension() not implemented");
456 return nullptr;
457 }
458
459 /************************************************************************/
460 /* CreateMDArray() */
461 /************************************************************************/
462
463 /** Create a multidimensional array within a group.
464 *
465 * It is recommended that the GDALDimension objects passed in aoDimensions
466 * belong to this group, either by retrieving them with GetDimensions()
467 * or creating a new one with CreateDimension().
468 *
469 * Optionally implemented.
470 *
471 * Drivers known to implement it: MEM, netCDF
472 *
473 * This is the same as the C function GDALGroupCreateMDArray().
474 *
475 * @note Driver implementation: drivers should take into account the possibility
476 * that GDALDimension object passed in aoDimensions might belong to a different
477 * group / dataset / driver and act accordingly.
478 *
479 * @param osName Array name.
480 * @param aoDimensions List of dimensions, ordered from the slowest varying
481 * dimension first to the fastest varying dimension last.
482 * Might be empty for a scalar array (if supported by driver)
483 * @param oDataType Array data type.
484 * @param papszOptions Driver specific options determining how the array
485 * should be created.
486 *
487 * @return the new array, or nullptr if case of error
488 */
CreateMDArray(CPL_UNUSED const std::string & osName,CPL_UNUSED const std::vector<std::shared_ptr<GDALDimension>> & aoDimensions,CPL_UNUSED const GDALExtendedDataType & oDataType,CPL_UNUSED CSLConstList papszOptions)489 std::shared_ptr<GDALMDArray> GDALGroup::CreateMDArray(
490 CPL_UNUSED const std::string& osName,
491 CPL_UNUSED const std::vector<std::shared_ptr<GDALDimension>>& aoDimensions,
492 CPL_UNUSED const GDALExtendedDataType& oDataType,
493 CPL_UNUSED CSLConstList papszOptions)
494 {
495 CPLError(CE_Failure, CPLE_NotSupported, "CreateMDArray() not implemented");
496 return nullptr;
497 }
498
499 /************************************************************************/
500 /* GetTotalCopyCost() */
501 /************************************************************************/
502
503 /** Return a total "cost" to copy the group.
504 *
505 * Used as a parameter for CopFrom()
506 */
GetTotalCopyCost() const507 GUInt64 GDALGroup::GetTotalCopyCost() const
508 {
509 GUInt64 nCost = COPY_COST;
510 nCost += GetAttributes().size() * GDALAttribute::COPY_COST;
511
512 auto groupNames = GetGroupNames();
513 for( const auto& name: groupNames )
514 {
515 auto subGroup = OpenGroup(name);
516 if( subGroup )
517 {
518 nCost += subGroup->GetTotalCopyCost();
519 }
520 }
521
522 auto arrayNames = GetMDArrayNames();
523 for( const auto& name: arrayNames )
524 {
525 auto array = OpenMDArray(name);
526 if( array )
527 {
528 nCost += array->GetTotalCopyCost();
529 }
530 }
531 return nCost;
532 }
533
534 /************************************************************************/
535 /* CopyFrom() */
536 /************************************************************************/
537
538 /** Copy the content of a group into a new (generally empty) group.
539 *
540 * @param poDstRootGroup Destination root group. Must NOT be nullptr.
541 * @param poSrcDS Source dataset. Might be nullptr (but for correct behavior
542 * of some output drivers this is not recommended)
543 * @param poSrcGroup Source group. Must NOT be nullptr.
544 * @param bStrict Whether to enable stict mode. In strict mode, any error will
545 * stop the copy. In relaxed mode, the copy will be attempted to
546 * be pursued.
547 * @param nCurCost Should be provided as a variable initially set to 0.
548 * @param nTotalCost Total cost from GetTotalCopyCost().
549 * @param pfnProgress Progress callback, or nullptr.
550 * @param pProgressData Progress user data, or nulptr.
551 * @param papszOptions Creation options. Currently, only array creation
552 * options are supported. They must be prefixed with "ARRAY:" .
553 * The scope may be further restricted to arrays of a certain
554 * dimension by adding "IF(DIM={ndims}):" after "ARRAY:".
555 * For example, "ARRAY:IF(DIM=2):BLOCKSIZE=256,256" will
556 * restrict BLOCKSIZE=256,256 to arrays of dimension 2.
557 * Restriction to arrays of a given name is done with adding
558 * "IF(NAME={name}):" after "ARRAY:". {name} can also be
559 * a full qualified name.
560 * A non-driver specific ARRAY option, "AUTOSCALE=YES" can be
561 * used to ask (non indexing) variables of type Float32 or Float64
562 * to be scaled to UInt16 with scale and offset values
563 * being computed from the minimum and maximum of the source array.
564 * The integer data type used can be set with
565 * AUTOSCALE_DATA_TYPE=Byte/UInt16/Int16/UInt32/Int32.
566 *
567 * @return true in case of success (or partial success if bStrict == false).
568 */
CopyFrom(const std::shared_ptr<GDALGroup> & poDstRootGroup,GDALDataset * poSrcDS,const std::shared_ptr<GDALGroup> & poSrcGroup,bool bStrict,GUInt64 & nCurCost,const GUInt64 nTotalCost,GDALProgressFunc pfnProgress,void * pProgressData,CSLConstList papszOptions)569 bool GDALGroup::CopyFrom( const std::shared_ptr<GDALGroup>& poDstRootGroup,
570 GDALDataset* poSrcDS,
571 const std::shared_ptr<GDALGroup>& poSrcGroup,
572 bool bStrict,
573 GUInt64& nCurCost,
574 const GUInt64 nTotalCost,
575 GDALProgressFunc pfnProgress,
576 void * pProgressData,
577 CSLConstList papszOptions )
578 {
579 if( pfnProgress == nullptr )
580 pfnProgress = GDALDummyProgress;
581
582 #define EXIT_OR_CONTINUE_IF_NULL(x) \
583 if( !(x) ) \
584 { \
585 if( bStrict ) \
586 return false; \
587 continue; \
588 } \
589 (void)0
590
591 try
592 {
593 nCurCost += GDALGroup::COPY_COST;
594
595 const auto srcDims = poSrcGroup->GetDimensions();
596 std::map<std::string, std::shared_ptr<GDALDimension>> mapExistingDstDims;
597 std::map<std::string, std::string> mapSrcVariableNameToIndexedDimName;
598 for( const auto& dim: srcDims )
599 {
600 auto dstDim = CreateDimension(dim->GetName(),
601 dim->GetType(),
602 dim->GetDirection(),
603 dim->GetSize());
604 EXIT_OR_CONTINUE_IF_NULL(dstDim);
605 mapExistingDstDims[dim->GetName()] = dstDim;
606 auto poIndexingVarSrc(dim->GetIndexingVariable());
607 if( poIndexingVarSrc )
608 {
609 mapSrcVariableNameToIndexedDimName[poIndexingVarSrc->GetName()] = dim->GetName();
610 }
611 }
612
613 auto attrs = poSrcGroup->GetAttributes();
614 for( const auto& attr: attrs )
615 {
616 auto dstAttr = CreateAttribute(attr->GetName(),
617 attr->GetDimensionsSize(),
618 attr->GetDataType());
619 EXIT_OR_CONTINUE_IF_NULL(dstAttr);
620 auto raw(attr->ReadAsRaw());
621 if( !dstAttr->Write(raw.data(), raw.size()) && bStrict )
622 return false;
623 }
624 if( !attrs.empty() )
625 {
626 nCurCost += attrs.size() * GDALAttribute::COPY_COST;
627 if( !pfnProgress(double(nCurCost) / nTotalCost, "", pProgressData) )
628 return false;
629 }
630
631 auto arrayNames = poSrcGroup->GetMDArrayNames();
632 for( const auto& name: arrayNames )
633 {
634 auto srcArray = poSrcGroup->OpenMDArray(name);
635 EXIT_OR_CONTINUE_IF_NULL(srcArray);
636
637 // Map source dimensions to target dimensions
638 std::vector<std::shared_ptr<GDALDimension>> dstArrayDims;
639 const auto& srcArrayDims(srcArray->GetDimensions());
640 for( const auto& dim : srcArrayDims )
641 {
642 auto dstDim = poDstRootGroup->OpenDimensionFromFullname(
643 dim->GetFullName());
644 if( dstDim && dstDim->GetSize() == dim->GetSize() )
645 {
646 dstArrayDims.emplace_back(dstDim);
647 }
648 else
649 {
650 auto oIter = mapExistingDstDims.find(dim->GetName());
651 if( oIter != mapExistingDstDims.end() &&
652 oIter->second->GetSize() == dim->GetSize() )
653 {
654 dstArrayDims.emplace_back(oIter->second);
655 }
656 else
657 {
658 std::string newDimName;
659 if( oIter == mapExistingDstDims.end() )
660 {
661 newDimName = dim->GetName();
662 }
663 else
664 {
665 std::string newDimNamePrefix(name + '_' + dim->GetName());
666 newDimName = newDimNamePrefix;
667 int nIterCount = 2;
668 while( mapExistingDstDims.find(newDimName) != mapExistingDstDims.end() )
669 {
670 newDimName = newDimNamePrefix + CPLSPrintf("_%d", nIterCount);
671 nIterCount ++;
672 }
673 }
674 dstDim = CreateDimension(newDimName,
675 dim->GetType(),
676 dim->GetDirection(),
677 dim->GetSize());
678 if( !dstDim )
679 return false;
680 mapExistingDstDims[newDimName] = dstDim;
681 dstArrayDims.emplace_back(dstDim);
682 }
683 }
684 }
685
686 CPLStringList aosArrayCO;
687 bool bAutoScale = false;
688 GDALDataType eAutoScaleType = GDT_UInt16;
689 for( CSLConstList papszIter = papszOptions;
690 papszIter && *papszIter; ++papszIter )
691 {
692 if( STARTS_WITH_CI(*papszIter, "ARRAY:") )
693 {
694 const char* pszOption = *papszIter + strlen("ARRAY:");
695 if( STARTS_WITH_CI(pszOption, "IF(DIM=") )
696 {
697 const char* pszNext = strchr(pszOption, ':');
698 if( pszNext != nullptr )
699 {
700 int nDim = atoi(pszOption + strlen("IF(DIM="));
701 if( static_cast<size_t>(nDim) == dstArrayDims.size() )
702 {
703 pszOption = pszNext + 1;
704 }
705 else
706 {
707 pszOption = nullptr;
708 }
709 }
710 }
711 else if( STARTS_WITH_CI(pszOption, "IF(NAME=") )
712 {
713 const char* pszName = pszOption + strlen("IF(NAME=");
714 const char* pszNext = strchr(pszName, ':');
715 if( pszNext != nullptr && pszNext > pszName &&
716 pszNext[-1] == ')' )
717 {
718 CPLString osName;
719 osName.assign(pszName, pszNext - pszName - 1);
720 if( osName == srcArray->GetName() ||
721 osName == srcArray->GetFullName() )
722 {
723 pszOption = pszNext + 1;
724 }
725 else
726 {
727 pszOption = nullptr;
728 }
729 }
730 }
731 if( pszOption )
732 {
733 if( STARTS_WITH_CI(pszOption, "AUTOSCALE=") )
734 {
735 bAutoScale = CPLTestBool(pszOption + strlen("AUTOSCALE="));
736 }
737 else if( STARTS_WITH_CI(pszOption, "AUTOSCALE_DATA_TYPE=") )
738 {
739 const char* pszDataType = pszOption + strlen("AUTOSCALE_DATA_TYPE=");
740 eAutoScaleType = GDALGetDataTypeByName(pszDataType);
741 if( eAutoScaleType != GDT_Byte &&
742 eAutoScaleType != GDT_UInt16 &&
743 eAutoScaleType != GDT_Int16 &&
744 eAutoScaleType != GDT_UInt32 &&
745 eAutoScaleType != GDT_Int32 )
746 {
747 CPLError(CE_Failure, CPLE_NotSupported,
748 "Unsupported value for AUTOSCALE_DATA_TYPE");
749 return false;
750 }
751 }
752 else
753 {
754 aosArrayCO.AddString(pszOption);
755 }
756 }
757 }
758 }
759
760 auto oIterDimName = mapSrcVariableNameToIndexedDimName.find(srcArray->GetName());
761 const auto& srcArrayType = srcArray->GetDataType();
762
763 std::shared_ptr<GDALMDArray> dstArray;
764
765 // Only autoscale non-indexing variables
766 bool bHasOffset = false;
767 bool bHasScale = false;
768 if( bAutoScale &&
769 srcArrayType.GetClass() == GEDTC_NUMERIC &&
770 (srcArrayType.GetNumericDataType() == GDT_Float32 ||
771 srcArrayType.GetNumericDataType() == GDT_Float64 ) &&
772 srcArray->GetOffset(&bHasOffset) == 0.0 &&
773 !bHasOffset &&
774 srcArray->GetScale(&bHasScale) == 1.0 &&
775 !bHasScale &&
776 oIterDimName == mapSrcVariableNameToIndexedDimName.end() )
777 {
778 constexpr bool bApproxOK = false;
779 constexpr bool bForce = true;
780 double dfMin = 0.0;
781 double dfMax = 0.0;
782 if( srcArray->GetStatistics(poSrcDS, bApproxOK, bForce,
783 &dfMin, &dfMax, nullptr, nullptr,
784 nullptr,
785 nullptr, nullptr) != CE_None )
786 {
787 CPLError(CE_Failure, CPLE_AppDefined,
788 "Could not retrieve statistics for array %s",
789 srcArray->GetName().c_str());
790 return false;
791 }
792 double dfDTMin = 0;
793 double dfDTMax = 0;
794 #define setDTMinMax(ctype) do \
795 { dfDTMin = std::numeric_limits<ctype>::min(); dfDTMax = std::numeric_limits<ctype>::max(); } while(0)
796
797 switch( eAutoScaleType )
798 {
799 case GDT_Byte: setDTMinMax(GByte); break;
800 case GDT_UInt16: setDTMinMax(GUInt16); break;
801 case GDT_Int16: setDTMinMax(GInt16); break;
802 case GDT_UInt32: setDTMinMax(GUInt32); break;
803 case GDT_Int32: setDTMinMax(GInt32); break;
804 default:
805 CPLAssert(false);
806 }
807
808 dstArray = CreateMDArray(srcArray->GetName(),
809 dstArrayDims,
810 GDALExtendedDataType::Create(eAutoScaleType),
811 aosArrayCO.List());
812 EXIT_OR_CONTINUE_IF_NULL(dstArray);
813
814 if( srcArray->GetRawNoDataValue() != nullptr )
815 {
816 // If there's a nodata value in the source array, reserve
817 // DTMax for that purpose in the target scaled array
818 if( !dstArray->SetNoDataValue(dfDTMax) )
819 {
820 CPLError(CE_Failure, CPLE_AppDefined,
821 "Cannot set nodata value");
822 return false;
823 }
824 dfDTMax --;
825 }
826 const double dfScale = dfMax > dfMin ?
827 (dfMax - dfMin) / (dfDTMax - dfDTMin) : 1.0;
828 const double dfOffset = dfMin - dfDTMin * dfScale;
829
830 if( !dstArray->SetOffset(dfOffset) ||
831 !dstArray->SetScale(dfScale) )
832 {
833 CPLError(CE_Failure, CPLE_AppDefined,
834 "Cannot set scale/offset");
835 return false;
836 }
837
838 auto poUnscaled = dstArray->GetUnscaled();
839 if( srcArray->GetRawNoDataValue() != nullptr )
840 {
841 poUnscaled->SetNoDataValue(
842 srcArray->GetNoDataValueAsDouble() );
843 }
844
845 // Copy source array into unscaled array
846 if( !poUnscaled->CopyFrom(poSrcDS,
847 srcArray.get(), bStrict,
848 nCurCost, nTotalCost,
849 pfnProgress, pProgressData) )
850 {
851 return false;
852 }
853 }
854 else
855 {
856 dstArray = CreateMDArray(srcArray->GetName(),
857 dstArrayDims,
858 srcArrayType,
859 aosArrayCO.List());
860 EXIT_OR_CONTINUE_IF_NULL(dstArray);
861
862 if( !dstArray->CopyFrom(poSrcDS,
863 srcArray.get(), bStrict,
864 nCurCost, nTotalCost,
865 pfnProgress, pProgressData) )
866 {
867 return false;
868 }
869 }
870
871 // If this array is the indexing variable of a dimension, link them
872 // together.
873 if( oIterDimName != mapSrcVariableNameToIndexedDimName.end() )
874 {
875 auto oCorrespondingDimIter = mapExistingDstDims.find(oIterDimName->second);
876 if( oCorrespondingDimIter != mapExistingDstDims.end() )
877 {
878 CPLErrorHandlerPusher oHandlerPusher(CPLQuietErrorHandler);
879 CPLErrorStateBackuper oErrorStateBackuper;
880 oCorrespondingDimIter->second->SetIndexingVariable(dstArray);
881 }
882 }
883 }
884
885 auto groupNames = poSrcGroup->GetGroupNames();
886 for( const auto& name: groupNames )
887 {
888 auto srcSubGroup = poSrcGroup->OpenGroup(name);
889 EXIT_OR_CONTINUE_IF_NULL(srcSubGroup);
890 auto dstSubGroup = CreateGroup(name);
891 EXIT_OR_CONTINUE_IF_NULL(dstSubGroup);
892 if( !dstSubGroup->CopyFrom(poDstRootGroup, poSrcDS,
893 srcSubGroup, bStrict,
894 nCurCost, nTotalCost,
895 pfnProgress, pProgressData,
896 papszOptions) )
897 return false;
898 }
899
900 if( !pfnProgress(double(nCurCost) / nTotalCost, "", pProgressData) )
901 return false;
902
903 return true;
904 }
905 catch( const std::exception& e )
906 {
907 CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
908 return false;
909 }
910 }
911
912 /************************************************************************/
913 /* GetInnerMostGroup() */
914 /************************************************************************/
915
916 //! @cond Doxygen_Suppress
GetInnerMostGroup(const std::string & osPathOrArrayOrDim,std::shared_ptr<GDALGroup> & curGroupHolder,std::string & osLastPart) const917 const GDALGroup* GDALGroup::GetInnerMostGroup(
918 const std::string& osPathOrArrayOrDim,
919 std::shared_ptr<GDALGroup>& curGroupHolder,
920 std::string& osLastPart) const
921 {
922 if( osPathOrArrayOrDim.empty() || osPathOrArrayOrDim[0] != '/' )
923 return nullptr;
924 const GDALGroup* poCurGroup = this;
925 CPLStringList aosTokens(CSLTokenizeString2(
926 osPathOrArrayOrDim.c_str(), "/", 0));
927 if( aosTokens.size() == 0 )
928 {
929 return nullptr;
930 }
931
932 for( int i = 0; i < aosTokens.size() - 1; i++ )
933 {
934 curGroupHolder = poCurGroup->OpenGroup(aosTokens[i], nullptr);
935 if( !curGroupHolder )
936 {
937 CPLError(CE_Failure, CPLE_AppDefined,
938 "Cannot find group %s", aosTokens[i]);
939 return nullptr;
940 }
941 poCurGroup = curGroupHolder.get();
942 }
943 osLastPart = aosTokens[aosTokens.size()-1];
944 return poCurGroup;
945 }
946 //! @endcond
947
948 /************************************************************************/
949 /* OpenMDArrayFromFullname() */
950 /************************************************************************/
951
952 /** Get an array from its fully qualified name */
OpenMDArrayFromFullname(const std::string & osFullName,CSLConstList papszOptions) const953 std::shared_ptr<GDALMDArray> GDALGroup::OpenMDArrayFromFullname(
954 const std::string& osFullName,
955 CSLConstList papszOptions) const
956 {
957 std::string osName;
958 std::shared_ptr<GDALGroup> curGroupHolder;
959 auto poGroup(GetInnerMostGroup(osFullName, curGroupHolder, osName));
960 if( poGroup == nullptr )
961 return nullptr;
962 return poGroup->OpenMDArray(osName, papszOptions);
963 }
964
965 /************************************************************************/
966 /* ResolveMDArray() */
967 /************************************************************************/
968
969 /** Locate an array in a group and its subgroups by name.
970 *
971 * If osName is a fully qualified name, then OpenMDArrayFromFullname() is first
972 * used
973 * Otherwise the search will start from the group identified by osStartingPath,
974 * and an array whose name is osName will be looked for in this group (if
975 * osStartingPath is empty or "/", then the current group is used). If there
976 * is no match, then a recursive descendent search will be made in its subgroups.
977 * If there is no match in the subgroups, then the parent (if existing) of the
978 * group pointed by osStartingPath will be used as the new starting point for the
979 * search.
980 *
981 * @param osName name, qualified or not
982 * @param osStartingPath fully qualified name of the (sub-)group from which
983 * the search should be started. If this is a non-empty
984 * string, the group on which this method is called should
985 * nominally be the root group (otherwise the path will
986 * be interpreted as from the current group)
987 * @param papszOptions options to pass to OpenMDArray()
988 * @since GDAL 3.2
989 */
ResolveMDArray(const std::string & osName,const std::string & osStartingPath,CSLConstList papszOptions) const990 std::shared_ptr<GDALMDArray> GDALGroup::ResolveMDArray(
991 const std::string& osName,
992 const std::string& osStartingPath,
993 CSLConstList papszOptions) const
994 {
995 if( !osName.empty() && osName[0] == '/' )
996 {
997 auto poArray = OpenMDArrayFromFullname(osName, papszOptions);
998 if( poArray )
999 return poArray;
1000 }
1001 std::string osPath(osStartingPath);
1002 std::set<std::string> oSetAlreadyVisited;
1003
1004 while(true)
1005 {
1006 std::shared_ptr<GDALGroup> curGroupHolder;
1007 std::shared_ptr<GDALGroup> poGroup;
1008
1009 std::queue<std::shared_ptr<GDALGroup>> oQueue;
1010 bool goOn = false;
1011 if( osPath.empty() || osPath == "/" )
1012 {
1013 goOn = true;
1014 }
1015 else
1016 {
1017 std::string osLastPart;
1018 const GDALGroup* poGroupPtr = GetInnerMostGroup(osPath, curGroupHolder, osLastPart);
1019 if( poGroupPtr )
1020 poGroup = poGroupPtr->OpenGroup(osLastPart);
1021 if( poGroup &&
1022 oSetAlreadyVisited.find(poGroup->GetFullName()) ==
1023 oSetAlreadyVisited.end() )
1024 {
1025 oQueue.push(poGroup);
1026 goOn = true;
1027 }
1028 }
1029
1030 if( goOn )
1031 {
1032 do
1033 {
1034 const GDALGroup* groupPtr;
1035 if( !oQueue.empty() )
1036 {
1037 poGroup = oQueue.front();
1038 oQueue.pop();
1039 groupPtr = poGroup.get();
1040 }
1041 else
1042 {
1043 groupPtr = this;
1044 }
1045
1046 auto poArray = groupPtr->OpenMDArray(osName, papszOptions);
1047 if( poArray )
1048 return poArray;
1049
1050 const auto aosGroupNames = groupPtr->GetGroupNames();
1051 for( const auto& osGroupName : aosGroupNames )
1052 {
1053 auto poSubGroup = groupPtr->OpenGroup(osGroupName);
1054 if( poSubGroup &&
1055 oSetAlreadyVisited.find(poSubGroup->GetFullName()) ==
1056 oSetAlreadyVisited.end() )
1057 {
1058 oQueue.push(poSubGroup);
1059 oSetAlreadyVisited.insert(poSubGroup->GetFullName());
1060 }
1061 }
1062 }
1063 while( !oQueue.empty() );
1064 }
1065
1066 if( osPath.empty() || osPath == "/" )
1067 break;
1068
1069 const auto nPos = osPath.rfind('/');
1070 if( nPos == 0 )
1071 osPath = "/";
1072 else
1073 {
1074 if( nPos == std::string::npos )
1075 break;
1076 osPath.resize(nPos);
1077 }
1078 }
1079 return nullptr;
1080 }
1081
1082 /************************************************************************/
1083 /* OpenGroupFromFullname() */
1084 /************************************************************************/
1085
1086 /** Get a group from its fully qualified name.
1087 * @since GDAL 3.2
1088 */
OpenGroupFromFullname(const std::string & osFullName,CSLConstList papszOptions) const1089 std::shared_ptr<GDALGroup> GDALGroup::OpenGroupFromFullname(
1090 const std::string& osFullName,
1091 CSLConstList papszOptions) const
1092 {
1093 std::string osName;
1094 std::shared_ptr<GDALGroup> curGroupHolder;
1095 auto poGroup(GetInnerMostGroup(osFullName, curGroupHolder, osName));
1096 if( poGroup == nullptr )
1097 return nullptr;
1098 return poGroup->OpenGroup(osName, papszOptions);
1099 }
1100
1101 /************************************************************************/
1102 /* OpenDimensionFromFullname() */
1103 /************************************************************************/
1104
1105 /** Get a dimension from its fully qualified name */
OpenDimensionFromFullname(const std::string & osFullName) const1106 std::shared_ptr<GDALDimension> GDALGroup::OpenDimensionFromFullname(
1107 const std::string& osFullName) const
1108 {
1109 std::string osName;
1110 std::shared_ptr<GDALGroup> curGroupHolder;
1111 auto poGroup(GetInnerMostGroup(osFullName, curGroupHolder, osName));
1112 if( poGroup == nullptr )
1113 return nullptr;
1114 auto dims(poGroup->GetDimensions());
1115 for( auto& dim: dims )
1116 {
1117 if( dim->GetName() == osName )
1118 return dim;
1119 }
1120 return nullptr;
1121 }
1122
1123 /************************************************************************/
1124 /* ~GDALAbstractMDArray() */
1125 /************************************************************************/
1126
1127 GDALAbstractMDArray::~GDALAbstractMDArray() = default;
1128
1129 /************************************************************************/
1130 /* GDALAbstractMDArray() */
1131 /************************************************************************/
1132
1133 //! @cond Doxygen_Suppress
GDALAbstractMDArray(const std::string & osParentName,const std::string & osName)1134 GDALAbstractMDArray::GDALAbstractMDArray(const std::string& osParentName,
1135 const std::string& osName):
1136 m_osName(osName),
1137 m_osFullName(!osParentName.empty() ? ((osParentName == "/" ? "/" : osParentName + "/") + osName) : osName)
1138 {}
1139 //! @endcond
1140
1141 /************************************************************************/
1142 /* GetDimensions() */
1143 /************************************************************************/
1144
1145 /** \fn GDALAbstractMDArray::GetDimensions() const
1146 * \brief Return the dimensions of an attribute/array.
1147 *
1148 * This is the same as the C functions GDALMDArrayGetDimensions() and
1149 * similar to GDALAttributeGetDimensionsSize().
1150 */
1151
1152 /************************************************************************/
1153 /* GetDataType() */
1154 /************************************************************************/
1155
1156 /** \fn GDALAbstractMDArray::GetDataType() const
1157 * \brief Return the data type of an attribute/array.
1158 *
1159 * This is the same as the C functions GDALMDArrayGetDataType() and
1160 * GDALAttributeGetDataType()
1161 */
1162
1163 /************************************************************************/
1164 /* GetDimensionCount() */
1165 /************************************************************************/
1166
1167 /** Return the number of dimensions.
1168 *
1169 * Default implementation is GetDimensions().size(), and may be overridden by
1170 * drivers if they have a faster / less expensive implementations.
1171 *
1172 * This is the same as the C function GDALMDArrayGetDimensionCount() or
1173 * GDALAttributeGetDimensionCount().
1174 *
1175 */
GetDimensionCount() const1176 size_t GDALAbstractMDArray::GetDimensionCount() const
1177 {
1178 return GetDimensions().size();
1179 }
1180
1181 /************************************************************************/
1182 /* CopyValue() */
1183 /************************************************************************/
1184
1185 /** Convert a value from a source type to a destination type.
1186 *
1187 * If dstType is GEDTC_STRING, the written value will be a pointer to a char*,
1188 * that must be freed with CPLFree().
1189 */
CopyValue(const void * pSrc,const GDALExtendedDataType & srcType,void * pDst,const GDALExtendedDataType & dstType)1190 bool GDALExtendedDataType::CopyValue(const void* pSrc,
1191 const GDALExtendedDataType& srcType,
1192 void* pDst,
1193 const GDALExtendedDataType& dstType)
1194 {
1195 if( srcType.GetClass() == GEDTC_NUMERIC &&
1196 dstType.GetClass() == GEDTC_NUMERIC )
1197 {
1198 GDALCopyWords( pSrc, srcType.GetNumericDataType(), 0,
1199 pDst, dstType.GetNumericDataType(), 0,
1200 1 );
1201 return true;
1202 }
1203 if( srcType.GetClass() == GEDTC_STRING &&
1204 dstType.GetClass() == GEDTC_STRING )
1205 {
1206 const char* srcStrPtr;
1207 memcpy(&srcStrPtr, pSrc, sizeof(const char*));
1208 char* pszDup = srcStrPtr ? CPLStrdup(srcStrPtr) : nullptr;
1209 memcpy(pDst, &pszDup, sizeof(char*));
1210 return true;
1211 }
1212 if( srcType.GetClass() == GEDTC_NUMERIC &&
1213 dstType.GetClass() == GEDTC_STRING )
1214 {
1215 const char* str = nullptr;
1216 switch(srcType.GetNumericDataType())
1217 {
1218 case GDT_Unknown: break;
1219 case GDT_Byte:
1220 str = CPLSPrintf("%d", *static_cast<const GByte*>(pSrc));
1221 break;
1222 case GDT_UInt16:
1223 str = CPLSPrintf("%d", *static_cast<const GUInt16*>(pSrc));
1224 break;
1225 case GDT_Int16:
1226 str = CPLSPrintf("%d", *static_cast<const GInt16*>(pSrc));
1227 break;
1228 case GDT_UInt32:
1229 str = CPLSPrintf("%u", *static_cast<const GUInt32*>(pSrc));
1230 break;
1231 case GDT_Int32:
1232 str = CPLSPrintf("%d", *static_cast<const GInt32*>(pSrc));
1233 break;
1234 case GDT_Float32:
1235 str = CPLSPrintf("%.9g", *static_cast<const float*>(pSrc));
1236 break;
1237 case GDT_Float64:
1238 str = CPLSPrintf("%.18g", *static_cast<const double*>(pSrc));
1239 break;
1240 case GDT_CInt16:
1241 {
1242 const GInt16* src = static_cast<const GInt16*>(pSrc);
1243 str = CPLSPrintf("%d+%dj", src[0], src[1]);
1244 break;
1245 }
1246 case GDT_CInt32:
1247 {
1248 const GInt32* src = static_cast<const GInt32*>(pSrc);
1249 str = CPLSPrintf("%d+%dj", src[0], src[1]);
1250 break;
1251 }
1252 case GDT_CFloat32:
1253 {
1254 const float* src = static_cast<const float*>(pSrc);
1255 str = CPLSPrintf("%.9g+%.9gj", src[0], src[1]);
1256 break;
1257 }
1258 case GDT_CFloat64:
1259 {
1260 const double* src = static_cast<const double*>(pSrc);
1261 str = CPLSPrintf("%.18g+%.18gj", src[0], src[1]);
1262 break;
1263 }
1264 case GDT_TypeCount:
1265 CPLAssert(false);
1266 break;
1267 }
1268 char* pszDup = str ? CPLStrdup(str) : nullptr;
1269 memcpy(pDst, &pszDup, sizeof(char*));
1270 return true;
1271 }
1272 if( srcType.GetClass() == GEDTC_STRING &&
1273 dstType.GetClass() == GEDTC_NUMERIC )
1274 {
1275 const char* srcStrPtr;
1276 memcpy(&srcStrPtr, pSrc, sizeof(const char*));
1277 const double dfVal = srcStrPtr == nullptr ? 0 : CPLAtof(srcStrPtr);
1278 GDALCopyWords( &dfVal, GDT_Float64, 0,
1279 pDst, dstType.GetNumericDataType(), 0,
1280 1 );
1281 return true;
1282 }
1283 if( srcType.GetClass() == GEDTC_COMPOUND &&
1284 dstType.GetClass() == GEDTC_COMPOUND )
1285 {
1286 const auto& srcComponents = srcType.GetComponents();
1287 const auto& dstComponents = dstType.GetComponents();
1288 const GByte* pabySrc = static_cast<const GByte*>(pSrc);
1289 GByte* pabyDst = static_cast<GByte*>(pDst);
1290
1291 std::map<std::string, const std::unique_ptr<GDALEDTComponent>*> srcComponentMap;
1292 for( const auto& srcComp: srcComponents )
1293 {
1294 srcComponentMap[srcComp->GetName()] = &srcComp;
1295 }
1296 for( const auto& dstComp: dstComponents )
1297 {
1298 auto oIter = srcComponentMap.find(dstComp->GetName());
1299 if( oIter == srcComponentMap.end() )
1300 return false;
1301 const auto& srcComp = *(oIter->second);
1302 if( !GDALExtendedDataType::CopyValue(pabySrc + srcComp->GetOffset(),
1303 srcComp->GetType(),
1304 pabyDst + dstComp->GetOffset(),
1305 dstComp->GetType()) )
1306 {
1307 return false;
1308 };
1309 }
1310 return true;
1311 }
1312
1313 return false;
1314 }
1315
1316 /************************************************************************/
1317 /* CheckReadWriteParams() */
1318 /************************************************************************/
1319 //! @cond Doxygen_Suppress
CheckReadWriteParams(const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * & arrayStep,const GPtrDiff_t * & bufferStride,const GDALExtendedDataType & bufferDataType,const void * buffer,const void * buffer_alloc_start,size_t buffer_alloc_size,std::vector<GInt64> & tmp_arrayStep,std::vector<GPtrDiff_t> & tmp_bufferStride) const1320 bool GDALAbstractMDArray::CheckReadWriteParams(const GUInt64* arrayStartIdx,
1321 const size_t* count,
1322 const GInt64*& arrayStep,
1323 const GPtrDiff_t*& bufferStride,
1324 const GDALExtendedDataType& bufferDataType,
1325 const void* buffer,
1326 const void* buffer_alloc_start,
1327 size_t buffer_alloc_size,
1328 std::vector<GInt64>& tmp_arrayStep,
1329 std::vector<GPtrDiff_t>& tmp_bufferStride) const
1330 {
1331 const auto lamda_error = []() {
1332 CPLError(CE_Failure, CPLE_AppDefined,
1333 "Not all elements pointed by buffer will fit in "
1334 "[buffer_alloc_start, "
1335 "buffer_alloc_start + buffer_alloc_size[");
1336 };
1337
1338 const auto& dims = GetDimensions();
1339 if( dims.empty() )
1340 {
1341 if( buffer_alloc_start )
1342 {
1343 const size_t elementSize = bufferDataType.GetSize();
1344 const GByte* paby_buffer = static_cast<const GByte*>(buffer);
1345 const GByte* paby_buffer_alloc_start =
1346 static_cast<const GByte*>(buffer_alloc_start);
1347 const GByte* paby_buffer_alloc_end =
1348 paby_buffer_alloc_start + buffer_alloc_size;
1349
1350 if( paby_buffer < paby_buffer_alloc_start ||
1351 paby_buffer + elementSize > paby_buffer_alloc_end )
1352 {
1353 lamda_error();
1354 return false;
1355 }
1356 }
1357 return true;
1358 }
1359
1360 if( arrayStep == nullptr )
1361 {
1362 tmp_arrayStep.resize(dims.size(), 1);
1363 arrayStep = tmp_arrayStep.data();
1364 }
1365 for( size_t i = 0; i < dims.size(); i++ )
1366 {
1367 if( count[i] == 0 )
1368 {
1369 CPLError(CE_Failure, CPLE_AppDefined,
1370 "count[%u] = 0 is invalid",
1371 static_cast<unsigned>(i));
1372 return false;
1373 }
1374 }
1375 bool bufferStride_all_positive = true;
1376 if( bufferStride == nullptr )
1377 {
1378 GPtrDiff_t stride = 1;
1379 // To compute strides we must proceed from the fastest varying dimension
1380 // (the last one), and then reverse the result
1381 for( size_t i = dims.size(); i != 0; )
1382 {
1383 --i;
1384 tmp_bufferStride.push_back(stride);
1385 GUInt64 newStride = 0;
1386 bool bOK;
1387 try
1388 {
1389 newStride = (CPLSM(static_cast<GUInt64>(stride)) *
1390 CPLSM(static_cast<GUInt64>(count[i]))).v();
1391 bOK = static_cast<size_t>(newStride) == newStride &&
1392 newStride < std::numeric_limits<size_t>::max() / 2;
1393 }
1394 catch( ... )
1395 {
1396 bOK = false;
1397 }
1398 if( !bOK )
1399 {
1400 CPLError(CE_Failure, CPLE_OutOfMemory, "Too big count values");
1401 return false;
1402 }
1403 stride = static_cast<GPtrDiff_t>(newStride);
1404 }
1405 std::reverse(tmp_bufferStride.begin(), tmp_bufferStride.end());
1406 bufferStride = tmp_bufferStride.data();
1407 }
1408 else
1409 {
1410 for( size_t i = 0; i < dims.size(); i++ )
1411 {
1412 if( bufferStride[i] < 0 )
1413 {
1414 bufferStride_all_positive = false;
1415 break;
1416 }
1417 }
1418 }
1419 for( size_t i = 0; i < dims.size(); i++ )
1420 {
1421 if( arrayStartIdx[i] >= dims[i]->GetSize() )
1422 {
1423 CPLError(CE_Failure, CPLE_AppDefined,
1424 "arrayStartIdx[%u] = " CPL_FRMT_GUIB " >= " CPL_FRMT_GUIB,
1425 static_cast<unsigned>(i),
1426 static_cast<GUInt64>(arrayStartIdx[i]),
1427 static_cast<GUInt64>(dims[i]->GetSize()));
1428 return false;
1429 }
1430 bool bOverflow;
1431 if( arrayStep[i] >= 0)
1432 {
1433 try
1434 {
1435 bOverflow = (CPLSM(static_cast<GUInt64>(arrayStartIdx[i])) +
1436 CPLSM(static_cast<GUInt64>(count[i] - 1)) *
1437 CPLSM(static_cast<GUInt64>(arrayStep[i]))).v() >= dims[i]->GetSize();
1438 }
1439 catch( ... )
1440 {
1441 bOverflow = true;
1442 }
1443 if( bOverflow )
1444 {
1445 CPLError(CE_Failure, CPLE_AppDefined,
1446 "arrayStartIdx[%u] + (count[%u]-1) * arrayStep[%u] >= " CPL_FRMT_GUIB,
1447 static_cast<unsigned>(i),
1448 static_cast<unsigned>(i),
1449 static_cast<unsigned>(i),
1450 static_cast<GUInt64>(dims[i]->GetSize()));
1451 return false;
1452 }
1453 }
1454 else
1455 {
1456 try
1457 {
1458 bOverflow = arrayStartIdx[i] <
1459 (CPLSM(static_cast<GUInt64>(count[i] - 1)) *
1460 CPLSM(arrayStep[i] == std::numeric_limits<GInt64>::min() ?
1461 (static_cast<GUInt64>(1) << 63) :
1462 static_cast<GUInt64>(-arrayStep[i]))).v();
1463 }
1464 catch( ... )
1465 {
1466 bOverflow = true;
1467 }
1468 if( bOverflow )
1469 {
1470 CPLError(CE_Failure, CPLE_AppDefined,
1471 "arrayStartIdx[%u] + (count[%u]-1) * arrayStep[%u] < 0",
1472 static_cast<unsigned>(i),
1473 static_cast<unsigned>(i),
1474 static_cast<unsigned>(i));
1475 return false;
1476 }
1477 }
1478 }
1479
1480 if( buffer_alloc_start )
1481 {
1482 const size_t elementSize = bufferDataType.GetSize();
1483 const GByte* paby_buffer = static_cast<const GByte*>(buffer);
1484 const GByte* paby_buffer_alloc_start = static_cast<const GByte*>(buffer_alloc_start);
1485 const GByte* paby_buffer_alloc_end = paby_buffer_alloc_start + buffer_alloc_size;
1486 if( bufferStride_all_positive )
1487 {
1488 if( paby_buffer < paby_buffer_alloc_start )
1489 {
1490 lamda_error();
1491 return false;
1492 }
1493 GUInt64 nOffset = elementSize;
1494 for( size_t i = 0; i < dims.size(); i++ )
1495 {
1496 try
1497 {
1498 nOffset = (CPLSM(static_cast<GUInt64>(nOffset)) +
1499 CPLSM(static_cast<GUInt64>(bufferStride[i])) *
1500 CPLSM(static_cast<GUInt64>(count[i] - 1)) *
1501 CPLSM(static_cast<GUInt64>(elementSize))).v();
1502 }
1503 catch( ... )
1504 {
1505 lamda_error();
1506 return false;
1507 }
1508 }
1509 #if SIZEOF_VOID == 4
1510 if( static_cast<size_t>(nOffset) != nOffset )
1511 {
1512 lamda_error();
1513 return false;
1514 }
1515 #endif
1516 if( paby_buffer + nOffset > paby_buffer_alloc_end )
1517 {
1518 lamda_error();
1519 return false;
1520 }
1521 }
1522 else if( dims.size() < 31 )
1523 {
1524 // Check all corners of the hypercube
1525 const unsigned nLoops = 1U << static_cast<unsigned>(dims.size());
1526 for( unsigned iCornerCode = 0; iCornerCode < nLoops; iCornerCode++ )
1527 {
1528 const GByte* paby = paby_buffer;
1529 for( unsigned i = 0; i < static_cast<unsigned>(dims.size()); i++ )
1530 {
1531 if( iCornerCode & (1U << i) )
1532 {
1533 // We should check for integer overflows
1534 paby += bufferStride[i] * (count[i] - 1) * elementSize;
1535 }
1536 }
1537 if( paby < paby_buffer_alloc_start ||
1538 paby + elementSize > paby_buffer_alloc_end )
1539 {
1540 lamda_error();
1541 return false;
1542 }
1543 }
1544 }
1545 }
1546
1547 return true;
1548 }
1549 //! @endcond
1550
1551 /************************************************************************/
1552 /* Read() */
1553 /************************************************************************/
1554
1555 /** Read part or totality of a multidimensional array or attribute.
1556 *
1557 * This will extract the content of a hyper-rectangle from the array into
1558 * a user supplied buffer.
1559 *
1560 * If bufferDataType is of type string, the values written in pDstBuffer
1561 * will be char* pointers and the strings should be freed with CPLFree().
1562 *
1563 * This is the same as the C function GDALMDArrayRead().
1564 *
1565 * @param arrayStartIdx Values representing the starting index to read
1566 * in each dimension (in [0, aoDims[i].GetSize()-1] range).
1567 * Array of GetDimensionCount() values. Must not be
1568 * nullptr, unless for a zero-dimensional array.
1569 *
1570 * @param count Values representing the number of values to extract in
1571 * each dimension.
1572 * Array of GetDimensionCount() values. Must not be
1573 * nullptr, unless for a zero-dimensional array.
1574 *
1575 * @param arrayStep Spacing between values to extract in each dimension.
1576 * The spacing is in number of array elements, not bytes.
1577 * If provided, must contain GetDimensionCount() values.
1578 * If set to nullptr, [1, 1, ... 1] will be used as a default
1579 * to indicate consecutive elements.
1580 *
1581 * @param bufferStride Spacing between values to store in pDstBuffer.
1582 * The spacing is in number of array elements, not bytes.
1583 * If provided, must contain GetDimensionCount() values.
1584 * Negative values are possible (for example to reorder
1585 * from bottom-to-top to top-to-bottom).
1586 * If set to nullptr, will be set so that pDstBuffer is
1587 * written in a compact way, with elements of the last /
1588 * fastest varying dimension being consecutive.
1589 *
1590 * @param bufferDataType Data type of values in pDstBuffer.
1591 *
1592 * @param pDstBuffer User buffer to store the values read. Should be big
1593 * enough to store the number of values indicated by count[] and
1594 * with the spacing of bufferStride[].
1595 *
1596 * @param pDstBufferAllocStart Optional pointer that can be used to validate the
1597 * validty of pDstBuffer. pDstBufferAllocStart should
1598 * be the pointer returned by the malloc() or equivalent
1599 * call used to allocate the buffer. It will generally
1600 * be equal to pDstBuffer (when bufferStride[] values are
1601 * all positive), but not necessarily.
1602 * If specified, nDstBufferAllocSize should be also
1603 * set to the appropriate value.
1604 * If no validation is needed, nullptr can be passed.
1605 *
1606 * @param nDstBufferAllocSize Optional buffer size, that can be used to validate the
1607 * validty of pDstBuffer. This is the size of the
1608 * buffer starting at pDstBufferAllocStart.
1609 * If specified, pDstBufferAllocStart should be also
1610 * set to the appropriate value.
1611 * If no validation is needed, 0 can be passed.
1612 *
1613 * @return true in case of success.
1614 */
Read(const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride,const GDALExtendedDataType & bufferDataType,void * pDstBuffer,const void * pDstBufferAllocStart,size_t nDstBufferAllocSize) const1615 bool GDALAbstractMDArray::Read(const GUInt64* arrayStartIdx,
1616 const size_t* count,
1617 const GInt64* arrayStep, // step in elements
1618 const GPtrDiff_t* bufferStride, // stride in elements
1619 const GDALExtendedDataType& bufferDataType,
1620 void* pDstBuffer,
1621 const void* pDstBufferAllocStart,
1622 size_t nDstBufferAllocSize) const
1623 {
1624 if( !GetDataType().CanConvertTo(bufferDataType) )
1625 {
1626 CPLError(CE_Failure, CPLE_AppDefined,
1627 "Array data type is not convertible to buffer data type");
1628 return false;
1629 }
1630
1631 std::vector<GInt64> tmp_arrayStep;
1632 std::vector<GPtrDiff_t> tmp_bufferStride;
1633 if( !CheckReadWriteParams(arrayStartIdx,
1634 count,
1635 arrayStep,
1636 bufferStride,
1637 bufferDataType,
1638 pDstBuffer,
1639 pDstBufferAllocStart,
1640 nDstBufferAllocSize,
1641 tmp_arrayStep,
1642 tmp_bufferStride) )
1643 {
1644 return false;
1645 }
1646
1647 return IRead(arrayStartIdx, count, arrayStep,
1648 bufferStride, bufferDataType, pDstBuffer);
1649 }
1650
1651 /************************************************************************/
1652 /* IWrite() */
1653 /************************************************************************/
1654
1655 //! @cond Doxygen_Suppress
IWrite(const GUInt64 *,const size_t *,const GInt64 *,const GPtrDiff_t *,const GDALExtendedDataType &,const void *)1656 bool GDALAbstractMDArray::IWrite(const GUInt64*,
1657 const size_t*,
1658 const GInt64*,
1659 const GPtrDiff_t*,
1660 const GDALExtendedDataType&,
1661 const void*)
1662 {
1663 CPLError(CE_Failure, CPLE_AppDefined, "IWrite() not implemented");
1664 return false;
1665 }
1666 //! @endcond
1667
1668 /************************************************************************/
1669 /* Write() */
1670 /************************************************************************/
1671
1672 /** Write part or totality of a multidimensional array or attribute.
1673 *
1674 * This will set the content of a hyper-rectangle into the array from
1675 * a user supplied buffer.
1676 *
1677 * If bufferDataType is of type string, the values read from pSrcBuffer
1678 * will be char* pointers.
1679 *
1680 * This is the same as the C function GDALMDArrayWrite().
1681 *
1682 * @param arrayStartIdx Values representing the starting index to write
1683 * in each dimension (in [0, aoDims[i].GetSize()-1] range).
1684 * Array of GetDimensionCount() values. Must not be
1685 * nullptr, unless for a zero-dimensional array.
1686 *
1687 * @param count Values representing the number of values to write in
1688 * each dimension.
1689 * Array of GetDimensionCount() values. Must not be
1690 * nullptr, unless for a zero-dimensional array.
1691 *
1692 * @param arrayStep Spacing between values to write in each dimension.
1693 * The spacing is in number of array elements, not bytes.
1694 * If provided, must contain GetDimensionCount() values.
1695 * If set to nullptr, [1, 1, ... 1] will be used as a default
1696 * to indicate consecutive elements.
1697 *
1698 * @param bufferStride Spacing between values to read from pSrcBuffer.
1699 * The spacing is in number of array elements, not bytes.
1700 * If provided, must contain GetDimensionCount() values.
1701 * Negative values are possible (for example to reorder
1702 * from bottom-to-top to top-to-bottom).
1703 * If set to nullptr, will be set so that pSrcBuffer is
1704 * written in a compact way, with elements of the last /
1705 * fastest varying dimension being consecutive.
1706 *
1707 * @param bufferDataType Data type of values in pSrcBuffer.
1708 *
1709 * @param pSrcBuffer User buffer to read the values from. Should be big
1710 * enough to store the number of values indicated by count[] and
1711 * with the spacing of bufferStride[].
1712 *
1713 * @param pSrcBufferAllocStart Optional pointer that can be used to validate the
1714 * validty of pSrcBuffer. pSrcBufferAllocStart should
1715 * be the pointer returned by the malloc() or equivalent
1716 * call used to allocate the buffer. It will generally
1717 * be equal to pSrcBuffer (when bufferStride[] values are
1718 * all positive), but not necessarily.
1719 * If specified, nSrcBufferAllocSize should be also
1720 * set to the appropriate value.
1721 * If no validation is needed, nullptr can be passed.
1722 *
1723 * @param nSrcBufferAllocSize Optional buffer size, that can be used to validate the
1724 * validty of pSrcBuffer. This is the size of the
1725 * buffer starting at pSrcBufferAllocStart.
1726 * If specified, pDstBufferAllocStart should be also
1727 * set to the appropriate value.
1728 * If no validation is needed, 0 can be passed.
1729 *
1730 * @return true in case of success.
1731 */
Write(const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride,const GDALExtendedDataType & bufferDataType,const void * pSrcBuffer,const void * pSrcBufferAllocStart,size_t nSrcBufferAllocSize)1732 bool GDALAbstractMDArray::Write(const GUInt64* arrayStartIdx,
1733 const size_t* count,
1734 const GInt64* arrayStep,
1735 const GPtrDiff_t* bufferStride,
1736 const GDALExtendedDataType& bufferDataType,
1737 const void* pSrcBuffer,
1738 const void* pSrcBufferAllocStart,
1739 size_t nSrcBufferAllocSize)
1740 {
1741 if( !bufferDataType.CanConvertTo(GetDataType()) )
1742 {
1743 CPLError(CE_Failure, CPLE_AppDefined,
1744 "Buffer data type is not convertible to array data type");
1745 return false;
1746 }
1747
1748 std::vector<GInt64> tmp_arrayStep;
1749 std::vector<GPtrDiff_t> tmp_bufferStride;
1750 if( !CheckReadWriteParams(arrayStartIdx,
1751 count,
1752 arrayStep,
1753 bufferStride,
1754 bufferDataType,
1755 pSrcBuffer,
1756 pSrcBufferAllocStart,
1757 nSrcBufferAllocSize,
1758 tmp_arrayStep,
1759 tmp_bufferStride) )
1760 {
1761 return false;
1762 }
1763
1764 return IWrite(arrayStartIdx, count, arrayStep,
1765 bufferStride, bufferDataType, pSrcBuffer);
1766 }
1767
1768 /************************************************************************/
1769 /* GetTotalElementsCount() */
1770 /************************************************************************/
1771
1772 /** Return the total number of values in the array.
1773 *
1774 * This is the same as the C functions GDALMDArrayGetTotalElementsCount()
1775 * and GDALAttributeGetTotalElementsCount().
1776 *
1777 */
GetTotalElementsCount() const1778 GUInt64 GDALAbstractMDArray::GetTotalElementsCount() const
1779 {
1780 const auto& dims = GetDimensions();
1781 if( dims.empty() )
1782 return 1;
1783 GUInt64 nElts = 1;
1784 for( const auto& dim: dims )
1785 {
1786 try
1787 {
1788 nElts = (CPLSM(static_cast<GUInt64>(nElts)) *
1789 CPLSM(static_cast<GUInt64>(dim->GetSize()))).v();
1790 }
1791 catch( ... )
1792 {
1793 return 0;
1794 }
1795 }
1796 return nElts;
1797 }
1798
1799 /************************************************************************/
1800 /* GetBlockSize() */
1801 /************************************************************************/
1802
1803 /** Return the "natural" block size of the array along all dimensions.
1804 *
1805 * Some drivers might organize the array in tiles/blocks and reading/writing
1806 * aligned on those tile/block boundaries will be more efficient.
1807 *
1808 * The returned number of elements in the vector is the same as
1809 * GetDimensionCount(). A value of 0 should be interpreted as no hint regarding
1810 * the natural block size along the considered dimension.
1811 * "Flat" arrays will typically return a vector of values set to 0.
1812 *
1813 * The default implementation will return a vector of values set to 0.
1814 *
1815 * This method is used by GetProcessingChunkSize().
1816 *
1817 * Pedantic note: the returned type is GUInt64, so in the highly unlikeley theoretical
1818 * case of a 32-bit platform, this might exceed its size_t allocation capabilities.
1819 *
1820 * This is the same as the C function GDALMDArrayGetBlockSize().
1821 *
1822 * @return the block size, in number of elements along each dimension.
1823 */
GetBlockSize() const1824 std::vector<GUInt64> GDALAbstractMDArray::GetBlockSize() const
1825 {
1826 return std::vector<GUInt64>(GetDimensionCount());
1827 }
1828
1829 /************************************************************************/
1830 /* GetProcessingChunkSize() */
1831 /************************************************************************/
1832
1833 /** \brief Return an optimal chunk size for read/write oerations, given the natural
1834 * block size and memory constraints specified.
1835 *
1836 * This method will use GetBlockSize() to define a chunk whose dimensions are
1837 * multiple of those returned by GetBlockSize() (unless the block define by
1838 * GetBlockSize() is larger than nMaxChunkMemory, in which case it will be
1839 * returned by this method).
1840 *
1841 * This is the same as the C function GDALMDArrayGetProcessingChunkSize().
1842 *
1843 * @param nMaxChunkMemory Maximum amount of memory, in bytes, to use for the chunk.
1844 *
1845 * @return the chunk size, in number of elements along each dimension.
1846 */
GetProcessingChunkSize(size_t nMaxChunkMemory) const1847 std::vector<size_t> GDALAbstractMDArray::GetProcessingChunkSize(size_t nMaxChunkMemory) const
1848 {
1849 const auto& dims = GetDimensions();
1850 const auto& nDTSize = GetDataType().GetSize();
1851 std::vector<size_t> anChunkSize;
1852 auto blockSize = GetBlockSize();
1853 CPLAssert( blockSize.size() == dims.size() );
1854 size_t nChunkSize = nDTSize;
1855 bool bOverflow = false;
1856 constexpr auto kSIZE_T_MAX = std::numeric_limits<size_t>::max();
1857 // Initialize anChunkSize[i] with blockSize[i] by properly clamping in
1858 // [1, min(sizet_max, dim_size[i])]
1859 // Also make sure that the product of all anChunkSize[i]) fits on size_t
1860 for( size_t i = 0; i < dims.size(); i++ )
1861 {
1862 const auto sizeDimI = std::max(
1863 static_cast<size_t>(1),
1864 static_cast<size_t>(
1865 std::min(
1866 static_cast<GUInt64>(kSIZE_T_MAX),
1867 std::min(blockSize[i], dims[i]->GetSize()))));
1868 anChunkSize.push_back(sizeDimI);
1869 if( nChunkSize > kSIZE_T_MAX / sizeDimI )
1870 {
1871 bOverflow = true;
1872 }
1873 else
1874 {
1875 nChunkSize *= sizeDimI;
1876 }
1877 }
1878 if( nChunkSize == 0 )
1879 return anChunkSize;
1880
1881 // If the product of all anChunkSize[i] does not fit on size_t, then
1882 // set lowest anChunkSize[i] to 1.
1883 if( bOverflow )
1884 {
1885 nChunkSize = nDTSize;
1886 bOverflow = false;
1887 for( size_t i = dims.size(); i > 0; )
1888 {
1889 --i;
1890 if( bOverflow || nChunkSize > kSIZE_T_MAX / anChunkSize[i] )
1891 {
1892 bOverflow = true;
1893 anChunkSize[i] = 1;
1894 }
1895 else
1896 {
1897 nChunkSize *= anChunkSize[i];
1898 }
1899 }
1900 }
1901
1902 nChunkSize = nDTSize;
1903 std::vector<size_t> anAccBlockSizeFromStart;
1904 for( size_t i = 0; i < dims.size(); i++ )
1905 {
1906 nChunkSize *= anChunkSize[i];
1907 anAccBlockSizeFromStart.push_back(nChunkSize);
1908 }
1909 if( nChunkSize <= nMaxChunkMemory / 2 )
1910 {
1911 size_t nVoxelsFromEnd = 1;
1912 for( size_t i = dims.size(); i > 0; )
1913 {
1914 --i;
1915 const auto nCurBlockSize =
1916 anAccBlockSizeFromStart[i] * nVoxelsFromEnd;
1917 const auto nMul = nMaxChunkMemory / nCurBlockSize;
1918 if( nMul >= 2 )
1919 {
1920 const auto nSizeThisDim(dims[i]->GetSize());
1921 const auto nBlocksThisDim =
1922 DIV_ROUND_UP(nSizeThisDim, anChunkSize[i]);
1923 anChunkSize[i] = static_cast<size_t>(std::min(
1924 anChunkSize[i] * std::min(
1925 static_cast<GUInt64>(nMul), nBlocksThisDim),
1926 nSizeThisDim ));
1927 }
1928 nVoxelsFromEnd *= anChunkSize[i];
1929 }
1930 }
1931 return anChunkSize;
1932 }
1933
1934 /************************************************************************/
1935 /* SetUnit() */
1936 /************************************************************************/
1937
1938 /** Set the variable unit.
1939 *
1940 * Values should conform as much as possible with those allowed by
1941 * the NetCDF CF conventions:
1942 * http://cfconventions.org/Data/cf-conventions/cf-conventions-1.7/cf-conventions.html#units
1943 * but others might be returned.
1944 *
1945 * Few examples are "meter", "degrees", "second", ...
1946 * Empty value means unknown.
1947 *
1948 * This is the same as the C function GDALMDArraySetUnit()
1949 *
1950 * @note Driver implementation: optionally implemented.
1951 *
1952 * @param osUnit unit name.
1953 * @return true in case of success.
1954 */
SetUnit(CPL_UNUSED const std::string & osUnit)1955 bool GDALMDArray::SetUnit(CPL_UNUSED const std::string& osUnit)
1956 {
1957 CPLError(CE_Failure, CPLE_NotSupported, "SetUnit() not implemented");
1958 return false;
1959 }
1960
1961 /************************************************************************/
1962 /* GetUnit() */
1963 /************************************************************************/
1964
1965 /** Return the array unit.
1966 *
1967 * Values should conform as much as possible with those allowed by
1968 * the NetCDF CF conventions:
1969 * http://cfconventions.org/Data/cf-conventions/cf-conventions-1.7/cf-conventions.html#units
1970 * but others might be returned.
1971 *
1972 * Few examples are "meter", "degrees", "second", ...
1973 * Empty value means unknown.
1974 *
1975 * This is the same as the C function GDALMDArrayGetUnit()
1976 */
GetUnit() const1977 const std::string& GDALMDArray::GetUnit() const
1978 {
1979 static const std::string emptyString;
1980 return emptyString;
1981 }
1982
1983 /************************************************************************/
1984 /* SetSpatialRef() */
1985 /************************************************************************/
1986
1987 /** Assign a spatial reference system object to the the array.
1988 *
1989 * This is the same as the C function GDALMDArraySetSpatialRef().
1990 */
SetSpatialRef(CPL_UNUSED const OGRSpatialReference * poSRS)1991 bool GDALMDArray::SetSpatialRef(CPL_UNUSED const OGRSpatialReference* poSRS)
1992 {
1993 CPLError(CE_Failure, CPLE_NotSupported, "SetSpatialRef() not implemented");
1994 return false;
1995 }
1996
1997 /************************************************************************/
1998 /* GetSpatialRef() */
1999 /************************************************************************/
2000
2001 /** Return the spatial reference system object associated with the array.
2002 *
2003 * This is the same as the C function GDALMDArrayGetSpatialRef().
2004 */
GetSpatialRef() const2005 std::shared_ptr<OGRSpatialReference> GDALMDArray::GetSpatialRef() const
2006 {
2007 return nullptr;
2008 }
2009
2010 /************************************************************************/
2011 /* GetRawNoDataValue() */
2012 /************************************************************************/
2013
2014 /** Return the nodata value as a "raw" value.
2015 *
2016 * The value returned might be nullptr in case of no nodata value. When
2017 * a nodata value is registered, a non-nullptr will be returned whose size in
2018 * bytes is GetDataType().GetSize().
2019 *
2020 * The returned value should not be modified or freed. It is valid until
2021 * the array is destroyed, or the next call to GetRawNoDataValue() or
2022 * SetRawNoDataValue(), or any similar methods.
2023 *
2024 * @note Driver implementation: this method shall be implemented if nodata
2025 * is supported.
2026 *
2027 * This is the same as the C function GDALMDArrayGetRawNoDataValue().
2028 *
2029 * @return nullptr or a pointer to GetDataType().GetSize() bytes.
2030 */
GetRawNoDataValue() const2031 const void* GDALMDArray::GetRawNoDataValue() const
2032 {
2033 return nullptr;
2034 }
2035
2036 /************************************************************************/
2037 /* GetNoDataValueAsDouble() */
2038 /************************************************************************/
2039
2040 /** Return the nodata value as a double.
2041 *
2042 * The value returned might be nullptr in case of no nodata value. When
2043 * a nodata value is registered, a non-nullptr will be returned whose size in
2044 * bytes is GetDataType().GetSize().
2045 *
2046 * This is the same as the C function GDALMDArrayGetNoDataValueAsDouble().
2047 *
2048 * @param pbHasNoData Pointer to a output boolean that will be set to true if
2049 * a nodata value exists and can be converted to double. Might be nullptr.
2050 *
2051 * @return the nodata value as a double. A 0.0 value might also indicate the
2052 * absence of a nodata value or an error in the conversion (*pbHasNoData will be
2053 * set to false then).
2054 */
GetNoDataValueAsDouble(bool * pbHasNoData) const2055 double GDALMDArray::GetNoDataValueAsDouble(bool* pbHasNoData) const
2056 {
2057 const void* pNoData = GetRawNoDataValue();
2058 if( !pNoData )
2059 {
2060 if( pbHasNoData )
2061 *pbHasNoData = false;
2062 return 0.0;
2063 }
2064 double dfNoData = 0.0;
2065 if( !GDALExtendedDataType::CopyValue(pNoData,
2066 GetDataType(),
2067 &dfNoData,
2068 GDALExtendedDataType::Create(GDT_Float64)) )
2069 {
2070 if( pbHasNoData )
2071 *pbHasNoData = false;
2072 return 0.0;
2073 }
2074 if( pbHasNoData )
2075 *pbHasNoData = true;
2076 return dfNoData;
2077 }
2078
2079 /************************************************************************/
2080 /* SetRawNoDataValue() */
2081 /************************************************************************/
2082
2083 /** Set the nodata value as a "raw" value.
2084 *
2085 * The value passed might be nullptr in case of no nodata value. When
2086 * a nodata value is registered, a non-nullptr whose size in
2087 * bytes is GetDataType().GetSize() must be passed.
2088 *
2089 * This is the same as the C function GDALMDArraySetRawNoDataValue().
2090 *
2091 * @note Driver implementation: this method shall be implemented if setting nodata
2092 * is supported.
2093
2094 * @return true in case of success.
2095 */
SetRawNoDataValue(CPL_UNUSED const void * pRawNoData)2096 bool GDALMDArray::SetRawNoDataValue(CPL_UNUSED const void* pRawNoData)
2097 {
2098 CPLError(CE_Failure, CPLE_NotSupported, "SetRawNoDataValue() not implemented");
2099 return false;
2100 }
2101
2102 /************************************************************************/
2103 /* SetNoDataValue() */
2104 /************************************************************************/
2105
2106 /** Set the nodata value as a double.
2107 *
2108 * If the natural data type of the attribute/array is not double, type conversion
2109 * will occur to the type returned by GetDataType().
2110 *
2111 * This is the same as the C function GDALMDArraySetNoDataValueAsDouble().
2112 *
2113 * @return true in case of success.
2114 */
SetNoDataValue(double dfNoData)2115 bool GDALMDArray::SetNoDataValue(double dfNoData)
2116 {
2117 void* pRawNoData = CPLMalloc(GetDataType().GetSize());
2118 bool bRet = false;
2119 if( GDALExtendedDataType::CopyValue(
2120 &dfNoData, GDALExtendedDataType::Create(GDT_Float64),
2121 pRawNoData, GetDataType()) )
2122 {
2123 bRet = SetRawNoDataValue(pRawNoData);
2124 }
2125 CPLFree(pRawNoData);
2126 return bRet;
2127 }
2128
2129 /************************************************************************/
2130 /* SetScale() */
2131 /************************************************************************/
2132
2133 /** Set the scale value to apply to raw values.
2134 *
2135 * unscaled_value = raw_value * GetScale() + GetOffset()
2136 *
2137 * This is the same as the C function GDALMDArraySetScale() / GDALMDArraySetScaleEx().
2138 *
2139 * @note Driver implementation: this method shall be implemented if setting scale
2140 * is supported.
2141 *
2142 * @param dfScale scale
2143 * @param eStorageType Data type to which create the potential attribute that will store
2144 * the scale. Added in GDAL 3.3
2145 * If let to its GDT_Unknown value, the implementation will decide
2146 * automatically the data type.
2147 * Note that changing the data type after initial setting might not be
2148 * supported.
2149 * @return true in case of success.
2150 */
SetScale(CPL_UNUSED double dfScale,CPL_UNUSED GDALDataType eStorageType)2151 bool GDALMDArray::SetScale(CPL_UNUSED double dfScale,
2152 CPL_UNUSED GDALDataType eStorageType)
2153 {
2154 CPLError(CE_Failure, CPLE_NotSupported, "SetScale() not implemented");
2155 return false;
2156 }
2157
2158 /************************************************************************/
2159 /* SetOffset) */
2160 /************************************************************************/
2161
2162 /** Set the offset value to apply to raw values.
2163 *
2164 * unscaled_value = raw_value * GetScale() + GetOffset()
2165 *
2166 * This is the same as the C function GDALMDArraySetOffset() / GDALMDArraySetOffsetEx().
2167 *
2168 * @note Driver implementation: this method shall be implemented if setting offset
2169 * is supported.
2170 *
2171 * @param dfOffset Offset
2172 * @param eStorageType Data type to which create the potential attribute that will store
2173 * the offset. Added in GDAL 3.3
2174 * If let to its GDT_Unknown value, the implementation will decide
2175 * automatically the data type.
2176 * Note that changing the data type after initial setting might not be
2177 * supported.
2178 * @return true in case of success.
2179 */
SetOffset(CPL_UNUSED double dfOffset,CPL_UNUSED GDALDataType eStorageType)2180 bool GDALMDArray::SetOffset(CPL_UNUSED double dfOffset,
2181 CPL_UNUSED GDALDataType eStorageType)
2182 {
2183 CPLError(CE_Failure, CPLE_NotSupported, "SetOffset() not implemented");
2184 return false;
2185 }
2186
2187 /************************************************************************/
2188 /* GetScale() */
2189 /************************************************************************/
2190
2191 /** Get the scale value to apply to raw values.
2192 *
2193 * unscaled_value = raw_value * GetScale() + GetOffset()
2194 *
2195 * This is the same as the C function GDALMDArrayGetScale().
2196 *
2197 * @note Driver implementation: this method shall be implemented if gettings scale
2198 * is supported.
2199 *
2200 * @param pbHasScale Pointer to a output boolean that will be set to true if
2201 * a scale value exists. Might be nullptr.
2202 * @param peStorageType Pointer to a output GDALDataType that will be set to
2203 * the storage type of the scale value, when known/relevant. Otherwise will be
2204 * set to GDT_Unknown. Might be nullptr. Since GDAL 3.3
2205 *
2206 * @return the scale value. A 1.0 value might also indicate the
2207 * absence of a scale value.
2208 */
GetScale(CPL_UNUSED bool * pbHasScale,CPL_UNUSED GDALDataType * peStorageType) const2209 double GDALMDArray::GetScale(CPL_UNUSED bool* pbHasScale,
2210 CPL_UNUSED GDALDataType* peStorageType) const
2211 {
2212 if( pbHasScale )
2213 *pbHasScale = false;
2214 return 1.0;
2215 }
2216
2217 /************************************************************************/
2218 /* GetOffset() */
2219 /************************************************************************/
2220
2221 /** Get the offset value to apply to raw values.
2222 *
2223 * unscaled_value = raw_value * GetScale() + GetOffset()
2224 *
2225 * This is the same as the C function GDALMDArrayGetOffset().
2226 *
2227 * @note Driver implementation: this method shall be implemented if gettings offset
2228 * is supported.
2229 *
2230 * @param pbHasOffset Pointer to a output boolean that will be set to true if
2231 * a offset value exists. Might be nullptr.
2232 * @param peStorageType Pointer to a output GDALDataType that will be set to
2233 * the storage type of the offset value, when known/relevant. Otherwise will be
2234 * set to GDT_Unknown. Might be nullptr. Since GDAL 3.3
2235 *
2236 * @return the offset value. A 0.0 value might also indicate the
2237 * absence of a offset value.
2238 */
GetOffset(CPL_UNUSED bool * pbHasOffset,CPL_UNUSED GDALDataType * peStorageType) const2239 double GDALMDArray::GetOffset(CPL_UNUSED bool* pbHasOffset,
2240 CPL_UNUSED GDALDataType* peStorageType) const
2241 {
2242 if( pbHasOffset )
2243 *pbHasOffset = false;
2244 return 0.0;
2245 }
2246
2247 /************************************************************************/
2248 /* ProcessPerChunk() */
2249 /************************************************************************/
2250
2251 namespace
2252 {
2253 enum class Caller
2254 {
2255 CALLER_END_OF_LOOP,
2256 CALLER_IN_LOOP,
2257 };
2258 }
2259
2260 /** \brief Call a user-provided function to operate on an array chunk by chunk.
2261 *
2262 * This method is to be used when doing operations on an array, or a subset of it,
2263 * in a chunk by chunk way.
2264 *
2265 * @param arrayStartIdx Values representing the starting index to use
2266 * in each dimension (in [0, aoDims[i].GetSize()-1] range).
2267 * Array of GetDimensionCount() values. Must not be
2268 * nullptr, unless for a zero-dimensional array.
2269 *
2270 * @param count Values representing the number of values to use in
2271 * each dimension.
2272 * Array of GetDimensionCount() values. Must not be
2273 * nullptr, unless for a zero-dimensional array.
2274 *
2275 * @param chunkSize Values representing the chunk size in each dimension.
2276 * Might typically the output of GetProcessingChunkSize().
2277 * Array of GetDimensionCount() values. Must not be
2278 * nullptr, unless for a zero-dimensional array.
2279 *
2280 * @param pfnFunc User-provided function of type FuncProcessPerChunkType.
2281 * Must NOT be nullptr.
2282 *
2283 * @param pUserData Pointer to pass as the value of the pUserData argument of
2284 * FuncProcessPerChunkType. Might be nullptr (depends on
2285 * pfnFunc.
2286 *
2287 * @return true in case of success.
2288 */
ProcessPerChunk(const GUInt64 * arrayStartIdx,const GUInt64 * count,const size_t * chunkSize,FuncProcessPerChunkType pfnFunc,void * pUserData)2289 bool GDALAbstractMDArray::ProcessPerChunk(const GUInt64* arrayStartIdx,
2290 const GUInt64* count,
2291 const size_t* chunkSize,
2292 FuncProcessPerChunkType pfnFunc,
2293 void* pUserData)
2294 {
2295 const auto& dims = GetDimensions();
2296 if( dims.empty() )
2297 {
2298 return pfnFunc(this, nullptr, nullptr, 1, 1, pUserData);
2299 }
2300
2301 // Sanity check
2302 size_t nTotalChunkSize = 1;
2303 for( size_t i = 0; i < dims.size(); i++ )
2304 {
2305 const auto nSizeThisDim(dims[i]->GetSize());
2306 if( count[i] == 0 ||
2307 count[i] > nSizeThisDim ||
2308 arrayStartIdx[i] > nSizeThisDim - count[i] )
2309 {
2310 CPLError(CE_Failure, CPLE_AppDefined,
2311 "Inconsistent arrayStartIdx[] / count[] values "
2312 "regarding array size");
2313 return false;
2314 }
2315 if( chunkSize[i] == 0 || chunkSize[i] > nSizeThisDim ||
2316 chunkSize[i] > std::numeric_limits<size_t>::max() / nTotalChunkSize )
2317 {
2318 CPLError(CE_Failure, CPLE_AppDefined,
2319 "Inconsistent chunkSize[] values");
2320 return false;
2321 }
2322 nTotalChunkSize *= chunkSize[i];
2323 }
2324
2325 size_t dimIdx = 0;
2326 std::vector<GUInt64> chunkArrayStartIdx(dims.size());
2327 std::vector<size_t> chunkCount(dims.size());
2328 struct Stack
2329 {
2330 GUInt64 nBlockCounter = 0;
2331 GUInt64 nBlocksMinusOne = 0;
2332 size_t first_count = 0; // only used if nBlocks > 1
2333 Caller return_point = Caller::CALLER_END_OF_LOOP;
2334 };
2335 std::vector<Stack> stack(dims.size());
2336 GUInt64 iCurChunk = 0;
2337 GUInt64 nChunkCount = 1;
2338 for( size_t i = 0; i < dims.size(); i++ )
2339 {
2340 const auto nStartBlock = arrayStartIdx[i] / chunkSize[i];
2341 const auto nEndBlock = (arrayStartIdx[i] + count[i] - 1) / chunkSize[i];
2342 stack[i].nBlocksMinusOne = nEndBlock - nStartBlock;
2343 nChunkCount *= 1 + stack[i].nBlocksMinusOne;
2344 if( stack[i].nBlocksMinusOne == 0 )
2345 {
2346 chunkArrayStartIdx[i] = arrayStartIdx[i];
2347 chunkCount[i] = static_cast<size_t>(count[i]);
2348 }
2349 else
2350 {
2351 stack[i].first_count = static_cast<size_t>(
2352 (nStartBlock + 1) * chunkSize[i] - arrayStartIdx[i]);
2353 }
2354 }
2355
2356 lbl_next_depth:
2357 if( dimIdx == dims.size() )
2358 {
2359 ++ iCurChunk;
2360 if( !pfnFunc(this, chunkArrayStartIdx.data(), chunkCount.data(),
2361 iCurChunk, nChunkCount, pUserData) )
2362 {
2363 return false;
2364 }
2365 }
2366 else
2367 {
2368 if( stack[dimIdx].nBlocksMinusOne != 0 )
2369 {
2370 stack[dimIdx].nBlockCounter = stack[dimIdx].nBlocksMinusOne;
2371 chunkArrayStartIdx[dimIdx] = arrayStartIdx[dimIdx];
2372 chunkCount[dimIdx] = stack[dimIdx].first_count;
2373 stack[dimIdx].return_point = Caller::CALLER_IN_LOOP;
2374 while(true)
2375 {
2376 dimIdx ++;
2377 goto lbl_next_depth;
2378 lbl_return_to_caller_in_loop:
2379 -- stack[dimIdx].nBlockCounter;
2380 if( stack[dimIdx].nBlockCounter == 0 )
2381 break;
2382 chunkArrayStartIdx[dimIdx] += chunkCount[dimIdx];
2383 chunkCount[dimIdx] = chunkSize[dimIdx];
2384 }
2385
2386 chunkArrayStartIdx[dimIdx] += chunkCount[dimIdx];
2387 chunkCount[dimIdx] = static_cast<size_t>(
2388 arrayStartIdx[dimIdx] + count[dimIdx] - chunkArrayStartIdx[dimIdx]);
2389 stack[dimIdx].return_point = Caller::CALLER_END_OF_LOOP;
2390 }
2391 dimIdx ++;
2392 goto lbl_next_depth;
2393 lbl_return_to_caller_end_of_loop:
2394 if( dimIdx == 0 )
2395 goto end;
2396 }
2397
2398 dimIdx --;
2399 // cppcheck-suppress negativeContainerIndex
2400 switch( stack[dimIdx].return_point )
2401 {
2402 case Caller::CALLER_END_OF_LOOP: goto lbl_return_to_caller_end_of_loop;
2403 case Caller::CALLER_IN_LOOP: goto lbl_return_to_caller_in_loop;
2404 }
2405 end:
2406 return true;
2407 }
2408
2409 /************************************************************************/
2410 /* GDALAttribute() */
2411 /************************************************************************/
2412
2413 //! @cond Doxygen_Suppress
GDALAttribute(CPL_UNUSED const std::string & osParentName,CPL_UNUSED const std::string & osName)2414 GDALAttribute::GDALAttribute(CPL_UNUSED const std::string& osParentName,
2415 CPL_UNUSED const std::string& osName)
2416 #if !defined(COMPILER_WARNS_ABOUT_ABSTRACT_VBASE_INIT)
2417 : GDALAbstractMDArray(osParentName, osName)
2418 #endif
2419 {}
2420 //! @endcond
2421
2422 /************************************************************************/
2423 /* GetDimensionSize() */
2424 /************************************************************************/
2425
2426 /** Return the size of the dimensions of the attribute.
2427 *
2428 * This will be an empty array for a scalar (single value) attribute.
2429 *
2430 * This is the same as the C function GDALAttributeGetDimensionsSize().
2431 */
GetDimensionsSize() const2432 std::vector<GUInt64> GDALAttribute::GetDimensionsSize() const
2433 {
2434 const auto& dims = GetDimensions();
2435 std::vector<GUInt64> ret;
2436 ret.reserve(dims.size());
2437 for( const auto& dim: dims )
2438 ret.push_back(dim->GetSize());
2439 return ret;
2440 }
2441
2442 /************************************************************************/
2443 /* GDALRawResult() */
2444 /************************************************************************/
2445
2446 //! @cond Doxygen_Suppress
GDALRawResult(GByte * raw,const GDALExtendedDataType & dt,size_t nEltCount)2447 GDALRawResult::GDALRawResult(GByte* raw,
2448 const GDALExtendedDataType& dt,
2449 size_t nEltCount):
2450 m_dt(dt),
2451 m_nEltCount(nEltCount),
2452 m_nSize(nEltCount * dt.GetSize()),
2453 m_raw(raw)
2454 {
2455 }
2456 //! @endcond
2457
2458 /************************************************************************/
2459 /* GDALRawResult() */
2460 /************************************************************************/
2461
2462 /** Move constructor. */
GDALRawResult(GDALRawResult && other)2463 GDALRawResult::GDALRawResult(GDALRawResult&& other):
2464 m_dt(std::move(other.m_dt)),
2465 m_nEltCount(other.m_nEltCount),
2466 m_nSize(other.m_nSize),
2467 m_raw(other.m_raw)
2468 {
2469 other.m_nEltCount = 0;
2470 other.m_nSize = 0;
2471 other.m_raw = nullptr;
2472 }
2473
2474 /************************************************************************/
2475 /* FreeMe() */
2476 /************************************************************************/
2477
FreeMe()2478 void GDALRawResult::FreeMe()
2479 {
2480 if( m_raw && m_dt.NeedsFreeDynamicMemory() )
2481 {
2482 GByte* pabyPtr = m_raw;
2483 const auto nDTSize(m_dt.GetSize());
2484 for( size_t i = 0; i < m_nEltCount; ++i )
2485 {
2486 m_dt.FreeDynamicMemory(pabyPtr);
2487 pabyPtr += nDTSize;
2488 }
2489 }
2490 VSIFree(m_raw);
2491 }
2492
2493 /************************************************************************/
2494 /* operator=() */
2495 /************************************************************************/
2496
2497 /** Move assignment. */
operator =(GDALRawResult && other)2498 GDALRawResult& GDALRawResult::operator=(GDALRawResult&& other)
2499 {
2500 FreeMe();
2501 m_dt = std::move(other.m_dt);
2502 m_nEltCount = other.m_nEltCount;
2503 m_nSize = other.m_nSize;
2504 m_raw = other.m_raw;
2505 other.m_nEltCount = 0;
2506 other.m_nSize = 0;
2507 other.m_raw = nullptr;
2508 return *this;
2509 }
2510
2511 /************************************************************************/
2512 /* ~GDALRawResult() */
2513 /************************************************************************/
2514
2515 /** Destructor. */
~GDALRawResult()2516 GDALRawResult::~GDALRawResult()
2517 {
2518 FreeMe();
2519 }
2520
2521 /************************************************************************/
2522 /* StealData() */
2523 /************************************************************************/
2524
2525 //! @cond Doxygen_Suppress
2526 /** Return buffer to caller which becomes owner of it.
2527 * Only to be used by GDALAttributeReadAsRaw().
2528 */
StealData()2529 GByte* GDALRawResult::StealData()
2530 {
2531 GByte* ret = m_raw;
2532 m_raw = nullptr;
2533 m_nEltCount = 0;
2534 m_nSize = 0;
2535 return ret;
2536 }
2537 //! @endcond
2538
2539 /************************************************************************/
2540 /* ReadAsRaw() */
2541 /************************************************************************/
2542
2543 /** Return the raw value of an attribute.
2544 *
2545 *
2546 * This is the same as the C function GDALAttributeReadAsRaw().
2547 */
ReadAsRaw() const2548 GDALRawResult GDALAttribute::ReadAsRaw() const
2549 {
2550 const auto nEltCount(GetTotalElementsCount());
2551 const auto dt(GetDataType());
2552 const auto nDTSize(dt.GetSize());
2553 GByte* res = static_cast<GByte*>(
2554 VSI_MALLOC2_VERBOSE(static_cast<size_t>(nEltCount), nDTSize));
2555 if( !res )
2556 return GDALRawResult(nullptr, dt, 0);
2557 const auto& dims = GetDimensions();
2558 const auto nDims = GetDimensionCount();
2559 std::vector<GUInt64> startIdx(1 + nDims, 0);
2560 std::vector<size_t> count(1 + nDims);
2561 for( size_t i = 0; i < nDims; i++ )
2562 {
2563 count[i] = static_cast<size_t>(dims[i]->GetSize());
2564 }
2565 if( !Read(startIdx.data(), count.data(), nullptr, nullptr,
2566 dt,
2567 &res[0], &res[0], static_cast<size_t>(nEltCount * nDTSize)) )
2568 {
2569 VSIFree(res);
2570 return GDALRawResult(nullptr, dt, 0);
2571 }
2572 return GDALRawResult(res, dt, static_cast<size_t>(nEltCount));
2573 }
2574
2575 /************************************************************************/
2576 /* ReadAsString() */
2577 /************************************************************************/
2578
2579 /** Return the value of an attribute as a string.
2580 *
2581 * The returned string should not be freed, and its lifetime does not
2582 * excess a next call to ReadAsString() on the same object, or the deletion
2583 * of the object itself.
2584 *
2585 * This function will only return the first element if there are several.
2586 *
2587 * This is the same as the C function GDALAttributeReadAsString()
2588 *
2589 * @return a string, or nullptr.
2590 */
ReadAsString() const2591 const char* GDALAttribute::ReadAsString() const
2592 {
2593 const auto nDims = GetDimensionCount();
2594 std::vector<GUInt64> startIdx(1 + nDims, 0);
2595 std::vector<size_t> count(1 + nDims, 1);
2596 char* szRet = nullptr;
2597 if( !Read(startIdx.data(), count.data(), nullptr, nullptr,
2598 GDALExtendedDataType::CreateString(),
2599 &szRet, &szRet, sizeof(szRet)) ||
2600 szRet == nullptr )
2601 {
2602 return nullptr;
2603 }
2604 m_osCachedVal = szRet;
2605 CPLFree(szRet);
2606 return m_osCachedVal.c_str();
2607 }
2608
2609 /************************************************************************/
2610 /* ReadAsInt() */
2611 /************************************************************************/
2612
2613 /** Return the value of an attribute as a integer.
2614 *
2615 * This function will only return the first element if there are several.
2616 *
2617 * It can fail if its value can be converted to integer.
2618 *
2619 * This is the same as the C function GDALAttributeReadAsInt()
2620 *
2621 * @return a integer, or INT_MIN in case of error.
2622 */
ReadAsInt() const2623 int GDALAttribute::ReadAsInt() const
2624 {
2625 const auto nDims = GetDimensionCount();
2626 std::vector<GUInt64> startIdx(1 + nDims, 0);
2627 std::vector<size_t> count(1 + nDims, 1);
2628 int nRet = INT_MIN;
2629 Read(startIdx.data(), count.data(), nullptr, nullptr,
2630 GDALExtendedDataType::Create(GDT_Int32),
2631 &nRet, &nRet, sizeof(nRet));
2632 return nRet;
2633 }
2634
2635 /************************************************************************/
2636 /* ReadAsDouble() */
2637 /************************************************************************/
2638
2639 /** Return the value of an attribute as a double.
2640 *
2641 * This function will only return the first element if there are several.
2642 *
2643 * It can fail if its value can be converted to double.
2644 *
2645 * This is the same as the C function GDALAttributeReadAsInt()
2646 *
2647 * @return a double value.
2648 */
ReadAsDouble() const2649 double GDALAttribute::ReadAsDouble() const
2650 {
2651 const auto nDims = GetDimensionCount();
2652 std::vector<GUInt64> startIdx(1 + nDims, 0);
2653 std::vector<size_t> count(1 + nDims, 1);
2654 double dfRet = 0;
2655 Read(startIdx.data(), count.data(), nullptr, nullptr,
2656 GDALExtendedDataType::Create(GDT_Float64),
2657 &dfRet, &dfRet, sizeof(dfRet));
2658 return dfRet;
2659 }
2660
2661 /************************************************************************/
2662 /* ReadAsStringArray() */
2663 /************************************************************************/
2664
2665 /** Return the value of an attribute as an array of strings.
2666 *
2667 * This is the same as the C function GDALAttributeReadAsStringArray()
2668 */
ReadAsStringArray() const2669 CPLStringList GDALAttribute::ReadAsStringArray() const
2670 {
2671 const auto nElts = GetTotalElementsCount();
2672 if( nElts > static_cast<unsigned>(std::numeric_limits<int>::max() - 1) )
2673 return CPLStringList();
2674 char** papszList = static_cast<char**>(
2675 VSI_CALLOC_VERBOSE(static_cast<int>(nElts) + 1, sizeof(char*)));
2676 const auto& dims = GetDimensions();
2677 const auto nDims = GetDimensionCount();
2678 std::vector<GUInt64> startIdx(1 + nDims, 0);
2679 std::vector<size_t> count(1 + nDims);
2680 for( size_t i = 0; i < nDims; i++ )
2681 {
2682 count[i] = static_cast<size_t>(dims[i]->GetSize());
2683 }
2684 Read(startIdx.data(), count.data(), nullptr, nullptr,
2685 GDALExtendedDataType::CreateString(),
2686 papszList, papszList, sizeof(char*) * static_cast<int>(nElts));
2687 for( int i = 0; i < static_cast<int>(nElts); i++ )
2688 {
2689 if( papszList[i] == nullptr )
2690 papszList[i] = CPLStrdup("");
2691 }
2692 return CPLStringList(papszList);
2693 }
2694
2695 /************************************************************************/
2696 /* ReadAsIntArray() */
2697 /************************************************************************/
2698
2699 /** Return the value of an attribute as an array of integers.
2700 *
2701 * This is the same as the C function GDALAttributeReadAsIntArray().
2702 */
ReadAsIntArray() const2703 std::vector<int> GDALAttribute::ReadAsIntArray() const
2704 {
2705 const auto nElts = GetTotalElementsCount();
2706 if( nElts > static_cast<size_t>(nElts) )
2707 return {};
2708 std::vector<int> res(static_cast<size_t>(nElts));
2709 const auto& dims = GetDimensions();
2710 const auto nDims = GetDimensionCount();
2711 std::vector<GUInt64> startIdx(1 + nDims, 0);
2712 std::vector<size_t> count(1 + nDims);
2713 for( size_t i = 0; i < nDims; i++ )
2714 {
2715 count[i] = static_cast<size_t>(dims[i]->GetSize());
2716 }
2717 Read(startIdx.data(), count.data(), nullptr, nullptr,
2718 GDALExtendedDataType::Create(GDT_Int32),
2719 &res[0], res.data(), res.size() * sizeof(res[0]));
2720 return res;
2721 }
2722
2723 /************************************************************************/
2724 /* ReadAsDoubleArray() */
2725 /************************************************************************/
2726
2727 /** Return the value of an attribute as an array of double.
2728 *
2729 * This is the same as the C function GDALAttributeReadAsDoubleArray().
2730 */
ReadAsDoubleArray() const2731 std::vector<double> GDALAttribute::ReadAsDoubleArray() const
2732 {
2733 const auto nElts = GetTotalElementsCount();
2734 if( nElts > static_cast<size_t>(nElts) )
2735 return {};
2736 std::vector<double> res(static_cast<size_t>(nElts));
2737 const auto& dims = GetDimensions();
2738 const auto nDims = GetDimensionCount();
2739 std::vector<GUInt64> startIdx(1 + nDims, 0);
2740 std::vector<size_t> count(1 + nDims);
2741 for( size_t i = 0; i < nDims; i++ )
2742 {
2743 count[i] = static_cast<size_t>(dims[i]->GetSize());
2744 }
2745 Read(startIdx.data(), count.data(), nullptr, nullptr,
2746 GDALExtendedDataType::Create(GDT_Float64),
2747 &res[0], res.data(), res.size() * sizeof(res[0]));
2748 return res;
2749 }
2750
2751 /************************************************************************/
2752 /* Write() */
2753 /************************************************************************/
2754
2755 /** Write an attribute from raw values expressed in GetDataType()
2756 *
2757 * The values should be provided in the type of GetDataType() and there should
2758 * be exactly GetTotalElementsCount() of them.
2759 * If GetDataType() is a string, each value should be a char* pointer.
2760 *
2761 * This is the same as the C function GDALAttributeWriteRaw().
2762 *
2763 * @param pabyValue Buffer of nLen bytes.
2764 * @param nLen Size of pabyValue in bytes. Should be equal to
2765 * GetTotalElementsCount() * GetDataType().GetSize()
2766 * @return true in case of success.
2767 */
Write(const void * pabyValue,size_t nLen)2768 bool GDALAttribute::Write(const void* pabyValue, size_t nLen)
2769 {
2770 if( nLen != GetTotalElementsCount() * GetDataType().GetSize() )
2771 {
2772 CPLError(CE_Failure, CPLE_AppDefined,
2773 "Length is not of expected value");
2774 return false;
2775 }
2776 const auto& dims = GetDimensions();
2777 const auto nDims = GetDimensionCount();
2778 std::vector<GUInt64> startIdx(1 + nDims, 0);
2779 std::vector<size_t> count(1 + nDims);
2780 for( size_t i = 0; i < nDims; i++ )
2781 {
2782 count[i] = static_cast<size_t>(dims[i]->GetSize());
2783 }
2784 return Write(startIdx.data(), count.data(), nullptr, nullptr,
2785 GetDataType(),
2786 pabyValue, pabyValue, nLen);
2787 }
2788
2789 /************************************************************************/
2790 /* Write() */
2791 /************************************************************************/
2792
2793 /** Write an attribute from a string value.
2794 *
2795 * Type conversion will be performed if needed. If the attribute contains
2796 * multiple values, only the first one will be updated.
2797 *
2798 * This is the same as the C function GDALAttributeWriteString().
2799 *
2800 * @param pszValue Pointer to a string.
2801 * @return true in case of success.
2802 */
Write(const char * pszValue)2803 bool GDALAttribute::Write(const char* pszValue)
2804 {
2805 const auto nDims = GetDimensionCount();
2806 std::vector<GUInt64> startIdx(1 + nDims, 0);
2807 std::vector<size_t> count(1 + nDims, 1);
2808 return Write(startIdx.data(), count.data(), nullptr, nullptr,
2809 GDALExtendedDataType::CreateString(),
2810 &pszValue, &pszValue, sizeof(pszValue));
2811 }
2812
2813 /************************************************************************/
2814 /* WriteInt() */
2815 /************************************************************************/
2816
2817 /** Write an attribute from a integer value.
2818 *
2819 * Type conversion will be performed if needed. If the attribute contains
2820 * multiple values, only the first one will be updated.
2821 *
2822 * This is the same as the C function GDALAttributeWriteInt().
2823 *
2824 * @param nVal Value.
2825 * @return true in case of success.
2826 */
WriteInt(int nVal)2827 bool GDALAttribute::WriteInt(int nVal)
2828 {
2829 const auto nDims = GetDimensionCount();
2830 std::vector<GUInt64> startIdx(1 + nDims, 0);
2831 std::vector<size_t> count(1 + nDims, 1);
2832 return Write(startIdx.data(), count.data(), nullptr, nullptr,
2833 GDALExtendedDataType::Create(GDT_Int32),
2834 &nVal, &nVal, sizeof(nVal));
2835 }
2836
2837 /************************************************************************/
2838 /* Write() */
2839 /************************************************************************/
2840
2841 /** Write an attribute from a double value.
2842 *
2843 * Type conversion will be performed if needed. If the attribute contains
2844 * multiple values, only the first one will be updated.
2845 *
2846 * This is the same as the C function GDALAttributeWriteDouble().
2847 *
2848 * @param dfVal Value.
2849 * @return true in case of success.
2850 */
Write(double dfVal)2851 bool GDALAttribute::Write(double dfVal)
2852 {
2853 const auto nDims = GetDimensionCount();
2854 std::vector<GUInt64> startIdx(1 + nDims, 0);
2855 std::vector<size_t> count(1 + nDims, 1);
2856 return Write(startIdx.data(), count.data(), nullptr, nullptr,
2857 GDALExtendedDataType::Create(GDT_Float64),
2858 &dfVal, &dfVal, sizeof(dfVal));
2859 }
2860
2861 /************************************************************************/
2862 /* Write() */
2863 /************************************************************************/
2864
2865 /** Write an attribute from an array of strings.
2866 *
2867 * Type conversion will be performed if needed.
2868 *
2869 * Exactly GetTotalElementsCount() strings must be provided
2870 *
2871 * This is the same as the C function GDALAttributeWriteStringArray().
2872 *
2873 * @param vals Array of strings.
2874 * @return true in case of success.
2875 */
Write(CSLConstList vals)2876 bool GDALAttribute::Write(CSLConstList vals)
2877 {
2878 if( static_cast<size_t>(CSLCount(vals)) != GetTotalElementsCount() )
2879 {
2880 CPLError(CE_Failure, CPLE_AppDefined,
2881 "Invalid number of input values");
2882 return false;
2883 }
2884 const auto nDims = GetDimensionCount();
2885 std::vector<GUInt64> startIdx(1 + nDims, 0);
2886 std::vector<size_t> count(1 + nDims);
2887 const auto& dims = GetDimensions();
2888 for( size_t i = 0; i < nDims; i++ )
2889 count[i] = static_cast<size_t>(dims[i]->GetSize());
2890 return Write(startIdx.data(), count.data(), nullptr, nullptr,
2891 GDALExtendedDataType::CreateString(),
2892 vals, vals,
2893 static_cast<size_t>(GetTotalElementsCount()) * sizeof(char*));
2894 }
2895
2896 /************************************************************************/
2897 /* Write() */
2898 /************************************************************************/
2899
2900 /** Write an attribute from an array of double.
2901 *
2902 * Type conversion will be performed if needed.
2903 *
2904 * Exactly GetTotalElementsCount() strings must be provided
2905 *
2906 * This is the same as the C function GDALAttributeWriteDoubleArray()
2907 *
2908 * @param vals Array of double.
2909 * @param nVals Should be equal to GetTotalElementsCount().
2910 * @return true in case of success.
2911 */
Write(const double * vals,size_t nVals)2912 bool GDALAttribute::Write(const double *vals, size_t nVals)
2913 {
2914 if( nVals != GetTotalElementsCount() )
2915 {
2916 CPLError(CE_Failure, CPLE_AppDefined,
2917 "Invalid number of input values");
2918 return false;
2919 }
2920 const auto nDims = GetDimensionCount();
2921 std::vector<GUInt64> startIdx(1 + nDims, 0);
2922 std::vector<size_t> count(1 + nDims);
2923 const auto& dims = GetDimensions();
2924 for( size_t i = 0; i < nDims; i++ )
2925 count[i] = static_cast<size_t>(dims[i]->GetSize());
2926 return Write(startIdx.data(), count.data(), nullptr, nullptr,
2927 GDALExtendedDataType::Create(GDT_Float64),
2928 vals, vals,
2929 static_cast<size_t>(GetTotalElementsCount()) * sizeof(double));
2930 }
2931
2932 /************************************************************************/
2933 /* GDALMDArray() */
2934 /************************************************************************/
2935
2936 //! @cond Doxygen_Suppress
GDALMDArray(CPL_UNUSED const std::string & osParentName,CPL_UNUSED const std::string & osName)2937 GDALMDArray::GDALMDArray(CPL_UNUSED const std::string &osParentName,
2938 CPL_UNUSED const std::string& osName)
2939 #if !defined(COMPILER_WARNS_ABOUT_ABSTRACT_VBASE_INIT)
2940 : GDALAbstractMDArray(osParentName, osName)
2941 #endif
2942 {}
2943 //! @endcond
2944
2945 /************************************************************************/
2946 /* GetTotalCopyCost() */
2947 /************************************************************************/
2948
2949 /** Return a total "cost" to copy the array.
2950 *
2951 * Used as a parameter for CopyFrom()
2952 */
GetTotalCopyCost() const2953 GUInt64 GDALMDArray::GetTotalCopyCost() const
2954 {
2955 return COPY_COST +
2956 GetAttributes().size() * GDALAttribute::COPY_COST +
2957 GetTotalElementsCount() * GetDataType().GetSize();
2958 }
2959
2960
2961 /************************************************************************/
2962 /* CopyFromAllExceptValues() */
2963 /************************************************************************/
2964
2965 //! @cond Doxygen_Suppress
2966
CopyFromAllExceptValues(const GDALMDArray * poSrcArray,bool bStrict,GUInt64 & nCurCost,const GUInt64 nTotalCost,GDALProgressFunc pfnProgress,void * pProgressData)2967 bool GDALMDArray::CopyFromAllExceptValues(const GDALMDArray* poSrcArray,
2968 bool bStrict,
2969 GUInt64& nCurCost,
2970 const GUInt64 nTotalCost,
2971 GDALProgressFunc pfnProgress,
2972 void * pProgressData)
2973 {
2974 const bool bThisIsUnscaledArray =
2975 dynamic_cast<GDALMDArrayUnscaled*>(this) != nullptr;
2976 auto attrs = poSrcArray->GetAttributes();
2977 for( const auto& attr: attrs )
2978 {
2979 const auto& osAttrName = attr->GetName();
2980 if( bThisIsUnscaledArray )
2981 {
2982 if( osAttrName == "missing_value" ||
2983 osAttrName == "_FillValue" ||
2984 osAttrName == "valid_min" ||
2985 osAttrName == "valid_max" ||
2986 osAttrName == "valid_range" )
2987 {
2988 continue;
2989 }
2990 }
2991
2992 auto dstAttr = CreateAttribute(osAttrName,
2993 attr->GetDimensionsSize(),
2994 attr->GetDataType());
2995 if( !dstAttr )
2996 {
2997 if( bStrict )
2998 return false;
2999 continue;
3000 }
3001 auto raw = attr->ReadAsRaw();
3002 if( !dstAttr->Write(raw.data(), raw.size()) && bStrict )
3003 return false;
3004 }
3005 if( !attrs.empty() )
3006 {
3007 nCurCost += attrs.size() * GDALAttribute::COPY_COST;
3008 if( pfnProgress &&
3009 !pfnProgress(double(nCurCost) / nTotalCost, "", pProgressData) )
3010 return false;
3011 }
3012
3013 auto srcSRS = poSrcArray->GetSpatialRef();
3014 if( srcSRS )
3015 {
3016 SetSpatialRef(srcSRS.get());
3017 }
3018
3019 const void* pNoData = poSrcArray->GetRawNoDataValue();
3020 if( pNoData && poSrcArray->GetDataType() == GetDataType() )
3021 {
3022 SetRawNoDataValue(pNoData);
3023 }
3024
3025 const std::string& osUnit(poSrcArray->GetUnit());
3026 if( !osUnit.empty() )
3027 {
3028 SetUnit(osUnit);
3029 }
3030
3031 bool bGotValue = false;
3032 GDALDataType eOffsetStorageType = GDT_Unknown;
3033 const double dfOffset = poSrcArray->GetOffset(&bGotValue, &eOffsetStorageType);
3034 if( bGotValue )
3035 {
3036 SetOffset(dfOffset, eOffsetStorageType);
3037 }
3038
3039 bGotValue = false;
3040 GDALDataType eScaleStorageType = GDT_Unknown;
3041 const double dfScale = poSrcArray->GetScale(&bGotValue, &eScaleStorageType);
3042 if( bGotValue )
3043 {
3044 SetScale(dfScale, eScaleStorageType);
3045 }
3046
3047 return true;
3048 }
3049
3050 //! @endcond
3051
3052 /************************************************************************/
3053 /* CopyFrom() */
3054 /************************************************************************/
3055
3056 /** Copy the content of an array into a new (generally empty) array.
3057 *
3058 * @param poSrcDS Source dataset. Might be nullptr (but for correct behavior
3059 * of some output drivers this is not recommended)
3060 * @param poSrcArray Source array. Should NOT be nullptr.
3061 * @param bStrict Whether to enable stict mode. In strict mode, any error will
3062 * stop the copy. In relaxed mode, the copy will be attempted to
3063 * be pursued.
3064 * @param nCurCost Should be provided as a variable initially set to 0.
3065 * @param nTotalCost Total cost from GetTotalCopyCost().
3066 * @param pfnProgress Progress callback, or nullptr.
3067 * @param pProgressData Progress user data, or nulptr.
3068 *
3069 * @return true in case of success (or partial success if bStrict == false).
3070 */
CopyFrom(CPL_UNUSED GDALDataset * poSrcDS,const GDALMDArray * poSrcArray,bool bStrict,GUInt64 & nCurCost,const GUInt64 nTotalCost,GDALProgressFunc pfnProgress,void * pProgressData)3071 bool GDALMDArray::CopyFrom(CPL_UNUSED GDALDataset* poSrcDS,
3072 const GDALMDArray* poSrcArray,
3073 bool bStrict,
3074 GUInt64& nCurCost,
3075 const GUInt64 nTotalCost,
3076 GDALProgressFunc pfnProgress,
3077 void * pProgressData)
3078 {
3079 if( pfnProgress == nullptr )
3080 pfnProgress = GDALDummyProgress;
3081
3082 nCurCost += GDALMDArray::COPY_COST;
3083
3084 if( !CopyFromAllExceptValues(poSrcArray, bStrict,
3085 nCurCost, nTotalCost,
3086 pfnProgress, pProgressData) )
3087 {
3088 return false;
3089 }
3090
3091 const auto& dims = poSrcArray->GetDimensions();
3092 const auto nDTSize = poSrcArray->GetDataType().GetSize();
3093 if( dims.empty() )
3094 {
3095 std::vector<GByte> abyTmp(nDTSize);
3096 if( !(poSrcArray->Read(nullptr, nullptr, nullptr, nullptr,
3097 GetDataType(), &abyTmp[0]) &&
3098 Write(nullptr, nullptr, nullptr, nullptr,
3099 GetDataType(), &abyTmp[0])) &&
3100 bStrict )
3101 {
3102 return false;
3103 }
3104 nCurCost += GetTotalElementsCount() * GetDataType().GetSize();
3105 if( !pfnProgress(double(nCurCost) / nTotalCost, "", pProgressData) )
3106 return false;
3107 }
3108 else
3109 {
3110 std::vector<GUInt64> arrayStartIdx(dims.size());
3111 std::vector<GUInt64> count(dims.size());
3112 for( size_t i = 0; i < dims.size(); i++ )
3113 {
3114 count[i] = static_cast<size_t>(dims[i]->GetSize());
3115 }
3116
3117 struct CopyFunc
3118 {
3119 GDALMDArray* poDstArray = nullptr;
3120 std::vector<GByte> abyTmp{};
3121 GDALProgressFunc pfnProgress = nullptr;
3122 void* pProgressData = nullptr;
3123 GUInt64 nCurCost = 0;
3124 GUInt64 nTotalCost = 0;
3125 GUInt64 nTotalBytesThisArray = 0;
3126 bool bStop = false;
3127
3128 static bool f(GDALAbstractMDArray* l_poSrcArray,
3129 const GUInt64* chunkArrayStartIdx,
3130 const size_t* chunkCount,
3131 GUInt64 iCurChunk,
3132 GUInt64 nChunkCount,
3133 void* pUserData)
3134 {
3135 const auto dt(l_poSrcArray->GetDataType());
3136 auto data = static_cast<CopyFunc*>(pUserData);
3137 auto poDstArray = data->poDstArray;
3138 if( !l_poSrcArray->Read(chunkArrayStartIdx,
3139 chunkCount,
3140 nullptr, nullptr,
3141 dt,
3142 &data->abyTmp[0]) )
3143 {
3144 return false;
3145 }
3146 bool bRet =
3147 poDstArray->Write(chunkArrayStartIdx,
3148 chunkCount,
3149 nullptr, nullptr,
3150 dt,
3151 &data->abyTmp[0]);
3152 if( dt.NeedsFreeDynamicMemory() )
3153 {
3154 const auto l_nDTSize = dt.GetSize();
3155 GByte* ptr = &data->abyTmp[0];
3156 const size_t l_nDims(l_poSrcArray->GetDimensionCount());
3157 size_t nEltCount = 1;
3158 for( size_t i = 0; i < l_nDims; ++i )
3159 {
3160 nEltCount *= chunkCount[i];
3161 }
3162 for( size_t i = 0; i < nEltCount; i++ )
3163 {
3164 dt.FreeDynamicMemory(ptr);
3165 ptr += l_nDTSize;
3166 }
3167 }
3168 if( !bRet )
3169 {
3170 return false;
3171 }
3172
3173 double dfCurCost = double(data->nCurCost) +
3174 double(iCurChunk) / nChunkCount * data->nTotalBytesThisArray;
3175 if( !data->pfnProgress(dfCurCost / data->nTotalCost, "",
3176 data->pProgressData) )
3177 {
3178 data->bStop = true;
3179 return false;
3180 }
3181
3182 return true;
3183 }
3184 };
3185
3186 CopyFunc copyFunc;
3187 copyFunc.poDstArray = this;
3188 copyFunc.nCurCost = nCurCost;
3189 copyFunc.nTotalCost = nTotalCost;
3190 copyFunc.nTotalBytesThisArray = GetTotalElementsCount() * nDTSize;
3191 copyFunc.pfnProgress = pfnProgress;
3192 copyFunc.pProgressData = pProgressData;
3193 const char* pszSwathSize = CPLGetConfigOption("GDAL_SWATH_SIZE", nullptr);
3194 const size_t nMaxChunkSize = pszSwathSize ?
3195 static_cast<size_t>(
3196 std::min(GIntBig(std::numeric_limits<size_t>::max() / 2),
3197 CPLAtoGIntBig(pszSwathSize))) :
3198 static_cast<size_t>(
3199 std::min(GIntBig(std::numeric_limits<size_t>::max() / 2),
3200 GDALGetCacheMax64() / 4));
3201 const auto anChunkSizes(GetProcessingChunkSize(nMaxChunkSize));
3202 size_t nRealChunkSize = nDTSize;
3203 for( const auto& nChunkSize: anChunkSizes )
3204 {
3205 nRealChunkSize *= nChunkSize;
3206 }
3207 try
3208 {
3209 copyFunc.abyTmp.resize(nRealChunkSize);
3210 }
3211 catch( const std::exception& )
3212 {
3213 CPLError(CE_Failure, CPLE_OutOfMemory,
3214 "Cannot allocate temporary buffer");
3215 nCurCost += copyFunc.nTotalBytesThisArray;
3216 return false;
3217 }
3218 if( copyFunc.nTotalBytesThisArray != 0 &&
3219 !const_cast<GDALMDArray*>(poSrcArray)->
3220 ProcessPerChunk(arrayStartIdx.data(), count.data(),
3221 anChunkSizes.data(),
3222 CopyFunc::f, ©Func) &&
3223 (bStrict || copyFunc.bStop) )
3224 {
3225 nCurCost += copyFunc.nTotalBytesThisArray;
3226 return false;
3227 }
3228 nCurCost += copyFunc.nTotalBytesThisArray;
3229 }
3230
3231 return true;
3232 }
3233
3234 /************************************************************************/
3235 /* GetStructuralInfo() */
3236 /************************************************************************/
3237
3238 /** Return structural information on the array.
3239 *
3240 * This may be the compression, etc..
3241 *
3242 * The return value should not be freed and is valid until GDALMDArray is
3243 * released or this function called again.
3244 *
3245 * This is the same as the C function GDALMDArrayGetStruturalInfo().
3246 */
GetStructuralInfo() const3247 CSLConstList GDALMDArray::GetStructuralInfo() const
3248 {
3249 return nullptr;
3250 }
3251
3252 /************************************************************************/
3253 /* AdviseRead() */
3254 /************************************************************************/
3255
3256 /** Advise driver of upcoming read requests.
3257 *
3258 * Some GDAL drivers operate more efficiently if they know in advance what
3259 * set of upcoming read requests will be made. The AdviseRead() method allows
3260 * an application to notify the driver of the region of interest.
3261 *
3262 * Many drivers just ignore the AdviseRead() call, but it can dramatically
3263 * accelerate access via some drivers. One such case is when reading through
3264 * a DAP dataset with the netCDF driver (a in-memory cache array is then created
3265 * with the region of interest defined by AdviseRead())
3266 *
3267 * This is the same as the C function GDALMDArrayAdviseRead().
3268 *
3269 * @param arrayStartIdx Values representing the starting index to read
3270 * in each dimension (in [0, aoDims[i].GetSize()-1] range).
3271 * Array of GetDimensionCount() values.
3272 * Can be nullptr as a synonymous for [0 for i in range(GetDimensionCount() ]
3273 *
3274 * @param count Values representing the number of values to extract in
3275 * each dimension.
3276 * Array of GetDimensionCount() values.
3277 * Can be nullptr as a synonymous for
3278 * [ aoDims[i].GetSize() - arrayStartIdx[i] for i in range(GetDimensionCount() ]
3279 * @return true in case of success (ignoring the advice is a success)
3280 *
3281 * @since GDAL 3.2
3282 */
AdviseRead(const GUInt64 * arrayStartIdx,const size_t * count) const3283 bool GDALMDArray::AdviseRead(const GUInt64* arrayStartIdx,
3284 const size_t* count) const
3285 {
3286 const auto nDimCount = GetDimensionCount();
3287 if( nDimCount == 0 )
3288 return true;
3289
3290 std::vector<GUInt64> tmp_arrayStartIdx;
3291 if( arrayStartIdx == nullptr )
3292 {
3293 tmp_arrayStartIdx.resize(nDimCount);
3294 arrayStartIdx = tmp_arrayStartIdx.data();
3295 }
3296
3297 std::vector<size_t> tmp_count;
3298 if( count == nullptr )
3299 {
3300 tmp_count.resize(nDimCount);
3301 const auto& dims = GetDimensions();
3302 for( size_t i = 0; i < nDimCount; i++ )
3303 {
3304 const GUInt64 nSize = dims[i]->GetSize() - arrayStartIdx[i];
3305 #if SIZEOF_VOIDP < 8
3306 if( nSize != static_cast<size_t>(nSize) )
3307 {
3308 CPLError(CE_Failure, CPLE_AppDefined, "Integer overflow");
3309 return false;
3310 }
3311 #endif
3312 tmp_count[i] = static_cast<size_t>(nSize);
3313 }
3314 count = tmp_count.data();
3315 }
3316
3317 std::vector<GInt64> tmp_arrayStep;
3318 std::vector<GPtrDiff_t> tmp_bufferStride;
3319 const GInt64* arrayStep = nullptr;
3320 const GPtrDiff_t* bufferStride = nullptr;
3321 if( !CheckReadWriteParams(arrayStartIdx,
3322 count,
3323 arrayStep,
3324 bufferStride,
3325 GDALExtendedDataType::Create(GDT_Unknown),
3326 nullptr,
3327 nullptr,
3328 0,
3329 tmp_arrayStep,
3330 tmp_bufferStride) )
3331 {
3332 return false;
3333 }
3334
3335 return IAdviseRead(arrayStartIdx, count);
3336 }
3337
3338 /************************************************************************/
3339 /* IAdviseRead() */
3340 /************************************************************************/
3341
3342 //! @cond Doxygen_Suppress
IAdviseRead(const GUInt64 *,const size_t *) const3343 bool GDALMDArray::IAdviseRead(const GUInt64*, const size_t*) const
3344 {
3345 return true;
3346 }
3347 //! @endcond
3348
3349 /************************************************************************/
3350 /* GDALSlicedMDArray */
3351 /************************************************************************/
3352
3353 class GDALSlicedMDArray final: public GDALMDArray
3354 {
3355 private:
3356 std::shared_ptr<GDALMDArray> m_poParent{};
3357 std::vector<std::shared_ptr<GDALDimension>> m_dims{};
3358 std::vector<size_t> m_mapDimIdxToParentDimIdx{}; // of size m_dims.size()
3359 std::vector<Range> m_parentRanges{} ; // of size m_poParent->GetDimensionCount()
3360
3361 mutable std::vector<GUInt64> m_parentStart;
3362 mutable std::vector<size_t> m_parentCount;
3363 mutable std::vector<GInt64> m_parentStep;
3364 mutable std::vector<GPtrDiff_t> m_parentStride;
3365
3366 void PrepareParentArrays(const GUInt64* arrayStartIdx,
3367 const size_t* count,
3368 const GInt64* arrayStep,
3369 const GPtrDiff_t* bufferStride) const;
3370
3371 protected:
GDALSlicedMDArray(const std::shared_ptr<GDALMDArray> & poParent,const std::string & viewExpr,std::vector<std::shared_ptr<GDALDimension>> && dims,std::vector<size_t> && mapDimIdxToParentDimIdx,std::vector<Range> && parentRanges)3372 explicit GDALSlicedMDArray(
3373 const std::shared_ptr<GDALMDArray>& poParent,
3374 const std::string& viewExpr,
3375 std::vector<std::shared_ptr<GDALDimension>>&& dims,
3376 std::vector<size_t>&& mapDimIdxToParentDimIdx,
3377 std::vector<Range>&& parentRanges)
3378 :
3379 GDALAbstractMDArray(std::string(), "Sliced view of " + poParent->GetFullName() + " (" + viewExpr + ")"),
3380 GDALMDArray(std::string(), "Sliced view of " + poParent->GetFullName() + " (" + viewExpr + ")"),
3381 m_poParent(std::move(poParent)),
3382 m_dims(std::move(dims)),
3383 m_mapDimIdxToParentDimIdx(std::move(mapDimIdxToParentDimIdx)),
3384 m_parentRanges(parentRanges),
3385 m_parentStart(m_poParent->GetDimensionCount()),
3386 m_parentCount(m_poParent->GetDimensionCount(), 1),
3387 m_parentStep(m_poParent->GetDimensionCount()),
3388 m_parentStride(m_poParent->GetDimensionCount())
3389 {
3390 }
3391
3392 bool IRead(const GUInt64* arrayStartIdx,
3393 const size_t* count,
3394 const GInt64* arrayStep,
3395 const GPtrDiff_t* bufferStride,
3396 const GDALExtendedDataType& bufferDataType,
3397 void* pDstBuffer) const override;
3398
3399 bool IWrite(const GUInt64* arrayStartIdx,
3400 const size_t* count,
3401 const GInt64* arrayStep,
3402 const GPtrDiff_t* bufferStride,
3403 const GDALExtendedDataType& bufferDataType,
3404 const void* pSrcBuffer) override;
3405
3406 bool IAdviseRead(const GUInt64* arrayStartIdx,
3407 const size_t* count) const override;
3408
3409 public:
Create(const std::shared_ptr<GDALMDArray> & poParent,const std::string & viewExpr,std::vector<std::shared_ptr<GDALDimension>> && dims,std::vector<size_t> && mapDimIdxToParentDimIdx,std::vector<Range> && parentRanges)3410 static std::shared_ptr<GDALSlicedMDArray> Create(
3411 const std::shared_ptr<GDALMDArray>& poParent,
3412 const std::string& viewExpr,
3413 std::vector<std::shared_ptr<GDALDimension>>&& dims,
3414 std::vector<size_t>&& mapDimIdxToParentDimIdx,
3415 std::vector<Range>&& parentRanges)
3416 {
3417 CPLAssert(dims.size() == mapDimIdxToParentDimIdx.size());
3418 CPLAssert(parentRanges.size() == poParent->GetDimensionCount());
3419
3420 auto newAr(std::shared_ptr<GDALSlicedMDArray>(new GDALSlicedMDArray(
3421 poParent, viewExpr, std::move(dims), std::move(mapDimIdxToParentDimIdx),
3422 std::move(parentRanges))));
3423 newAr->SetSelf(newAr);
3424 return newAr;
3425 }
3426
IsWritable() const3427 bool IsWritable() const override { return m_poParent->IsWritable(); }
3428
GetDimensions() const3429 const std::vector<std::shared_ptr<GDALDimension>>& GetDimensions() const override { return m_dims; }
3430
GetDataType() const3431 const GDALExtendedDataType &GetDataType() const override { return m_poParent->GetDataType(); }
3432
GetUnit() const3433 const std::string& GetUnit() const override { return m_poParent->GetUnit(); }
3434
3435 // bool SetUnit(const std::string& osUnit) override { return m_poParent->SetUnit(osUnit); }
3436
GetSpatialRef() const3437 std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
3438 {
3439 auto poSrcSRS = m_poParent->GetSpatialRef();
3440 if( !poSrcSRS )
3441 return nullptr;
3442 auto srcMapping = poSrcSRS->GetDataAxisToSRSAxisMapping();
3443 std::vector<int> dstMapping;
3444 for( int srcAxis: srcMapping )
3445 {
3446 bool bFound = false;
3447 for( size_t i = 0; i < m_mapDimIdxToParentDimIdx.size(); i++ )
3448 {
3449 if( static_cast<int>(m_mapDimIdxToParentDimIdx[i]) == srcAxis - 1 )
3450 {
3451 dstMapping.push_back(static_cast<int>(i) + 1);
3452 bFound = true;
3453 break;
3454 }
3455 }
3456 if( !bFound )
3457 {
3458 dstMapping.push_back(0);
3459 }
3460 }
3461 auto poClone(std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone()));
3462 poClone->SetDataAxisToSRSAxisMapping(dstMapping);
3463 return poClone;
3464 }
3465
GetRawNoDataValue() const3466 const void* GetRawNoDataValue() const override { return m_poParent->GetRawNoDataValue(); }
3467
3468 // bool SetRawNoDataValue(const void* pRawNoData) override { return m_poParent->SetRawNoDataValue(pRawNoData); }
3469
GetOffset(bool * pbHasOffset,GDALDataType * peStorageType) const3470 double GetOffset(bool* pbHasOffset, GDALDataType* peStorageType) const override { return m_poParent->GetOffset(pbHasOffset, peStorageType); }
3471
GetScale(bool * pbHasScale,GDALDataType * peStorageType) const3472 double GetScale(bool* pbHasScale, GDALDataType* peStorageType) const override { return m_poParent->GetScale(pbHasScale, peStorageType); }
3473
3474 // bool SetOffset(double dfOffset) override { return m_poParent->SetOffset(dfOffset); }
3475
3476 // bool SetScale(double dfScale) override { return m_poParent->SetScale(dfScale); }
3477
GetBlockSize() const3478 std::vector<GUInt64> GetBlockSize() const override
3479 {
3480 std::vector<GUInt64> ret(GetDimensionCount());
3481 const auto parentBlockSize(m_poParent->GetBlockSize());
3482 for( size_t i = 0; i < m_mapDimIdxToParentDimIdx.size(); ++i )
3483 {
3484 const auto iOldAxis = m_mapDimIdxToParentDimIdx[i];
3485 if( iOldAxis != static_cast<size_t>(-1) )
3486 {
3487 ret[i] = parentBlockSize[iOldAxis];
3488 }
3489 }
3490 return ret;
3491 }
3492
GetAttribute(const std::string & osName) const3493 std::shared_ptr<GDALAttribute> GetAttribute(const std::string& osName) const override
3494 { return m_poParent->GetAttribute(osName); }
3495
GetAttributes(CSLConstList papszOptions=nullptr) const3496 std::vector<std::shared_ptr<GDALAttribute>> GetAttributes(CSLConstList papszOptions = nullptr) const override
3497 { return m_poParent->GetAttributes(papszOptions); }
3498 };
3499
3500 /************************************************************************/
3501 /* PrepareParentArrays() */
3502 /************************************************************************/
3503
PrepareParentArrays(const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride) const3504 void GDALSlicedMDArray::PrepareParentArrays(const GUInt64* arrayStartIdx,
3505 const size_t* count,
3506 const GInt64* arrayStep,
3507 const GPtrDiff_t* bufferStride) const
3508 {
3509 const size_t nParentDimCount = m_parentRanges.size();
3510 for( size_t i = 0; i < nParentDimCount; i++ )
3511 {
3512 // For dimensions in parent that have no existence in sliced array
3513 m_parentStart[i] = m_parentRanges[i].m_nStartIdx;
3514 }
3515
3516 for( size_t i = 0; i < m_dims.size(); i++ )
3517 {
3518 const auto iParent = m_mapDimIdxToParentDimIdx[i];
3519 if( iParent != static_cast<size_t>(-1) )
3520 {
3521 m_parentStart[iParent] =
3522 m_parentRanges[iParent].m_nIncr >= 0 ?
3523 m_parentRanges[iParent].m_nStartIdx +
3524 arrayStartIdx[i] * m_parentRanges[iParent].m_nIncr :
3525 m_parentRanges[iParent].m_nStartIdx -
3526 arrayStartIdx[i] *
3527 static_cast<GUInt64>(-m_parentRanges[iParent].m_nIncr);
3528 m_parentCount[iParent] = count[i];
3529 if( arrayStep )
3530 {
3531 m_parentStep[iParent] = count[i] == 1 ? 1 :
3532 // other checks should have ensured this does not
3533 // overflow
3534 arrayStep[i] * m_parentRanges[iParent].m_nIncr;
3535 }
3536 if( bufferStride )
3537 {
3538 m_parentStride[iParent] = bufferStride[i];
3539 }
3540 }
3541 }
3542 }
3543
3544 /************************************************************************/
3545 /* IRead() */
3546 /************************************************************************/
3547
IRead(const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride,const GDALExtendedDataType & bufferDataType,void * pDstBuffer) const3548 bool GDALSlicedMDArray::IRead(const GUInt64* arrayStartIdx,
3549 const size_t* count,
3550 const GInt64* arrayStep,
3551 const GPtrDiff_t* bufferStride,
3552 const GDALExtendedDataType& bufferDataType,
3553 void* pDstBuffer) const
3554 {
3555 PrepareParentArrays(arrayStartIdx, count, arrayStep, bufferStride);
3556 return m_poParent->Read(m_parentStart.data(),
3557 m_parentCount.data(),
3558 m_parentStep.data(),
3559 m_parentStride.data(),
3560 bufferDataType,
3561 pDstBuffer);
3562 }
3563
3564 /************************************************************************/
3565 /* IWrite() */
3566 /************************************************************************/
3567
IWrite(const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride,const GDALExtendedDataType & bufferDataType,const void * pSrcBuffer)3568 bool GDALSlicedMDArray::IWrite(const GUInt64* arrayStartIdx,
3569 const size_t* count,
3570 const GInt64* arrayStep,
3571 const GPtrDiff_t* bufferStride,
3572 const GDALExtendedDataType& bufferDataType,
3573 const void* pSrcBuffer)
3574 {
3575 PrepareParentArrays(arrayStartIdx, count, arrayStep, bufferStride);
3576 return m_poParent->Write(m_parentStart.data(),
3577 m_parentCount.data(),
3578 m_parentStep.data(),
3579 m_parentStride.data(),
3580 bufferDataType,
3581 pSrcBuffer);
3582 }
3583
3584 /************************************************************************/
3585 /* IAdviseRead() */
3586 /************************************************************************/
3587
IAdviseRead(const GUInt64 * arrayStartIdx,const size_t * count) const3588 bool GDALSlicedMDArray::IAdviseRead(const GUInt64* arrayStartIdx,
3589 const size_t* count) const
3590 {
3591 PrepareParentArrays(arrayStartIdx, count, nullptr, nullptr);
3592 return m_poParent->AdviseRead(m_parentStart.data(),
3593 m_parentCount.data());
3594 }
3595
3596 /************************************************************************/
3597 /* CreateSlicedArray() */
3598 /************************************************************************/
3599
CreateSlicedArray(const std::shared_ptr<GDALMDArray> & self,const std::string & viewExpr,const std::string & activeSlice,bool bRenameDimensions,std::vector<GDALMDArray::ViewSpec> & viewSpecs)3600 static std::shared_ptr<GDALMDArray> CreateSlicedArray(
3601 const std::shared_ptr<GDALMDArray>& self,
3602 const std::string& viewExpr,
3603 const std::string& activeSlice,
3604 bool bRenameDimensions,
3605 std::vector<GDALMDArray::ViewSpec>& viewSpecs)
3606 {
3607 const auto& srcDims(self->GetDimensions());
3608 if( srcDims.empty() )
3609 {
3610 CPLError(CE_Failure, CPLE_AppDefined,
3611 "Cannot slice a 0-d array");
3612 return nullptr;
3613 }
3614
3615 CPLStringList aosTokens(CSLTokenizeString2(activeSlice.c_str(), ",", 0));
3616 const auto nTokens = static_cast<size_t>(aosTokens.size());
3617
3618 std::vector<std::shared_ptr<GDALDimension>> newDims;
3619 std::vector<size_t> mapDimIdxToParentDimIdx;
3620 std::vector<GDALSlicedMDArray::Range> parentRanges;
3621 newDims.reserve(nTokens);
3622 mapDimIdxToParentDimIdx.reserve(nTokens);
3623 parentRanges.reserve(nTokens);
3624
3625 bool bGotEllipsis = false;
3626 size_t nCurSrcDim = 0;
3627 for( size_t i = 0; i < nTokens; i++ )
3628 {
3629 const char* pszIdxSpec = aosTokens[i];
3630 if( EQUAL(pszIdxSpec, "...") )
3631 {
3632 if( bGotEllipsis )
3633 {
3634 CPLError(CE_Failure, CPLE_AppDefined,
3635 "Only one single ellipsis is supported");
3636 return nullptr;
3637 }
3638 bGotEllipsis = true;
3639 const auto nSubstitutionCount = srcDims.size() - (nTokens - 1);
3640 for( size_t j = 0; j < nSubstitutionCount; j++, nCurSrcDim++ )
3641 {
3642 parentRanges.emplace_back(0, 1);
3643 newDims.push_back(srcDims[nCurSrcDim]);
3644 mapDimIdxToParentDimIdx.push_back(nCurSrcDim);
3645 }
3646 continue;
3647 }
3648 else if( EQUAL(pszIdxSpec, "newaxis") ||
3649 EQUAL(pszIdxSpec, "np.newaxis") )
3650 {
3651 newDims.push_back(std::make_shared<GDALDimension>(
3652 std::string(),
3653 "newaxis",
3654 std::string(),
3655 std::string(),
3656 1));
3657 mapDimIdxToParentDimIdx.push_back(static_cast<size_t>(-1));
3658 continue;
3659 }
3660 else if( CPLGetValueType(pszIdxSpec) == CPL_VALUE_INTEGER )
3661 {
3662 if( nCurSrcDim >= srcDims.size() )
3663 {
3664 CPLError(CE_Failure, CPLE_AppDefined,
3665 "Too many values in %s", activeSlice.c_str());
3666 return nullptr;
3667 }
3668
3669 auto nVal = CPLAtoGIntBig(pszIdxSpec);
3670 GUInt64 nDimSize = srcDims[nCurSrcDim]->GetSize();
3671 if( (nVal >= 0 && static_cast<GUInt64>(nVal) >= nDimSize) ||
3672 (nVal < 0 && nDimSize < static_cast<GUInt64>(-nVal)) )
3673 {
3674 CPLError(CE_Failure, CPLE_AppDefined,
3675 "Index " CPL_FRMT_GIB " is out of bounds", nVal);
3676 return nullptr;
3677 }
3678 if( nVal < 0 )
3679 nVal += nDimSize;
3680 parentRanges.emplace_back(nVal, 0);
3681 }
3682 else
3683 {
3684 if( nCurSrcDim >= srcDims.size() )
3685 {
3686 CPLError(CE_Failure, CPLE_AppDefined,
3687 "Too many values in %s", activeSlice.c_str());
3688 return nullptr;
3689 }
3690
3691 CPLStringList aosRangeTokens(CSLTokenizeString2(
3692 pszIdxSpec, ":", CSLT_ALLOWEMPTYTOKENS));
3693 int nRangeTokens = aosRangeTokens.size();
3694 if( nRangeTokens > 3 )
3695 {
3696 CPLError(CE_Failure, CPLE_AppDefined,
3697 "Too many : in %s", pszIdxSpec);
3698 return nullptr;
3699 }
3700 if( nRangeTokens <= 1 )
3701 {
3702 CPLError(CE_Failure, CPLE_AppDefined,
3703 "Invalid value %s", pszIdxSpec);
3704 return nullptr;
3705 }
3706 const char* pszStart = aosRangeTokens[0];
3707 const char* pszEnd = aosRangeTokens[1];
3708 const char* pszInc = (nRangeTokens == 3) ? aosRangeTokens[2]: "";
3709 GDALSlicedMDArray::Range range;
3710 const GUInt64 nDimSize(srcDims[nCurSrcDim]->GetSize());
3711 range.m_nIncr = EQUAL(pszInc, "") ? 1 : CPLAtoGIntBig(pszInc);
3712 if( range.m_nIncr == 0 )
3713 {
3714 CPLError(CE_Failure, CPLE_AppDefined,
3715 "Invalid increment 0");
3716 return nullptr;
3717 }
3718 auto startIdx(CPLAtoGIntBig(pszStart));
3719 if( startIdx < 0 )
3720 {
3721 if( nDimSize < static_cast<GUInt64>(-startIdx) )
3722 startIdx = 0;
3723 else
3724 startIdx = nDimSize + startIdx;
3725 }
3726 range.m_nStartIdx = startIdx;
3727 range.m_nStartIdx = EQUAL(pszStart, "") ?
3728 (range.m_nIncr > 0 ? 0 : nDimSize-1) :
3729 range.m_nStartIdx;
3730 if( range.m_nStartIdx >= nDimSize - 1)
3731 range.m_nStartIdx = nDimSize - 1;
3732 auto endIdx(CPLAtoGIntBig(pszEnd));
3733 if( endIdx < 0 )
3734 {
3735 const auto positiveEndIdx = static_cast<GUInt64>(-endIdx);
3736 if( nDimSize < positiveEndIdx )
3737 endIdx = 0;
3738 else
3739 endIdx = nDimSize - positiveEndIdx;
3740 }
3741 GUInt64 nEndIdx = endIdx;
3742 nEndIdx = EQUAL(pszEnd, "") ?
3743 (range.m_nIncr < 0 ? 0 : nDimSize) :
3744 nEndIdx;
3745 if( (range.m_nIncr > 0 && range.m_nStartIdx >= nEndIdx) ||
3746 (range.m_nIncr < 0 && range.m_nStartIdx <= nEndIdx) )
3747 {
3748 CPLError(CE_Failure, CPLE_AppDefined,
3749 "Output dimension of size 0 is not allowed");
3750 return nullptr;
3751 }
3752 int inc = (EQUAL(pszEnd, "") && range.m_nIncr < 0) ? 1 : 0;
3753 const GUInt64 newSize = range.m_nIncr > 0 ?
3754 (nEndIdx - range.m_nStartIdx) / range.m_nIncr +
3755 (((inc + nEndIdx - range.m_nStartIdx) % range.m_nIncr) ? 1 : 0):
3756 (inc + range.m_nStartIdx - nEndIdx) / -range.m_nIncr +
3757 (((inc + range.m_nStartIdx - nEndIdx) % -range.m_nIncr) ? 1 : 0);
3758 if( range.m_nStartIdx == 0 &&
3759 range.m_nIncr == 1 &&
3760 newSize == srcDims[nCurSrcDim]->GetSize() )
3761 {
3762 newDims.push_back(srcDims[nCurSrcDim]);
3763 }
3764 else
3765 {
3766 std::string osNewDimName(srcDims[nCurSrcDim]->GetName());
3767 if( bRenameDimensions )
3768 {
3769 osNewDimName =
3770 "subset_" + srcDims[nCurSrcDim]->GetName() +
3771 CPLSPrintf("_" CPL_FRMT_GUIB "_" CPL_FRMT_GIB "_" CPL_FRMT_GUIB,
3772 static_cast<GUIntBig>(range.m_nStartIdx),
3773 static_cast<GIntBig>(range.m_nIncr),
3774 static_cast<GUIntBig>(newSize));
3775 }
3776 newDims.push_back(std::make_shared<GDALDimension>(
3777 std::string(),
3778 osNewDimName,
3779 srcDims[nCurSrcDim]->GetType(),
3780 range.m_nIncr > 0 ?
3781 srcDims[nCurSrcDim]->GetDirection():
3782 std::string(),
3783 newSize));
3784 }
3785 mapDimIdxToParentDimIdx.push_back(nCurSrcDim);
3786 parentRanges.emplace_back(range);
3787 }
3788
3789 nCurSrcDim++;
3790 }
3791 for( ; nCurSrcDim < srcDims.size(); nCurSrcDim++ )
3792 {
3793 parentRanges.emplace_back(0, 1);
3794 newDims.push_back(srcDims[nCurSrcDim]);
3795 mapDimIdxToParentDimIdx.push_back(nCurSrcDim);
3796 }
3797
3798 GDALMDArray::ViewSpec viewSpec;
3799 viewSpec.m_mapDimIdxToParentDimIdx = mapDimIdxToParentDimIdx;
3800 viewSpec.m_parentRanges = parentRanges;
3801 viewSpecs.emplace_back(std::move(viewSpec));
3802
3803 return GDALSlicedMDArray::Create(self,
3804 viewExpr,
3805 std::move(newDims),
3806 std::move(mapDimIdxToParentDimIdx),
3807 std::move(parentRanges));
3808 }
3809
3810 /************************************************************************/
3811 /* GDALExtractFieldMDArray */
3812 /************************************************************************/
3813
3814 class GDALExtractFieldMDArray final: public GDALMDArray
3815 {
3816 private:
3817 std::shared_ptr<GDALMDArray> m_poParent{};
3818 GDALExtendedDataType m_dt;
3819 std::string m_srcCompName;
3820 mutable std::vector<GByte> m_pabyNoData{};
3821
3822 protected:
GDALExtractFieldMDArray(const std::shared_ptr<GDALMDArray> & poParent,const std::string & fieldName,const std::unique_ptr<GDALEDTComponent> & srcComp)3823 GDALExtractFieldMDArray(
3824 const std::shared_ptr<GDALMDArray>& poParent,
3825 const std::string& fieldName,
3826 const std::unique_ptr<GDALEDTComponent>& srcComp)
3827 :
3828 GDALAbstractMDArray(
3829 std::string(), "Extract field " + fieldName + " of " + poParent->GetFullName()),
3830 GDALMDArray(
3831 std::string(), "Extract field " + fieldName + " of " + poParent->GetFullName()),
3832 m_poParent(poParent),
3833 m_dt(srcComp->GetType()),
3834 m_srcCompName(srcComp->GetName())
3835 {
3836 m_pabyNoData.resize(m_dt.GetSize());
3837 }
3838
3839 bool IRead(const GUInt64* arrayStartIdx,
3840 const size_t* count,
3841 const GInt64* arrayStep,
3842 const GPtrDiff_t* bufferStride,
3843 const GDALExtendedDataType& bufferDataType,
3844 void* pDstBuffer) const override;
3845
IAdviseRead(const GUInt64 * arrayStartIdx,const size_t * count) const3846 bool IAdviseRead(const GUInt64* arrayStartIdx,
3847 const size_t* count) const override
3848 { return m_poParent->AdviseRead(arrayStartIdx, count); }
3849
3850 public:
Create(const std::shared_ptr<GDALMDArray> & poParent,const std::string & fieldName,const std::unique_ptr<GDALEDTComponent> & srcComp)3851 static std::shared_ptr<GDALExtractFieldMDArray> Create(
3852 const std::shared_ptr<GDALMDArray>& poParent,
3853 const std::string& fieldName,
3854 const std::unique_ptr<GDALEDTComponent>& srcComp)
3855 {
3856 auto newAr(std::shared_ptr<GDALExtractFieldMDArray>(
3857 new GDALExtractFieldMDArray(poParent, fieldName, srcComp)));
3858 newAr->SetSelf(newAr);
3859 return newAr;
3860 }
~GDALExtractFieldMDArray()3861 ~GDALExtractFieldMDArray()
3862 {
3863 m_dt.FreeDynamicMemory(&m_pabyNoData[0]);
3864 }
3865
IsWritable() const3866 bool IsWritable() const override { return m_poParent->IsWritable(); }
3867
GetDimensions() const3868 const std::vector<std::shared_ptr<GDALDimension>>& GetDimensions() const override
3869 { return m_poParent->GetDimensions(); }
3870
GetDataType() const3871 const GDALExtendedDataType &GetDataType() const override { return m_dt; }
3872
GetUnit() const3873 const std::string& GetUnit() const override { return m_poParent->GetUnit(); }
3874
GetSpatialRef() const3875 std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override { return m_poParent->GetSpatialRef(); }
3876
GetRawNoDataValue() const3877 const void* GetRawNoDataValue() const override
3878 {
3879 const void* parentNoData = m_poParent->GetRawNoDataValue();
3880 if( parentNoData == nullptr )
3881 return nullptr;
3882
3883 m_dt.FreeDynamicMemory(&m_pabyNoData[0]);
3884 memset(&m_pabyNoData[0], 0, m_dt.GetSize());
3885
3886 std::vector<std::unique_ptr<GDALEDTComponent>> comps;
3887 comps.emplace_back(std::unique_ptr<GDALEDTComponent>(
3888 new GDALEDTComponent(m_srcCompName, 0, m_dt)));
3889 auto tmpDT(GDALExtendedDataType::Create(std::string(),
3890 m_dt.GetSize(),
3891 std::move(comps)));
3892
3893 GDALExtendedDataType::CopyValue(
3894 parentNoData, m_poParent->GetDataType(),
3895 &m_pabyNoData[0], tmpDT);
3896
3897 return &m_pabyNoData[0];
3898 }
3899
GetOffset(bool * pbHasOffset,GDALDataType * peStorageType) const3900 double GetOffset(bool* pbHasOffset, GDALDataType* peStorageType) const override { return m_poParent->GetOffset(pbHasOffset, peStorageType); }
3901
GetScale(bool * pbHasScale,GDALDataType * peStorageType) const3902 double GetScale(bool* pbHasScale, GDALDataType* peStorageType) const override { return m_poParent->GetScale(pbHasScale, peStorageType); }
3903
GetBlockSize() const3904 std::vector<GUInt64> GetBlockSize() const override { return m_poParent->GetBlockSize(); }
3905 };
3906
3907 /************************************************************************/
3908 /* IRead() */
3909 /************************************************************************/
3910
IRead(const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride,const GDALExtendedDataType & bufferDataType,void * pDstBuffer) const3911 bool GDALExtractFieldMDArray::IRead(const GUInt64* arrayStartIdx,
3912 const size_t* count,
3913 const GInt64* arrayStep,
3914 const GPtrDiff_t* bufferStride,
3915 const GDALExtendedDataType& bufferDataType,
3916 void* pDstBuffer) const
3917 {
3918 std::vector<std::unique_ptr<GDALEDTComponent>> comps;
3919 comps.emplace_back(std::unique_ptr<GDALEDTComponent>(
3920 new GDALEDTComponent(m_srcCompName, 0, bufferDataType)));
3921 auto tmpDT(GDALExtendedDataType::Create(std::string(),
3922 bufferDataType.GetSize(),
3923 std::move(comps)));
3924
3925 return m_poParent->Read(arrayStartIdx, count, arrayStep, bufferStride,
3926 tmpDT, pDstBuffer);
3927 }
3928
3929 /************************************************************************/
3930 /* CreateFieldNameExtractArray() */
3931 /************************************************************************/
3932
CreateFieldNameExtractArray(const std::shared_ptr<GDALMDArray> & self,const std::string & fieldName)3933 static std::shared_ptr<GDALMDArray> CreateFieldNameExtractArray(
3934 const std::shared_ptr<GDALMDArray>& self,
3935 const std::string& fieldName)
3936 {
3937 CPLAssert( self->GetDataType().GetClass() == GEDTC_COMPOUND );
3938 const std::unique_ptr<GDALEDTComponent>* srcComp = nullptr;
3939 for( const auto& comp: self->GetDataType().GetComponents() )
3940 {
3941 if( comp->GetName() == fieldName )
3942 {
3943 srcComp = ∁
3944 break;
3945 }
3946 }
3947 if( srcComp == nullptr )
3948 {
3949 CPLError(CE_Failure, CPLE_AppDefined, "Cannot find field %s",
3950 fieldName.c_str());
3951 return nullptr;
3952 }
3953 return GDALExtractFieldMDArray::Create(self, fieldName, *srcComp);
3954 }
3955
3956 /************************************************************************/
3957 /* GetView() */
3958 /************************************************************************/
3959
3960 /** Return a view of the array using slicing or field access.
3961 *
3962 * The slice expression uses the same syntax as NumPy basic slicing and
3963 * indexing. See
3964 * https://www.numpy.org/devdocs/reference/arrays.indexing.html#basic-slicing-and-indexing
3965 * Or it can use field access by name. See
3966 * https://www.numpy.org/devdocs/reference/arrays.indexing.html#field-access
3967 *
3968 * Multiple [] bracket elements can be concatenated, with a slice expression
3969 * or field name inside each.
3970 *
3971 * For basic slicing and indexing, inside each [] bracket element, a list of
3972 * indexes that apply to successive source dimensions, can be specified, using
3973 * integer indexing (e.g. 1), range indexing (start:stop:step), ellipsis (...)
3974 * or newaxis, using a comma separator.
3975 *
3976 * Examples with a 2-dimensional array whose content is [[0,1,2,3],[4,5,6,7]].
3977 * <ul>
3978 * <li>GetView("[1][2]"): returns a 0-dimensional/scalar array with the value
3979 * at index 1 in the first dimension, and index 2 in the second dimension
3980 * from the source array. That is 5</li>
3981 * <li>GetView("[1]")->GetView("[2]"): same as above. Above is actually implemented
3982 * internally doing this intermediate slicing approach.</li>
3983 * <li>GetView("[1,2]"): same as above, but a bit more performant.</li>
3984 * <li>GetView("[1]"): returns a 1-dimensional array, sliced at index 1 in the
3985 * first dimension. That is [4,5,6,7].</li>
3986 * <li>GetView("[:,2]"): returns a 1-dimensional array, sliced at index 2 in the
3987 * second dimension. That is [2,6].</li>
3988 * <li>GetView("[:,2:3:]"): returns a 2-dimensional array, sliced at index 2 in the
3989 * second dimension. That is [[2],[6]].</li>
3990 * <li>GetView("[::,2]"): Same as above.</li>
3991 * <li>GetView("[...,2]"): same as above, in that case, since the ellipsis only
3992 * expands to one dimension here.</li>
3993 * <li>GetView("[:,::2]"): returns a 2-dimensional array, with even-indexed elements
3994 * of the second dimension. That is [[0,2],[4,6]].</li>
3995 * <li>GetView("[:,1::2]"): returns a 2-dimensional array, with odd-indexed elements
3996 * of the second dimension. That is [[1,3],[5,7]].</li>
3997 * <li>GetView("[:,1:3:]"): returns a 2-dimensional array, with elements of the
3998 * second dimension with index in the range [1,3[. That is [[1,2],[5,6]].</li>
3999 * <li>GetView("[::-1,:]"): returns a 2-dimensional array, with the values in
4000 * first dimension reversed. That is [[4,5,6,7],[0,1,2,3]].</li>
4001 * <li>GetView("[newaxis,...]"): returns a 3-dimensional array, with an addditional
4002 * dimension of size 1 put at the beginning. That is [[[0,1,2,3],[4,5,6,7]]].</li>
4003 * </ul>
4004 *
4005 * One difference with NumPy behavior is that ranges that would result in
4006 * zero elements are not allowed (dimensions of size 0 not being allowed in the
4007 * GDAL multidimensional model).
4008 *
4009 * For field access, the syntax to use is ["field_name"] or ['field_name'].
4010 * Multiple field specification is not supported currently.
4011 *
4012 * Both type of access can be combined, e.g. GetView("[1]['field_name']")
4013 *
4014 * \note When using the GDAL Python bindings, natural Python syntax can be
4015 * used. That is ar[0,::,1]["foo"] will be internally translated to
4016 * ar.GetView("[0,::,1]['foo']")
4017 * \note When using the C++ API and integer indexing only, you may use the
4018 * at(idx0, idx1, ...) method.
4019 *
4020 * The returned array holds a reference to the original one, and thus is
4021 * a view of it (not a copy). If the content of the original array changes,
4022 * the content of the view array too. When using basic slicing and indexing,
4023 * the view can be written if the underlying array is writable.
4024 *
4025 * This is the same as the C function GDALMDArrayGetView()
4026 *
4027 * @param viewExpr Expression expressing basic slicing and indexing, or field access.
4028 * @return a new array, that holds a reference to the original one, and thus is
4029 * a view of it (not a copy), or nullptr in case of error.
4030 */
GetView(const std::string & viewExpr) const4031 std::shared_ptr<GDALMDArray> GDALMDArray::GetView(const std::string& viewExpr) const
4032 {
4033 std::vector<ViewSpec> viewSpecs;
4034 return GetView(viewExpr, true, viewSpecs);
4035 }
4036
4037 //! @cond Doxygen_Suppress
GetView(const std::string & viewExpr,bool bRenameDimensions,std::vector<ViewSpec> & viewSpecs) const4038 std::shared_ptr<GDALMDArray> GDALMDArray::GetView(const std::string& viewExpr,
4039 bool bRenameDimensions,
4040 std::vector<ViewSpec>& viewSpecs) const
4041 {
4042 auto self = std::dynamic_pointer_cast<GDALMDArray>(m_pSelf.lock());
4043 if( !self )
4044 {
4045 CPLError(CE_Failure, CPLE_AppDefined,
4046 "Driver implementation issue: m_pSelf not set !");
4047 return nullptr;
4048 }
4049 std::string curExpr(viewExpr);
4050 while( true )
4051 {
4052 if( curExpr.empty() || curExpr[0] != '[' )
4053 {
4054 CPLError(CE_Failure, CPLE_AppDefined,
4055 "Slice string should start with ['");
4056 return nullptr;
4057 }
4058
4059 std::string fieldName;
4060 size_t endExpr;
4061 if( curExpr.size() > 2 &&
4062 (curExpr[1] == '"' || curExpr[1] == '\'') )
4063 {
4064 if( self->GetDataType().GetClass() != GEDTC_COMPOUND )
4065 {
4066 CPLError(CE_Failure, CPLE_AppDefined,
4067 "Field access not allowed on non-compound data type");
4068 return nullptr;
4069 }
4070 size_t idx = 2;
4071 for(; idx < curExpr.size(); idx++ )
4072 {
4073 const char ch = curExpr[idx];
4074 if( ch == curExpr[1] )
4075 break;
4076 if( ch == '\\' && idx + 1 < curExpr.size() )
4077 {
4078 fieldName += curExpr[idx+1];
4079 idx++;
4080 }
4081 else
4082 {
4083 fieldName += ch;
4084 }
4085 }
4086 if( idx + 1 >= curExpr.size() ||
4087 curExpr[idx+1] != ']' )
4088 {
4089 CPLError(CE_Failure, CPLE_AppDefined,
4090 "Invalid field access specification");
4091 return nullptr;
4092 }
4093 endExpr = idx + 1;
4094 }
4095 else
4096 {
4097 endExpr = curExpr.find(']');
4098 }
4099 if( endExpr == std::string::npos )
4100 {
4101 CPLError(CE_Failure, CPLE_AppDefined,
4102 "Missing ]'");
4103 return nullptr;
4104 }
4105 if( endExpr == 1 )
4106 {
4107 CPLError(CE_Failure, CPLE_AppDefined, "[] not allowed");
4108 return nullptr;
4109 }
4110 std::string activeSlice(curExpr.substr(1, endExpr-1));
4111
4112 if( !fieldName.empty() )
4113 {
4114 ViewSpec viewSpec;
4115 viewSpec.m_osFieldName = fieldName;
4116 viewSpecs.emplace_back(std::move(viewSpec));
4117 }
4118
4119 auto newArray = !fieldName.empty() ?
4120 CreateFieldNameExtractArray(self, fieldName):
4121 CreateSlicedArray(self, viewExpr, activeSlice, bRenameDimensions, viewSpecs);
4122
4123 if( endExpr == curExpr.size() - 1 )
4124 {
4125 return newArray;
4126 }
4127 self = std::move(newArray);
4128 curExpr = curExpr.substr(endExpr+1);
4129 }
4130 }
4131 //! @endcond
4132
GetView(const std::vector<GUInt64> & indices) const4133 std::shared_ptr<GDALMDArray> GDALMDArray::GetView(const std::vector<GUInt64>& indices) const
4134 {
4135 std::string osExpr("[");
4136 bool bFirst = true;
4137 for(const auto& idx: indices )
4138 {
4139 if( !bFirst )
4140 osExpr += ',';
4141 bFirst = false;
4142 osExpr += CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(idx));
4143 }
4144 return GetView(osExpr + ']');
4145 }
4146
4147 /************************************************************************/
4148 /* operator[] */
4149 /************************************************************************/
4150
4151 /** Return a view of the array using field access
4152 *
4153 * Equivalent of GetView("['fieldName']")
4154 *
4155 * \note When operationg on a shared_ptr, use (*array)["fieldName"] syntax.
4156 */
operator [](const std::string & fieldName) const4157 std::shared_ptr<GDALMDArray> GDALMDArray::operator[](const std::string& fieldName) const
4158 {
4159 return GetView(CPLSPrintf("['%s']",
4160 CPLString(fieldName).replaceAll('\\', "\\\\").
4161 replaceAll('\'', "\\\'").c_str()));
4162 }
4163
4164 /************************************************************************/
4165 /* GDALMDArrayTransposed */
4166 /************************************************************************/
4167
4168 class GDALMDArrayTransposed final: public GDALMDArray
4169 {
4170 private:
4171 std::shared_ptr<GDALMDArray> m_poParent{};
4172 std::vector<int> m_anMapNewAxisToOldAxis{};
4173 std::vector<std::shared_ptr<GDALDimension>> m_dims{};
4174
4175 mutable std::vector<GUInt64> m_parentStart;
4176 mutable std::vector<size_t> m_parentCount;
4177 mutable std::vector<GInt64> m_parentStep;
4178 mutable std::vector<GPtrDiff_t> m_parentStride;
4179
4180 void PrepareParentArrays(const GUInt64* arrayStartIdx,
4181 const size_t* count,
4182 const GInt64* arrayStep,
4183 const GPtrDiff_t* bufferStride) const;
4184
MappingToStr(const std::vector<int> & anMapNewAxisToOldAxis)4185 static std::string MappingToStr(const std::vector<int>& anMapNewAxisToOldAxis)
4186 {
4187 std::string ret;
4188 ret += '[';
4189 for( size_t i = 0; i < anMapNewAxisToOldAxis.size(); ++i )
4190 {
4191 if( i > 0 )
4192 ret += ',';
4193 ret += CPLSPrintf("%d", anMapNewAxisToOldAxis[i]);
4194 }
4195 ret += ']';
4196 return ret;
4197 }
4198
4199 protected:
GDALMDArrayTransposed(const std::shared_ptr<GDALMDArray> & poParent,const std::vector<int> & anMapNewAxisToOldAxis,std::vector<std::shared_ptr<GDALDimension>> && dims)4200 GDALMDArrayTransposed(
4201 const std::shared_ptr<GDALMDArray>& poParent,
4202 const std::vector<int>& anMapNewAxisToOldAxis,
4203 std::vector<std::shared_ptr<GDALDimension>>&& dims)
4204 :
4205 GDALAbstractMDArray(std::string(), "Transposed view of " + poParent->GetFullName() + " along " + MappingToStr(anMapNewAxisToOldAxis)),
4206 GDALMDArray(std::string(), "Transposed view of " + poParent->GetFullName() + " along " + MappingToStr(anMapNewAxisToOldAxis)),
4207 m_poParent(std::move(poParent)),
4208 m_anMapNewAxisToOldAxis(anMapNewAxisToOldAxis),
4209 m_dims(std::move(dims)),
4210 m_parentStart(m_poParent->GetDimensionCount()),
4211 m_parentCount(m_poParent->GetDimensionCount()),
4212 m_parentStep(m_poParent->GetDimensionCount()),
4213 m_parentStride(m_poParent->GetDimensionCount())
4214 {
4215 }
4216
4217 bool IRead(const GUInt64* arrayStartIdx,
4218 const size_t* count,
4219 const GInt64* arrayStep,
4220 const GPtrDiff_t* bufferStride,
4221 const GDALExtendedDataType& bufferDataType,
4222 void* pDstBuffer) const override;
4223
4224 bool IWrite(const GUInt64* arrayStartIdx,
4225 const size_t* count,
4226 const GInt64* arrayStep,
4227 const GPtrDiff_t* bufferStride,
4228 const GDALExtendedDataType& bufferDataType,
4229 const void* pSrcBuffer) override;
4230
4231 bool IAdviseRead(const GUInt64* arrayStartIdx,
4232 const size_t* count) const override;
4233
4234 public:
Create(const std::shared_ptr<GDALMDArray> & poParent,const std::vector<int> & anMapNewAxisToOldAxis)4235 static std::shared_ptr<GDALMDArrayTransposed> Create(
4236 const std::shared_ptr<GDALMDArray>& poParent,
4237 const std::vector<int>& anMapNewAxisToOldAxis)
4238 {
4239 const auto& parentDims(poParent->GetDimensions());
4240 std::vector<std::shared_ptr<GDALDimension>> dims;
4241 for( const auto iOldAxis: anMapNewAxisToOldAxis )
4242 {
4243 if( iOldAxis < 0 )
4244 {
4245 dims.push_back(std::make_shared<GDALDimension>(
4246 std::string(),
4247 "newaxis",
4248 std::string(),
4249 std::string(),
4250 1));
4251 }
4252 else
4253 {
4254 dims.emplace_back(parentDims[iOldAxis]);
4255 }
4256 }
4257
4258 auto newAr(std::shared_ptr<GDALMDArrayTransposed>(new GDALMDArrayTransposed(
4259 poParent, anMapNewAxisToOldAxis, std::move(dims))));
4260 newAr->SetSelf(newAr);
4261 return newAr;
4262 }
4263
IsWritable() const4264 bool IsWritable() const override { return m_poParent->IsWritable(); }
4265
GetDimensions() const4266 const std::vector<std::shared_ptr<GDALDimension>>& GetDimensions() const override { return m_dims; }
4267
GetDataType() const4268 const GDALExtendedDataType &GetDataType() const override { return m_poParent->GetDataType(); }
4269
GetUnit() const4270 const std::string& GetUnit() const override { return m_poParent->GetUnit(); }
4271
GetSpatialRef() const4272 std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
4273 {
4274 auto poSrcSRS = m_poParent->GetSpatialRef();
4275 if( !poSrcSRS )
4276 return nullptr;
4277 auto srcMapping = poSrcSRS->GetDataAxisToSRSAxisMapping();
4278 std::vector<int> dstMapping;
4279 for( int srcAxis: srcMapping )
4280 {
4281 bool bFound = false;
4282 for( size_t i = 0; i < m_anMapNewAxisToOldAxis.size(); i++ )
4283 {
4284 if( m_anMapNewAxisToOldAxis[i] == srcAxis - 1 )
4285 {
4286 dstMapping.push_back(static_cast<int>(i) + 1);
4287 bFound = true;
4288 break;
4289 }
4290 }
4291 if( !bFound )
4292 {
4293 dstMapping.push_back(0);
4294 }
4295 }
4296 auto poClone(std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone()));
4297 poClone->SetDataAxisToSRSAxisMapping(dstMapping);
4298 return poClone;
4299 }
4300
GetRawNoDataValue() const4301 const void* GetRawNoDataValue() const override { return m_poParent->GetRawNoDataValue(); }
4302
4303 // bool SetRawNoDataValue(const void* pRawNoData) override { return m_poParent->SetRawNoDataValue(pRawNoData); }
4304
GetOffset(bool * pbHasOffset,GDALDataType * peStorageType) const4305 double GetOffset(bool* pbHasOffset, GDALDataType* peStorageType) const override { return m_poParent->GetOffset(pbHasOffset, peStorageType); }
4306
GetScale(bool * pbHasScale,GDALDataType * peStorageType) const4307 double GetScale(bool* pbHasScale, GDALDataType* peStorageType) const override { return m_poParent->GetScale(pbHasScale, peStorageType); }
4308
4309 // bool SetOffset(double dfOffset) override { return m_poParent->SetOffset(dfOffset); }
4310
4311 // bool SetScale(double dfScale) override { return m_poParent->SetScale(dfScale); }
4312
GetBlockSize() const4313 std::vector<GUInt64> GetBlockSize() const override
4314 {
4315 std::vector<GUInt64> ret(GetDimensionCount());
4316 const auto parentBlockSize(m_poParent->GetBlockSize());
4317 for( size_t i = 0; i < m_anMapNewAxisToOldAxis.size(); ++i )
4318 {
4319 const auto iOldAxis = m_anMapNewAxisToOldAxis[i];
4320 if( iOldAxis >= 0 )
4321 {
4322 ret[i] = parentBlockSize[iOldAxis];
4323 }
4324 }
4325 return ret;
4326 }
4327
GetAttribute(const std::string & osName) const4328 std::shared_ptr<GDALAttribute> GetAttribute(const std::string& osName) const override
4329 { return m_poParent->GetAttribute(osName); }
4330
GetAttributes(CSLConstList papszOptions=nullptr) const4331 std::vector<std::shared_ptr<GDALAttribute>> GetAttributes(CSLConstList papszOptions = nullptr) const override
4332 { return m_poParent->GetAttributes(papszOptions); }
4333 };
4334
4335 /************************************************************************/
4336 /* PrepareParentArrays() */
4337 /************************************************************************/
4338
PrepareParentArrays(const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride) const4339 void GDALMDArrayTransposed::PrepareParentArrays(const GUInt64* arrayStartIdx,
4340 const size_t* count,
4341 const GInt64* arrayStep,
4342 const GPtrDiff_t* bufferStride) const
4343 {
4344 for( size_t i = 0; i < m_anMapNewAxisToOldAxis.size(); ++i )
4345 {
4346 const auto iOldAxis = m_anMapNewAxisToOldAxis[i];
4347 if( iOldAxis >= 0 )
4348 {
4349 m_parentStart[iOldAxis] = arrayStartIdx[i];
4350 m_parentCount[iOldAxis] = count[i];
4351 if( arrayStep )
4352 {
4353 m_parentStep[iOldAxis] = arrayStep[i];
4354 }
4355 if( bufferStride )
4356 {
4357 m_parentStride[iOldAxis] = bufferStride[i];
4358 }
4359 }
4360 }
4361 }
4362
4363 /************************************************************************/
4364 /* IRead() */
4365 /************************************************************************/
4366
IRead(const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride,const GDALExtendedDataType & bufferDataType,void * pDstBuffer) const4367 bool GDALMDArrayTransposed::IRead(const GUInt64* arrayStartIdx,
4368 const size_t* count,
4369 const GInt64* arrayStep,
4370 const GPtrDiff_t* bufferStride,
4371 const GDALExtendedDataType& bufferDataType,
4372 void* pDstBuffer) const
4373 {
4374 PrepareParentArrays(arrayStartIdx, count, arrayStep, bufferStride);
4375 return m_poParent->Read(m_parentStart.data(),
4376 m_parentCount.data(),
4377 m_parentStep.data(),
4378 m_parentStride.data(),
4379 bufferDataType,
4380 pDstBuffer);
4381 }
4382
4383 /************************************************************************/
4384 /* IWrite() */
4385 /************************************************************************/
4386
IWrite(const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride,const GDALExtendedDataType & bufferDataType,const void * pSrcBuffer)4387 bool GDALMDArrayTransposed::IWrite(const GUInt64* arrayStartIdx,
4388 const size_t* count,
4389 const GInt64* arrayStep,
4390 const GPtrDiff_t* bufferStride,
4391 const GDALExtendedDataType& bufferDataType,
4392 const void* pSrcBuffer)
4393 {
4394 PrepareParentArrays(arrayStartIdx, count, arrayStep, bufferStride);
4395 return m_poParent->Write(m_parentStart.data(),
4396 m_parentCount.data(),
4397 m_parentStep.data(),
4398 m_parentStride.data(),
4399 bufferDataType,
4400 pSrcBuffer);
4401 }
4402
4403 /************************************************************************/
4404 /* IAdviseRead() */
4405 /************************************************************************/
4406
IAdviseRead(const GUInt64 * arrayStartIdx,const size_t * count) const4407 bool GDALMDArrayTransposed::IAdviseRead(const GUInt64* arrayStartIdx,
4408 const size_t* count) const
4409 {
4410 PrepareParentArrays(arrayStartIdx, count, nullptr, nullptr);
4411 return m_poParent->AdviseRead(m_parentStart.data(),
4412 m_parentCount.data());
4413 }
4414
4415 /************************************************************************/
4416 /* Transpose() */
4417 /************************************************************************/
4418
4419 /** Return a view of the array whose axis have been reordered.
4420 *
4421 * The anMapNewAxisToOldAxis parameter should contain all the values between 0
4422 * and GetDimensionCount() - 1, and each only once.
4423 * -1 can be used as a special index value to ask for the insertion of a new
4424 * axis of size 1.
4425 * The new array will have anMapNewAxisToOldAxis.size() axis, and if i is the
4426 * index of one of its dimension, it corresponds to the axis of index
4427 * anMapNewAxisToOldAxis[i] from the current array.
4428 *
4429 * This is similar to the numpy.transpose() method
4430 *
4431 * The returned array holds a reference to the original one, and thus is
4432 * a view of it (not a copy). If the content of the original array changes,
4433 * the content of the view array too. The view can be written if the underlying
4434 * array is writable.
4435 *
4436 * Note that I/O performance in such a transposed view might be poor.
4437 *
4438 * This is the same as the C function GDALMDArrayTranspose().
4439 *
4440 * @return a new array, that holds a reference to the original one, and thus is
4441 * a view of it (not a copy), or nullptr in case of error.
4442 */
Transpose(const std::vector<int> & anMapNewAxisToOldAxis) const4443 std::shared_ptr<GDALMDArray> GDALMDArray::Transpose(
4444 const std::vector<int>& anMapNewAxisToOldAxis) const
4445 {
4446 auto self = std::dynamic_pointer_cast<GDALMDArray>(m_pSelf.lock());
4447 if( !self )
4448 {
4449 CPLError(CE_Failure, CPLE_AppDefined,
4450 "Driver implementation issue: m_pSelf not set !");
4451 return nullptr;
4452 }
4453 const int nDims = static_cast<int>(GetDimensionCount());
4454 std::vector<bool> alreadyUsedOldAxis(nDims, false);
4455 int nCountOldAxis = 0;
4456 for( const auto iOldAxis: anMapNewAxisToOldAxis )
4457 {
4458 if( iOldAxis < -1 || iOldAxis >= nDims )
4459 {
4460 CPLError(CE_Failure, CPLE_AppDefined, "Invalid axis number");
4461 return nullptr;
4462 }
4463 if( iOldAxis >= 0 )
4464 {
4465 if( alreadyUsedOldAxis[iOldAxis] )
4466 {
4467 CPLError(CE_Failure, CPLE_AppDefined,
4468 "Axis %d is repeated", iOldAxis);
4469 return nullptr;
4470 }
4471 alreadyUsedOldAxis[iOldAxis] = true;
4472 nCountOldAxis ++;
4473 }
4474 }
4475 if( nCountOldAxis != nDims )
4476 {
4477 CPLError(CE_Failure, CPLE_AppDefined,
4478 "One or several original axis missing");
4479 return nullptr;
4480 }
4481 return GDALMDArrayTransposed::Create(self, anMapNewAxisToOldAxis);
4482 }
4483
4484 /************************************************************************/
4485 /* IRead() */
4486 /************************************************************************/
4487
IRead(const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride,const GDALExtendedDataType & bufferDataType,void * pDstBuffer) const4488 bool GDALMDArrayUnscaled::IRead(const GUInt64* arrayStartIdx,
4489 const size_t* count,
4490 const GInt64* arrayStep,
4491 const GPtrDiff_t* bufferStride,
4492 const GDALExtendedDataType& bufferDataType,
4493 void* pDstBuffer) const
4494 {
4495 const double dfScale = m_poParent->GetScale();
4496 const double dfOffset = m_poParent->GetOffset();
4497 const bool bDTIsComplex = m_dt.GetNumericDataType() == GDT_CFloat64;
4498 const size_t nDTSize = m_dt.GetSize();
4499 const bool bTempBufferNeeded = ( m_dt != bufferDataType );
4500
4501 double adfSrcNoData[2] = { 0, 0 };
4502 if( m_bHasNoData )
4503 {
4504 GDALExtendedDataType::CopyValue(m_poParent->GetRawNoDataValue(),
4505 m_poParent->GetDataType(),
4506 &adfSrcNoData[0], m_dt);
4507 }
4508
4509 const auto nDims = GetDimensions().size();
4510 if( nDims == 0 )
4511 {
4512 double adfVal[2];
4513 if( !m_poParent->Read(arrayStartIdx, count, arrayStep, bufferStride,
4514 m_dt, &adfVal[0]) )
4515 {
4516 return false;
4517 }
4518 if( !m_bHasNoData || adfVal[0] != adfSrcNoData[0] )
4519 {
4520 adfVal[0] = adfVal[0] * dfScale + dfOffset;
4521 if( bDTIsComplex )
4522 {
4523 adfVal[1] = adfVal[1] * dfScale + dfOffset;
4524 }
4525 GDALExtendedDataType::CopyValue(&adfVal[0], m_dt,
4526 pDstBuffer, bufferDataType);
4527 }
4528 else
4529 {
4530 GDALExtendedDataType::CopyValue(&m_adfNoData[0], m_dt,
4531 pDstBuffer, bufferDataType);
4532 }
4533 return true;
4534 }
4535
4536 std::vector<GPtrDiff_t> actualBufferStrideVector;
4537 const GPtrDiff_t* actualBufferStridePtr = bufferStride;
4538 void* pTempBuffer = pDstBuffer;
4539 if( bTempBufferNeeded )
4540 {
4541 size_t nElts = 1;
4542 actualBufferStrideVector.resize(nDims);
4543 for( size_t i = 0; i < nDims; i++ )
4544 nElts *= count[i];
4545 actualBufferStrideVector.back() = 1;
4546 for( size_t i = nDims - 1; i > 0; )
4547 {
4548 --i;
4549 actualBufferStrideVector[i] =
4550 actualBufferStrideVector[i+1] * count[i+1];
4551 }
4552 actualBufferStridePtr = actualBufferStrideVector.data();
4553 pTempBuffer = VSI_MALLOC2_VERBOSE(nDTSize, nElts);
4554 if( !pTempBuffer )
4555 return false;
4556 }
4557 if( !m_poParent->Read(arrayStartIdx,
4558 count,
4559 arrayStep,
4560 actualBufferStridePtr,
4561 m_dt,
4562 pTempBuffer) )
4563 {
4564 if( bTempBufferNeeded )
4565 VSIFree(pTempBuffer);
4566 return false;
4567 }
4568
4569 struct Stack
4570 {
4571 size_t nIters = 0;
4572 double* src_ptr = nullptr;
4573 GByte* dst_ptr = nullptr;
4574 GPtrDiff_t src_inc_offset = 0;
4575 GPtrDiff_t dst_inc_offset = 0;
4576 };
4577 std::vector<Stack> stack(nDims);
4578 const size_t nBufferDTSize = bufferDataType.GetSize();
4579 for( size_t i = 0; i < nDims; i++ )
4580 {
4581 stack[i].src_inc_offset = actualBufferStridePtr[i] *
4582 (bDTIsComplex ? 2 : 1);
4583 stack[i].dst_inc_offset = static_cast<GPtrDiff_t>(
4584 bufferStride[i] * nBufferDTSize);
4585 }
4586 stack[0].src_ptr = static_cast<double*>(pTempBuffer);
4587 stack[0].dst_ptr = static_cast<GByte*>(pDstBuffer);
4588
4589 size_t dimIdx = 0;
4590 const size_t nDimsMinus1 = nDims - 1;
4591 GByte abyDstNoData[16];
4592 CPLAssert(nBufferDTSize <= sizeof(abyDstNoData));
4593 GDALExtendedDataType::CopyValue(&m_adfNoData[0], m_dt,
4594 abyDstNoData, bufferDataType);
4595
4596 lbl_next_depth:
4597 if( dimIdx == nDimsMinus1 )
4598 {
4599 auto nIters = count[dimIdx];
4600 double* padfVal = stack[dimIdx].src_ptr;
4601 GByte* dst_ptr = stack[dimIdx].dst_ptr;
4602 while(true)
4603 {
4604 if( !m_bHasNoData || padfVal[0] != adfSrcNoData[0] )
4605 {
4606 padfVal[0] = padfVal[0] * dfScale + dfOffset;
4607 if( bDTIsComplex )
4608 {
4609 padfVal[1] = padfVal[1] * dfScale + dfOffset;
4610 }
4611 if( bTempBufferNeeded )
4612 {
4613 GDALExtendedDataType::CopyValue(&padfVal[0], m_dt,
4614 dst_ptr,
4615 bufferDataType);
4616 }
4617 }
4618 else
4619 {
4620 memcpy(dst_ptr, abyDstNoData, nBufferDTSize);
4621 }
4622
4623 if( (--nIters) == 0 )
4624 break;
4625 padfVal += stack[dimIdx].src_inc_offset;
4626 dst_ptr += stack[dimIdx].dst_inc_offset;
4627 }
4628 }
4629 else
4630 {
4631 stack[dimIdx].nIters = count[dimIdx];
4632 while(true)
4633 {
4634 dimIdx ++;
4635 stack[dimIdx].src_ptr = stack[dimIdx-1].src_ptr;
4636 stack[dimIdx].dst_ptr = stack[dimIdx-1].dst_ptr;
4637 goto lbl_next_depth;
4638 lbl_return_to_caller:
4639 dimIdx --;
4640 if( (--stack[dimIdx].nIters) == 0 )
4641 break;
4642 stack[dimIdx].src_ptr += stack[dimIdx].src_inc_offset;
4643 stack[dimIdx].dst_ptr += stack[dimIdx].dst_inc_offset;
4644 }
4645 }
4646 if( dimIdx > 0 )
4647 goto lbl_return_to_caller;
4648
4649 if( bTempBufferNeeded )
4650 VSIFree(pTempBuffer);
4651 return true;
4652 }
4653
4654 /************************************************************************/
4655 /* IWrite() */
4656 /************************************************************************/
4657
IWrite(const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride,const GDALExtendedDataType & bufferDataType,const void * pSrcBuffer)4658 bool GDALMDArrayUnscaled::IWrite(const GUInt64* arrayStartIdx,
4659 const size_t* count,
4660 const GInt64* arrayStep,
4661 const GPtrDiff_t* bufferStride,
4662 const GDALExtendedDataType& bufferDataType,
4663 const void* pSrcBuffer)
4664 {
4665 const double dfScale = m_poParent->GetScale();
4666 const double dfOffset = m_poParent->GetOffset();
4667 const bool bDTIsComplex = m_dt.GetNumericDataType() == GDT_CFloat64;
4668 const size_t nDTSize = m_dt.GetSize();
4669 CPLAssert( nDTSize == 8 || nDTSize == 16 );
4670 const bool bIsBufferDataTypeNativeDataType = ( m_dt == bufferDataType );
4671 const bool bSelfAndParentHaveNoData =
4672 m_bHasNoData && m_poParent->GetRawNoDataValue() != nullptr;
4673
4674 double adfSrcNoData[2] = { 0, 0 };
4675 if( bSelfAndParentHaveNoData )
4676 {
4677 GDALExtendedDataType::CopyValue(m_poParent->GetRawNoDataValue(),
4678 m_poParent->GetDataType(),
4679 &adfSrcNoData[0], m_dt);
4680 }
4681
4682 const auto nDims = GetDimensions().size();
4683 if( nDims == 0 )
4684 {
4685 double adfVal[2];
4686 GDALExtendedDataType::CopyValue(pSrcBuffer, bufferDataType,
4687 &adfVal[0], m_dt);
4688 if( bSelfAndParentHaveNoData &&
4689 (std::isnan(adfVal[0]) || adfVal[0] == m_adfNoData[0]) )
4690 {
4691 return m_poParent->Write(arrayStartIdx, count, arrayStep, bufferStride,
4692 m_poParent->GetDataType(),
4693 m_poParent->GetRawNoDataValue());
4694 }
4695 else
4696 {
4697 adfVal[0] = (adfVal[0] - dfOffset) / dfScale;
4698 if( bDTIsComplex )
4699 {
4700 adfVal[1] = (adfVal[1] - dfOffset) / dfScale;
4701 }
4702 return m_poParent->Write(arrayStartIdx, count, arrayStep, bufferStride,
4703 m_dt, &adfVal[0]);
4704 }
4705 }
4706
4707 std::vector<GPtrDiff_t> tmpBufferStrideVector;
4708 size_t nElts = 1;
4709 tmpBufferStrideVector.resize(nDims);
4710 for( size_t i = 0; i < nDims; i++ )
4711 nElts *= count[i];
4712 tmpBufferStrideVector.back() = 1;
4713 for( size_t i = nDims - 1; i > 0; )
4714 {
4715 --i;
4716 tmpBufferStrideVector[i] =
4717 tmpBufferStrideVector[i+1] * count[i+1];
4718 }
4719 const GPtrDiff_t* tmpBufferStridePtr = tmpBufferStrideVector.data();
4720 void* pTempBuffer = VSI_MALLOC2_VERBOSE(nDTSize, nElts);
4721 if( !pTempBuffer )
4722 return false;
4723
4724 struct Stack
4725 {
4726 size_t nIters = 0;
4727 double* dst_ptr = nullptr;
4728 const GByte* src_ptr = nullptr;
4729 GPtrDiff_t src_inc_offset = 0;
4730 GPtrDiff_t dst_inc_offset = 0;
4731 };
4732 std::vector<Stack> stack(nDims);
4733 const size_t nBufferDTSize = bufferDataType.GetSize();
4734 for( size_t i = 0; i < nDims; i++ )
4735 {
4736 stack[i].dst_inc_offset = tmpBufferStridePtr[i] *
4737 (bDTIsComplex ? 2 : 1);
4738 stack[i].src_inc_offset = static_cast<GPtrDiff_t>(
4739 bufferStride[i] * nBufferDTSize);
4740 }
4741 stack[0].dst_ptr = static_cast<double*>(pTempBuffer);
4742 stack[0].src_ptr = static_cast<const GByte*>(pSrcBuffer);
4743
4744 size_t dimIdx = 0;
4745 const size_t nDimsMinus1 = nDims - 1;
4746
4747 lbl_next_depth:
4748 if( dimIdx == nDimsMinus1 )
4749 {
4750 auto nIters = count[dimIdx];
4751 double* dst_ptr = stack[dimIdx].dst_ptr;
4752 const GByte* src_ptr = stack[dimIdx].src_ptr;
4753 while(true)
4754 {
4755 double adfVal[2];
4756 const double* padfSrcVal;
4757 if( bIsBufferDataTypeNativeDataType )
4758 {
4759 padfSrcVal = reinterpret_cast<const double*>(src_ptr);
4760 }
4761 else
4762 {
4763 GDALExtendedDataType::CopyValue(src_ptr, bufferDataType,
4764 &adfVal[0], m_dt);
4765 padfSrcVal = adfVal;
4766 }
4767
4768 if( bSelfAndParentHaveNoData &&
4769 (std::isnan(padfSrcVal[0]) || padfSrcVal[0] == m_adfNoData[0]) )
4770 {
4771 dst_ptr[0] = adfSrcNoData[0];
4772 if( bDTIsComplex )
4773 {
4774 dst_ptr[1] = adfSrcNoData[1];
4775 }
4776 }
4777 else
4778 {
4779 dst_ptr[0] = (padfSrcVal[0] - dfOffset) / dfScale;
4780 if( bDTIsComplex )
4781 {
4782 dst_ptr[1] = (padfSrcVal[1] - dfOffset) / dfScale;
4783 }
4784 }
4785
4786 if( (--nIters) == 0 )
4787 break;
4788 dst_ptr += stack[dimIdx].dst_inc_offset;
4789 src_ptr += stack[dimIdx].src_inc_offset;
4790 }
4791 }
4792 else
4793 {
4794 stack[dimIdx].nIters = count[dimIdx];
4795 while(true)
4796 {
4797 dimIdx ++;
4798 stack[dimIdx].src_ptr = stack[dimIdx-1].src_ptr;
4799 stack[dimIdx].dst_ptr = stack[dimIdx-1].dst_ptr;
4800 goto lbl_next_depth;
4801 lbl_return_to_caller:
4802 dimIdx --;
4803 if( (--stack[dimIdx].nIters) == 0 )
4804 break;
4805 stack[dimIdx].src_ptr += stack[dimIdx].src_inc_offset;
4806 stack[dimIdx].dst_ptr += stack[dimIdx].dst_inc_offset;
4807 }
4808 }
4809 if( dimIdx > 0 )
4810 goto lbl_return_to_caller;
4811
4812 // If the parent array is not double/complex-double, then convert the
4813 // values to it, before calling Write(), as some implementations can be
4814 // very slow when doing the type conversion.
4815 const auto& eParentDT = m_poParent->GetDataType();
4816 const size_t nParentDTSize = eParentDT.GetSize();
4817 if( nParentDTSize <= nDTSize / 2 )
4818 {
4819 // Copy in-place by making sure that source and target do not overlap
4820 const auto eNumericDT = m_dt.GetNumericDataType();
4821 const auto eParentNumericDT = eParentDT.GetNumericDataType();
4822
4823 // Copy first element
4824 {
4825 std::vector<GByte> abyTemp(nParentDTSize);
4826 GDALCopyWords64( static_cast<GByte*>(pTempBuffer),
4827 eNumericDT, static_cast<int>(nDTSize),
4828 &abyTemp[0],
4829 eParentNumericDT, static_cast<int>(nParentDTSize),
4830 1 );
4831 memcpy( pTempBuffer, abyTemp.data(), abyTemp.size() );
4832 }
4833 // Remaining elements
4834 for( size_t i = 1; i < nElts; ++i )
4835 {
4836 GDALCopyWords( static_cast<GByte*>(pTempBuffer) + i * nDTSize,
4837 eNumericDT, 0,
4838 static_cast<GByte*>(pTempBuffer) + i * nParentDTSize,
4839 eParentNumericDT, 0,
4840 1 );
4841 }
4842 }
4843
4844 const bool ret = m_poParent->Write(arrayStartIdx,
4845 count,
4846 arrayStep,
4847 tmpBufferStridePtr,
4848 eParentDT,
4849 pTempBuffer);
4850
4851 VSIFree(pTempBuffer);
4852 return ret;
4853 }
4854
4855 /************************************************************************/
4856 /* GetUnscaled() */
4857 /************************************************************************/
4858
4859 /** Return an array that is the unscaled version of the current one.
4860 *
4861 * That is each value of the unscaled array will be
4862 * unscaled_value = raw_value * GetScale() + GetOffset()
4863 *
4864 * Starting with GDAL 3.3, the Write() method is implemented and will convert
4865 * from unscaled values to raw values.
4866 *
4867 * This is the same as the C function GDALMDArrayGetUnscaled().
4868 *
4869 * @return a new array, that holds a reference to the original one, and thus is
4870 * a view of it (not a copy), or nullptr in case of error.
4871 */
GetUnscaled() const4872 std::shared_ptr<GDALMDArray> GDALMDArray::GetUnscaled() const
4873 {
4874 auto self = std::dynamic_pointer_cast<GDALMDArray>(m_pSelf.lock());
4875 if( !self )
4876 {
4877 CPLError(CE_Failure, CPLE_AppDefined,
4878 "Driver implementation issue: m_pSelf not set !");
4879 return nullptr;
4880 }
4881 if( GetDataType().GetClass() != GEDTC_NUMERIC )
4882 {
4883 CPLError(CE_Failure, CPLE_AppDefined,
4884 "GetUnscaled() only supports numeric data type");
4885 return nullptr;
4886 }
4887 const double dfScale = GetScale();
4888 const double dfOffset = GetOffset();
4889 if( dfScale == 1.0 && dfOffset == 0.0 )
4890 return self;
4891
4892 return GDALMDArrayUnscaled::Create(self);
4893 }
4894
4895 /************************************************************************/
4896 /* GDALMDArrayTransposed */
4897 /************************************************************************/
4898
4899 class GDALMDArrayMask final: public GDALMDArray
4900 {
4901 private:
4902 std::shared_ptr<GDALMDArray> m_poParent{};
4903 GDALExtendedDataType m_dt {GDALExtendedDataType::Create(GDT_Byte) };
4904
4905 template<typename Type> void ReadInternal(const size_t* count,
4906 const GPtrDiff_t* bufferStride,
4907 const GDALExtendedDataType& bufferDataType,
4908 void* pDstBuffer,
4909 const void* pTempBuffer,
4910 const GDALExtendedDataType& oTmpBufferDT,
4911 const std::vector<GPtrDiff_t>& tmpBufferStrideVector,
4912 bool bHasMissingValue, double dfMissingValue,
4913 bool bHasFillValue, double dfFillValue,
4914 bool bHasValidMin, double dfValidMin,
4915 bool bHasValidMax, double dfValidMax) const;
4916
4917 protected:
GDALMDArrayMask(const std::shared_ptr<GDALMDArray> & poParent)4918 explicit GDALMDArrayMask(const std::shared_ptr<GDALMDArray>& poParent):
4919 GDALAbstractMDArray(std::string(), "Mask of " + poParent->GetFullName()),
4920 GDALMDArray(std::string(), "Mask of " + poParent->GetFullName()),
4921 m_poParent(std::move(poParent))
4922 {
4923 }
4924
4925 bool IRead(const GUInt64* arrayStartIdx,
4926 const size_t* count,
4927 const GInt64* arrayStep,
4928 const GPtrDiff_t* bufferStride,
4929 const GDALExtendedDataType& bufferDataType,
4930 void* pDstBuffer) const override;
4931
IAdviseRead(const GUInt64 * arrayStartIdx,const size_t * count) const4932 bool IAdviseRead(const GUInt64* arrayStartIdx,
4933 const size_t* count) const override
4934 { return m_poParent->AdviseRead(arrayStartIdx, count); }
4935
4936 public:
Create(const std::shared_ptr<GDALMDArray> & poParent)4937 static std::shared_ptr<GDALMDArrayMask> Create(
4938 const std::shared_ptr<GDALMDArray>& poParent)
4939 {
4940 auto newAr(std::shared_ptr<GDALMDArrayMask>(new GDALMDArrayMask(
4941 poParent)));
4942 newAr->SetSelf(newAr);
4943 return newAr;
4944 }
4945
IsWritable() const4946 bool IsWritable() const override { return false; }
4947
GetDimensions() const4948 const std::vector<std::shared_ptr<GDALDimension>>& GetDimensions() const override { return m_poParent->GetDimensions(); }
4949
GetDataType() const4950 const GDALExtendedDataType &GetDataType() const override { return m_dt; }
4951
GetSpatialRef() const4952 std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override { return m_poParent->GetSpatialRef(); }
4953
GetBlockSize() const4954 std::vector<GUInt64> GetBlockSize() const override { return m_poParent->GetBlockSize(); }
4955 };
4956
4957 /************************************************************************/
4958 /* IRead() */
4959 /************************************************************************/
4960
IRead(const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride,const GDALExtendedDataType & bufferDataType,void * pDstBuffer) const4961 bool GDALMDArrayMask::IRead(const GUInt64* arrayStartIdx,
4962 const size_t* count,
4963 const GInt64* arrayStep,
4964 const GPtrDiff_t* bufferStride,
4965 const GDALExtendedDataType& bufferDataType,
4966 void* pDstBuffer) const
4967 {
4968 size_t nElts = 1;
4969 const size_t nDims = GetDimensionCount();
4970 std::vector<GPtrDiff_t> tmpBufferStrideVector(nDims);
4971 for( size_t i = 0; i < nDims; i++ )
4972 nElts *= count[i];
4973 if( nDims > 0 )
4974 {
4975 tmpBufferStrideVector.back() = 1;
4976 for( size_t i = nDims - 1; i > 0; )
4977 {
4978 --i;
4979 tmpBufferStrideVector[i] =
4980 tmpBufferStrideVector[i+1] * count[i+1];
4981 }
4982 }
4983
4984 const auto GetSingleValNumericAttr = [this]
4985 (const char* pszAttrName, bool& bHasVal, double& dfVal)
4986 {
4987 auto poAttr = m_poParent->GetAttribute(pszAttrName);
4988 if( poAttr && poAttr->GetDataType().GetClass() == GEDTC_NUMERIC )
4989 {
4990 const auto anDimSizes = poAttr->GetDimensionsSize();
4991 if( anDimSizes.empty() ||
4992 (anDimSizes.size() == 1 && anDimSizes[0] == 1) )
4993 {
4994 bHasVal = true;
4995 dfVal = poAttr->ReadAsDouble();
4996 }
4997 }
4998 };
4999
5000 double dfMissingValue = 0.0;
5001 bool bHasMissingValue = false;
5002 GetSingleValNumericAttr("missing_value", bHasMissingValue, dfMissingValue);
5003
5004 double dfFillValue = 0.0;
5005 bool bHasFillValue = false;
5006 GetSingleValNumericAttr("_FillValue", bHasFillValue, dfFillValue);
5007
5008 double dfValidMin = 0.0;
5009 bool bHasValidMin = false;
5010 GetSingleValNumericAttr("valid_min", bHasValidMin, dfValidMin);
5011
5012 double dfValidMax = 0.0;
5013 bool bHasValidMax = false;
5014 GetSingleValNumericAttr("valid_max", bHasValidMax, dfValidMax);
5015
5016 {
5017 auto poValidRange = m_poParent->GetAttribute("valid_range");
5018 if( poValidRange && poValidRange->GetDimensionsSize().size() == 1 &&
5019 poValidRange->GetDimensionsSize()[0] == 2 &&
5020 poValidRange->GetDataType().GetClass() == GEDTC_NUMERIC )
5021 {
5022 bHasValidMin = true;
5023 bHasValidMax = true;
5024 auto vals = poValidRange->ReadAsDoubleArray();
5025 CPLAssert(vals.size() == 2);
5026 dfValidMin = vals[0];
5027 dfValidMax = vals[1];
5028 }
5029 }
5030
5031 /* Optimized case: if we are an integer data type and that there is no */
5032 /* attribute that can be used to set mask = 0, then fill the mask buffer */
5033 /* directly */
5034 if( !bHasMissingValue && !bHasFillValue && !bHasValidMin && !bHasValidMax &&
5035 m_poParent->GetRawNoDataValue() == nullptr &&
5036 GDALDataTypeIsInteger(m_poParent->GetDataType().GetNumericDataType()) )
5037 {
5038 if( bufferDataType == m_dt ) // Byte case
5039 {
5040 bool bContiguous = true;
5041 for( size_t i = 0; i < nDims; i++)
5042 {
5043 if( bufferStride[i] != tmpBufferStrideVector[i] )
5044 {
5045 bContiguous = false;
5046 break;
5047 }
5048 }
5049 if( bContiguous )
5050 {
5051 // CPLDebug("GDAL", "GetMask(): contiguous case");
5052 memset(pDstBuffer, 1, nElts);
5053 return true;
5054 }
5055 }
5056
5057 struct Stack
5058 {
5059 size_t nIters = 0;
5060 GByte* dst_ptr = nullptr;
5061 GPtrDiff_t dst_inc_offset = 0;
5062 };
5063 std::vector<Stack> stack(std::max(static_cast<size_t>(1), nDims));
5064 const size_t nBufferDTSize = bufferDataType.GetSize();
5065 for( size_t i = 0; i < nDims; i++ )
5066 {
5067 stack[i].dst_inc_offset = static_cast<GPtrDiff_t>(
5068 bufferStride[i] * nBufferDTSize);
5069 }
5070 stack[0].dst_ptr = static_cast<GByte*>(pDstBuffer);
5071
5072 size_t dimIdx = 0;
5073 const size_t nDimsMinus1 = nDims > 0 ? nDims - 1 : 0;
5074 const bool bBufferDataTypeIsByte = bufferDataType == m_dt;
5075 GByte abyOne[16]; // 16 is sizeof GDT_CFloat64
5076 CPLAssert(nBufferDTSize <= 16);
5077 const GByte flag = 1;
5078 // Coverity misses that m_dt is of type Byte
5079 // coverity[overrun-buffer-val]
5080 GDALExtendedDataType::CopyValue(&flag, m_dt, abyOne, bufferDataType);
5081
5082 lbl_next_depth:
5083 if( dimIdx == nDimsMinus1 )
5084 {
5085 auto nIters = nDims > 0 ? count[dimIdx] : 1;
5086 GByte* dst_ptr = stack[dimIdx].dst_ptr;
5087
5088 while(true)
5089 {
5090 if( bBufferDataTypeIsByte )
5091 {
5092 *dst_ptr = flag;
5093 }
5094 else
5095 {
5096 memcpy(dst_ptr, abyOne, nBufferDTSize);
5097 }
5098
5099 if( (--nIters) == 0 )
5100 break;
5101 dst_ptr += stack[dimIdx].dst_inc_offset;
5102 }
5103 }
5104 else
5105 {
5106 stack[dimIdx].nIters = count[dimIdx];
5107 while(true)
5108 {
5109 dimIdx ++;
5110 stack[dimIdx].dst_ptr = stack[dimIdx-1].dst_ptr;
5111 goto lbl_next_depth;
5112 lbl_return_to_caller:
5113 dimIdx --;
5114 if( (--stack[dimIdx].nIters) == 0 )
5115 break;
5116 stack[dimIdx].dst_ptr += stack[dimIdx].dst_inc_offset;
5117 }
5118 }
5119 if( dimIdx > 0 )
5120 goto lbl_return_to_caller;
5121
5122 return true;
5123 }
5124
5125 const auto oTmpBufferDT = GDALDataTypeIsComplex(
5126 m_poParent->GetDataType().GetNumericDataType()) ?
5127 GDALExtendedDataType::Create(GDT_Float64) :
5128 m_poParent->GetDataType();
5129 const size_t nTmpBufferDTSize = oTmpBufferDT.GetSize();
5130 void *pTempBuffer = VSI_MALLOC2_VERBOSE(nTmpBufferDTSize, nElts);
5131 if( !pTempBuffer )
5132 return false;
5133 if( !m_poParent->Read(arrayStartIdx,
5134 count,
5135 arrayStep,
5136 tmpBufferStrideVector.data(),
5137 oTmpBufferDT,
5138 pTempBuffer) )
5139 {
5140 VSIFree(pTempBuffer);
5141 return false;
5142 }
5143
5144 switch( oTmpBufferDT.GetNumericDataType() )
5145 {
5146 case GDT_Byte:
5147 ReadInternal<GByte>(count, bufferStride, bufferDataType, pDstBuffer,
5148 pTempBuffer, oTmpBufferDT, tmpBufferStrideVector,
5149 bHasMissingValue, dfMissingValue,
5150 bHasFillValue, dfFillValue,
5151 bHasValidMin, dfValidMin,
5152 bHasValidMax, dfValidMax);
5153 break;
5154
5155 case GDT_UInt16:
5156 ReadInternal<GUInt16>(count, bufferStride, bufferDataType, pDstBuffer,
5157 pTempBuffer, oTmpBufferDT, tmpBufferStrideVector,
5158 bHasMissingValue, dfMissingValue,
5159 bHasFillValue, dfFillValue,
5160 bHasValidMin, dfValidMin,
5161 bHasValidMax, dfValidMax);
5162 break;
5163
5164 case GDT_Int16:
5165 ReadInternal<GInt16>(count, bufferStride, bufferDataType, pDstBuffer,
5166 pTempBuffer, oTmpBufferDT, tmpBufferStrideVector,
5167 bHasMissingValue, dfMissingValue,
5168 bHasFillValue, dfFillValue,
5169 bHasValidMin, dfValidMin,
5170 bHasValidMax, dfValidMax);
5171 break;
5172
5173 case GDT_UInt32:
5174 ReadInternal<GUInt32>(count, bufferStride, bufferDataType, pDstBuffer,
5175 pTempBuffer, oTmpBufferDT, tmpBufferStrideVector,
5176 bHasMissingValue, dfMissingValue,
5177 bHasFillValue, dfFillValue,
5178 bHasValidMin, dfValidMin,
5179 bHasValidMax, dfValidMax);
5180 break;
5181
5182 case GDT_Int32:
5183 ReadInternal<GInt32>(count, bufferStride, bufferDataType, pDstBuffer,
5184 pTempBuffer, oTmpBufferDT, tmpBufferStrideVector,
5185 bHasMissingValue, dfMissingValue,
5186 bHasFillValue, dfFillValue,
5187 bHasValidMin, dfValidMin,
5188 bHasValidMax, dfValidMax);
5189 break;
5190
5191 case GDT_Float32:
5192 ReadInternal<float>(count, bufferStride, bufferDataType, pDstBuffer,
5193 pTempBuffer, oTmpBufferDT, tmpBufferStrideVector,
5194 bHasMissingValue, dfMissingValue,
5195 bHasFillValue, dfFillValue,
5196 bHasValidMin, dfValidMin,
5197 bHasValidMax, dfValidMax);
5198 break;
5199
5200 default:
5201 CPLAssert(oTmpBufferDT.GetNumericDataType() == GDT_Float64);
5202 ReadInternal<double>(count, bufferStride, bufferDataType, pDstBuffer,
5203 pTempBuffer, oTmpBufferDT, tmpBufferStrideVector,
5204 bHasMissingValue, dfMissingValue,
5205 bHasFillValue, dfFillValue,
5206 bHasValidMin, dfValidMin,
5207 bHasValidMax, dfValidMax);
5208 break;
5209
5210 }
5211
5212 VSIFree(pTempBuffer);
5213
5214 return true;
5215 }
5216
5217 /************************************************************************/
5218 /* IsValidForDT() */
5219 /************************************************************************/
5220
IsValidForDT(double dfVal)5221 template<typename Type> static bool IsValidForDT(double dfVal)
5222 {
5223 if( std::isnan(dfVal) )
5224 return false;
5225 if( dfVal < static_cast<double>(std::numeric_limits<Type>::lowest()) )
5226 return false;
5227 if( dfVal > static_cast<double>(std::numeric_limits<Type>::max()) )
5228 return false;
5229 return static_cast<double>(static_cast<Type>(dfVal)) == dfVal;
5230 }
5231
IsValidForDT(double)5232 template<> bool IsValidForDT<double>(double)
5233 {
5234 return true;
5235 }
5236
5237 /************************************************************************/
5238 /* IsNan() */
5239 /************************************************************************/
5240
IsNan(Type)5241 template<typename Type> inline bool IsNan(Type)
5242 {
5243 return false;
5244 }
5245
IsNan(double val)5246 template<> bool IsNan<double>(double val)
5247 {
5248 return std::isnan(val);
5249 }
5250
IsNan(float val)5251 template<> bool IsNan<float>(float val)
5252 {
5253 return std::isnan(val);
5254 }
5255
5256 /************************************************************************/
5257 /* ReadInternal() */
5258 /************************************************************************/
5259
ReadInternal(const size_t * count,const GPtrDiff_t * bufferStride,const GDALExtendedDataType & bufferDataType,void * pDstBuffer,const void * pTempBuffer,const GDALExtendedDataType & oTmpBufferDT,const std::vector<GPtrDiff_t> & tmpBufferStrideVector,bool bHasMissingValue,double dfMissingValue,bool bHasFillValue,double dfFillValue,bool bHasValidMin,double dfValidMin,bool bHasValidMax,double dfValidMax) const5260 template<typename Type> void GDALMDArrayMask::ReadInternal(
5261 const size_t* count,
5262 const GPtrDiff_t* bufferStride,
5263 const GDALExtendedDataType& bufferDataType,
5264 void* pDstBuffer,
5265 const void* pTempBuffer,
5266 const GDALExtendedDataType& oTmpBufferDT,
5267 const std::vector<GPtrDiff_t>& tmpBufferStrideVector,
5268 bool bHasMissingValue, double dfMissingValue,
5269 bool bHasFillValue, double dfFillValue,
5270 bool bHasValidMin, double dfValidMin,
5271 bool bHasValidMax, double dfValidMax) const
5272 {
5273 const size_t nDims = GetDimensionCount();
5274
5275 const auto castValue = [](bool& bHasVal, double dfVal) -> Type
5276 {
5277 if( bHasVal )
5278 {
5279 if( IsValidForDT<Type>(dfVal) )
5280 {
5281 return static_cast<Type>(dfVal);
5282 }
5283 else
5284 {
5285 bHasVal = false;
5286 }
5287 }
5288 return 0;
5289 };
5290
5291 const void* pSrcRawNoDataValue = m_poParent->GetRawNoDataValue();
5292 bool bHasNodataValue = pSrcRawNoDataValue != nullptr;
5293 const Type nNoDataValue = castValue(bHasNodataValue, m_poParent->GetNoDataValueAsDouble());
5294 const Type nMissingValue = castValue(bHasMissingValue, dfMissingValue);
5295 const Type nFillValue = castValue(bHasFillValue, dfFillValue);
5296 const Type nValidMin = castValue(bHasValidMin, dfValidMin);
5297 const Type nValidMax = castValue(bHasValidMax, dfValidMax);
5298
5299 #define GET_MASK_FOR_SAMPLE(v) \
5300 static_cast<GByte>( !IsNan(v) && \
5301 !(bHasNodataValue && v == nNoDataValue) && \
5302 !(bHasMissingValue && v == nMissingValue) && \
5303 !(bHasFillValue && v == nFillValue) && \
5304 !(bHasValidMin && v < nValidMin) && \
5305 !(bHasValidMax && v > nValidMax) )
5306
5307 const bool bBufferDataTypeIsByte = bufferDataType == m_dt;
5308 /* Optimized case: Byte output and output buffer is contiguous */
5309 if( bBufferDataTypeIsByte )
5310 {
5311 bool bContiguous = true;
5312 for( size_t i = 0; i < nDims; i++)
5313 {
5314 if( bufferStride[i] != tmpBufferStrideVector[i] )
5315 {
5316 bContiguous = false;
5317 break;
5318 }
5319 }
5320 if( bContiguous )
5321 {
5322 size_t nElts = 1;
5323 for( size_t i = 0; i < nDims; i++ )
5324 nElts *= count[i];
5325
5326 for( size_t i = 0; i < nElts; i++)
5327 {
5328 const Type* pSrc = static_cast<const Type*>(pTempBuffer) + i;
5329 static_cast<GByte*>(pDstBuffer)[i] = GET_MASK_FOR_SAMPLE(*pSrc);
5330 }
5331 return;
5332 }
5333 }
5334
5335 const size_t nTmpBufferDTSize = oTmpBufferDT.GetSize();
5336 struct Stack
5337 {
5338 size_t nIters = 0;
5339 const GByte* src_ptr = nullptr;
5340 GByte* dst_ptr = nullptr;
5341 GPtrDiff_t src_inc_offset = 0;
5342 GPtrDiff_t dst_inc_offset = 0;
5343 };
5344 std::vector<Stack> stack(std::max(static_cast<size_t>(1), nDims));
5345 const size_t nBufferDTSize = bufferDataType.GetSize();
5346 for( size_t i = 0; i < nDims; i++ )
5347 {
5348 stack[i].src_inc_offset = static_cast<GPtrDiff_t>(
5349 tmpBufferStrideVector[i] * nTmpBufferDTSize);
5350 stack[i].dst_inc_offset = static_cast<GPtrDiff_t>(
5351 bufferStride[i] * nBufferDTSize);
5352 }
5353 stack[0].src_ptr = static_cast<const GByte*>(pTempBuffer);
5354 stack[0].dst_ptr = static_cast<GByte*>(pDstBuffer);
5355
5356 size_t dimIdx = 0;
5357 const size_t nDimsMinus1 = nDims > 0 ? nDims - 1 : 0;
5358 GByte abyZeroOrOne[2][16]; // 16 is sizeof GDT_CFloat64
5359 CPLAssert(nBufferDTSize <= 16);
5360 for( GByte flag = 0; flag <= 1; flag++ )
5361 {
5362 // Coverity misses that m_dt is of type Byte
5363 // coverity[overrun-buffer-val]
5364 GDALExtendedDataType::CopyValue(&flag, m_dt,
5365 abyZeroOrOne[flag], bufferDataType);
5366 }
5367
5368 lbl_next_depth:
5369 if( dimIdx == nDimsMinus1 )
5370 {
5371 auto nIters = nDims > 0 ? count[dimIdx] : 1;
5372 const GByte* src_ptr = stack[dimIdx].src_ptr;
5373 GByte* dst_ptr = stack[dimIdx].dst_ptr;
5374
5375 while(true)
5376 {
5377 const Type* pSrc = reinterpret_cast<const Type*>(src_ptr);
5378 const GByte flag = GET_MASK_FOR_SAMPLE(*pSrc);
5379
5380 if( bBufferDataTypeIsByte )
5381 {
5382 *dst_ptr = flag;
5383 }
5384 else
5385 {
5386 memcpy(dst_ptr, abyZeroOrOne[flag], nBufferDTSize);
5387 }
5388
5389 if( (--nIters) == 0 )
5390 break;
5391 src_ptr += stack[dimIdx].src_inc_offset;
5392 dst_ptr += stack[dimIdx].dst_inc_offset;
5393 }
5394 }
5395 else
5396 {
5397 stack[dimIdx].nIters = count[dimIdx];
5398 while(true)
5399 {
5400 dimIdx ++;
5401 stack[dimIdx].src_ptr = stack[dimIdx-1].src_ptr;
5402 stack[dimIdx].dst_ptr = stack[dimIdx-1].dst_ptr;
5403 goto lbl_next_depth;
5404 lbl_return_to_caller:
5405 dimIdx --;
5406 if( (--stack[dimIdx].nIters) == 0 )
5407 break;
5408 stack[dimIdx].src_ptr += stack[dimIdx].src_inc_offset;
5409 stack[dimIdx].dst_ptr += stack[dimIdx].dst_inc_offset;
5410 }
5411 }
5412 if( dimIdx > 0 )
5413 goto lbl_return_to_caller;
5414 }
5415
5416 /************************************************************************/
5417 /* GetMask() */
5418 /************************************************************************/
5419
5420 /** Return an array that is a mask for the current array
5421 *
5422 * This array will be of type Byte, with values set to 0 to indicate invalid
5423 * pixels of the current array, and values set to 1 to indicate valid pixels.
5424 *
5425 * The generic implementation honours the NoDataValue, as well as various
5426 * netCDF CF attributes: missing_value, _FillValue, valid_min, valid_max
5427 * and valid_range.
5428 *
5429 * This is the same as the C function GDALMDArrayGetMask().
5430 *
5431 * @param papszOptions NULL-terminated list of options, or NULL.
5432 *
5433 * @return a new array, that holds a reference to the original one, and thus is
5434 * a view of it (not a copy), or nullptr in case of error.
5435 */
GetMask(CPL_UNUSED CSLConstList papszOptions) const5436 std::shared_ptr<GDALMDArray> GDALMDArray::GetMask(CPL_UNUSED
5437 CSLConstList papszOptions) const
5438 {
5439 auto self = std::dynamic_pointer_cast<GDALMDArray>(m_pSelf.lock());
5440 if( !self )
5441 {
5442 CPLError(CE_Failure, CPLE_AppDefined,
5443 "Driver implementation issue: m_pSelf not set !");
5444 return nullptr;
5445 }
5446 if( GetDataType().GetClass() != GEDTC_NUMERIC )
5447 {
5448 CPLError(CE_Failure, CPLE_AppDefined,
5449 "GetMask() only supports numeric data type");
5450 return nullptr;
5451 }
5452 return GDALMDArrayMask::Create(self);
5453 }
5454
5455 /************************************************************************/
5456 /* GDALDatasetFromArray() */
5457 /************************************************************************/
5458
5459 class GDALDatasetFromArray;
5460
5461 class GDALRasterBandFromArray final: public GDALRasterBand
5462 {
5463 std::vector<GUInt64> m_anOffset{};
5464 std::vector<size_t> m_anCount{};
5465 std::vector<GPtrDiff_t> m_anStride{};
5466
5467 protected:
5468 CPLErr IReadBlock( int, int, void * ) override;
5469 CPLErr IWriteBlock( int, int, void * ) override;
5470 CPLErr IRasterIO( GDALRWFlag eRWFlag,
5471 int nXOff, int nYOff, int nXSize, int nYSize,
5472 void * pData, int nBufXSize, int nBufYSize,
5473 GDALDataType eBufType,
5474 GSpacing nPixelSpaceBuf,
5475 GSpacing nLineSpaceBuf,
5476 GDALRasterIOExtraArg* psExtraArg ) override;
5477 public:
5478 explicit GDALRasterBandFromArray(GDALDatasetFromArray* poDSIn,
5479 const std::vector<GUInt64>& anOtherDimCoord);
5480
5481 double GetNoDataValue(int* pbHasNoData) override;
5482 double GetOffset(int* pbHasOffset) override;
5483 double GetScale(int* pbHasScale) override;
5484 const char* GetUnitType() override;
5485 };
5486
5487
5488 class GDALDatasetFromArray final: public GDALDataset
5489 {
5490 friend class GDALRasterBandFromArray;
5491
5492 std::shared_ptr<GDALMDArray> m_poArray;
5493 size_t m_iXDim;
5494 size_t m_iYDim;
5495 double m_adfGeoTransform[6]{0,1,0,0,0,1};
5496 bool m_bHasGT = false;
5497 mutable std::shared_ptr<OGRSpatialReference> m_poSRS{};
5498
5499 public:
GuessGeoTransform()5500 void GuessGeoTransform()
5501 {
5502 const auto& dims(m_poArray->GetDimensions());
5503 if( dims.size() < 2 )
5504 return;
5505 auto poVarX = dims[m_iXDim]->GetIndexingVariable();
5506 auto poVarY = dims[m_iYDim]->GetIndexingVariable();
5507 if( poVarX && poVarX->GetDimensionCount() == 1 &&
5508 poVarX->GetDimensions()[0]->GetSize() == dims[m_iXDim]->GetSize() &&
5509 poVarY && poVarY->GetDimensionCount() == 1 &&
5510 poVarY->GetDimensions()[0]->GetSize() == dims[m_iYDim]->GetSize() &&
5511 dims[m_iXDim]->GetSize() > 1 &&
5512 dims[m_iXDim]->GetSize() < 10 * 1000 * 1000 &&
5513 dims[m_iYDim]->GetSize() > 1 &&
5514 dims[m_iYDim]->GetSize() < 10 * 1000 * 1000 )
5515 {
5516 std::vector<double> adfTmp(static_cast<size_t>(std::max(
5517 dims[m_iXDim]->GetSize(), dims[m_iYDim]->GetSize())));
5518 const GUInt64 anStart[1] = { 0 };
5519 size_t nCount = static_cast<size_t>(dims[m_iXDim]->GetSize());
5520 size_t anCount[1] = { nCount };
5521 if( !poVarX->Read(anStart, anCount, nullptr, nullptr,
5522 GDALExtendedDataType::Create(GDT_Float64),
5523 &adfTmp[0]) )
5524 {
5525 return;
5526 }
5527
5528 double dfSpacing = (adfTmp[nCount-1] - adfTmp[0]) / (nCount - 1);
5529 for(size_t i = 1; i < nCount; i++ )
5530 {
5531 if( fabs((adfTmp[i] - adfTmp[i-1]) - dfSpacing) > 1e-3 * fabs(dfSpacing) )
5532 {
5533 return;
5534 }
5535 }
5536 const double dfXStart = adfTmp[0];
5537 const double dfXSpacing = dfSpacing;
5538
5539 nCount = static_cast<size_t>(dims[m_iYDim]->GetSize());
5540 anCount[0] = nCount;
5541 if( !poVarY->Read(anStart, anCount, nullptr, nullptr,
5542 GDALExtendedDataType::Create(GDT_Float64),
5543 &adfTmp[0]) )
5544 {
5545 return;
5546 }
5547 dfSpacing = (adfTmp[nCount-1] - adfTmp[0]) / (nCount - 1);
5548 for(size_t i = 1; i < nCount; i++ )
5549 {
5550 if( fabs((adfTmp[i] - adfTmp[i-1]) - dfSpacing) > 1e-3 * fabs(dfSpacing) )
5551 {
5552 return;
5553 }
5554 }
5555 const double dfYStart = adfTmp[0];
5556 const double dfYSpacing = dfSpacing;
5557 m_bHasGT = true;
5558 m_adfGeoTransform[0] = dfXStart - dfXSpacing / 2;
5559 m_adfGeoTransform[1] = dfXSpacing;
5560 m_adfGeoTransform[2] = 0;
5561 m_adfGeoTransform[3] = dfYStart - dfYSpacing / 2;
5562 m_adfGeoTransform[4] = 0;
5563 m_adfGeoTransform[5] = dfYSpacing;
5564 }
5565
5566 }
5567
GDALDatasetFromArray(const std::shared_ptr<GDALMDArray> & array,size_t iXDim,size_t iYDim)5568 GDALDatasetFromArray(const std::shared_ptr<GDALMDArray>& array,
5569 size_t iXDim, size_t iYDim):
5570 m_poArray(array),
5571 m_iXDim(iXDim),
5572 m_iYDim(iYDim)
5573 {
5574 const auto& dims(m_poArray->GetDimensions());
5575 const auto nDimCount = dims.size();
5576 nRasterYSize = nDimCount < 2 ? 1 : static_cast<int>(
5577 std::min(static_cast<GUInt64>(INT_MAX), dims[iYDim]->GetSize()));
5578 nRasterXSize = static_cast<int>(
5579 std::min(static_cast<GUInt64>(INT_MAX), dims[iXDim]->GetSize()));
5580 eAccess = array->IsWritable() ? GA_Update: GA_ReadOnly;
5581
5582 const size_t nNewDimCount = nDimCount >= 2 ? nDimCount - 2 : 0;
5583 std::vector<GUInt64> anOtherDimCoord(nNewDimCount);
5584 std::vector<GUInt64> anStackIters(nDimCount);
5585 std::vector<size_t> anMapNewToOld(nNewDimCount);
5586 for( size_t i = 0, j = 0; i < nDimCount; ++i )
5587 {
5588 if( i != iXDim && !(nDimCount >= 2 && i == iYDim) )
5589 {
5590 anMapNewToOld[j] = i;
5591 j++;
5592 }
5593 }
5594
5595 GuessGeoTransform();
5596
5597 const auto attrs(array->GetAttributes());
5598 for( const auto& attr: attrs )
5599 {
5600 auto stringArray = attr->ReadAsStringArray();
5601 std::string val;
5602 if( stringArray.size() > 1 )
5603 {
5604 val += '{';
5605 }
5606 for( int i = 0; i < stringArray.size(); ++i )
5607 {
5608 if( i > 0 )
5609 val += ',';
5610 val += stringArray[i];
5611 }
5612 if( stringArray.size() > 1 )
5613 {
5614 val += '}';
5615 }
5616 SetMetadataItem(attr->GetName().c_str(), val.c_str());
5617 }
5618
5619 // Instantiate bands by iterating over non-XY variables
5620 size_t iDim = 0;
5621 lbl_next_depth:
5622 if( iDim < nNewDimCount )
5623 {
5624 anStackIters[iDim] = dims[anMapNewToOld[iDim]]->GetSize();
5625 anOtherDimCoord[iDim] = 0;
5626 while( true )
5627 {
5628 ++iDim;
5629 goto lbl_next_depth;
5630 lbl_return_to_caller:
5631 --iDim;
5632 --anStackIters[iDim];
5633 if( anStackIters[iDim] == 0 )
5634 break;
5635 ++anOtherDimCoord[iDim];
5636 }
5637 }
5638 else
5639 {
5640 SetBand(nBands + 1, new GDALRasterBandFromArray(this, anOtherDimCoord));
5641 }
5642 if( iDim > 0 )
5643 goto lbl_return_to_caller;
5644 }
5645
GetGeoTransform(double * padfGeoTransform)5646 CPLErr GetGeoTransform(double* padfGeoTransform) override
5647 {
5648 memcpy(padfGeoTransform, m_adfGeoTransform, 6 * sizeof(double));
5649 return m_bHasGT ? CE_None : CE_Failure;
5650 }
5651
GetSpatialRef() const5652 const OGRSpatialReference* GetSpatialRef() const override
5653 {
5654 if( m_poArray->GetDimensionCount() < 2 )
5655 return nullptr;
5656 m_poSRS = m_poArray->GetSpatialRef();
5657 if( m_poSRS )
5658 {
5659 m_poSRS.reset(m_poSRS->Clone());
5660 auto axisMapping = m_poSRS->GetDataAxisToSRSAxisMapping();
5661 for( auto& m: axisMapping )
5662 {
5663 if( m == static_cast<int>(m_iXDim) + 1 )
5664 m = 1;
5665 else if( m == static_cast<int>(m_iYDim) + 1 )
5666 m = 2;
5667 else
5668 m = 0;
5669 }
5670 m_poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
5671 }
5672 return m_poSRS.get();
5673 }
5674 };
5675
5676 /************************************************************************/
5677 /* GDALRasterBandFromArray() */
5678 /************************************************************************/
5679
GDALRasterBandFromArray(GDALDatasetFromArray * poDSIn,const std::vector<GUInt64> & anOtherDimCoord)5680 GDALRasterBandFromArray::GDALRasterBandFromArray(
5681 GDALDatasetFromArray* poDSIn,
5682 const std::vector<GUInt64>& anOtherDimCoord)
5683 {
5684 const auto& poArray(poDSIn->m_poArray);
5685 const auto& dims(poArray->GetDimensions());
5686 const auto nDimCount(dims.size());
5687 const auto blockSize(poArray->GetBlockSize());
5688 nBlockYSize = (nDimCount >= 2 && blockSize[poDSIn->m_iYDim]) ? static_cast<int>(
5689 std::min(static_cast<GUInt64>(INT_MAX), blockSize[poDSIn->m_iYDim])) : 1;
5690 nBlockXSize = blockSize[poDSIn->m_iXDim] ? static_cast<int>(
5691 std::min(static_cast<GUInt64>(INT_MAX), blockSize[poDSIn->m_iXDim])) :
5692 poDSIn->GetRasterXSize();
5693 eDataType = poArray->GetDataType().GetNumericDataType();
5694 eAccess = poDSIn->eAccess;
5695 m_anOffset.resize(nDimCount);
5696 m_anCount.resize(nDimCount, 1);
5697 m_anStride.resize(nDimCount);
5698 for( size_t i = 0, j = 0; i < nDimCount; ++i )
5699 {
5700 if( i != poDSIn->m_iXDim && !(nDimCount >= 2 && i == poDSIn->m_iYDim) )
5701 {
5702 std::string dimName(dims[i]->GetName());
5703 GUInt64 nIndex = anOtherDimCoord[j];
5704 // Detect subset_{orig_dim_name}_{start}_{incr}_{size} names of
5705 // subsetted dimensions as generated by GetView()
5706 if( STARTS_WITH(dimName.c_str(), "subset_") )
5707 {
5708 CPLStringList aosTokens(CSLTokenizeString2(dimName.c_str(), "_", 0));
5709 if( aosTokens.size() == 5 )
5710 {
5711 dimName = aosTokens[1];
5712 const auto nStartDim = static_cast<GUInt64>(
5713 CPLScanUIntBig(aosTokens[2], static_cast<int>(strlen(aosTokens[2]))));
5714 const auto nIncrDim = CPLAtoGIntBig(aosTokens[3]);
5715 nIndex = nIncrDim > 0 ?
5716 nStartDim + nIndex * nIncrDim :
5717 nStartDim - (nIndex * -nIncrDim);
5718 }
5719 }
5720 SetMetadataItem(
5721 CPLSPrintf("DIM_%s_INDEX", dimName.c_str()),
5722 CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nIndex)) );
5723 auto indexingVar = dims[i]->GetIndexingVariable();
5724 if( indexingVar && indexingVar->GetDimensionCount() == 1 &&
5725 indexingVar->GetDimensions()[0]->GetSize() == dims[i]->GetSize() )
5726 {
5727 size_t nCount = 1;
5728 const auto& dt(indexingVar->GetDataType());
5729 std::vector<GByte> abyTmp(dt.GetSize());
5730 if( indexingVar->Read(&(anOtherDimCoord[j]), &nCount, nullptr, nullptr,
5731 dt, &abyTmp[0]) )
5732 {
5733 char* pszTmp = nullptr;
5734 GDALExtendedDataType::CopyValue(
5735 &abyTmp[0], dt,
5736 &pszTmp, GDALExtendedDataType::CreateString());
5737 if( pszTmp )
5738 {
5739 SetMetadataItem(
5740 CPLSPrintf("DIM_%s_VALUE", dimName.c_str()),
5741 pszTmp );
5742 CPLFree(pszTmp);
5743 }
5744
5745 const auto unit(indexingVar->GetUnit());
5746 if( !unit.empty() )
5747 {
5748 SetMetadataItem(
5749 CPLSPrintf("DIM_%s_UNIT", dimName.c_str()),
5750 unit.c_str() );
5751 }
5752 }
5753 }
5754 m_anOffset[i] = anOtherDimCoord[j];
5755 j++;
5756 }
5757 }
5758 }
5759
5760 /************************************************************************/
5761 /* GetNoDataValue() */
5762 /************************************************************************/
5763
GetNoDataValue(int * pbHasNoData)5764 double GDALRasterBandFromArray::GetNoDataValue(int* pbHasNoData)
5765 {
5766 auto l_poDS(cpl::down_cast<GDALDatasetFromArray*>(poDS));
5767 const auto& poArray(l_poDS->m_poArray);
5768 bool bHasNodata = false;
5769 double dfRes = poArray->GetNoDataValueAsDouble(&bHasNodata);
5770 if( pbHasNoData )
5771 *pbHasNoData = bHasNodata;
5772 return dfRes;
5773 }
5774
5775 /************************************************************************/
5776 /* GetOffset() */
5777 /************************************************************************/
5778
GetOffset(int * pbHasOffset)5779 double GDALRasterBandFromArray::GetOffset(int* pbHasOffset)
5780 {
5781 auto l_poDS(cpl::down_cast<GDALDatasetFromArray*>(poDS));
5782 const auto& poArray(l_poDS->m_poArray);
5783 bool bHasValue = false;
5784 double dfRes = poArray->GetOffset(&bHasValue);
5785 if( pbHasOffset )
5786 *pbHasOffset = bHasValue;
5787 return dfRes;
5788 }
5789
5790 /************************************************************************/
5791 /* GetUnitType() */
5792 /************************************************************************/
5793
GetUnitType()5794 const char* GDALRasterBandFromArray::GetUnitType()
5795 {
5796 auto l_poDS(cpl::down_cast<GDALDatasetFromArray*>(poDS));
5797 const auto& poArray(l_poDS->m_poArray);
5798 return poArray->GetUnit().c_str();
5799 }
5800
5801 /************************************************************************/
5802 /* GetScale() */
5803 /************************************************************************/
5804
GetScale(int * pbHasScale)5805 double GDALRasterBandFromArray::GetScale(int* pbHasScale)
5806 {
5807 auto l_poDS(cpl::down_cast<GDALDatasetFromArray*>(poDS));
5808 const auto& poArray(l_poDS->m_poArray);
5809 bool bHasValue = false;
5810 double dfRes = poArray->GetScale(&bHasValue);
5811 if( pbHasScale )
5812 *pbHasScale = bHasValue;
5813 return dfRes;
5814 }
5815
5816 /************************************************************************/
5817 /* IReadBlock() */
5818 /************************************************************************/
5819
IReadBlock(int nBlockXOff,int nBlockYOff,void * pImage)5820 CPLErr GDALRasterBandFromArray::IReadBlock( int nBlockXOff,
5821 int nBlockYOff,
5822 void * pImage )
5823 {
5824 const int nDTSize(GDALGetDataTypeSizeBytes(eDataType));
5825 const int nXOff = nBlockXOff * nBlockXSize;
5826 const int nYOff = nBlockYOff * nBlockYSize;
5827 const int nReqXSize = std::min(nRasterXSize - nXOff, nBlockXSize);
5828 const int nReqYSize = std::min(nRasterYSize - nYOff, nBlockYSize);
5829 GDALRasterIOExtraArg sExtraArg;
5830 INIT_RASTERIO_EXTRA_ARG(sExtraArg);
5831 return IRasterIO(GF_Read, nXOff, nYOff, nReqXSize, nReqYSize,
5832 pImage, nReqXSize, nReqYSize, eDataType,
5833 nDTSize, nDTSize * nBlockXSize, &sExtraArg);
5834 }
5835
5836 /************************************************************************/
5837 /* IWriteBlock() */
5838 /************************************************************************/
5839
IWriteBlock(int nBlockXOff,int nBlockYOff,void * pImage)5840 CPLErr GDALRasterBandFromArray::IWriteBlock( int nBlockXOff,
5841 int nBlockYOff,
5842 void * pImage )
5843 {
5844 const int nDTSize(GDALGetDataTypeSizeBytes(eDataType));
5845 const int nXOff = nBlockXOff * nBlockXSize;
5846 const int nYOff = nBlockYOff * nBlockYSize;
5847 const int nReqXSize = std::min(nRasterXSize - nXOff, nBlockXSize);
5848 const int nReqYSize = std::min(nRasterYSize - nYOff, nBlockYSize);
5849 GDALRasterIOExtraArg sExtraArg;
5850 INIT_RASTERIO_EXTRA_ARG(sExtraArg);
5851 return IRasterIO(GF_Write, nXOff, nYOff, nReqXSize, nReqYSize,
5852 pImage, nReqXSize, nReqYSize, eDataType,
5853 nDTSize, nDTSize * nBlockXSize, &sExtraArg);
5854 }
5855
5856 /************************************************************************/
5857 /* IRasterIO() */
5858 /************************************************************************/
5859
IRasterIO(GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,int nBufXSize,int nBufYSize,GDALDataType eBufType,GSpacing nPixelSpaceBuf,GSpacing nLineSpaceBuf,GDALRasterIOExtraArg * psExtraArg)5860 CPLErr GDALRasterBandFromArray::IRasterIO( GDALRWFlag eRWFlag,
5861 int nXOff, int nYOff, int nXSize, int nYSize,
5862 void * pData, int nBufXSize, int nBufYSize,
5863 GDALDataType eBufType,
5864 GSpacing nPixelSpaceBuf,
5865 GSpacing nLineSpaceBuf,
5866 GDALRasterIOExtraArg* psExtraArg )
5867 {
5868 auto l_poDS(cpl::down_cast<GDALDatasetFromArray*>(poDS));
5869 const auto& poArray(l_poDS->m_poArray);
5870 const int nBufferDTSize(GDALGetDataTypeSizeBytes(eBufType));
5871 if( nXSize == nBufXSize && nYSize == nBufYSize && nBufferDTSize > 0 &&
5872 (nPixelSpaceBuf % nBufferDTSize) == 0 &&
5873 (nLineSpaceBuf % nBufferDTSize) == 0 )
5874 {
5875 m_anOffset[l_poDS->m_iXDim] = static_cast<GUInt64>(nXOff);
5876 m_anCount[l_poDS->m_iXDim] = static_cast<size_t>(nXSize);
5877 m_anStride[l_poDS->m_iXDim] =
5878 static_cast<GPtrDiff_t>(nPixelSpaceBuf / nBufferDTSize);
5879 if( poArray->GetDimensionCount() >= 2 )
5880 {
5881 m_anOffset[l_poDS->m_iYDim] = static_cast<GUInt64>(nYOff);
5882 m_anCount[l_poDS->m_iYDim] = static_cast<size_t>(nYSize);
5883 m_anStride[l_poDS->m_iYDim] =
5884 static_cast<GPtrDiff_t>(nLineSpaceBuf / nBufferDTSize);
5885 }
5886 if( eRWFlag == GF_Read )
5887 {
5888 return poArray->Read(m_anOffset.data(),
5889 m_anCount.data(),
5890 nullptr, m_anStride.data(),
5891 GDALExtendedDataType::Create(eBufType), pData) ?
5892 CE_None : CE_Failure;
5893 }
5894 else
5895 {
5896 return poArray->Write(m_anOffset.data(),
5897 m_anCount.data(),
5898 nullptr, m_anStride.data(),
5899 GDALExtendedDataType::Create(eBufType), pData) ?
5900 CE_None : CE_Failure;
5901 }
5902 }
5903 return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
5904 pData, nBufXSize, nBufYSize,
5905 eBufType,
5906 nPixelSpaceBuf, nLineSpaceBuf,
5907 psExtraArg);
5908 }
5909
5910 /************************************************************************/
5911 /* AsClassicDataset() */
5912 /************************************************************************/
5913
5914 /** Return a view of this array as a "classic" GDALDataset (ie 2D)
5915 *
5916 * In the case of > 2D arrays, additional dimensions will be represented as
5917 * raster bands.
5918 *
5919 * The "reverse" method is GDALRasterBand::AsMDArray().
5920 *
5921 * This is the same as the C function GDALMDArrayAsClassicDataset().
5922 *
5923 * @param iXDim Index of the dimension that will be used as the X/width axis.
5924 * @param iYDim Index of the dimension that will be used as the Y/height axis.
5925 * Ignored if the dimension count is 1.
5926 * @return a new GDALDataset that must be freed with GDALClose(), or nullptr
5927 */
AsClassicDataset(size_t iXDim,size_t iYDim) const5928 GDALDataset* GDALMDArray::AsClassicDataset(size_t iXDim, size_t iYDim) const
5929 {
5930 auto self = std::dynamic_pointer_cast<GDALMDArray>(m_pSelf.lock());
5931 if( !self )
5932 {
5933 CPLError(CE_Failure, CPLE_AppDefined,
5934 "Driver implementation issue: m_pSelf not set !");
5935 return nullptr;
5936 }
5937 const auto nDimCount(GetDimensionCount());
5938 if( nDimCount == 0 )
5939 {
5940 CPLError(CE_Failure, CPLE_NotSupported,
5941 "Unsupported number of dimensions");
5942 return nullptr;
5943 }
5944 if( GetDataType().GetClass() != GEDTC_NUMERIC ||
5945 GetDataType().GetNumericDataType() == GDT_Unknown )
5946 {
5947 CPLError(CE_Failure, CPLE_NotSupported,
5948 "Only arrays with numeric data types "
5949 "can be exposed as classic GDALDataset");
5950 return nullptr;
5951 }
5952 if( iXDim >= nDimCount ||
5953 (nDimCount >=2 && (iYDim >= nDimCount || iXDim == iYDim)) )
5954 {
5955 CPLError(CE_Failure, CPLE_NotSupported,
5956 "Invalid iXDim and/or iYDim");
5957 return nullptr;
5958 }
5959 GUInt64 nBands = 1;
5960 const auto& dims(GetDimensions());
5961 for( size_t i = 0; i < nDimCount; ++i )
5962 {
5963 if( i != iXDim && !(nDimCount >= 2 && i == iYDim) )
5964 {
5965 if( dims[i]->GetSize() > 65536 / nBands )
5966 {
5967 CPLError(CE_Failure, CPLE_AppDefined,
5968 "Too many bands. Operate on a sliced view");
5969 return nullptr;
5970 }
5971 nBands *= dims[i]->GetSize();
5972 }
5973 }
5974 return new GDALDatasetFromArray(self, iXDim, iYDim);
5975 }
5976
5977 /************************************************************************/
5978 /* GetStatistics() */
5979 /************************************************************************/
5980
5981 /**
5982 * \brief Fetch statistics.
5983 *
5984 * Returns the minimum, maximum, mean and standard deviation of all
5985 * pixel values in this array.
5986 *
5987 * If bForce is FALSE results will only be returned if it can be done
5988 * quickly (i.e. without scanning the data). If bForce is FALSE and
5989 * results cannot be returned efficiently, the method will return CE_Warning
5990 * but no warning will have been issued. This is a non-standard use of
5991 * the CE_Warning return value to indicate "nothing done".
5992 *
5993 * When cached statistics are not available, and bForce is TRUE,
5994 * ComputeStatistics() is called.
5995 *
5996 * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5997 * will generally cache statistics in the .aux.xml file allowing fast fetch
5998 * after the first request.
5999 *
6000 * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6001 *
6002 * This method is the same as the C function GDALMDArrayGetStatistics().
6003 *
6004 * @param poDS Owing dataset. If set to NULL, this method will always call
6005 * ComputeStatistics(). If set to non-NULL, the method will attempt to retrieve
6006 * from it (generally its persistent auxiliary metadata) already cached
6007 * statistics.
6008 *
6009 * @param bApproxOK Currently ignored. In the future, should be set to true
6010 * if statistics on the whole array are wished, or to false if a subset of it
6011 * may be used.
6012 *
6013 * @param bForce If false statistics will only be returned if it can
6014 * be done without rescanning the image.
6015 *
6016 * @param pdfMin Location into which to load image minimum (may be NULL).
6017 *
6018 * @param pdfMax Location into which to load image maximum (may be NULL).-
6019 *
6020 * @param pdfMean Location into which to load image mean (may be NULL).
6021 *
6022 * @param pdfStdDev Location into which to load image standard deviation
6023 * (may be NULL).
6024 *
6025 * @param pnValidCount Number of samples whose value is different from the nodata
6026 * value. (may be NULL)
6027 *
6028 * @param pfnProgress a function to call to report progress, or NULL.
6029 *
6030 * @param pProgressData application data to pass to the progress function.
6031 *
6032 * @return CE_None on success, CE_Warning if no values returned,
6033 * CE_Failure if an error occurs.
6034 *
6035 * @since GDAL 3.2
6036 */
6037
GetStatistics(GDALDataset * poDS,bool bApproxOK,bool bForce,double * pdfMin,double * pdfMax,double * pdfMean,double * pdfStdDev,GUInt64 * pnValidCount,GDALProgressFunc pfnProgress,void * pProgressData)6038 CPLErr GDALMDArray::GetStatistics( GDALDataset* poDS,
6039 bool bApproxOK, bool bForce,
6040 double *pdfMin, double *pdfMax,
6041 double *pdfMean, double *pdfStdDev,
6042 GUInt64* pnValidCount,
6043 GDALProgressFunc pfnProgress, void *pProgressData )
6044 {
6045 GDALPamDataset* poPamDS = dynamic_cast<GDALPamDataset*>(poDS);
6046 if( poPamDS != nullptr )
6047 {
6048 bool bGotApproxStats = false;
6049 if( poPamDS->GetMDArrayStatistics(GetFullName().c_str(),
6050 &bGotApproxStats,
6051 pdfMin, pdfMax,
6052 pdfMean, pdfStdDev,
6053 pnValidCount) )
6054 {
6055 if( bApproxOK )
6056 return CE_None;
6057 if( !bGotApproxStats )
6058 return CE_None;
6059 }
6060 }
6061
6062 if( !bForce )
6063 return CE_Warning;
6064
6065 return ComputeStatistics(poDS, bApproxOK, pdfMin, pdfMax, pdfMean,
6066 pdfStdDev, pnValidCount,
6067 pfnProgress, pProgressData)
6068 ? CE_None: CE_Failure;
6069 }
6070
6071 /************************************************************************/
6072 /* ComputeStatistics() */
6073 /************************************************************************/
6074
6075 /**
6076 * \brief Compute statistics.
6077 *
6078 * Returns the minimum, maximum, mean and standard deviation of all
6079 * pixel values in this array.
6080 *
6081 * Pixels taken into account in statistics are those whose mask value
6082 * (as determined by GetMask()) is non-zero.
6083 *
6084 * Once computed, the statistics will generally be "set" back on the
6085 * owing dataset (if poDS is not NULL).
6086 *
6087 * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6088 *
6089 * This method is the same as the C function GDALMDArrayComputeStatistics().
6090 *
6091 * @param poDS Owing dataset. If set to non-NULL, the method will attempt to
6092 * store computed statistics in it (generally its persistent auxiliary metadata)
6093 * for further retrieval by GetStatistics()
6094 *
6095 * @param bApproxOK Currently ignored. In the future, should be set to true
6096 * if statistics on the whole array are wished, or to false if a subset of it
6097 * may be used.
6098 *
6099 * @param pdfMin Location into which to load image minimum (may be NULL).
6100 *
6101 * @param pdfMax Location into which to load image maximum (may be NULL).-
6102 *
6103 * @param pdfMean Location into which to load image mean (may be NULL).
6104 *
6105 * @param pdfStdDev Location into which to load image standard deviation
6106 * (may be NULL).
6107 *
6108 * @param pnValidCount Number of samples whose value is different from the nodata
6109 * value. (may be NULL)
6110 *
6111 * @param pfnProgress a function to call to report progress, or NULL.
6112 *
6113 * @param pProgressData application data to pass to the progress function.
6114 *
6115 * @return true on success
6116 *
6117 * @since GDAL 3.2
6118 */
6119
ComputeStatistics(GDALDataset * poDS,bool bApproxOK,double * pdfMin,double * pdfMax,double * pdfMean,double * pdfStdDev,GUInt64 * pnValidCount,GDALProgressFunc pfnProgress,void * pProgressData)6120 bool GDALMDArray::ComputeStatistics( GDALDataset* poDS,
6121 bool bApproxOK,
6122 double *pdfMin, double *pdfMax,
6123 double *pdfMean, double *pdfStdDev,
6124 GUInt64* pnValidCount,
6125 GDALProgressFunc pfnProgress, void *pProgressData )
6126 {
6127 struct StatsPerChunkType
6128 {
6129 const GDALMDArray* array = nullptr;
6130 std::shared_ptr<GDALMDArray> poMask{};
6131 double dfMin = std::numeric_limits<double>::max();
6132 double dfMax = -std::numeric_limits<double>::max();
6133 double dfMean = 0.0;
6134 double dfM2 = 0.0;
6135 GUInt64 nValidCount = 0;
6136 std::vector<GByte> abyData{};
6137 std::vector<double> adfData{};
6138 std::vector<GByte> abyMaskData{};
6139 GDALProgressFunc pfnProgress = nullptr;
6140 void* pProgressData = nullptr;
6141 };
6142
6143 const auto PerChunkFunc = [](GDALAbstractMDArray*,
6144 const GUInt64* chunkArrayStartIdx,
6145 const size_t* chunkCount,
6146 GUInt64 iCurChunk,
6147 GUInt64 nChunkCount,
6148 void* pUserData)
6149 {
6150 StatsPerChunkType* data = static_cast<StatsPerChunkType*>(pUserData);
6151 const GDALMDArray* array = data->array;
6152 const GDALMDArray* poMask = data->poMask.get();
6153 const size_t nDims = array->GetDimensionCount();
6154 size_t nVals = 1;
6155 for( size_t i = 0; i < nDims; i++ )
6156 nVals *= chunkCount[i];
6157
6158 // Get mask
6159 data->abyMaskData.resize(nVals);
6160 if( !(poMask->Read(chunkArrayStartIdx, chunkCount, nullptr, nullptr,
6161 poMask->GetDataType(), &data->abyMaskData[0])) )
6162 {
6163 return false;
6164 }
6165
6166 // Get data
6167 const auto& oType = array->GetDataType();
6168 if( oType.GetNumericDataType() == GDT_Float64 )
6169 {
6170 data->adfData.resize(nVals);
6171 if( !array->Read(chunkArrayStartIdx, chunkCount, nullptr, nullptr,
6172 oType, &data->adfData[0]) )
6173 {
6174 return false;
6175 }
6176 }
6177 else
6178 {
6179 data->abyData.resize(nVals * oType.GetSize());
6180 if( !array->Read(chunkArrayStartIdx, chunkCount, nullptr, nullptr,
6181 oType, &data->abyData[0]) )
6182 {
6183 return false;
6184 }
6185 data->adfData.resize(nVals);
6186 GDALCopyWords64( &data->abyData[0], oType.GetNumericDataType(),
6187 static_cast<int>(oType.GetSize()),
6188 &data->adfData[0], GDT_Float64,
6189 static_cast<int>(sizeof(double)),
6190 static_cast<GPtrDiff_t>(nVals) );
6191 }
6192 for( size_t i = 0; i < nVals; i++ )
6193 {
6194 if( data->abyMaskData[i] )
6195 {
6196 const double dfValue = data->adfData[i];
6197 data->dfMin = std::min(data->dfMin, dfValue);
6198 data->dfMax = std::max(data->dfMax, dfValue);
6199 data->nValidCount++;
6200 const double dfDelta = dfValue - data->dfMean;
6201 data->dfMean += dfDelta / data->nValidCount;
6202 data->dfM2 += dfDelta * (dfValue - data->dfMean);
6203 }
6204 }
6205 if( data->pfnProgress &&
6206 !data->pfnProgress(static_cast<double>(iCurChunk+1) / nChunkCount,
6207 "", data->pProgressData) )
6208 {
6209 return false;
6210 }
6211 return true;
6212 };
6213
6214 const auto& oType = GetDataType();
6215 if( oType.GetClass() != GEDTC_NUMERIC ||
6216 GDALDataTypeIsComplex(oType.GetNumericDataType()) )
6217 {
6218 CPLError(CE_Failure, CPLE_NotSupported,
6219 "Statistics can only be computed on non-complex numeric data type");
6220 return false;
6221 }
6222
6223 const size_t nDims = GetDimensionCount();
6224 std::vector<GUInt64> arrayStartIdx(nDims);
6225 std::vector<GUInt64> count(nDims);
6226 const auto& poDims = GetDimensions();
6227 for( size_t i = 0; i < nDims; i++ )
6228 {
6229 count[i] = poDims[i]->GetSize();
6230 }
6231 const char* pszSwathSize = CPLGetConfigOption("GDAL_SWATH_SIZE", nullptr);
6232 const size_t nMaxChunkSize = pszSwathSize ?
6233 static_cast<size_t>(
6234 std::min(GIntBig(std::numeric_limits<size_t>::max() / 2),
6235 CPLAtoGIntBig(pszSwathSize))) :
6236 static_cast<size_t>(
6237 std::min(GIntBig(std::numeric_limits<size_t>::max() / 2),
6238 GDALGetCacheMax64() / 4));
6239 StatsPerChunkType sData;
6240 sData.array = this;
6241 sData.poMask = GetMask(nullptr);
6242 if( sData.poMask == nullptr )
6243 {
6244 return false;
6245 }
6246 sData.pfnProgress = pfnProgress;
6247 sData.pProgressData = pProgressData;
6248 if( !ProcessPerChunk(arrayStartIdx.data(), count.data(),
6249 GetProcessingChunkSize(nMaxChunkSize).data(),
6250 PerChunkFunc, &sData) )
6251 {
6252 return false;
6253 }
6254
6255 if( pdfMin )
6256 *pdfMin = sData.dfMin;
6257
6258 if( pdfMax )
6259 *pdfMax = sData.dfMax;
6260
6261 if( pdfMean )
6262 *pdfMean = sData.dfMean;
6263
6264 const double dfStdDev = sData.nValidCount > 0 ? sqrt(sData.dfM2 / sData.nValidCount) : 0.0;
6265 if( pdfStdDev )
6266 *pdfStdDev = dfStdDev;
6267
6268 if( pnValidCount )
6269 *pnValidCount = sData.nValidCount;
6270
6271 if( poDS )
6272 {
6273 SetStatistics(poDS, bApproxOK,
6274 sData.dfMin, sData.dfMax, sData.dfMean, dfStdDev,
6275 sData.nValidCount);
6276 }
6277
6278 return true;
6279 }
6280
SetStatistics(GDALDataset * poDS,bool bApproxStats,double dfMin,double dfMax,double dfMean,double dfStdDev,GUInt64 nValidCount)6281 bool GDALMDArray::SetStatistics( GDALDataset* poDS,
6282 bool bApproxStats,
6283 double dfMin, double dfMax,
6284 double dfMean, double dfStdDev,
6285 GUInt64 nValidCount )
6286 {
6287 if( poDS == nullptr )
6288 {
6289 CPLError(CE_Failure, CPLE_IllegalArg,
6290 "Dataset should be defined to enable serialization");
6291 return false;
6292 }
6293
6294 GDALPamDataset* poPamDS = dynamic_cast<GDALPamDataset*>(poDS);
6295 if( poPamDS == nullptr )
6296 {
6297 CPLDebug("GDAL", "Cannot save statistics on a non-PAM dataset");
6298 return false;
6299 }
6300
6301 poPamDS->StoreMDArrayStatistics(GetFullName().c_str(),
6302 bApproxStats,
6303 dfMin, dfMax,
6304 dfMean, dfStdDev,
6305 nValidCount );
6306
6307 return false;
6308 }
6309
6310
6311 /************************************************************************/
6312 /* ~GDALExtendedDataType() */
6313 /************************************************************************/
6314
6315 GDALExtendedDataType::~GDALExtendedDataType() = default;
6316
6317 /************************************************************************/
6318 /* GDALExtendedDataType() */
6319 /************************************************************************/
6320
GDALExtendedDataType(size_t nMaxStringLength)6321 GDALExtendedDataType::GDALExtendedDataType(size_t nMaxStringLength):
6322 m_eClass(GEDTC_STRING),
6323 m_nSize(sizeof(char*)),
6324 m_nMaxStringLength(nMaxStringLength)
6325 {}
6326
6327 /************************************************************************/
6328 /* GDALExtendedDataType() */
6329 /************************************************************************/
6330
GDALExtendedDataType(GDALDataType eType)6331 GDALExtendedDataType::GDALExtendedDataType(GDALDataType eType):
6332 m_eClass(GEDTC_NUMERIC),
6333 m_eNumericDT(eType),
6334 m_nSize(GDALGetDataTypeSizeBytes(eType))
6335 {}
6336
6337 /************************************************************************/
6338 /* GDALExtendedDataType() */
6339 /************************************************************************/
6340
GDALExtendedDataType(const std::string & osName,size_t nTotalSize,std::vector<std::unique_ptr<GDALEDTComponent>> && components)6341 GDALExtendedDataType::GDALExtendedDataType(
6342 const std::string& osName,
6343 size_t nTotalSize,
6344 std::vector<std::unique_ptr<GDALEDTComponent>>&& components):
6345 m_osName(osName),
6346 m_eClass(GEDTC_COMPOUND),
6347 m_aoComponents(std::move(components)),
6348 m_nSize(nTotalSize)
6349 {
6350 }
6351
6352 /************************************************************************/
6353 /* GDALExtendedDataType() */
6354 /************************************************************************/
6355
6356 /** Copy constructor. */
GDALExtendedDataType(const GDALExtendedDataType & other)6357 GDALExtendedDataType::GDALExtendedDataType(const GDALExtendedDataType& other):
6358 m_osName(other.m_osName),
6359 m_eClass(other.m_eClass),
6360 m_eNumericDT(other.m_eNumericDT),
6361 m_nSize(other.m_nSize),
6362 m_nMaxStringLength(other.m_nMaxStringLength)
6363 {
6364 if( m_eClass == GEDTC_COMPOUND )
6365 {
6366 for( const auto& elt: other.m_aoComponents )
6367 {
6368 m_aoComponents.emplace_back(new GDALEDTComponent(*elt));
6369 }
6370 }
6371 }
6372
6373 /************************************************************************/
6374 /* operator= () */
6375 /************************************************************************/
6376
6377 /** Move assignment. */
operator =(GDALExtendedDataType && other)6378 GDALExtendedDataType& GDALExtendedDataType::operator= (GDALExtendedDataType&& other)
6379 {
6380 m_osName = std::move(other.m_osName);
6381 m_eClass = other.m_eClass;
6382 m_eNumericDT = other.m_eNumericDT;
6383 m_nSize = other.m_nSize;
6384 m_nMaxStringLength = other.m_nMaxStringLength;
6385 m_aoComponents = std::move(other.m_aoComponents);
6386 other.m_eClass = GEDTC_NUMERIC;
6387 other.m_eNumericDT = GDT_Unknown;
6388 other.m_nSize = 0;
6389 other.m_nMaxStringLength = 0;
6390 return *this;
6391 }
6392
6393 /************************************************************************/
6394 /* Create() */
6395 /************************************************************************/
6396
6397 /** Return a new GDALExtendedDataType of class GEDTC_NUMERIC.
6398 *
6399 * This is the same as the C function GDALExtendedDataTypeCreate()
6400 *
6401 * @param eType Numeric data type.
6402 */
Create(GDALDataType eType)6403 GDALExtendedDataType GDALExtendedDataType::Create(GDALDataType eType)
6404 {
6405 return GDALExtendedDataType(eType);
6406 }
6407
6408 /************************************************************************/
6409 /* Create() */
6410 /************************************************************************/
6411
6412 /** Return a new GDALExtendedDataType of class GEDTC_COMPOUND.
6413 *
6414 * This is the same as the C function GDALExtendedDataTypeCreateCompound()
6415 *
6416 * @param osName Type name.
6417 * @param nTotalSize Total size of the type in bytes.
6418 * Should be large enough to store all components.
6419 * @param components Components of the compound type.
6420 */
Create(const std::string & osName,size_t nTotalSize,std::vector<std::unique_ptr<GDALEDTComponent>> && components)6421 GDALExtendedDataType GDALExtendedDataType::Create(
6422 const std::string& osName,
6423 size_t nTotalSize,
6424 std::vector<std::unique_ptr<GDALEDTComponent>>&& components)
6425 {
6426 size_t nLastOffset = 0;
6427 // Some arbitrary threshold to avoid potential integer overflows
6428 if( nTotalSize > static_cast<size_t>(std::numeric_limits<int>::max() / 2) )
6429 {
6430 CPLError(CE_Failure, CPLE_AppDefined, "Invalid offset/size");
6431 return GDALExtendedDataType(GDT_Unknown);
6432 }
6433 for( const auto& comp: components )
6434 {
6435 // Check alignment too ?
6436 if( comp->GetOffset() < nLastOffset )
6437 {
6438 CPLError(CE_Failure, CPLE_AppDefined, "Invalid offset/size");
6439 return GDALExtendedDataType(GDT_Unknown);
6440 }
6441 nLastOffset = comp->GetOffset() + comp->GetType().GetSize();
6442 }
6443 if( nTotalSize < nLastOffset )
6444 {
6445 CPLError(CE_Failure, CPLE_AppDefined, "Invalid offset/size");
6446 return GDALExtendedDataType(GDT_Unknown);
6447 }
6448 if( nTotalSize == 0 || components.empty() )
6449 {
6450 CPLError(CE_Failure, CPLE_AppDefined, "Empty compound not allowed");
6451 return GDALExtendedDataType(GDT_Unknown);
6452 }
6453 return GDALExtendedDataType(osName, nTotalSize, std::move(components));
6454 }
6455
6456 /************************************************************************/
6457 /* Create() */
6458 /************************************************************************/
6459
6460 /** Return a new GDALExtendedDataType of class GEDTC_STRING.
6461 *
6462 * This is the same as the C function GDALExtendedDataTypeCreateString().
6463 *
6464 * @param nMaxStringLength maximum length of a string in bytes. 0 if unknown/unlimited
6465 */
CreateString(size_t nMaxStringLength)6466 GDALExtendedDataType GDALExtendedDataType::CreateString(size_t nMaxStringLength)
6467 {
6468 return GDALExtendedDataType(nMaxStringLength);
6469 }
6470
6471 /************************************************************************/
6472 /* operator==() */
6473 /************************************************************************/
6474
6475 /** Equality operator.
6476 *
6477 * This is the same as the C function GDALExtendedDataTypeEquals().
6478 */
operator ==(const GDALExtendedDataType & other) const6479 bool GDALExtendedDataType::operator==(const GDALExtendedDataType& other) const
6480 {
6481 if( m_eClass != other.m_eClass ||
6482 m_nSize != other.m_nSize ||
6483 m_osName != other.m_osName )
6484 {
6485 return false;
6486 }
6487 if( m_eClass == GEDTC_NUMERIC )
6488 {
6489 return m_eNumericDT == other.m_eNumericDT;
6490 }
6491 if( m_eClass == GEDTC_STRING )
6492 {
6493 return true;
6494 }
6495 CPLAssert( m_eClass == GEDTC_COMPOUND );
6496 if( m_aoComponents.size() != other.m_aoComponents.size() )
6497 {
6498 return false;
6499 }
6500 for( size_t i = 0; i < m_aoComponents.size(); i++ )
6501 {
6502 if( !(*m_aoComponents[i] == *other.m_aoComponents[i]) )
6503 {
6504 return false;
6505 }
6506 }
6507 return true;
6508 }
6509
6510 /************************************************************************/
6511 /* CanConvertTo() */
6512 /************************************************************************/
6513
6514 /** Return whether this data type can be converted to the other one.
6515 *
6516 * This is the same as the C function GDALExtendedDataTypeCanConvertTo().
6517 *
6518 * @param other Target data type for the conversion being considered.
6519 */
CanConvertTo(const GDALExtendedDataType & other) const6520 bool GDALExtendedDataType::CanConvertTo(const GDALExtendedDataType& other) const
6521 {
6522 if( m_eClass == GEDTC_NUMERIC )
6523 {
6524 if( m_eNumericDT == GDT_Unknown )
6525 return false;
6526 if( other.m_eClass == GEDTC_NUMERIC && other.m_eNumericDT == GDT_Unknown )
6527 return false;
6528 return other.m_eClass == GEDTC_NUMERIC || other.m_eClass == GEDTC_STRING;
6529 }
6530 if( m_eClass == GEDTC_STRING )
6531 {
6532 return other.m_eClass == m_eClass;
6533 }
6534 CPLAssert( m_eClass == GEDTC_COMPOUND );
6535 if( other.m_eClass != GEDTC_COMPOUND )
6536 return false;
6537 std::map<std::string, const std::unique_ptr<GDALEDTComponent>*> srcComponents;
6538 for( const auto& srcComp: m_aoComponents )
6539 {
6540 srcComponents[srcComp->GetName()] = &srcComp;
6541 }
6542 for( const auto& dstComp: other.m_aoComponents )
6543 {
6544 auto oIter = srcComponents.find(dstComp->GetName());
6545 if( oIter == srcComponents.end() )
6546 return false;
6547 if( !(*(oIter->second))->GetType().CanConvertTo(dstComp->GetType()) )
6548 return false;
6549 }
6550 return true;
6551 }
6552
6553 /************************************************************************/
6554 /* NeedsFreeDynamicMemory() */
6555 /************************************************************************/
6556
6557 /** Return whether the data type holds dynamically allocated memory, that
6558 * needs to be freed with FreeDynamicMemory().
6559 *
6560 */
NeedsFreeDynamicMemory() const6561 bool GDALExtendedDataType::NeedsFreeDynamicMemory() const
6562 {
6563 switch( m_eClass )
6564 {
6565 case GEDTC_STRING:
6566 return true;
6567
6568 case GEDTC_NUMERIC:
6569 return false;
6570
6571 case GEDTC_COMPOUND:
6572 {
6573 for( const auto& comp: m_aoComponents )
6574 {
6575 if( comp->GetType().NeedsFreeDynamicMemory() )
6576 return true;
6577 }
6578 }
6579 }
6580 return false;
6581 }
6582
6583 /************************************************************************/
6584 /* FreeDynamicMemory() */
6585 /************************************************************************/
6586
6587 /** Release the dynamic memory (strings typically) from a raw value.
6588 *
6589 * This is the same as the C function GDALExtendedDataTypeFreeDynamicMemory().
6590 *
6591 * @param pBuffer Raw buffer of a single element of an attribute or array value.
6592 */
FreeDynamicMemory(void * pBuffer) const6593 void GDALExtendedDataType::FreeDynamicMemory(void* pBuffer) const
6594 {
6595 switch( m_eClass )
6596 {
6597 case GEDTC_STRING:
6598 {
6599 char* pszStr;
6600 memcpy(&pszStr, pBuffer, sizeof(char*));
6601 if( pszStr )
6602 {
6603 VSIFree(pszStr);
6604 }
6605 break;
6606 }
6607
6608 case GEDTC_NUMERIC:
6609 {
6610 break;
6611 }
6612
6613 case GEDTC_COMPOUND:
6614 {
6615 GByte* pabyBuffer = static_cast<GByte*>(pBuffer);
6616 for( const auto& comp: m_aoComponents )
6617 {
6618 comp->GetType().FreeDynamicMemory(pabyBuffer + comp->GetOffset());
6619 }
6620 break;
6621 }
6622 }
6623 }
6624
6625
6626 /************************************************************************/
6627 /* ~GDALEDTComponent() */
6628 /************************************************************************/
6629
6630 GDALEDTComponent::~GDALEDTComponent() = default;
6631
6632 /************************************************************************/
6633 /* GDALEDTComponent() */
6634 /************************************************************************/
6635
6636 /** constructor of a GDALEDTComponent
6637 *
6638 * This is the same as the C function GDALEDTComponendCreate()
6639 *
6640 * @param name Component name
6641 * @param offset Offset in byte of the component in the compound data type.
6642 * In case of nesting of compound data type, this should be
6643 * the offset to the immediate belonging data type, not to the
6644 * higher level one.
6645 * @param type Component data type.
6646 */
GDALEDTComponent(const std::string & name,size_t offset,const GDALExtendedDataType & type)6647 GDALEDTComponent::GDALEDTComponent(const std::string& name,
6648 size_t offset,
6649 const GDALExtendedDataType& type):
6650 m_osName(name),
6651 m_nOffset(offset),
6652 m_oType(type)
6653 {}
6654
6655 /************************************************************************/
6656 /* GDALEDTComponent() */
6657 /************************************************************************/
6658
6659 /** Copy constructor. */
6660 GDALEDTComponent::GDALEDTComponent(const GDALEDTComponent&) = default;
6661
6662 /************************************************************************/
6663 /* operator==() */
6664 /************************************************************************/
6665
6666 /** Equality operator.
6667 */
operator ==(const GDALEDTComponent & other) const6668 bool GDALEDTComponent::operator==(const GDALEDTComponent& other) const
6669 {
6670 return m_osName == other.m_osName &&
6671 m_nOffset == other.m_nOffset &&
6672 m_oType == other.m_oType;
6673 }
6674
6675 /************************************************************************/
6676 /* ~GDALDimension() */
6677 /************************************************************************/
6678
6679 GDALDimension::~GDALDimension() = default;
6680
6681 /************************************************************************/
6682 /* GDALDimension() */
6683 /************************************************************************/
6684
6685 //! @cond Doxygen_Suppress
6686 /** Constructor.
6687 *
6688 * @param osParentName Parent name
6689 * @param osName name
6690 * @param osType type. See GetType().
6691 * @param osDirection direction. See GetDirection().
6692 * @param nSize size.
6693 */
GDALDimension(const std::string & osParentName,const std::string & osName,const std::string & osType,const std::string & osDirection,GUInt64 nSize)6694 GDALDimension::GDALDimension(const std::string& osParentName,
6695 const std::string& osName,
6696 const std::string& osType,
6697 const std::string& osDirection,
6698 GUInt64 nSize):
6699 m_osName(osName),
6700 m_osFullName(!osParentName.empty() ? ((osParentName == "/" ? "/" : osParentName + "/") + osName) : osName),
6701 m_osType(osType),
6702 m_osDirection(osDirection),
6703 m_nSize(nSize)
6704 {
6705 }
6706 //! @endcond
6707
6708 /************************************************************************/
6709 /* GetIndexingVariable() */
6710 /************************************************************************/
6711
6712 /** Return the variable that is used to index the dimension (if there is one).
6713 *
6714 * This is the array, typically one-dimensional, describing the values taken
6715 * by the dimension.
6716 */
GetIndexingVariable() const6717 std::shared_ptr<GDALMDArray> GDALDimension::GetIndexingVariable() const
6718 {
6719 return nullptr;
6720 }
6721
6722 /************************************************************************/
6723 /* SetIndexingVariable() */
6724 /************************************************************************/
6725
6726 /** Set the variable that is used to index the dimension.
6727 *
6728 * This is the array, typically one-dimensional, describing the values taken
6729 * by the dimension.
6730 *
6731 * Optionally implemented by drivers.
6732 *
6733 * Drivers known to implement it: MEM.
6734 *
6735 * @param poArray Variable to use to index the dimension.
6736 * @return true in case of success.
6737 */
SetIndexingVariable(CPL_UNUSED std::shared_ptr<GDALMDArray> poArray)6738 bool GDALDimension::SetIndexingVariable(CPL_UNUSED std::shared_ptr<GDALMDArray> poArray)
6739 {
6740 CPLError(CE_Failure, CPLE_NotSupported, "SetIndexingVariable() not implemented");
6741 return false;
6742 }
6743
6744 /************************************************************************/
6745 /************************************************************************/
6746 /************************************************************************/
6747 /* C API */
6748 /************************************************************************/
6749 /************************************************************************/
6750 /************************************************************************/
6751
6752
6753 struct GDALExtendedDataTypeHS
6754 {
6755 std::unique_ptr<GDALExtendedDataType> m_poImpl;
6756
GDALExtendedDataTypeHSGDALExtendedDataTypeHS6757 explicit GDALExtendedDataTypeHS(GDALExtendedDataType* dt): m_poImpl(dt) {}
6758 };
6759
6760 struct GDALEDTComponentHS
6761 {
6762 std::unique_ptr<GDALEDTComponent> m_poImpl;
6763
GDALEDTComponentHSGDALEDTComponentHS6764 explicit GDALEDTComponentHS(const GDALEDTComponent& component):
6765 m_poImpl(new GDALEDTComponent(component)) {}
6766 };
6767
6768 struct GDALGroupHS
6769 {
6770 std::shared_ptr<GDALGroup> m_poImpl;
6771
GDALGroupHSGDALGroupHS6772 explicit GDALGroupHS(const std::shared_ptr<GDALGroup>& poGroup): m_poImpl(poGroup) {}
6773 };
6774
6775 struct GDALMDArrayHS
6776 {
6777 std::shared_ptr<GDALMDArray> m_poImpl;
6778
GDALMDArrayHSGDALMDArrayHS6779 explicit GDALMDArrayHS(const std::shared_ptr<GDALMDArray>& poArray): m_poImpl(poArray) {}
6780 };
6781
6782 struct GDALAttributeHS
6783 {
6784 std::shared_ptr<GDALAttribute> m_poImpl;
6785
GDALAttributeHSGDALAttributeHS6786 explicit GDALAttributeHS(const std::shared_ptr<GDALAttribute>& poAttr): m_poImpl(poAttr) {}
6787 };
6788
6789 struct GDALDimensionHS
6790 {
6791 std::shared_ptr<GDALDimension> m_poImpl;
6792
GDALDimensionHSGDALDimensionHS6793 explicit GDALDimensionHS(const std::shared_ptr<GDALDimension>& poDim): m_poImpl(poDim) {}
6794 };
6795
6796 /************************************************************************/
6797 /* GDALExtendedDataTypeCreate() */
6798 /************************************************************************/
6799
6800 /** Return a new GDALExtendedDataType of class GEDTC_NUMERIC.
6801 *
6802 * This is the same as the C++ method GDALExtendedDataType::Create()
6803 *
6804 * The returned handle should be freed with GDALExtendedDataTypeRelease().
6805 *
6806 * @param eType Numeric data type.
6807 *
6808 * @return a new GDALExtendedDataTypeH handle, or nullptr.
6809 */
GDALExtendedDataTypeCreate(GDALDataType eType)6810 GDALExtendedDataTypeH GDALExtendedDataTypeCreate(GDALDataType eType)
6811 {
6812 return new GDALExtendedDataTypeHS(
6813 new GDALExtendedDataType(
6814 GDALExtendedDataType::Create(eType)));
6815 }
6816
6817 /************************************************************************/
6818 /* GDALExtendedDataTypeCreateString() */
6819 /************************************************************************/
6820
6821 /** Return a new GDALExtendedDataType of class GEDTC_STRING.
6822 *
6823 * This is the same as the C++ method GDALExtendedDataType::CreateString()
6824 *
6825 * The returned handle should be freed with GDALExtendedDataTypeRelease().
6826 *
6827 * @return a new GDALExtendedDataTypeH handle, or nullptr.
6828 */
GDALExtendedDataTypeCreateString(size_t nMaxStringLength)6829 GDALExtendedDataTypeH GDALExtendedDataTypeCreateString(size_t nMaxStringLength)
6830 {
6831 return new GDALExtendedDataTypeHS(
6832 new GDALExtendedDataType(
6833 GDALExtendedDataType::CreateString(nMaxStringLength)));
6834 }
6835
6836 /************************************************************************/
6837 /* GDALExtendedDataTypeCreateCompound() */
6838 /************************************************************************/
6839
6840 /** Return a new GDALExtendedDataType of class GEDTC_COMPOUND.
6841 *
6842 * This is the same as the C++ method GDALExtendedDataType::Create(const std::string&, size_t, std::vector<std::unique_ptr<GDALEDTComponent>>&&)
6843 *
6844 * The returned handle should be freed with GDALExtendedDataTypeRelease().
6845 *
6846 * @param pszName Type name.
6847 * @param nTotalSize Total size of the type in bytes.
6848 * Should be large enough to store all components.
6849 * @param nComponents Number of components in comps array.
6850 * @param comps Components.
6851 * @return a new GDALExtendedDataTypeH handle, or nullptr.
6852 */
GDALExtendedDataTypeCreateCompound(const char * pszName,size_t nTotalSize,size_t nComponents,const GDALEDTComponentH * comps)6853 GDALExtendedDataTypeH GDALExtendedDataTypeCreateCompound(
6854 const char* pszName, size_t nTotalSize, size_t nComponents,
6855 const GDALEDTComponentH* comps)
6856 {
6857 std::vector<std::unique_ptr<GDALEDTComponent>> compsCpp;
6858 for( size_t i = 0; i < nComponents; i++ )
6859 {
6860 compsCpp.emplace_back(std::unique_ptr<GDALEDTComponent>(
6861 new GDALEDTComponent(*(comps[i]->m_poImpl.get()))));
6862 }
6863 auto dt = GDALExtendedDataType::Create(pszName ? pszName : "",
6864 nTotalSize, std::move(compsCpp));
6865 if( dt.GetClass() != GEDTC_COMPOUND )
6866 return nullptr;
6867 return new GDALExtendedDataTypeHS(new GDALExtendedDataType(dt));
6868 }
6869
6870 /************************************************************************/
6871 /* GDALExtendedDataTypeRelease() */
6872 /************************************************************************/
6873
6874 /** Release the GDAL in-memory object associated with a GDALExtendedDataTypeH.
6875 *
6876 * Note: when applied on a object coming from a driver, this does not
6877 * destroy the object in the file, database, etc...
6878 */
GDALExtendedDataTypeRelease(GDALExtendedDataTypeH hEDT)6879 void GDALExtendedDataTypeRelease(GDALExtendedDataTypeH hEDT)
6880 {
6881 delete hEDT;
6882 }
6883
6884 /************************************************************************/
6885 /* GDALExtendedDataTypeGetName() */
6886 /************************************************************************/
6887
6888 /** Return type name.
6889 *
6890 * This is the same as the C++ method GDALExtendedDataType::GetName()
6891 */
GDALExtendedDataTypeGetName(GDALExtendedDataTypeH hEDT)6892 const char* GDALExtendedDataTypeGetName(GDALExtendedDataTypeH hEDT)
6893 {
6894 VALIDATE_POINTER1( hEDT, __func__, "" );
6895 return hEDT->m_poImpl->GetName().c_str();
6896 }
6897
6898 /************************************************************************/
6899 /* GDALExtendedDataTypeGetClass() */
6900 /************************************************************************/
6901
6902 /** Return type class.
6903 *
6904 * This is the same as the C++ method GDALExtendedDataType::GetClass()
6905 */
GDALExtendedDataTypeGetClass(GDALExtendedDataTypeH hEDT)6906 GDALExtendedDataTypeClass GDALExtendedDataTypeGetClass(GDALExtendedDataTypeH hEDT)
6907 {
6908 VALIDATE_POINTER1( hEDT, __func__, GEDTC_NUMERIC );
6909 return hEDT->m_poImpl->GetClass();
6910 }
6911
6912 /************************************************************************/
6913 /* GDALExtendedDataTypeGetNumericDataType() */
6914 /************************************************************************/
6915
6916 /** Return numeric data type (only valid when GetClass() == GEDTC_NUMERIC)
6917 *
6918 * This is the same as the C++ method GDALExtendedDataType::GetNumericDataType()
6919 */
GDALExtendedDataTypeGetNumericDataType(GDALExtendedDataTypeH hEDT)6920 GDALDataType GDALExtendedDataTypeGetNumericDataType(GDALExtendedDataTypeH hEDT)
6921 {
6922 VALIDATE_POINTER1( hEDT, __func__, GDT_Unknown );
6923 return hEDT->m_poImpl->GetNumericDataType();
6924 }
6925
6926 /************************************************************************/
6927 /* GDALExtendedDataTypeGetSize() */
6928 /************************************************************************/
6929
6930 /** Return data type size in bytes.
6931 *
6932 * This is the same as the C++ method GDALExtendedDataType::GetSize()
6933 */
GDALExtendedDataTypeGetSize(GDALExtendedDataTypeH hEDT)6934 size_t GDALExtendedDataTypeGetSize(GDALExtendedDataTypeH hEDT)
6935 {
6936 VALIDATE_POINTER1( hEDT, __func__, 0 );
6937 return hEDT->m_poImpl->GetSize();
6938 }
6939
6940 /************************************************************************/
6941 /* GDALExtendedDataTypeGetMaxStringLength() */
6942 /************************************************************************/
6943
6944 /** Return the maximum length of a string in bytes.
6945 *
6946 * 0 indicates unknown/unlimited string.
6947 *
6948 * This is the same as the C++ method GDALExtendedDataType::GetMaxStringLength()
6949 */
GDALExtendedDataTypeGetMaxStringLength(GDALExtendedDataTypeH hEDT)6950 size_t GDALExtendedDataTypeGetMaxStringLength(GDALExtendedDataTypeH hEDT)
6951 {
6952 VALIDATE_POINTER1( hEDT, __func__, 0 );
6953 return hEDT->m_poImpl->GetMaxStringLength();
6954 }
6955
6956 /************************************************************************/
6957 /* GDALExtendedDataTypeCanConvertTo() */
6958 /************************************************************************/
6959
6960 /** Return whether this data type can be converted to the other one.
6961 *
6962 * This is the same as the C function GDALExtendedDataType::CanConvertTo()
6963 *
6964 * @param hSourceEDT Source data type for the conversion being considered.
6965 * @param hTargetEDT Target data type for the conversion being considered.
6966 * @return TRUE if hSourceEDT can be convert to hTargetEDT. FALSE otherwise.
6967 */
GDALExtendedDataTypeCanConvertTo(GDALExtendedDataTypeH hSourceEDT,GDALExtendedDataTypeH hTargetEDT)6968 int GDALExtendedDataTypeCanConvertTo(GDALExtendedDataTypeH hSourceEDT,
6969 GDALExtendedDataTypeH hTargetEDT)
6970 {
6971 VALIDATE_POINTER1( hSourceEDT, __func__, FALSE );
6972 VALIDATE_POINTER1( hTargetEDT, __func__, FALSE );
6973 return hSourceEDT->m_poImpl->CanConvertTo(*(hTargetEDT->m_poImpl));
6974 }
6975
6976 /************************************************************************/
6977 /* GDALExtendedDataTypeEquals() */
6978 /************************************************************************/
6979
6980 /** Return whether this data type is equal to another one.
6981 *
6982 * This is the same as the C++ method GDALExtendedDataType::operator==()
6983 *
6984 * @param hFirstEDT First data type.
6985 * @param hSecondEDT Second data type.
6986 * @return TRUE if they are equal. FALSE otherwise.
6987 */
GDALExtendedDataTypeEquals(GDALExtendedDataTypeH hFirstEDT,GDALExtendedDataTypeH hSecondEDT)6988 int GDALExtendedDataTypeEquals(GDALExtendedDataTypeH hFirstEDT,
6989 GDALExtendedDataTypeH hSecondEDT)
6990 {
6991 VALIDATE_POINTER1( hFirstEDT, __func__, FALSE );
6992 VALIDATE_POINTER1( hSecondEDT, __func__, FALSE );
6993 return *(hFirstEDT->m_poImpl) == *(hSecondEDT->m_poImpl);
6994 }
6995
6996 /************************************************************************/
6997 /* GDALExtendedDataTypeGetComponents() */
6998 /************************************************************************/
6999
7000 /** Return the components of the data type (only valid when GetClass() == GEDTC_COMPOUND)
7001 *
7002 * The returned array and its content must be freed with GDALExtendedDataTypeFreeComponents(). If only the array itself needs to be
7003 * freed, CPLFree() should be called (and GDALExtendedDataTypeRelease() on
7004 * individual array members).
7005 *
7006 * This is the same as the C++ method GDALExtendedDataType::GetComponents()
7007 *
7008 * @param hEDT Data type
7009 * @param pnCount Pointer to the number of values returned. Must NOT be NULL.
7010 * @return an array of *pnCount components.
7011 */
GDALExtendedDataTypeGetComponents(GDALExtendedDataTypeH hEDT,size_t * pnCount)7012 GDALEDTComponentH *GDALExtendedDataTypeGetComponents(
7013 GDALExtendedDataTypeH hEDT, size_t* pnCount)
7014 {
7015 VALIDATE_POINTER1( hEDT, __func__, nullptr );
7016 VALIDATE_POINTER1( pnCount, __func__, nullptr );
7017 const auto& components = hEDT->m_poImpl->GetComponents();
7018 auto ret = static_cast<GDALEDTComponentH*>(
7019 CPLMalloc(sizeof(GDALEDTComponentH) * components.size()));
7020 for( size_t i = 0; i < components.size(); i++ )
7021 {
7022 ret[i] = new GDALEDTComponentHS(*components[i].get());
7023 }
7024 *pnCount = components.size();
7025 return ret;
7026 }
7027
7028 /************************************************************************/
7029 /* GDALExtendedDataTypeFreeComponents() */
7030 /************************************************************************/
7031
7032 /** Free the return of GDALExtendedDataTypeGetComponents().
7033 *
7034 * @param components return value of GDALExtendedDataTypeGetComponents()
7035 * @param nCount *pnCount value returned by GDALExtendedDataTypeGetComponents()
7036 */
GDALExtendedDataTypeFreeComponents(GDALEDTComponentH * components,size_t nCount)7037 void GDALExtendedDataTypeFreeComponents(GDALEDTComponentH* components, size_t nCount)
7038 {
7039 for( size_t i = 0; i < nCount; i++ )
7040 {
7041 delete components[i];
7042 }
7043 CPLFree(components);
7044 }
7045
7046 /************************************************************************/
7047 /* GDALEDTComponentCreate() */
7048 /************************************************************************/
7049
7050 /** Create a new GDALEDTComponent.
7051 *
7052 * The returned value must be freed with GDALEDTComponentRelease().
7053 *
7054 * This is the same as the C++ constructor GDALEDTComponent::GDALEDTComponent().
7055 */
GDALEDTComponentCreate(const char * pszName,size_t nOffset,GDALExtendedDataTypeH hType)7056 GDALEDTComponentH GDALEDTComponentCreate(const char* pszName, size_t nOffset, GDALExtendedDataTypeH hType)
7057 {
7058 VALIDATE_POINTER1( pszName, __func__, nullptr );
7059 VALIDATE_POINTER1( hType, __func__, nullptr );
7060 return new GDALEDTComponentHS(GDALEDTComponent(pszName, nOffset, *(hType->m_poImpl.get())));
7061 }
7062
7063 /************************************************************************/
7064 /* GDALEDTComponentRelease() */
7065 /************************************************************************/
7066
7067 /** Release the GDAL in-memory object associated with a GDALEDTComponentH.
7068 *
7069 * Note: when applied on a object coming from a driver, this does not
7070 * destroy the object in the file, database, etc...
7071 */
GDALEDTComponentRelease(GDALEDTComponentH hComp)7072 void GDALEDTComponentRelease(GDALEDTComponentH hComp)
7073 {
7074 delete hComp;
7075 }
7076
7077 /************************************************************************/
7078 /* GDALEDTComponentGetName() */
7079 /************************************************************************/
7080
7081 /** Return the name.
7082 *
7083 * The returned pointer is valid until hComp is released.
7084 *
7085 * This is the same as the C++ method GDALEDTComponent::GetName().
7086 */
GDALEDTComponentGetName(GDALEDTComponentH hComp)7087 const char * GDALEDTComponentGetName(GDALEDTComponentH hComp)
7088 {
7089 VALIDATE_POINTER1( hComp, __func__, nullptr );
7090 return hComp->m_poImpl->GetName().c_str();
7091 }
7092
7093 /************************************************************************/
7094 /* GDALEDTComponentGetOffset() */
7095 /************************************************************************/
7096
7097 /** Return the offset (in bytes) of the component in the compound data type.
7098 *
7099 * This is the same as the C++ method GDALEDTComponent::GetOffset().
7100 */
GDALEDTComponentGetOffset(GDALEDTComponentH hComp)7101 size_t GDALEDTComponentGetOffset(GDALEDTComponentH hComp)
7102 {
7103 VALIDATE_POINTER1( hComp, __func__, 0 );
7104 return hComp->m_poImpl->GetOffset();
7105 }
7106
7107 /************************************************************************/
7108 /* GDALEDTComponentGetType() */
7109 /************************************************************************/
7110
7111 /** Return the data type of the component.
7112 *
7113 * This is the same as the C++ method GDALEDTComponent::GetType().
7114 */
GDALEDTComponentGetType(GDALEDTComponentH hComp)7115 GDALExtendedDataTypeH GDALEDTComponentGetType(GDALEDTComponentH hComp)
7116 {
7117 VALIDATE_POINTER1( hComp, __func__, nullptr );
7118 return new GDALExtendedDataTypeHS(
7119 new GDALExtendedDataType(hComp->m_poImpl->GetType()));
7120 }
7121
7122 /************************************************************************/
7123 /* GDALGroupRelease() */
7124 /************************************************************************/
7125
7126 /** Release the GDAL in-memory object associated with a GDALGroupH.
7127 *
7128 * Note: when applied on a object coming from a driver, this does not
7129 * destroy the object in the file, database, etc...
7130 */
GDALGroupRelease(GDALGroupH hGroup)7131 void GDALGroupRelease(GDALGroupH hGroup)
7132 {
7133 delete hGroup;
7134 }
7135
7136 /************************************************************************/
7137 /* GDALGroupGetName() */
7138 /************************************************************************/
7139
7140 /** Return the name of the group.
7141 *
7142 * The returned pointer is valid until hGroup is released.
7143 *
7144 * This is the same as the C++ method GDALGroup::GetName().
7145 */
GDALGroupGetName(GDALGroupH hGroup)7146 const char *GDALGroupGetName(GDALGroupH hGroup)
7147 {
7148 VALIDATE_POINTER1( hGroup, __func__, nullptr );
7149 return hGroup->m_poImpl->GetName().c_str();
7150 }
7151
7152 /************************************************************************/
7153 /* GDALGroupGetFullName() */
7154 /************************************************************************/
7155
7156 /** Return the full name of the group.
7157 *
7158 * The returned pointer is valid until hGroup is released.
7159 *
7160 * This is the same as the C++ method GDALGroup::GetFullName().
7161 */
GDALGroupGetFullName(GDALGroupH hGroup)7162 const char *GDALGroupGetFullName(GDALGroupH hGroup)
7163 {
7164 VALIDATE_POINTER1( hGroup, __func__, nullptr );
7165 return hGroup->m_poImpl->GetFullName().c_str();
7166 }
7167
7168 /************************************************************************/
7169 /* GDALGroupGetMDArrayNames() */
7170 /************************************************************************/
7171
7172 /** Return the list of multidimensional array names contained in this group.
7173 *
7174 * This is the same as the C++ method GDALGroup::GetGroupNames().
7175 *
7176 * @return the array names, to be freed with CSLDestroy()
7177 */
GDALGroupGetMDArrayNames(GDALGroupH hGroup,CSLConstList papszOptions)7178 char **GDALGroupGetMDArrayNames(GDALGroupH hGroup, CSLConstList papszOptions)
7179 {
7180 VALIDATE_POINTER1( hGroup, __func__, nullptr );
7181 auto names = hGroup->m_poImpl->GetMDArrayNames(papszOptions);
7182 CPLStringList res;
7183 for( const auto& name: names )
7184 {
7185 res.AddString(name.c_str());
7186 }
7187 return res.StealList();
7188 }
7189
7190 /************************************************************************/
7191 /* GDALGroupOpenMDArray() */
7192 /************************************************************************/
7193
7194 /** Open and return a multidimensional array.
7195 *
7196 * This is the same as the C++ method GDALGroup::OpenMDArray().
7197 *
7198 * @return the array, to be freed with GDALMDArrayRelease(), or nullptr.
7199 */
GDALGroupOpenMDArray(GDALGroupH hGroup,const char * pszMDArrayName,CSLConstList papszOptions)7200 GDALMDArrayH GDALGroupOpenMDArray(GDALGroupH hGroup, const char* pszMDArrayName,
7201 CSLConstList papszOptions)
7202 {
7203 VALIDATE_POINTER1( hGroup, __func__, nullptr );
7204 VALIDATE_POINTER1( pszMDArrayName, __func__, nullptr );
7205 auto array = hGroup->m_poImpl->OpenMDArray(std::string(pszMDArrayName), papszOptions);
7206 if( !array )
7207 return nullptr;
7208 return new GDALMDArrayHS(array);
7209 }
7210
7211 /************************************************************************/
7212 /* GDALGroupOpenMDArrayFromFullname() */
7213 /************************************************************************/
7214
7215 /** Open and return a multidimensional array from its fully qualified name.
7216 *
7217 * This is the same as the C++ method GDALGroup::OpenMDArrayFromFullname().
7218 *
7219 * @return the array, to be freed with GDALMDArrayRelease(), or nullptr.
7220 *
7221 * @since GDAL 3.2
7222 */
GDALGroupOpenMDArrayFromFullname(GDALGroupH hGroup,const char * pszFullname,CSLConstList papszOptions)7223 GDALMDArrayH GDALGroupOpenMDArrayFromFullname(GDALGroupH hGroup, const char* pszFullname,
7224 CSLConstList papszOptions)
7225 {
7226 VALIDATE_POINTER1( hGroup, __func__, nullptr );
7227 VALIDATE_POINTER1( pszFullname, __func__, nullptr );
7228 auto array = hGroup->m_poImpl->OpenMDArrayFromFullname(std::string(pszFullname), papszOptions);
7229 if( !array )
7230 return nullptr;
7231 return new GDALMDArrayHS(array);
7232 }
7233
7234
7235
7236 /************************************************************************/
7237 /* GDALGroupResolveMDArray() */
7238 /************************************************************************/
7239
7240 /** Locate an array in a group and its subgroups by name.
7241 *
7242 * See GDALGroup::ResolveMDArray() for description of the behavior.
7243 * @since GDAL 3.2
7244 */
GDALGroupResolveMDArray(GDALGroupH hGroup,const char * pszName,const char * pszStartingPoint,CSLConstList papszOptions)7245 GDALMDArrayH GDALGroupResolveMDArray(GDALGroupH hGroup,
7246 const char* pszName,
7247 const char* pszStartingPoint,
7248 CSLConstList papszOptions)
7249 {
7250 VALIDATE_POINTER1( hGroup, __func__, nullptr );
7251 VALIDATE_POINTER1( pszName, __func__, nullptr );
7252 VALIDATE_POINTER1( pszStartingPoint, __func__, nullptr );
7253 auto array = hGroup->m_poImpl->ResolveMDArray(std::string(pszName),
7254 std::string(pszStartingPoint),
7255 papszOptions);
7256 if( !array )
7257 return nullptr;
7258 return new GDALMDArrayHS(array);
7259 }
7260
7261 /************************************************************************/
7262 /* GDALGroupGetGroupNames() */
7263 /************************************************************************/
7264
7265 /** Return the list of sub-groups contained in this group.
7266 *
7267 * This is the same as the C++ method GDALGroup::GetGroupNames().
7268 *
7269 * @return the group names, to be freed with CSLDestroy()
7270 */
GDALGroupGetGroupNames(GDALGroupH hGroup,CSLConstList papszOptions)7271 char **GDALGroupGetGroupNames(GDALGroupH hGroup, CSLConstList papszOptions)
7272 {
7273 VALIDATE_POINTER1( hGroup, __func__, nullptr );
7274 auto names = hGroup->m_poImpl->GetGroupNames(papszOptions);
7275 CPLStringList res;
7276 for( const auto& name: names )
7277 {
7278 res.AddString(name.c_str());
7279 }
7280 return res.StealList();
7281 }
7282
7283 /************************************************************************/
7284 /* GDALGroupOpenGroup() */
7285 /************************************************************************/
7286
7287 /** Open and return a sub-group.
7288 *
7289 * This is the same as the C++ method GDALGroup::OpenGroup().
7290 *
7291 * @return the sub-group, to be freed with GDALGroupRelease(), or nullptr.
7292 */
GDALGroupOpenGroup(GDALGroupH hGroup,const char * pszSubGroupName,CSLConstList papszOptions)7293 GDALGroupH GDALGroupOpenGroup(GDALGroupH hGroup, const char* pszSubGroupName,
7294 CSLConstList papszOptions)
7295 {
7296 VALIDATE_POINTER1( hGroup, __func__, nullptr );
7297 VALIDATE_POINTER1( pszSubGroupName, __func__, nullptr );
7298 auto subGroup = hGroup->m_poImpl->OpenGroup(std::string(pszSubGroupName), papszOptions);
7299 if( !subGroup )
7300 return nullptr;
7301 return new GDALGroupHS(subGroup);
7302 }
7303
7304 /************************************************************************/
7305 /* GDALGroupOpenMDArrayFromFullname() */
7306 /************************************************************************/
7307
7308 /** Open and return a sub-group from its fully qualified name.
7309 *
7310 * This is the same as the C++ method GDALGroup::OpenGroupFromFullname().
7311 *
7312 * @return the sub-group, to be freed with GDALGroupRelease(), or nullptr.
7313 *
7314 * @since GDAL 3.2
7315 */
GDALGroupOpenGroupFromFullname(GDALGroupH hGroup,const char * pszFullname,CSLConstList papszOptions)7316 GDALGroupH GDALGroupOpenGroupFromFullname(GDALGroupH hGroup, const char* pszFullname,
7317 CSLConstList papszOptions)
7318 {
7319 VALIDATE_POINTER1( hGroup, __func__, nullptr );
7320 VALIDATE_POINTER1( pszFullname, __func__, nullptr );
7321 auto subGroup = hGroup->m_poImpl->OpenGroupFromFullname(std::string(pszFullname), papszOptions);
7322 if( !subGroup )
7323 return nullptr;
7324 return new GDALGroupHS(subGroup);
7325 }
7326
7327 /************************************************************************/
7328 /* GDALGroupGetDimensions() */
7329 /************************************************************************/
7330
7331 /** Return the list of dimensions contained in this group and used by its
7332 * arrays.
7333 *
7334 * The returned array must be freed with GDALReleaseDimensions(). If only the array itself needs to be
7335 * freed, CPLFree() should be called (and GDALDimensionRelease() on
7336 * individual array members).
7337 *
7338 * This is the same as the C++ method GDALGroup::GetDimensions().
7339 *
7340 * @param hGroup Group.
7341 * @param pnCount Pointer to the number of values returned. Must NOT be NULL.
7342 * @param papszOptions Driver specific options determining how dimensions
7343 * should be retrieved. Pass nullptr for default behavior.
7344 *
7345 * @return an array of *pnCount dimensions.
7346 */
GDALGroupGetDimensions(GDALGroupH hGroup,size_t * pnCount,CSLConstList papszOptions)7347 GDALDimensionH *GDALGroupGetDimensions(GDALGroupH hGroup, size_t* pnCount,
7348 CSLConstList papszOptions)
7349 {
7350 VALIDATE_POINTER1( hGroup, __func__, nullptr );
7351 VALIDATE_POINTER1( pnCount, __func__, nullptr );
7352 auto dims = hGroup->m_poImpl->GetDimensions(papszOptions);
7353 auto ret = static_cast<GDALDimensionH*>(
7354 CPLMalloc(sizeof(GDALDimensionH) * dims.size()));
7355 for( size_t i = 0; i < dims.size(); i++ )
7356 {
7357 ret[i] = new GDALDimensionHS(dims[i]);
7358 }
7359 *pnCount = dims.size();
7360 return ret;
7361 }
7362
7363 /************************************************************************/
7364 /* GDALGroupGetAttribute() */
7365 /************************************************************************/
7366
7367 /** Return an attribute by its name.
7368 *
7369 * This is the same as the C++ method GDALIHasAttribute::GetAttribute()
7370 *
7371 * The returned attribute must be freed with GDALAttributeRelease().
7372 */
GDALGroupGetAttribute(GDALGroupH hGroup,const char * pszName)7373 GDALAttributeH GDALGroupGetAttribute(GDALGroupH hGroup, const char* pszName)
7374 {
7375 VALIDATE_POINTER1( hGroup, __func__, nullptr );
7376 VALIDATE_POINTER1( pszName, __func__, nullptr );
7377 auto attr = hGroup->m_poImpl->GetAttribute(std::string(pszName));
7378 if( attr )
7379 return new GDALAttributeHS(attr);
7380 return nullptr;
7381 }
7382
7383 /************************************************************************/
7384 /* GDALGroupGetAttributes() */
7385 /************************************************************************/
7386
7387 /** Return the list of attributes contained in this group.
7388 *
7389 * The returned array must be freed with GDALReleaseAttributes(). If only the array itself needs to be
7390 * freed, CPLFree() should be called (and GDALAttributeRelease() on
7391 * individual array members).
7392 *
7393 * This is the same as the C++ method GDALGroup::GetAttributes().
7394 *
7395 * @param hGroup Group.
7396 * @param pnCount Pointer to the number of values returned. Must NOT be NULL.
7397 * @param papszOptions Driver specific options determining how attributes
7398 * should be retrieved. Pass nullptr for default behavior.
7399 *
7400 * @return an array of *pnCount attributes.
7401 */
GDALGroupGetAttributes(GDALGroupH hGroup,size_t * pnCount,CSLConstList papszOptions)7402 GDALAttributeH *GDALGroupGetAttributes(GDALGroupH hGroup, size_t* pnCount,
7403 CSLConstList papszOptions)
7404 {
7405 VALIDATE_POINTER1( hGroup, __func__, nullptr );
7406 VALIDATE_POINTER1( pnCount, __func__, nullptr );
7407 auto attrs = hGroup->m_poImpl->GetAttributes(papszOptions);
7408 auto ret = static_cast<GDALAttributeH*>(
7409 CPLMalloc(sizeof(GDALAttributeH) * attrs.size()));
7410 for( size_t i = 0; i < attrs.size(); i++ )
7411 {
7412 ret[i] = new GDALAttributeHS(attrs[i]);
7413 }
7414 *pnCount = attrs.size();
7415 return ret;
7416 }
7417
7418 /************************************************************************/
7419 /* GDALGroupGetStructuralInfo() */
7420 /************************************************************************/
7421
7422 /** Return structural information on the group.
7423 *
7424 * This may be the compression, etc..
7425 *
7426 * The return value should not be freed and is valid until GDALGroup is
7427 * released or this function called again.
7428 *
7429 * This is the same as the C++ method GDALGroup::GetStruturalInfo().
7430 */
GDALGroupGetStructuralInfo(GDALGroupH hGroup)7431 CSLConstList GDALGroupGetStructuralInfo(GDALGroupH hGroup)
7432 {
7433 VALIDATE_POINTER1( hGroup, __func__, nullptr );
7434 return hGroup->m_poImpl->GetStructuralInfo();
7435 }
7436
7437 /************************************************************************/
7438 /* GDALReleaseAttributes() */
7439 /************************************************************************/
7440
7441 /** Free the return of GDALGroupGetAttributes() or GDALMDArrayGetAttributes()
7442 *
7443 * @param attributes return pointer of above methods
7444 * @param nCount *pnCount value returned by above methods
7445 */
GDALReleaseAttributes(GDALAttributeH * attributes,size_t nCount)7446 void GDALReleaseAttributes(GDALAttributeH* attributes, size_t nCount)
7447 {
7448 for( size_t i = 0; i < nCount; i++ )
7449 {
7450 delete attributes[i];
7451 }
7452 CPLFree(attributes);
7453 }
7454
7455 /************************************************************************/
7456 /* GDALGroupCreateGroup() */
7457 /************************************************************************/
7458
7459 /** Create a sub-group within a group.
7460 *
7461 * This is the same as the C++ method GDALGroup::CreateGroup().
7462 *
7463 * @return the sub-group, to be freed with GDALGroupRelease(), or nullptr.
7464 */
GDALGroupCreateGroup(GDALGroupH hGroup,const char * pszSubGroupName,CSLConstList papszOptions)7465 GDALGroupH GDALGroupCreateGroup(GDALGroupH hGroup,
7466 const char* pszSubGroupName,
7467 CSLConstList papszOptions)
7468 {
7469 VALIDATE_POINTER1( hGroup, __func__, nullptr );
7470 VALIDATE_POINTER1( pszSubGroupName, __func__, nullptr );
7471 auto ret = hGroup->m_poImpl->CreateGroup(std::string(pszSubGroupName),
7472 papszOptions);
7473 if( !ret )
7474 return nullptr;
7475 return new GDALGroupHS(ret);
7476 }
7477
7478 /************************************************************************/
7479 /* GDALGroupCreateDimension() */
7480 /************************************************************************/
7481
7482 /** Create a dimension within a group.
7483 *
7484 * This is the same as the C++ method GDALGroup::CreateDimension().
7485 *
7486 * @return the dimension, to be freed with GDALDimensionRelease(), or nullptr.
7487 */
GDALGroupCreateDimension(GDALGroupH hGroup,const char * pszName,const char * pszType,const char * pszDirection,GUInt64 nSize,CSLConstList papszOptions)7488 GDALDimensionH GDALGroupCreateDimension(GDALGroupH hGroup,
7489 const char* pszName,
7490 const char* pszType,
7491 const char* pszDirection,
7492 GUInt64 nSize,
7493 CSLConstList papszOptions)
7494 {
7495 VALIDATE_POINTER1( hGroup, __func__, nullptr );
7496 VALIDATE_POINTER1( pszName, __func__, nullptr );
7497 auto ret = hGroup->m_poImpl->CreateDimension(std::string(pszName),
7498 std::string(pszType ? pszType : ""),
7499 std::string(pszDirection ? pszDirection: ""),
7500 nSize,
7501 papszOptions);
7502 if( !ret )
7503 return nullptr;
7504 return new GDALDimensionHS(ret);
7505 }
7506
7507 /************************************************************************/
7508 /* GDALGroupCreateMDArray() */
7509 /************************************************************************/
7510
7511 /** Create a multidimensional array within a group.
7512 *
7513 * This is the same as the C++ method GDALGroup::CreateMDArray().
7514 *
7515 * @return the array, to be freed with GDALMDArrayRelease(), or nullptr.
7516 */
GDALGroupCreateMDArray(GDALGroupH hGroup,const char * pszName,size_t nDimensions,GDALDimensionH * pahDimensions,GDALExtendedDataTypeH hEDT,CSLConstList papszOptions)7517 GDALMDArrayH GDALGroupCreateMDArray(GDALGroupH hGroup,
7518 const char* pszName,
7519 size_t nDimensions,
7520 GDALDimensionH* pahDimensions,
7521 GDALExtendedDataTypeH hEDT,
7522 CSLConstList papszOptions)
7523 {
7524 VALIDATE_POINTER1( hGroup, __func__, nullptr );
7525 VALIDATE_POINTER1( pszName, __func__, nullptr );
7526 VALIDATE_POINTER1( hEDT, __func__, nullptr );
7527 std::vector<std::shared_ptr<GDALDimension>> dims;
7528 dims.reserve(nDimensions);
7529 for(size_t i = 0; i < nDimensions; i++)
7530 dims.push_back(pahDimensions[i]->m_poImpl);
7531 auto ret = hGroup->m_poImpl->CreateMDArray(std::string(pszName),
7532 dims,
7533 *(hEDT->m_poImpl),
7534 papszOptions);
7535 if( !ret )
7536 return nullptr;
7537 return new GDALMDArrayHS(ret);
7538 }
7539
7540 /************************************************************************/
7541 /* GDALGroupCreateAttribute() */
7542 /************************************************************************/
7543
7544 /** Create a attribute within a group.
7545 *
7546 * This is the same as the C++ method GDALGroup::CreateAttribute().
7547 *
7548 * @return the attribute, to be freed with GDALAttributeRelease(), or nullptr.
7549 */
GDALGroupCreateAttribute(GDALGroupH hGroup,const char * pszName,size_t nDimensions,const GUInt64 * panDimensions,GDALExtendedDataTypeH hEDT,CSLConstList papszOptions)7550 GDALAttributeH GDALGroupCreateAttribute(GDALGroupH hGroup,
7551 const char* pszName,
7552 size_t nDimensions,
7553 const GUInt64* panDimensions,
7554 GDALExtendedDataTypeH hEDT,
7555 CSLConstList papszOptions)
7556 {
7557 VALIDATE_POINTER1( hGroup, __func__, nullptr );
7558 VALIDATE_POINTER1( hEDT, __func__, nullptr );
7559 std::vector<GUInt64> dims;
7560 dims.reserve(nDimensions);
7561 for(size_t i = 0; i < nDimensions; i++)
7562 dims.push_back(panDimensions[i]);
7563 auto ret = hGroup->m_poImpl->CreateAttribute(std::string(pszName),
7564 dims,
7565 *(hEDT->m_poImpl),
7566 papszOptions);
7567 if( !ret )
7568 return nullptr;
7569 return new GDALAttributeHS(ret);
7570 }
7571
7572 /************************************************************************/
7573 /* GDALMDArrayRelease() */
7574 /************************************************************************/
7575
7576 /** Release the GDAL in-memory object associated with a GDALMDArray.
7577 *
7578 * Note: when applied on a object coming from a driver, this does not
7579 * destroy the object in the file, database, etc...
7580 */
GDALMDArrayRelease(GDALMDArrayH hMDArray)7581 void GDALMDArrayRelease(GDALMDArrayH hMDArray)
7582 {
7583 delete hMDArray;
7584 }
7585
7586 /************************************************************************/
7587 /* GDALMDArrayGetName() */
7588 /************************************************************************/
7589
7590 /** Return array name.
7591 *
7592 * This is the same as the C++ method GDALMDArray::GetName()
7593 */
GDALMDArrayGetName(GDALMDArrayH hArray)7594 const char* GDALMDArrayGetName(GDALMDArrayH hArray)
7595 {
7596 VALIDATE_POINTER1( hArray, __func__, nullptr );
7597 return hArray->m_poImpl->GetName().c_str();
7598 }
7599
7600 /************************************************************************/
7601 /* GDALMDArrayGetFullName() */
7602 /************************************************************************/
7603
7604 /** Return array full name.
7605 *
7606 * This is the same as the C++ method GDALMDArray::GetFullName()
7607 */
GDALMDArrayGetFullName(GDALMDArrayH hArray)7608 const char* GDALMDArrayGetFullName(GDALMDArrayH hArray)
7609 {
7610 VALIDATE_POINTER1( hArray, __func__, nullptr );
7611 return hArray->m_poImpl->GetFullName().c_str();
7612 }
7613
7614 /************************************************************************/
7615 /* GDALMDArrayGetName() */
7616 /************************************************************************/
7617
7618 /** Return the total number of values in the array.
7619 *
7620 * This is the same as the C++ method GDALAbstractMDArray::GetTotalElementsCount()
7621 */
GDALMDArrayGetTotalElementsCount(GDALMDArrayH hArray)7622 GUInt64 GDALMDArrayGetTotalElementsCount(GDALMDArrayH hArray)
7623 {
7624 VALIDATE_POINTER1( hArray, __func__, 0 );
7625 return hArray->m_poImpl->GetTotalElementsCount();
7626 }
7627
7628 /************************************************************************/
7629 /* GDALMDArrayGetDimensionCount() */
7630 /************************************************************************/
7631
7632 /** Return the number of dimensions.
7633 *
7634 * This is the same as the C++ method GDALAbstractMDArray::GetDimensionCount()
7635 */
GDALMDArrayGetDimensionCount(GDALMDArrayH hArray)7636 size_t GDALMDArrayGetDimensionCount(GDALMDArrayH hArray)
7637 {
7638 VALIDATE_POINTER1( hArray, __func__, 0 );
7639 return hArray->m_poImpl->GetDimensionCount();
7640 }
7641
7642 /************************************************************************/
7643 /* GDALMDArrayGetDimensions() */
7644 /************************************************************************/
7645
7646 /** Return the dimensions of the array
7647 *
7648 * The returned array must be freed with GDALReleaseDimensions(). If only the array itself needs to be
7649 * freed, CPLFree() should be called (and GDALDimensionRelease() on
7650 * individual array members).
7651 *
7652 * This is the same as the C++ method GDALAbstractMDArray::GetDimensions()
7653 *
7654 * @param hArray Array.
7655 * @param pnCount Pointer to the number of values returned. Must NOT be NULL.
7656 *
7657 * @return an array of *pnCount dimensions.
7658 */
GDALMDArrayGetDimensions(GDALMDArrayH hArray,size_t * pnCount)7659 GDALDimensionH* GDALMDArrayGetDimensions(GDALMDArrayH hArray, size_t *pnCount)
7660 {
7661 VALIDATE_POINTER1( hArray, __func__, nullptr );
7662 VALIDATE_POINTER1( pnCount, __func__, nullptr );
7663 const auto& dims(hArray->m_poImpl->GetDimensions());
7664 auto ret = static_cast<GDALDimensionH*>(
7665 CPLMalloc(sizeof(GDALDimensionH) * dims.size()));
7666 for( size_t i = 0; i < dims.size(); i++ )
7667 {
7668 ret[i] = new GDALDimensionHS(dims[i]);
7669 }
7670 *pnCount = dims.size();
7671 return ret;
7672 }
7673
7674 /************************************************************************/
7675 /* GDALReleaseDimensions() */
7676 /************************************************************************/
7677
7678 /** Free the return of GDALGroupGetDimensions() or GDALMDArrayGetDimensions()
7679 *
7680 * @param dims return pointer of above methods
7681 * @param nCount *pnCount value returned by above methods
7682 */
GDALReleaseDimensions(GDALDimensionH * dims,size_t nCount)7683 void GDALReleaseDimensions(GDALDimensionH* dims, size_t nCount)
7684 {
7685 for( size_t i = 0; i < nCount; i++ )
7686 {
7687 delete dims[i];
7688 }
7689 CPLFree(dims);
7690 }
7691
7692 /************************************************************************/
7693 /* GDALMDArrayGetDataType() */
7694 /************************************************************************/
7695
7696 /** Return the data type
7697 *
7698 * The return must be freed with GDALExtendedDataTypeRelease().
7699 */
GDALMDArrayGetDataType(GDALMDArrayH hArray)7700 GDALExtendedDataTypeH GDALMDArrayGetDataType(GDALMDArrayH hArray)
7701 {
7702 VALIDATE_POINTER1( hArray, __func__, nullptr );
7703 return new GDALExtendedDataTypeHS(
7704 new GDALExtendedDataType(hArray->m_poImpl->GetDataType()));
7705 }
7706
7707 /************************************************************************/
7708 /* GDALMDArrayRead() */
7709 /************************************************************************/
7710
7711 /** Read part or totality of a multidimensional array.
7712 *
7713 * This is the same as the C++ method GDALAbstractMDArray::Read()
7714 *
7715 * @return TRUE in case of success.
7716 */
GDALMDArrayRead(GDALMDArrayH hArray,const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride,GDALExtendedDataTypeH bufferDataType,void * pDstBuffer,const void * pDstBufferAllocStart,size_t nDstBufferAllocSize)7717 int GDALMDArrayRead(GDALMDArrayH hArray,
7718 const GUInt64* arrayStartIdx,
7719 const size_t* count,
7720 const GInt64* arrayStep,
7721 const GPtrDiff_t* bufferStride,
7722 GDALExtendedDataTypeH bufferDataType,
7723 void* pDstBuffer,
7724 const void* pDstBufferAllocStart,
7725 size_t nDstBufferAllocSize)
7726 {
7727 VALIDATE_POINTER1( hArray, __func__, FALSE );
7728 if( (arrayStartIdx == nullptr || count == nullptr) &&
7729 hArray->m_poImpl->GetDimensionCount() > 0 )
7730 {
7731 VALIDATE_POINTER1( arrayStartIdx, __func__, FALSE );
7732 VALIDATE_POINTER1( count, __func__, FALSE );
7733 }
7734 VALIDATE_POINTER1( bufferDataType, __func__, FALSE );
7735 VALIDATE_POINTER1( pDstBuffer, __func__, FALSE );
7736 // coverity[var_deref_model]
7737 return hArray->m_poImpl->Read(arrayStartIdx,
7738 count,
7739 arrayStep,
7740 bufferStride,
7741 *(bufferDataType->m_poImpl),
7742 pDstBuffer,
7743 pDstBufferAllocStart,
7744 nDstBufferAllocSize);
7745 }
7746
7747 /************************************************************************/
7748 /* GDALMDArrayWrite() */
7749 /************************************************************************/
7750
7751 /** Write part or totality of a multidimensional array.
7752 *
7753 * This is the same as the C++ method GDALAbstractMDArray::Write()
7754 *
7755 * @return TRUE in case of success.
7756 */
GDALMDArrayWrite(GDALMDArrayH hArray,const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride,GDALExtendedDataTypeH bufferDataType,const void * pSrcBuffer,const void * pSrcBufferAllocStart,size_t nSrcBufferAllocSize)7757 int GDALMDArrayWrite(GDALMDArrayH hArray,
7758 const GUInt64* arrayStartIdx,
7759 const size_t* count,
7760 const GInt64* arrayStep,
7761 const GPtrDiff_t* bufferStride,
7762 GDALExtendedDataTypeH bufferDataType,
7763 const void* pSrcBuffer,
7764 const void* pSrcBufferAllocStart,
7765 size_t nSrcBufferAllocSize)
7766 {
7767 VALIDATE_POINTER1( hArray, __func__, FALSE );
7768 if( (arrayStartIdx == nullptr || count == nullptr) &&
7769 hArray->m_poImpl->GetDimensionCount() > 0 )
7770 {
7771 VALIDATE_POINTER1( arrayStartIdx, __func__, FALSE );
7772 VALIDATE_POINTER1( count, __func__, FALSE );
7773 }
7774 VALIDATE_POINTER1( bufferDataType, __func__, FALSE );
7775 VALIDATE_POINTER1( pSrcBuffer, __func__, FALSE );
7776 // coverity[var_deref_model]
7777 return hArray->m_poImpl->Write(arrayStartIdx,
7778 count,
7779 arrayStep,
7780 bufferStride,
7781 *(bufferDataType->m_poImpl),
7782 pSrcBuffer,
7783 pSrcBufferAllocStart,
7784 nSrcBufferAllocSize);
7785 }
7786
7787 /************************************************************************/
7788 /* GDALMDArrayAdviseRead() */
7789 /************************************************************************/
7790
7791 /** Advise driver of upcoming read requests.
7792 *
7793 * This is the same as the C++ method GDALMDArray::AdviseRead()
7794 *
7795 * @return TRUE in case of success.
7796 *
7797 * @since GDAL 3.2
7798 */
GDALMDArrayAdviseRead(GDALMDArrayH hArray,const GUInt64 * arrayStartIdx,const size_t * count)7799 int GDALMDArrayAdviseRead(GDALMDArrayH hArray,
7800 const GUInt64* arrayStartIdx,
7801 const size_t* count)
7802 {
7803 VALIDATE_POINTER1( hArray, __func__, FALSE );
7804 // coverity[var_deref_model]
7805 return hArray->m_poImpl->AdviseRead(arrayStartIdx, count);
7806 }
7807
7808 /************************************************************************/
7809 /* GDALMDArrayGetAttribute() */
7810 /************************************************************************/
7811
7812 /** Return an attribute by its name.
7813 *
7814 * This is the same as the C++ method GDALIHasAttribute::GetAttribute()
7815 *
7816 * The returned attribute must be freed with GDALAttributeRelease().
7817 */
GDALMDArrayGetAttribute(GDALMDArrayH hArray,const char * pszName)7818 GDALAttributeH GDALMDArrayGetAttribute(GDALMDArrayH hArray, const char* pszName)
7819 {
7820 VALIDATE_POINTER1( hArray, __func__, nullptr );
7821 VALIDATE_POINTER1( pszName, __func__, nullptr );
7822 auto attr = hArray->m_poImpl->GetAttribute(std::string(pszName));
7823 if( attr )
7824 return new GDALAttributeHS(attr);
7825 return nullptr;
7826 }
7827
7828 /************************************************************************/
7829 /* GDALMDArrayGetAttributes() */
7830 /************************************************************************/
7831
7832 /** Return the list of attributes contained in this array.
7833 *
7834 * The returned array must be freed with GDALReleaseAttributes(). If only the array itself needs to be
7835 * freed, CPLFree() should be called (and GDALAttributeRelease() on
7836 * individual array members).
7837 *
7838 * This is the same as the C++ method GDALMDArray::GetAttributes().
7839 *
7840 * @param hArray Array.
7841 * @param pnCount Pointer to the number of values returned. Must NOT be NULL.
7842 * @param papszOptions Driver specific options determining how attributes
7843 * should be retrieved. Pass nullptr for default behavior.
7844 *
7845 * @return an array of *pnCount attributes.
7846 */
GDALMDArrayGetAttributes(GDALMDArrayH hArray,size_t * pnCount,CSLConstList papszOptions)7847 GDALAttributeH *GDALMDArrayGetAttributes(GDALMDArrayH hArray, size_t* pnCount,
7848 CSLConstList papszOptions)
7849 {
7850 VALIDATE_POINTER1( hArray, __func__, nullptr );
7851 VALIDATE_POINTER1( pnCount, __func__, nullptr );
7852 auto attrs = hArray->m_poImpl->GetAttributes(papszOptions);
7853 auto ret = static_cast<GDALAttributeH*>(
7854 CPLMalloc(sizeof(GDALAttributeH) * attrs.size()));
7855 for( size_t i = 0; i < attrs.size(); i++ )
7856 {
7857 ret[i] = new GDALAttributeHS(attrs[i]);
7858 }
7859 *pnCount = attrs.size();
7860 return ret;
7861 }
7862
7863 /************************************************************************/
7864 /* GDALMDArrayCreateAttribute() */
7865 /************************************************************************/
7866
7867 /** Create a attribute within an array.
7868 *
7869 * This is the same as the C++ method GDALMDArray::CreateAttribute().
7870 *
7871 * @return the attribute, to be freed with GDALAttributeRelease(), or nullptr.
7872 */
GDALMDArrayCreateAttribute(GDALMDArrayH hArray,const char * pszName,size_t nDimensions,const GUInt64 * panDimensions,GDALExtendedDataTypeH hEDT,CSLConstList papszOptions)7873 GDALAttributeH GDALMDArrayCreateAttribute(GDALMDArrayH hArray,
7874 const char* pszName,
7875 size_t nDimensions,
7876 const GUInt64* panDimensions,
7877 GDALExtendedDataTypeH hEDT,
7878 CSLConstList papszOptions)
7879 {
7880 VALIDATE_POINTER1( hArray, __func__, nullptr );
7881 VALIDATE_POINTER1( pszName, __func__, nullptr );
7882 VALIDATE_POINTER1( hEDT, __func__, nullptr );
7883 std::vector<GUInt64> dims;
7884 dims.reserve(nDimensions);
7885 for(size_t i = 0; i < nDimensions; i++)
7886 dims.push_back(panDimensions[i]);
7887 auto ret = hArray->m_poImpl->CreateAttribute(std::string(pszName),
7888 dims,
7889 *(hEDT->m_poImpl),
7890 papszOptions);
7891 if( !ret )
7892 return nullptr;
7893 return new GDALAttributeHS(ret);
7894 }
7895
7896 /************************************************************************/
7897 /* GDALMDArrayGetRawNoDataValue() */
7898 /************************************************************************/
7899
7900 /** Return the nodata value as a "raw" value.
7901 *
7902 * The value returned might be nullptr in case of no nodata value. When
7903 * a nodata value is registered, a non-nullptr will be returned whose size in
7904 * bytes is GetDataType().GetSize().
7905 *
7906 * The returned value should not be modified or freed.
7907 *
7908 * This is the same as the ++ method GDALMDArray::GetRawNoDataValue().
7909 *
7910 * @return nullptr or a pointer to GetDataType().GetSize() bytes.
7911 */
GDALMDArrayGetRawNoDataValue(GDALMDArrayH hArray)7912 const void *GDALMDArrayGetRawNoDataValue(GDALMDArrayH hArray)
7913 {
7914 VALIDATE_POINTER1( hArray, __func__, nullptr );
7915 return hArray->m_poImpl->GetRawNoDataValue();
7916 }
7917
7918 /************************************************************************/
7919 /* GDALMDArrayGetNoDataValueAsDouble() */
7920 /************************************************************************/
7921
7922 /** Return the nodata value as a double.
7923 *
7924 * The value returned might be nullptr in case of no nodata value. When
7925 * a nodata value is registered, a non-nullptr will be returned whose size in
7926 * bytes is GetDataType().GetSize().
7927 *
7928 * This is the same as the C++ method GDALMDArray::GetNoDataValueAsDouble().
7929 *
7930 * @param hArray Array handle.
7931 * @param pbHasNoDataValue Pointer to a output boolean that will be set to true if
7932 * a nodata value exists and can be converted to double. Might be nullptr.
7933 *
7934 * @return the nodata value as a double. A 0.0 value might also indicate the
7935 * absence of a nodata value or an error in the conversion (*pbHasNoDataValue will be
7936 * set to false then).
7937 */
GDALMDArrayGetNoDataValueAsDouble(GDALMDArrayH hArray,int * pbHasNoDataValue)7938 double GDALMDArrayGetNoDataValueAsDouble(GDALMDArrayH hArray,
7939 int* pbHasNoDataValue)
7940 {
7941 VALIDATE_POINTER1( hArray, __func__, 0 );
7942 bool bHasNodataValue = false;
7943 double ret = hArray->m_poImpl->GetNoDataValueAsDouble(&bHasNodataValue);
7944 if( pbHasNoDataValue )
7945 *pbHasNoDataValue = bHasNodataValue;
7946 return ret;
7947 }
7948
7949 /************************************************************************/
7950 /* GDALMDArraySetRawNoDataValue() */
7951 /************************************************************************/
7952
7953 /** Set the nodata value as a "raw" value.
7954 *
7955 * The value passed might be nullptr in case of no nodata value. When
7956 * a nodata value is registered, a non-nullptr whose size in
7957 * bytes is GetDataType().GetSize() must be passed.
7958 *
7959 * This is the same as the C++ method GDALMDArray::SetRawNoDataValue(const void*).
7960 *
7961 * @return TRUE in case of success.
7962 */
GDALMDArraySetRawNoDataValue(GDALMDArrayH hArray,const void * pNoData)7963 int GDALMDArraySetRawNoDataValue(GDALMDArrayH hArray, const void* pNoData)
7964 {
7965 VALIDATE_POINTER1( hArray, __func__, FALSE );
7966 return hArray->m_poImpl->SetRawNoDataValue(pNoData);
7967 }
7968
7969 /************************************************************************/
7970 /* GDALMDArraySetNoDataValueAsDouble() */
7971 /************************************************************************/
7972
7973 /** Set the nodata value as a double.
7974 *
7975 * If the natural data type of the attribute/array is not double, type conversion
7976 * will occur to the type returned by GetDataType().
7977 *
7978 * This is the same as the C++ method GDALMDArray::SetNoDataValue(double).
7979 *
7980 * @return TRUE in case of success.
7981 */
GDALMDArraySetNoDataValueAsDouble(GDALMDArrayH hArray,double dfNoDataValue)7982 int GDALMDArraySetNoDataValueAsDouble(GDALMDArrayH hArray,
7983 double dfNoDataValue)
7984 {
7985 VALIDATE_POINTER1( hArray, __func__, FALSE );
7986 return hArray->m_poImpl->SetNoDataValue(dfNoDataValue);
7987 }
7988
7989 /************************************************************************/
7990 /* GDALMDArraySetScale() */
7991 /************************************************************************/
7992
7993 /** Set the scale value to apply to raw values.
7994 *
7995 * unscaled_value = raw_value * GetScale() + GetOffset()
7996 *
7997 * This is the same as the C++ method GDALMDArray::SetScale().
7998 *
7999 * @return TRUE in case of success.
8000 */
GDALMDArraySetScale(GDALMDArrayH hArray,double dfScale)8001 int GDALMDArraySetScale(GDALMDArrayH hArray, double dfScale)
8002 {
8003 VALIDATE_POINTER1( hArray, __func__, FALSE );
8004 return hArray->m_poImpl->SetScale(dfScale);
8005 }
8006
8007 /************************************************************************/
8008 /* GDALMDArraySetScaleEx() */
8009 /************************************************************************/
8010
8011 /** Set the scale value to apply to raw values.
8012 *
8013 * unscaled_value = raw_value * GetScale() + GetOffset()
8014 *
8015 * This is the same as the C++ method GDALMDArray::SetScale().
8016 *
8017 * @return TRUE in case of success.
8018 * @since GDAL 3.3
8019 */
GDALMDArraySetScaleEx(GDALMDArrayH hArray,double dfScale,GDALDataType eStorageType)8020 int GDALMDArraySetScaleEx(GDALMDArrayH hArray, double dfScale,
8021 GDALDataType eStorageType)
8022 {
8023 VALIDATE_POINTER1( hArray, __func__, FALSE );
8024 return hArray->m_poImpl->SetScale(dfScale, eStorageType);
8025 }
8026
8027 /************************************************************************/
8028 /* GDALMDArraySetOffset() */
8029 /************************************************************************/
8030
8031 /** Set the scale value to apply to raw values.
8032 *
8033 * unscaled_value = raw_value * GetScale() + GetOffset()
8034 *
8035 * This is the same as the C++ method GDALMDArray::SetOffset().
8036 *
8037 * @return TRUE in case of success.
8038 */
GDALMDArraySetOffset(GDALMDArrayH hArray,double dfOffset)8039 int GDALMDArraySetOffset(GDALMDArrayH hArray, double dfOffset)
8040 {
8041 VALIDATE_POINTER1( hArray, __func__, FALSE );
8042 return hArray->m_poImpl->SetOffset(dfOffset);
8043 }
8044
8045 /************************************************************************/
8046 /* GDALMDArraySetOffsetEx() */
8047 /************************************************************************/
8048
8049 /** Set the scale value to apply to raw values.
8050 *
8051 * unscaled_value = raw_value * GetOffset() + GetOffset()
8052 *
8053 * This is the same as the C++ method GDALMDArray::SetOffset().
8054 *
8055 * @return TRUE in case of success.
8056 * @since GDAL 3.3
8057 */
GDALMDArraySetOffsetEx(GDALMDArrayH hArray,double dfOffset,GDALDataType eStorageType)8058 int GDALMDArraySetOffsetEx(GDALMDArrayH hArray, double dfOffset,
8059 GDALDataType eStorageType)
8060 {
8061 VALIDATE_POINTER1( hArray, __func__, FALSE );
8062 return hArray->m_poImpl->SetOffset(dfOffset, eStorageType);
8063 }
8064
8065 /************************************************************************/
8066 /* GDALMDArrayGetScale() */
8067 /************************************************************************/
8068
8069 /** Get the scale value to apply to raw values.
8070 *
8071 * unscaled_value = raw_value * GetScale() + GetOffset()
8072 *
8073 * This is the same as the C++ method GDALMDArray::GetScale().
8074 *
8075 * @return the scale value
8076 */
GDALMDArrayGetScale(GDALMDArrayH hArray,int * pbHasValue)8077 double GDALMDArrayGetScale(GDALMDArrayH hArray, int* pbHasValue)
8078 {
8079 VALIDATE_POINTER1( hArray, __func__, 0.0 );
8080 bool bHasValue = false;
8081 double dfRet = hArray->m_poImpl->GetScale(&bHasValue);
8082 if( pbHasValue )
8083 *pbHasValue = bHasValue;
8084 return dfRet;
8085 }
8086
8087 /************************************************************************/
8088 /* GDALMDArrayGetScaleEx() */
8089 /************************************************************************/
8090
8091 /** Get the scale value to apply to raw values.
8092 *
8093 * unscaled_value = raw_value * GetScale() + GetScale()
8094 *
8095 * This is the same as the C++ method GDALMDArray::GetScale().
8096 *
8097 * @return the scale value
8098 * @since GDAL 3.3
8099 */
GDALMDArrayGetScaleEx(GDALMDArrayH hArray,int * pbHasValue,GDALDataType * peStorageType)8100 double GDALMDArrayGetScaleEx(GDALMDArrayH hArray, int* pbHasValue,
8101 GDALDataType* peStorageType)
8102 {
8103 VALIDATE_POINTER1( hArray, __func__, 0.0 );
8104 bool bHasValue = false;
8105 double dfRet = hArray->m_poImpl->GetScale(&bHasValue, peStorageType);
8106 if( pbHasValue )
8107 *pbHasValue = bHasValue;
8108 return dfRet;
8109 }
8110
8111 /************************************************************************/
8112 /* GDALMDArrayGetOffset() */
8113 /************************************************************************/
8114
8115 /** Get the scale value to apply to raw values.
8116 *
8117 * unscaled_value = raw_value * GetScale() + GetOffset()
8118 *
8119 * This is the same as the C++ method GDALMDArray::GetOffset().
8120 *
8121 * @return the scale value
8122 */
GDALMDArrayGetOffset(GDALMDArrayH hArray,int * pbHasValue)8123 double GDALMDArrayGetOffset(GDALMDArrayH hArray, int* pbHasValue)
8124 {
8125 VALIDATE_POINTER1( hArray, __func__, 0.0 );
8126 bool bHasValue = false;
8127 double dfRet = hArray->m_poImpl->GetOffset(&bHasValue);
8128 if( pbHasValue )
8129 *pbHasValue = bHasValue;
8130 return dfRet;
8131 }
8132
8133 /************************************************************************/
8134 /* GDALMDArrayGetOffsetEx() */
8135 /************************************************************************/
8136
8137 /** Get the scale value to apply to raw values.
8138 *
8139 * unscaled_value = raw_value * GetScale() + GetOffset()
8140 *
8141 * This is the same as the C++ method GDALMDArray::GetOffset().
8142 *
8143 * @return the scale value
8144 * @since GDAL 3.3
8145 */
GDALMDArrayGetOffsetEx(GDALMDArrayH hArray,int * pbHasValue,GDALDataType * peStorageType)8146 double GDALMDArrayGetOffsetEx(GDALMDArrayH hArray, int* pbHasValue,
8147 GDALDataType* peStorageType)
8148 {
8149 VALIDATE_POINTER1( hArray, __func__, 0.0 );
8150 bool bHasValue = false;
8151 double dfRet = hArray->m_poImpl->GetOffset(&bHasValue, peStorageType);
8152 if( pbHasValue )
8153 *pbHasValue = bHasValue;
8154 return dfRet;
8155 }
8156
8157 /************************************************************************/
8158 /* GDALMDArrayGetBlockSize() */
8159 /************************************************************************/
8160
8161 /** Return the "natural" block size of the array along all dimensions.
8162 *
8163 * Some drivers might organize the array in tiles/blocks and reading/writing
8164 * aligned on those tile/block boundaries will be more efficient.
8165 *
8166 * The returned number of elements in the vector is the same as
8167 * GetDimensionCount(). A value of 0 should be interpreted as no hint regarding
8168 * the natural block size along the considered dimension.
8169 * "Flat" arrays will typically return a vector of values set to 0.
8170 *
8171 * The default implementation will return a vector of values set to 0.
8172 *
8173 * This method is used by GetProcessingChunkSize().
8174 *
8175 * Pedantic note: the returned type is GUInt64, so in the highly unlikeley theoretical
8176 * case of a 32-bit platform, this might exceed its size_t allocation capabilities.
8177 *
8178 * This is the same as the C++ method GDALAbstractMDArray::GetBlockSize().
8179 *
8180 * @return the block size, in number of elements along each dimension.
8181 */
GDALMDArrayGetBlockSize(GDALMDArrayH hArray,size_t * pnCount)8182 GUInt64 *GDALMDArrayGetBlockSize(GDALMDArrayH hArray, size_t *pnCount)
8183 {
8184 VALIDATE_POINTER1( hArray, __func__, nullptr );
8185 VALIDATE_POINTER1( pnCount, __func__, nullptr );
8186 auto res = hArray->m_poImpl->GetBlockSize();
8187 auto ret = static_cast<GUInt64*>(
8188 CPLMalloc(sizeof(GUInt64) * res.size()));
8189 for( size_t i = 0; i < res.size(); i++ )
8190 {
8191 ret[i] = res[i];
8192 }
8193 *pnCount = res.size();
8194 return ret;
8195 }
8196
8197 /***********************************************************************/
8198 /* GDALMDArrayGetProcessingChunkSize() */
8199 /************************************************************************/
8200
8201 /** \brief Return an optimal chunk size for read/write oerations, given the natural
8202 * block size and memory constraints specified.
8203 *
8204 * This method will use GetBlockSize() to define a chunk whose dimensions are
8205 * multiple of those returned by GetBlockSize() (unless the block define by
8206 * GetBlockSize() is larger than nMaxChunkMemory, in which case it will be
8207 * returned by this method).
8208 *
8209 * This is the same as the C++ method GDALAbstractMDArray::GetProcessingChunkSize().
8210 *
8211 * @param hArray Array.
8212 * @param pnCount Pointer to the number of values returned. Must NOT be NULL.
8213 * @param nMaxChunkMemory Maximum amount of memory, in bytes, to use for the chunk.
8214 *
8215 * @return the chunk size, in number of elements along each dimension.
8216 */
8217
GDALMDArrayGetProcessingChunkSize(GDALMDArrayH hArray,size_t * pnCount,size_t nMaxChunkMemory)8218 size_t *GDALMDArrayGetProcessingChunkSize(GDALMDArrayH hArray, size_t *pnCount,
8219 size_t nMaxChunkMemory)
8220 {
8221 VALIDATE_POINTER1( hArray, __func__, nullptr );
8222 VALIDATE_POINTER1( pnCount, __func__, nullptr );
8223 auto res = hArray->m_poImpl->GetProcessingChunkSize(nMaxChunkMemory);
8224 auto ret = static_cast<size_t*>(
8225 CPLMalloc(sizeof(size_t) * res.size()));
8226 for( size_t i = 0; i < res.size(); i++ )
8227 {
8228 ret[i] = res[i];
8229 }
8230 *pnCount = res.size();
8231 return ret;
8232 }
8233
8234 /************************************************************************/
8235 /* GDALMDArrayGetStructuralInfo() */
8236 /************************************************************************/
8237
8238 /** Return structural information on the array.
8239 *
8240 * This may be the compression, etc..
8241 *
8242 * The return value should not be freed and is valid until GDALMDArray is
8243 * released or this function called again.
8244 *
8245 * This is the same as the C++ method GDALMDArray::GetStruturalInfo().
8246 */
GDALMDArrayGetStructuralInfo(GDALMDArrayH hArray)8247 CSLConstList GDALMDArrayGetStructuralInfo(GDALMDArrayH hArray)
8248 {
8249 VALIDATE_POINTER1( hArray, __func__, nullptr );
8250 return hArray->m_poImpl->GetStructuralInfo();
8251 }
8252
8253 /************************************************************************/
8254 /* GDALMDArrayGetView() */
8255 /************************************************************************/
8256
8257 /** Return a view of the array using slicing or field access.
8258 *
8259 * The returned object should be released with GDALMDArrayRelease().
8260 *
8261 * This is the same as the C++ method GDALMDArray::GetView().
8262 */
GDALMDArrayGetView(GDALMDArrayH hArray,const char * pszViewExpr)8263 GDALMDArrayH GDALMDArrayGetView(GDALMDArrayH hArray, const char* pszViewExpr)
8264 {
8265 VALIDATE_POINTER1( hArray, __func__, nullptr );
8266 VALIDATE_POINTER1( pszViewExpr, __func__, nullptr );
8267 auto sliced = hArray->m_poImpl->GetView(std::string(pszViewExpr));
8268 if( !sliced )
8269 return nullptr;
8270 return new GDALMDArrayHS(sliced);
8271 }
8272
8273 /************************************************************************/
8274 /* GDALMDArrayTranspose() */
8275 /************************************************************************/
8276
8277 /** Return a view of the array whose axis have been reordered.
8278 *
8279 * The returned object should be released with GDALMDArrayRelease().
8280 *
8281 * This is the same as the C++ method GDALMDArray::Transpose().
8282 */
GDALMDArrayTranspose(GDALMDArrayH hArray,size_t nNewAxisCount,const int * panMapNewAxisToOldAxis)8283 GDALMDArrayH GDALMDArrayTranspose(GDALMDArrayH hArray,
8284 size_t nNewAxisCount,
8285 const int *panMapNewAxisToOldAxis)
8286 {
8287 VALIDATE_POINTER1( hArray, __func__, nullptr );
8288 std::vector<int> anMapNewAxisToOldAxis(nNewAxisCount);
8289 if( nNewAxisCount )
8290 {
8291 memcpy(&anMapNewAxisToOldAxis[0], panMapNewAxisToOldAxis,
8292 nNewAxisCount * sizeof(int));
8293 }
8294 auto reordered = hArray->m_poImpl->Transpose(anMapNewAxisToOldAxis);
8295 if( !reordered )
8296 return nullptr;
8297 return new GDALMDArrayHS(reordered);
8298 }
8299
8300 /************************************************************************/
8301 /* GDALMDArrayGetUnscaled() */
8302 /************************************************************************/
8303
8304 /** Return an array that is the unscaled version of the current one.
8305 *
8306 * That is each value of the unscaled array will be
8307 * unscaled_value = raw_value * GetScale() + GetOffset()
8308 *
8309 * Starting with GDAL 3.3, the Write() method is implemented and will convert
8310 * from unscaled values to raw values.
8311 *
8312 * The returned object should be released with GDALMDArrayRelease().
8313 *
8314 * This is the same as the C++ method GDALMDArray::GetUnscaled().
8315 */
GDALMDArrayGetUnscaled(GDALMDArrayH hArray)8316 GDALMDArrayH GDALMDArrayGetUnscaled(GDALMDArrayH hArray)
8317 {
8318 VALIDATE_POINTER1( hArray, __func__, nullptr );
8319 auto unscaled = hArray->m_poImpl->GetUnscaled();
8320 if( !unscaled )
8321 return nullptr;
8322 return new GDALMDArrayHS(unscaled);
8323 }
8324
8325 /************************************************************************/
8326 /* GDALMDArrayGetMask() */
8327 /************************************************************************/
8328
8329 /** Return an array that is a mask for the current array
8330 *
8331 * This array will be of type Byte, with values set to 0 to indicate invalid
8332 * pixels of the current array, and values set to 1 to indicate valid pixels.
8333 *
8334 * The returned object should be released with GDALMDArrayRelease().
8335 *
8336 * This is the same as the C++ method GDALMDArray::GetMask().
8337 */
GDALMDArrayGetMask(GDALMDArrayH hArray,CSLConstList papszOptions)8338 GDALMDArrayH GDALMDArrayGetMask(GDALMDArrayH hArray, CSLConstList papszOptions)
8339 {
8340 VALIDATE_POINTER1( hArray, __func__, nullptr );
8341 auto unscaled = hArray->m_poImpl->GetMask(papszOptions);
8342 if( !unscaled )
8343 return nullptr;
8344 return new GDALMDArrayHS(unscaled);
8345 }
8346
8347 /************************************************************************/
8348 /* GDALMDArraySetUnit() */
8349 /************************************************************************/
8350
8351 /** Set the variable unit.
8352 *
8353 * Values should conform as much as possible with those allowed by
8354 * the NetCDF CF conventions:
8355 * http://cfconventions.org/Data/cf-conventions/cf-conventions-1.7/cf-conventions.html#units
8356 * but others might be returned.
8357 *
8358 * Few examples are "meter", "degrees", "second", ...
8359 * Empty value means unknown.
8360 *
8361 * This is the same as the C function GDALMDArraySetUnit()
8362 *
8363 * @param hArray array.
8364 * @param pszUnit unit name.
8365 * @return TRUE in case of success.
8366 */
GDALMDArraySetUnit(GDALMDArrayH hArray,const char * pszUnit)8367 int GDALMDArraySetUnit(GDALMDArrayH hArray, const char* pszUnit)
8368 {
8369 VALIDATE_POINTER1( hArray, __func__, FALSE );
8370 return hArray->m_poImpl->SetUnit(pszUnit ? pszUnit : "");
8371 }
8372
8373 /************************************************************************/
8374 /* GDALMDArrayGetUnit() */
8375 /************************************************************************/
8376
8377 /** Return the array unit.
8378 *
8379 * Values should conform as much as possible with those allowed by
8380 * the NetCDF CF conventions:
8381 * http://cfconventions.org/Data/cf-conventions/cf-conventions-1.7/cf-conventions.html#units
8382 * but others might be returned.
8383 *
8384 * Few examples are "meter", "degrees", "second", ...
8385 * Empty value means unknown.
8386 *
8387 * The return value should not be freed and is valid until GDALMDArray is
8388 * released or this function called again.
8389 *
8390 * This is the same as the C++ method GDALMDArray::GetUnit().
8391 */
GDALMDArrayGetUnit(GDALMDArrayH hArray)8392 const char* GDALMDArrayGetUnit(GDALMDArrayH hArray)
8393 {
8394 VALIDATE_POINTER1( hArray, __func__, nullptr );
8395 return hArray->m_poImpl->GetUnit().c_str();
8396 }
8397
8398
8399 /************************************************************************/
8400 /* GDALMDArrayGetSpatialRef() */
8401 /************************************************************************/
8402
8403 /** Assign a spatial reference system object to the the array.
8404 *
8405 * This is the same as the C++ method GDALMDArray::SetSpatialRef().
8406 * @return TRUE in case of success.
8407 */
GDALMDArraySetSpatialRef(GDALMDArrayH hArray,OGRSpatialReferenceH hSRS)8408 int GDALMDArraySetSpatialRef(GDALMDArrayH hArray,
8409 OGRSpatialReferenceH hSRS)
8410 {
8411 VALIDATE_POINTER1( hArray, __func__, FALSE );
8412 return hArray->m_poImpl->SetSpatialRef(OGRSpatialReference::FromHandle(hSRS));
8413 }
8414
8415 /************************************************************************/
8416 /* GDALMDArrayGetSpatialRef() */
8417 /************************************************************************/
8418
8419 /** Return the spatial reference system object associated with the array.
8420 *
8421 * This is the same as the C++ method GDALMDArray::GetSpatialRef().
8422 *
8423 * The returned object must be freed with OSRDestroySpatialReference().
8424 */
GDALMDArrayGetSpatialRef(GDALMDArrayH hArray)8425 OGRSpatialReferenceH GDALMDArrayGetSpatialRef(GDALMDArrayH hArray)
8426 {
8427 VALIDATE_POINTER1( hArray, __func__, nullptr );
8428 auto poSRS = hArray->m_poImpl->GetSpatialRef();
8429 return poSRS ? OGRSpatialReference::ToHandle(poSRS->Clone()) : nullptr;
8430 }
8431
8432 /************************************************************************/
8433 /* GDALMDArrayGetStatistics() */
8434 /************************************************************************/
8435
8436 /**
8437 * \brief Fetch statistics.
8438 *
8439 * This is the same as the C++ method GDALMDArray::GetStatistics().
8440 *
8441 * @since GDAL 3.2
8442 */
8443
GDALMDArrayGetStatistics(GDALMDArrayH hArray,GDALDatasetH hDS,int bApproxOK,int bForce,double * pdfMin,double * pdfMax,double * pdfMean,double * pdfStdDev,GUInt64 * pnValidCount,GDALProgressFunc pfnProgress,void * pProgressData)8444 CPLErr GDALMDArrayGetStatistics(
8445 GDALMDArrayH hArray,
8446 GDALDatasetH hDS, int bApproxOK, int bForce,
8447 double *pdfMin, double *pdfMax,
8448 double *pdfMean, double *pdfStdDev,
8449 GUInt64* pnValidCount,
8450 GDALProgressFunc pfnProgress, void *pProgressData )
8451 {
8452 VALIDATE_POINTER1( hArray, __func__, CE_Failure );
8453 return hArray->m_poImpl->GetStatistics(
8454 GDALDataset::FromHandle(hDS),
8455 CPL_TO_BOOL(bApproxOK),
8456 CPL_TO_BOOL(bForce),
8457 pdfMin, pdfMax, pdfMean, pdfStdDev, pnValidCount,
8458 pfnProgress, pProgressData);
8459 }
8460
8461 /************************************************************************/
8462 /* GDALMDArrayComputeStatistics() */
8463 /************************************************************************/
8464
8465 /**
8466 * \brief Compute statistics.
8467 *
8468 * This is the same as the C++ method GDALMDArray::ComputeStatistics().
8469 *
8470 * @since GDAL 3.2
8471 */
8472
GDALMDArrayComputeStatistics(GDALMDArrayH hArray,GDALDatasetH hDS,int bApproxOK,double * pdfMin,double * pdfMax,double * pdfMean,double * pdfStdDev,GUInt64 * pnValidCount,GDALProgressFunc pfnProgress,void * pProgressData)8473 int GDALMDArrayComputeStatistics( GDALMDArrayH hArray,
8474 GDALDatasetH hDS,
8475 int bApproxOK,
8476 double *pdfMin, double *pdfMax,
8477 double *pdfMean, double *pdfStdDev,
8478 GUInt64* pnValidCount,
8479 GDALProgressFunc pfnProgress,
8480 void *pProgressData )
8481 {
8482 VALIDATE_POINTER1( hArray, __func__, FALSE );
8483 return hArray->m_poImpl->ComputeStatistics(
8484 GDALDataset::FromHandle(hDS),
8485 CPL_TO_BOOL(bApproxOK),
8486 pdfMin, pdfMax, pdfMean, pdfStdDev, pnValidCount,
8487 pfnProgress, pProgressData);
8488 }
8489
8490 /************************************************************************/
8491 /* GDALAttributeRelease() */
8492 /************************************************************************/
8493
8494 /** Release the GDAL in-memory object associated with a GDALAttribute.
8495 *
8496 * Note: when applied on a object coming from a driver, this does not
8497 * destroy the object in the file, database, etc...
8498 */
GDALAttributeRelease(GDALAttributeH hAttr)8499 void GDALAttributeRelease(GDALAttributeH hAttr)
8500 {
8501 delete hAttr;
8502 }
8503
8504 /************************************************************************/
8505 /* GDALAttributeGetName() */
8506 /************************************************************************/
8507
8508 /** Return the name of the attribute.
8509 *
8510 * The returned pointer is valid until hAttr is released.
8511 *
8512 * This is the same as the C++ method GDALAttribute::GetName().
8513 */
GDALAttributeGetName(GDALAttributeH hAttr)8514 const char* GDALAttributeGetName(GDALAttributeH hAttr)
8515 {
8516 VALIDATE_POINTER1( hAttr, __func__, nullptr );
8517 return hAttr->m_poImpl->GetName().c_str();
8518 }
8519
8520 /************************************************************************/
8521 /* GDALAttributeGetFullName() */
8522 /************************************************************************/
8523
8524 /** Return the full name of the attribute.
8525 *
8526 * The returned pointer is valid until hAttr is released.
8527 *
8528 * This is the same as the C++ method GDALAttribute::GetFullName().
8529 */
GDALAttributeGetFullName(GDALAttributeH hAttr)8530 const char* GDALAttributeGetFullName(GDALAttributeH hAttr)
8531 {
8532 VALIDATE_POINTER1( hAttr, __func__, nullptr );
8533 return hAttr->m_poImpl->GetFullName().c_str();
8534 }
8535
8536 /************************************************************************/
8537 /* GDALAttributeGetTotalElementsCount() */
8538 /************************************************************************/
8539
8540 /** Return the total number of values in the attribute.
8541 *
8542 * This is the same as the C++ method GDALAbstractMDArray::GetTotalElementsCount()
8543 */
GDALAttributeGetTotalElementsCount(GDALAttributeH hAttr)8544 GUInt64 GDALAttributeGetTotalElementsCount(GDALAttributeH hAttr)
8545 {
8546 VALIDATE_POINTER1( hAttr, __func__, 0 );
8547 return hAttr->m_poImpl->GetTotalElementsCount();
8548 }
8549
8550 /************************************************************************/
8551 /* GDALAttributeGetDimensionCount() */
8552 /************************************************************************/
8553
8554 /** Return the number of dimensions.
8555 *
8556 * This is the same as the C++ method GDALAbstractMDArray::GetDimensionCount()
8557 */
GDALAttributeGetDimensionCount(GDALAttributeH hAttr)8558 size_t GDALAttributeGetDimensionCount(GDALAttributeH hAttr)
8559 {
8560 VALIDATE_POINTER1( hAttr, __func__, 0 );
8561 return hAttr->m_poImpl->GetDimensionCount();
8562 }
8563
8564 /************************************************************************/
8565 /* GDALAttributeGetDimensionsSize() */
8566 /************************************************************************/
8567
8568 /** Return the dimension sizes of the attribute.
8569 *
8570 * The returned array must be freed with CPLFree()
8571 *
8572 * @param hAttr Attribute.
8573 * @param pnCount Pointer to the number of values returned. Must NOT be NULL.
8574 *
8575 * @return an array of *pnCount values.
8576 */
GDALAttributeGetDimensionsSize(GDALAttributeH hAttr,size_t * pnCount)8577 GUInt64* GDALAttributeGetDimensionsSize(GDALAttributeH hAttr, size_t *pnCount)
8578 {
8579 VALIDATE_POINTER1( hAttr, __func__, nullptr );
8580 VALIDATE_POINTER1( pnCount, __func__, nullptr );
8581 const auto& dims = hAttr->m_poImpl->GetDimensions();
8582 auto ret = static_cast<GUInt64*>(
8583 CPLMalloc(sizeof(GUInt64) * dims.size()));
8584 for( size_t i = 0; i < dims.size(); i++ )
8585 {
8586 ret[i] = dims[i]->GetSize();
8587 }
8588 *pnCount = dims.size();
8589 return ret;
8590 }
8591
8592 /************************************************************************/
8593 /* GDALAttributeGetDataType() */
8594 /************************************************************************/
8595
8596 /** Return the data type
8597 *
8598 * The return must be freed with GDALExtendedDataTypeRelease().
8599 */
GDALAttributeGetDataType(GDALAttributeH hAttr)8600 GDALExtendedDataTypeH GDALAttributeGetDataType(GDALAttributeH hAttr)
8601 {
8602 VALIDATE_POINTER1( hAttr, __func__, nullptr );
8603 return new GDALExtendedDataTypeHS(
8604 new GDALExtendedDataType(hAttr->m_poImpl->GetDataType()));
8605 }
8606
8607 /************************************************************************/
8608 /* GDALAttributeReadAsRaw() */
8609 /************************************************************************/
8610
8611 /** Return the raw value of an attribute.
8612 *
8613 * This is the same as the C++ method GDALAttribute::ReadAsRaw().
8614 *
8615 * The returned buffer must be freed with GDALAttributeFreeRawResult()
8616 *
8617 * @param hAttr Attribute.
8618 * @param pnSize Pointer to the number of bytes returned. Must NOT be NULL.
8619 *
8620 * @return a buffer of *pnSize bytes.
8621 */
GDALAttributeReadAsRaw(GDALAttributeH hAttr,size_t * pnSize)8622 GByte *GDALAttributeReadAsRaw(GDALAttributeH hAttr, size_t *pnSize)
8623 {
8624 VALIDATE_POINTER1( hAttr, __func__, nullptr );
8625 VALIDATE_POINTER1( pnSize, __func__, nullptr );
8626 auto res(hAttr->m_poImpl->ReadAsRaw());
8627 *pnSize = res.size();
8628 auto ret = res.StealData();
8629 if( !ret )
8630 {
8631 *pnSize = 0;
8632 return nullptr;
8633 }
8634 return ret;
8635 }
8636
8637 /************************************************************************/
8638 /* GDALAttributeFreeRawResult() */
8639 /************************************************************************/
8640
8641 /** Free the return of GDALAttributeAsRaw()
8642 */
GDALAttributeFreeRawResult(GDALAttributeH hAttr,GByte * raw,CPL_UNUSED size_t nSize)8643 void GDALAttributeFreeRawResult(GDALAttributeH hAttr, GByte* raw,
8644 CPL_UNUSED size_t nSize)
8645 {
8646 VALIDATE_POINTER0( hAttr, __func__ );
8647 if( raw )
8648 {
8649 const auto dt(hAttr->m_poImpl->GetDataType());
8650 const auto nDTSize(dt.GetSize());
8651 GByte* pabyPtr = raw;
8652 const auto nEltCount(hAttr->m_poImpl->GetTotalElementsCount());
8653 CPLAssert( nSize == nDTSize * nEltCount );
8654 for( size_t i = 0; i < nEltCount; ++i )
8655 {
8656 dt.FreeDynamicMemory(pabyPtr);
8657 pabyPtr += nDTSize;
8658 }
8659 CPLFree(raw);
8660 }
8661 }
8662
8663 /************************************************************************/
8664 /* GDALAttributeReadAsString() */
8665 /************************************************************************/
8666
8667 /** Return the value of an attribute as a string.
8668 *
8669 * The returned string should not be freed, and its lifetime does not
8670 * excess a next call to ReadAsString() on the same object, or the deletion
8671 * of the object itself.
8672 *
8673 * This function will only return the first element if there are several.
8674 *
8675 * This is the same as the C++ method GDALAttribute::ReadAsString()
8676 *
8677 * @return a string, or nullptr.
8678 */
GDALAttributeReadAsString(GDALAttributeH hAttr)8679 const char* GDALAttributeReadAsString(GDALAttributeH hAttr)
8680 {
8681 VALIDATE_POINTER1( hAttr, __func__, nullptr );
8682 return hAttr->m_poImpl->ReadAsString();
8683 }
8684
8685 /************************************************************************/
8686 /* GDALAttributeReadAsInt() */
8687 /************************************************************************/
8688
8689 /** Return the value of an attribute as a integer.
8690 *
8691 * This function will only return the first element if there are several.
8692 *
8693 * It can fail if its value can be converted to integer.
8694 *
8695 * This is the same as the C++ method GDALAttribute::ReadAsInt()
8696 *
8697 * @return a integer, or INT_MIN in case of error.
8698 */
GDALAttributeReadAsInt(GDALAttributeH hAttr)8699 int GDALAttributeReadAsInt(GDALAttributeH hAttr)
8700 {
8701 VALIDATE_POINTER1( hAttr, __func__, 0 );
8702 return hAttr->m_poImpl->ReadAsInt();
8703 }
8704
8705 /************************************************************************/
8706 /* GDALAttributeReadAsDouble() */
8707 /************************************************************************/
8708
8709 /** Return the value of an attribute as a double.
8710 *
8711 * This function will only return the first element if there are several.
8712 *
8713 * It can fail if its value can be converted to double.
8714 *
8715 * This is the same as the C++ method GDALAttribute::ReadAsDoubl()
8716 *
8717 * @return a double value.
8718 */
GDALAttributeReadAsDouble(GDALAttributeH hAttr)8719 double GDALAttributeReadAsDouble(GDALAttributeH hAttr)
8720 {
8721 VALIDATE_POINTER1( hAttr, __func__, 0 );
8722 return hAttr->m_poImpl->ReadAsDouble();
8723 }
8724
8725 /************************************************************************/
8726 /* GDALAttributeReadAsStringArray() */
8727 /************************************************************************/
8728
8729 /** Return the value of an attribute as an array of strings.
8730 *
8731 * This is the same as the C++ method GDALAttribute::ReadAsStringArray()
8732 *
8733 * The return value must be freed with CSLDestroy().
8734 */
GDALAttributeReadAsStringArray(GDALAttributeH hAttr)8735 char **GDALAttributeReadAsStringArray(GDALAttributeH hAttr)
8736 {
8737 VALIDATE_POINTER1( hAttr, __func__, nullptr );
8738 return hAttr->m_poImpl->ReadAsStringArray().StealList();
8739 }
8740
8741 /************************************************************************/
8742 /* GDALAttributeReadAsIntArray() */
8743 /************************************************************************/
8744
8745 /** Return the value of an attribute as an array of integers.
8746 *
8747 * This is the same as the C++ method GDALAttribute::ReadAsIntArray()
8748 *
8749 * @param hAttr Attribute
8750 * @param pnCount Pointer to the number of values returned. Must NOT be NULL.
8751 * @return array to be freed with CPLFree(), or nullptr.
8752 */
GDALAttributeReadAsIntArray(GDALAttributeH hAttr,size_t * pnCount)8753 int *GDALAttributeReadAsIntArray(GDALAttributeH hAttr, size_t* pnCount)
8754 {
8755 VALIDATE_POINTER1( hAttr, __func__, nullptr );
8756 VALIDATE_POINTER1( pnCount, __func__, nullptr );
8757 *pnCount = 0;
8758 auto tmp(hAttr->m_poImpl->ReadAsIntArray());
8759 if( tmp.empty() )
8760 return nullptr;
8761 auto ret = static_cast<int*>(VSI_MALLOC2_VERBOSE(tmp.size(),
8762 sizeof(int)));
8763 if( !ret )
8764 return nullptr;
8765 memcpy(ret, tmp.data(), tmp.size() * sizeof(int));
8766 *pnCount = tmp.size();
8767 return ret;
8768 }
8769
8770 /************************************************************************/
8771 /* GDALAttributeReadAsDoubleArray() */
8772 /************************************************************************/
8773
8774 /** Return the value of an attribute as an array of doubles.
8775 *
8776 * This is the same as the C++ method GDALAttribute::ReadAsDoubleArray()
8777 *
8778 * @param hAttr Attribute
8779 * @param pnCount Pointer to the number of values returned. Must NOT be NULL.
8780 * @return array to be freed with CPLFree(), or nullptr.
8781 */
GDALAttributeReadAsDoubleArray(GDALAttributeH hAttr,size_t * pnCount)8782 double *GDALAttributeReadAsDoubleArray(GDALAttributeH hAttr, size_t* pnCount)
8783 {
8784 VALIDATE_POINTER1( hAttr, __func__, nullptr );
8785 VALIDATE_POINTER1( pnCount, __func__, nullptr );
8786 *pnCount = 0;
8787 auto tmp(hAttr->m_poImpl->ReadAsDoubleArray());
8788 if( tmp.empty() )
8789 return nullptr;
8790 auto ret = static_cast<double*>(VSI_MALLOC2_VERBOSE(tmp.size(),
8791 sizeof(double)));
8792 if( !ret )
8793 return nullptr;
8794 memcpy(ret, tmp.data(), tmp.size() * sizeof(double));
8795 *pnCount = tmp.size();
8796 return ret;
8797 }
8798
8799 /************************************************************************/
8800 /* GDALAttributeWriteRaw() */
8801 /************************************************************************/
8802
8803 /** Write an attribute from raw values expressed in GetDataType()
8804 *
8805 * The values should be provided in the type of GetDataType() and there should
8806 * be exactly GetTotalElementsCount() of them.
8807 * If GetDataType() is a string, each value should be a char* pointer.
8808 *
8809 * This is the same as the C++ method GDALAttribute::Write(const void*, size_t).
8810 *
8811 * @param hAttr Attribute
8812 * @param pabyValue Buffer of nLen bytes.
8813 * @param nLength Size of pabyValue in bytes. Should be equal to
8814 * GetTotalElementsCount() * GetDataType().GetSize()
8815 * @return TRUE in case of success.
8816 */
GDALAttributeWriteRaw(GDALAttributeH hAttr,const void * pabyValue,size_t nLength)8817 int GDALAttributeWriteRaw(GDALAttributeH hAttr, const void* pabyValue, size_t nLength)
8818 {
8819 VALIDATE_POINTER1( hAttr, __func__, FALSE );
8820 return hAttr->m_poImpl->Write(pabyValue, nLength);
8821 }
8822
8823 /************************************************************************/
8824 /* GDALAttributeWriteString() */
8825 /************************************************************************/
8826
8827 /** Write an attribute from a string value.
8828 *
8829 * Type conversion will be performed if needed. If the attribute contains
8830 * multiple values, only the first one will be updated.
8831 *
8832 * This is the same as the C++ method GDALAttribute::Write(const char*)
8833 *
8834 * @param hAttr Attribute
8835 * @param pszVal Pointer to a string.
8836 * @return TRUE in case of success.
8837 */
GDALAttributeWriteString(GDALAttributeH hAttr,const char * pszVal)8838 int GDALAttributeWriteString(GDALAttributeH hAttr, const char* pszVal)
8839 {
8840 VALIDATE_POINTER1( hAttr, __func__, FALSE );
8841 return hAttr->m_poImpl->Write(pszVal);
8842 }
8843
8844 /************************************************************************/
8845 /* GDALAttributeWriteInt() */
8846 /************************************************************************/
8847
8848 /** Write an attribute from a integer value.
8849 *
8850 * Type conversion will be performed if needed. If the attribute contains
8851 * multiple values, only the first one will be updated.
8852 *
8853 * This is the same as the C++ method GDALAttribute::WriteInt()
8854 *
8855 * @param hAttr Attribute
8856 * @param nVal Value.
8857 * @return TRUE in case of success.
8858 */
GDALAttributeWriteInt(GDALAttributeH hAttr,int nVal)8859 int GDALAttributeWriteInt(GDALAttributeH hAttr, int nVal)
8860 {
8861 VALIDATE_POINTER1( hAttr, __func__, FALSE );
8862 return hAttr->m_poImpl->WriteInt(nVal);
8863 }
8864
8865 /************************************************************************/
8866 /* GDALAttributeWriteDouble() */
8867 /************************************************************************/
8868
8869 /** Write an attribute from a double value.
8870 *
8871 * Type conversion will be performed if needed. If the attribute contains
8872 * multiple values, only the first one will be updated.
8873 *
8874 * This is the same as the C++ method GDALAttribute::Write(double);
8875 *
8876 * @param hAttr Attribute
8877 * @param dfVal Value.
8878 *
8879 * @return TRUE in case of success.
8880 */
GDALAttributeWriteDouble(GDALAttributeH hAttr,double dfVal)8881 int GDALAttributeWriteDouble(GDALAttributeH hAttr, double dfVal)
8882 {
8883 VALIDATE_POINTER1( hAttr, __func__, FALSE );
8884 return hAttr->m_poImpl->Write(dfVal);
8885 }
8886
8887 /************************************************************************/
8888 /* GDALAttributeWriteStringArray() */
8889 /************************************************************************/
8890
8891 /** Write an attribute from an array of strings.
8892 *
8893 * Type conversion will be performed if needed.
8894 *
8895 * Exactly GetTotalElementsCount() strings must be provided
8896 *
8897 * This is the same as the C++ method GDALAttribute::Write(CSLConstList)
8898 *
8899 * @param hAttr Attribute
8900 * @param papszValues Array of strings.
8901 * @return TRUE in case of success.
8902 */
GDALAttributeWriteStringArray(GDALAttributeH hAttr,CSLConstList papszValues)8903 int GDALAttributeWriteStringArray(GDALAttributeH hAttr, CSLConstList papszValues)
8904 {
8905 VALIDATE_POINTER1( hAttr, __func__, FALSE );
8906 return hAttr->m_poImpl->Write(papszValues);
8907 }
8908
8909
8910 /************************************************************************/
8911 /* GDALAttributeWriteDoubleArray() */
8912 /************************************************************************/
8913
8914 /** Write an attribute from an array of double.
8915 *
8916 * Type conversion will be performed if needed.
8917 *
8918 * Exactly GetTotalElementsCount() strings must be provided
8919 *
8920 * This is the same as the C++ method GDALAttribute::Write(const double *, size_t)
8921 *
8922 * @param hAttr Attribute
8923 * @param padfValues Array of double.
8924 * @param nCount Should be equal to GetTotalElementsCount().
8925 * @return TRUE in case of success.
8926 */
GDALAttributeWriteDoubleArray(GDALAttributeH hAttr,const double * padfValues,size_t nCount)8927 int GDALAttributeWriteDoubleArray(GDALAttributeH hAttr,
8928 const double* padfValues, size_t nCount)
8929 {
8930 VALIDATE_POINTER1( hAttr, __func__, FALSE );
8931 return hAttr->m_poImpl->Write(padfValues, nCount);
8932 }
8933
8934 /************************************************************************/
8935 /* GDALDimensionRelease() */
8936 /************************************************************************/
8937
8938 /** Release the GDAL in-memory object associated with a GDALDimension.
8939 *
8940 * Note: when applied on a object coming from a driver, this does not
8941 * destroy the object in the file, database, etc...
8942 */
GDALDimensionRelease(GDALDimensionH hDim)8943 void GDALDimensionRelease(GDALDimensionH hDim)
8944 {
8945 delete hDim;
8946 }
8947
8948 /************************************************************************/
8949 /* GDALDimensionGetName() */
8950 /************************************************************************/
8951
8952 /** Return dimension name.
8953 *
8954 * This is the same as the C++ method GDALDimension::GetName()
8955 */
GDALDimensionGetName(GDALDimensionH hDim)8956 const char *GDALDimensionGetName(GDALDimensionH hDim)
8957 {
8958 VALIDATE_POINTER1( hDim, __func__, nullptr );
8959 return hDim->m_poImpl->GetName().c_str();
8960 }
8961
8962 /************************************************************************/
8963 /* GDALDimensionGetFullName() */
8964 /************************************************************************/
8965
8966 /** Return dimension full name.
8967 *
8968 * This is the same as the C++ method GDALDimension::GetFullName()
8969 */
GDALDimensionGetFullName(GDALDimensionH hDim)8970 const char *GDALDimensionGetFullName(GDALDimensionH hDim)
8971 {
8972 VALIDATE_POINTER1( hDim, __func__, nullptr );
8973 return hDim->m_poImpl->GetFullName().c_str();
8974 }
8975
8976 /************************************************************************/
8977 /* GDALDimensionGetType() */
8978 /************************************************************************/
8979
8980 /** Return dimension type.
8981 *
8982 * This is the same as the C++ method GDALDimension::GetType()
8983 */
GDALDimensionGetType(GDALDimensionH hDim)8984 const char *GDALDimensionGetType(GDALDimensionH hDim)
8985 {
8986 VALIDATE_POINTER1( hDim, __func__, nullptr );
8987 return hDim->m_poImpl->GetType().c_str();
8988 }
8989
8990 /************************************************************************/
8991 /* GDALDimensionGetDirection() */
8992 /************************************************************************/
8993
8994 /** Return dimension direction.
8995 *
8996 * This is the same as the C++ method GDALDimension::GetDirection()
8997 */
GDALDimensionGetDirection(GDALDimensionH hDim)8998 const char *GDALDimensionGetDirection(GDALDimensionH hDim)
8999 {
9000 VALIDATE_POINTER1( hDim, __func__, nullptr );
9001 return hDim->m_poImpl->GetDirection().c_str();
9002 }
9003
9004 /************************************************************************/
9005 /* GDALDimensionGetSize() */
9006 /************************************************************************/
9007
9008 /** Return the size, that is the number of values along the dimension.
9009 *
9010 * This is the same as the C++ method GDALDimension::GetSize()
9011 */
GDALDimensionGetSize(GDALDimensionH hDim)9012 GUInt64 GDALDimensionGetSize(GDALDimensionH hDim)
9013 {
9014 VALIDATE_POINTER1( hDim, __func__, 0 );
9015 return hDim->m_poImpl->GetSize();
9016 }
9017
9018 /************************************************************************/
9019 /* GDALDimensionGetIndexingVariable() */
9020 /************************************************************************/
9021
9022 /** Return the variable that is used to index the dimension (if there is one).
9023 *
9024 * This is the array, typically one-dimensional, describing the values taken
9025 * by the dimension.
9026 *
9027 * The returned value should be freed with GDALMDArrayRelease().
9028 *
9029 * This is the same as the C++ method GDALDimension::GetIndexingVariable()
9030 */
GDALDimensionGetIndexingVariable(GDALDimensionH hDim)9031 GDALMDArrayH GDALDimensionGetIndexingVariable(GDALDimensionH hDim)
9032 {
9033 VALIDATE_POINTER1( hDim, __func__, nullptr );
9034 auto var(hDim->m_poImpl->GetIndexingVariable());
9035 if( !var )
9036 return nullptr;
9037 return new GDALMDArrayHS(var);
9038 }
9039
9040 /************************************************************************/
9041 /* GDALDimensionSetIndexingVariable() */
9042 /************************************************************************/
9043
9044 /** Set the variable that is used to index the dimension.
9045 *
9046 * This is the array, typically one-dimensional, describing the values taken
9047 * by the dimension.
9048 *
9049 * This is the same as the C++ method GDALDimension::SetIndexingVariable()
9050 *
9051 * @return TRUE in case of success.
9052 */
GDALDimensionSetIndexingVariable(GDALDimensionH hDim,GDALMDArrayH hArray)9053 int GDALDimensionSetIndexingVariable(GDALDimensionH hDim, GDALMDArrayH hArray)
9054 {
9055 VALIDATE_POINTER1( hDim, __func__, FALSE );
9056 return hDim->m_poImpl->SetIndexingVariable(hArray ? hArray->m_poImpl : nullptr);
9057 }
9058
9059 /************************************************************************/
9060 /* GDALDatasetGetRootGroup() */
9061 /************************************************************************/
9062
9063 /** Return the root GDALGroup of this dataset.
9064 *
9065 * Only valid for multidimensional datasets.
9066 *
9067 * The returned value must be freed with GDALGroupRelease().
9068 *
9069 * This is the same as the C++ method GDALDataset::GetRootGroup().
9070 *
9071 * @since GDAL 3.1
9072 */
GDALDatasetGetRootGroup(GDALDatasetH hDS)9073 GDALGroupH GDALDatasetGetRootGroup(GDALDatasetH hDS)
9074 {
9075 VALIDATE_POINTER1( hDS, __func__, nullptr );
9076 auto poGroup(GDALDataset::FromHandle(hDS)->GetRootGroup());
9077 return poGroup ? new GDALGroupHS(poGroup) : nullptr;
9078 }
9079
9080
9081 /************************************************************************/
9082 /* GDALRasterBandAsMDArray() */
9083 /************************************************************************/
9084
9085 /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
9086 *
9087 * The band must be linked to a GDALDataset. If this dataset is not already
9088 * marked as shared, it will be, so that the returned array holds a reference
9089 * to it.
9090 *
9091 * If the dataset has a geotransform attached, the X and Y dimensions of the
9092 * returned array will have an associated indexing variable.
9093 *
9094 * The returned pointer must be released with GDALMDArrayRelease().
9095 *
9096 * This is the same as the C++ method GDALRasterBand::AsMDArray().
9097 *
9098 * @return a new array, or NULL.
9099 *
9100 * @since GDAL 3.1
9101 */
GDALRasterBandAsMDArray(GDALRasterBandH hBand)9102 GDALMDArrayH GDALRasterBandAsMDArray(GDALRasterBandH hBand)
9103 {
9104 VALIDATE_POINTER1( hBand, __func__, nullptr );
9105 auto poArray(GDALRasterBand::FromHandle(hBand)->AsMDArray());
9106 if( !poArray )
9107 return nullptr;
9108 return new GDALMDArrayHS(poArray);
9109 }
9110
9111
9112 /************************************************************************/
9113 /* GDALMDArrayAsClassicDataset() */
9114 /************************************************************************/
9115
9116 /** Return a view of this array as a "classic" GDALDataset (ie 2D)
9117 *
9118 * Only 2D or more arrays are supported.
9119 *
9120 * In the case of > 2D arrays, additional dimensions will be represented as
9121 * raster bands.
9122 *
9123 * The "reverse" method is GDALRasterBand::AsMDArray().
9124 *
9125 * This is the same as the C++ method GDALMDArray::AsClassicDataset().
9126 *
9127 * @param hArray Array.
9128 * @param iXDim Index of the dimension that will be used as the X/width axis.
9129 * @param iYDim Index of the dimension that will be used as the Y/height axis.
9130 * @return a new GDALDataset that must be freed with GDALClose(), or nullptr
9131 */
GDALMDArrayAsClassicDataset(GDALMDArrayH hArray,size_t iXDim,size_t iYDim)9132 GDALDatasetH GDALMDArrayAsClassicDataset(GDALMDArrayH hArray,
9133 size_t iXDim, size_t iYDim)
9134 {
9135 VALIDATE_POINTER1( hArray, __func__, nullptr );
9136 return GDALDataset::ToHandle(
9137 hArray->m_poImpl->AsClassicDataset(iXDim, iYDim));
9138 }
9139
9140
9141 //! @cond Doxygen_Suppress
9142
GDALAttributeString(const std::string & osParentName,const std::string & osName,const std::string & osValue)9143 GDALAttributeString::GDALAttributeString(const std::string& osParentName,
9144 const std::string& osName,
9145 const std::string& osValue):
9146 GDALAbstractMDArray(osParentName, osName),
9147 GDALAttribute(osParentName, osName),
9148 m_osValue(osValue)
9149 {}
9150
GetDimensions() const9151 const std::vector<std::shared_ptr<GDALDimension>>& GDALAttributeString::GetDimensions() const
9152 {
9153 return m_dims;
9154 }
9155
GetDataType() const9156 const GDALExtendedDataType &GDALAttributeString::GetDataType() const
9157 {
9158 return m_dt;
9159 }
9160
IRead(const GUInt64 *,const size_t *,const GInt64 *,const GPtrDiff_t *,const GDALExtendedDataType & bufferDataType,void * pDstBuffer) const9161 bool GDALAttributeString::IRead(const GUInt64* ,
9162 const size_t* ,
9163 const GInt64* ,
9164 const GPtrDiff_t* ,
9165 const GDALExtendedDataType& bufferDataType,
9166 void* pDstBuffer) const
9167 {
9168 if( bufferDataType.GetClass() != GEDTC_STRING )
9169 return false;
9170 char* pszStr = static_cast<char*>(VSIMalloc(m_osValue.size() + 1));
9171 if( !pszStr )
9172 return false;
9173 memcpy(pszStr, m_osValue.c_str(), m_osValue.size() + 1);
9174 *static_cast<char**>(pDstBuffer) = pszStr;
9175 return true;
9176 }
9177
GDALAttributeNumeric(const std::string & osParentName,const std::string & osName,double dfValue)9178 GDALAttributeNumeric::GDALAttributeNumeric(const std::string& osParentName,
9179 const std::string& osName,
9180 double dfValue):
9181 GDALAbstractMDArray(osParentName, osName),
9182 GDALAttribute(osParentName, osName),
9183 m_dt(GDALExtendedDataType::Create(GDT_Float64)),
9184 m_dfValue(dfValue)
9185 {}
9186
GDALAttributeNumeric(const std::string & osParentName,const std::string & osName,int nValue)9187 GDALAttributeNumeric::GDALAttributeNumeric(const std::string& osParentName,
9188 const std::string& osName,
9189 int nValue):
9190 GDALAbstractMDArray(osParentName, osName),
9191 GDALAttribute(osParentName, osName),
9192 m_dt(GDALExtendedDataType::Create(GDT_Int32)),
9193 m_nValue(nValue)
9194 {}
9195
GDALAttributeNumeric(const std::string & osParentName,const std::string & osName,const std::vector<GUInt32> & anValues)9196 GDALAttributeNumeric::GDALAttributeNumeric(const std::string& osParentName,
9197 const std::string& osName,
9198 const std::vector<GUInt32>& anValues):
9199 GDALAbstractMDArray(osParentName, osName),
9200 GDALAttribute(osParentName, osName),
9201 m_dt(GDALExtendedDataType::Create(GDT_UInt32)),
9202 m_anValuesUInt32(anValues)
9203 {
9204 m_dims.push_back(std::make_shared<GDALDimension>(
9205 std::string(), "dim0", std::string(), std::string(), m_anValuesUInt32.size()));
9206 }
9207
GetDimensions() const9208 const std::vector<std::shared_ptr<GDALDimension>>& GDALAttributeNumeric::GetDimensions() const
9209 {
9210 return m_dims;
9211 }
9212
GetDataType() const9213 const GDALExtendedDataType &GDALAttributeNumeric::GetDataType() const
9214 {
9215 return m_dt;
9216 }
9217
IRead(const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride,const GDALExtendedDataType & bufferDataType,void * pDstBuffer) const9218 bool GDALAttributeNumeric::IRead(const GUInt64* arrayStartIdx,
9219 const size_t* count,
9220 const GInt64* arrayStep,
9221 const GPtrDiff_t* bufferStride,
9222 const GDALExtendedDataType& bufferDataType,
9223 void* pDstBuffer) const
9224 {
9225 if( m_dims.empty() )
9226 {
9227 if( m_dt.GetNumericDataType() == GDT_Float64 )
9228 GDALExtendedDataType::CopyValue(&m_dfValue, m_dt, pDstBuffer, bufferDataType);
9229 else
9230 {
9231 CPLAssert( m_dt.GetNumericDataType() == GDT_Int32 );
9232 GDALExtendedDataType::CopyValue(&m_nValue, m_dt, pDstBuffer, bufferDataType);
9233 }
9234 }
9235 else
9236 {
9237 CPLAssert( m_dt.GetNumericDataType() == GDT_UInt32 );
9238 GByte* pabyDstBuffer = static_cast<GByte*>(pDstBuffer);
9239 for(size_t i = 0; i < count[0]; ++i )
9240 {
9241 GDALExtendedDataType::CopyValue(
9242 &m_anValuesUInt32[static_cast<size_t>(arrayStartIdx[0] + i * arrayStep[0])],
9243 m_dt,
9244 pabyDstBuffer,
9245 bufferDataType);
9246 pabyDstBuffer += bufferDataType.GetSize() * bufferStride[0];
9247 }
9248 }
9249 return true;
9250 }
9251
GDALMDArrayRegularlySpaced(const std::string & osParentName,const std::string & osName,const std::shared_ptr<GDALDimension> & poDim,double dfStart,double dfIncrement,double dfOffsetInIncrement)9252 GDALMDArrayRegularlySpaced::GDALMDArrayRegularlySpaced(
9253 const std::string& osParentName,
9254 const std::string& osName,
9255 const std::shared_ptr<GDALDimension>& poDim,
9256 double dfStart, double dfIncrement,
9257 double dfOffsetInIncrement):
9258 GDALAbstractMDArray(osParentName, osName),
9259 GDALMDArray(osParentName, osName),
9260 m_dfStart(dfStart),
9261 m_dfIncrement(dfIncrement),
9262 m_dfOffsetInIncrement(dfOffsetInIncrement),
9263 m_dims{poDim}
9264 {}
9265
GetDimensions() const9266 const std::vector<std::shared_ptr<GDALDimension>>& GDALMDArrayRegularlySpaced::GetDimensions() const
9267 {
9268 return m_dims;
9269 }
9270
GetDataType() const9271 const GDALExtendedDataType &GDALMDArrayRegularlySpaced::GetDataType() const
9272 {
9273 return m_dt;
9274 }
9275
GetAttributes(CSLConstList) const9276 std::vector<std::shared_ptr<GDALAttribute>> GDALMDArrayRegularlySpaced::GetAttributes(CSLConstList) const
9277 {
9278 return m_attributes;
9279 }
9280
AddAttribute(const std::shared_ptr<GDALAttribute> & poAttr)9281 void GDALMDArrayRegularlySpaced::AddAttribute(const std::shared_ptr<GDALAttribute>& poAttr)
9282 {
9283 m_attributes.emplace_back(poAttr);
9284 }
9285
IRead(const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride,const GDALExtendedDataType & bufferDataType,void * pDstBuffer) const9286 bool GDALMDArrayRegularlySpaced::IRead(const GUInt64* arrayStartIdx,
9287 const size_t* count,
9288 const GInt64* arrayStep,
9289 const GPtrDiff_t* bufferStride,
9290 const GDALExtendedDataType& bufferDataType,
9291 void* pDstBuffer) const
9292 {
9293 GByte* pabyDstBuffer = static_cast<GByte*>(pDstBuffer);
9294 for( size_t i = 0; i < count[0]; i++ )
9295 {
9296 const double dfVal = m_dfStart +
9297 (arrayStartIdx[0] + i * arrayStep[0] + m_dfOffsetInIncrement) * m_dfIncrement;
9298 GDALExtendedDataType::CopyValue(&dfVal, m_dt,
9299 pabyDstBuffer, bufferDataType);
9300 pabyDstBuffer += bufferStride[0] * bufferDataType.GetSize();
9301 }
9302 return true;
9303 }
9304
GDALDimensionWeakIndexingVar(const std::string & osParentName,const std::string & osName,const std::string & osType,const std::string & osDirection,GUInt64 nSize)9305 GDALDimensionWeakIndexingVar::GDALDimensionWeakIndexingVar(const std::string& osParentName,
9306 const std::string& osName,
9307 const std::string& osType,
9308 const std::string& osDirection,
9309 GUInt64 nSize) :
9310 GDALDimension(osParentName, osName, osType, osDirection, nSize)
9311 {}
9312
GetIndexingVariable() const9313 std::shared_ptr<GDALMDArray> GDALDimensionWeakIndexingVar::GetIndexingVariable() const
9314 {
9315 return m_poIndexingVariable.lock();
9316 }
9317
9318 // cppcheck-suppress passedByValue
SetIndexingVariable(std::shared_ptr<GDALMDArray> poIndexingVariable)9319 bool GDALDimensionWeakIndexingVar::SetIndexingVariable(std::shared_ptr<GDALMDArray> poIndexingVariable)
9320 {
9321 m_poIndexingVariable = poIndexingVariable;
9322 return true;
9323 }
9324
9325 //! @endcond
9326