LCOV - code coverage report
Current view: top level - frmts/zarr - zarr_attribute.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 222 231 96.1 %
Date: 2026-01-27 01:43:19 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Zarr driver
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2021, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "zarr.h"
      14             : 
      15             : #include <algorithm>
      16             : #include <cassert>
      17             : #include <map>
      18             : 
      19             : constexpr const char *ATTRIBUTE_GROUP_SUFFIX = "/_GLOBAL_";
      20             : 
      21             : /************************************************************************/
      22             : /*               ZarrAttributeGroup::ZarrAttributeGroup()               */
      23             : /************************************************************************/
      24             : 
      25        6937 : ZarrAttributeGroup::ZarrAttributeGroup(const std::string &osParentName,
      26        6937 :                                        bool bContainerIsGroup)
      27             :     : m_bContainerIsGroup(bContainerIsGroup),
      28             :       m_poGroup(MEMGroup::Create(
      29             :           bContainerIsGroup
      30       13874 :               ? (osParentName == "/" ? ATTRIBUTE_GROUP_SUFFIX
      31             :                                      : osParentName + ATTRIBUTE_GROUP_SUFFIX)
      32             :               : osParentName,
      33       13874 :           nullptr))
      34             : {
      35        6937 : }
      36             : 
      37             : /************************************************************************/
      38             : /*                      ZarrAttributeGroup::Init()                      */
      39             : /************************************************************************/
      40             : 
      41        3758 : void ZarrAttributeGroup::Init(const CPLJSONObject &obj, bool bUpdatable)
      42             : {
      43        3758 :     if (obj.GetType() != CPLJSONObject::Type::Object)
      44          92 :         return;
      45        7332 :     const auto children = obj.GetChildren();
      46        4564 :     for (const auto &item : children)
      47             :     {
      48         898 :         const auto itemType = item.GetType();
      49         898 :         bool bDone = false;
      50         898 :         std::shared_ptr<GDALAttribute> poAttr;
      51         898 :         switch (itemType)
      52             :         {
      53         444 :             case CPLJSONObject::Type::String:
      54             :             {
      55         444 :                 bDone = true;
      56        1776 :                 poAttr = m_poGroup->CreateAttribute(
      57         888 :                     item.GetName(), {}, GDALExtendedDataType::CreateString(),
      58         888 :                     nullptr);
      59         444 :                 if (poAttr)
      60             :                 {
      61         444 :                     const GUInt64 arrayStartIdx = 0;
      62         444 :                     const size_t count = 1;
      63         444 :                     const GInt64 arrayStep = 0;
      64         444 :                     const GPtrDiff_t bufferStride = 0;
      65        1332 :                     const std::string str = item.ToString();
      66         444 :                     const char *c_str = str.c_str();
      67         888 :                     poAttr->Write(&arrayStartIdx, &count, &arrayStep,
      68         444 :                                   &bufferStride, poAttr->GetDataType(), &c_str);
      69             :                 }
      70         444 :                 break;
      71             :             }
      72          31 :             case CPLJSONObject::Type::Integer:
      73             :             {
      74          31 :                 bDone = true;
      75         124 :                 poAttr = m_poGroup->CreateAttribute(
      76          62 :                     item.GetName(), {}, GDALExtendedDataType::Create(GDT_Int32),
      77          62 :                     nullptr);
      78          31 :                 if (poAttr)
      79             :                 {
      80          31 :                     const GUInt64 arrayStartIdx = 0;
      81          31 :                     const size_t count = 1;
      82          31 :                     const GInt64 arrayStep = 0;
      83          31 :                     const GPtrDiff_t bufferStride = 0;
      84          31 :                     const int val = item.ToInteger();
      85          62 :                     poAttr->Write(
      86             :                         &arrayStartIdx, &count, &arrayStep, &bufferStride,
      87          62 :                         GDALExtendedDataType::Create(GDT_Int32), &val);
      88             :                 }
      89          31 :                 break;
      90             :             }
      91          35 :             case CPLJSONObject::Type::Long:
      92             :             {
      93          35 :                 bDone = true;
      94         140 :                 poAttr = m_poGroup->CreateAttribute(
      95          70 :                     item.GetName(), {}, GDALExtendedDataType::Create(GDT_Int64),
      96          70 :                     nullptr);
      97          35 :                 if (poAttr)
      98             :                 {
      99          35 :                     const GUInt64 arrayStartIdx = 0;
     100          35 :                     const size_t count = 1;
     101          35 :                     const GInt64 arrayStep = 0;
     102          35 :                     const GPtrDiff_t bufferStride = 0;
     103          35 :                     const int64_t val = item.ToLong();
     104          70 :                     poAttr->Write(
     105             :                         &arrayStartIdx, &count, &arrayStep, &bufferStride,
     106          70 :                         GDALExtendedDataType::Create(GDT_Int64), &val);
     107             :                 }
     108          35 :                 break;
     109             :             }
     110          69 :             case CPLJSONObject::Type::Double:
     111             :             {
     112          69 :                 bDone = true;
     113         276 :                 poAttr = m_poGroup->CreateAttribute(
     114         138 :                     item.GetName(), {},
     115         207 :                     GDALExtendedDataType::Create(GDT_Float64), nullptr);
     116          69 :                 if (poAttr)
     117             :                 {
     118          69 :                     const GUInt64 arrayStartIdx = 0;
     119          69 :                     const size_t count = 1;
     120          69 :                     const GInt64 arrayStep = 0;
     121          69 :                     const GPtrDiff_t bufferStride = 0;
     122          69 :                     const double val = item.ToDouble();
     123         138 :                     poAttr->Write(
     124             :                         &arrayStartIdx, &count, &arrayStep, &bufferStride,
     125         138 :                         GDALExtendedDataType::Create(GDT_Float64), &val);
     126             :                 }
     127          69 :                 break;
     128             :             }
     129         197 :             case CPLJSONObject::Type::Array:
     130             :             {
     131         394 :                 const auto array = item.ToArray();
     132         197 :                 bool isFirst = true;
     133         197 :                 bool isString = false;
     134         197 :                 bool isNumeric = false;
     135         197 :                 bool foundInt64 = false;
     136         197 :                 bool foundDouble = false;
     137         197 :                 bool mixedType = false;
     138         197 :                 size_t countItems = 0;
     139         660 :                 for (const auto &subItem : array)
     140             :                 {
     141         463 :                     const auto subItemType = subItem.GetType();
     142         463 :                     if (subItemType == CPLJSONObject::Type::String)
     143             :                     {
     144          91 :                         if (isFirst)
     145             :                         {
     146          45 :                             isString = true;
     147             :                         }
     148          46 :                         else if (!isString)
     149             :                         {
     150           0 :                             mixedType = true;
     151           0 :                             break;
     152             :                         }
     153          91 :                         countItems++;
     154             :                     }
     155         372 :                     else if (subItemType == CPLJSONObject::Type::Integer ||
     156         224 :                              subItemType == CPLJSONObject::Type::Long ||
     157             :                              subItemType == CPLJSONObject::Type::Double)
     158             :                     {
     159         333 :                         if (isFirst)
     160             :                         {
     161         113 :                             isNumeric = true;
     162             :                         }
     163         220 :                         else if (!isNumeric)
     164             :                         {
     165           5 :                             mixedType = true;
     166           5 :                             break;
     167             :                         }
     168         328 :                         if (subItemType == CPLJSONObject::Type::Double)
     169         185 :                             foundDouble = true;
     170         143 :                         else if (subItemType == CPLJSONObject::Type::Long)
     171          60 :                             foundInt64 = true;
     172         328 :                         countItems++;
     173             :                     }
     174             :                     else
     175             :                     {
     176          39 :                         mixedType = true;
     177          39 :                         break;
     178             :                     }
     179         419 :                     isFirst = false;
     180             :                 }
     181             : 
     182         197 :                 if (!mixedType && !isFirst)
     183             :                 {
     184         153 :                     bDone = true;
     185         765 :                     poAttr = m_poGroup->CreateAttribute(
     186         306 :                         item.GetName(), {countItems},
     187         367 :                         isString ? GDALExtendedDataType::CreateString()
     188             :                                  : GDALExtendedDataType::Create(
     189             :                                        foundDouble  ? GDT_Float64
     190          61 :                                        : foundInt64 ? GDT_Int64
     191             :                                                     : GDT_Int32),
     192         306 :                         nullptr);
     193         153 :                     if (poAttr)
     194             :                     {
     195         153 :                         size_t idx = 0;
     196         567 :                         for (const auto &subItem : array)
     197             :                         {
     198         414 :                             const GUInt64 arrayStartIdx = idx;
     199         414 :                             const size_t count = 1;
     200         414 :                             const GInt64 arrayStep = 0;
     201         414 :                             const GPtrDiff_t bufferStride = 0;
     202         414 :                             const auto subItemType = subItem.GetType();
     203             :                             switch (subItemType)
     204             :                             {
     205          86 :                                 case CPLJSONObject::Type::String:
     206             :                                 {
     207         258 :                                     const std::string str = subItem.ToString();
     208          86 :                                     const char *c_str = str.c_str();
     209         172 :                                     poAttr->Write(&arrayStartIdx, &count,
     210             :                                                   &arrayStep, &bufferStride,
     211          86 :                                                   poAttr->GetDataType(),
     212             :                                                   &c_str);
     213          86 :                                     break;
     214             :                                 }
     215          83 :                                 case CPLJSONObject::Type::Integer:
     216             :                                 {
     217          83 :                                     const int val = subItem.ToInteger();
     218         166 :                                     poAttr->Write(
     219             :                                         &arrayStartIdx, &count, &arrayStep,
     220             :                                         &bufferStride,
     221         166 :                                         GDALExtendedDataType::Create(GDT_Int32),
     222             :                                         &val);
     223          83 :                                     break;
     224             :                                 }
     225          60 :                                 case CPLJSONObject::Type::Long:
     226             :                                 {
     227          60 :                                     const int64_t val = subItem.ToLong();
     228         120 :                                     poAttr->Write(
     229             :                                         &arrayStartIdx, &count, &arrayStep,
     230             :                                         &bufferStride,
     231         120 :                                         GDALExtendedDataType::Create(GDT_Int64),
     232             :                                         &val);
     233          60 :                                     break;
     234             :                                 }
     235         185 :                                 case CPLJSONObject::Type::Double:
     236             :                                 {
     237         185 :                                     const double val = subItem.ToDouble();
     238         370 :                                     poAttr->Write(&arrayStartIdx, &count,
     239             :                                                   &arrayStep, &bufferStride,
     240         370 :                                                   GDALExtendedDataType::Create(
     241             :                                                       GDT_Float64),
     242             :                                                   &val);
     243         185 :                                     break;
     244             :                                 }
     245           0 :                                 default:
     246             :                                     // Ignore other JSON object types
     247           0 :                                     break;
     248             :                             }
     249         414 :                             ++idx;
     250             :                         }
     251             :                     }
     252             :                 }
     253         197 :                 break;
     254             :             }
     255         122 :             default:
     256             :                 // Ignore other JSON object types
     257         122 :                 break;
     258             :         }
     259             : 
     260         898 :         if (!bDone)
     261             :         {
     262         166 :             constexpr size_t nMaxStringLength = 0;
     263             :             const auto eDT = GDALExtendedDataType::CreateString(
     264         332 :                 nMaxStringLength, GEDTST_JSON);
     265             :             poAttr =
     266         166 :                 m_poGroup->CreateAttribute(item.GetName(), {}, eDT, nullptr);
     267         166 :             if (poAttr)
     268             :             {
     269         166 :                 const GUInt64 arrayStartIdx = 0;
     270         166 :                 const size_t count = 1;
     271         166 :                 const GInt64 arrayStep = 0;
     272         166 :                 const GPtrDiff_t bufferStride = 0;
     273         498 :                 const std::string str = item.ToString();
     274         166 :                 const char *c_str = str.c_str();
     275         332 :                 poAttr->Write(&arrayStartIdx, &count, &arrayStep, &bufferStride,
     276         166 :                               poAttr->GetDataType(), &c_str);
     277             :             }
     278             :         }
     279             : 
     280        1796 :         auto poMemAttr = std::dynamic_pointer_cast<MEMAttribute>(poAttr);
     281         898 :         if (poMemAttr)
     282         898 :             poMemAttr->SetModified(false);
     283             :     }
     284        3666 :     SetUpdatable(bUpdatable);
     285             : }
     286             : 
     287             : /************************************************************************/
     288             : /*                   ZarrAttributeGroup::Serialize()                    */
     289             : /************************************************************************/
     290             : 
     291         599 : CPLJSONObject ZarrAttributeGroup::Serialize() const
     292             : {
     293         599 :     CPLJSONObject o;
     294        1198 :     const auto attrs = m_poGroup->GetAttributes(nullptr);
     295        1132 :     for (const auto &attr : attrs)
     296             :     {
     297         533 :         const auto &oType = attr->GetDataType();
     298         533 :         if (oType.GetClass() == GEDTC_STRING)
     299             :         {
     300         660 :             const auto anDims = attr->GetDimensionsSize();
     301         330 :             if (anDims.size() == 0)
     302             :             {
     303         310 :                 const char *pszStr = attr->ReadAsString();
     304         310 :                 if (pszStr)
     305             :                 {
     306         620 :                     CPLJSONDocument oDoc;
     307         335 :                     if (oType.GetSubType() == GEDTST_JSON &&
     308         335 :                         oDoc.LoadMemory(pszStr))
     309             :                     {
     310          25 :                         o.Add(attr->GetName(), oDoc.GetRoot());
     311             :                     }
     312             :                     else
     313             :                     {
     314         285 :                         o.Add(attr->GetName(), pszStr);
     315             :                     }
     316             :                 }
     317             :                 else
     318             :                 {
     319           0 :                     o.AddNull(attr->GetName());
     320             :                 }
     321             :             }
     322          20 :             else if (anDims.size() == 1)
     323             :             {
     324          40 :                 const auto list = attr->ReadAsStringArray();
     325          40 :                 CPLJSONArray arr;
     326          64 :                 for (int i = 0; i < list.size(); ++i)
     327             :                 {
     328          44 :                     arr.Add(list[i]);
     329             :                 }
     330          20 :                 o.Add(attr->GetName(), arr);
     331             :             }
     332             :             else
     333             :             {
     334           0 :                 CPLError(
     335             :                     CE_Warning, CPLE_AppDefined,
     336             :                     "Cannot serialize attribute %s of dimension count >= 2",
     337           0 :                     attr->GetName().c_str());
     338             :             }
     339             :         }
     340         203 :         else if (oType.GetClass() == GEDTC_NUMERIC)
     341             :         {
     342         406 :             const auto anDims = attr->GetDimensionsSize();
     343         203 :             const auto eDT = oType.GetNumericDataType();
     344         203 :             if (anDims.size() == 0)
     345             :             {
     346         120 :                 if (eDT == GDT_Int8 || eDT == GDT_Int16 || eDT == GDT_Int32 ||
     347             :                     eDT == GDT_Int64)
     348             :                 {
     349          49 :                     const int64_t nVal = attr->ReadAsInt64();
     350          49 :                     o.Add(attr->GetName(), static_cast<GInt64>(nVal));
     351             :                 }
     352          71 :                 else if (eDT == GDT_UInt8 || eDT == GDT_UInt16 ||
     353          24 :                          eDT == GDT_UInt32 || eDT == GDT_UInt64)
     354             :                 {
     355          55 :                     const int64_t nVal = attr->ReadAsInt64();
     356          55 :                     o.Add(attr->GetName(), static_cast<uint64_t>(nVal));
     357             :                 }
     358             :                 else
     359             :                 {
     360          16 :                     const double dfVal = attr->ReadAsDouble();
     361          16 :                     o.Add(attr->GetName(), dfVal);
     362             :                 }
     363             :             }
     364          83 :             else if (anDims.size() == 1)
     365             :             {
     366         166 :                 CPLJSONArray arr;
     367          83 :                 if (eDT == GDT_Int8 || eDT == GDT_Int16 || eDT == GDT_Int32 ||
     368             :                     eDT == GDT_Int64)
     369             :                 {
     370          96 :                     const auto list = attr->ReadAsInt64Array();
     371         144 :                     for (const auto nVal : list)
     372             :                     {
     373          96 :                         arr.Add(static_cast<GInt64>(nVal));
     374          48 :                     }
     375             :                 }
     376          35 :                 else if (eDT == GDT_UInt8 || eDT == GDT_UInt16 ||
     377          27 :                          eDT == GDT_UInt32 || eDT == GDT_UInt64)
     378             :                 {
     379          32 :                     const auto list = attr->ReadAsInt64Array();
     380          48 :                     for (const auto nVal : list)
     381             :                     {
     382          32 :                         arr.Add(static_cast<uint64_t>(nVal));
     383          16 :                     }
     384             :                 }
     385             :                 else
     386             :                 {
     387          38 :                     const auto list = attr->ReadAsDoubleArray();
     388          65 :                     for (const auto dfVal : list)
     389             :                     {
     390          46 :                         arr.Add(dfVal);
     391             :                     }
     392             :                 }
     393          83 :                 o.Add(attr->GetName(), arr);
     394             :             }
     395             :             else
     396             :             {
     397           0 :                 CPLError(
     398             :                     CE_Warning, CPLE_AppDefined,
     399             :                     "Cannot serialize attribute %s of dimension count >= 2",
     400           0 :                     attr->GetName().c_str());
     401             :             }
     402             :         }
     403             :     }
     404        1198 :     return o;
     405             : }
     406             : 
     407             : /************************************************************************/
     408             : /*                           ParentRenamed()                            */
     409             : /************************************************************************/
     410             : 
     411          25 : void ZarrAttributeGroup::ParentRenamed(const std::string &osNewParentFullName)
     412             : {
     413          25 :     if (m_bContainerIsGroup)
     414          10 :         m_poGroup->SetFullName(osNewParentFullName + ATTRIBUTE_GROUP_SUFFIX);
     415             :     else
     416          15 :         m_poGroup->SetFullName(osNewParentFullName);
     417          50 :     const auto attrs = m_poGroup->GetAttributes(nullptr);
     418          52 :     for (auto &attr : attrs)
     419             :     {
     420          27 :         attr->ParentRenamed(m_poGroup->GetFullName());
     421             :     }
     422          25 : }
     423             : 
     424             : /************************************************************************/
     425             : /*                           ParentDeleted()                            */
     426             : /************************************************************************/
     427             : 
     428          14 : void ZarrAttributeGroup::ParentDeleted()
     429             : {
     430          14 :     m_poGroup->Deleted();
     431          14 : }

Generated by: LCOV version 1.14