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-09-10 17:48:50 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          10 :     char **GetFileList(void) override
      31             :     {
      32          20 :         CPLStringList aosList;
      33          10 :         if (!m_filename.empty())
      34           9 :             aosList.push_back(m_filename);
      35          20 :         return aosList.StealList();
      36             :     }
      37             : 
      38             :     static int Identify(GDALOpenInfo *poOpenInfo);
      39             :     static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
      40             : 
      41             :   protected:
      42         331 :     GDALDataset *RefUnderlyingDataset() const override
      43             :     {
      44         331 :         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          51 :     GDALDriver *GetDriver() override
      57             :     {
      58          51 :         return poDriver;
      59             :     }
      60             : 
      61          43 :     int GetLayerCount() const override
      62             :     {
      63          43 :         return m_poUnderlyingDS->GetLayerCount();
      64             :     }
      65             : 
      66          25 :     const OGRLayer *GetLayer(int idx) const override
      67             :     {
      68          25 :         return m_poUnderlyingDS->GetLayer(idx);
      69             :     }
      70             : 
      71           8 :     OGRLayer *GetLayerByName(const char *pszName) override
      72             :     {
      73           8 :         return m_poUnderlyingDS->GetLayerByName(pszName);
      74             :     }
      75             : 
      76          43 :     OGRLayer *ExecuteSQL(const char *pszStatement, OGRGeometry *poSpatialFilter,
      77             :                          const char *pszDialect) override
      78             :     {
      79          43 :         return m_poUnderlyingDS->ExecuteSQL(pszStatement, poSpatialFilter,
      80          43 :                                             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          57 :     int TestCapability(const char *pszCap) const override
      98             :     {
      99          57 :         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        1719 :     RefUnderlyingRasterBand(bool /* bForceOpen */) const override
     115             :     {
     116        1719 :         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          52 : GDALGDataset::GDALGDataset(const std::string &filename,
     132             :                            std::unique_ptr<GDALAlgorithm> poAlg,
     133          52 :                            GDALDataset *poDS)
     134          52 :     : m_filename(filename), m_poAlg(std::move(poAlg)), m_poUnderlyingDS(poDS)
     135             : {
     136          52 :     nRasterXSize = m_poUnderlyingDS->GetRasterXSize();
     137          52 :     nRasterYSize = m_poUnderlyingDS->GetRasterYSize();
     138         118 :     for (int i = 0; i < m_poUnderlyingDS->GetRasterCount(); ++i)
     139             :     {
     140          66 :         SetBand(i + 1, std::make_unique<GDALGRasterBand>(
     141         132 :                            m_poUnderlyingDS->GetRasterBand(i + 1)));
     142             :     }
     143          52 : }
     144             : 
     145             : /************************************************************************/
     146             : /*                GDALGDataset::UnrefUnderlyingDataset()                */
     147             : /************************************************************************/
     148             : 
     149         331 : void GDALGDataset::UnrefUnderlyingDataset(GDALDataset *) const
     150             : {
     151         331 : }
     152             : 
     153             : /************************************************************************/
     154             : /*                    GDALGRasterBand::GDALGRasterBand()                */
     155             : /************************************************************************/
     156             : 
     157          66 : GDALGRasterBand::GDALGRasterBand(GDALRasterBand *poUnderlyingBand)
     158          66 :     : m_poUnderlyingBand(poUnderlyingBand)
     159             : {
     160          66 :     nBand = poUnderlyingBand->GetBand();
     161          66 :     eDataType = poUnderlyingBand->GetRasterDataType();
     162          66 :     nRasterXSize = poUnderlyingBand->GetXSize();
     163          66 :     nRasterYSize = poUnderlyingBand->GetYSize();
     164          66 :     poUnderlyingBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
     165          66 : }
     166             : 
     167             : /************************************************************************/
     168             : /*             GDALGRasterBand::UnrefUnderlyingDataset()                */
     169             : /************************************************************************/
     170             : 
     171        1719 : void GDALGRasterBand::UnrefUnderlyingRasterBand(GDALRasterBand *) const
     172             : {
     173        1719 : }
     174             : 
     175             : /************************************************************************/
     176             : /*                         GDALGDataset::Identify()                     */
     177             : /************************************************************************/
     178             : 
     179       67395 : /* static */ int GDALGDataset::Identify(GDALOpenInfo *poOpenInfo)
     180             : {
     181       67395 :     return poOpenInfo->IsSingleAllowedDriver("GDALG") ||
     182       67390 :            (poOpenInfo->pabyHeader &&
     183       11003 :             strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
     184      134783 :                    "\"gdal_streamed_alg\"")) ||
     185      134740 :            (strstr(poOpenInfo->pszFilename, "\"gdal_streamed_alg\""));
     186             : }
     187             : 
     188             : /************************************************************************/
     189             : /*                         GDALGDataset::Open()                         */
     190             : /************************************************************************/
     191             : 
     192          75 : /* static */ GDALDataset *GDALGDataset::Open(GDALOpenInfo *poOpenInfo)
     193             : {
     194         150 :     CPLJSONDocument oDoc;
     195          75 :     if (poOpenInfo->pabyHeader)
     196             :     {
     197          40 :         if (!oDoc.Load(poOpenInfo->pszFilename))
     198             :         {
     199           2 :             return nullptr;
     200             :         }
     201             :     }
     202             :     else
     203             :     {
     204          70 :         if (!oDoc.LoadMemory(
     205          35 :                 reinterpret_cast<const char *>(poOpenInfo->pszFilename)))
     206             :         {
     207           1 :             return nullptr;
     208             :         }
     209             :     }
     210          72 :     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          71 :     if (poOpenInfo->eAccess == GA_Update)
     217             :     {
     218           1 :         ReportUpdateNotSupportedByDriver("GDALG");
     219           1 :         return nullptr;
     220             :     }
     221             : 
     222         210 :     const std::string osCommandLine = oDoc.GetRoot().GetString("command_line");
     223          70 :     if (osCommandLine.empty())
     224             :     {
     225           1 :         CPLError(CE_Failure, CPLE_AppDefined, "command_line missing");
     226           1 :         return nullptr;
     227             :     }
     228             : 
     229          14 :     const auto CheckVersion = [&oDoc]()
     230             :     {
     231          42 :         const std::string osVersion = oDoc.GetRoot().GetString("gdal_version");
     232          19 :         if (!osVersion.empty() &&
     233           5 :             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          14 :     };
     242             : 
     243         138 :     const CPLStringList aosArgs(CSLTokenizeString(osCommandLine.c_str()));
     244             : 
     245          69 :     auto alg = GDALGlobalAlgorithmRegistry::GetSingleton().Instantiate(
     246         207 :         GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME);
     247             : 
     248         106 :     if (poOpenInfo->pabyHeader &&
     249         106 :         oDoc.GetRoot().GetBool("relative_paths_relative_to_this_file", true))
     250             :     {
     251          66 :         alg->SetReferencePathForRelativePaths(
     252          44 :             CPLGetPathSafe(poOpenInfo->pszFilename).c_str());
     253             :     }
     254             : 
     255          69 :     alg->SetExecutionForStreamedOutput();
     256             : 
     257         138 :     alg->SetCallPath(std::vector<std::string>{aosArgs[0]});
     258         138 :     std::vector<std::string> args;
     259         499 :     for (int i = 1; i < aosArgs.size(); ++i)
     260         430 :         args.push_back(aosArgs[i]);
     261          69 :     if (!alg->ParseCommandLineArguments(args))
     262             :     {
     263           3 :         CheckVersion();
     264           3 :         return nullptr;
     265             :     }
     266          66 :     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          65 :     if (!alg->Run(nullptr, nullptr))
     275             :     {
     276          11 :         CheckVersion();
     277          11 :         return nullptr;
     278             :     }
     279             : 
     280          54 :     std::unique_ptr<GDALDataset> ret;
     281          54 :     const auto outputArg = alg->GetActualAlgorithm().GetArg("output");
     282          54 :     if (outputArg && outputArg->GetType() == GAAT_DATASET)
     283             :     {
     284          54 :         auto &val = outputArg->Get<GDALArgDatasetValue>();
     285          54 :         auto poUnderlyingDS = val.GetDatasetRef();
     286          54 :         if (poUnderlyingDS)
     287             :         {
     288          54 :             if ((poOpenInfo->nOpenFlags & GDAL_OF_RASTER) &&
     289          36 :                 !(poOpenInfo->nOpenFlags & GDAL_OF_VECTOR))
     290             :             {
     291             :                 // Don't return if asked for a raster dataset but the
     292             :                 // underlying one is not.
     293          36 :                 if (poUnderlyingDS->GetRasterCount() == 0 &&
     294           1 :                     !poUnderlyingDS->GetMetadata("SUBDATASETS"))
     295             :                 {
     296           2 :                     return nullptr;
     297             :                 }
     298             :             }
     299          19 :             else if (!(poOpenInfo->nOpenFlags & GDAL_OF_RASTER) &&
     300          18 :                      (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR))
     301             :             {
     302             :                 // Don't return if asked for a vector dataset but the
     303             :                 // underlying one is not.
     304          18 :                 if (poUnderlyingDS->GetLayerCount() == 0)
     305             :                 {
     306           1 :                     return nullptr;
     307             :                 }
     308             :             }
     309          52 :             ret = std::make_unique<GDALGDataset>(
     310         104 :                 poOpenInfo->pabyHeader ? poOpenInfo->pszFilename : "",
     311         104 :                 std::move(alg), poUnderlyingDS);
     312             :         }
     313             :     }
     314             : 
     315          52 :     return ret.release();
     316             : }
     317             : 
     318             : /************************************************************************/
     319             : /*                       GDALRegister_GDALG()                           */
     320             : /************************************************************************/
     321             : 
     322        2024 : void GDALRegister_GDALG()
     323             : {
     324        2024 :     if (GDALGetDriverByName("GDALG") != nullptr)
     325         283 :         return;
     326             : 
     327        3482 :     auto poDriver = std::make_unique<GDALDriver>();
     328             : 
     329        1741 :     poDriver->SetDescription("GDALG");
     330        1741 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     331        1741 :     poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
     332        1741 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
     333        1741 :                               "GDAL Streamed Algorithm driver");
     334        1741 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "gdalg.json");
     335             : 
     336        1741 :     poDriver->SetMetadataItem(GDAL_DCAP_MEASURED_GEOMETRIES, "YES");
     337        1741 :     poDriver->SetMetadataItem(GDAL_DCAP_CURVE_GEOMETRIES, "YES");
     338        1741 :     poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES");
     339             : 
     340        1741 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     341             : 
     342        1741 :     poDriver->pfnIdentify = GDALGDataset::Identify;
     343        1741 :     poDriver->pfnOpen = GDALGDataset::Open;
     344             : 
     345        1741 :     GetGDALDriverManager()->RegisterDriver(poDriver.release());
     346             : }

Generated by: LCOV version 1.14