LCOV - code coverage report
Current view: top level - frmts/zarr - zarr.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 241 241 100.0 %
Date: 2026-07-24 18:27:47 Functions: 85 85 100.0 %

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

Generated by: LCOV version 1.14