Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: OpenGIS Simple Features Reference Implementation 4 : * Purpose: Implements OGRVRTDriver class. 5 : * Author: Frank Warmerdam, warmerdam@pobox.com 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com> 9 : * Copyright (c) 2009-2014, Even Rouault <even dot rouault at spatialys.com> 10 : * 11 : * SPDX-License-Identifier: MIT 12 : ****************************************************************************/ 13 : 14 : #include "cpl_port.h" 15 : #include "ogr_vrt.h" 16 : 17 : #include <cctype> 18 : #include <cstddef> 19 : #include <cstdio> 20 : #include <cstring> 21 : #include <limits> 22 : #include <memory> 23 : #include <vector> 24 : 25 : #include "cpl_conv.h" 26 : #include "cpl_error.h" 27 : #include "cpl_minixml.h" 28 : #include "cpl_string.h" 29 : #include "cpl_vsi.h" 30 : #include "gdal.h" 31 : #include "gdal_priv.h" 32 : 33 : /************************************************************************/ 34 : /* OGRVRTErrorHandler() */ 35 : /************************************************************************/ 36 : 37 68 : static void CPL_STDCALL OGRVRTErrorHandler(CPL_UNUSED CPLErr eErr, 38 : CPL_UNUSED CPLErrorNum nType, 39 : const char *pszMsg) 40 : { 41 : std::vector<CPLString> *paosErrors = 42 68 : static_cast<std::vector<CPLString> *>(CPLGetErrorHandlerUserData()); 43 68 : paosErrors->push_back(pszMsg); 44 68 : } 45 : 46 : /************************************************************************/ 47 : /* OGRVRTDriverIdentify() */ 48 : /************************************************************************/ 49 : 50 49612 : static int OGRVRTDriverIdentify(GDALOpenInfo *poOpenInfo) 51 : { 52 49612 : if (!poOpenInfo->bStatOK) 53 : { 54 : // Are we being passed the XML definition directly? 55 : // Skip any leading spaces/blanks. 56 43166 : const char *pszTestXML = poOpenInfo->pszFilename; 57 43197 : while (*pszTestXML != '\0' && 58 42378 : isspace(static_cast<unsigned char>(*pszTestXML))) 59 31 : pszTestXML++; 60 43166 : if (STARTS_WITH_CI(pszTestXML, "<OGRVRTDataSource>")) 61 : { 62 108 : return TRUE; 63 : } 64 43058 : return FALSE; 65 : } 66 : 67 12142 : return poOpenInfo->fpL != nullptr && 68 5696 : strstr(reinterpret_cast<char *>(poOpenInfo->pabyHeader), 69 6446 : "<OGRVRTDataSource") != nullptr; 70 : } 71 : 72 : /************************************************************************/ 73 : /* Open() */ 74 : /************************************************************************/ 75 : 76 403 : static GDALDataset *OGRVRTDriverOpen(GDALOpenInfo *poOpenInfo) 77 : 78 : { 79 : #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 80 403 : if (!OGRVRTDriverIdentify(poOpenInfo)) 81 0 : return nullptr; 82 : #endif 83 : 84 : // Are we being passed the XML definition directly? 85 : // Skip any leading spaces/blanks. 86 403 : const char *pszTestXML = poOpenInfo->pszFilename; 87 414 : while (*pszTestXML != '\0' && 88 414 : isspace(static_cast<unsigned char>(*pszTestXML))) 89 11 : pszTestXML++; 90 : 91 403 : char *pszXML = nullptr; 92 403 : if (STARTS_WITH_CI(pszTestXML, "<OGRVRTDataSource>")) 93 : { 94 54 : pszXML = CPLStrdup(pszTestXML); 95 : } 96 : 97 : // Open file and check if it contains appropriate XML. 98 : else 99 : { 100 : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 101 : if (poOpenInfo->fpL == nullptr) 102 : return nullptr; 103 : #endif 104 : VSIStatBufL sStatBuf; 105 349 : if (VSIStatL(poOpenInfo->pszFilename, &sStatBuf) != 0) 106 : { 107 0 : return nullptr; 108 : } 109 349 : if (sStatBuf.st_size > 10 * 1024 * 1024 && 110 0 : !CPLTestBool(CPLGetConfigOption("OGR_VRT_FORCE_LOADING", "NO"))) 111 : { 112 0 : CPLError(CE_Failure, CPLE_AppDefined, 113 : "Suscipicously long VRT file. If you really want to " 114 : "open it, define OGR_VRT_FORCE_LOADING=YES as " 115 : "configuration option"); 116 0 : return nullptr; 117 : } 118 698 : if (static_cast<uint64_t>(sStatBuf.st_size) > 119 349 : std::numeric_limits<size_t>::max() - 1) 120 : { 121 0 : return nullptr; 122 : } 123 : 124 : // It is the right file, now load the full XML definition. 125 349 : const size_t nLen = static_cast<size_t>(sStatBuf.st_size); 126 : 127 349 : pszXML = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen + 1)); 128 349 : if (pszXML == nullptr) 129 0 : return nullptr; 130 : 131 349 : pszXML[nLen] = '\0'; 132 349 : VSIFSeekL(poOpenInfo->fpL, 0, SEEK_SET); 133 349 : if (VSIFReadL(pszXML, 1, nLen, poOpenInfo->fpL) != nLen) 134 : { 135 0 : CPLFree(pszXML); 136 0 : return nullptr; 137 : } 138 349 : VSIFCloseL(poOpenInfo->fpL); 139 349 : poOpenInfo->fpL = nullptr; 140 : } 141 : 142 : // Parse the XML. 143 403 : CPLXMLNode *psTree = CPLParseXMLString(pszXML); 144 : 145 403 : if (psTree == nullptr) 146 : { 147 1 : CPLFree(pszXML); 148 1 : return nullptr; 149 : } 150 : 151 : // XML Validation. 152 402 : if (CPLTestBool(CPLGetConfigOption("GDAL_XML_VALIDATION", "YES"))) 153 : { 154 402 : const char *pszXSD = CPLFindFile("gdal", "ogrvrt.xsd"); 155 402 : if (pszXSD != nullptr) 156 : { 157 804 : std::vector<CPLString> aosErrors; 158 402 : CPLPushErrorHandlerEx(OGRVRTErrorHandler, &aosErrors); 159 402 : const int bRet = CPLValidateXML(pszXML, pszXSD, nullptr); 160 402 : CPLPopErrorHandler(); 161 402 : if (!bRet) 162 : { 163 110 : if (!aosErrors.empty() && 164 55 : strstr(aosErrors[0].c_str(), "missing libxml2 support") == 165 : nullptr) 166 : { 167 118 : for (size_t i = 0; i < aosErrors.size(); i++) 168 : { 169 63 : CPLError(CE_Warning, CPLE_AppDefined, "%s", 170 63 : aosErrors[i].c_str()); 171 : } 172 : } 173 : } 174 402 : CPLErrorReset(); 175 : } 176 : } 177 402 : CPLFree(pszXML); 178 : 179 : // Create a virtual datasource configured based on this XML input. 180 : OGRVRTDataSource *poDS = new OGRVRTDataSource( 181 402 : static_cast<GDALDriver *>(GDALGetDriverByName("OGR_VRT"))); 182 : 183 : // psTree is owned by poDS. 184 402 : if (!poDS->Initialize(psTree, poOpenInfo->pszFilename, 185 402 : poOpenInfo->eAccess == GA_Update)) 186 : { 187 1 : delete poDS; 188 1 : return nullptr; 189 : } 190 : 191 401 : return poDS; 192 : } 193 : 194 : /************************************************************************/ 195 : /* RegisterOGRVRT() */ 196 : /************************************************************************/ 197 : 198 1595 : void RegisterOGRVRT() 199 : 200 : { 201 1595 : if (GDALGetDriverByName("OGR_VRT") != nullptr) 202 302 : return; 203 : 204 1293 : GDALDriver *poDriver = new GDALDriver(); 205 : 206 1293 : poDriver->SetDescription("OGR_VRT"); 207 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); 208 1293 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "VRT - Virtual Datasource"); 209 1293 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "vrt"); 210 1293 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/vrt.html"); 211 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 212 1293 : poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES, "YES"); 213 1293 : poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES_READ, "YES"); 214 1293 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, "YES"); 215 1293 : poDriver->SetMetadataItem(GDAL_DCAP_CURVE_GEOMETRIES, "YES"); 216 1293 : poDriver->SetMetadataItem(GDAL_DCAP_MEASURED_GEOMETRIES, "YES"); 217 1293 : poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES"); 218 1293 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); 219 : 220 1293 : poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS, 221 : "WidthPrecision Nullable Unique Default " 222 1293 : "Comment AlternativeName"); 223 : 224 1293 : poDriver->pfnOpen = OGRVRTDriverOpen; 225 1293 : poDriver->pfnIdentify = OGRVRTDriverIdentify; 226 : 227 1293 : GetGDALDriverManager()->RegisterDriver(poDriver); 228 : }