LCOV - code coverage report
Current view: top level - frmts/zarr - zarrdrivercore.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 61 61 100.0 %
Date: 2026-06-28 22:25:56 Functions: 4 4 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 "zarrdrivercore.h"
      14             : #include "gdal_frmts.h"
      15             : #include "gdalplugindriverproxy.h"
      16             : 
      17             : #include "cpl_string.h"
      18             : #include "cpl_vsi_virtual.h"
      19             : #include "vsikerchunk.h"
      20             : #include "vsikerchunk_inline.hpp"
      21             : 
      22             : /************************************************************************/
      23             : /*                    CheckExistenceOfOneZarrFile()                     */
      24             : /************************************************************************/
      25             : 
      26        3397 : static bool CheckExistenceOfOneZarrFile(const char *pszFilename)
      27             : {
      28             : 
      29             :     CPLString osMDFilename =
      30        6794 :         CPLFormFilenameSafe(pszFilename, ".zarray", nullptr);
      31        3397 :     if (VSIFilesystemHandler::OpenStatic(osMDFilename, "rb"))
      32         632 :         return true;
      33             : 
      34        2765 :     osMDFilename = CPLFormFilenameSafe(pszFilename, ".zgroup", nullptr);
      35        2765 :     if (VSIFilesystemHandler::OpenStatic(osMDFilename, "rb"))
      36         438 :         return true;
      37             : 
      38             :     // Zarr V3
      39        2327 :     osMDFilename = CPLFormFilenameSafe(pszFilename, "zarr.json", nullptr);
      40        2327 :     if (VSIFilesystemHandler::OpenStatic(osMDFilename, "rb"))
      41        1950 :         return true;
      42             : 
      43         377 :     return false;
      44             : }
      45             : 
      46             : /************************************************************************/
      47             : /*                    ZARRIsLikelyKerchunkJSONRef()                     */
      48             : /************************************************************************/
      49             : 
      50       63046 : bool ZARRIsLikelyKerchunkJSONRef(const GDALOpenInfo *poOpenInfo)
      51             : {
      52       66205 :     if (poOpenInfo->nHeaderBytes > 0 && poOpenInfo->eAccess == GA_ReadOnly &&
      53        3159 :         (poOpenInfo->IsExtensionEqualToCI("json") ||
      54             :          // e.g. like in https://noaa-nodd-kerchunk-pds.s3.amazonaws.com/nos/cbofs/cbofs.fields.best.nc.zarr
      55        1490 :          poOpenInfo->IsExtensionEqualToCI("zarr")))
      56             :     {
      57         188 :         const char *pszHeader =
      58             :             reinterpret_cast<const char *>(poOpenInfo->pabyHeader);
      59         188 :         if (ZARRIsLikelyStreamableKerchunkJSONRefContent(
      60         376 :                 std::string_view(pszHeader, poOpenInfo->nHeaderBytes)))
      61             :         {
      62          57 :             return true;
      63             :         }
      64             :     }
      65       62989 :     return false;
      66             : }
      67             : 
      68             : /************************************************************************/
      69             : /*                         ZARRDriverIdentify()                         */
      70             : /************************************************************************/
      71             : 
      72       61518 : int ZARRDriverIdentify(GDALOpenInfo *poOpenInfo)
      73             : 
      74             : {
      75       61518 :     const std::string_view osvFilename(poOpenInfo->pszFilename);
      76      122876 :     if (cpl::starts_with(osvFilename, "ZARR:") ||
      77      122876 :         cpl::starts_with(osvFilename, "ZARR_DUMMY:"))
      78             :     {
      79         162 :         return TRUE;
      80             :     }
      81             : 
      82       61356 :     if (ZARRIsLikelyKerchunkJSONRef(poOpenInfo))
      83             :     {
      84          38 :         return TRUE;
      85             :     }
      86       61318 :     if (cpl::starts_with(osvFilename, JSON_REF_FS_PREFIX))
      87             :     {
      88           4 :         return -1;
      89             :     }
      90      245154 :     for (const char *pszFile :
      91      306468 :          {".zarray", ".zgroup", ".zmetadata", "zarr.json"})
      92             :     {
      93      245244 :         if (cpl::ends_with(osvFilename, pszFile))
      94             :         {
      95          90 :             return TRUE;
      96             :         }
      97             :     }
      98       61224 :     if (!poOpenInfo->bIsDirectory)
      99             :     {
     100       57827 :         return FALSE;
     101             :     }
     102             : 
     103        3397 :     return CheckExistenceOfOneZarrFile(poOpenInfo->pszFilename);
     104             : }
     105             : 
     106             : /************************************************************************/
     107             : /*                    ZARRDriverSetCommonMetadata()                     */
     108             : /************************************************************************/
     109             : 
     110        1873 : void ZARRDriverSetCommonMetadata(GDALDriver *poDriver)
     111             : {
     112        1873 :     poDriver->SetDescription(DRIVER_NAME);
     113        1873 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     114        1873 :     poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
     115        1873 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Zarr");
     116        1873 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "zarr");
     117        1873 :     poDriver->SetMetadataItem(
     118             :         GDAL_DMD_CREATIONDATATYPES,
     119             :         "Int8 Byte Int16 UInt16 Int32 UInt32 Int64 UInt64 "
     120        1873 :         "Float16 Float32 Float64 CFLoat16 CFloat32 CFloat64");
     121        1873 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     122        1873 :     poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
     123        1873 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE_SUBDATASETS, "YES");
     124             : 
     125        1873 :     poDriver->SetMetadataItem(
     126             :         GDAL_DMD_OPENOPTIONLIST,
     127             :         "<OpenOptionList>"
     128             :         "   <Option name='LIST_ALL_ARRAYS' type='boolean' "
     129             :         "description='Whether to list all arrays, and not only those whose "
     130             :         "dimension count is 2 or more' default='NO'/>"
     131             :         "   <Option name='USE_CONSOLIDATED_METADATA' alias='USE_ZMETADATA' "
     132             :         "type='boolean' description='Whether "
     133             :         "to use consolidated metadata' default='YES'/>"
     134             :         "   <Option name='CACHE_TILE_PRESENCE' type='boolean' "
     135             :         "description='Whether to establish an initial listing of present "
     136             :         "tiles' default='NO'/>"
     137             :         "   <Option name='CACHE_KERCHUNK_JSON' type='boolean' "
     138             :         "description='Whether to transform Kerchunk JSON reference files into "
     139             :         "Kerchunk Parquet reference files in a local cache' default='NO'/>"
     140             :         "   <Option name='MULTIBAND' type='boolean' default='YES' "
     141             :         "description='Whether to expose >= 3D arrays as GDAL multiband "
     142             :         "datasets "
     143             :         "(when using the classic 2D API)'/>"
     144             :         "   <Option name='DIM_X' type='string' description="
     145             :         "'Name or index of the X dimension (only used when MULTIBAND=YES)'/>"
     146             :         "   <Option name='DIM_Y' type='string' description="
     147             :         "'Name or index of the Y dimension (only used when MULTIBAND=YES)'/>"
     148             :         "   <Option name='LOAD_EXTRA_DIM_METADATA_DELAY' type='string' "
     149             :         "description="
     150             :         "'Maximum delay in seconds allowed to set the DIM_{dimname}_VALUE band "
     151             :         "metadata items'/>"
     152        1873 :         "</OpenOptionList>");
     153             : 
     154        1873 :     poDriver->SetMetadataItem(
     155             :         GDAL_DMD_MULTIDIM_DATASET_CREATIONOPTIONLIST,
     156             :         "<MultiDimDatasetCreationOptionList>"
     157             :         "   <Option name='FORMAT' type='string-select' default='ZARR_V3'>"
     158             :         "     <Value>ZARR_V2</Value>"
     159             :         "     <Value>ZARR_V3</Value>"
     160             :         "   </Option>"
     161             :         "   <Option name='CREATE_CONSOLIDATED_METADATA' "
     162             :         "alias='CREATE_ZMETADATA' type='boolean' "
     163             :         "description='Whether to create consolidated metadata' default='YES'/>"
     164        1873 :         "</MultiDimDatasetCreationOptionList>");
     165             : 
     166        1873 :     poDriver->pfnIdentify = ZARRDriverIdentify;
     167        1873 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
     168        1873 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
     169        1873 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
     170        1873 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE_MULTIDIMENSIONAL, "YES");
     171             : 
     172        3746 :     poDriver->DeclareAlgorithm({"add-georeferencing-convention"});
     173             : 
     174        1873 :     poDriver->SetMetadataItem(GDAL_DCAP_UPDATE, "YES");
     175        1873 :     poDriver->SetMetadataItem(GDAL_DMD_UPDATE_ITEMS,
     176             :                               "GeoTransform SRS NoData "
     177             :                               "RasterValues "
     178        1873 :                               "DatasetMetadata BandMetadata");
     179        1873 : }
     180             : 
     181             : /************************************************************************/
     182             : /*                     DeclareDeferredZarrPlugin()                      */
     183             : /************************************************************************/
     184             : 
     185             : #ifdef PLUGIN_FILENAME
     186             : void DeclareDeferredZarrPlugin()
     187             : {
     188             :     if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
     189             :     {
     190             :         return;
     191             :     }
     192             :     auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
     193             : #ifdef PLUGIN_INSTALLATION_MESSAGE
     194             :     poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
     195             :                               PLUGIN_INSTALLATION_MESSAGE);
     196             : #endif
     197             :     ZARRDriverSetCommonMetadata(poDriver);
     198             :     GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     199             : 
     200             :     const auto loadLambda = []()
     201             :     {
     202             :         auto poDrv = GetGDALDriverManager()->GetDriverByName(DRIVER_NAME);
     203             :         // Querying any non-standard driver metadata forces the plugin
     204             :         // to be loaded.
     205             :         if (poDrv)
     206             :             poDrv->GetMetadata("FORCE_LOAD");
     207             :     };
     208             : 
     209             :     // trigger the loading of the plugin if Kerchunk related file systems are
     210             :     // queried.
     211             :     VSIFileManager::RegisterHandlerLoader(JSON_REF_FS_PREFIX, loadLambda);
     212             :     VSIFileManager::RegisterHandlerLoader(PARQUET_REF_FS_PREFIX, loadLambda);
     213             : }
     214             : #endif

Generated by: LCOV version 1.14