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