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-08-22 15:37:05 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       75392 : /* static */ int GDALGDataset::Identify(GDALOpenInfo *poOpenInfo)
     186             : {
     187       75392 :     return poOpenInfo->IsSingleAllowedDriver("GDALG") ||
     188       75390 :            (poOpenInfo->pabyHeader &&
     189       13598 :             strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
     190      150782 :                    "\"gdal_streamed_alg\"")) ||
     191      150718 :            (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         194 :     const CPLStringList aosArgs(CSLTokenizeString(osCommandLine.c_str()));
     230          97 :     if (aosArgs.empty())
     231             :     {
     232           1 :         CPLError(CE_Failure, CPLE_AppDefined, "command_line missing");
     233           1 :         return nullptr;
     234             :     }
     235             : 
     236          14 :     const auto CheckVersion = [&oDoc]()
     237             :     {
     238          42 :         const std::string osVersion = oDoc.GetRoot().GetString("gdal_version");
     239          19 :         if (!osVersion.empty() &&
     240           5 :             atoi(GDALVersionInfo("VERSION_NUM")) < atoi(osVersion.c_str()))
     241             :         {
     242           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     243             :                      "The failure might be due to the .gdalg.json file having "
     244             :                      "been created with GDAL VERSION_NUM=%s which is newer "
     245             :                      "than current GDAL VERSION_NUM=%s",
     246             :                      osVersion.c_str(), GDALVersionInfo("VERSION_NUM"));
     247             :         }
     248          14 :     };
     249             : 
     250          96 :     auto alg = GDALGlobalAlgorithmRegistry::GetSingleton().Instantiate(
     251         288 :         GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME);
     252             : 
     253         156 :     if (poOpenInfo->pabyHeader &&
     254         156 :         oDoc.GetRoot().GetBool("relative_paths_relative_to_this_file", true))
     255             :     {
     256          72 :         alg->SetReferencePathForRelativePaths(
     257          48 :             CPLGetPathSafe(poOpenInfo->pszFilename).c_str());
     258             :     }
     259             : 
     260          96 :     alg->SetExecutionForStreamedOutput();
     261             : 
     262         192 :     alg->SetCallPath(std::vector<std::string>{aosArgs[0]});
     263         192 :     std::vector<std::string> args;
     264         720 :     for (int i = 1; i < aosArgs.size(); ++i)
     265         624 :         args.push_back(aosArgs[i]);
     266          96 :     if (!alg->ParseCommandLineArguments(args))
     267             :     {
     268           3 :         CheckVersion();
     269           3 :         return nullptr;
     270             :     }
     271          93 :     if (!alg->GetActualAlgorithm().SupportsStreamedOutput())
     272             :     {
     273           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     274             :                  "Algorithm %s does not support a streamed output",
     275           1 :                  alg->GetActualAlgorithm().GetName().c_str());
     276           1 :         return nullptr;
     277             :     }
     278             : 
     279          92 :     if (!alg->Run(nullptr, nullptr))
     280             :     {
     281          11 :         CheckVersion();
     282          11 :         return nullptr;
     283             :     }
     284             : 
     285          81 :     std::unique_ptr<GDALDataset> ret;
     286          81 :     const auto outputArg = alg->GetActualAlgorithm().GetArg("output");
     287          81 :     if (outputArg && outputArg->GetType() == GAAT_DATASET)
     288             :     {
     289          81 :         auto &val = outputArg->Get<GDALArgDatasetValue>();
     290          81 :         auto poUnderlyingDS = val.GetDatasetRef();
     291          81 :         if (poUnderlyingDS)
     292             :         {
     293          81 :             if ((poOpenInfo->nOpenFlags & GDAL_OF_RASTER) &&
     294          39 :                 !(poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) &&
     295          18 :                 !(poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER))
     296             :             {
     297             :                 // Don't return if asked for a raster dataset but the
     298             :                 // underlying one is not.
     299          19 :                 if (poUnderlyingDS->GetRasterCount() == 0 &&
     300           1 :                     !poUnderlyingDS->GetMetadata(GDAL_MDD_SUBDATASETS))
     301             :                 {
     302           2 :                     return nullptr;
     303             :                 }
     304             :             }
     305          63 :             else if ((poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) &&
     306          62 :                      !(poOpenInfo->nOpenFlags & GDAL_OF_RASTER) &&
     307          41 :                      !(poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER))
     308             :             {
     309             :                 // Don't return if asked for a vector dataset but the
     310             :                 // underlying one is not.
     311          41 :                 if (poUnderlyingDS->GetLayerCount() == 0)
     312             :                 {
     313           1 :                     return nullptr;
     314             :                 }
     315             :             }
     316          22 :             else if ((poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER) &&
     317           1 :                      !(poOpenInfo->nOpenFlags & GDAL_OF_RASTER) &&
     318           1 :                      !(poOpenInfo->nOpenFlags & GDAL_OF_VECTOR))
     319             :             {
     320             :                 // Don't return if asked for a multidim dataset but the
     321             :                 // underlying one is not.
     322           1 :                 if (!poUnderlyingDS->GetRootGroup())
     323             :                 {
     324           0 :                     return nullptr;
     325             :                 }
     326             :             }
     327          79 :             ret = std::make_unique<GDALGDataset>(
     328         158 :                 poOpenInfo->pabyHeader ? poOpenInfo->pszFilename : "",
     329         158 :                 std::move(alg), poUnderlyingDS);
     330             :         }
     331             :     }
     332             : 
     333          79 :     return ret.release();
     334             : }
     335             : 
     336             : /************************************************************************/
     337             : /*                         GDALRegister_GDALG()                         */
     338             : /************************************************************************/
     339             : 
     340        2138 : void GDALRegister_GDALG()
     341             : {
     342        2138 :     if (GDALGetDriverByName("GDALG") != nullptr)
     343         263 :         return;
     344             : 
     345        3750 :     auto poDriver = std::make_unique<GDALDriver>();
     346             : 
     347        1875 :     poDriver->SetDescription("GDALG");
     348        1875 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     349        1875 :     poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
     350        1875 :     poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
     351        1875 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
     352        1875 :                               "GDAL Streamed Algorithm driver");
     353        1875 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "gdalg.json");
     354             : 
     355        1875 :     poDriver->SetMetadataItem(GDAL_DCAP_MEASURED_GEOMETRIES, "YES");
     356        1875 :     poDriver->SetMetadataItem(GDAL_DCAP_CURVE_GEOMETRIES, "YES");
     357        1875 :     poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES");
     358             : 
     359        1875 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     360             : 
     361        1875 :     poDriver->pfnIdentify = GDALGDataset::Identify;
     362        1875 :     poDriver->pfnOpen = GDALGDataset::Open;
     363             : 
     364        1875 :     GetGDALDriverManager()->RegisterDriver(poDriver.release());
     365             : }

Generated by: LCOV version 1.14