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 56446 : int PostGISRasterDriverIdentify(GDALOpenInfo *poOpenInfo) 24 : 25 : { 26 56446 : if (poOpenInfo->pszFilename == nullptr || poOpenInfo->fpL != nullptr || 27 53093 : !STARTS_WITH_CI(poOpenInfo->pszFilename, "PG:")) 28 : { 29 56442 : 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 : void parseFileName() override; 112 : }; 113 : 114 0 : void PostGISRasterDriverSubdatasetInfo::parseFileName() 115 : { 116 0 : if (!STARTS_WITH_CI(m_fileName.c_str(), "PG:")) 117 : { 118 0 : return; 119 : } 120 : 121 0 : char **papszParams = PostGISRasterParseConnectionString(m_fileName.c_str()); 122 : 123 0 : const int nTableIdx = CSLFindName(papszParams, "table"); 124 0 : if (nTableIdx != -1) 125 : { 126 0 : size_t nTableStart = m_fileName.find("table="); 127 0 : bool bHasQuotes{false}; 128 : try 129 : { 130 0 : bHasQuotes = m_fileName.at(nTableStart + 6) == '\''; 131 : } 132 0 : catch (const std::out_of_range &) 133 : { 134 : // ignore error 135 : } 136 : 137 0 : m_subdatasetComponent = papszParams[nTableIdx]; 138 : 139 0 : if (bHasQuotes) 140 : { 141 0 : m_subdatasetComponent.insert(6, "'"); 142 0 : m_subdatasetComponent.push_back('\''); 143 : } 144 : 145 0 : m_driverPrefixComponent = "PG"; 146 : 147 0 : size_t nPathLength = m_subdatasetComponent.length(); 148 0 : if (nTableStart != 0) 149 : { 150 0 : nPathLength++; 151 0 : nTableStart--; 152 : } 153 : 154 0 : m_pathComponent = m_fileName; 155 0 : m_pathComponent.erase(nTableStart, nPathLength); 156 0 : m_pathComponent.erase(0, 3); 157 : } 158 : 159 0 : CSLDestroy(papszParams); 160 : } 161 : 162 : static GDALSubdatasetInfo * 163 2670 : PostGISRasterDriverGetSubdatasetInfo(const char *pszFileName) 164 : { 165 2670 : 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 2670 : return nullptr; 176 : } 177 : 178 : /************************************************************************/ 179 : /* PostGISRasterDriverSetCommonMetadata() */ 180 : /************************************************************************/ 181 : 182 1639 : void PostGISRasterDriverSetCommonMetadata(GDALDriver *poDriver) 183 : { 184 1639 : poDriver->SetDescription(DRIVER_NAME); 185 1639 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); 186 1639 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "PostGIS Raster driver"); 187 1639 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES"); 188 : 189 1639 : poDriver->pfnIdentify = PostGISRasterDriverIdentify; 190 1639 : poDriver->pfnGetSubdatasetInfoFunc = PostGISRasterDriverGetSubdatasetInfo; 191 : 192 1639 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); 193 1639 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES"); 194 1639 : } 195 : 196 : /************************************************************************/ 197 : /* DeclareDeferredPostGISRasterPlugin() */ 198 : /************************************************************************/ 199 : 200 : #ifdef PLUGIN_FILENAME 201 1911 : void DeclareDeferredPostGISRasterPlugin() 202 : { 203 1911 : if (GDALGetDriverByName(DRIVER_NAME) != nullptr) 204 : { 205 282 : return; 206 : } 207 1629 : 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 1629 : PostGISRasterDriverSetCommonMetadata(poDriver); 213 1629 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver); 214 : } 215 : #endif