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

Generated by: LCOV version 1.14