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

Generated by: LCOV version 1.14