LCOV - code coverage report
Current view: top level - frmts/zarr - zarr.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 234 234 100.0 %
Date: 2026-02-11 08:43:47 Functions: 79 80 98.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Zarr driver
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2021, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #ifndef ZARR_H
      14             : #define ZARR_H
      15             : 
      16             : #include "cpl_compressor.h"
      17             : #include "cpl_json.h"
      18             : #include "gdal_priv.h"
      19             : #include "gdal_pam_multidim.h"
      20             : #include "memmultidim.h"
      21             : 
      22             : #include <array>
      23             : #include <iterator>
      24             : #include <map>
      25             : #include <memory>
      26             : #include <mutex>
      27             : #include <numeric>
      28             : #include <set>
      29             : 
      30             : #define ZARR_DEBUG_KEY "ZARR"
      31             : 
      32             : #define CRS_ATTRIBUTE_NAME "_CRS"
      33             : 
      34             : const CPLCompressor *ZarrGetShuffleCompressor();
      35             : const CPLCompressor *ZarrGetShuffleDecompressor();
      36             : const CPLCompressor *ZarrGetQuantizeDecompressor();
      37             : const CPLCompressor *ZarrGetTIFFDecompressor();
      38             : const CPLCompressor *ZarrGetFixedScaleOffsetDecompressor();
      39             : 
      40             : /************************************************************************/
      41             : /*                          MultiplyElements()                          */
      42             : /************************************************************************/
      43             : 
      44             : /** Return the product of elements in the vector
      45             :  */
      46       59698 : template <class T> inline T MultiplyElements(const std::vector<T> &vector)
      47             : {
      48       59698 :     return std::reduce(vector.begin(), vector.end(), T{1},
      49       59698 :                        std::multiplies<T>{});
      50             : }
      51             : 
      52             : /************************************************************************/
      53             : /*                             ZarrDataset                              */
      54             : /************************************************************************/
      55             : 
      56             : class ZarrGroupBase;
      57             : 
      58             : class ZarrDataset final : public GDALDataset
      59             : {
      60             :     friend class ZarrRasterBand;
      61             : 
      62             :     std::shared_ptr<ZarrGroupBase> m_poRootGroup{};
      63             :     CPLStringList m_aosSubdatasets{};
      64             :     GDALGeoTransform m_gt{};
      65             :     bool m_bHasGT = false;
      66             :     bool m_bSpatialProjConvention = false;
      67             :     std::shared_ptr<GDALDimension> m_poDimX{};
      68             :     std::shared_ptr<GDALDimension> m_poDimY{};
      69             :     std::shared_ptr<GDALMDArray> m_poSingleArray{};
      70             : 
      71             :     static GDALDataset *OpenMultidim(const char *pszFilename, bool bUpdateMode,
      72             :                                      CSLConstList papszOpenOptions);
      73             : 
      74             :   public:
      75             :     explicit ZarrDataset(const std::shared_ptr<ZarrGroupBase> &poRootGroup);
      76             :     ~ZarrDataset() override;
      77             : 
      78             :     CPLErr FlushCache(bool bAtClosing = false) override;
      79             : 
      80             :     static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
      81             :     static GDALDataset *
      82             :     CreateMultiDimensional(const char *pszFilename,
      83             :                            CSLConstList /*papszRootGroupOptions*/,
      84             :                            CSLConstList /*papszOptions*/);
      85             : 
      86             :     static GDALDataset *Create(const char *pszName, int nXSize, int nYSize,
      87             :                                int nBands, GDALDataType eType,
      88             :                                CSLConstList papszOptions);
      89             : 
      90             :     static GDALDataset *CreateCopy(const char *, GDALDataset *, int,
      91             :                                    CSLConstList papszOptions,
      92             :                                    GDALProgressFunc pfnProgress,
      93             :                                    void *pProgressData);
      94             : 
      95             :     const char *GetMetadataItem(const char *pszName,
      96             :                                 const char *pszDomain) override;
      97             :     CSLConstList GetMetadata(const char *pszDomain) override;
      98             : 
      99             :     CPLErr SetMetadata(CSLConstList papszMetadata,
     100             :                        const char *pszDomain) override;
     101             : 
     102             :     const OGRSpatialReference *GetSpatialRef() const override;
     103             :     CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
     104             : 
     105             :     CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
     106             :     CPLErr SetGeoTransform(const GDALGeoTransform &gt) override;
     107             : 
     108             :     std::shared_ptr<GDALGroup> GetRootGroup() const override;
     109             : };
     110             : 
     111             : /************************************************************************/
     112             : /*                            ZarrRasterBand                            */
     113             : /************************************************************************/
     114             : 
     115             : class ZarrRasterBand final : public GDALRasterBand
     116             : {
     117             :     friend class ZarrDataset;
     118             : 
     119             :     std::shared_ptr<GDALMDArray> m_poArray;
     120             :     GDALColorInterp m_eColorInterp = GCI_Undefined;
     121             : 
     122             :   protected:
     123             :     CPLErr IReadBlock(int nBlockXOff, int nBlockYOff, void *pData) override;
     124             :     CPLErr IWriteBlock(int nBlockXOff, int nBlockYOff, void *pData) override;
     125             :     CPLErr IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
     126             :                      int nYSize, void *pData, int nBufXSize, int nBufYSize,
     127             :                      GDALDataType eBufType, GSpacing nPixelSpaceBuf,
     128             :                      GSpacing nLineSpaceBuf,
     129             :                      GDALRasterIOExtraArg *psExtraArg) override;
     130             : 
     131             :   public:
     132             :     explicit ZarrRasterBand(const std::shared_ptr<GDALMDArray> &poArray);
     133             : 
     134             :     double GetNoDataValue(int *pbHasNoData) override;
     135             :     int64_t GetNoDataValueAsInt64(int *pbHasNoData) override;
     136             :     uint64_t GetNoDataValueAsUInt64(int *pbHasNoData) override;
     137             :     CPLErr SetNoDataValue(double dfNoData) override;
     138             :     CPLErr SetNoDataValueAsInt64(int64_t nNoData) override;
     139             :     CPLErr SetNoDataValueAsUInt64(uint64_t nNoData) override;
     140             :     double GetOffset(int *pbSuccess = nullptr) override;
     141             :     CPLErr SetOffset(double dfNewOffset) override;
     142             :     double GetScale(int *pbSuccess = nullptr) override;
     143             :     CPLErr SetScale(double dfNewScale) override;
     144             :     const char *GetUnitType() override;
     145             :     CPLErr SetUnitType(const char *pszNewValue) override;
     146             :     GDALColorInterp GetColorInterpretation() override;
     147             :     CPLErr SetColorInterpretation(GDALColorInterp eColorInterp) override;
     148             : };
     149             : 
     150             : /************************************************************************/
     151             : /*                         ZarrAttributeGroup()                         */
     152             : /************************************************************************/
     153             : 
     154             : class ZarrAttributeGroup
     155             : {
     156             :     // Use a MEMGroup as a convenient container for attributes.
     157             :     const bool m_bContainerIsGroup;
     158             :     std::shared_ptr<MEMGroup> m_poGroup;
     159             :     bool m_bModified = false;
     160             : 
     161             :   public:
     162             :     explicit ZarrAttributeGroup(const std::string &osParentName,
     163             :                                 bool bContainerIsGroup);
     164             : 
     165             :     bool Close();
     166             : 
     167             :     void Init(const CPLJSONObject &obj, bool bUpdatable);
     168             : 
     169        8288 :     std::shared_ptr<GDALAttribute> GetAttribute(const std::string &osName) const
     170             :     {
     171        8288 :         return m_poGroup->GetAttribute(osName);
     172             :     }
     173             : 
     174             :     std::vector<std::shared_ptr<GDALAttribute>>
     175         220 :     GetAttributes(CSLConstList papszOptions = nullptr) const
     176             :     {
     177         220 :         return m_poGroup->GetAttributes(papszOptions);
     178             :     }
     179             : 
     180             :     std::shared_ptr<GDALAttribute>
     181         201 :     CreateAttribute(const std::string &osName,
     182             :                     const std::vector<GUInt64> &anDimensions,
     183             :                     const GDALExtendedDataType &oDataType,
     184             :                     CSLConstList /* papszOptions */ = nullptr)
     185             :     {
     186         201 :         auto poAttr = m_poGroup->CreateAttribute(osName, anDimensions,
     187         201 :                                                  oDataType, nullptr);
     188         201 :         if (poAttr)
     189             :         {
     190         201 :             m_bModified = true;
     191             :         }
     192         201 :         return poAttr;
     193             :     }
     194             : 
     195          24 :     bool DeleteAttribute(const std::string &osName)
     196             :     {
     197          24 :         const bool bOK = m_poGroup->DeleteAttribute(osName, nullptr);
     198          24 :         if (bOK)
     199             :         {
     200          12 :             m_bModified = true;
     201             :         }
     202          24 :         return bOK;
     203             :     }
     204             : 
     205        3742 :     void SetUpdatable(bool bUpdatable)
     206             :     {
     207        7484 :         auto attrs = m_poGroup->GetAttributes(nullptr);
     208        4648 :         for (auto &attr : attrs)
     209             :         {
     210        1812 :             auto memAttr = std::dynamic_pointer_cast<MEMAttribute>(attr);
     211         906 :             if (memAttr)
     212         906 :                 memAttr->SetWritable(bUpdatable);
     213             :         }
     214        3742 :     }
     215             : 
     216         392 :     void UnsetModified()
     217             :     {
     218         392 :         m_bModified = false;
     219         784 :         auto attrs = m_poGroup->GetAttributes(nullptr);
     220         533 :         for (auto &attr : attrs)
     221             :         {
     222         282 :             auto memAttr = std::dynamic_pointer_cast<MEMAttribute>(attr);
     223         141 :             if (memAttr)
     224         141 :                 memAttr->SetModified(false);
     225             :         }
     226         392 :     }
     227             : 
     228       14674 :     bool IsModified() const
     229             :     {
     230       14674 :         if (m_bModified)
     231         233 :             return true;
     232       28882 :         const auto attrs = m_poGroup->GetAttributes(nullptr);
     233       16619 :         for (const auto &attr : attrs)
     234             :         {
     235        2210 :             const auto memAttr = std::dynamic_pointer_cast<MEMAttribute>(attr);
     236        2210 :             if (memAttr && memAttr->IsModified())
     237          32 :                 return true;
     238             :         }
     239       14409 :         return false;
     240             :     }
     241             : 
     242             :     CPLJSONObject Serialize() const;
     243             : 
     244             :     void ParentRenamed(const std::string &osNewParentFullName);
     245             : 
     246             :     void ParentDeleted();
     247             : };
     248             : 
     249             : /************************************************************************/
     250             : /*                          ZarrSharedResource                          */
     251             : /************************************************************************/
     252             : 
     253             : class ZarrSharedResource
     254             :     : public std::enable_shared_from_this<ZarrSharedResource>
     255             : {
     256             :   public:
     257             :     enum class ConsolidatedMetadataKind
     258             :     {
     259             :         NONE,
     260             :         EXTERNAL,  // Zarr V2 .zmetadata
     261             :         INTERNAL,  // Zarr V3 consolidated_metadata
     262             :     };
     263             : 
     264             :   private:
     265             :     bool m_bUpdatable = false;
     266             :     std::string m_osRootDirectoryName{};
     267             : 
     268             :     ConsolidatedMetadataKind m_eConsolidatedMetadataKind =
     269             :         ConsolidatedMetadataKind::NONE;
     270             :     CPLJSONObject m_oObjConsolidatedMetadata{};
     271             :     CPLJSONObject m_oRootAttributes{};
     272             :     bool m_bConsolidatedMetadataModified = false;
     273             : 
     274             :     std::shared_ptr<GDALPamMultiDim> m_poPAM{};
     275             :     CPLStringList m_aosOpenOptions{};
     276             :     std::weak_ptr<ZarrGroupBase> m_poWeakRootGroup{};
     277             :     std::set<std::string> m_oSetArrayInLoading{};
     278             :     std::map<std::string, std::shared_ptr<GDALMDArray>> m_oCacheIndexingVar{};
     279             : 
     280             :     explicit ZarrSharedResource(const std::string &osRootDirectoryName,
     281             :                                 bool bUpdatable);
     282             : 
     283             :     std::shared_ptr<ZarrGroupBase> OpenRootGroup();
     284             :     void InitConsolidatedMetadataIfNeeded();
     285             : 
     286             :   public:
     287             :     static std::shared_ptr<ZarrSharedResource>
     288             :     Create(const std::string &osRootDirectoryName, bool bUpdatable);
     289             : 
     290             :     ~ZarrSharedResource();
     291             : 
     292        4486 :     bool IsUpdatable() const
     293             :     {
     294        4486 :         return m_bUpdatable;
     295             :     }
     296             : 
     297          35 :     const CPLJSONObject &GetConsolidatedMetadataObj() const
     298             :     {
     299          35 :         return m_oObjConsolidatedMetadata;
     300             :     }
     301             : 
     302         257 :     bool IsConsolidatedMetadataEnabled() const
     303             :     {
     304         257 :         return m_eConsolidatedMetadataKind != ConsolidatedMetadataKind::NONE;
     305             :     }
     306             : 
     307         294 :     void EnableConsolidatedMetadata(ConsolidatedMetadataKind kind)
     308             :     {
     309         294 :         m_eConsolidatedMetadataKind = kind;
     310         294 :     }
     311             : 
     312             :     void SetZMetadataItem(const std::string &osFilename,
     313             :                           const CPLJSONObject &obj);
     314             : 
     315             :     void DeleteZMetadataItemRecursive(const std::string &osFilename);
     316             : 
     317             :     void RenameZMetadataRecursive(const std::string &osOldFilename,
     318             :                                   const std::string &osNewFilename);
     319             : 
     320        2173 :     const std::shared_ptr<GDALPamMultiDim> &GetPAM()
     321             :     {
     322        2173 :         return m_poPAM;
     323             :     }
     324             : 
     325          13 :     const std::string &GetRootDirectoryName() const
     326             :     {
     327          13 :         return m_osRootDirectoryName;
     328             :     }
     329             : 
     330        2636 :     const CPLStringList &GetOpenOptions() const
     331             :     {
     332        2636 :         return m_aosOpenOptions;
     333             :     }
     334             : 
     335        1473 :     void SetOpenOptions(CSLConstList papszOpenOptions)
     336             :     {
     337        1473 :         m_aosOpenOptions = papszOpenOptions;
     338        1473 :     }
     339             : 
     340             :     void
     341             :     UpdateDimensionSize(const std::shared_ptr<GDALDimension> &poUpdatedDim);
     342             : 
     343             :     std::shared_ptr<ZarrGroupBase> GetRootGroup();
     344             : 
     345          85 :     void SetRootGroup(const std::shared_ptr<ZarrGroupBase> &poRootGroup)
     346             :     {
     347          85 :         m_poWeakRootGroup = poRootGroup;
     348          85 :     }
     349             : 
     350             :     bool AddArrayInLoading(const std::string &osZarrayFilename);
     351             :     void RemoveArrayInLoading(const std::string &osZarrayFilename);
     352             : 
     353             :     struct SetFilenameAdder
     354             :     {
     355             :         std::shared_ptr<ZarrSharedResource> m_poSharedResource;
     356             :         const std::string m_osFilename;
     357             :         const bool m_bOK;
     358             : 
     359        1821 :         SetFilenameAdder(
     360             :             const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     361             :             const std::string &osFilename)
     362        1821 :             : m_poSharedResource(poSharedResource), m_osFilename(osFilename),
     363        1821 :               m_bOK(m_poSharedResource->AddArrayInLoading(m_osFilename))
     364             :         {
     365        1821 :         }
     366             : 
     367        1821 :         ~SetFilenameAdder()
     368        1821 :         {
     369        1821 :             if (m_bOK)
     370        1819 :                 m_poSharedResource->RemoveArrayInLoading(m_osFilename);
     371        1821 :         }
     372             : 
     373        1821 :         bool ok() const
     374             :         {
     375        1821 :             return m_bOK;
     376             :         }
     377             :     };
     378             : 
     379           8 :     void RegisterIndexingVariable(const std::string &osDimName,
     380             :                                   const std::shared_ptr<GDALMDArray> &poVar)
     381             :     {
     382           8 :         m_oCacheIndexingVar[osDimName] = poVar;
     383           8 :     }
     384             : };
     385             : 
     386             : /************************************************************************/
     387             : /*                              ZarrGroup                               */
     388             : /************************************************************************/
     389             : 
     390             : class ZarrArray;
     391             : class ZarrDimension;
     392             : 
     393             : class ZarrGroupBase CPL_NON_FINAL : public GDALGroup
     394             : {
     395             :   protected:
     396             :     friend class ZarrV2Group;
     397             :     friend class ZarrV3Group;
     398             : 
     399             :     // For ZarrV2, this is the directory of the group
     400             :     // For ZarrV3, this is the root directory of the dataset
     401             :     std::shared_ptr<ZarrSharedResource> m_poSharedResource;
     402             :     std::string m_osDirectoryName{};
     403             :     std::weak_ptr<ZarrGroupBase>
     404             :         m_poParent{};  // weak reference to owning parent
     405             :     std::shared_ptr<ZarrGroupBase>
     406             :         m_poParentStrongRef{};  // strong reference, used only when opening from
     407             :                                 // a subgroup
     408             :     mutable std::map<CPLString, std::shared_ptr<ZarrGroupBase>> m_oMapGroups{};
     409             :     mutable std::map<CPLString, std::shared_ptr<ZarrArray>> m_oMapMDArrays{};
     410             :     mutable std::map<CPLString, std::shared_ptr<ZarrDimension>>
     411             :         m_oMapDimensions{};
     412             :     mutable bool m_bDirectoryExplored = false;
     413             :     mutable std::set<std::string> m_oSetGroupNames{};
     414             :     mutable std::vector<std::string> m_aosGroups{};
     415             :     mutable std::set<std::string> m_oSetArrayNames{};
     416             :     mutable std::vector<std::string> m_aosArrays{};
     417             :     mutable ZarrAttributeGroup m_oAttrGroup;
     418             :     mutable bool m_bAttributesLoaded = false;
     419             :     bool m_bReadFromConsolidatedMetadata = false;
     420             :     mutable bool m_bDimensionsInstantiated = false;
     421             :     bool m_bUpdatable = false;
     422             :     bool m_bDimSizeInUpdate = false;
     423             : 
     424             :     virtual void ExploreDirectory() const = 0;
     425             :     virtual void LoadAttributes() const = 0;
     426             : 
     427        2202 :     ZarrGroupBase(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     428             :                   const std::string &osParentName, const std::string &osName)
     429        2202 :         : GDALGroup(osParentName, osName), m_poSharedResource(poSharedResource),
     430        2202 :           m_oAttrGroup(m_osFullName, /*bContainerIsGroup=*/true)
     431             :     {
     432        2202 :     }
     433             : 
     434             :   protected:
     435             :     friend class ZarrDimension;
     436             :     bool RenameDimension(const std::string &osOldName,
     437             :                          const std::string &osNewName);
     438             : 
     439             :     void NotifyChildrenOfRenaming() override;
     440             : 
     441             :     void NotifyChildrenOfDeletion() override;
     442             : 
     443             :   public:
     444             :     ~ZarrGroupBase() override;
     445             : 
     446             :     virtual bool Close();
     447             : 
     448             :     std::shared_ptr<GDALAttribute>
     449         361 :     GetAttribute(const std::string &osName) const override
     450             :     {
     451         361 :         LoadAttributes();
     452         361 :         return m_oAttrGroup.GetAttribute(osName);
     453             :     }
     454             : 
     455             :     std::vector<std::shared_ptr<GDALAttribute>>
     456          47 :     GetAttributes(CSLConstList papszOptions = nullptr) const override
     457             :     {
     458          47 :         LoadAttributes();
     459          47 :         return m_oAttrGroup.GetAttributes(papszOptions);
     460             :     }
     461             : 
     462             :     std::shared_ptr<GDALAttribute>
     463             :     CreateAttribute(const std::string &osName,
     464             :                     const std::vector<GUInt64> &anDimensions,
     465             :                     const GDALExtendedDataType &oDataType,
     466             :                     CSLConstList papszOptions = nullptr) override;
     467             : 
     468             :     bool DeleteAttribute(const std::string &osName,
     469             :                          CSLConstList papszOptions = nullptr) override;
     470             : 
     471             :     std::vector<std::shared_ptr<GDALDimension>>
     472             :     GetDimensions(CSLConstList papszOptions = nullptr) const override;
     473             : 
     474             :     std::shared_ptr<GDALDimension>
     475             :     CreateDimension(const std::string &osName, const std::string &osType,
     476             :                     const std::string &osDirection, GUInt64 nSize,
     477             :                     CSLConstList papszOptions = nullptr) override;
     478             : 
     479             :     std::vector<std::string>
     480             :     GetMDArrayNames(CSLConstList papszOptions = nullptr) const override;
     481             : 
     482             :     std::vector<std::string>
     483             :     GetGroupNames(CSLConstList papszOptions = nullptr) const override;
     484             : 
     485             :     virtual std::shared_ptr<ZarrGroupBase>
     486             :     OpenZarrGroup(const std::string &osName,
     487             :                   CSLConstList papszOptions = nullptr) const = 0;
     488             : 
     489             :     std::shared_ptr<GDALGroup>
     490        1326 :     OpenGroup(const std::string &osName,
     491             :               CSLConstList papszOptions = nullptr) const override
     492             :     {
     493             :         return std::static_pointer_cast<GDALGroup>(
     494        1326 :             OpenZarrGroup(osName, papszOptions));
     495             :     }
     496             : 
     497             :     bool DeleteGroup(const std::string &osName,
     498             :                      CSLConstList papszOptions = nullptr) override;
     499             : 
     500             :     std::shared_ptr<GDALMDArray>
     501        1913 :     OpenMDArray(const std::string &osName,
     502             :                 CSLConstList papszOptions = nullptr) const override
     503             :     {
     504             :         return std::static_pointer_cast<GDALMDArray>(
     505        1913 :             OpenZarrArray(osName, papszOptions));
     506             :     }
     507             : 
     508             :     bool DeleteMDArray(const std::string &osName,
     509             :                        CSLConstList papszOptions = nullptr) override;
     510             : 
     511             :     virtual std::shared_ptr<ZarrArray>
     512             :     OpenZarrArray(const std::string &osName,
     513             :                   CSLConstList papszOptions = nullptr) const = 0;
     514             : 
     515        1042 :     void SetDirectoryName(const std::string &osDirectoryName)
     516             :     {
     517        1042 :         m_osDirectoryName = osDirectoryName;
     518        1042 :     }
     519             : 
     520           9 :     const std::string &GetDirectoryName() const
     521             :     {
     522           9 :         return m_osDirectoryName;
     523             :     }
     524             : 
     525             :     void RegisterArray(const std::shared_ptr<ZarrArray> &array) const;
     526             : 
     527        2196 :     void SetUpdatable(bool bUpdatable)
     528             :     {
     529        2196 :         m_bUpdatable = bUpdatable;
     530        2196 :     }
     531             : 
     532             :     void UpdateDimensionSize(const std::shared_ptr<GDALDimension> &poDim);
     533             : 
     534             :     static bool IsValidObjectName(const std::string &osName);
     535             : 
     536             :     bool Rename(const std::string &osNewName) override;
     537             : 
     538             :     //! Returns false in case of error
     539             :     bool
     540             :     CheckArrayOrGroupWithSameNameDoesNotExist(const std::string &osName) const;
     541             : 
     542             :     void ParentRenamed(const std::string &osNewParentFullName) override;
     543             : 
     544             :     void NotifyArrayRenamed(const std::string &osOldName,
     545             :                             const std::string &osNewName);
     546             : 
     547             :     //! Return the group owning the array. Might be nullptr
     548             :     std::shared_ptr<ZarrGroupBase> GetParentGroup() const;
     549             : 
     550        3903 :     std::shared_ptr<ZarrGroupBase> Self() const
     551             :     {
     552        3903 :         return std::dynamic_pointer_cast<ZarrGroupBase>(m_pSelf.lock());
     553             :     }
     554             : 
     555        2503 :     const ZarrAttributeGroup &GetAttributeGroup() const
     556             :     {
     557        2503 :         return m_oAttrGroup;
     558             :     }
     559             : };
     560             : 
     561             : /************************************************************************/
     562             : /*                             ZarrV2Group                              */
     563             : /************************************************************************/
     564             : 
     565             : class ZarrV2Group final : public ZarrGroupBase
     566             : {
     567             :     void ExploreDirectory() const override;
     568             :     void LoadAttributes() const override;
     569             : 
     570             :     std::shared_ptr<ZarrV2Group>
     571             :     GetOrCreateSubGroup(const std::string &osSubGroupFullname);
     572             : 
     573         916 :     ZarrV2Group(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     574             :                 const std::string &osParentName, const std::string &osName)
     575         916 :         : ZarrGroupBase(poSharedResource, osParentName, osName)
     576             :     {
     577         916 :     }
     578             : 
     579             :     bool Close() override;
     580             : 
     581             :   public:
     582             :     static std::shared_ptr<ZarrV2Group>
     583             :     Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     584             :            const std::string &osParentName, const std::string &osName);
     585             : 
     586             :     ~ZarrV2Group() override;
     587             : 
     588             :     static std::shared_ptr<ZarrV2Group>
     589             :     CreateOnDisk(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     590             :                  const std::string &osParentName, const std::string &osName,
     591             :                  const std::string &osDirectoryName);
     592             : 
     593             :     std::shared_ptr<ZarrArray>
     594             :     OpenZarrArray(const std::string &osName,
     595             :                   CSLConstList papszOptions = nullptr) const override;
     596             : 
     597             :     std::shared_ptr<ZarrGroupBase>
     598             :     OpenZarrGroup(const std::string &osName,
     599             :                   CSLConstList papszOptions = nullptr) const override;
     600             : 
     601             :     std::shared_ptr<GDALGroup>
     602             :     CreateGroup(const std::string &osName,
     603             :                 CSLConstList papszOptions = nullptr) override;
     604             : 
     605             :     std::shared_ptr<ZarrArray>
     606             :     LoadArray(const std::string &osArrayName,
     607             :               const std::string &osZarrayFilename, const CPLJSONObject &oRoot,
     608             :               bool bLoadedFromZMetadata,
     609             :               const CPLJSONObject &oAttributes) const;
     610             : 
     611             :     std::shared_ptr<GDALMDArray> CreateMDArray(
     612             :         const std::string &osName,
     613             :         const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
     614             :         const GDALExtendedDataType &oDataType,
     615             :         CSLConstList papszOptions = nullptr) override;
     616             : 
     617             :     void InitFromConsolidatedMetadata(const CPLJSONObject &oRoot);
     618             : 
     619             :     bool InitFromZGroup(const CPLJSONObject &oRoot);
     620             : };
     621             : 
     622             : /************************************************************************/
     623             : /*                             ZarrV3Group                              */
     624             : /************************************************************************/
     625             : 
     626             : class ZarrV3Group final : public ZarrGroupBase
     627             : {
     628             :     bool m_bFileHasBeenWritten = false;
     629             : 
     630             :     void ExploreDirectory() const override;
     631             :     void LoadAttributes() const override;
     632             : 
     633             :     ZarrV3Group(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     634             :                 const std::string &osParentName, const std::string &osName,
     635             :                 const std::string &osDirectoryName);
     636             : 
     637             :     std::shared_ptr<ZarrV3Group>
     638             :     GetOrCreateSubGroup(const std::string &osSubGroupFullname);
     639             : 
     640             :     bool Close() override;
     641             : 
     642             :   public:
     643             :     ~ZarrV3Group() override;
     644             : 
     645             :     static std::shared_ptr<ZarrV3Group>
     646             :     Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     647             :            const std::string &osParentName, const std::string &osName,
     648             :            const std::string &osDirectoryName);
     649             : 
     650             :     std::shared_ptr<ZarrArray>
     651             :     OpenZarrArray(const std::string &osName,
     652             :                   CSLConstList papszOptions = nullptr) const override;
     653             : 
     654             :     std::shared_ptr<ZarrGroupBase>
     655             :     OpenZarrGroup(const std::string &osName,
     656             :                   CSLConstList papszOptions = nullptr) const override;
     657             : 
     658             :     static std::shared_ptr<ZarrV3Group>
     659             :     CreateOnDisk(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     660             :                  const std::string &osParentFullName, const std::string &osName,
     661             :                  const std::string &osDirectoryName);
     662             : 
     663             :     std::shared_ptr<GDALGroup>
     664             :     CreateGroup(const std::string &osName,
     665             :                 CSLConstList papszOptions = nullptr) override;
     666             : 
     667             :     std::shared_ptr<ZarrArray> LoadArray(const std::string &osArrayName,
     668             :                                          const std::string &osZarrayFilename,
     669             :                                          const CPLJSONObject &oRoot) const;
     670             : 
     671             :     std::shared_ptr<GDALMDArray> CreateMDArray(
     672             :         const std::string &osName,
     673             :         const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
     674             :         const GDALExtendedDataType &oDataType,
     675             :         CSLConstList papszOptions = nullptr) override;
     676             : 
     677         708 :     void SetExplored()
     678             :     {
     679         708 :         m_bDirectoryExplored = true;
     680         708 :     }
     681             : 
     682             :     void
     683             :     InitFromConsolidatedMetadata(const CPLJSONObject &oConsolidatedMetadata,
     684             :                                  const CPLJSONObject &oRootAttributes);
     685             : };
     686             : 
     687             : /************************************************************************/
     688             : /*                            ZarrDimension                             */
     689             : /************************************************************************/
     690             : 
     691             : class ZarrDimension final : public GDALDimensionWeakIndexingVar
     692             : {
     693             :     const bool m_bUpdatable;
     694             :     std::weak_ptr<ZarrGroupBase> m_poParentGroup;
     695             :     bool m_bModified = false;
     696             :     bool m_bXArrayDim = false;
     697             : 
     698             :   public:
     699        4486 :     ZarrDimension(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     700             :                   const std::weak_ptr<ZarrGroupBase> &poParentGroup,
     701             :                   const std::string &osParentName, const std::string &osName,
     702             :                   const std::string &osType, const std::string &osDirection,
     703             :                   GUInt64 nSize)
     704        4486 :         : GDALDimensionWeakIndexingVar(osParentName, osName, osType,
     705             :                                        osDirection, nSize),
     706        4486 :           m_bUpdatable(poSharedResource->IsUpdatable()),
     707        8972 :           m_poParentGroup(poParentGroup)
     708             :     {
     709        4486 :     }
     710             : 
     711             :     bool Rename(const std::string &osNewName) override;
     712             : 
     713        8241 :     bool IsModified() const
     714             :     {
     715        8241 :         return m_bModified;
     716             :     }
     717             : 
     718        1381 :     void SetXArrayDimension()
     719             :     {
     720        1381 :         m_bXArrayDim = true;
     721        1381 :     }
     722             : 
     723       12435 :     bool IsXArrayDimension() const
     724             :     {
     725       12435 :         return m_bXArrayDim;
     726             :     }
     727             : };
     728             : 
     729             : /************************************************************************/
     730             : /*                              DtypeElt()                              */
     731             : /************************************************************************/
     732             : 
     733             : struct DtypeElt
     734             : {
     735             :     enum class NativeType
     736             :     {
     737             :         BOOLEAN,
     738             :         UNSIGNED_INT,
     739             :         SIGNED_INT,
     740             :         IEEEFP,
     741             :         COMPLEX_IEEEFP,
     742             :         STRING_ASCII,
     743             :         STRING_UNICODE
     744             :     };
     745             : 
     746             :     NativeType nativeType = NativeType::BOOLEAN;
     747             :     size_t nativeOffset = 0;
     748             :     size_t nativeSize = 0;
     749             :     bool needByteSwapping = false;
     750             :     bool gdalTypeIsApproxOfNative = false;
     751             :     GDALExtendedDataType gdalType = GDALExtendedDataType::Create(GDT_Unknown);
     752             :     size_t gdalOffset = 0;
     753             :     size_t gdalSize = 0;
     754             : };
     755             : 
     756             : /************************************************************************/
     757             : /*                      ZarrByteVectorQuickResize                       */
     758             : /************************************************************************/
     759             : 
     760             : /* std::vector<GByte> with quick resizing (ie that doesn't zero out when
     761             :  * growing back to a previously reached greater size).
     762             :  */
     763      151511 : class ZarrByteVectorQuickResize
     764             : {
     765             :     std::vector<GByte> m_oVec{};
     766             :     size_t m_nSize = 0;
     767             : 
     768             :   public:
     769      100209 :     ZarrByteVectorQuickResize() = default;
     770             : 
     771             :     ZarrByteVectorQuickResize(const ZarrByteVectorQuickResize &) = delete;
     772             :     ZarrByteVectorQuickResize &
     773             :     operator=(const ZarrByteVectorQuickResize &) = delete;
     774             : 
     775       54735 :     ZarrByteVectorQuickResize(ZarrByteVectorQuickResize &&) = default;
     776             :     ZarrByteVectorQuickResize &
     777             :     operator=(ZarrByteVectorQuickResize &&) = default;
     778             : 
     779      167853 :     void resize(size_t nNewSize)
     780             :     {
     781      167853 :         if (nNewSize > m_oVec.size())
     782       58047 :             m_oVec.resize(nNewSize);
     783      167853 :         m_nSize = nNewSize;
     784      167853 :     }
     785             : 
     786        1653 :     inline void clear()
     787             :     {
     788        1653 :         m_nSize = 0;
     789        1653 :     }
     790             : 
     791             :     inline std::vector<GByte>::iterator begin()
     792             :     {
     793             :         return m_oVec.begin();
     794             :     }
     795             : 
     796        1140 :     inline std::vector<GByte>::const_iterator begin() const
     797             :     {
     798        1140 :         return m_oVec.begin();
     799             :     }
     800             : 
     801         643 :     inline std::vector<GByte>::iterator end()
     802             :     {
     803         643 :         return m_oVec.begin() + m_nSize;
     804             :     }
     805             : 
     806         146 :     inline std::vector<GByte>::const_iterator end() const
     807             :     {
     808         146 :         return m_oVec.begin() + m_nSize;
     809             :     }
     810             : 
     811             :     template <class InputIt>
     812             :     inline std::vector<GByte>::iterator
     813         643 :     insert(std::vector<GByte>::const_iterator pos, InputIt first, InputIt last)
     814             :     {
     815         643 :         const size_t nCount = std::distance(first, last);
     816         643 :         const auto &oVec = m_oVec;
     817         643 :         const size_t nStart = std::distance(oVec.begin(), pos);
     818         643 :         if (nStart == m_nSize && nStart + nCount <= m_oVec.size())
     819             :         {
     820             :             // Insert at end of user-visible vector, but fully inside the
     821             :             // container vector. We can just copy
     822         371 :             std::copy(first, last, m_oVec.begin() + nStart);
     823         371 :             m_nSize += nCount;
     824         371 :             return m_oVec.begin() + nStart;
     825             :         }
     826             :         else
     827             :         {
     828             :             // Generic case
     829         272 :             auto ret = m_oVec.insert(pos, first, last);
     830         272 :             m_nSize += nCount;
     831         272 :             return ret;
     832             :         }
     833             :     }
     834             : 
     835      251334 :     inline bool empty() const
     836             :     {
     837      251334 :         return m_nSize == 0;
     838             :     }
     839             : 
     840      205584 :     inline size_t size() const
     841             :     {
     842      205584 :         return m_nSize;
     843             :     }
     844             : 
     845       33922 :     inline size_t capacity() const
     846             :     {
     847             :         // Not a typo: the capacity of this object is the size
     848             :         // of the underlying std::vector
     849       33922 :         return m_oVec.size();
     850             :     }
     851             : 
     852      120967 :     inline GByte *data()
     853             :     {
     854      120967 :         return m_oVec.data();
     855             :     }
     856             : 
     857       49236 :     inline const GByte *data() const
     858             :     {
     859       49236 :         return m_oVec.data();
     860             :     }
     861             : 
     862        1000 :     inline GByte operator[](size_t idx) const
     863             :     {
     864        1000 :         return m_oVec[idx];
     865             :     }
     866             : 
     867       54418 :     inline GByte &operator[](size_t idx)
     868             :     {
     869       54418 :         return m_oVec[idx];
     870             :     }
     871             : };
     872             : 
     873             : /************************************************************************/
     874             : /*                              ZarrArray                               */
     875             : /************************************************************************/
     876             : 
     877             : class ZarrArray CPL_NON_FINAL : public GDALPamMDArray
     878             : {
     879             :   protected:
     880             :     std::shared_ptr<ZarrSharedResource> m_poSharedResource;
     881             : 
     882             :     //! weak reference to owning parent
     883             :     std::weak_ptr<ZarrGroupBase> m_poParent{};
     884             : 
     885             :     const std::vector<std::shared_ptr<GDALDimension>> m_aoDims;
     886             :     const GDALExtendedDataType m_oType;
     887             : 
     888             :     //! Array (several in case of compound data type) of native Zarr data types
     889             :     const std::vector<DtypeElt> m_aoDtypeElts;
     890             : 
     891             :     /** m_anOuterBlockSize is the chunk_size at the Zarr array level, which
     892             :      * determines the files/objects
     893             :      */
     894             :     const std::vector<GUInt64> m_anOuterBlockSize;
     895             : 
     896             :     /** m_anInnerBlockSize is the inner most block size of sharding, which
     897             :      * is the one exposed to the user with GetBlockSize()
     898             :      * When no sharding is involved m_anOuterBlockSize == m_anInnerBlockSize
     899             :      * Note that m_anOuterBlockSize might be equal to m_anInnerBlockSize, even
     900             :      * when sharding is involved, and it is actually a common use case.
     901             :      */
     902             :     const std::vector<GUInt64> m_anInnerBlockSize;
     903             : 
     904             :     /** m_anCountInnerBlockInOuter[i] = m_anOuterBlockSize[i] / m_anInnerBlockSize[i]
     905             :      * That is the number of inner blocks in one outer block
     906             :      */
     907             :     const std::vector<GUInt64> m_anCountInnerBlockInOuter;
     908             : 
     909             :     //! Total number of inner chunks in the array
     910             :     const uint64_t m_nTotalInnerChunkCount;
     911             : 
     912             :     //! Size in bytes of a inner chunk using the Zarr native data type
     913             :     const size_t m_nInnerBlockSizeBytes;
     914             : 
     915             :     mutable ZarrAttributeGroup m_oAttrGroup;
     916             : 
     917             :     const bool m_bUseOptimizedCodePaths;
     918             : 
     919             :     CPLStringList m_aosStructuralInfo{};
     920             :     CPLJSONObject m_dtype{};
     921             :     GByte *m_pabyNoData = nullptr;
     922             :     std::string m_osDimSeparator{"."};
     923             :     std::string m_osFilename{};
     924             :     mutable ZarrByteVectorQuickResize m_abyRawBlockData{};
     925             :     mutable ZarrByteVectorQuickResize m_abyDecodedBlockData{};
     926             : 
     927             :     /** Inner block index of the cached block
     928             :      * i.e. m_anCachedBlockIndices[i] < cpl::round_up(m_aoDims[i]->GetSize, m_anInnerBlockSize[i])
     929             :      */
     930             :     mutable std::vector<uint64_t> m_anCachedBlockIndices{};
     931             : 
     932             :     mutable bool m_bCachedBlockValid = false;
     933             :     mutable bool m_bCachedBlockEmpty = false;
     934             :     mutable bool m_bDirtyBlock = false;
     935             :     mutable std::shared_ptr<OGRSpatialReference> m_poSRS{};
     936             :     mutable bool m_bAllocateWorkingBuffersDone = false;
     937             :     mutable bool m_bWorkingBuffersOK = false;
     938             :     bool m_bUpdatable = false;
     939             :     bool m_bDefinitionModified = false;
     940             :     bool m_bSRSModified = false;
     941             :     bool m_bNew = false;
     942             :     std::string m_osUnit{};
     943             :     bool m_bUnitModified = false;
     944             :     double m_dfOffset = 0.0;
     945             :     bool m_bHasOffset = false;
     946             :     bool m_bOffsetModified = false;
     947             :     double m_dfScale = 1.0;
     948             :     bool m_bHasScale = false;
     949             :     bool m_bScaleModified = false;
     950             :     std::weak_ptr<ZarrGroupBase> m_poGroupWeak{};
     951             :     mutable bool m_bHasTriedBlockCachePresenceArray = false;
     952             :     mutable std::shared_ptr<GDALMDArray> m_poBlockCachePresenceArray{};
     953             :     mutable std::mutex m_oMutex{};
     954             :     CPLStringList m_aosCreationOptions{};
     955             : 
     956             :     struct CachedBlock
     957             :     {
     958             :         ZarrByteVectorQuickResize abyDecoded{};
     959             :     };
     960             : 
     961             :     mutable std::map<std::vector<uint64_t>, CachedBlock> m_oChunkCache{};
     962             : 
     963             :     static uint64_t
     964             :     ComputeBlockCount(const std::string &osName,
     965             :                       const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
     966             :                       const std::vector<GUInt64> &anBlockSize);
     967             : 
     968             :     ZarrArray(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     969             :               const std::shared_ptr<ZarrGroupBase> &poParent,
     970             :               const std::string &osName,
     971             :               const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
     972             :               const GDALExtendedDataType &oType,
     973             :               const std::vector<DtypeElt> &aoDtypeElts,
     974             :               const std::vector<GUInt64> &anOuterBlockSize,
     975             :               const std::vector<GUInt64> &anInnerBlockSize);
     976             : 
     977             :     virtual bool LoadBlockData(const uint64_t *blockIndices,
     978             :                                bool &bMissingBlockOut) const = 0;
     979             : 
     980             :     virtual bool AllocateWorkingBuffers() const = 0;
     981             : 
     982             :     void SerializeNumericNoData(CPLJSONObject &oRoot) const;
     983             : 
     984             :     void DeallocateDecodedBlockData();
     985             : 
     986             :     virtual std::string GetDataDirectory() const = 0;
     987             : 
     988             :     virtual CPLStringList
     989             :     GetChunkIndicesFromFilename(const char *pszFilename) const = 0;
     990             : 
     991             :     virtual bool FlushDirtyBlock() const = 0;
     992             : 
     993             :     std::shared_ptr<GDALMDArray> OpenBlockPresenceCache(bool bCanCreate) const;
     994             : 
     995             :     void NotifyChildrenOfRenaming() override;
     996             : 
     997             :     void NotifyChildrenOfDeletion() override;
     998             : 
     999             :     static void EncodeElt(const std::vector<DtypeElt> &elts, const GByte *pSrc,
    1000             :                           GByte *pDst);
    1001             : 
    1002             :     // Disable copy constructor and assignment operator
    1003             :     ZarrArray(const ZarrArray &) = delete;
    1004             :     ZarrArray &operator=(const ZarrArray &) = delete;
    1005             : 
    1006             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
    1007             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    1008             :                const GDALExtendedDataType &bufferDataType,
    1009             :                void *pDstBuffer) const override;
    1010             : 
    1011             :     bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
    1012             :                 const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    1013             :                 const GDALExtendedDataType &bufferDataType,
    1014             :                 const void *pSrcBuffer) override;
    1015             : 
    1016             :     bool IsEmptyBlock(const ZarrByteVectorQuickResize &abyBlock) const;
    1017             : 
    1018             :     bool IAdviseReadCommon(const GUInt64 *arrayStartIdx, const size_t *count,
    1019             :                            CSLConstList papszOptions,
    1020             :                            std::vector<uint64_t> &anIndicesCur,
    1021             :                            int &nThreadsMax,
    1022             :                            std::vector<uint64_t> &anReqBlocksIndices,
    1023             :                            size_t &nReqBlocks) const;
    1024             : 
    1025             :     CPLJSONObject SerializeSpecialAttributes();
    1026             : 
    1027             :     virtual std::string
    1028             :     BuildChunkFilename(const uint64_t *blockIndices) const = 0;
    1029             : 
    1030             :     bool SetStatistics(bool bApproxStats, double dfMin, double dfMax,
    1031             :                        double dfMean, double dfStdDev, GUInt64 nValidCount,
    1032             :                        CSLConstList papszOptions) override;
    1033             : 
    1034             :     bool IsBlockMissingFromCacheInfo(const std::string &osFilename,
    1035             :                                      const uint64_t *blockIndices) const;
    1036             : 
    1037             :     virtual CPLStringList GetRawBlockInfoInfo() const = 0;
    1038             : 
    1039             :   public:
    1040             :     ~ZarrArray() override;
    1041             : 
    1042             :     static bool ParseChunkSize(const CPLJSONArray &oChunks,
    1043             :                                const GDALExtendedDataType &oType,
    1044             :                                std::vector<GUInt64> &anBlockSize);
    1045             : 
    1046             :     static bool FillBlockSize(
    1047             :         const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
    1048             :         const GDALExtendedDataType &oDataType,
    1049             :         std::vector<GUInt64> &anBlockSize, CSLConstList papszOptions);
    1050             : 
    1051         145 :     bool IsWritable() const override
    1052             :     {
    1053         145 :         return m_bUpdatable;
    1054             :     }
    1055             : 
    1056        4026 :     const std::string &GetFilename() const override
    1057             :     {
    1058        4026 :         return m_osFilename;
    1059             :     }
    1060             : 
    1061             :     const std::vector<std::shared_ptr<GDALDimension>> &
    1062       29200 :     GetDimensions() const override
    1063             :     {
    1064       29200 :         return m_aoDims;
    1065             :     }
    1066             : 
    1067       29982 :     const GDALExtendedDataType &GetDataType() const override
    1068             :     {
    1069       29982 :         return m_oType;
    1070             :     }
    1071             : 
    1072         619 :     std::vector<GUInt64> GetBlockSize() const override
    1073             :     {
    1074         619 :         return m_anInnerBlockSize;
    1075             :     }
    1076             : 
    1077          21 :     CSLConstList GetStructuralInfo() const override
    1078             :     {
    1079          21 :         return m_aosStructuralInfo.List();
    1080             :     }
    1081             : 
    1082       22117 :     const void *GetRawNoDataValue() const override
    1083             :     {
    1084       22117 :         return m_pabyNoData;
    1085             :     }
    1086             : 
    1087          85 :     const std::string &GetUnit() const override
    1088             :     {
    1089          85 :         return m_osUnit;
    1090             :     }
    1091             : 
    1092             :     bool SetUnit(const std::string &osUnit) override;
    1093             : 
    1094          55 :     void RegisterUnit(const std::string &osUnit)
    1095             :     {
    1096          55 :         m_osUnit = osUnit;
    1097          55 :     }
    1098             : 
    1099        2171 :     void RegisterGroup(const std::weak_ptr<ZarrGroupBase> &group)
    1100             :     {
    1101        2171 :         m_poGroupWeak = group;
    1102        2171 :     }
    1103             : 
    1104             :     double GetOffset(bool *pbHasOffset,
    1105             :                      GDALDataType *peStorageType) const override;
    1106             : 
    1107             :     double GetScale(bool *pbHasScale,
    1108             :                     GDALDataType *peStorageType) const override;
    1109             : 
    1110             :     bool SetOffset(double dfOffset, GDALDataType eStorageType) override;
    1111             : 
    1112             :     bool SetScale(double dfScale, GDALDataType eStorageType) override;
    1113             : 
    1114             :     std::vector<std::shared_ptr<GDALMDArray>>
    1115             :     GetCoordinateVariables() const override;
    1116             : 
    1117             :     bool IsRegularlySpaced(double &dfStart, double &dfIncrement) const override;
    1118             : 
    1119             :     bool Resize(const std::vector<GUInt64> &anNewDimSizes,
    1120             :                 CSLConstList) override;
    1121             : 
    1122           3 :     void RegisterOffset(double dfOffset)
    1123             :     {
    1124           3 :         m_bHasOffset = true;
    1125           3 :         m_dfOffset = dfOffset;
    1126           3 :     }
    1127             : 
    1128           3 :     void RegisterScale(double dfScale)
    1129             :     {
    1130           3 :         m_bHasScale = true;
    1131           3 :         m_dfScale = dfScale;
    1132           3 :     }
    1133             : 
    1134             :     bool SetRawNoDataValue(const void *pRawNoData) override;
    1135             : 
    1136             :     void RegisterNoDataValue(const void *);
    1137             : 
    1138        2171 :     void SetFilename(const std::string &osFilename)
    1139             :     {
    1140        2171 :         m_osFilename = osFilename;
    1141        2171 :     }
    1142             : 
    1143        2171 :     void SetDimSeparator(const std::string &osDimSeparator)
    1144             :     {
    1145        2171 :         m_osDimSeparator = osDimSeparator;
    1146        2171 :     }
    1147             : 
    1148             :     void SetAttributes(const std::shared_ptr<ZarrGroupBase> &poGroup,
    1149             :                        CPLJSONObject &oAttributes);
    1150             : 
    1151          51 :     void SetSRS(const std::shared_ptr<OGRSpatialReference> &srs)
    1152             :     {
    1153          51 :         m_poSRS = srs;
    1154          51 :     }
    1155             : 
    1156             :     std::shared_ptr<GDALAttribute>
    1157          67 :     GetAttribute(const std::string &osName) const override
    1158             :     {
    1159          67 :         return m_oAttrGroup.GetAttribute(osName);
    1160             :     }
    1161             : 
    1162             :     std::vector<std::shared_ptr<GDALAttribute>>
    1163         173 :     GetAttributes(CSLConstList papszOptions) const override
    1164             :     {
    1165         173 :         return m_oAttrGroup.GetAttributes(papszOptions);
    1166             :     }
    1167             : 
    1168             :     std::shared_ptr<GDALAttribute>
    1169             :     CreateAttribute(const std::string &osName,
    1170             :                     const std::vector<GUInt64> &anDimensions,
    1171             :                     const GDALExtendedDataType &oDataType,
    1172             :                     CSLConstList papszOptions = nullptr) override;
    1173             : 
    1174             :     bool DeleteAttribute(const std::string &osName,
    1175             :                          CSLConstList papszOptions = nullptr) override;
    1176             : 
    1177             :     std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override;
    1178             : 
    1179             :     bool SetSpatialRef(const OGRSpatialReference *poSRS) override;
    1180             : 
    1181        2171 :     void SetUpdatable(bool bUpdatable)
    1182             :     {
    1183        2171 :         m_bUpdatable = bUpdatable;
    1184        2171 :     }
    1185             : 
    1186        2171 :     void SetDtype(const CPLJSONObject &dtype)
    1187             :     {
    1188        2171 :         m_dtype = dtype;
    1189        2171 :     }
    1190             : 
    1191         456 :     void SetDefinitionModified(bool bModified)
    1192             :     {
    1193         456 :         m_bDefinitionModified = bModified;
    1194         456 :     }
    1195             : 
    1196         441 :     void SetNew(bool bNew)
    1197             :     {
    1198         441 :         m_bNew = bNew;
    1199         441 :     }
    1200             : 
    1201             :     bool Rename(const std::string &osNewName) override;
    1202             : 
    1203             :     void ParentRenamed(const std::string &osNewParentFullName) override;
    1204             : 
    1205             :     virtual bool Flush() = 0;
    1206             : 
    1207             :     //! Return the group owning the array. Might be nullptr
    1208             :     std::shared_ptr<ZarrGroupBase> GetParentGroup() const;
    1209             : 
    1210             :     //! Return the root group. Might be nullptr
    1211        1778 :     std::shared_ptr<GDALGroup> GetRootGroup() const override
    1212             :     {
    1213        1778 :         return m_poSharedResource->GetRootGroup();
    1214             :     }
    1215             : 
    1216             :     bool GetRawBlockInfo(const uint64_t *panBlockCoordinates,
    1217             :                          GDALMDArrayRawBlockInfo &info) const override;
    1218             : 
    1219             :     bool BlockCachePresence();
    1220             : 
    1221         693 :     void SetStructuralInfo(const char *pszKey, const char *pszValue)
    1222             :     {
    1223         693 :         m_aosStructuralInfo.SetNameValue(pszKey, pszValue);
    1224         693 :     }
    1225             : 
    1226         441 :     void SetCreationOptions(CSLConstList papszOptions)
    1227             :     {
    1228         441 :         m_aosCreationOptions = papszOptions;
    1229         441 :     }
    1230             : 
    1231             :     static void DecodeSourceElt(const std::vector<DtypeElt> &elts,
    1232             :                                 const GByte *pSrc, GByte *pDst);
    1233             : 
    1234             :     static void GetDimensionTypeDirection(CPLJSONObject &oAttributes,
    1235             :                                           std::string &osType,
    1236             :                                           std::string &osDirection);
    1237             : };
    1238             : 
    1239             : /************************************************************************/
    1240             : /*                             ZarrV2Array                              */
    1241             : /************************************************************************/
    1242             : 
    1243             : class ZarrV2Array final : public ZarrArray
    1244             : {
    1245             :     CPLJSONObject m_oCompressorJSon{};
    1246             :     const CPLCompressor *m_psCompressor = nullptr;
    1247             :     std::string m_osDecompressorId{};
    1248             :     const CPLCompressor *m_psDecompressor = nullptr;
    1249             :     CPLJSONArray m_oFiltersArray{};  // ZarrV2 specific
    1250             :     bool m_bFortranOrder = false;
    1251             :     mutable ZarrByteVectorQuickResize
    1252             :         m_abyTmpRawBlockData{};  // used for Fortran order
    1253             : 
    1254             :     ZarrV2Array(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
    1255             :                 const std::shared_ptr<ZarrGroupBase> &poParent,
    1256             :                 const std::string &osName,
    1257             :                 const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
    1258             :                 const GDALExtendedDataType &oType,
    1259             :                 const std::vector<DtypeElt> &aoDtypeElts,
    1260             :                 const std::vector<GUInt64> &anOuterBlockSize,
    1261             :                 bool bFortranOrder);
    1262             : 
    1263             :     bool Serialize();
    1264             : 
    1265             :     bool LoadBlockData(const uint64_t *blockIndices, bool bUseMutex,
    1266             :                        const CPLCompressor *psDecompressor,
    1267             :                        ZarrByteVectorQuickResize &abyRawBlockData,
    1268             :                        ZarrByteVectorQuickResize &abyTmpRawBlockData,
    1269             :                        ZarrByteVectorQuickResize &abyDecodedBlockData,
    1270             :                        bool &bMissingBlockOut) const;
    1271             : 
    1272             :     bool NeedDecodedBuffer() const;
    1273             : 
    1274             :     bool AllocateWorkingBuffers(
    1275             :         ZarrByteVectorQuickResize &abyRawBlockData,
    1276             :         ZarrByteVectorQuickResize &abyTmpRawBlockData,
    1277             :         ZarrByteVectorQuickResize &abyDecodedBlockData) const;
    1278             : 
    1279             :     void BlockTranspose(const ZarrByteVectorQuickResize &abySrc,
    1280             :                         ZarrByteVectorQuickResize &abyDst, bool bDecode) const;
    1281             : 
    1282             :     // Disable copy constructor and assignment operator
    1283             :     ZarrV2Array(const ZarrV2Array &) = delete;
    1284             :     ZarrV2Array &operator=(const ZarrV2Array &) = delete;
    1285             : 
    1286             :   public:
    1287             :     ~ZarrV2Array() override;
    1288             : 
    1289             :     static std::shared_ptr<ZarrV2Array>
    1290             :     Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
    1291             :            const std::shared_ptr<ZarrGroupBase> &poParent,
    1292             :            const std::string &osName,
    1293             :            const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
    1294             :            const GDALExtendedDataType &oType,
    1295             :            const std::vector<DtypeElt> &aoDtypeElts,
    1296             :            const std::vector<GUInt64> &anBlockSize, bool bFortranOrder);
    1297             : 
    1298             :     void SetCompressorJson(const CPLJSONObject &oCompressor);
    1299             : 
    1300         996 :     void SetCompressorDecompressor(const std::string &osDecompressorId,
    1301             :                                    const CPLCompressor *psComp,
    1302             :                                    const CPLCompressor *psDecomp)
    1303             :     {
    1304         996 :         m_psCompressor = psComp;
    1305         996 :         m_osDecompressorId = osDecompressorId;
    1306         996 :         m_psDecompressor = psDecomp;
    1307         996 :     }
    1308             : 
    1309             :     void SetFilters(const CPLJSONArray &oFiltersArray);
    1310             : 
    1311             :     bool Flush() override;
    1312             : 
    1313             :   protected:
    1314             :     std::string GetDataDirectory() const override;
    1315             : 
    1316             :     CPLStringList
    1317             :     GetChunkIndicesFromFilename(const char *pszFilename) const override;
    1318             : 
    1319             :     bool FlushDirtyBlock() const override;
    1320             : 
    1321             :     std::string BuildChunkFilename(const uint64_t *blockIndices) const override;
    1322             : 
    1323             :     bool AllocateWorkingBuffers() const override;
    1324             : 
    1325             :     bool LoadBlockData(const uint64_t *blockIndices,
    1326             :                        bool &bMissingBlockOut) const override;
    1327             : 
    1328             :     bool IAdviseRead(const GUInt64 *arrayStartIdx, const size_t *count,
    1329             :                      CSLConstList papszOptions) const override;
    1330             : 
    1331             :     CPLStringList GetRawBlockInfoInfo() const override;
    1332             : };
    1333             : 
    1334             : /************************************************************************/
    1335             : /*                             ZarrV3Array                              */
    1336             : /************************************************************************/
    1337             : 
    1338             : class ZarrV3CodecSequence;
    1339             : 
    1340             : class ZarrV3Array final : public ZarrArray
    1341             : {
    1342             :     bool m_bV2ChunkKeyEncoding = false;
    1343             :     std::unique_ptr<ZarrV3CodecSequence> m_poCodecs{};
    1344             :     CPLJSONArray m_oJSONCodecs{};
    1345             :     mutable bool m_bOverviewsLoaded = false;
    1346             :     mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
    1347             : 
    1348             :     ZarrV3Array(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
    1349             :                 const std::shared_ptr<ZarrGroupBase> &poParent,
    1350             :                 const std::string &osName,
    1351             :                 const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
    1352             :                 const GDALExtendedDataType &oType,
    1353             :                 const std::vector<DtypeElt> &aoDtypeElts,
    1354             :                 const std::vector<GUInt64> &anOuterBlockSize,
    1355             :                 const std::vector<GUInt64> &anInnerBlockSize);
    1356             : 
    1357             :     bool Serialize(const CPLJSONObject &oAttrs);
    1358             : 
    1359             :     bool NeedDecodedBuffer() const;
    1360             : 
    1361             :     bool AllocateWorkingBuffers(
    1362             :         ZarrByteVectorQuickResize &abyRawBlockData,
    1363             :         ZarrByteVectorQuickResize &abyDecodedBlockData) const;
    1364             : 
    1365             :     bool LoadBlockData(const uint64_t *blockIndices, bool bUseMutex,
    1366             :                        ZarrV3CodecSequence *poCodecs,
    1367             :                        ZarrByteVectorQuickResize &abyRawBlockData,
    1368             :                        ZarrByteVectorQuickResize &abyDecodedBlockData,
    1369             :                        bool &bMissingBlockOut) const;
    1370             : 
    1371             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
    1372             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    1373             :                const GDALExtendedDataType &bufferDataType,
    1374             :                void *pDstBuffer) const override;
    1375             : 
    1376             :     void PreloadShardedBlocks(const GUInt64 *arrayStartIdx,
    1377             :                               const size_t *count) const;
    1378             : 
    1379             :     bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
    1380             :                 const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    1381             :                 const GDALExtendedDataType &bufferDataType,
    1382             :                 const void *pSrcBuffer) override;
    1383             : 
    1384             :     void LoadOverviews() const;
    1385             : 
    1386             :   public:
    1387             :     ~ZarrV3Array() override;
    1388             : 
    1389             :     static std::shared_ptr<ZarrV3Array>
    1390             :     Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
    1391             :            const std::shared_ptr<ZarrGroupBase> &poParent,
    1392             :            const std::string &osName,
    1393             :            const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
    1394             :            const GDALExtendedDataType &oType,
    1395             :            const std::vector<DtypeElt> &aoDtypeElts,
    1396             :            const std::vector<GUInt64> &anOuterBlockSize,
    1397             :            const std::vector<GUInt64> &anInnerBlockSize);
    1398             : 
    1399        1046 :     void SetIsV2ChunkKeyEncoding(bool b)
    1400             :     {
    1401        1046 :         m_bV2ChunkKeyEncoding = b;
    1402        1046 :     }
    1403             : 
    1404             :     void SetCodecs(const CPLJSONArray &oJSONCodecs,
    1405             :                    std::unique_ptr<ZarrV3CodecSequence> &&poCodecs);
    1406             : 
    1407             :     bool Flush() override;
    1408             : 
    1409             :     static std::unique_ptr<ZarrV3CodecSequence>
    1410             :     SetupCodecs(const CPLJSONArray &oCodecs,
    1411             :                 const std::vector<GUInt64> &anOuterBlockSize,
    1412             :                 std::vector<GUInt64> &anInnerBlockSize, DtypeElt &zarrDataType,
    1413             :                 const std::vector<GByte> &abyNoData);
    1414             :     int GetOverviewCount() const override;
    1415             : 
    1416             :     std::shared_ptr<GDALMDArray> GetOverview(int idx) const override;
    1417             : 
    1418             :   protected:
    1419             :     std::string GetDataDirectory() const override;
    1420             : 
    1421             :     CPLStringList
    1422             :     GetChunkIndicesFromFilename(const char *pszFilename) const override;
    1423             : 
    1424             :     bool AllocateWorkingBuffers() const override;
    1425             : 
    1426             :     bool FlushDirtyBlock() const override;
    1427             : 
    1428             :     std::string BuildChunkFilename(const uint64_t *blockIndices) const override;
    1429             : 
    1430             :     bool LoadBlockData(const uint64_t *blockIndices,
    1431             :                        bool &bMissingBlockOut) const override;
    1432             : 
    1433             :     bool IAdviseRead(const GUInt64 *arrayStartIdx, const size_t *count,
    1434             :                      CSLConstList papszOptions) const override;
    1435             : 
    1436             :     CPLStringList GetRawBlockInfoInfo() const override;
    1437             : };
    1438             : 
    1439             : void ZarrClearCoordinateCache();
    1440             : 
    1441             : #endif  // ZARR_H

Generated by: LCOV version 1.14