LCOV - code coverage report
Current view: top level - frmts/zarr - zarr.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 241 244 98.8 %
Date: 2025-10-22 21:46:17 Functions: 84 86 97.7 %

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

Generated by: LCOV version 1.14