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

Generated by: LCOV version 1.14