LCOV - code coverage report
Current view: top level - frmts/postgisraster - postgisrasterdrivercore.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 42 73 57.5 %
Date: 2025-01-18 12:42:00 Functions: 8 11 72.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * File :    PostGISRasterDriver.cpp
       3             :  * Project:  PostGIS Raster driver
       4             :  * Purpose:  Implements PostGIS Raster driver class methods
       5             :  * Author:   Jorge Arevalo, jorge.arevalo@deimos-space.com
       6             :  *
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2010, Jorge Arevalo, jorge.arevalo@deimos-space.com
      10             :  * Copyright (c) 2013, Even Rouault
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ******************************************************************************/
      14             : 
      15             : #include <stdexcept>
      16             : 
      17             : #include "postgisrasterdrivercore.h"
      18             : 
      19             : /************************************************************************/
      20             : /*                     PostGISRasterDriverIdentify()                    */
      21             : /************************************************************************/
      22             : 
      23       51362 : int PostGISRasterDriverIdentify(GDALOpenInfo *poOpenInfo)
      24             : 
      25             : {
      26       51362 :     if (poOpenInfo->pszFilename == nullptr || poOpenInfo->fpL != nullptr ||
      27       48129 :         !STARTS_WITH_CI(poOpenInfo->pszFilename, "PG:"))
      28             :     {
      29       51358 :         return FALSE;
      30             :     }
      31             : 
      32             :     // Will avoid a OGR PostgreSQL connection string to be recognized as a
      33             :     // PostgisRaster one and later fail (#6034)
      34           4 :     if (strstr(poOpenInfo->pszFilename, " schemas=") ||
      35           4 :         strstr(poOpenInfo->pszFilename, " SCHEMAS="))
      36             :     {
      37           0 :         return FALSE;
      38             :     }
      39             : 
      40           4 :     return TRUE;
      41             : }
      42             : 
      43             : /**************************************************************
      44             :  * \brief Replace the single quotes by " in the input string
      45             :  *
      46             :  * Needed before tokenize function
      47             :  *************************************************************/
      48           2 : static char *ReplaceSingleQuotes(const char *pszInput, int nLength)
      49             : {
      50             :     int i;
      51           2 :     char *pszOutput = nullptr;
      52             : 
      53           2 :     if (nLength == -1)
      54           2 :         nLength = static_cast<int>(strlen(pszInput));
      55             : 
      56           2 :     pszOutput = static_cast<char *>(CPLCalloc(nLength + 1, sizeof(char)));
      57             : 
      58         106 :     for (i = 0; i < nLength; i++)
      59             :     {
      60         104 :         if (pszInput[i] == '\'')
      61          12 :             pszOutput[i] = '"';
      62             :         else
      63          92 :             pszOutput[i] = pszInput[i];
      64             :     }
      65             : 
      66           2 :     return pszOutput;
      67             : }
      68             : 
      69             : /***********************************************************************
      70             :  * \brief Split connection string into user, password, host, database...
      71             :  *
      72             :  * The parameters separated by spaces are return as a list of strings.
      73             :  * The function accepts all the PostgreSQL recognized parameter keywords.
      74             :  *
      75             :  * The returned list must be freed with CSLDestroy when no longer needed
      76             :  **********************************************************************/
      77           2 : char **PostGISRasterParseConnectionString(const char *pszConnectionString)
      78             : {
      79             : 
      80             :     /* Escape string following SQL scheme */
      81             :     char *pszEscapedConnectionString =
      82           2 :         ReplaceSingleQuotes(pszConnectionString, -1);
      83             : 
      84             :     /* Avoid PG: part */
      85           2 :     char *pszStartPos = strstr(pszEscapedConnectionString, ":") + 1;
      86             : 
      87             :     /* Tokenize */
      88             :     char **papszParams =
      89           2 :         CSLTokenizeString2(pszStartPos, " ", CSLT_HONOURSTRINGS);
      90             : 
      91             :     /* Free */
      92           2 :     CPLFree(pszEscapedConnectionString);
      93             : 
      94           2 :     return papszParams;
      95             : }
      96             : 
      97             : /************************************************************************/
      98             : /*                    PostGISRasterDriverGetSubdatasetInfo()            */
      99             : /************************************************************************/
     100             : 
     101             : struct PostGISRasterDriverSubdatasetInfo : public GDALSubdatasetInfo
     102             : {
     103             :   public:
     104           0 :     explicit PostGISRasterDriverSubdatasetInfo(const std::string &fileName)
     105           0 :         : GDALSubdatasetInfo(fileName)
     106             :     {
     107           0 :     }
     108             : 
     109             :     // GDALSubdatasetInfo interface
     110             :   private:
     111           0 :     void parseFileName() override
     112             :     {
     113           0 :         if (!STARTS_WITH_CI(m_fileName.c_str(), "PG:"))
     114             :         {
     115           0 :             return;
     116             :         }
     117             : 
     118             :         char **papszParams =
     119           0 :             PostGISRasterParseConnectionString(m_fileName.c_str());
     120             : 
     121           0 :         const int nTableIdx = CSLFindName(papszParams, "table");
     122           0 :         if (nTableIdx != -1)
     123             :         {
     124           0 :             size_t nTableStart = m_fileName.find("table=");
     125           0 :             bool bHasQuotes{false};
     126             :             try
     127             :             {
     128           0 :                 bHasQuotes = m_fileName.at(nTableStart + 6) == '\'';
     129             :             }
     130           0 :             catch (const std::out_of_range &)
     131             :             {
     132             :                 // ignore error
     133             :             }
     134             : 
     135           0 :             m_subdatasetComponent = papszParams[nTableIdx];
     136             : 
     137           0 :             if (bHasQuotes)
     138             :             {
     139           0 :                 m_subdatasetComponent.insert(6, "'");
     140           0 :                 m_subdatasetComponent.push_back('\'');
     141             :             }
     142             : 
     143           0 :             m_driverPrefixComponent = "PG";
     144             : 
     145           0 :             size_t nPathLength = m_subdatasetComponent.length();
     146           0 :             if (nTableStart != 0)
     147             :             {
     148           0 :                 nPathLength++;
     149           0 :                 nTableStart--;
     150             :             }
     151             : 
     152           0 :             m_pathComponent = m_fileName;
     153           0 :             m_pathComponent.erase(nTableStart, nPathLength);
     154           0 :             m_pathComponent.erase(0, 3);
     155             :         }
     156             : 
     157           0 :         CSLDestroy(papszParams);
     158             :     }
     159             : };
     160             : 
     161             : static GDALSubdatasetInfo *
     162        2623 : PostGISRasterDriverGetSubdatasetInfo(const char *pszFileName)
     163             : {
     164        2623 :     if (STARTS_WITH_CI(pszFileName, "PG:"))
     165             :     {
     166             :         std::unique_ptr<GDALSubdatasetInfo> info =
     167           0 :             std::make_unique<PostGISRasterDriverSubdatasetInfo>(pszFileName);
     168           0 :         if (!info->GetSubdatasetComponent().empty() &&
     169           0 :             !info->GetPathComponent().empty())
     170             :         {
     171           0 :             return info.release();
     172             :         }
     173             :     }
     174        2623 :     return nullptr;
     175             : }
     176             : 
     177             : /************************************************************************/
     178             : /*                PostGISRasterDriverSetCommonMetadata()                */
     179             : /************************************************************************/
     180             : 
     181        1390 : void PostGISRasterDriverSetCommonMetadata(GDALDriver *poDriver)
     182             : {
     183        1390 :     poDriver->SetDescription(DRIVER_NAME);
     184        1390 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     185        1390 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "PostGIS Raster driver");
     186        1390 :     poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
     187             : 
     188        1390 :     poDriver->pfnIdentify = PostGISRasterDriverIdentify;
     189        1390 :     poDriver->pfnGetSubdatasetInfoFunc = PostGISRasterDriverGetSubdatasetInfo;
     190             : 
     191        1390 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
     192        1390 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
     193        1390 : }
     194             : 
     195             : /************************************************************************/
     196             : /*                   DeclareDeferredPostGISRasterPlugin()               */
     197             : /************************************************************************/
     198             : 
     199             : #ifdef PLUGIN_FILENAME
     200        1682 : void DeclareDeferredPostGISRasterPlugin()
     201             : {
     202        1682 :     if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
     203             :     {
     204         301 :         return;
     205             :     }
     206        1381 :     auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
     207             : #ifdef PLUGIN_INSTALLATION_MESSAGE
     208             :     poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
     209             :                               PLUGIN_INSTALLATION_MESSAGE);
     210             : #endif
     211        1381 :     PostGISRasterDriverSetCommonMetadata(poDriver);
     212        1381 :     GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     213             : }
     214             : #endif

Generated by: LCOV version 1.14