LCOV - code coverage report
Current view: top level - frmts/zarr - zarr.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 236 239 98.7 %
Date: 2025-03-27 19:00:23 Functions: 82 84 97.6 %

          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.h"
      20             : #include "memmultidim.h"
      21             : 
      22             : #include <array>
      23             : #include <map>
      24             : #include <memory>
      25             : #include <mutex>
      26             : #include <set>
      27             : 
      28             : #define ZARR_DEBUG_KEY "ZARR"
      29             : 
      30             : #define CRS_ATTRIBUTE_NAME "_CRS"
      31             : 
      32             : const CPLCompressor *ZarrGetShuffleCompressor();
      33             : const CPLCompressor *ZarrGetShuffleDecompressor();
      34             : const CPLCompressor *ZarrGetQuantizeDecompressor();
      35             : 
      36             : /************************************************************************/
      37             : /*                            ZarrDataset                               */
      38             : /************************************************************************/
      39             : 
      40             : class ZarrDataset final : public GDALDataset
      41             : {
      42             :     friend class ZarrRasterBand;
      43             : 
      44             :     std::shared_ptr<GDALGroup> m_poRootGroup{};
      45             :     CPLStringList m_aosSubdatasets{};
      46             :     std::array<double, 6> m_adfGeoTransform{{0.0, 1.0, 0.0, 0.0, 0.0, 1.0}};
      47             :     bool m_bHasGT = false;
      48             :     std::shared_ptr<GDALDimension> m_poDimX{};
      49             :     std::shared_ptr<GDALDimension> m_poDimY{};
      50             :     std::shared_ptr<GDALMDArray> m_poSingleArray{};
      51             : 
      52             :     static GDALDataset *OpenMultidim(const char *pszFilename, bool bUpdateMode,
      53             :                                      CSLConstList papszOpenOptions);
      54             : 
      55             :   public:
      56             :     explicit ZarrDataset(const std::shared_ptr<GDALGroup> &poRootGroup);
      57             :     ~ZarrDataset() override;
      58             : 
      59             :     CPLErr FlushCache(bool bAtClosing = false) override;
      60             : 
      61             :     static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
      62             :     static GDALDataset *
      63             :     CreateMultiDimensional(const char *pszFilename,
      64             :                            CSLConstList /*papszRootGroupOptions*/,
      65             :                            CSLConstList /*papszOptions*/);
      66             : 
      67             :     static GDALDataset *Create(const char *pszName, int nXSize, int nYSize,
      68             :                                int nBands, GDALDataType eType,
      69             :                                char **papszOptions);
      70             : 
      71             :     const char *GetMetadataItem(const char *pszName,
      72             :                                 const char *pszDomain) override;
      73             :     char **GetMetadata(const char *pszDomain) override;
      74             : 
      75             :     CPLErr SetMetadata(char **papszMetadata, const char *pszDomain) override;
      76             : 
      77             :     const OGRSpatialReference *GetSpatialRef() const override;
      78             :     CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
      79             : 
      80             :     CPLErr GetGeoTransform(double *padfTransform) override;
      81             :     CPLErr SetGeoTransform(double *padfTransform) override;
      82             : 
      83         856 :     std::shared_ptr<GDALGroup> GetRootGroup() const override
      84             :     {
      85         856 :         return m_poRootGroup;
      86             :     }
      87             : };
      88             : 
      89             : /************************************************************************/
      90             : /*                          ZarrRasterBand                              */
      91             : /************************************************************************/
      92             : 
      93             : class ZarrRasterBand final : public GDALRasterBand
      94             : {
      95             :     friend class ZarrDataset;
      96             : 
      97             :     std::shared_ptr<GDALMDArray> m_poArray;
      98             :     GDALColorInterp m_eColorInterp = GCI_Undefined;
      99             : 
     100             :   protected:
     101             :     CPLErr IReadBlock(int nBlockXOff, int nBlockYOff, void *pData) override;
     102             :     CPLErr IWriteBlock(int nBlockXOff, int nBlockYOff, void *pData) override;
     103             :     CPLErr IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
     104             :                      int nYSize, void *pData, int nBufXSize, int nBufYSize,
     105             :                      GDALDataType eBufType, GSpacing nPixelSpaceBuf,
     106             :                      GSpacing nLineSpaceBuf,
     107             :                      GDALRasterIOExtraArg *psExtraArg) override;
     108             : 
     109             :   public:
     110             :     explicit ZarrRasterBand(const std::shared_ptr<GDALMDArray> &poArray);
     111             : 
     112             :     double GetNoDataValue(int *pbHasNoData) override;
     113             :     int64_t GetNoDataValueAsInt64(int *pbHasNoData) override;
     114             :     uint64_t GetNoDataValueAsUInt64(int *pbHasNoData) override;
     115             :     CPLErr SetNoDataValue(double dfNoData) override;
     116             :     CPLErr SetNoDataValueAsInt64(int64_t nNoData) override;
     117             :     CPLErr SetNoDataValueAsUInt64(uint64_t nNoData) override;
     118             :     double GetOffset(int *pbSuccess = nullptr) override;
     119             :     CPLErr SetOffset(double dfNewOffset) override;
     120             :     double GetScale(int *pbSuccess = nullptr) override;
     121             :     CPLErr SetScale(double dfNewScale) override;
     122             :     const char *GetUnitType() override;
     123             :     CPLErr SetUnitType(const char *pszNewValue) override;
     124             :     GDALColorInterp GetColorInterpretation() override;
     125             :     CPLErr SetColorInterpretation(GDALColorInterp eColorInterp) override;
     126             : };
     127             : 
     128             : /************************************************************************/
     129             : /*                        ZarrAttributeGroup()                          */
     130             : /************************************************************************/
     131             : 
     132             : class ZarrAttributeGroup
     133             : {
     134             :     // Use a MEMGroup as a convenient container for attributes.
     135             :     const bool m_bContainerIsGroup;
     136             :     std::shared_ptr<MEMGroup> m_poGroup;
     137             :     bool m_bModified = false;
     138             : 
     139             :   public:
     140             :     explicit ZarrAttributeGroup(const std::string &osParentName,
     141             :                                 bool bContainerIsGroup);
     142             : 
     143             :     void Init(const CPLJSONObject &obj, bool bUpdatable);
     144             : 
     145         129 :     std::shared_ptr<GDALAttribute> GetAttribute(const std::string &osName) const
     146             :     {
     147         129 :         return m_poGroup->GetAttribute(osName);
     148             :     }
     149             : 
     150             :     std::vector<std::shared_ptr<GDALAttribute>>
     151         159 :     GetAttributes(CSLConstList papszOptions = nullptr) const
     152             :     {
     153         159 :         return m_poGroup->GetAttributes(papszOptions);
     154             :     }
     155             : 
     156             :     std::shared_ptr<GDALAttribute>
     157         175 :     CreateAttribute(const std::string &osName,
     158             :                     const std::vector<GUInt64> &anDimensions,
     159             :                     const GDALExtendedDataType &oDataType,
     160             :                     CSLConstList /* papszOptions */ = nullptr)
     161             :     {
     162         175 :         auto poAttr = m_poGroup->CreateAttribute(osName, anDimensions,
     163         175 :                                                  oDataType, nullptr);
     164         175 :         if (poAttr)
     165             :         {
     166         175 :             m_bModified = true;
     167             :         }
     168         175 :         return poAttr;
     169             :     }
     170             : 
     171          24 :     bool DeleteAttribute(const std::string &osName)
     172             :     {
     173          24 :         const bool bOK = m_poGroup->DeleteAttribute(osName, nullptr);
     174          24 :         if (bOK)
     175             :         {
     176          12 :             m_bModified = true;
     177             :         }
     178          24 :         return bOK;
     179             :     }
     180             : 
     181         805 :     void SetUpdatable(bool bUpdatable)
     182             :     {
     183        1610 :         auto attrs = m_poGroup->GetAttributes(nullptr);
     184        1151 :         for (auto &attr : attrs)
     185             :         {
     186         692 :             auto memAttr = std::dynamic_pointer_cast<MEMAttribute>(attr);
     187         346 :             if (memAttr)
     188         346 :                 memAttr->SetWritable(bUpdatable);
     189             :         }
     190         805 :     }
     191             : 
     192         410 :     void UnsetModified()
     193             :     {
     194         410 :         m_bModified = false;
     195         820 :         auto attrs = m_poGroup->GetAttributes(nullptr);
     196         535 :         for (auto &attr : attrs)
     197             :         {
     198         250 :             auto memAttr = std::dynamic_pointer_cast<MEMAttribute>(attr);
     199         125 :             if (memAttr)
     200         125 :                 memAttr->SetModified(false);
     201             :         }
     202         410 :     }
     203             : 
     204        4256 :     bool IsModified() const
     205             :     {
     206        4256 :         if (m_bModified)
     207         114 :             return true;
     208        8284 :         const auto attrs = m_poGroup->GetAttributes(nullptr);
     209        4675 :         for (const auto &attr : attrs)
     210             :         {
     211         550 :             const auto memAttr = std::dynamic_pointer_cast<MEMAttribute>(attr);
     212         550 :             if (memAttr && memAttr->IsModified())
     213          17 :                 return true;
     214             :         }
     215        4125 :         return false;
     216             :     }
     217             : 
     218             :     CPLJSONObject Serialize() const;
     219             : 
     220             :     void ParentRenamed(const std::string &osNewParentFullName);
     221             : 
     222             :     void ParentDeleted();
     223             : };
     224             : 
     225             : /************************************************************************/
     226             : /*                         ZarrSharedResource                           */
     227             : /************************************************************************/
     228             : 
     229             : class ZarrGroupBase;
     230             : 
     231             : class ZarrSharedResource
     232             :     : public std::enable_shared_from_this<ZarrSharedResource>
     233             : {
     234             :     bool m_bUpdatable = false;
     235             :     std::string m_osRootDirectoryName{};
     236             :     bool m_bZMetadataEnabled = false;
     237             :     CPLJSONObject m_oObj{};  // For .zmetadata
     238             :     bool m_bZMetadataModified = false;
     239             :     std::shared_ptr<GDALPamMultiDim> m_poPAM{};
     240             :     CPLStringList m_aosOpenOptions{};
     241             :     std::weak_ptr<ZarrGroupBase> m_poWeakRootGroup{};
     242             :     std::set<std::string> m_oSetArrayInLoading{};
     243             : 
     244             :     explicit ZarrSharedResource(const std::string &osRootDirectoryName,
     245             :                                 bool bUpdatable);
     246             : 
     247             :     std::shared_ptr<ZarrGroupBase> OpenRootGroup();
     248             : 
     249             :   public:
     250             :     static std::shared_ptr<ZarrSharedResource>
     251             :     Create(const std::string &osRootDirectoryName, bool bUpdatable);
     252             : 
     253             :     ~ZarrSharedResource();
     254             : 
     255        2277 :     bool IsUpdatable() const
     256             :     {
     257        2277 :         return m_bUpdatable;
     258             :     }
     259             : 
     260         167 :     void EnableZMetadata()
     261             :     {
     262         167 :         m_bZMetadataEnabled = true;
     263         167 :     }
     264             : 
     265             :     void SetZMetadataItem(const std::string &osFilename,
     266             :                           const CPLJSONObject &obj);
     267             : 
     268             :     void DeleteZMetadataItemRecursive(const std::string &osFilename);
     269             : 
     270             :     void RenameZMetadataRecursive(const std::string &osOldFilename,
     271             :                                   const std::string &osNewFilename);
     272             : 
     273        1197 :     const std::shared_ptr<GDALPamMultiDim> &GetPAM()
     274             :     {
     275        1197 :         return m_poPAM;
     276             :     }
     277             : 
     278        1210 :     const CPLStringList &GetOpenOptions() const
     279             :     {
     280        1210 :         return m_aosOpenOptions;
     281             :     }
     282             : 
     283         696 :     void SetOpenOptions(CSLConstList papszOpenOptions)
     284             :     {
     285         696 :         m_aosOpenOptions = papszOpenOptions;
     286         696 :     }
     287             : 
     288             :     void
     289             :     UpdateDimensionSize(const std::shared_ptr<GDALDimension> &poUpdatedDim);
     290             : 
     291         696 :     std::shared_ptr<ZarrGroupBase> GetRootGroup()
     292             :     {
     293         696 :         auto poRootGroup = m_poWeakRootGroup.lock();
     294         696 :         if (poRootGroup)
     295           0 :             return poRootGroup;
     296         696 :         poRootGroup = OpenRootGroup();
     297         696 :         m_poWeakRootGroup = poRootGroup;
     298         696 :         return poRootGroup;
     299             :     }
     300             : 
     301          80 :     void SetRootGroup(const std::shared_ptr<ZarrGroupBase> &poRootGroup)
     302             :     {
     303          80 :         m_poWeakRootGroup = poRootGroup;
     304          80 :     }
     305             : 
     306             :     bool AddArrayInLoading(const std::string &osZarrayFilename);
     307             :     void RemoveArrayInLoading(const std::string &osZarrayFilename);
     308             : 
     309             :     struct SetFilenameAdder
     310             :     {
     311             :         std::shared_ptr<ZarrSharedResource> m_poSharedResource;
     312             :         const std::string m_osFilename;
     313             :         const bool m_bOK;
     314             : 
     315         842 :         SetFilenameAdder(
     316             :             const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     317             :             const std::string &osFilename)
     318         842 :             : m_poSharedResource(poSharedResource), m_osFilename(osFilename),
     319         842 :               m_bOK(m_poSharedResource->AddArrayInLoading(m_osFilename))
     320             :         {
     321         842 :         }
     322             : 
     323         842 :         ~SetFilenameAdder()
     324         842 :         {
     325         842 :             if (m_bOK)
     326         840 :                 m_poSharedResource->RemoveArrayInLoading(m_osFilename);
     327         842 :         }
     328             : 
     329         842 :         bool ok() const
     330             :         {
     331         842 :             return m_bOK;
     332             :         }
     333             :     };
     334             : };
     335             : 
     336             : /************************************************************************/
     337             : /*                             ZarrGroup                                */
     338             : /************************************************************************/
     339             : 
     340             : class ZarrArray;
     341             : class ZarrDimension;
     342             : 
     343             : class ZarrGroupBase CPL_NON_FINAL : public GDALGroup
     344             : {
     345             :   protected:
     346             :     friend class ZarrV2Group;
     347             :     friend class ZarrV3Group;
     348             : 
     349             :     // For ZarrV2, this is the directory of the group
     350             :     // For ZarrV3, this is the root directory of the dataset
     351             :     std::shared_ptr<ZarrSharedResource> m_poSharedResource;
     352             :     std::string m_osDirectoryName{};
     353             :     std::weak_ptr<ZarrGroupBase>
     354             :         m_poParent{};  // weak reference to owning parent
     355             :     std::shared_ptr<ZarrGroupBase>
     356             :         m_poParentStrongRef{};  // strong reference, used only when opening from
     357             :                                 // a subgroup
     358             :     mutable std::map<CPLString, std::shared_ptr<ZarrGroupBase>> m_oMapGroups{};
     359             :     mutable std::map<CPLString, std::shared_ptr<ZarrArray>> m_oMapMDArrays{};
     360             :     mutable std::map<CPLString, std::shared_ptr<ZarrDimension>>
     361             :         m_oMapDimensions{};
     362             :     mutable bool m_bDirectoryExplored = false;
     363             :     mutable std::vector<std::string> m_aosGroups{};
     364             :     mutable std::vector<std::string> m_aosArrays{};
     365             :     mutable ZarrAttributeGroup m_oAttrGroup;
     366             :     mutable bool m_bAttributesLoaded = false;
     367             :     bool m_bReadFromZMetadata = false;
     368             :     mutable bool m_bDimensionsInstantiated = false;
     369             :     bool m_bUpdatable = false;
     370             :     bool m_bDimSizeInUpdate = false;
     371             : 
     372             :     virtual void ExploreDirectory() const = 0;
     373             :     virtual void LoadAttributes() const = 0;
     374             : 
     375        1461 :     ZarrGroupBase(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     376             :                   const std::string &osParentName, const std::string &osName)
     377        1461 :         : GDALGroup(osParentName, osName), m_poSharedResource(poSharedResource),
     378        1461 :           m_oAttrGroup(m_osFullName, /*bContainerIsGroup=*/true)
     379             :     {
     380        1461 :     }
     381             : 
     382             :   protected:
     383             :     friend class ZarrDimension;
     384             :     bool RenameDimension(const std::string &osOldName,
     385             :                          const std::string &osNewName);
     386             : 
     387             :     void NotifyChildrenOfRenaming() override;
     388             : 
     389             :     void NotifyChildrenOfDeletion() override;
     390             : 
     391             :   public:
     392             :     ~ZarrGroupBase() override;
     393             : 
     394             :     std::shared_ptr<GDALAttribute>
     395          65 :     GetAttribute(const std::string &osName) const override
     396             :     {
     397          65 :         LoadAttributes();
     398          65 :         return m_oAttrGroup.GetAttribute(osName);
     399             :     }
     400             : 
     401             :     std::vector<std::shared_ptr<GDALAttribute>>
     402          42 :     GetAttributes(CSLConstList papszOptions = nullptr) const override
     403             :     {
     404          42 :         LoadAttributes();
     405          42 :         return m_oAttrGroup.GetAttributes(papszOptions);
     406             :     }
     407             : 
     408             :     std::shared_ptr<GDALAttribute>
     409             :     CreateAttribute(const std::string &osName,
     410             :                     const std::vector<GUInt64> &anDimensions,
     411             :                     const GDALExtendedDataType &oDataType,
     412             :                     CSLConstList papszOptions = nullptr) override;
     413             : 
     414             :     bool DeleteAttribute(const std::string &osName,
     415             :                          CSLConstList papszOptions = nullptr) override;
     416             : 
     417             :     std::vector<std::shared_ptr<GDALDimension>>
     418             :     GetDimensions(CSLConstList papszOptions = nullptr) const override;
     419             : 
     420             :     std::shared_ptr<GDALDimension>
     421             :     CreateDimension(const std::string &osName, const std::string &osType,
     422             :                     const std::string &osDirection, GUInt64 nSize,
     423             :                     CSLConstList papszOptions = nullptr) override;
     424             : 
     425             :     std::vector<std::string>
     426             :     GetMDArrayNames(CSLConstList papszOptions = nullptr) const override;
     427             : 
     428             :     std::vector<std::string>
     429             :     GetGroupNames(CSLConstList papszOptions = nullptr) const override;
     430             : 
     431             :     virtual std::shared_ptr<ZarrGroupBase>
     432             :     OpenZarrGroup(const std::string &osName,
     433             :                   CSLConstList papszOptions = nullptr) const = 0;
     434             : 
     435             :     std::shared_ptr<GDALGroup>
     436         603 :     OpenGroup(const std::string &osName,
     437             :               CSLConstList papszOptions = nullptr) const override
     438             :     {
     439             :         return std::static_pointer_cast<GDALGroup>(
     440         603 :             OpenZarrGroup(osName, papszOptions));
     441             :     }
     442             : 
     443             :     bool DeleteGroup(const std::string &osName,
     444             :                      CSLConstList papszOptions = nullptr) override;
     445             : 
     446             :     std::shared_ptr<GDALMDArray>
     447         941 :     OpenMDArray(const std::string &osName,
     448             :                 CSLConstList papszOptions = nullptr) const override
     449             :     {
     450             :         return std::static_pointer_cast<GDALMDArray>(
     451         941 :             OpenZarrArray(osName, papszOptions));
     452             :     }
     453             : 
     454             :     bool DeleteMDArray(const std::string &osName,
     455             :                        CSLConstList papszOptions = nullptr) override;
     456             : 
     457             :     virtual std::shared_ptr<ZarrArray>
     458             :     OpenZarrArray(const std::string &osName,
     459             :                   CSLConstList papszOptions = nullptr) const = 0;
     460             : 
     461        1042 :     void SetDirectoryName(const std::string &osDirectoryName)
     462             :     {
     463        1042 :         m_osDirectoryName = osDirectoryName;
     464        1042 :     }
     465             : 
     466           9 :     const std::string &GetDirectoryName() const
     467             :     {
     468           9 :         return m_osDirectoryName;
     469             :     }
     470             : 
     471             :     void RegisterArray(const std::shared_ptr<ZarrArray> &array) const;
     472             : 
     473        1455 :     void SetUpdatable(bool bUpdatable)
     474             :     {
     475        1455 :         m_bUpdatable = bUpdatable;
     476        1455 :     }
     477             : 
     478             :     void UpdateDimensionSize(const std::shared_ptr<GDALDimension> &poDim);
     479             : 
     480             :     static bool IsValidObjectName(const std::string &osName);
     481             : 
     482             :     bool Rename(const std::string &osNewName) override;
     483             : 
     484             :     //! Returns false in case of error
     485             :     bool
     486             :     CheckArrayOrGroupWithSameNameDoesNotExist(const std::string &osName) const;
     487             : 
     488             :     void ParentRenamed(const std::string &osNewParentFullName) override;
     489             : 
     490             :     void NotifyArrayRenamed(const std::string &osOldName,
     491             :                             const std::string &osNewName);
     492             : };
     493             : 
     494             : /************************************************************************/
     495             : /*                             ZarrV2Group                              */
     496             : /************************************************************************/
     497             : 
     498             : class ZarrV2Group final : public ZarrGroupBase
     499             : {
     500             :     void ExploreDirectory() const override;
     501             :     void LoadAttributes() const override;
     502             : 
     503             :     std::shared_ptr<ZarrV2Group>
     504             :     GetOrCreateSubGroup(const std::string &osSubGroupFullname);
     505             : 
     506        1042 :     ZarrV2Group(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     507             :                 const std::string &osParentName, const std::string &osName)
     508        1042 :         : ZarrGroupBase(poSharedResource, osParentName, osName)
     509             :     {
     510        1042 :     }
     511             : 
     512             :   public:
     513             :     static std::shared_ptr<ZarrV2Group>
     514             :     Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     515             :            const std::string &osParentName, const std::string &osName);
     516             : 
     517             :     ~ZarrV2Group() override;
     518             : 
     519             :     static std::shared_ptr<ZarrV2Group>
     520             :     CreateOnDisk(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     521             :                  const std::string &osParentName, const std::string &osName,
     522             :                  const std::string &osDirectoryName);
     523             : 
     524             :     std::shared_ptr<ZarrArray>
     525             :     OpenZarrArray(const std::string &osName,
     526             :                   CSLConstList papszOptions = nullptr) const override;
     527             : 
     528             :     std::shared_ptr<ZarrGroupBase>
     529             :     OpenZarrGroup(const std::string &osName,
     530             :                   CSLConstList papszOptions = nullptr) const override;
     531             : 
     532             :     std::shared_ptr<GDALGroup>
     533             :     CreateGroup(const std::string &osName,
     534             :                 CSLConstList papszOptions = nullptr) override;
     535             : 
     536             :     std::shared_ptr<ZarrArray>
     537             :     LoadArray(const std::string &osArrayName,
     538             :               const std::string &osZarrayFilename, const CPLJSONObject &oRoot,
     539             :               bool bLoadedFromZMetadata,
     540             :               const CPLJSONObject &oAttributes) const;
     541             : 
     542             :     std::shared_ptr<GDALMDArray> CreateMDArray(
     543             :         const std::string &osName,
     544             :         const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
     545             :         const GDALExtendedDataType &oDataType,
     546             :         CSLConstList papszOptions = nullptr) override;
     547             : 
     548             :     void InitFromZMetadata(const CPLJSONObject &oRoot);
     549             :     bool InitFromZGroup(const CPLJSONObject &oRoot);
     550             : };
     551             : 
     552             : /************************************************************************/
     553             : /*                             ZarrV3Group                              */
     554             : /************************************************************************/
     555             : 
     556             : class ZarrV3Group final : public ZarrGroupBase
     557             : {
     558             :     void ExploreDirectory() const override;
     559             :     void LoadAttributes() const override;
     560             : 
     561             :     ZarrV3Group(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     562             :                 const std::string &osParentName, const std::string &osName,
     563             :                 const std::string &osDirectoryName);
     564             : 
     565             :   public:
     566             :     ~ZarrV3Group() override;
     567             : 
     568             :     static std::shared_ptr<ZarrV3Group>
     569             :     Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     570             :            const std::string &osParentName, const std::string &osName,
     571             :            const std::string &osDirectoryName);
     572             : 
     573             :     std::shared_ptr<ZarrArray>
     574             :     OpenZarrArray(const std::string &osName,
     575             :                   CSLConstList papszOptions = nullptr) const override;
     576             : 
     577             :     std::shared_ptr<ZarrGroupBase>
     578             :     OpenZarrGroup(const std::string &osName,
     579             :                   CSLConstList papszOptions = nullptr) const override;
     580             : 
     581             :     static std::shared_ptr<ZarrV3Group>
     582             :     CreateOnDisk(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     583             :                  const std::string &osParentFullName, const std::string &osName,
     584             :                  const std::string &osDirectoryName);
     585             : 
     586             :     std::shared_ptr<GDALGroup>
     587             :     CreateGroup(const std::string &osName,
     588             :                 CSLConstList papszOptions = nullptr) override;
     589             : 
     590             :     std::shared_ptr<ZarrArray> LoadArray(const std::string &osArrayName,
     591             :                                          const std::string &osZarrayFilename,
     592             :                                          const CPLJSONObject &oRoot) const;
     593             : 
     594             :     std::shared_ptr<GDALMDArray> CreateMDArray(
     595             :         const std::string &osName,
     596             :         const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
     597             :         const GDALExtendedDataType &oDataType,
     598             :         CSLConstList papszOptions = nullptr) override;
     599             : 
     600          53 :     void SetExplored()
     601             :     {
     602          53 :         m_bDirectoryExplored = true;
     603          53 :     }
     604             : };
     605             : 
     606             : /************************************************************************/
     607             : /*                           ZarrDimension                              */
     608             : /************************************************************************/
     609             : 
     610             : class ZarrDimension final : public GDALDimensionWeakIndexingVar
     611             : {
     612             :     const bool m_bUpdatable;
     613             :     std::weak_ptr<ZarrGroupBase> m_poParentGroup;
     614             :     bool m_bModified = false;
     615             :     bool m_bXArrayDim = false;
     616             : 
     617             :   public:
     618        2277 :     ZarrDimension(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     619             :                   const std::weak_ptr<ZarrGroupBase> &poParentGroup,
     620             :                   const std::string &osParentName, const std::string &osName,
     621             :                   const std::string &osType, const std::string &osDirection,
     622             :                   GUInt64 nSize)
     623        2277 :         : GDALDimensionWeakIndexingVar(osParentName, osName, osType,
     624             :                                        osDirection, nSize),
     625        2277 :           m_bUpdatable(poSharedResource->IsUpdatable()),
     626        4554 :           m_poParentGroup(poParentGroup)
     627             :     {
     628        2277 :     }
     629             : 
     630             :     bool Rename(const std::string &osNewName) override;
     631             : 
     632        3094 :     bool IsModified() const
     633             :     {
     634        3094 :         return m_bModified;
     635             :     }
     636             : 
     637        1024 :     void SetXArrayDimension()
     638             :     {
     639        1024 :         m_bXArrayDim = true;
     640        1024 :     }
     641             : 
     642        3857 :     bool IsXArrayDimension() const
     643             :     {
     644        3857 :         return m_bXArrayDim;
     645             :     }
     646             : };
     647             : 
     648             : /************************************************************************/
     649             : /*                              DtypeElt()                              */
     650             : /************************************************************************/
     651             : 
     652             : struct DtypeElt
     653             : {
     654             :     enum class NativeType
     655             :     {
     656             :         BOOLEAN,
     657             :         UNSIGNED_INT,
     658             :         SIGNED_INT,
     659             :         IEEEFP,
     660             :         COMPLEX_IEEEFP,
     661             :         STRING_ASCII,
     662             :         STRING_UNICODE
     663             :     };
     664             : 
     665             :     NativeType nativeType = NativeType::BOOLEAN;
     666             :     size_t nativeOffset = 0;
     667             :     size_t nativeSize = 0;
     668             :     bool needByteSwapping = false;
     669             :     bool gdalTypeIsApproxOfNative = false;
     670             :     GDALExtendedDataType gdalType = GDALExtendedDataType::Create(GDT_Unknown);
     671             :     size_t gdalOffset = 0;
     672             :     size_t gdalSize = 0;
     673             : };
     674             : 
     675             : /************************************************************************/
     676             : /*                      ZarrByteVectorQuickResize                       */
     677             : /************************************************************************/
     678             : 
     679             : /* std::vector<GByte> with quick resizing (ie that doesn't zero out when
     680             :  * growing back to a previously reached greater size).
     681             :  */
     682       85469 : class ZarrByteVectorQuickResize
     683             : {
     684             :     std::vector<GByte> m_oVec{};
     685             :     size_t m_nSize = 0;
     686             : 
     687             :   public:
     688       51702 :     ZarrByteVectorQuickResize() = default;
     689             : 
     690             :     ZarrByteVectorQuickResize(const ZarrByteVectorQuickResize &) = delete;
     691             :     ZarrByteVectorQuickResize &
     692             :     operator=(const ZarrByteVectorQuickResize &) = delete;
     693             : 
     694       31929 :     ZarrByteVectorQuickResize(ZarrByteVectorQuickResize &&) = default;
     695             :     ZarrByteVectorQuickResize &
     696             :     operator=(ZarrByteVectorQuickResize &&) = default;
     697             : 
     698      101181 :     void resize(size_t nNewSize)
     699             :     {
     700      101181 :         if (nNewSize > m_oVec.size())
     701       32708 :             m_oVec.resize(nNewSize);
     702      100590 :         m_nSize = nNewSize;
     703      100590 :     }
     704             : 
     705      228059 :     inline bool empty() const
     706             :     {
     707      228059 :         return m_nSize == 0;
     708             :     }
     709             : 
     710      159405 :     inline size_t size() const
     711             :     {
     712      159405 :         return m_nSize;
     713             :     }
     714             : 
     715       21099 :     inline size_t capacity() const
     716             :     {
     717             :         // Not a typo: the capacity of this object is the size
     718             :         // of the underlying std::vector
     719       21099 :         return m_oVec.size();
     720             :     }
     721             : 
     722       88883 :     inline GByte *data()
     723             :     {
     724       88883 :         return m_oVec.data();
     725             :     }
     726             : 
     727       35883 :     inline const GByte *data() const
     728             :     {
     729       35883 :         return m_oVec.data();
     730             :     }
     731             : 
     732         993 :     inline GByte operator[](size_t idx) const
     733             :     {
     734         993 :         return m_oVec[idx];
     735             :     }
     736             : 
     737       53289 :     inline GByte &operator[](size_t idx)
     738             :     {
     739       53289 :         return m_oVec[idx];
     740             :     }
     741             : };
     742             : 
     743             : /************************************************************************/
     744             : /*                             ZarrArray                                */
     745             : /************************************************************************/
     746             : 
     747             : class ZarrArray CPL_NON_FINAL : public GDALPamMDArray
     748             : {
     749             :   protected:
     750             :     std::shared_ptr<ZarrSharedResource> m_poSharedResource;
     751             :     const std::vector<std::shared_ptr<GDALDimension>> m_aoDims;
     752             :     const GDALExtendedDataType m_oType;
     753             :     const std::vector<DtypeElt> m_aoDtypeElts;
     754             :     const std::vector<GUInt64> m_anBlockSize;
     755             :     CPLStringList m_aosStructuralInfo{};
     756             :     CPLJSONObject m_dtype{};
     757             :     GByte *m_pabyNoData = nullptr;
     758             :     std::string m_osDimSeparator{"."};
     759             :     std::string m_osFilename{};
     760             :     size_t m_nTileSize = 0;
     761             :     mutable ZarrByteVectorQuickResize m_abyRawTileData{};
     762             :     mutable ZarrByteVectorQuickResize m_abyDecodedTileData{};
     763             :     mutable std::vector<uint64_t> m_anCachedTiledIndices{};
     764             :     mutable bool m_bCachedTiledValid = false;
     765             :     mutable bool m_bCachedTiledEmpty = false;
     766             :     mutable bool m_bDirtyTile = false;
     767             :     bool m_bUseOptimizedCodePaths = true;
     768             :     mutable ZarrAttributeGroup m_oAttrGroup;
     769             :     mutable std::shared_ptr<OGRSpatialReference> m_poSRS{};
     770             :     mutable bool m_bAllocateWorkingBuffersDone = false;
     771             :     mutable bool m_bWorkingBuffersOK = false;
     772             :     bool m_bUpdatable = false;
     773             :     bool m_bDefinitionModified = false;
     774             :     bool m_bSRSModified = false;
     775             :     bool m_bNew = false;
     776             :     std::string m_osUnit{};
     777             :     bool m_bUnitModified = false;
     778             :     double m_dfOffset = 0.0;
     779             :     bool m_bHasOffset = false;
     780             :     bool m_bOffsetModified = false;
     781             :     double m_dfScale = 1.0;
     782             :     bool m_bHasScale = false;
     783             :     bool m_bScaleModified = false;
     784             :     std::weak_ptr<ZarrGroupBase> m_poGroupWeak{};
     785             :     uint64_t m_nTotalTileCount = 0;
     786             :     mutable bool m_bHasTriedCacheTilePresenceArray = false;
     787             :     mutable std::shared_ptr<GDALMDArray> m_poCacheTilePresenceArray{};
     788             :     mutable std::mutex m_oMutex{};
     789             : 
     790             :     struct CachedTile
     791             :     {
     792             :         ZarrByteVectorQuickResize abyDecoded{};
     793             :     };
     794             : 
     795             :     mutable std::map<uint64_t, CachedTile> m_oMapTileIndexToCachedTile{};
     796             : 
     797             :     static uint64_t
     798             :     ComputeTileCount(const std::string &osName,
     799             :                      const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
     800             :                      const std::vector<GUInt64> &anBlockSize);
     801             : 
     802             :     ZarrArray(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     803             :               const std::string &osParentName, const std::string &osName,
     804             :               const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
     805             :               const GDALExtendedDataType &oType,
     806             :               const std::vector<DtypeElt> &aoDtypeElts,
     807             :               const std::vector<GUInt64> &anBlockSize);
     808             : 
     809             :     virtual bool LoadTileData(const uint64_t *tileIndices,
     810             :                               bool &bMissingTileOut) const = 0;
     811             : 
     812             :     void BlockTranspose(const ZarrByteVectorQuickResize &abySrc,
     813             :                         ZarrByteVectorQuickResize &abyDst, bool bDecode) const;
     814             : 
     815             :     virtual bool AllocateWorkingBuffers() const = 0;
     816             : 
     817             :     void SerializeNumericNoData(CPLJSONObject &oRoot) const;
     818             : 
     819             :     void DeallocateDecodedTileData();
     820             : 
     821             :     virtual std::string GetDataDirectory() const = 0;
     822             : 
     823             :     virtual CPLStringList
     824             :     GetTileIndicesFromFilename(const char *pszFilename) const = 0;
     825             : 
     826             :     virtual bool FlushDirtyTile() const = 0;
     827             : 
     828             :     std::shared_ptr<GDALMDArray> OpenTilePresenceCache(bool bCanCreate) const;
     829             : 
     830             :     void NotifyChildrenOfRenaming() override;
     831             : 
     832             :     void NotifyChildrenOfDeletion() override;
     833             : 
     834             :     static void EncodeElt(const std::vector<DtypeElt> &elts, const GByte *pSrc,
     835             :                           GByte *pDst);
     836             : 
     837             :     // Disable copy constructor and assignment operator
     838             :     ZarrArray(const ZarrArray &) = delete;
     839             :     ZarrArray &operator=(const ZarrArray &) = delete;
     840             : 
     841             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
     842             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
     843             :                const GDALExtendedDataType &bufferDataType,
     844             :                void *pDstBuffer) const override;
     845             : 
     846             :     bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
     847             :                 const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
     848             :                 const GDALExtendedDataType &bufferDataType,
     849             :                 const void *pSrcBuffer) override;
     850             : 
     851             :     bool IsEmptyTile(const ZarrByteVectorQuickResize &abyTile) const;
     852             : 
     853             :     bool IAdviseReadCommon(const GUInt64 *arrayStartIdx, const size_t *count,
     854             :                            CSLConstList papszOptions,
     855             :                            std::vector<uint64_t> &anIndicesCur,
     856             :                            int &nThreadsMax,
     857             :                            std::vector<uint64_t> &anReqTilesIndices,
     858             :                            size_t &nReqTiles) const;
     859             : 
     860             :     CPLJSONObject SerializeSpecialAttributes();
     861             : 
     862             :     virtual std::string
     863             :     BuildTileFilename(const uint64_t *tileIndices) const = 0;
     864             : 
     865             :     bool SetStatistics(bool bApproxStats, double dfMin, double dfMax,
     866             :                        double dfMean, double dfStdDev, GUInt64 nValidCount,
     867             :                        CSLConstList papszOptions) override;
     868             : 
     869             :   public:
     870             :     ~ZarrArray() override;
     871             : 
     872             :     static bool ParseChunkSize(const CPLJSONArray &oChunks,
     873             :                                const GDALExtendedDataType &oType,
     874             :                                std::vector<GUInt64> &anBlockSize);
     875             : 
     876             :     static bool FillBlockSize(
     877             :         const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
     878             :         const GDALExtendedDataType &oDataType,
     879             :         std::vector<GUInt64> &anBlockSize, CSLConstList papszOptions);
     880             : 
     881          97 :     bool IsWritable() const override
     882             :     {
     883          97 :         return m_bUpdatable;
     884             :     }
     885             : 
     886        1911 :     const std::string &GetFilename() const override
     887             :     {
     888        1911 :         return m_osFilename;
     889             :     }
     890             : 
     891             :     const std::vector<std::shared_ptr<GDALDimension>> &
     892       12518 :     GetDimensions() const override
     893             :     {
     894       12518 :         return m_aoDims;
     895             :     }
     896             : 
     897       27443 :     const GDALExtendedDataType &GetDataType() const override
     898             :     {
     899       27443 :         return m_oType;
     900             :     }
     901             : 
     902         523 :     std::vector<GUInt64> GetBlockSize() const override
     903             :     {
     904         523 :         return m_anBlockSize;
     905             :     }
     906             : 
     907          13 :     CSLConstList GetStructuralInfo() const override
     908             :     {
     909          13 :         return m_aosStructuralInfo.List();
     910             :     }
     911             : 
     912       22109 :     const void *GetRawNoDataValue() const override
     913             :     {
     914       22109 :         return m_pabyNoData;
     915             :     }
     916             : 
     917          77 :     const std::string &GetUnit() const override
     918             :     {
     919          77 :         return m_osUnit;
     920             :     }
     921             : 
     922             :     bool SetUnit(const std::string &osUnit) override;
     923             : 
     924          53 :     void RegisterUnit(const std::string &osUnit)
     925             :     {
     926          53 :         m_osUnit = osUnit;
     927          53 :     }
     928             : 
     929        1195 :     void RegisterGroup(const std::weak_ptr<ZarrGroupBase> &group)
     930             :     {
     931        1195 :         m_poGroupWeak = group;
     932        1195 :     }
     933             : 
     934             :     double GetOffset(bool *pbHasOffset,
     935             :                      GDALDataType *peStorageType) const override;
     936             : 
     937             :     double GetScale(bool *pbHasScale,
     938             :                     GDALDataType *peStorageType) const override;
     939             : 
     940             :     bool SetOffset(double dfOffset, GDALDataType eStorageType) override;
     941             : 
     942             :     bool SetScale(double dfScale, GDALDataType eStorageType) override;
     943             : 
     944             :     std::vector<std::shared_ptr<GDALMDArray>>
     945             :     GetCoordinateVariables() const override;
     946             : 
     947             :     bool Resize(const std::vector<GUInt64> &anNewDimSizes,
     948             :                 CSLConstList) override;
     949             : 
     950           3 :     void RegisterOffset(double dfOffset)
     951             :     {
     952           3 :         m_bHasOffset = true;
     953           3 :         m_dfOffset = dfOffset;
     954           3 :     }
     955             : 
     956           3 :     void RegisterScale(double dfScale)
     957             :     {
     958           3 :         m_bHasScale = true;
     959           3 :         m_dfScale = dfScale;
     960           3 :     }
     961             : 
     962             :     bool SetRawNoDataValue(const void *pRawNoData) override;
     963             : 
     964             :     void RegisterNoDataValue(const void *);
     965             : 
     966        1195 :     void SetFilename(const std::string &osFilename)
     967             :     {
     968        1195 :         m_osFilename = osFilename;
     969        1195 :     }
     970             : 
     971        1195 :     void SetDimSeparator(const std::string &osDimSeparator)
     972             :     {
     973        1195 :         m_osDimSeparator = osDimSeparator;
     974        1195 :     }
     975             : 
     976             :     void ParseSpecialAttributes(const std::shared_ptr<GDALGroup> &poGroup,
     977             :                                 CPLJSONObject &oAttributes);
     978             : 
     979         769 :     void SetAttributes(const CPLJSONObject &attrs)
     980             :     {
     981         769 :         m_oAttrGroup.Init(attrs, m_bUpdatable);
     982         769 :     }
     983             : 
     984          27 :     void SetSRS(const std::shared_ptr<OGRSpatialReference> &srs)
     985             :     {
     986          27 :         m_poSRS = srs;
     987          27 :     }
     988             : 
     989             :     std::shared_ptr<GDALAttribute>
     990          64 :     GetAttribute(const std::string &osName) const override
     991             :     {
     992          64 :         return m_oAttrGroup.GetAttribute(osName);
     993             :     }
     994             : 
     995             :     std::vector<std::shared_ptr<GDALAttribute>>
     996         117 :     GetAttributes(CSLConstList papszOptions) const override
     997             :     {
     998         117 :         return m_oAttrGroup.GetAttributes(papszOptions);
     999             :     }
    1000             : 
    1001             :     std::shared_ptr<GDALAttribute>
    1002             :     CreateAttribute(const std::string &osName,
    1003             :                     const std::vector<GUInt64> &anDimensions,
    1004             :                     const GDALExtendedDataType &oDataType,
    1005             :                     CSLConstList papszOptions = nullptr) override;
    1006             : 
    1007             :     bool DeleteAttribute(const std::string &osName,
    1008             :                          CSLConstList papszOptions = nullptr) override;
    1009             : 
    1010             :     std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override;
    1011             : 
    1012             :     bool SetSpatialRef(const OGRSpatialReference *poSRS) override;
    1013             : 
    1014        1195 :     void SetUpdatable(bool bUpdatable)
    1015             :     {
    1016        1195 :         m_bUpdatable = bUpdatable;
    1017        1195 :     }
    1018             : 
    1019        1195 :     void SetDtype(const CPLJSONObject &dtype)
    1020             :     {
    1021        1195 :         m_dtype = dtype;
    1022        1195 :     }
    1023             : 
    1024         441 :     void SetDefinitionModified(bool bModified)
    1025             :     {
    1026         441 :         m_bDefinitionModified = bModified;
    1027         441 :     }
    1028             : 
    1029         426 :     void SetNew(bool bNew)
    1030             :     {
    1031         426 :         m_bNew = bNew;
    1032         426 :     }
    1033             : 
    1034             :     bool Rename(const std::string &osNewName) override;
    1035             : 
    1036             :     void ParentRenamed(const std::string &osNewParentFullName) override;
    1037             : 
    1038             :     virtual void Flush() = 0;
    1039             : 
    1040           0 :     std::shared_ptr<GDALGroup> GetRootGroup() const override
    1041             :     {
    1042           0 :         return m_poSharedResource->GetRootGroup();
    1043             :     }
    1044             : 
    1045             :     bool CacheTilePresence();
    1046             : 
    1047          55 :     void SetStructuralInfo(const char *pszKey, const char *pszValue)
    1048             :     {
    1049          55 :         m_aosStructuralInfo.SetNameValue(pszKey, pszValue);
    1050          55 :     }
    1051             : 
    1052             :     static void DecodeSourceElt(const std::vector<DtypeElt> &elts,
    1053             :                                 const GByte *pSrc, GByte *pDst);
    1054             : 
    1055             :     static void GetDimensionTypeDirection(CPLJSONObject &oAttributes,
    1056             :                                           std::string &osType,
    1057             :                                           std::string &osDirection);
    1058             : };
    1059             : 
    1060             : /************************************************************************/
    1061             : /*                           ZarrV2Array                                */
    1062             : /************************************************************************/
    1063             : 
    1064             : class ZarrV2Array final : public ZarrArray
    1065             : {
    1066             :     CPLJSONObject m_oCompressorJSon{};
    1067             :     const CPLCompressor *m_psCompressor = nullptr;
    1068             :     std::string m_osDecompressorId{};
    1069             :     const CPLCompressor *m_psDecompressor = nullptr;
    1070             :     CPLJSONArray m_oFiltersArray{};  // ZarrV2 specific
    1071             :     bool m_bFortranOrder = false;
    1072             :     mutable ZarrByteVectorQuickResize
    1073             :         m_abyTmpRawTileData{};  // used for Fortran order
    1074             : 
    1075             :     ZarrV2Array(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
    1076             :                 const std::string &osParentName, const std::string &osName,
    1077             :                 const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
    1078             :                 const GDALExtendedDataType &oType,
    1079             :                 const std::vector<DtypeElt> &aoDtypeElts,
    1080             :                 const std::vector<GUInt64> &anBlockSize, bool bFortranOrder);
    1081             : 
    1082             :     void Serialize();
    1083             : 
    1084             :     bool LoadTileData(const uint64_t *tileIndices, bool bUseMutex,
    1085             :                       const CPLCompressor *psDecompressor,
    1086             :                       ZarrByteVectorQuickResize &abyRawTileData,
    1087             :                       ZarrByteVectorQuickResize &abyTmpRawTileData,
    1088             :                       ZarrByteVectorQuickResize &abyDecodedTileData,
    1089             :                       bool &bMissingTileOut) const;
    1090             : 
    1091             :     bool NeedDecodedBuffer() const;
    1092             : 
    1093             :     bool
    1094             :     AllocateWorkingBuffers(ZarrByteVectorQuickResize &abyRawTileData,
    1095             :                            ZarrByteVectorQuickResize &abyTmpRawTileData,
    1096             :                            ZarrByteVectorQuickResize &abyDecodedTileData) const;
    1097             : 
    1098             :     // Disable copy constructor and assignment operator
    1099             :     ZarrV2Array(const ZarrV2Array &) = delete;
    1100             :     ZarrV2Array &operator=(const ZarrV2Array &) = delete;
    1101             : 
    1102             :   public:
    1103             :     ~ZarrV2Array() override;
    1104             : 
    1105             :     static std::shared_ptr<ZarrV2Array>
    1106             :     Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
    1107             :            const std::string &osParentName, const std::string &osName,
    1108             :            const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
    1109             :            const GDALExtendedDataType &oType,
    1110             :            const std::vector<DtypeElt> &aoDtypeElts,
    1111             :            const std::vector<GUInt64> &anBlockSize, bool bFortranOrder);
    1112             : 
    1113             :     void SetCompressorJson(const CPLJSONObject &oCompressor);
    1114             : 
    1115         913 :     void SetCompressorDecompressor(const std::string &osDecompressorId,
    1116             :                                    const CPLCompressor *psComp,
    1117             :                                    const CPLCompressor *psDecomp)
    1118             :     {
    1119         913 :         m_psCompressor = psComp;
    1120         913 :         m_osDecompressorId = osDecompressorId;
    1121         913 :         m_psDecompressor = psDecomp;
    1122         913 :     }
    1123             : 
    1124             :     void SetFilters(const CPLJSONArray &oFiltersArray);
    1125             : 
    1126             :     void Flush() override;
    1127             : 
    1128             :   protected:
    1129             :     std::string GetDataDirectory() const override;
    1130             : 
    1131             :     CPLStringList
    1132             :     GetTileIndicesFromFilename(const char *pszFilename) const override;
    1133             : 
    1134             :     bool FlushDirtyTile() const override;
    1135             : 
    1136             :     std::string BuildTileFilename(const uint64_t *tileIndices) const override;
    1137             : 
    1138             :     bool AllocateWorkingBuffers() const override;
    1139             : 
    1140             :     bool LoadTileData(const uint64_t *tileIndices,
    1141             :                       bool &bMissingTileOut) const override;
    1142             : 
    1143             :     bool IAdviseRead(const GUInt64 *arrayStartIdx, const size_t *count,
    1144             :                      CSLConstList papszOptions) const override;
    1145             : };
    1146             : 
    1147             : /************************************************************************/
    1148             : /*                        ZarrArrayMetadata                             */
    1149             : /************************************************************************/
    1150             : 
    1151             : struct ZarrArrayMetadata
    1152             : {
    1153             :     DtypeElt oElt{};
    1154             :     std::vector<size_t> anBlockSizes{};
    1155             : 
    1156       10833 :     size_t GetEltCount() const
    1157             :     {
    1158       10833 :         size_t n = 1;
    1159       32121 :         for (auto i : anBlockSizes)
    1160       21260 :             n *= i;
    1161       10667 :         return n;
    1162             :     }
    1163             : };
    1164             : 
    1165             : /************************************************************************/
    1166             : /*                            ZarrV3Codec                               */
    1167             : /************************************************************************/
    1168             : 
    1169         396 : class ZarrV3Codec CPL_NON_FINAL
    1170             : {
    1171             :   protected:
    1172             :     const std::string m_osName;
    1173             :     CPLJSONObject m_oConfiguration{};
    1174             :     ZarrArrayMetadata m_oInputArrayMetadata{};
    1175             : 
    1176             :     ZarrV3Codec(const std::string &osName);
    1177             : 
    1178             :   public:
    1179             :     virtual ~ZarrV3Codec() = 0;
    1180             : 
    1181             :     enum class IOType
    1182             :     {
    1183             :         BYTES,
    1184             :         ARRAY
    1185             :     };
    1186             : 
    1187             :     virtual IOType GetInputType() const = 0;
    1188             :     virtual IOType GetOutputType() const = 0;
    1189             : 
    1190             :     virtual bool
    1191             :     InitFromConfiguration(const CPLJSONObject &configuration,
    1192             :                           const ZarrArrayMetadata &oInputArrayMetadata,
    1193             :                           ZarrArrayMetadata &oOutputArrayMetadata) = 0;
    1194             : 
    1195             :     virtual std::unique_ptr<ZarrV3Codec> Clone() const = 0;
    1196             : 
    1197          55 :     virtual bool IsNoOp() const
    1198             :     {
    1199          55 :         return false;
    1200             :     }
    1201             : 
    1202             :     virtual bool Encode(const ZarrByteVectorQuickResize &abySrc,
    1203             :                         ZarrByteVectorQuickResize &abyDst) const = 0;
    1204             :     virtual bool Decode(const ZarrByteVectorQuickResize &abySrc,
    1205             :                         ZarrByteVectorQuickResize &abyDst) const = 0;
    1206             : 
    1207         388 :     const std::string &GetName() const
    1208             :     {
    1209         388 :         return m_osName;
    1210             :     }
    1211             : 
    1212             :     const CPLJSONObject &GetConfiguration() const
    1213             :     {
    1214             :         return m_oConfiguration;
    1215             :     }
    1216             : };
    1217             : 
    1218             : /************************************************************************/
    1219             : /*                      ZarrV3CodecAbstractCompressor                   */
    1220             : /************************************************************************/
    1221             : 
    1222             : class ZarrV3CodecAbstractCompressor CPL_NON_FINAL : public ZarrV3Codec
    1223             : {
    1224             :   protected:
    1225             :     CPLStringList m_aosCompressorOptions{};
    1226             :     const CPLCompressor *m_pDecompressor = nullptr;
    1227             :     const CPLCompressor *m_pCompressor = nullptr;
    1228             : 
    1229             :     explicit ZarrV3CodecAbstractCompressor(const std::string &osName);
    1230             : 
    1231             :     ZarrV3CodecAbstractCompressor(const ZarrV3CodecAbstractCompressor &) =
    1232             :         delete;
    1233             :     ZarrV3CodecAbstractCompressor &
    1234             :     operator=(const ZarrV3CodecAbstractCompressor &) = delete;
    1235             : 
    1236             :   public:
    1237          55 :     IOType GetInputType() const override
    1238             :     {
    1239          55 :         return IOType::BYTES;
    1240             :     }
    1241             : 
    1242          55 :     IOType GetOutputType() const override
    1243             :     {
    1244          55 :         return IOType::BYTES;
    1245             :     }
    1246             : 
    1247             :     bool Encode(const ZarrByteVectorQuickResize &abySrc,
    1248             :                 ZarrByteVectorQuickResize &abyDst) const override;
    1249             :     bool Decode(const ZarrByteVectorQuickResize &abySrc,
    1250             :                 ZarrByteVectorQuickResize &abyDst) const override;
    1251             : };
    1252             : 
    1253             : /************************************************************************/
    1254             : /*                           ZarrV3CodecGZip                            */
    1255             : /************************************************************************/
    1256             : 
    1257             : // Implements https://zarr-specs.readthedocs.io/en/latest/v3/codecs/gzip/v1.0.html
    1258             : class ZarrV3CodecGZip final : public ZarrV3CodecAbstractCompressor
    1259             : {
    1260             :   public:
    1261             :     static constexpr const char *NAME = "gzip";
    1262             : 
    1263             :     ZarrV3CodecGZip();
    1264             : 
    1265             :     static CPLJSONObject GetConfiguration(int nLevel);
    1266             : 
    1267             :     bool
    1268             :     InitFromConfiguration(const CPLJSONObject &configuration,
    1269             :                           const ZarrArrayMetadata &oInputArrayMetadata,
    1270             :                           ZarrArrayMetadata &oOutputArrayMetadata) override;
    1271             : 
    1272             :     std::unique_ptr<ZarrV3Codec> Clone() const override;
    1273             : };
    1274             : 
    1275             : /************************************************************************/
    1276             : /*                          ZarrV3CodecBlosc                            */
    1277             : /************************************************************************/
    1278             : 
    1279             : // Implements https://zarr-specs.readthedocs.io/en/latest/v3/codecs/blosc/v1.0.html
    1280             : class ZarrV3CodecBlosc final : public ZarrV3CodecAbstractCompressor
    1281             : {
    1282             :   public:
    1283             :     static constexpr const char *NAME = "blosc";
    1284             : 
    1285             :     ZarrV3CodecBlosc();
    1286             : 
    1287             :     static CPLJSONObject GetConfiguration(const char *cname, int clevel,
    1288             :                                           const char *shuffle, int typesize,
    1289             :                                           int blocksize);
    1290             : 
    1291             :     bool
    1292             :     InitFromConfiguration(const CPLJSONObject &configuration,
    1293             :                           const ZarrArrayMetadata &oInputArrayMetadata,
    1294             :                           ZarrArrayMetadata &oOutputArrayMetadata) override;
    1295             : 
    1296             :     std::unique_ptr<ZarrV3Codec> Clone() const override;
    1297             : };
    1298             : 
    1299             : /************************************************************************/
    1300             : /*                          ZarrV3CodecZstd                             */
    1301             : /************************************************************************/
    1302             : 
    1303             : // Implements https://github.com/zarr-developers/zarr-specs/pull/256
    1304             : class ZarrV3CodecZstd final : public ZarrV3CodecAbstractCompressor
    1305             : {
    1306             :   public:
    1307             :     static constexpr const char *NAME = "zstd";
    1308             : 
    1309             :     ZarrV3CodecZstd();
    1310             : 
    1311             :     static CPLJSONObject GetConfiguration(int level, bool checksum);
    1312             : 
    1313             :     bool
    1314             :     InitFromConfiguration(const CPLJSONObject &configuration,
    1315             :                           const ZarrArrayMetadata &oInputArrayMetadata,
    1316             :                           ZarrArrayMetadata &oOutputArrayMetadata) override;
    1317             : 
    1318             :     std::unique_ptr<ZarrV3Codec> Clone() const override;
    1319             : };
    1320             : 
    1321             : /************************************************************************/
    1322             : /*                           ZarrV3CodecBytes                           */
    1323             : /************************************************************************/
    1324             : 
    1325             : // Implements https://zarr-specs.readthedocs.io/en/latest/v3/codecs/bytes/v1.0.html
    1326             : class ZarrV3CodecBytes final : public ZarrV3Codec
    1327             : {
    1328             :     bool m_bLittle = true;
    1329             : 
    1330             :   public:
    1331             :     static constexpr const char *NAME = "bytes";
    1332             : 
    1333             :     ZarrV3CodecBytes();
    1334             : 
    1335         253 :     IOType GetInputType() const override
    1336             :     {
    1337         253 :         return IOType::ARRAY;
    1338             :     }
    1339             : 
    1340         253 :     IOType GetOutputType() const override
    1341             :     {
    1342         253 :         return IOType::BYTES;
    1343             :     }
    1344             : 
    1345             :     static CPLJSONObject GetConfiguration(bool bLittle);
    1346             : 
    1347             :     bool
    1348             :     InitFromConfiguration(const CPLJSONObject &configuration,
    1349             :                           const ZarrArrayMetadata &oInputArrayMetadata,
    1350             :                           ZarrArrayMetadata &oOutputArrayMetadata) override;
    1351             : 
    1352             : #if CPL_IS_LSB
    1353         301 :     bool IsNoOp() const override
    1354             :     {
    1355         301 :         return m_oInputArrayMetadata.oElt.nativeSize == 1 || m_bLittle;
    1356             :     }
    1357             : #else
    1358             :     bool IsNoOp() const override
    1359             :     {
    1360             :         return m_oInputArrayMetadata.oElt.nativeSize == 1 || !m_bLittle;
    1361             :     }
    1362             : #endif
    1363             : 
    1364             :     std::unique_ptr<ZarrV3Codec> Clone() const override;
    1365             : 
    1366             :     bool Encode(const ZarrByteVectorQuickResize &abySrc,
    1367             :                 ZarrByteVectorQuickResize &abyDst) const override;
    1368             :     bool Decode(const ZarrByteVectorQuickResize &abySrc,
    1369             :                 ZarrByteVectorQuickResize &abyDst) const override;
    1370             : };
    1371             : 
    1372             : /************************************************************************/
    1373             : /*                         ZarrV3CodecTranspose                         */
    1374             : /************************************************************************/
    1375             : 
    1376             : // Implements https://zarr-specs.readthedocs.io/en/latest/v3/codecs/transpose/v1.0.html
    1377             : class ZarrV3CodecTranspose final : public ZarrV3Codec
    1378             : {
    1379             :     // m_anOrder is such that dest_shape[i] = source_shape[m_anOrder[i]]
    1380             :     // where source_shape[] is the size of the array before the Encode() operation
    1381             :     // and dest_shape[] its size after.
    1382             :     // m_anOrder[] describes a bijection of [0,N-1] to [0,N-1]
    1383             :     std::vector<int> m_anOrder{};
    1384             : 
    1385             :     // m_anReverseOrder is such that m_anReverseOrder[m_anOrder[i]] = i
    1386             :     std::vector<int> m_anReverseOrder{};
    1387             : 
    1388             :     bool Transpose(const ZarrByteVectorQuickResize &abySrc,
    1389             :                    ZarrByteVectorQuickResize &abyDst,
    1390             :                    bool bEncodeDirection) const;
    1391             : 
    1392             :   public:
    1393             :     static constexpr const char *NAME = "transpose";
    1394             : 
    1395             :     ZarrV3CodecTranspose();
    1396             : 
    1397          80 :     IOType GetInputType() const override
    1398             :     {
    1399          80 :         return IOType::ARRAY;
    1400             :     }
    1401             : 
    1402          80 :     IOType GetOutputType() const override
    1403             :     {
    1404          80 :         return IOType::ARRAY;
    1405             :     }
    1406             : 
    1407             :     static CPLJSONObject GetConfiguration(const std::vector<int> &anOrder);
    1408             :     static CPLJSONObject GetConfiguration(const std::string &osOrder);
    1409             : 
    1410             :     bool
    1411             :     InitFromConfiguration(const CPLJSONObject &configuration,
    1412             :                           const ZarrArrayMetadata &oInputArrayMetadata,
    1413             :                           ZarrArrayMetadata &oOutputArrayMetadata) override;
    1414             : 
    1415             :     bool IsNoOp() const override;
    1416             : 
    1417             :     std::unique_ptr<ZarrV3Codec> Clone() const override;
    1418             : 
    1419             :     bool Encode(const ZarrByteVectorQuickResize &abySrc,
    1420             :                 ZarrByteVectorQuickResize &abyDst) const override;
    1421             :     bool Decode(const ZarrByteVectorQuickResize &abySrc,
    1422             :                 ZarrByteVectorQuickResize &abyDst) const override;
    1423             : };
    1424             : 
    1425             : /************************************************************************/
    1426             : /*                          ZarrV3CodecSequence                         */
    1427             : /************************************************************************/
    1428             : 
    1429             : class ZarrV3CodecSequence
    1430             : {
    1431             :     const ZarrArrayMetadata m_oInputArrayMetadata;
    1432             :     std::vector<std::unique_ptr<ZarrV3Codec>> m_apoCodecs{};
    1433             :     CPLJSONObject m_oCodecArray{};
    1434             :     ZarrByteVectorQuickResize m_abyTmp{};
    1435             : 
    1436             :     bool AllocateBuffer(ZarrByteVectorQuickResize &abyBuffer);
    1437             : 
    1438             :   public:
    1439         269 :     explicit ZarrV3CodecSequence(const ZarrArrayMetadata &oInputArrayMetadata)
    1440         269 :         : m_oInputArrayMetadata(oInputArrayMetadata)
    1441             :     {
    1442         269 :     }
    1443             : 
    1444             :     // This method is not thread safe due to cloning a JSON object
    1445             :     std::unique_ptr<ZarrV3CodecSequence> Clone() const;
    1446             : 
    1447             :     bool InitFromJson(const CPLJSONObject &oCodecs);
    1448             : 
    1449         155 :     const CPLJSONObject &GetJSon() const
    1450             :     {
    1451         155 :         return m_oCodecArray;
    1452             :     }
    1453             : 
    1454             :     bool Encode(ZarrByteVectorQuickResize &abyBuffer);
    1455             :     bool Decode(ZarrByteVectorQuickResize &abyBuffer);
    1456             : };
    1457             : 
    1458             : /************************************************************************/
    1459             : /*                           ZarrV3Array                                */
    1460             : /************************************************************************/
    1461             : 
    1462             : class ZarrV3Array final : public ZarrArray
    1463             : {
    1464             :     bool m_bV2ChunkKeyEncoding = false;
    1465             :     std::unique_ptr<ZarrV3CodecSequence> m_poCodecs{};
    1466             : 
    1467             :     ZarrV3Array(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
    1468             :                 const std::string &osParentName, const std::string &osName,
    1469             :                 const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
    1470             :                 const GDALExtendedDataType &oType,
    1471             :                 const std::vector<DtypeElt> &aoDtypeElts,
    1472             :                 const std::vector<GUInt64> &anBlockSize);
    1473             : 
    1474             :     void Serialize(const CPLJSONObject &oAttrs);
    1475             : 
    1476             :     bool NeedDecodedBuffer() const;
    1477             : 
    1478             :     bool
    1479             :     AllocateWorkingBuffers(ZarrByteVectorQuickResize &abyRawTileData,
    1480             :                            ZarrByteVectorQuickResize &abyDecodedTileData) const;
    1481             : 
    1482             :     bool LoadTileData(const uint64_t *tileIndices, bool bUseMutex,
    1483             :                       ZarrV3CodecSequence *poCodecs,
    1484             :                       ZarrByteVectorQuickResize &abyRawTileData,
    1485             :                       ZarrByteVectorQuickResize &abyDecodedTileData,
    1486             :                       bool &bMissingTileOut) const;
    1487             : 
    1488             :   public:
    1489             :     ~ZarrV3Array() override;
    1490             : 
    1491             :     static std::shared_ptr<ZarrV3Array>
    1492             :     Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
    1493             :            const std::string &osParentName, const std::string &osName,
    1494             :            const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
    1495             :            const GDALExtendedDataType &oType,
    1496             :            const std::vector<DtypeElt> &aoDtypeElts,
    1497             :            const std::vector<GUInt64> &anBlockSize);
    1498             : 
    1499         161 :     void SetIsV2ChunkKeyEncoding(bool b)
    1500             :     {
    1501         161 :         m_bV2ChunkKeyEncoding = b;
    1502         161 :     }
    1503             : 
    1504         253 :     void SetCodecs(std::unique_ptr<ZarrV3CodecSequence> &&poCodecs)
    1505             :     {
    1506         253 :         m_poCodecs = std::move(poCodecs);
    1507         253 :     }
    1508             : 
    1509             :     void Flush() override;
    1510             : 
    1511             :   protected:
    1512             :     std::string GetDataDirectory() const override;
    1513             : 
    1514             :     CPLStringList
    1515             :     GetTileIndicesFromFilename(const char *pszFilename) const override;
    1516             : 
    1517             :     bool AllocateWorkingBuffers() const override;
    1518             : 
    1519             :     bool FlushDirtyTile() const override;
    1520             : 
    1521             :     std::string BuildTileFilename(const uint64_t *tileIndices) const override;
    1522             : 
    1523             :     bool LoadTileData(const uint64_t *tileIndices,
    1524             :                       bool &bMissingTileOut) const override;
    1525             : 
    1526             :     bool IAdviseRead(const GUInt64 *arrayStartIdx, const size_t *count,
    1527             :                      CSLConstList papszOptions) const override;
    1528             : };
    1529             : 
    1530             : #endif  // ZARR_H

Generated by: LCOV version 1.14