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

Generated by: LCOV version 1.14