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

Generated by: LCOV version 1.14