LCOV - code coverage report
Current view: top level - frmts/zarr - zarr.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 245 248 98.8 %
Date: 2024-05-13 13:33:37 Functions: 92 94 97.9 %

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

Generated by: LCOV version 1.14