LCOV - code coverage report
Current view: top level - frmts/zarr - zarr_group.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 239 266 89.8 %
Date: 2026-04-18 22:07:07 Functions: 22 23 95.7 %

          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 <limits>
      18             : #include <map>
      19             : #include <set>
      20             : 
      21             : /************************************************************************/
      22             : /*                           ~ZarrGroupBase()                           */
      23             : /************************************************************************/
      24             : 
      25        2417 : ZarrGroupBase::~ZarrGroupBase()
      26             : {
      27        2417 :     CPL_IGNORE_RET_VAL(ZarrGroupBase::Close());
      28        2417 : }
      29             : 
      30             : /************************************************************************/
      31             : /*                               Close()                                */
      32             : /************************************************************************/
      33             : 
      34        8009 : bool ZarrGroupBase::Close()
      35             : {
      36        8009 :     bool ret = true;
      37             : 
      38        9302 :     for (auto &kv : m_oMapGroups)
      39             :     {
      40        1293 :         ret = kv.second->Close() && ret;
      41             :     }
      42             : 
      43       16027 :     for (auto &kv : m_oMapMDArrays)
      44             :     {
      45        8018 :         ret = kv.second->Flush() && ret;
      46             :     }
      47        8009 :     return ret;
      48             : }
      49             : 
      50             : /************************************************************************/
      51             : /*                               Flush()                                */
      52             : /************************************************************************/
      53             : 
      54          42 : bool ZarrGroupBase::Flush()
      55             : {
      56          42 :     bool ret = true;
      57             : 
      58         169 :     for (auto &kv : m_oMapMDArrays)
      59             :     {
      60         127 :         ret = kv.second->Flush() && ret;
      61             :     }
      62          42 :     return ret;
      63             : }
      64             : 
      65             : /************************************************************************/
      66             : /*                          GetMDArrayNames()                           */
      67             : /************************************************************************/
      68             : 
      69        1446 : std::vector<std::string> ZarrGroupBase::GetMDArrayNames(CSLConstList) const
      70             : {
      71        1446 :     if (!CheckValidAndErrorOutIfNot())
      72           0 :         return {};
      73             : 
      74        1446 :     if (!m_bDirectoryExplored)
      75         354 :         ExploreDirectory();
      76             : 
      77        1446 :     return m_aosArrays;
      78             : }
      79             : 
      80             : /************************************************************************/
      81             : /*                           RegisterArray()                            */
      82             : /************************************************************************/
      83             : 
      84        2414 : void ZarrGroupBase::RegisterArray(const std::shared_ptr<ZarrArray> &array) const
      85             : {
      86        2414 :     m_oMapMDArrays[array->GetName()] = array;
      87        2414 :     if (!cpl::contains(m_oSetArrayNames, array->GetName()))
      88             :     {
      89        2324 :         m_oSetArrayNames.insert(array->GetName());
      90        2324 :         m_aosArrays.emplace_back(array->GetName());
      91             :     }
      92        4828 :     array->RegisterGroup(
      93        4828 :         std::dynamic_pointer_cast<ZarrGroupBase>(m_pSelf.lock()));
      94        2414 : }
      95             : 
      96             : /************************************************************************/
      97             : /*                           GetGroupNames()                            */
      98             : /************************************************************************/
      99             : 
     100         419 : std::vector<std::string> ZarrGroupBase::GetGroupNames(CSLConstList) const
     101             : {
     102         419 :     if (!CheckValidAndErrorOutIfNot())
     103           0 :         return {};
     104             : 
     105         419 :     if (!m_bDirectoryExplored)
     106          38 :         ExploreDirectory();
     107             : 
     108         419 :     return m_aosGroups;
     109             : }
     110             : 
     111             : /************************************************************************/
     112             : /*                            DeleteGroup()                             */
     113             : /************************************************************************/
     114             : 
     115          20 : bool ZarrGroupBase::DeleteGroup(const std::string &osName,
     116             :                                 CSLConstList /*papszOptions*/)
     117             : {
     118          20 :     if (!CheckValidAndErrorOutIfNot())
     119           0 :         return false;
     120             : 
     121          20 :     if (!m_bUpdatable)
     122             :     {
     123           6 :         CPLError(CE_Failure, CPLE_NotSupported,
     124             :                  "Dataset not open in update mode");
     125           6 :         return false;
     126             :     }
     127          14 :     if (CPLHasPathTraversal(osName.c_str()))
     128             :     {
     129           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Path traversal detected in %s",
     130             :                  osName.c_str());
     131           0 :         return false;
     132             :     }
     133          14 :     GetGroupNames();
     134             : 
     135          14 :     auto oIterNames = std::find(m_aosGroups.begin(), m_aosGroups.end(), osName);
     136          14 :     if (oIterNames == m_aosGroups.end())
     137             :     {
     138           6 :         CPLError(CE_Failure, CPLE_AppDefined,
     139             :                  "Group %s is not a sub-group of this group", osName.c_str());
     140           6 :         return false;
     141             :     }
     142             : 
     143             :     const std::string osSubDirName =
     144          16 :         CPLFormFilenameSafe(m_osDirectoryName.c_str(), osName.c_str(), nullptr);
     145           8 :     if (VSIRmdirRecursive(osSubDirName.c_str()) != 0)
     146             :     {
     147           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot delete %s",
     148             :                  osSubDirName.c_str());
     149           0 :         return false;
     150             :     }
     151             : 
     152           8 :     m_poSharedResource->DeleteZMetadataItemRecursive(osSubDirName);
     153             : 
     154           8 :     m_oSetGroupNames.erase(osName);
     155           8 :     m_aosGroups.erase(oIterNames);
     156             : 
     157           8 :     auto oIter = m_oMapGroups.find(osName);
     158           8 :     if (oIter != m_oMapGroups.end())
     159             :     {
     160           6 :         oIter->second->Deleted();
     161           6 :         m_oMapGroups.erase(oIter);
     162             :     }
     163             : 
     164           8 :     return true;
     165             : }
     166             : 
     167             : /************************************************************************/
     168             : /*                      NotifyChildrenOfDeletion()                      */
     169             : /************************************************************************/
     170             : 
     171           8 : void ZarrGroupBase::NotifyChildrenOfDeletion()
     172             : {
     173          10 :     for (const auto &oIter : m_oMapGroups)
     174           2 :         oIter.second->ParentDeleted();
     175             : 
     176          14 :     for (const auto &oIter : m_oMapMDArrays)
     177           6 :         oIter.second->ParentDeleted();
     178             : 
     179           8 :     m_oAttrGroup.ParentDeleted();
     180             : 
     181          16 :     for (const auto &oIter : m_oMapDimensions)
     182           8 :         oIter.second->ParentDeleted();
     183           8 : }
     184             : 
     185             : /************************************************************************/
     186             : /*                   ZarrGroupBase::CreateAttribute()                   */
     187             : /************************************************************************/
     188             : 
     189          95 : std::shared_ptr<GDALAttribute> ZarrGroupBase::CreateAttribute(
     190             :     const std::string &osName, const std::vector<GUInt64> &anDimensions,
     191             :     const GDALExtendedDataType &oDataType, CSLConstList papszOptions)
     192             : {
     193          95 :     if (!CheckValidAndErrorOutIfNot())
     194           0 :         return nullptr;
     195             : 
     196          95 :     if (!m_bUpdatable)
     197             :     {
     198           6 :         CPLError(CE_Failure, CPLE_NotSupported,
     199             :                  "Dataset not open in update mode");
     200           6 :         return nullptr;
     201             :     }
     202          89 :     if (anDimensions.size() >= 2)
     203             :     {
     204           4 :         CPLError(CE_Failure, CPLE_NotSupported,
     205             :                  "Cannot create attributes of dimension >= 2");
     206           4 :         return nullptr;
     207             :     }
     208          85 :     LoadAttributes();
     209             :     return m_oAttrGroup.CreateAttribute(osName, anDimensions, oDataType,
     210          85 :                                         papszOptions);
     211             : }
     212             : 
     213             : /************************************************************************/
     214             : /*                   ZarrGroupBase::DeleteAttribute()                   */
     215             : /************************************************************************/
     216             : 
     217          18 : bool ZarrGroupBase::DeleteAttribute(const std::string &osName, CSLConstList)
     218             : {
     219          18 :     if (!CheckValidAndErrorOutIfNot())
     220           0 :         return false;
     221             : 
     222          18 :     if (!m_bUpdatable)
     223             :     {
     224           6 :         CPLError(CE_Failure, CPLE_NotSupported,
     225             :                  "Dataset not open in update mode");
     226           6 :         return false;
     227             :     }
     228             : 
     229          12 :     LoadAttributes();
     230          12 :     return m_oAttrGroup.DeleteAttribute(osName);
     231             : }
     232             : 
     233             : /************************************************************************/
     234             : /*                           GetDimensions()                            */
     235             : /************************************************************************/
     236             : 
     237             : std::vector<std::shared_ptr<GDALDimension>>
     238         748 : ZarrGroupBase::GetDimensions(CSLConstList) const
     239             : {
     240         748 :     if (!CheckValidAndErrorOutIfNot())
     241           0 :         return {};
     242             : 
     243         748 :     if (!m_bReadFromConsolidatedMetadata && !m_bDimensionsInstantiated)
     244             :     {
     245         347 :         m_bDimensionsInstantiated = true;
     246             :         // We need to instantiate arrays to discover dimensions
     247         694 :         const auto aosArrays = GetMDArrayNames();
     248         381 :         for (const auto &osArray : aosArrays)
     249             :         {
     250          34 :             OpenMDArray(osArray);
     251             :         }
     252             :     }
     253             : 
     254        1496 :     std::vector<std::shared_ptr<GDALDimension>> oRes;
     255        1311 :     for (const auto &oIter : m_oMapDimensions)
     256             :     {
     257         563 :         oRes.push_back(oIter.second);
     258             :     }
     259         748 :     return oRes;
     260             : }
     261             : 
     262             : /************************************************************************/
     263             : /*                           DeleteMDArray()                            */
     264             : /************************************************************************/
     265             : 
     266          18 : bool ZarrGroupBase::DeleteMDArray(const std::string &osName,
     267             :                                   CSLConstList /*papszOptions*/)
     268             : {
     269          18 :     if (!CheckValidAndErrorOutIfNot())
     270           0 :         return false;
     271             : 
     272          18 :     if (!m_bUpdatable)
     273             :     {
     274           6 :         CPLError(CE_Failure, CPLE_NotSupported,
     275             :                  "Dataset not open in update mode");
     276           6 :         return false;
     277             :     }
     278          12 :     if (CPLHasPathTraversal(osName.c_str()))
     279             :     {
     280           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Path traversal detected in %s",
     281             :                  osName.c_str());
     282           0 :         return false;
     283             :     }
     284          12 :     GetMDArrayNames();
     285             : 
     286          12 :     auto oIterNames = std::find(m_aosArrays.begin(), m_aosArrays.end(), osName);
     287          12 :     if (oIterNames == m_aosArrays.end())
     288             :     {
     289           6 :         CPLError(CE_Failure, CPLE_AppDefined,
     290             :                  "Array %s is not an array of this group", osName.c_str());
     291           6 :         return false;
     292             :     }
     293             : 
     294             :     const std::string osSubDirName =
     295          12 :         CPLFormFilenameSafe(m_osDirectoryName.c_str(), osName.c_str(), nullptr);
     296           6 :     if (VSIRmdirRecursive(osSubDirName.c_str()) != 0)
     297             :     {
     298           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot delete %s",
     299             :                  osSubDirName.c_str());
     300           0 :         return false;
     301             :     }
     302             : 
     303           6 :     m_poSharedResource->DeleteZMetadataItemRecursive(osSubDirName);
     304             : 
     305           6 :     m_oSetArrayNames.erase(osName);
     306           6 :     m_aosArrays.erase(oIterNames);
     307             : 
     308           6 :     auto oIter = m_oMapMDArrays.find(osName);
     309           6 :     if (oIter != m_oMapMDArrays.end())
     310             :     {
     311           4 :         oIter->second->Deleted();
     312           4 :         m_oMapMDArrays.erase(oIter);
     313             :     }
     314             : 
     315           6 :     return true;
     316             : }
     317             : 
     318             : /************************************************************************/
     319             : /*                          CreateDimension()                           */
     320             : /************************************************************************/
     321             : 
     322         670 : std::shared_ptr<GDALDimension> ZarrGroupBase::CreateDimension(
     323             :     const std::string &osName, const std::string &osType,
     324             :     const std::string &osDirection, GUInt64 nSize, CSLConstList)
     325             : {
     326         670 :     if (!CheckValidAndErrorOutIfNot())
     327           0 :         return nullptr;
     328             : 
     329         670 :     if (osName.empty())
     330             :     {
     331           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     332             :                  "Empty dimension name not supported");
     333           0 :         return nullptr;
     334             :     }
     335         670 :     GetDimensions(nullptr);
     336             : 
     337         670 :     if (m_oMapDimensions.find(osName) != m_oMapDimensions.end())
     338             :     {
     339           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     340             :                  "A dimension with same name (%s) already exists in group %s",
     341           0 :                  osName.c_str(), GetFullName().c_str());
     342           0 :         return nullptr;
     343             :     }
     344             :     auto newDim(std::make_shared<ZarrDimension>(
     345         670 :         m_poSharedResource,
     346        1340 :         std::dynamic_pointer_cast<ZarrGroupBase>(m_pSelf.lock()), GetFullName(),
     347        1340 :         osName, osType, osDirection, nSize));
     348         670 :     newDim->SetXArrayDimension();
     349         670 :     m_oMapDimensions[osName] = newDim;
     350         670 :     return newDim;
     351             : }
     352             : 
     353             : /************************************************************************/
     354             : /*                          RenameDimension()                           */
     355             : /************************************************************************/
     356             : 
     357          12 : bool ZarrGroupBase::RenameDimension(const std::string &osOldName,
     358             :                                     const std::string &osNewName)
     359             : {
     360          12 :     if (m_oMapDimensions.find(osNewName) != m_oMapDimensions.end())
     361             :     {
     362           6 :         CPLError(CE_Failure, CPLE_AppDefined,
     363             :                  "A dimension with same name already exists");
     364           6 :         return false;
     365             :     }
     366           6 :     auto oIter = m_oMapDimensions.find(osOldName);
     367           6 :     if (oIter == m_oMapDimensions.end())
     368             :     {
     369           0 :         CPLAssert(false);
     370             :         return false;
     371             :     }
     372           6 :     auto poDim = std::move(oIter->second);
     373           6 :     m_oMapDimensions.erase(oIter);
     374           6 :     m_oMapDimensions[osNewName] = std::move(poDim);
     375           6 :     return true;
     376             : }
     377             : 
     378             : /************************************************************************/
     379             : /*                 ZarrGroupBase::UpdateDimensionSize()                 */
     380             : /************************************************************************/
     381             : 
     382           7 : void ZarrGroupBase::UpdateDimensionSize(
     383             :     const std::shared_ptr<GDALDimension> &poUpdatedDim)
     384             : {
     385          14 :     const auto aosGroupNames = GetGroupNames();
     386           7 :     for (const auto &osGroupName : aosGroupNames)
     387             :     {
     388           0 :         auto poSubGroup = OpenZarrGroup(osGroupName);
     389           0 :         if (poSubGroup)
     390             :         {
     391           0 :             poSubGroup->UpdateDimensionSize(poUpdatedDim);
     392             :         }
     393             :     }
     394          14 :     const auto aosArrayNames = GetMDArrayNames();
     395          22 :     for (const auto &osArrayName : aosArrayNames)
     396             :     {
     397             :         // Disable checks that size of variables referenced by _ARRAY_DIMENSIONS
     398             :         // are consistent with array shapes, as we are in the middle of updating
     399             :         // things
     400          15 :         m_bDimSizeInUpdate = true;
     401          30 :         auto poArray = OpenZarrArray(osArrayName);
     402          15 :         m_bDimSizeInUpdate = false;
     403          15 :         if (poArray)
     404             :         {
     405          39 :             for (auto &poDim : poArray->GetDimensions())
     406             :             {
     407          24 :                 if (poDim->GetFullName() == poUpdatedDim->GetFullName())
     408             :                 {
     409             :                     auto poModifiableDim =
     410          30 :                         std::dynamic_pointer_cast<ZarrDimension>(poDim);
     411          15 :                     CPLAssert(poModifiableDim);
     412          15 :                     poModifiableDim->SetSize(poUpdatedDim->GetSize());
     413          15 :                     poArray->SetDefinitionModified(true);
     414             :                 }
     415             :             }
     416             :         }
     417             :     }
     418           7 : }
     419             : 
     420             : /************************************************************************/
     421             : /*                 ZarrGroupBase::NotifyArrayRenamed()                  */
     422             : /************************************************************************/
     423             : 
     424           6 : void ZarrGroupBase::NotifyArrayRenamed(const std::string &osOldName,
     425             :                                        const std::string &osNewName)
     426             : {
     427           6 :     for (auto &osName : m_aosArrays)
     428             :     {
     429           6 :         if (osName == osOldName)
     430             :         {
     431           6 :             osName = osNewName;
     432           6 :             break;
     433             :         }
     434             :     }
     435             : 
     436           6 :     auto oIter = m_oMapMDArrays.find(osOldName);
     437           6 :     if (oIter != m_oMapMDArrays.end())
     438             :     {
     439           6 :         auto poArray = std::move(oIter->second);
     440           6 :         m_oMapMDArrays.erase(oIter);
     441           6 :         m_oMapMDArrays[osNewName] = std::move(poArray);
     442             :     }
     443           6 : }
     444             : 
     445             : /************************************************************************/
     446             : /*                         IsValidObjectName()                          */
     447             : /************************************************************************/
     448             : 
     449             : /* static */
     450         772 : bool ZarrGroupBase::IsValidObjectName(const std::string &osName)
     451             : {
     452        2230 :     return !(osName.empty() || osName == "." || osName == ".." ||
     453        1458 :              osName.find('/') != std::string::npos ||
     454        1442 :              osName.find('\\') != std::string::npos ||
     455         717 :              osName.find(':') != std::string::npos ||
     456        1481 :              STARTS_WITH(osName.c_str(), ".z"));
     457             : }
     458             : 
     459             : /************************************************************************/
     460             : /*             CheckArrayOrGroupWithSameNameDoesNotExist()              */
     461             : /************************************************************************/
     462             : 
     463          27 : bool ZarrGroupBase::CheckArrayOrGroupWithSameNameDoesNotExist(
     464             :     const std::string &osName) const
     465             : {
     466          54 :     const auto groupNames = GetGroupNames();
     467          27 :     if (std::find(groupNames.begin(), groupNames.end(), osName) !=
     468          54 :         groupNames.end())
     469             :     {
     470           9 :         CPLError(CE_Failure, CPLE_AppDefined,
     471             :                  "A group with same name already exists");
     472           9 :         return false;
     473             :     }
     474             : 
     475          36 :     const auto arrayNames = GetMDArrayNames();
     476          18 :     if (std::find(arrayNames.begin(), arrayNames.end(), osName) !=
     477          36 :         arrayNames.end())
     478             :     {
     479           6 :         CPLError(CE_Failure, CPLE_AppDefined,
     480             :                  "An array with same name already exists");
     481           6 :         return false;
     482             :     }
     483             : 
     484          12 :     return true;
     485             : }
     486             : 
     487             : /************************************************************************/
     488             : /*                               Rename()                               */
     489             : /************************************************************************/
     490             : 
     491          36 : bool ZarrGroupBase::Rename(const std::string &osNewName)
     492             : {
     493          36 :     if (!CheckValidAndErrorOutIfNot())
     494           3 :         return false;
     495             : 
     496          33 :     if (!m_bUpdatable)
     497             :     {
     498           6 :         CPLError(CE_Failure, CPLE_NotSupported,
     499             :                  "Dataset not open in update mode");
     500           6 :         return false;
     501             :     }
     502          27 :     if (!IsValidObjectName(osNewName))
     503             :     {
     504           6 :         CPLError(CE_Failure, CPLE_NotSupported, "Invalid group name");
     505           6 :         return false;
     506             :     }
     507          21 :     if (m_osName == "/")
     508             :     {
     509           6 :         CPLError(CE_Failure, CPLE_NotSupported, "Cannot rename root group");
     510           6 :         return false;
     511             :     }
     512             : 
     513          30 :     auto pParent = std::dynamic_pointer_cast<ZarrGroupBase>(m_poParent.lock());
     514          15 :     if (pParent)
     515             :     {
     516          15 :         if (!pParent->CheckArrayOrGroupWithSameNameDoesNotExist(osNewName))
     517           9 :             return false;
     518             :     }
     519             : 
     520          12 :     std::string osNewDirectoryName(m_osDirectoryName);
     521           6 :     osNewDirectoryName.resize(osNewDirectoryName.size() - m_osName.size());
     522           6 :     osNewDirectoryName += osNewName;
     523             : 
     524           6 :     if (VSIRename(m_osDirectoryName.c_str(), osNewDirectoryName.c_str()) != 0)
     525             :     {
     526           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Renaming of %s to %s failed",
     527             :                  m_osDirectoryName.c_str(), osNewDirectoryName.c_str());
     528           0 :         return false;
     529             :     }
     530             : 
     531           6 :     if (pParent)
     532             :     {
     533           6 :         auto oIter = pParent->m_oMapGroups.find(m_osName);
     534           6 :         if (oIter != pParent->m_oMapGroups.end())
     535             :         {
     536           6 :             pParent->m_oMapGroups.erase(oIter);
     537           6 :             CPLAssert(m_pSelf.lock());
     538          12 :             pParent->m_oMapGroups[osNewName] =
     539          18 :                 std::dynamic_pointer_cast<ZarrGroupBase>(m_pSelf.lock());
     540             :         }
     541             : 
     542           6 :         for (auto &osName : pParent->m_aosGroups)
     543             :         {
     544           6 :             if (osName == m_osName)
     545             :             {
     546           6 :                 osName = osNewName;
     547           6 :                 break;
     548             :             }
     549             :         }
     550             :     }
     551             : 
     552           6 :     m_poSharedResource->RenameZMetadataRecursive(m_osDirectoryName,
     553             :                                                  osNewDirectoryName);
     554             : 
     555           6 :     m_osDirectoryName = std::move(osNewDirectoryName);
     556             : 
     557           6 :     BaseRename(osNewName);
     558             : 
     559           6 :     return true;
     560             : }
     561             : 
     562             : /************************************************************************/
     563             : /*                           ParentRenamed()                            */
     564             : /************************************************************************/
     565             : 
     566           4 : void ZarrGroupBase::ParentRenamed(const std::string &osNewParentFullName)
     567             : {
     568           8 :     auto pParent = std::dynamic_pointer_cast<ZarrGroupBase>(m_poParent.lock());
     569             :     // The parent necessarily exist, since it notified us
     570           4 :     CPLAssert(pParent);
     571             : 
     572           8 :     m_osDirectoryName = CPLFormFilenameSafe(pParent->m_osDirectoryName.c_str(),
     573           4 :                                             m_osName.c_str(), nullptr);
     574             : 
     575           4 :     GDALGroup::ParentRenamed(osNewParentFullName);
     576           4 : }
     577             : 
     578             : /************************************************************************/
     579             : /*                      NotifyChildrenOfRenaming()                      */
     580             : /************************************************************************/
     581             : 
     582          10 : void ZarrGroupBase::NotifyChildrenOfRenaming()
     583             : {
     584          14 :     for (const auto &oIter : m_oMapGroups)
     585           4 :         oIter.second->ParentRenamed(m_osFullName);
     586             : 
     587          19 :     for (const auto &oIter : m_oMapMDArrays)
     588           9 :         oIter.second->ParentRenamed(m_osFullName);
     589             : 
     590          10 :     m_oAttrGroup.ParentRenamed(m_osFullName);
     591             : 
     592          16 :     for (const auto &oIter : m_oMapDimensions)
     593           6 :         oIter.second->ParentRenamed(m_osFullName);
     594          10 : }
     595             : 
     596             : /************************************************************************/
     597             : /*                   ZarrGroupBase::GetParentGroup()                    */
     598             : /************************************************************************/
     599             : 
     600          43 : std::shared_ptr<ZarrGroupBase> ZarrGroupBase::GetParentGroup() const
     601             : {
     602          43 :     std::shared_ptr<ZarrGroupBase> poGroup = m_poParent.lock();
     603          43 :     if (!poGroup)
     604             :     {
     605           2 :         if (auto poRootGroup = m_poSharedResource->GetRootGroup())
     606             :         {
     607           1 :             const auto nPos = m_osFullName.rfind('/');
     608           1 :             if (nPos != std::string::npos)
     609             :             {
     610           2 :                 poGroup = std::dynamic_pointer_cast<ZarrGroupBase>(
     611           3 :                     poRootGroup->OpenGroupFromFullname(m_osFullName.substr(
     612           3 :                         0, std::max(static_cast<size_t>(1), nPos))));
     613             :             }
     614             :         }
     615             :     }
     616          43 :     return poGroup;
     617             : }

Generated by: LCOV version 1.14