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