LCOV - code coverage report
Current view: top level - frmts/zarr - zarr_attribute.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 220 231 95.2 %
Date: 2024-11-21 22:18:42 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        2586 : ZarrAttributeGroup::ZarrAttributeGroup(const std::string &osParentName,
      26        2586 :                                        bool bContainerIsGroup)
      27             :     : m_bContainerIsGroup(bContainerIsGroup),
      28             :       m_poGroup(MEMGroup::Create(
      29             :           bContainerIsGroup
      30        5172 :               ? (osParentName == "/" ? ATTRIBUTE_GROUP_SUFFIX
      31             :                                      : osParentName + ATTRIBUTE_GROUP_SUFFIX)
      32             :               : osParentName,
      33        5172 :           nullptr))
      34             : {
      35        2586 : }
      36             : 
      37             : /************************************************************************/
      38             : /*                   ZarrAttributeGroup::Init()                         */
      39             : /************************************************************************/
      40             : 
      41         809 : void ZarrAttributeGroup::Init(const CPLJSONObject &obj, bool bUpdatable)
      42             : {
      43         809 :     if (obj.GetType() != CPLJSONObject::Type::Object)
      44          28 :         return;
      45        1562 :     const auto children = obj.GetChildren();
      46        1122 :     for (const auto &item : children)
      47             :     {
      48         341 :         const auto itemType = item.GetType();
      49         341 :         bool bDone = false;
      50         341 :         std::shared_ptr<GDALAttribute> poAttr;
      51         341 :         switch (itemType)
      52             :         {
      53         192 :             case CPLJSONObject::Type::String:
      54             :             {
      55         192 :                 bDone = true;
      56         768 :                 poAttr = m_poGroup->CreateAttribute(
      57         384 :                     item.GetName(), {}, GDALExtendedDataType::CreateString(),
      58         384 :                     nullptr);
      59         192 :                 if (poAttr)
      60             :                 {
      61         192 :                     const GUInt64 arrayStartIdx = 0;
      62         192 :                     const size_t count = 1;
      63         192 :                     const GInt64 arrayStep = 0;
      64         192 :                     const GPtrDiff_t bufferStride = 0;
      65         576 :                     const std::string str = item.ToString();
      66         192 :                     const char *c_str = str.c_str();
      67         384 :                     poAttr->Write(&arrayStartIdx, &count, &arrayStep,
      68         192 :                                   &bufferStride, poAttr->GetDataType(), &c_str);
      69             :                 }
      70         192 :                 break;
      71             :             }
      72          17 :             case CPLJSONObject::Type::Integer:
      73             :             {
      74          17 :                 bDone = true;
      75          68 :                 poAttr = m_poGroup->CreateAttribute(
      76          34 :                     item.GetName(), {}, GDALExtendedDataType::Create(GDT_Int32),
      77          34 :                     nullptr);
      78          17 :                 if (poAttr)
      79             :                 {
      80          17 :                     const GUInt64 arrayStartIdx = 0;
      81          17 :                     const size_t count = 1;
      82          17 :                     const GInt64 arrayStep = 0;
      83          17 :                     const GPtrDiff_t bufferStride = 0;
      84          17 :                     const int val = item.ToInteger();
      85          34 :                     poAttr->Write(
      86             :                         &arrayStartIdx, &count, &arrayStep, &bufferStride,
      87          34 :                         GDALExtendedDataType::Create(GDT_Int32), &val);
      88             :                 }
      89          17 :                 break;
      90             :             }
      91          20 :             case CPLJSONObject::Type::Long:
      92             :             {
      93          20 :                 bDone = true;
      94          80 :                 poAttr = m_poGroup->CreateAttribute(
      95          40 :                     item.GetName(), {}, GDALExtendedDataType::Create(GDT_Int64),
      96          40 :                     nullptr);
      97          20 :                 if (poAttr)
      98             :                 {
      99          20 :                     const GUInt64 arrayStartIdx = 0;
     100          20 :                     const size_t count = 1;
     101          20 :                     const GInt64 arrayStep = 0;
     102          20 :                     const GPtrDiff_t bufferStride = 0;
     103          20 :                     const int64_t val = item.ToLong();
     104          40 :                     poAttr->Write(
     105             :                         &arrayStartIdx, &count, &arrayStep, &bufferStride,
     106          40 :                         GDALExtendedDataType::Create(GDT_Int64), &val);
     107             :                 }
     108          20 :                 break;
     109             :             }
     110          32 :             case CPLJSONObject::Type::Double:
     111             :             {
     112          32 :                 bDone = true;
     113         128 :                 poAttr = m_poGroup->CreateAttribute(
     114          64 :                     item.GetName(), {},
     115          96 :                     GDALExtendedDataType::Create(GDT_Float64), nullptr);
     116          32 :                 if (poAttr)
     117             :                 {
     118          32 :                     const GUInt64 arrayStartIdx = 0;
     119          32 :                     const size_t count = 1;
     120          32 :                     const GInt64 arrayStep = 0;
     121          32 :                     const GPtrDiff_t bufferStride = 0;
     122          32 :                     const double val = item.ToDouble();
     123          64 :                     poAttr->Write(
     124             :                         &arrayStartIdx, &count, &arrayStep, &bufferStride,
     125          64 :                         GDALExtendedDataType::Create(GDT_Float64), &val);
     126             :                 }
     127          32 :                 break;
     128             :             }
     129          54 :             case CPLJSONObject::Type::Array:
     130             :             {
     131         108 :                 const auto array = item.ToArray();
     132          54 :                 bool isFirst = true;
     133          54 :                 bool isString = false;
     134          54 :                 bool isNumeric = false;
     135          54 :                 bool foundInt64 = false;
     136          54 :                 bool foundDouble = false;
     137          54 :                 bool mixedType = false;
     138          54 :                 size_t countItems = 0;
     139         165 :                 for (const auto &subItem : array)
     140             :                 {
     141         111 :                     const auto subItemType = subItem.GetType();
     142         111 :                     if (subItemType == CPLJSONObject::Type::String)
     143             :                     {
     144          27 :                         if (isFirst)
     145             :                         {
     146          13 :                             isString = true;
     147             :                         }
     148          14 :                         else if (!isString)
     149             :                         {
     150           0 :                             mixedType = true;
     151           0 :                             break;
     152             :                         }
     153          27 :                         countItems++;
     154             :                     }
     155          84 :                     else if (subItemType == CPLJSONObject::Type::Integer ||
     156          20 :                              subItemType == CPLJSONObject::Type::Long ||
     157             :                              subItemType == CPLJSONObject::Type::Double)
     158             :                     {
     159          84 :                         if (isFirst)
     160             :                         {
     161          41 :                             isNumeric = true;
     162             :                         }
     163          43 :                         else if (!isNumeric)
     164             :                         {
     165           2 :                             mixedType = true;
     166           2 :                             break;
     167             :                         }
     168          82 :                         if (subItemType == CPLJSONObject::Type::Double)
     169          20 :                             foundDouble = true;
     170          62 :                         else if (subItemType == CPLJSONObject::Type::Long)
     171          34 :                             foundInt64 = true;
     172          82 :                         countItems++;
     173             :                     }
     174             :                     else
     175             :                     {
     176           0 :                         mixedType = true;
     177           0 :                         break;
     178             :                     }
     179         109 :                     isFirst = false;
     180             :                 }
     181             : 
     182          54 :                 if (!mixedType && !isFirst)
     183             :                 {
     184          52 :                     bDone = true;
     185         260 :                     poAttr = m_poGroup->CreateAttribute(
     186         104 :                         item.GetName(), {countItems},
     187         134 :                         isString ? GDALExtendedDataType::CreateString()
     188             :                                  : GDALExtendedDataType::Create(
     189             :                                        foundDouble  ? GDT_Float64
     190          30 :                                        : foundInt64 ? GDT_Int64
     191             :                                                     : GDT_Int32),
     192         104 :                         nullptr);
     193          52 :                     if (poAttr)
     194             :                     {
     195          52 :                         size_t idx = 0;
     196         159 :                         for (const auto &subItem : array)
     197             :                         {
     198         107 :                             const GUInt64 arrayStartIdx = idx;
     199         107 :                             const size_t count = 1;
     200         107 :                             const GInt64 arrayStep = 0;
     201         107 :                             const GPtrDiff_t bufferStride = 0;
     202         107 :                             const auto subItemType = subItem.GetType();
     203             :                             switch (subItemType)
     204             :                             {
     205          25 :                                 case CPLJSONObject::Type::String:
     206             :                                 {
     207          75 :                                     const std::string str = subItem.ToString();
     208          25 :                                     const char *c_str = str.c_str();
     209          50 :                                     poAttr->Write(&arrayStartIdx, &count,
     210             :                                                   &arrayStep, &bufferStride,
     211          25 :                                                   poAttr->GetDataType(),
     212             :                                                   &c_str);
     213          25 :                                     break;
     214             :                                 }
     215          28 :                                 case CPLJSONObject::Type::Integer:
     216             :                                 {
     217          28 :                                     const int val = subItem.ToInteger();
     218          56 :                                     poAttr->Write(
     219             :                                         &arrayStartIdx, &count, &arrayStep,
     220             :                                         &bufferStride,
     221          56 :                                         GDALExtendedDataType::Create(GDT_Int32),
     222             :                                         &val);
     223          28 :                                     break;
     224             :                                 }
     225          34 :                                 case CPLJSONObject::Type::Long:
     226             :                                 {
     227          34 :                                     const int64_t val = subItem.ToLong();
     228          68 :                                     poAttr->Write(
     229             :                                         &arrayStartIdx, &count, &arrayStep,
     230             :                                         &bufferStride,
     231          68 :                                         GDALExtendedDataType::Create(GDT_Int64),
     232             :                                         &val);
     233          34 :                                     break;
     234             :                                 }
     235          20 :                                 case CPLJSONObject::Type::Double:
     236             :                                 {
     237          20 :                                     const double val = subItem.ToDouble();
     238          40 :                                     poAttr->Write(&arrayStartIdx, &count,
     239             :                                                   &arrayStep, &bufferStride,
     240          40 :                                                   GDALExtendedDataType::Create(
     241             :                                                       GDT_Float64),
     242             :                                                   &val);
     243          20 :                                     break;
     244             :                                 }
     245           0 :                                 default:
     246             :                                     // Ignore other JSON object types
     247           0 :                                     break;
     248             :                             }
     249         107 :                             ++idx;
     250             :                         }
     251             :                     }
     252             :                 }
     253          54 :                 break;
     254             :             }
     255          26 :             default:
     256             :                 // Ignore other JSON object types
     257          26 :                 break;
     258             :         }
     259             : 
     260         341 :         if (!bDone)
     261             :         {
     262          28 :             constexpr size_t nMaxStringLength = 0;
     263             :             const auto eDT = GDALExtendedDataType::CreateString(
     264          56 :                 nMaxStringLength, GEDTST_JSON);
     265             :             poAttr =
     266          28 :                 m_poGroup->CreateAttribute(item.GetName(), {}, eDT, nullptr);
     267          28 :             if (poAttr)
     268             :             {
     269          28 :                 const GUInt64 arrayStartIdx = 0;
     270          28 :                 const size_t count = 1;
     271          28 :                 const GInt64 arrayStep = 0;
     272          28 :                 const GPtrDiff_t bufferStride = 0;
     273          84 :                 const std::string str = item.ToString();
     274          28 :                 const char *c_str = str.c_str();
     275          56 :                 poAttr->Write(&arrayStartIdx, &count, &arrayStep, &bufferStride,
     276          28 :                               poAttr->GetDataType(), &c_str);
     277             :             }
     278             :         }
     279             : 
     280         682 :         auto poMemAttr = std::dynamic_pointer_cast<MEMAttribute>(poAttr);
     281         341 :         if (poMemAttr)
     282         341 :             poMemAttr->SetModified(false);
     283             :     }
     284         781 :     SetUpdatable(bUpdatable);
     285             : }
     286             : 
     287             : /************************************************************************/
     288             : /*                    ZarrAttributeGroup::Serialize()                   */
     289             : /************************************************************************/
     290             : 
     291         443 : CPLJSONObject ZarrAttributeGroup::Serialize() const
     292             : {
     293         443 :     CPLJSONObject o;
     294         886 :     const auto attrs = m_poGroup->GetAttributes(nullptr);
     295         685 :     for (const auto &attr : attrs)
     296             :     {
     297         242 :         const auto &oType = attr->GetDataType();
     298         242 :         if (oType.GetClass() == GEDTC_STRING)
     299             :         {
     300         332 :             const auto anDims = attr->GetDimensionsSize();
     301         166 :             if (anDims.size() == 0)
     302             :             {
     303         157 :                 const char *pszStr = attr->ReadAsString();
     304         157 :                 if (pszStr)
     305             :                 {
     306         314 :                     CPLJSONDocument oDoc;
     307         163 :                     if (oType.GetSubType() == GEDTST_JSON &&
     308         163 :                         oDoc.LoadMemory(pszStr))
     309             :                     {
     310           6 :                         o.Add(attr->GetName(), oDoc.GetRoot());
     311             :                     }
     312             :                     else
     313             :                     {
     314         151 :                         o.Add(attr->GetName(), pszStr);
     315             :                     }
     316             :                 }
     317             :                 else
     318             :                 {
     319           0 :                     o.AddNull(attr->GetName());
     320             :                 }
     321             :             }
     322           9 :             else if (anDims.size() == 1)
     323             :             {
     324          18 :                 const auto list = attr->ReadAsStringArray();
     325          18 :                 CPLJSONArray arr;
     326          30 :                 for (int i = 0; i < list.size(); ++i)
     327             :                 {
     328          21 :                     arr.Add(list[i]);
     329             :                 }
     330           9 :                 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          76 :         else if (oType.GetClass() == GEDTC_NUMERIC)
     341             :         {
     342         152 :             const auto anDims = attr->GetDimensionsSize();
     343          76 :             const auto eDT = oType.GetNumericDataType();
     344          76 :             if (anDims.size() == 0)
     345             :             {
     346          45 :                 if (eDT == GDT_Int8 || eDT == GDT_Int16 || eDT == GDT_Int32 ||
     347             :                     eDT == GDT_Int64)
     348             :                 {
     349          18 :                     const int64_t nVal = attr->ReadAsInt64();
     350          18 :                     o.Add(attr->GetName(), static_cast<GInt64>(nVal));
     351             :                 }
     352          27 :                 else if (eDT == GDT_Byte || eDT == GDT_UInt16 ||
     353           9 :                          eDT == GDT_UInt32 || eDT == GDT_UInt64)
     354             :                 {
     355          21 :                     const int64_t nVal = attr->ReadAsInt64();
     356          21 :                     o.Add(attr->GetName(), static_cast<uint64_t>(nVal));
     357             :                 }
     358             :                 else
     359             :                 {
     360           6 :                     const double dfVal = attr->ReadAsDouble();
     361           6 :                     o.Add(attr->GetName(), dfVal);
     362             :                 }
     363             :             }
     364          31 :             else if (anDims.size() == 1)
     365             :             {
     366          62 :                 CPLJSONArray arr;
     367          31 :                 if (eDT == GDT_Int8 || eDT == GDT_Int16 || eDT == GDT_Int32 ||
     368             :                     eDT == GDT_Int64)
     369             :                 {
     370          36 :                     const auto list = attr->ReadAsInt64Array();
     371          54 :                     for (const auto nVal : list)
     372             :                     {
     373          36 :                         arr.Add(static_cast<GInt64>(nVal));
     374          18 :                     }
     375             :                 }
     376          13 :                 else if (eDT == GDT_Byte || eDT == GDT_UInt16 ||
     377          10 :                          eDT == GDT_UInt32 || eDT == GDT_UInt64)
     378             :                 {
     379          12 :                     const auto list = attr->ReadAsInt64Array();
     380          18 :                     for (const auto nVal : list)
     381             :                     {
     382          12 :                         arr.Add(static_cast<uint64_t>(nVal));
     383           6 :                     }
     384             :                 }
     385             :                 else
     386             :                 {
     387          14 :                     const auto list = attr->ReadAsDoubleArray();
     388          21 :                     for (const auto dfVal : list)
     389             :                     {
     390          14 :                         arr.Add(dfVal);
     391             :                     }
     392             :                 }
     393          31 :                 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         886 :     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