LCOV - code coverage report
Current view: top level - frmts/zarr - zarr_v3_codec.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 339 468 72.4 %
Date: 2024-05-13 13:33:37 Functions: 29 33 87.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) 2023, 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             : #include "zarr.h"
      30             : 
      31             : #include "cpl_compressor.h"
      32             : 
      33             : /************************************************************************/
      34             : /*                          ZarrV3Codec()                               */
      35             : /************************************************************************/
      36             : 
      37         238 : ZarrV3Codec::ZarrV3Codec(const std::string &osName) : m_osName(osName)
      38             : {
      39         238 : }
      40             : 
      41             : /************************************************************************/
      42             : /*                         ~ZarrV3Codec()                               */
      43             : /************************************************************************/
      44             : 
      45             : ZarrV3Codec::~ZarrV3Codec() = default;
      46             : 
      47             : /************************************************************************/
      48             : /*                        ZarrV3CodecGZip()                             */
      49             : /************************************************************************/
      50             : 
      51          54 : ZarrV3CodecGZip::ZarrV3CodecGZip() : ZarrV3Codec(NAME)
      52             : {
      53          54 : }
      54             : 
      55             : /************************************************************************/
      56             : /*                       ~ZarrV3CodecGZip()                             */
      57             : /************************************************************************/
      58             : 
      59             : ZarrV3CodecGZip::~ZarrV3CodecGZip() = default;
      60             : 
      61             : /************************************************************************/
      62             : /*                           GetConfiguration()                         */
      63             : /************************************************************************/
      64             : 
      65          23 : /* static */ CPLJSONObject ZarrV3CodecGZip::GetConfiguration(int nLevel)
      66             : {
      67          23 :     CPLJSONObject oConfig;
      68          23 :     oConfig.Add("level", nLevel);
      69          23 :     return oConfig;
      70             : }
      71             : 
      72             : /************************************************************************/
      73             : /*                   ZarrV3CodecGZip::InitFromConfiguration()           */
      74             : /************************************************************************/
      75             : 
      76          54 : bool ZarrV3CodecGZip::InitFromConfiguration(
      77             :     const CPLJSONObject &configuration,
      78             :     const ZarrArrayMetadata &oInputArrayMetadata,
      79             :     ZarrArrayMetadata &oOutputArrayMetadata)
      80             : {
      81          54 :     m_pCompressor = CPLGetCompressor("gzip");
      82          54 :     m_pDecompressor = CPLGetDecompressor("gzip");
      83          54 :     if (!m_pCompressor || !m_pDecompressor)
      84             :     {
      85           0 :         CPLError(CE_Failure, CPLE_AppDefined, "gzip compressor not available");
      86           0 :         return false;
      87             :     }
      88             : 
      89          54 :     m_oConfiguration = configuration.Clone();
      90          54 :     m_oInputArrayMetadata = oInputArrayMetadata;
      91             :     // byte->byte codec
      92          54 :     oOutputArrayMetadata = oInputArrayMetadata;
      93             : 
      94          54 :     int nLevel = 6;
      95             : 
      96          54 :     if (configuration.IsValid())
      97             :     {
      98          54 :         if (configuration.GetType() != CPLJSONObject::Type::Object)
      99             :         {
     100           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     101             :                      "Codec gzip: configuration is not an object");
     102           0 :             return false;
     103             :         }
     104             : 
     105         108 :         for (const auto &oChild : configuration.GetChildren())
     106             :         {
     107          54 :             if (oChild.GetName() != "level")
     108             :             {
     109           0 :                 CPLError(
     110             :                     CE_Failure, CPLE_AppDefined,
     111             :                     "Codec gzip: configuration contains a unhandled member: %s",
     112           0 :                     oChild.GetName().c_str());
     113           0 :                 return false;
     114             :             }
     115             :         }
     116             : 
     117         108 :         const auto oLevel = configuration.GetObj("level");
     118          54 :         if (oLevel.IsValid())
     119             :         {
     120          54 :             if (oLevel.GetType() != CPLJSONObject::Type::Integer)
     121             :             {
     122           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     123             :                          "Codec gzip: level is not an integer");
     124           0 :                 return false;
     125             :             }
     126          54 :             nLevel = oLevel.ToInteger();
     127          54 :             if (nLevel < 0 || nLevel > 9)
     128             :             {
     129           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     130             :                          "Codec gzip: invalid value for level: %d", nLevel);
     131           0 :                 return false;
     132             :             }
     133             :         }
     134             :     }
     135             : 
     136          54 :     m_aosCompressorOptions.SetNameValue("LEVEL", CPLSPrintf("%d", nLevel));
     137             : 
     138          54 :     return true;
     139             : }
     140             : 
     141             : /************************************************************************/
     142             : /*                      ZarrV3CodecGZip::Clone()                        */
     143             : /************************************************************************/
     144             : 
     145           8 : std::unique_ptr<ZarrV3Codec> ZarrV3CodecGZip::Clone() const
     146             : {
     147          16 :     auto psClone = std::make_unique<ZarrV3CodecGZip>();
     148          16 :     ZarrArrayMetadata oOutputArrayMetadata;
     149           8 :     psClone->InitFromConfiguration(m_oConfiguration, m_oInputArrayMetadata,
     150             :                                    oOutputArrayMetadata);
     151          16 :     return psClone;
     152             : }
     153             : 
     154             : /************************************************************************/
     155             : /*                      ZarrV3CodecGZip::Encode()                       */
     156             : /************************************************************************/
     157             : 
     158        5363 : bool ZarrV3CodecGZip::Encode(const ZarrByteVectorQuickResize &abySrc,
     159             :                              ZarrByteVectorQuickResize &abyDst) const
     160             : {
     161        5363 :     abyDst.resize(abyDst.capacity());
     162        5363 :     void *pOutputData = abyDst.data();
     163        5363 :     size_t nOutputSize = abyDst.size();
     164       10726 :     bool bRet = m_pCompressor->pfnFunc(
     165        5363 :         abySrc.data(), abySrc.size(), &pOutputData, &nOutputSize,
     166        5363 :         m_aosCompressorOptions.List(), m_pCompressor->user_data);
     167        5363 :     if (bRet)
     168             :     {
     169        5363 :         abyDst.resize(nOutputSize);
     170             :     }
     171           0 :     else if (nOutputSize > abyDst.size())
     172             :     {
     173           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     174             :                  "ZarrV3CodecGZip::Encode(): output buffer too small");
     175             :     }
     176        5363 :     return bRet;
     177             : }
     178             : 
     179             : /************************************************************************/
     180             : /*                      ZarrV3CodecGZip::Decode()                       */
     181             : /************************************************************************/
     182             : 
     183        5206 : bool ZarrV3CodecGZip::Decode(const ZarrByteVectorQuickResize &abySrc,
     184             :                              ZarrByteVectorQuickResize &abyDst) const
     185             : {
     186        5206 :     abyDst.resize(abyDst.capacity());
     187        5112 :     void *pOutputData = abyDst.data();
     188        4999 :     size_t nOutputSize = abyDst.size();
     189        5124 :     bool bRet = m_pDecompressor->pfnFunc(abySrc.data(), abySrc.size(),
     190             :                                          &pOutputData, &nOutputSize, nullptr,
     191        4952 :                                          m_pDecompressor->user_data);
     192        5208 :     if (bRet)
     193             :     {
     194        5208 :         abyDst.resize(nOutputSize);
     195             :     }
     196           0 :     else if (nOutputSize > abyDst.size())
     197             :     {
     198           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     199             :                  "ZarrV3CodecGZip::Decode(): output buffer too small");
     200             :     }
     201        5105 :     return bRet;
     202             : }
     203             : 
     204             : /************************************************************************/
     205             : /*                       ZarrV3CodecBlosc()                             */
     206             : /************************************************************************/
     207             : 
     208           4 : ZarrV3CodecBlosc::ZarrV3CodecBlosc() : ZarrV3Codec(NAME)
     209             : {
     210           4 : }
     211             : 
     212             : /************************************************************************/
     213             : /*                      ~ZarrV3CodecBlosc()                             */
     214             : /************************************************************************/
     215             : 
     216             : ZarrV3CodecBlosc::~ZarrV3CodecBlosc() = default;
     217             : 
     218             : /************************************************************************/
     219             : /*                           GetConfiguration()                         */
     220             : /************************************************************************/
     221             : 
     222             : /* static */ CPLJSONObject
     223           2 : ZarrV3CodecBlosc::GetConfiguration(const char *cname, int clevel,
     224             :                                    const char *shuffle, int typesize,
     225             :                                    int blocksize)
     226             : {
     227           2 :     CPLJSONObject oConfig;
     228           2 :     oConfig.Add("cname", cname);
     229           2 :     oConfig.Add("clevel", clevel);
     230           2 :     oConfig.Add("shuffle", shuffle);
     231           2 :     if (strcmp(shuffle, "noshuffle") != 0)
     232           1 :         oConfig.Add("typesize", typesize);
     233           2 :     oConfig.Add("blocksize", blocksize);
     234           2 :     return oConfig;
     235             : }
     236             : 
     237             : /************************************************************************/
     238             : /*                   ZarrV3CodecBlosc::InitFromConfiguration()           */
     239             : /************************************************************************/
     240             : 
     241           4 : bool ZarrV3CodecBlosc::InitFromConfiguration(
     242             :     const CPLJSONObject &configuration,
     243             :     const ZarrArrayMetadata &oInputArrayMetadata,
     244             :     ZarrArrayMetadata &oOutputArrayMetadata)
     245             : {
     246           4 :     m_pCompressor = CPLGetCompressor("blosc");
     247           4 :     m_pDecompressor = CPLGetDecompressor("blosc");
     248           4 :     if (!m_pCompressor || !m_pDecompressor)
     249             :     {
     250           0 :         CPLError(CE_Failure, CPLE_AppDefined, "blosc compressor not available");
     251           0 :         return false;
     252             :     }
     253             : 
     254           4 :     m_oConfiguration = configuration.Clone();
     255           4 :     m_oInputArrayMetadata = oInputArrayMetadata;
     256             :     // byte->byte codec
     257           4 :     oOutputArrayMetadata = oInputArrayMetadata;
     258             : 
     259           8 :     if (!configuration.IsValid() ||
     260           4 :         configuration.GetType() != CPLJSONObject::Type::Object)
     261             :     {
     262           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     263             :                  "Codec blosc: configuration missing or not an object");
     264           0 :         return false;
     265             :     }
     266             : 
     267          22 :     for (const auto &oChild : configuration.GetChildren())
     268             :     {
     269          18 :         const auto osName = oChild.GetName();
     270          32 :         if (osName != "cname" && osName != "clevel" && osName != "shuffle" &&
     271          32 :             osName != "typesize" && osName != "blocksize")
     272             :         {
     273           0 :             CPLError(
     274             :                 CE_Failure, CPLE_AppDefined,
     275             :                 "Codec blosc: configuration contains a unhandled member: %s",
     276             :                 osName.c_str());
     277           0 :             return false;
     278             :         }
     279             :     }
     280             : 
     281          12 :     const auto oCname = configuration.GetObj("cname");
     282           4 :     if (oCname.GetType() != CPLJSONObject::Type::String)
     283             :     {
     284           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     285             :                  "Codec blosc: cname is missing or not a string");
     286           0 :         return false;
     287             :     }
     288           4 :     m_aosCompressorOptions.SetNameValue("CNAME", oCname.ToString().c_str());
     289             : 
     290          12 :     const auto oLevel = configuration.GetObj("clevel");
     291           4 :     if (oLevel.IsValid())
     292             :     {
     293           4 :         if (oLevel.GetType() != CPLJSONObject::Type::Integer)
     294             :         {
     295           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     296             :                      "Codec blosc: clevel is not an integer");
     297           0 :             return false;
     298             :         }
     299           4 :         const int nLevel = oLevel.ToInteger();
     300           4 :         if (nLevel < 0 || nLevel > 9)
     301             :         {
     302           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     303             :                      "Codec blosc: clevel value for level: %d", nLevel);
     304           0 :             return false;
     305             :         }
     306           4 :         m_aosCompressorOptions.SetNameValue("CLEVEL", CPLSPrintf("%d", nLevel));
     307             :     }
     308             : 
     309          12 :     const auto oShuffle = configuration.GetObj("shuffle");
     310           4 :     if (oShuffle.GetType() != CPLJSONObject::Type::String)
     311             :     {
     312           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     313             :                  "Codec blosc: shuffle is missing or not a string");
     314           0 :         return false;
     315             :     }
     316           4 :     if (oShuffle.ToString() == "noshuffle")
     317           2 :         m_aosCompressorOptions.SetNameValue("SHUFFLE", "NONE");
     318           2 :     else if (oShuffle.ToString() == "shuffle")
     319           2 :         m_aosCompressorOptions.SetNameValue("SHUFFLE", "BYTE");
     320           0 :     else if (oShuffle.ToString() == "bitshuffle")
     321           0 :         m_aosCompressorOptions.SetNameValue("SHUFFLE", "BIT");
     322             :     else
     323             :     {
     324           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     325             :                  "Codec blosc: Invalid value for shuffle");
     326           0 :         return false;
     327             :     }
     328             : 
     329          12 :     const auto oTypesize = configuration.GetObj("typesize");
     330           4 :     if (oTypesize.IsValid())
     331             :     {
     332           2 :         if (oTypesize.GetType() != CPLJSONObject::Type::Integer)
     333             :         {
     334           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     335             :                      "Codec blosc: typesize is not an integer");
     336           0 :             return false;
     337             :         }
     338           2 :         const int nTypeSize = oTypesize.ToInteger();
     339             :         m_aosCompressorOptions.SetNameValue("TYPESIZE",
     340           2 :                                             CPLSPrintf("%d", nTypeSize));
     341             :     }
     342             : 
     343          12 :     const auto oBlocksize = configuration.GetObj("blocksize");
     344           4 :     if (oBlocksize.IsValid())
     345             :     {
     346           4 :         if (oBlocksize.GetType() != CPLJSONObject::Type::Integer)
     347             :         {
     348           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     349             :                      "Codec blosc: blocksize is not an integer");
     350           0 :             return false;
     351             :         }
     352           4 :         const int nBlocksize = oBlocksize.ToInteger();
     353             :         m_aosCompressorOptions.SetNameValue("BLOCKSIZE",
     354           4 :                                             CPLSPrintf("%d", nBlocksize));
     355             :     }
     356             : 
     357           4 :     return true;
     358             : }
     359             : 
     360             : /************************************************************************/
     361             : /*                      ZarrV3CodecBlosc::Clone()                        */
     362             : /************************************************************************/
     363             : 
     364           0 : std::unique_ptr<ZarrV3Codec> ZarrV3CodecBlosc::Clone() const
     365             : {
     366           0 :     auto psClone = std::make_unique<ZarrV3CodecBlosc>();
     367           0 :     ZarrArrayMetadata oOutputArrayMetadata;
     368           0 :     psClone->InitFromConfiguration(m_oConfiguration, m_oInputArrayMetadata,
     369             :                                    oOutputArrayMetadata);
     370           0 :     return psClone;
     371             : }
     372             : 
     373             : /************************************************************************/
     374             : /*                      ZarrV3CodecBlosc::Encode()                       */
     375             : /************************************************************************/
     376             : 
     377           2 : bool ZarrV3CodecBlosc::Encode(const ZarrByteVectorQuickResize &abySrc,
     378             :                               ZarrByteVectorQuickResize &abyDst) const
     379             : {
     380           2 :     abyDst.resize(abyDst.capacity());
     381           2 :     void *pOutputData = abyDst.data();
     382           2 :     size_t nOutputSize = abyDst.size();
     383           4 :     bool bRet = m_pCompressor->pfnFunc(
     384           2 :         abySrc.data(), abySrc.size(), &pOutputData, &nOutputSize,
     385           2 :         m_aosCompressorOptions.List(), m_pCompressor->user_data);
     386           2 :     if (bRet)
     387             :     {
     388           2 :         abyDst.resize(nOutputSize);
     389             :     }
     390           0 :     else if (nOutputSize > abyDst.size())
     391             :     {
     392           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     393             :                  "ZarrV3CodecBlosc::Encode(): output buffer too small");
     394             :     }
     395           2 :     return bRet;
     396             : }
     397             : 
     398             : /************************************************************************/
     399             : /*                      ZarrV3CodecBlosc::Decode()                       */
     400             : /************************************************************************/
     401             : 
     402           2 : bool ZarrV3CodecBlosc::Decode(const ZarrByteVectorQuickResize &abySrc,
     403             :                               ZarrByteVectorQuickResize &abyDst) const
     404             : {
     405           2 :     abyDst.resize(abyDst.capacity());
     406           2 :     void *pOutputData = abyDst.data();
     407           2 :     size_t nOutputSize = abyDst.size();
     408           2 :     bool bRet = m_pDecompressor->pfnFunc(abySrc.data(), abySrc.size(),
     409             :                                          &pOutputData, &nOutputSize, nullptr,
     410           2 :                                          m_pDecompressor->user_data);
     411           2 :     if (bRet)
     412             :     {
     413           2 :         abyDst.resize(nOutputSize);
     414             :     }
     415           0 :     else if (nOutputSize > abyDst.size())
     416             :     {
     417           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     418             :                  "ZarrV3CodecBlosc::Decode(): output buffer too small");
     419             :     }
     420           2 :     return bRet;
     421             : }
     422             : 
     423             : /************************************************************************/
     424             : /*                       ZarrV3CodecEndian()                            */
     425             : /************************************************************************/
     426             : 
     427         100 : ZarrV3CodecEndian::ZarrV3CodecEndian() : ZarrV3Codec(NAME)
     428             : {
     429         100 : }
     430             : 
     431             : /************************************************************************/
     432             : /*                       ~ZarrV3CodecEndian()                           */
     433             : /************************************************************************/
     434             : 
     435             : ZarrV3CodecEndian::~ZarrV3CodecEndian() = default;
     436             : 
     437             : /************************************************************************/
     438             : /*                           GetConfiguration()                         */
     439             : /************************************************************************/
     440             : 
     441          50 : /* static */ CPLJSONObject ZarrV3CodecEndian::GetConfiguration(bool bLittle)
     442             : {
     443          50 :     CPLJSONObject oConfig;
     444          50 :     oConfig.Add("endian", bLittle ? "little" : "big");
     445          50 :     return oConfig;
     446             : }
     447             : 
     448             : /************************************************************************/
     449             : /*                 ZarrV3CodecEndian::InitFromConfiguration()           */
     450             : /************************************************************************/
     451             : 
     452         100 : bool ZarrV3CodecEndian::InitFromConfiguration(
     453             :     const CPLJSONObject &configuration,
     454             :     const ZarrArrayMetadata &oInputArrayMetadata,
     455             :     ZarrArrayMetadata &oOutputArrayMetadata)
     456             : {
     457         100 :     m_oConfiguration = configuration.Clone();
     458         100 :     m_bLittle = true;
     459         100 :     m_oInputArrayMetadata = oInputArrayMetadata;
     460         100 :     oOutputArrayMetadata = oInputArrayMetadata;
     461             : 
     462         100 :     if (configuration.IsValid())
     463             :     {
     464         100 :         if (configuration.GetType() != CPLJSONObject::Type::Object)
     465             :         {
     466           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     467             :                      "Codec endian: configuration is not an object");
     468           0 :             return false;
     469             :         }
     470             : 
     471         200 :         for (const auto &oChild : configuration.GetChildren())
     472             :         {
     473         100 :             if (oChild.GetName() != "endian")
     474             :             {
     475           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     476             :                          "Codec endian: configuration contains a unhandled "
     477             :                          "member: %s",
     478           0 :                          oChild.GetName().c_str());
     479           0 :                 return false;
     480             :             }
     481             :         }
     482             : 
     483         200 :         const auto oEndian = configuration.GetObj("endian");
     484         100 :         if (oEndian.IsValid())
     485             :         {
     486         100 :             if (oEndian.GetType() != CPLJSONObject::Type::String)
     487             :             {
     488           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     489             :                          "Codec gzip: endian is not a string");
     490           0 :                 return false;
     491             :             }
     492         100 :             if (oEndian.ToString() == "little")
     493          40 :                 m_bLittle = true;
     494          60 :             else if (oEndian.ToString() == "big")
     495          60 :                 m_bLittle = false;
     496             :             else
     497             :             {
     498           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     499             :                          "Codec gzip: invalid value for endian");
     500           0 :                 return false;
     501             :             }
     502             :         }
     503             :     }
     504             : 
     505         100 :     return true;
     506             : }
     507             : 
     508             : /************************************************************************/
     509             : /*                     ZarrV3CodecEndian::Clone()                       */
     510             : /************************************************************************/
     511             : 
     512           0 : std::unique_ptr<ZarrV3Codec> ZarrV3CodecEndian::Clone() const
     513             : {
     514           0 :     auto psClone = std::make_unique<ZarrV3CodecEndian>();
     515           0 :     ZarrArrayMetadata oOutputArrayMetadata;
     516           0 :     psClone->InitFromConfiguration(m_oConfiguration, m_oInputArrayMetadata,
     517             :                                    oOutputArrayMetadata);
     518           0 :     return psClone;
     519             : }
     520             : 
     521             : /************************************************************************/
     522             : /*                      ZarrV3CodecEndian::Encode()                     */
     523             : /************************************************************************/
     524             : 
     525          48 : bool ZarrV3CodecEndian::Encode(const ZarrByteVectorQuickResize &abySrc,
     526             :                                ZarrByteVectorQuickResize &abyDst) const
     527             : {
     528          48 :     CPLAssert(!IsNoOp());
     529             : 
     530          48 :     size_t nEltCount = m_oInputArrayMetadata.GetEltCount();
     531          48 :     size_t nNativeSize = m_oInputArrayMetadata.oElt.nativeSize;
     532          48 :     if (abySrc.size() < nEltCount * nNativeSize)
     533             :     {
     534           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     535             :                  "ZarrV3CodecTranspose::Encode(): input buffer too small");
     536           0 :         return false;
     537             :     }
     538          48 :     CPLAssert(abySrc.size() >= nEltCount * nNativeSize);
     539          48 :     abyDst.resize(nEltCount * nNativeSize);
     540             : 
     541          48 :     const GByte *pabySrc = abySrc.data();
     542          48 :     GByte *pabyDst = abyDst.data();
     543             : 
     544          48 :     if (m_oInputArrayMetadata.oElt.nativeType ==
     545             :         DtypeElt::NativeType::COMPLEX_IEEEFP)
     546             :     {
     547           0 :         nEltCount *= 2;
     548           0 :         nNativeSize /= 2;
     549             :     }
     550          48 :     if (nNativeSize == 2)
     551             :     {
     552          36 :         for (size_t i = 0; i < nEltCount; ++i)
     553             :         {
     554          24 :             const uint16_t val = CPL_SWAP16(*reinterpret_cast<const uint16_t *>(
     555             :                 pabySrc + sizeof(uint16_t) * i));
     556          24 :             memcpy(pabyDst + sizeof(uint16_t) * i, &val, sizeof(val));
     557             :         }
     558             :     }
     559          36 :     else if (nNativeSize == 4)
     560             :     {
     561          54 :         for (size_t i = 0; i < nEltCount; ++i)
     562             :         {
     563          36 :             const uint32_t val = CPL_SWAP32(*reinterpret_cast<const uint32_t *>(
     564             :                 pabySrc + sizeof(uint32_t) * i));
     565          36 :             memcpy(pabyDst + sizeof(uint32_t) * i, &val, sizeof(val));
     566             :         }
     567             :     }
     568          18 :     else if (nNativeSize == 8)
     569             :     {
     570          54 :         for (size_t i = 0; i < nEltCount; ++i)
     571             :         {
     572          36 :             const uint64_t val = CPL_SWAP64(*reinterpret_cast<const uint64_t *>(
     573             :                 pabySrc + sizeof(uint64_t) * i));
     574          36 :             memcpy(pabyDst + sizeof(uint64_t) * i, &val, sizeof(val));
     575             :         }
     576             :     }
     577             :     else
     578             :     {
     579           0 :         CPLAssert(false);
     580             :     }
     581          48 :     return true;
     582             : }
     583             : 
     584             : /************************************************************************/
     585             : /*                      ZarrV3CodecEndian::Decode()                     */
     586             : /************************************************************************/
     587             : 
     588          24 : bool ZarrV3CodecEndian::Decode(const ZarrByteVectorQuickResize &abySrc,
     589             :                                ZarrByteVectorQuickResize &abyDst) const
     590             : {
     591          24 :     return Encode(abySrc, abyDst);
     592             : }
     593             : 
     594             : /************************************************************************/
     595             : /*                       ZarrV3CodecTranspose()                         */
     596             : /************************************************************************/
     597             : 
     598          80 : ZarrV3CodecTranspose::ZarrV3CodecTranspose() : ZarrV3Codec(NAME)
     599             : {
     600          80 : }
     601             : 
     602             : /************************************************************************/
     603             : /*                       ~ZarrV3CodecTranspose()                        */
     604             : /************************************************************************/
     605             : 
     606             : ZarrV3CodecTranspose::~ZarrV3CodecTranspose() = default;
     607             : 
     608             : /************************************************************************/
     609             : /*                             IsNoOp()                                 */
     610             : /************************************************************************/
     611             : 
     612         120 : bool ZarrV3CodecTranspose::IsNoOp() const
     613             : {
     614         180 :     for (int i = 0; i < static_cast<int>(m_anOrder.size()); ++i)
     615             :     {
     616         120 :         if (m_anOrder[i] != i)
     617          60 :             return false;
     618             :     }
     619          60 :     return true;
     620             : }
     621             : 
     622             : /************************************************************************/
     623             : /*                           GetConfiguration()                         */
     624             : /************************************************************************/
     625             : 
     626             : /* static */ CPLJSONObject
     627           0 : ZarrV3CodecTranspose::GetConfiguration(const std::vector<int> &anOrder)
     628             : {
     629           0 :     CPLJSONObject oConfig;
     630           0 :     CPLJSONArray oOrder;
     631           0 :     for (const auto nVal : anOrder)
     632           0 :         oOrder.Add(nVal);
     633           0 :     oConfig.Add("order", oOrder);
     634           0 :     return oConfig;
     635             : }
     636             : 
     637             : /************************************************************************/
     638             : /*                           GetConfiguration()                         */
     639             : /************************************************************************/
     640             : 
     641             : /* static */ CPLJSONObject
     642          40 : ZarrV3CodecTranspose::GetConfiguration(const std::string &osOrder)
     643             : {
     644          40 :     CPLJSONObject oConfig;
     645          80 :     CPLJSONArray oOrder;
     646          40 :     oConfig.Add("order", osOrder);
     647          80 :     return oConfig;
     648             : }
     649             : 
     650             : /************************************************************************/
     651             : /*                ZarrV3CodecTranspose::InitFromConfiguration()         */
     652             : /************************************************************************/
     653             : 
     654          80 : bool ZarrV3CodecTranspose::InitFromConfiguration(
     655             :     const CPLJSONObject &configuration,
     656             :     const ZarrArrayMetadata &oInputArrayMetadata,
     657             :     ZarrArrayMetadata &oOutputArrayMetadata)
     658             : {
     659          80 :     m_oConfiguration = configuration.Clone();
     660          80 :     m_oInputArrayMetadata = oInputArrayMetadata;
     661          80 :     oOutputArrayMetadata = oInputArrayMetadata;
     662             : 
     663          80 :     if (!configuration.IsValid() &&
     664           0 :         configuration.GetType() != CPLJSONObject::Type::Object)
     665             :     {
     666           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     667             :                  "Codec transpose: configuration missing or not an object");
     668           0 :         return false;
     669             :     }
     670             : 
     671         160 :     for (const auto &oChild : configuration.GetChildren())
     672             :     {
     673          80 :         if (oChild.GetName() != "order")
     674             :         {
     675           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     676             :                      "Codec transpose: configuration contains a unhandled "
     677             :                      "member: %s",
     678           0 :                      oChild.GetName().c_str());
     679           0 :             return false;
     680             :         }
     681             :     }
     682             : 
     683         240 :     const auto oOrder = configuration.GetObj("order");
     684          80 :     const int nDims = static_cast<int>(oInputArrayMetadata.anBlockSizes.size());
     685          80 :     if (oOrder.GetType() == CPLJSONObject::Type::String)
     686             :     {
     687         160 :         const auto osOrder = oOrder.ToString();
     688          80 :         if (osOrder == "C")
     689             :         {
     690           0 :             for (int i = 0; i < nDims; ++i)
     691             :             {
     692           0 :                 m_anOrder.push_back(i);
     693             :             }
     694             :         }
     695          80 :         else if (osOrder == "F")
     696             :         {
     697         200 :             for (int i = 0; i < nDims; ++i)
     698             :             {
     699         120 :                 m_anOrder.push_back(nDims - 1 - i);
     700         120 :                 oOutputArrayMetadata.anBlockSizes[i] =
     701         120 :                     oInputArrayMetadata.anBlockSizes[nDims - 1 - i];
     702             :             }
     703             :         }
     704             :         else
     705             :         {
     706           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     707             :                      "Codec transpose: invalid value for order");
     708           0 :             return false;
     709             :         }
     710             :     }
     711           0 :     else if (oOrder.GetType() == CPLJSONObject::Type::Array)
     712             :     {
     713           0 :         const auto oOrderArray = oOrder.ToArray();
     714           0 :         if (oOrderArray.Size() != nDims)
     715             :         {
     716           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     717             :                      "Codec transpose: order[] does not have the expected "
     718             :                      "number of elements");
     719           0 :             return false;
     720             :         }
     721           0 :         std::vector<int> oSet(nDims);
     722           0 :         oOutputArrayMetadata.anBlockSizes.clear();
     723           0 :         for (const auto &oVal : oOrderArray)
     724             :         {
     725           0 :             const int nVal = oVal.ToInteger();
     726           0 :             if (nVal < 0 || nVal >= nDims || oSet[nVal])
     727             :             {
     728           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     729             :                          "Codec transpose: order[] does not define a valid "
     730             :                          "transposition");
     731           0 :                 return false;
     732             :             }
     733           0 :             oSet[nVal] = true;
     734           0 :             m_anOrder.push_back(nVal);
     735           0 :             oOutputArrayMetadata.anBlockSizes.push_back(
     736           0 :                 oInputArrayMetadata.anBlockSizes[nVal]);
     737             :         }
     738             :     }
     739             :     else
     740             :     {
     741           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     742             :                  "Codec transpose: invalid value for order");
     743           0 :         return false;
     744             :     }
     745             : 
     746          80 :     int i = 0;
     747          80 :     m_anReverseOrder.resize(m_anOrder.size());
     748         200 :     for (const auto nVal : m_anOrder)
     749             :     {
     750         120 :         m_anReverseOrder[nVal] = i;
     751         120 :         ++i;
     752             :     }
     753             : 
     754          80 :     return true;
     755             : }
     756             : 
     757             : /************************************************************************/
     758             : /*                   ZarrV3CodecTranspose::Clone()                      */
     759             : /************************************************************************/
     760             : 
     761           0 : std::unique_ptr<ZarrV3Codec> ZarrV3CodecTranspose::Clone() const
     762             : {
     763           0 :     auto psClone = std::make_unique<ZarrV3CodecTranspose>();
     764           0 :     ZarrArrayMetadata oOutputArrayMetadata;
     765           0 :     psClone->InitFromConfiguration(m_oConfiguration, m_oInputArrayMetadata,
     766             :                                    oOutputArrayMetadata);
     767           0 :     return psClone;
     768             : }
     769             : 
     770             : /************************************************************************/
     771             : /*                  ZarrV3CodecTranspose::Transpose()                   */
     772             : /************************************************************************/
     773             : 
     774          40 : bool ZarrV3CodecTranspose::Transpose(const ZarrByteVectorQuickResize &abySrc,
     775             :                                      ZarrByteVectorQuickResize &abyDst,
     776             :                                      bool bEncodeDirection) const
     777             : {
     778          40 :     CPLAssert(m_anOrder.size() == m_oInputArrayMetadata.anBlockSizes.size());
     779          40 :     CPLAssert(m_anReverseOrder.size() ==
     780             :               m_oInputArrayMetadata.anBlockSizes.size());
     781          40 :     const size_t nDims = m_anOrder.size();
     782          40 :     const size_t nSourceSize = m_oInputArrayMetadata.oElt.nativeSize;
     783          40 :     const auto &anBlockSizes = m_oInputArrayMetadata.anBlockSizes;
     784          40 :     CPLAssert(nDims > 0);
     785          40 :     if (abySrc.size() < m_oInputArrayMetadata.GetEltCount() * nSourceSize)
     786             :     {
     787           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     788             :                  "ZarrV3CodecTranspose::Transpose(): input buffer too small");
     789           0 :         return false;
     790             :     }
     791          40 :     abyDst.resize(m_oInputArrayMetadata.GetEltCount() * nSourceSize);
     792             : 
     793             :     struct Stack
     794             :     {
     795             :         size_t nIters = 0;
     796             :         const GByte *src_ptr = nullptr;
     797             :         GByte *dst_ptr = nullptr;
     798             :         size_t src_inc_offset = 0;
     799             :         size_t dst_inc_offset = 0;
     800             :     };
     801             : 
     802          40 :     std::vector<Stack> stack(nDims);
     803             :     stack.emplace_back(
     804          40 :         Stack());  // to make gcc 9.3 -O2 -Wnull-dereference happy
     805             : 
     806          40 :     if (!bEncodeDirection)
     807             :     {
     808          20 :         stack[m_anReverseOrder[nDims - 1]].src_inc_offset = nSourceSize;
     809          20 :         size_t nStride = nSourceSize;
     810          60 :         for (size_t i = nDims - 1; i > 0;)
     811             :         {
     812          40 :             --i;
     813          40 :             nStride *=
     814          40 :                 static_cast<size_t>(anBlockSizes[m_anReverseOrder[i + 1]]);
     815          40 :             stack[m_anReverseOrder[i]].src_inc_offset = nStride;
     816             :         }
     817             : 
     818          20 :         stack[nDims - 1].dst_inc_offset = nSourceSize;
     819          20 :         nStride = nSourceSize;
     820          60 :         for (size_t i = nDims - 1; i > 0;)
     821             :         {
     822          40 :             --i;
     823          40 :             nStride *= static_cast<size_t>(anBlockSizes[i + 1]);
     824          40 :             stack[i].dst_inc_offset = nStride;
     825             :         }
     826             :     }
     827             :     else
     828             :     {
     829          20 :         stack[m_anReverseOrder[nDims - 1]].dst_inc_offset = nSourceSize;
     830          20 :         size_t nStride = nSourceSize;
     831          60 :         for (size_t i = nDims - 1; i > 0;)
     832             :         {
     833          40 :             --i;
     834          40 :             nStride *=
     835          40 :                 static_cast<size_t>(anBlockSizes[m_anReverseOrder[i + 1]]);
     836          40 :             stack[m_anReverseOrder[i]].dst_inc_offset = nStride;
     837             :         }
     838             : 
     839          20 :         stack[nDims - 1].src_inc_offset = nSourceSize;
     840          20 :         nStride = nSourceSize;
     841          60 :         for (size_t i = nDims - 1; i > 0;)
     842             :         {
     843          40 :             --i;
     844          40 :             nStride *= static_cast<size_t>(anBlockSizes[i + 1]);
     845          40 :             stack[i].src_inc_offset = nStride;
     846             :         }
     847             :     }
     848             : 
     849          40 :     stack[0].src_ptr = abySrc.data();
     850          40 :     stack[0].dst_ptr = &abyDst[0];
     851             : 
     852          40 :     size_t dimIdx = 0;
     853         680 : lbl_next_depth:
     854         680 :     if (dimIdx == nDims)
     855             :     {
     856         480 :         void *dst_ptr = stack[nDims].dst_ptr;
     857         480 :         const void *src_ptr = stack[nDims].src_ptr;
     858         480 :         if (nSourceSize == 1)
     859          96 :             *stack[nDims].dst_ptr = *stack[nDims].src_ptr;
     860         384 :         else if (nSourceSize == 2)
     861          96 :             *static_cast<uint16_t *>(dst_ptr) =
     862          96 :                 *static_cast<const uint16_t *>(src_ptr);
     863         288 :         else if (nSourceSize == 4)
     864         144 :             *static_cast<uint32_t *>(dst_ptr) =
     865         144 :                 *static_cast<const uint32_t *>(src_ptr);
     866         144 :         else if (nSourceSize == 8)
     867         144 :             *static_cast<uint64_t *>(dst_ptr) =
     868         144 :                 *static_cast<const uint64_t *>(src_ptr);
     869             :         else
     870           0 :             memcpy(dst_ptr, src_ptr, nSourceSize);
     871             :     }
     872             :     else
     873             :     {
     874         200 :         stack[dimIdx].nIters = static_cast<size_t>(anBlockSizes[dimIdx]);
     875             :         while (true)
     876             :         {
     877         640 :             dimIdx++;
     878         640 :             stack[dimIdx].src_ptr = stack[dimIdx - 1].src_ptr;
     879         640 :             stack[dimIdx].dst_ptr = stack[dimIdx - 1].dst_ptr;
     880         640 :             goto lbl_next_depth;
     881         640 :         lbl_return_to_caller:
     882         640 :             dimIdx--;
     883         640 :             if ((--stack[dimIdx].nIters) == 0)
     884         200 :                 break;
     885         440 :             stack[dimIdx].src_ptr += stack[dimIdx].src_inc_offset;
     886         440 :             stack[dimIdx].dst_ptr += stack[dimIdx].dst_inc_offset;
     887             :         }
     888             :     }
     889         680 :     if (dimIdx > 0)
     890         640 :         goto lbl_return_to_caller;
     891             : 
     892          40 :     return true;
     893             : }
     894             : 
     895             : /************************************************************************/
     896             : /*                    ZarrV3CodecTranspose::Encode()                    */
     897             : /************************************************************************/
     898             : 
     899          20 : bool ZarrV3CodecTranspose::Encode(const ZarrByteVectorQuickResize &abySrc,
     900             :                                   ZarrByteVectorQuickResize &abyDst) const
     901             : {
     902          20 :     CPLAssert(!IsNoOp());
     903             : 
     904          20 :     return Transpose(abySrc, abyDst, true);
     905             : }
     906             : 
     907             : /************************************************************************/
     908             : /*                    ZarrV3CodecTranspose::Decode()                    */
     909             : /************************************************************************/
     910             : 
     911          20 : bool ZarrV3CodecTranspose::Decode(const ZarrByteVectorQuickResize &abySrc,
     912             :                                   ZarrByteVectorQuickResize &abyDst) const
     913             : {
     914          20 :     CPLAssert(!IsNoOp());
     915             : 
     916          20 :     return Transpose(abySrc, abyDst, false);
     917             : }
     918             : 
     919             : /************************************************************************/
     920             : /*                    ZarrV3CodecSequence::Clone()                      */
     921             : /************************************************************************/
     922             : 
     923           8 : std::unique_ptr<ZarrV3CodecSequence> ZarrV3CodecSequence::Clone() const
     924             : {
     925           8 :     auto poClone = std::make_unique<ZarrV3CodecSequence>(m_oInputArrayMetadata);
     926          16 :     for (const auto &poCodec : m_apoCodecs)
     927           8 :         poClone->m_apoCodecs.emplace_back(poCodec->Clone());
     928           8 :     poClone->m_oCodecArray = m_oCodecArray.Clone();
     929           8 :     return poClone;
     930             : }
     931             : 
     932             : /************************************************************************/
     933             : /*                    ZarrV3CodecSequence::InitFromJson()               */
     934             : /************************************************************************/
     935             : 
     936         130 : bool ZarrV3CodecSequence::InitFromJson(const CPLJSONObject &oCodecs)
     937             : {
     938         130 :     if (oCodecs.GetType() != CPLJSONObject::Type::Array)
     939             :     {
     940           0 :         CPLError(CE_Failure, CPLE_AppDefined, "codecs is not an array");
     941           0 :         return false;
     942             :     }
     943         260 :     auto oCodecsArray = oCodecs.ToArray();
     944             : 
     945         260 :     ZarrArrayMetadata oInputArrayMetadata = m_oInputArrayMetadata;
     946         130 :     ZarrV3Codec::IOType eLastType = ZarrV3Codec::IOType::ARRAY;
     947         260 :     std::string osLastCodec;
     948             : 
     949             : #if !CPL_IS_LSB
     950             :     const auto InsertImplicitEndianCodecIfNeeded =
     951             :         [this, &oInputArrayMetadata, &eLastType, &osLastCodec]()
     952             :     {
     953             :         // Insert a little endian codec if we are on a big endian target
     954             :         if (eLastType == ZarrV3Codec::IOType::ARRAY &&
     955             :             oInputArrayMetadata.oElt.nativeSize > 1)
     956             :         {
     957             :             auto poEndianCodec = std::make_unique<ZarrV3CodecEndian>();
     958             :             ZarrArrayMetadata oOutputArrayMetadata;
     959             :             poEndianCodec->InitFromConfiguration(
     960             :                 ZarrV3CodecEndian::GetConfiguration(true), oInputArrayMetadata,
     961             :                 oOutputArrayMetadata);
     962             :             oInputArrayMetadata = oOutputArrayMetadata;
     963             :             eLastType = poEndianCodec->GetOutputType();
     964             :             osLastCodec = poEndianCodec->GetName();
     965             :             m_apoCodecs.emplace_back(std::move(poEndianCodec));
     966             :         }
     967             :     };
     968             : #endif
     969             : 
     970         360 :     for (const auto &oCodec : oCodecsArray)
     971             :     {
     972         230 :         if (oCodec.GetType() != CPLJSONObject::Type::Object)
     973             :         {
     974           0 :             CPLError(CE_Failure, CPLE_AppDefined, "codecs[] is not an array");
     975           0 :             return false;
     976             :         }
     977         460 :         const auto osName = oCodec["name"].ToString();
     978           0 :         std::unique_ptr<ZarrV3Codec> poCodec;
     979         230 :         if (osName == "gzip")
     980          46 :             poCodec = std::make_unique<ZarrV3CodecGZip>();
     981         184 :         else if (osName == "blosc")
     982           4 :             poCodec = std::make_unique<ZarrV3CodecBlosc>();
     983         180 :         else if (osName == "endian")
     984         100 :             poCodec = std::make_unique<ZarrV3CodecEndian>();
     985          80 :         else if (osName == "transpose")
     986          80 :             poCodec = std::make_unique<ZarrV3CodecTranspose>();
     987             :         else
     988             :         {
     989           0 :             CPLError(CE_Failure, CPLE_NotSupported, "Unsupported codec: %s",
     990             :                      osName.c_str());
     991           0 :             return false;
     992             :         }
     993             : 
     994         230 :         if (poCodec->GetInputType() == ZarrV3Codec::IOType::ARRAY)
     995             :         {
     996         180 :             if (eLastType == ZarrV3Codec::IOType::BYTES)
     997             :             {
     998           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     999             :                          "Cannot chain codec %s with %s",
    1000           0 :                          poCodec->GetName().c_str(), osLastCodec.c_str());
    1001           0 :                 return false;
    1002             :             }
    1003             :         }
    1004             : #if !CPL_IS_LSB
    1005             :         else
    1006             :         {
    1007             :             InsertImplicitEndianCodecIfNeeded();
    1008             :         }
    1009             : #endif
    1010             : 
    1011         230 :         ZarrArrayMetadata oOutputArrayMetadata;
    1012         460 :         if (!poCodec->InitFromConfiguration(oCodec["configuration"],
    1013             :                                             oInputArrayMetadata,
    1014         230 :                                             oOutputArrayMetadata))
    1015             :         {
    1016           0 :             return false;
    1017             :         }
    1018         230 :         oInputArrayMetadata = std::move(oOutputArrayMetadata);
    1019         230 :         eLastType = poCodec->GetOutputType();
    1020         230 :         osLastCodec = poCodec->GetName();
    1021             : 
    1022         230 :         if (!poCodec->IsNoOp())
    1023         118 :             m_apoCodecs.emplace_back(std::move(poCodec));
    1024             :     }
    1025             : 
    1026             : #if !CPL_IS_LSB
    1027             :     InsertImplicitEndianCodecIfNeeded();
    1028             : #endif
    1029             : 
    1030         130 :     m_oCodecArray = oCodecs.Clone();
    1031         130 :     return true;
    1032             : }
    1033             : 
    1034             : /************************************************************************/
    1035             : /*                  ZarrV3CodecEndian::AllocateBuffer()                 */
    1036             : /************************************************************************/
    1037             : 
    1038       10689 : bool ZarrV3CodecSequence::AllocateBuffer(ZarrByteVectorQuickResize &abyBuffer)
    1039             : {
    1040       10689 :     if (!m_apoCodecs.empty())
    1041             :     {
    1042       10439 :         const size_t nRawSize = m_oInputArrayMetadata.GetEltCount() *
    1043       10640 :                                 m_oInputArrayMetadata.oElt.nativeSize;
    1044             :         // Grow the temporary buffer a bit beyond the uncompressed size
    1045       10640 :         const size_t nMaxSize = nRawSize + nRawSize / 3 + 64;
    1046             :         try
    1047             :         {
    1048       10640 :             m_abyTmp.resize(nMaxSize);
    1049             :         }
    1050           0 :         catch (const std::exception &e)
    1051             :         {
    1052           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
    1053           0 :             return false;
    1054             :         }
    1055       10551 :         m_abyTmp.resize(nRawSize);
    1056             : 
    1057             :         // Grow the input/output buffer too if we have several steps
    1058       10533 :         if (m_apoCodecs.size() >= 2 && abyBuffer.capacity() < nMaxSize)
    1059             :         {
    1060          36 :             const size_t nSize = abyBuffer.size();
    1061             :             try
    1062             :             {
    1063          36 :                 abyBuffer.resize(nMaxSize);
    1064             :             }
    1065           0 :             catch (const std::exception &e)
    1066             :             {
    1067           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
    1068           0 :                 return false;
    1069             :             }
    1070          36 :             abyBuffer.resize(nSize);
    1071             :         }
    1072             :     }
    1073       10386 :     return true;
    1074             : }
    1075             : 
    1076             : /************************************************************************/
    1077             : /*                    ZarrV3CodecSequence::Encode()                     */
    1078             : /************************************************************************/
    1079             : 
    1080        5405 : bool ZarrV3CodecSequence::Encode(ZarrByteVectorQuickResize &abyBuffer)
    1081             : {
    1082        5405 :     if (!AllocateBuffer(abyBuffer))
    1083           0 :         return false;
    1084       10814 :     for (const auto &poCodec : m_apoCodecs)
    1085             :     {
    1086        5409 :         if (!poCodec->Encode(abyBuffer, m_abyTmp))
    1087           0 :             return false;
    1088        5409 :         std::swap(abyBuffer, m_abyTmp);
    1089             :     }
    1090        5405 :     return true;
    1091             : }
    1092             : 
    1093             : /************************************************************************/
    1094             : /*                    ZarrV3CodecSequence::Decode()                     */
    1095             : /************************************************************************/
    1096             : 
    1097        5347 : bool ZarrV3CodecSequence::Decode(ZarrByteVectorQuickResize &abyBuffer)
    1098             : {
    1099        5347 :     if (!AllocateBuffer(abyBuffer))
    1100           0 :         return false;
    1101       10467 :     for (auto iter = m_apoCodecs.rbegin(); iter != m_apoCodecs.rend(); ++iter)
    1102             :     {
    1103        5044 :         const auto &poCodec = *iter;
    1104        5030 :         if (!poCodec->Decode(abyBuffer, m_abyTmp))
    1105           0 :             return false;
    1106        5255 :         std::swap(abyBuffer, m_abyTmp);
    1107             :     }
    1108        5232 :     return true;
    1109             : }

Generated by: LCOV version 1.14