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

Generated by: LCOV version 1.14