LCOV - code coverage report
Current view: top level - frmts/gdalg - gdalgdriver.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 146 147 99.3 %
Date: 2026-06-19 21:24:00 Functions: 20 20 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  GDAL Algorithm driver
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2025, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_json.h"
      14             : #include "cpl_string.h"
      15             : 
      16             : #include "gdalalgorithm.h"
      17             : #include "gdal_frmts.h"
      18             : #include "gdal_proxy.h"
      19             : #include "gdal_priv.h"
      20             : 
      21             : /************************************************************************/
      22             : /*                             GDALGDataset                             */
      23             : /************************************************************************/
      24             : 
      25             : class GDALGDataset final : public GDALProxyDataset
      26             : {
      27             :   public:
      28             :     GDALGDataset(const std::string &filename,
      29             :                  std::unique_ptr<GDALAlgorithm> poAlg, GDALDataset *poDS);
      30             : 
      31          21 :     char **GetFileList(void) override
      32             :     {
      33          42 :         CPLStringList aosList;
      34          21 :         if (!m_filename.empty())
      35          20 :             aosList.push_back(m_filename);
      36          42 :         return aosList.StealList();
      37             :     }
      38             : 
      39             :     static int Identify(GDALOpenInfo *poOpenInfo);
      40             :     static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
      41             : 
      42             :   protected:
      43         436 :     GDALDataset *RefUnderlyingDataset() const override
      44             :     {
      45         436 :         return m_poUnderlyingDS;
      46             :     }
      47             : 
      48             :     void UnrefUnderlyingDataset(GDALDataset *) const override;
      49             : 
      50             :   private:
      51             :     const std::string m_filename;
      52             :     std::unique_ptr<GDALAlgorithm> m_poAlg{};
      53             :     GDALDataset *m_poUnderlyingDS = nullptr;
      54             : 
      55             :     CPL_DISALLOW_COPY_ASSIGN(GDALGDataset)
      56             : 
      57         110 :     GDALDriver *GetDriver() const override
      58             :     {
      59         110 :         return poDriver;
      60             :     }
      61             : 
      62         113 :     int GetLayerCount() const override
      63             :     {
      64         113 :         return m_poUnderlyingDS->GetLayerCount();
      65             :     }
      66             : 
      67          64 :     const OGRLayer *GetLayer(int idx) const override
      68             :     {
      69          64 :         return m_poUnderlyingDS->GetLayer(idx);
      70             :     }
      71             : 
      72          19 :     OGRLayer *GetLayerByName(const char *pszName) override
      73             :     {
      74          19 :         return m_poUnderlyingDS->GetLayerByName(pszName);
      75             :     }
      76             : 
      77         129 :     OGRLayer *ExecuteSQL(const char *pszStatement, OGRGeometry *poSpatialFilter,
      78             :                          const char *pszDialect) override
      79             :     {
      80         129 :         return m_poUnderlyingDS->ExecuteSQL(pszStatement, poSpatialFilter,
      81         129 :                                             pszDialect);
      82             :     }
      83             : 
      84           1 :     void ResetReading() override
      85             :     {
      86           1 :         m_poUnderlyingDS->ResetReading();
      87           1 :     }
      88             : 
      89          11 :     OGRFeature *GetNextFeature(OGRLayer **ppoBelongingLayer,
      90             :                                double *pdfProgressPct,
      91             :                                GDALProgressFunc pfnProgress,
      92             :                                void *pProgressData) override
      93             :     {
      94          11 :         return m_poUnderlyingDS->GetNextFeature(
      95          11 :             ppoBelongingLayer, pdfProgressPct, pfnProgress, pProgressData);
      96             :     }
      97             : 
      98         144 :     int TestCapability(const char *pszCap) const override
      99             :     {
     100         144 :         return m_poUnderlyingDS->TestCapability(pszCap);
     101             :     }
     102             : 
     103           1 :     std::shared_ptr<GDALGroup> GetRootGroup() const override
     104             :     {
     105           1 :         return m_poUnderlyingDS->GetRootGroup();
     106             :     }
     107             : };
     108             : 
     109             : /************************************************************************/
     110             : /*                           GDALGRasterBand                            */
     111             : /************************************************************************/
     112             : 
     113             : class GDALGRasterBand final : public GDALProxyRasterBand
     114             : {
     115             :   public:
     116             :     explicit GDALGRasterBand(GDALRasterBand *poUnderlyingBand);
     117             : 
     118             :   protected:
     119             :     GDALRasterBand *
     120        1767 :     RefUnderlyingRasterBand(bool /* bForceOpen */) const override
     121             :     {
     122        1767 :         return m_poUnderlyingBand;
     123             :     }
     124             : 
     125             :     void UnrefUnderlyingRasterBand(GDALRasterBand *) const override;
     126             : 
     127             :   private:
     128             :     GDALRasterBand *m_poUnderlyingBand = nullptr;
     129             : 
     130             :     CPL_DISALLOW_COPY_ASSIGN(GDALGRasterBand)
     131             : };
     132             : 
     133             : /************************************************************************/
     134             : /*                     GDALGDataset::GDALGDataset()                     */
     135             : /************************************************************************/
     136             : 
     137          79 : GDALGDataset::GDALGDataset(const std::string &filename,
     138             :                            std::unique_ptr<GDALAlgorithm> poAlg,
     139          79 :                            GDALDataset *poDS)
     140          79 :     : m_filename(filename), m_poAlg(std::move(poAlg)), m_poUnderlyingDS(poDS)
     141             : {
     142          79 :     nRasterXSize = m_poUnderlyingDS->GetRasterXSize();
     143          79 :     nRasterYSize = m_poUnderlyingDS->GetRasterYSize();
     144         148 :     for (int i = 0; i < m_poUnderlyingDS->GetRasterCount(); ++i)
     145             :     {
     146          69 :         SetBand(i + 1, std::make_unique<GDALGRasterBand>(
     147         138 :                            m_poUnderlyingDS->GetRasterBand(i + 1)));
     148             :     }
     149          79 : }
     150             : 
     151             : /************************************************************************/
     152             : /*                GDALGDataset::UnrefUnderlyingDataset()                */
     153             : /************************************************************************/
     154             : 
     155         436 : void GDALGDataset::UnrefUnderlyingDataset(GDALDataset *) const
     156             : {
     157         436 : }
     158             : 
     159             : /************************************************************************/
     160             : /*                  GDALGRasterBand::GDALGRasterBand()                  */
     161             : /************************************************************************/
     162             : 
     163          69 : GDALGRasterBand::GDALGRasterBand(GDALRasterBand *poUnderlyingBand)
     164          69 :     : m_poUnderlyingBand(poUnderlyingBand)
     165             : {
     166          69 :     nBand = poUnderlyingBand->GetBand();
     167          69 :     eDataType = poUnderlyingBand->GetRasterDataType();
     168          69 :     nRasterXSize = poUnderlyingBand->GetXSize();
     169          69 :     nRasterYSize = poUnderlyingBand->GetYSize();
     170          69 :     poUnderlyingBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
     171          69 : }
     172             : 
     173             : /************************************************************************/
     174             : /*              GDALGRasterBand::UnrefUnderlyingDataset()               */
     175             : /************************************************************************/
     176             : 
     177        1767 : void GDALGRasterBand::UnrefUnderlyingRasterBand(GDALRasterBand *) const
     178             : {
     179        1767 : }
     180             : 
     181             : /************************************************************************/
     182             : /*                       GDALGDataset::Identify()                       */
     183             : /************************************************************************/
     184             : 
     185       74946 : /* static */ int GDALGDataset::Identify(GDALOpenInfo *poOpenInfo)
     186             : {
     187       74946 :     return poOpenInfo->IsSingleAllowedDriver("GDALG") ||
     188       74944 :            (poOpenInfo->pabyHeader &&
     189       13508 :             strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
     190      149890 :                    "\"gdal_streamed_alg\"")) ||
     191      149826 :            (strstr(poOpenInfo->pszFilename, "\"gdal_streamed_alg\""));
     192             : }
     193             : 
     194             : /************************************************************************/
     195             : /*                         GDALGDataset::Open()                         */
     196             : /************************************************************************/
     197             : 
     198         102 : /* static */ GDALDataset *GDALGDataset::Open(GDALOpenInfo *poOpenInfo)
     199             : {
     200         204 :     CPLJSONDocument oDoc;
     201         102 :     if (poOpenInfo->pabyHeader)
     202             :     {
     203          63 :         if (!oDoc.Load(poOpenInfo->pszFilename))
     204             :         {
     205           2 :             return nullptr;
     206             :         }
     207             :     }
     208             :     else
     209             :     {
     210          78 :         if (!oDoc.LoadMemory(
     211          39 :                 reinterpret_cast<const char *>(poOpenInfo->pszFilename)))
     212             :         {
     213           1 :             return nullptr;
     214             :         }
     215             :     }
     216          99 :     if (oDoc.GetRoot().GetString("type") != "gdal_streamed_alg")
     217             :     {
     218           1 :         CPLDebug("GDALG", "\"type\" = \"gdal_streamed_alg\" missing");
     219           1 :         return nullptr;
     220             :     }
     221             : 
     222          98 :     if (poOpenInfo->eAccess == GA_Update)
     223             :     {
     224           1 :         ReportUpdateNotSupportedByDriver("GDALG");
     225           1 :         return nullptr;
     226             :     }
     227             : 
     228         291 :     const std::string osCommandLine = oDoc.GetRoot().GetString("command_line");
     229          97 :     if (osCommandLine.empty())
     230             :     {
     231           1 :         CPLError(CE_Failure, CPLE_AppDefined, "command_line missing");
     232           1 :         return nullptr;
     233             :     }
     234             : 
     235          14 :     const auto CheckVersion = [&oDoc]()
     236             :     {
     237          42 :         const std::string osVersion = oDoc.GetRoot().GetString("gdal_version");
     238          19 :         if (!osVersion.empty() &&
     239           5 :             atoi(GDALVersionInfo("VERSION_NUM")) < atoi(osVersion.c_str()))
     240             :         {
     241           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     242             :                      "The failure might be due to the .gdalg.json file having "
     243             :                      "been created with GDAL VERSION_NUM=%s which is newer "
     244             :                      "than current GDAL VERSION_NUM=%s",
     245             :                      osVersion.c_str(), GDALVersionInfo("VERSION_NUM"));
     246             :         }
     247          14 :     };
     248             : 
     249         192 :     const CPLStringList aosArgs(CSLTokenizeString(osCommandLine.c_str()));
     250             : 
     251          96 :     auto alg = GDALGlobalAlgorithmRegistry::GetSingleton().Instantiate(
     252         288 :         GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME);
     253             : 
     254         156 :     if (poOpenInfo->pabyHeader &&
     255         156 :         oDoc.GetRoot().GetBool("relative_paths_relative_to_this_file", true))
     256             :     {
     257          72 :         alg->SetReferencePathForRelativePaths(
     258          48 :             CPLGetPathSafe(poOpenInfo->pszFilename).c_str());
     259             :     }
     260             : 
     261          96 :     alg->SetExecutionForStreamedOutput();
     262             : 
     263         192 :     alg->SetCallPath(std::vector<std::string>{aosArgs[0]});
     264         192 :     std::vector<std::string> args;
     265         720 :     for (int i = 1; i < aosArgs.size(); ++i)
     266         624 :         args.push_back(aosArgs[i]);
     267          96 :     if (!alg->ParseCommandLineArguments(args))
     268             :     {
     269           3 :         CheckVersion();
     270           3 :         return nullptr;
     271             :     }
     272          93 :     if (!alg->GetActualAlgorithm().SupportsStreamedOutput())
     273             :     {
     274           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     275             :                  "Algorithm %s does not support a streamed output",
     276           1 :                  alg->GetActualAlgorithm().GetName().c_str());
     277           1 :         return nullptr;
     278             :     }
     279             : 
     280          92 :     if (!alg->Run(nullptr, nullptr))
     281             :     {
     282          11 :         CheckVersion();
     283          11 :         return nullptr;
     284             :     }
     285             : 
     286          81 :     std::unique_ptr<GDALDataset> ret;
     287          81 :     const auto outputArg = alg->GetActualAlgorithm().GetArg("output");
     288          81 :     if (outputArg && outputArg->GetType() == GAAT_DATASET)
     289             :     {
     290          81 :         auto &val = outputArg->Get<GDALArgDatasetValue>();
     291          81 :         auto poUnderlyingDS = val.GetDatasetRef();
     292          81 :         if (poUnderlyingDS)
     293             :         {
     294          81 :             if ((poOpenInfo->nOpenFlags & GDAL_OF_RASTER) &&
     295          39 :                 !(poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) &&
     296          38 :                 !(poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER))
     297             :             {
     298             :                 // Don't return if asked for a raster dataset but the
     299             :                 // underlying one is not.
     300          39 :                 if (poUnderlyingDS->GetRasterCount() == 0 &&
     301           1 :                     !poUnderlyingDS->GetMetadata(GDAL_MDD_SUBDATASETS))
     302             :                 {
     303           2 :                     return nullptr;
     304             :                 }
     305             :             }
     306          43 :             else if ((poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) &&
     307          42 :                      !(poOpenInfo->nOpenFlags & GDAL_OF_RASTER) &&
     308          41 :                      !(poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER))
     309             :             {
     310             :                 // Don't return if asked for a vector dataset but the
     311             :                 // underlying one is not.
     312          41 :                 if (poUnderlyingDS->GetLayerCount() == 0)
     313             :                 {
     314           1 :                     return nullptr;
     315             :                 }
     316             :             }
     317           2 :             else if ((poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER) &&
     318           1 :                      !(poOpenInfo->nOpenFlags & GDAL_OF_RASTER) &&
     319           1 :                      !(poOpenInfo->nOpenFlags & GDAL_OF_VECTOR))
     320             :             {
     321             :                 // Don't return if asked for a multidim dataset but the
     322             :                 // underlying one is not.
     323           1 :                 if (!poUnderlyingDS->GetRootGroup())
     324             :                 {
     325           0 :                     return nullptr;
     326             :                 }
     327             :             }
     328          79 :             ret = std::make_unique<GDALGDataset>(
     329         158 :                 poOpenInfo->pabyHeader ? poOpenInfo->pszFilename : "",
     330         158 :                 std::move(alg), poUnderlyingDS);
     331             :         }
     332             :     }
     333             : 
     334          79 :     return ret.release();
     335             : }
     336             : 
     337             : /************************************************************************/
     338             : /*                         GDALRegister_GDALG()                         */
     339             : /************************************************************************/
     340             : 
     341        2135 : void GDALRegister_GDALG()
     342             : {
     343        2135 :     if (GDALGetDriverByName("GDALG") != nullptr)
     344         263 :         return;
     345             : 
     346        3744 :     auto poDriver = std::make_unique<GDALDriver>();
     347             : 
     348        1872 :     poDriver->SetDescription("GDALG");
     349        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     350        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
     351        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
     352        1872 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
     353        1872 :                               "GDAL Streamed Algorithm driver");
     354        1872 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "gdalg.json");
     355             : 
     356        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_MEASURED_GEOMETRIES, "YES");
     357        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_CURVE_GEOMETRIES, "YES");
     358        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES");
     359             : 
     360        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     361             : 
     362        1872 :     poDriver->pfnIdentify = GDALGDataset::Identify;
     363        1872 :     poDriver->pfnOpen = GDALGDataset::Open;
     364             : 
     365        1872 :     GetGDALDriverManager()->RegisterDriver(poDriver.release());
     366             : }

Generated by: LCOV version 1.14