/* which would be an undesired effect... */ CPLErr VRTDataset::Delete( const char * pszFilename ) { GDALDriverH hDriver = GDALIdentifyDriver(pszFilename, NULL); if (hDriver && EQUAL(GDALGetDriverShortName(hDriver), "VRT")) { if( VSIUnlink( pszFilename ) != 0 ) { CPLError( CE_Failure, CPLE_AppDefined, "Deleting %s failed:\n%s", pszFilename, VSIStrerror(errno) ); return CE_Failure; } return CE_None; } else return CE_Failure; }
static void ProcessIdentifyTarget( const char *pszTarget, char **papszSiblingList, bool bRecursive, bool bReportFailures, bool bForceRecurse ) { GDALDriverH hDriver; VSIStatBufL sStatBuf; int i; hDriver = GDALIdentifyDriver( pszTarget, papszSiblingList ); if( hDriver != nullptr ) printf( "%s: %s\n", pszTarget, GDALGetDriverShortName( hDriver ) ); else if( bReportFailures ) printf( "%s: unrecognized\n", pszTarget ); if( !bForceRecurse && (!bRecursive || hDriver != nullptr) ) return; if( VSIStatL( pszTarget, &sStatBuf ) != 0 || !VSI_ISDIR( sStatBuf.st_mode ) ) return; papszSiblingList = VSIReadDir( pszTarget ); for( i = 0; papszSiblingList && papszSiblingList[i]; i++ ) { if( EQUAL(papszSiblingList[i],"..") || EQUAL(papszSiblingList[i],".") ) continue; CPLString osSubTarget = CPLFormFilename( pszTarget, papszSiblingList[i], nullptr ); ProcessIdentifyTarget( osSubTarget, papszSiblingList, bRecursive, bReportFailures, bForceRecurse ); } CSLDestroy(papszSiblingList); }
int main( int argc, char ** argv ) { EarlySetConfigOptions(argc, argv); /* -------------------------------------------------------------------- */ /* Register standard GDAL drivers, and process generic GDAL */ /* command options. */ /* -------------------------------------------------------------------- */ GDALAllRegister(); argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 ); if( argc < 1 ) exit( -argc ); for( int i = 0; argv != NULL && argv[i] != NULL; i++ ) { if( EQUAL(argv[i], "--utility_version") ) { printf("%s was compiled against GDAL %s and is running against GDAL %s\n", argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME")); CSLDestroy( argv ); return 0; } else if( EQUAL(argv[i],"--help") ) { Usage(NULL); } } GDALBuildVRTOptionsForBinary* psOptionsForBinary = GDALBuildVRTOptionsForBinaryNew(); /* coverity[tainted_data] */ GDALBuildVRTOptions *psOptions = GDALBuildVRTOptionsNew(argv + 1, psOptionsForBinary); CSLDestroy( argv ); if( psOptions == NULL ) { Usage(NULL); } if( psOptionsForBinary->pszDstFilename == NULL ) { Usage("No target filename specified."); } if( !(psOptionsForBinary->bQuiet) ) { GDALBuildVRTOptionsSetProgress(psOptions, GDALTermProgress, NULL); } /* Avoid overwriting a non VRT dataset if the user did not put the */ /* filenames in the right order */ VSIStatBuf sBuf; if (!psOptionsForBinary->bOverwrite) { int bExists = (VSIStat(psOptionsForBinary->pszDstFilename, &sBuf) == 0); if (bExists) { GDALDriverH hDriver = GDALIdentifyDriver( psOptionsForBinary->pszDstFilename, NULL ); if (hDriver && !(EQUAL(GDALGetDriverShortName(hDriver), "VRT") || (EQUAL(GDALGetDriverShortName(hDriver), "API_PROXY") && EQUAL(CPLGetExtension(psOptionsForBinary->pszDstFilename), "VRT"))) ) { fprintf(stderr, "'%s' is an existing GDAL dataset managed by %s driver.\n" "There is an high chance you did not put filenames in the right order.\n" "If you want to overwrite %s, add -overwrite option to the command line.\n\n", psOptionsForBinary->pszDstFilename, GDALGetDriverShortName(hDriver), psOptionsForBinary->pszDstFilename); Usage(); } } } int bUsageError = FALSE; GDALDatasetH hOutDS = GDALBuildVRT(psOptionsForBinary->pszDstFilename, psOptionsForBinary->nSrcFiles, NULL, (const char* const*)psOptionsForBinary->papszSrcFiles, psOptions, &bUsageError); if( bUsageError ) Usage(); int nRetCode = (hOutDS) ? 0 : 1; GDALBuildVRTOptionsFree(psOptions); GDALBuildVRTOptionsForBinaryFree(psOptionsForBinary); CPLErrorReset(); // The flush to disk is only done at that stage, so check if any error has // happened GDALClose( hOutDS ); if( CPLGetLastErrorType() != CE_None ) nRetCode = 1; GDALDumpOpenDatasets( stderr ); GDALDestroyDriverManager(); OGRCleanupAll(); return nRetCode; }
void GDALJP2AbstractDataset::LoadVectorLayers(int bOpenRemoteResources) { char** papszGMLJP2 = GetMetadata("xml:gml.root-instance"); if( papszGMLJP2 == NULL ) return; GDALDriver* poMemDriver = (GDALDriver*)GDALGetDriverByName("Memory"); if( poMemDriver == NULL ) return; CPLXMLNode* psRoot = CPLParseXMLString(papszGMLJP2[0]); if( psRoot == NULL ) return; CPLXMLNode* psCC = CPLGetXMLNode(psRoot, "=gmljp2:GMLJP2CoverageCollection"); if( psCC == NULL ) { CPLDestroyXMLNode(psRoot); return; } // Find feature collections CPLXMLNode* psCCChildIter = psCC->psChild; int nLayersAtCC = 0; int nLayersAtGC = 0; for( ; psCCChildIter != NULL; psCCChildIter = psCCChildIter->psNext ) { if( psCCChildIter->eType != CXT_Element || strcmp(psCCChildIter->pszValue, "gmljp2:featureMember") != 0 || psCCChildIter->psChild == NULL || psCCChildIter->psChild->eType != CXT_Element ) continue; CPLXMLNode* psGCorGMLJP2Features = psCCChildIter->psChild; int bIsGC = ( strstr(psGCorGMLJP2Features->pszValue, "GridCoverage") != NULL ); CPLXMLNode* psGCorGMLJP2FeaturesChildIter = psGCorGMLJP2Features->psChild; for( ; psGCorGMLJP2FeaturesChildIter != NULL; psGCorGMLJP2FeaturesChildIter = psGCorGMLJP2FeaturesChildIter->psNext ) { if( psGCorGMLJP2FeaturesChildIter->eType != CXT_Element || strcmp(psGCorGMLJP2FeaturesChildIter->pszValue, "gmljp2:feature") != 0 || psGCorGMLJP2FeaturesChildIter->psChild == NULL ) continue; CPLXMLNode* psFC = NULL; int bFreeFC = FALSE; CPLString osGMLTmpFile; CPLXMLNode* psChild = psGCorGMLJP2FeaturesChildIter->psChild; if( psChild->eType == CXT_Attribute && strcmp(psChild->pszValue, "xlink:href") == 0 && strncmp(psChild->psChild->pszValue, "gmljp2://xml/", strlen("gmljp2://xml/")) == 0 ) { const char* pszBoxName = psChild->psChild->pszValue + strlen("gmljp2://xml/"); char** papszBoxData = GetMetadata(CPLSPrintf("xml:%s", pszBoxName)); if( papszBoxData != NULL ) { psFC = CPLParseXMLString(papszBoxData[0]); bFreeFC = TRUE; } else { CPLDebug("GMLJP2", "gmljp2:feature references %s, but no corresponding box found", psChild->psChild->pszValue); } } if( psChild->eType == CXT_Attribute && strcmp(psChild->pszValue, "xlink:href") == 0 && (strncmp(psChild->psChild->pszValue, "http://", strlen("http://")) == 0 || strncmp(psChild->psChild->pszValue, "https://", strlen("https://")) == 0) ) { if( !bOpenRemoteResources ) CPLDebug("GMLJP2", "Remote feature collection %s mentionned in GMLJP2 box", psChild->psChild->pszValue); else osGMLTmpFile = "/vsicurl/" + CPLString(psChild->psChild->pszValue); } else if( psChild->eType == CXT_Element && strstr(psChild->pszValue, "FeatureCollection") != NULL ) { psFC = psChild; } if( psFC == NULL && osGMLTmpFile.size() == 0 ) continue; if( psFC != NULL ) { osGMLTmpFile = CPLSPrintf("/vsimem/gmljp2/%p/my.gml", this); // Create temporary .gml file CPLSerializeXMLTreeToFile(psFC, osGMLTmpFile); } CPLDebug("GMLJP2", "Found a FeatureCollection at %s level", (bIsGC) ? "GridCoverage" : "CoverageCollection"); CPLString osXSDTmpFile; if( psFC ) { // Try to localize its .xsd schema in a GMLJP2 auxiliary box const char* pszSchemaLocation = CPLGetXMLValue(psFC, "xsi:schemaLocation", NULL); if( pszSchemaLocation ) { char **papszTokens = CSLTokenizeString2( pszSchemaLocation, " \t\n", CSLT_HONOURSTRINGS | CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES); if( (CSLCount(papszTokens) % 2) == 0 ) { for(char** papszIter = papszTokens; *papszIter; papszIter += 2 ) { if( strncmp(papszIter[1], "gmljp2://xml/", strlen("gmljp2://xml/")) == 0 ) { const char* pszBoxName = papszIter[1] + strlen("gmljp2://xml/"); char** papszBoxData = GetMetadata(CPLSPrintf("xml:%s", pszBoxName)); if( papszBoxData != NULL ) { osXSDTmpFile = CPLSPrintf("/vsimem/gmljp2/%p/my.xsd", this); VSIFCloseL(VSIFileFromMemBuffer(osXSDTmpFile, (GByte*)papszBoxData[0], strlen(papszBoxData[0]), FALSE)); } else { CPLDebug("GMLJP2", "Feature collection references %s, but no corresponding box found", papszIter[1]); } break; } } } CSLDestroy(papszTokens); } if( bFreeFC ) { CPLDestroyXMLNode(psFC); psFC = NULL; } } GDALDriverH hDrv = GDALIdentifyDriver(osGMLTmpFile, NULL); GDALDriverH hGMLDrv = GDALGetDriverByName("GML"); if( hDrv != NULL && hDrv == hGMLDrv ) { char* apszOpenOptions[2]; apszOpenOptions[0] = (char*) "FORCE_SRS_DETECTION=YES"; apszOpenOptions[1] = NULL; GDALDataset* poTmpDS = (GDALDataset*)GDALOpenEx( osGMLTmpFile, GDAL_OF_VECTOR, NULL, apszOpenOptions, NULL ); if( poTmpDS ) { int nLayers = poTmpDS->GetLayerCount(); for(int i=0;i<nLayers;i++) { if( poMemDS == NULL ) poMemDS = poMemDriver->Create("", 0, 0, 0, GDT_Unknown, NULL); OGRLayer* poSrcLyr = poTmpDS->GetLayer(i); const char* pszLayerName; if( bIsGC ) pszLayerName = CPLSPrintf("FC_GridCoverage_%d_%s", ++nLayersAtGC, poSrcLyr->GetName()); else pszLayerName = CPLSPrintf("FC_CoverageCollection_%d_%s", ++nLayersAtCC, poSrcLyr->GetName()); poMemDS->CopyLayer(poSrcLyr, pszLayerName, NULL); } GDALClose(poTmpDS); // In case we don't have a schema, a .gfs might have been generated VSIUnlink(CPLSPrintf("/vsimem/gmljp2/%p/my.gfs", this)); } } else { CPLDebug("GMLJP2", "No GML driver found to read feature collection"); } if( strncmp(osGMLTmpFile, "/vsicurl/", strlen("/vsicurl/")) != 0 ) VSIUnlink(osGMLTmpFile); if( osXSDTmpFile.size() ) VSIUnlink(osXSDTmpFile); } } // Find annotations psCCChildIter = psCC->psChild; int nAnnotations = 0; for( ; psCCChildIter != NULL; psCCChildIter = psCCChildIter->psNext ) { if( psCCChildIter->eType != CXT_Element || strcmp(psCCChildIter->pszValue, "gmljp2:featureMember") != 0 || psCCChildIter->psChild == NULL || psCCChildIter->psChild->eType != CXT_Element ) continue; CPLXMLNode* psGCorGMLJP2Features = psCCChildIter->psChild; int bIsGC = ( strstr(psGCorGMLJP2Features->pszValue, "GridCoverage") != NULL ); if( !bIsGC ) continue; CPLXMLNode* psGCorGMLJP2FeaturesChildIter = psGCorGMLJP2Features->psChild; for( ; psGCorGMLJP2FeaturesChildIter != NULL; psGCorGMLJP2FeaturesChildIter = psGCorGMLJP2FeaturesChildIter->psNext ) { if( psGCorGMLJP2FeaturesChildIter->eType != CXT_Element || strcmp(psGCorGMLJP2FeaturesChildIter->pszValue, "gmljp2:annotation") != 0 || psGCorGMLJP2FeaturesChildIter->psChild == NULL || psGCorGMLJP2FeaturesChildIter->psChild->eType != CXT_Element || strstr(psGCorGMLJP2FeaturesChildIter->psChild->pszValue, "kml") == NULL ) continue; CPLDebug("GMLJP2", "Found a KML annotation"); // Create temporary .kml file CPLXMLNode* psKML = psGCorGMLJP2FeaturesChildIter->psChild; CPLString osKMLTmpFile(CPLSPrintf("/vsimem/gmljp2/%p/my.kml", this)); CPLSerializeXMLTreeToFile(psKML, osKMLTmpFile); GDALDataset* poTmpDS = (GDALDataset*)GDALOpenEx( osKMLTmpFile, GDAL_OF_VECTOR, NULL, NULL, NULL ); if( poTmpDS ) { int nLayers = poTmpDS->GetLayerCount(); for(int i=0;i<nLayers;i++) { if( poMemDS == NULL ) poMemDS = poMemDriver->Create("", 0, 0, 0, GDT_Unknown, NULL); OGRLayer* poSrcLyr = poTmpDS->GetLayer(i); const char* pszLayerName; pszLayerName = CPLSPrintf("Annotation_%d_%s", ++nAnnotations, poSrcLyr->GetName()); poMemDS->CopyLayer(poSrcLyr, pszLayerName, NULL); } GDALClose(poTmpDS); } else { CPLDebug("GMLJP2", "No KML/LIBKML driver found to read annotation"); } VSIUnlink(osKMLTmpFile); } } CPLDestroyXMLNode(psRoot); }
QgsDataItem *QgsOgrDataItemProvider::createDataItem( const QString &pathIn, QgsDataItem *parentItem ) { QString path( pathIn ); if ( path.isEmpty() ) return nullptr; QgsDebugMsgLevel( "thePath: " + path, 2 ); // zip settings + info QgsSettings settings; QString scanZipSetting = settings.value( QStringLiteral( "qgis/scanZipInBrowser2" ), "basic" ).toString(); QString vsiPrefix = QgsZipItem::vsiPrefix( path ); bool is_vsizip = ( vsiPrefix == QLatin1String( "/vsizip/" ) ); bool is_vsigzip = ( vsiPrefix == QLatin1String( "/vsigzip/" ) ); bool is_vsitar = ( vsiPrefix == QLatin1String( "/vsitar/" ) ); // should we check ext. only? // check if scanItemsInBrowser2 == extension or parent dir in scanItemsFastScanUris // TODO - do this in dir item, but this requires a way to inform which extensions are supported by provider // maybe a callback function or in the provider registry? bool scanExtSetting = false; if ( ( settings.value( QStringLiteral( "qgis/scanItemsInBrowser2" ), "extension" ).toString() == QLatin1String( "extension" ) ) || ( parentItem && settings.value( QStringLiteral( "qgis/scanItemsFastScanUris" ), QStringList() ).toStringList().contains( parentItem->path() ) ) || ( ( is_vsizip || is_vsitar ) && parentItem && parentItem->parent() && settings.value( QStringLiteral( "qgis/scanItemsFastScanUris" ), QStringList() ).toStringList().contains( parentItem->parent()->path() ) ) ) { scanExtSetting = true; } // get suffix, removing .gz if present QString tmpPath = path; //path used for testing, not for layer creation if ( is_vsigzip ) tmpPath.chop( 3 ); QFileInfo info( tmpPath ); QString suffix = info.suffix().toLower(); // extract basename with extension info.setFile( path ); QString name = info.fileName(); // If a .tab exists, then the corresponding .map/.dat is very likely a // side-car file of the .tab if ( suffix == QLatin1String( "map" ) || suffix == QLatin1String( "dat" ) ) { if ( QFileInfo( QDir( info.path() ), info.baseName() + ".tab" ).exists() ) return nullptr; } QgsDebugMsgLevel( "thePath= " + path + " tmpPath= " + tmpPath + " name= " + name + " suffix= " + suffix + " vsiPrefix= " + vsiPrefix, 3 ); QStringList myExtensions = fileExtensions(); QStringList dirExtensions = directoryExtensions(); // allow only normal files, supported directories, or VSIFILE items to continue bool isOgrSupportedDirectory = info.isDir() && dirExtensions.contains( suffix ); if ( !isOgrSupportedDirectory && !info.isFile() && vsiPrefix.isEmpty() ) return nullptr; // skip *.aux.xml files (GDAL auxiliary metadata files), // *.shp.xml files (ESRI metadata) and *.tif.xml files (TIFF metadata) // unless that extension is in the list (*.xml might be though) if ( path.endsWith( QLatin1String( ".aux.xml" ), Qt::CaseInsensitive ) && !myExtensions.contains( QStringLiteral( "aux.xml" ) ) ) return nullptr; if ( path.endsWith( QLatin1String( ".shp.xml" ), Qt::CaseInsensitive ) && !myExtensions.contains( QStringLiteral( "shp.xml" ) ) ) return nullptr; if ( path.endsWith( QLatin1String( ".tif.xml" ), Qt::CaseInsensitive ) && !myExtensions.contains( QStringLiteral( "tif.xml" ) ) ) return nullptr; // skip QGIS style xml files if ( path.endsWith( QLatin1String( ".xml" ), Qt::CaseInsensitive ) && QgsStyle::isXmlStyleFile( path ) ) return nullptr; // We have to filter by extensions, otherwise e.g. all Shapefile files are displayed // because OGR drive can open also .dbf, .shx. if ( myExtensions.indexOf( suffix ) < 0 && !dirExtensions.contains( suffix ) ) { bool matches = false; const auto constWildcards = wildcards(); for ( const QString &wildcard : constWildcards ) { QRegExp rx( wildcard, Qt::CaseInsensitive, QRegExp::Wildcard ); if ( rx.exactMatch( info.fileName() ) ) { matches = true; break; } } if ( !matches ) return nullptr; } // .dbf should probably appear if .shp is not present if ( suffix == QLatin1String( "dbf" ) ) { QString pathShp = path.left( path.count() - 4 ) + ".shp"; if ( QFileInfo::exists( pathShp ) ) return nullptr; } // fix vsifile path and name if ( !vsiPrefix.isEmpty() ) { // add vsiPrefix to path if needed if ( !path.startsWith( vsiPrefix ) ) path = vsiPrefix + path; // if this is a /vsigzip/path_to_zip.zip/file_inside_zip remove the full path from the name // no need to change the name I believe #if 0 if ( ( is_vsizip || is_vsitar ) && ( path != vsiPrefix + parentItem->path() ) ) { name = path; name = name.replace( vsiPrefix + parentItem->path() + '/', "" ); } #endif } // Filters out the OGR/GDAL supported formats that can contain multiple layers // and should be treated like a DB: GeoPackage and SQLite // NOTE: this formats are scanned for rasters too and they must // be skipped by "gdal" provider or the rasters will be listed // twice. ogrSupportedDbLayersExtensions must be kept in sync // with the companion variable (same name) in the gdal provider // class // TODO: add more OGR supported multiple layers formats here! static QStringList sOgrSupportedDbLayersExtensions { QStringLiteral( "gpkg" ), QStringLiteral( "sqlite" ), QStringLiteral( "db" ), QStringLiteral( "gdb" ), QStringLiteral( "kml" ) }; static QStringList sOgrSupportedDbDriverNames { QStringLiteral( "GPKG" ), QStringLiteral( "db" ), QStringLiteral( "gdb" ) }; // these extensions are trivial to read, so there's no need to rely on // the extension only scan here -- avoiding it always gives us the correct data type // and sublayer visiblity static QStringList sSkipFastTrackExtensions { QStringLiteral( "xlsx" ), QStringLiteral( "ods" ), QStringLiteral( "csv" ), QStringLiteral( "nc" ) }; // Fast track: return item without testing if: // scanExtSetting or zipfile and scan zip == "Basic scan" // netCDF files can be both raster or vector, so fallback to opening if ( ( scanExtSetting || ( ( is_vsizip || is_vsitar ) && scanZipSetting == QLatin1String( "basic" ) ) ) && !sSkipFastTrackExtensions.contains( suffix ) ) { // if this is a VRT file make sure it is vector VRT to avoid duplicates if ( suffix == QLatin1String( "vrt" ) ) { CPLPushErrorHandler( CPLQuietErrorHandler ); CPLErrorReset(); GDALDriverH hDriver = GDALIdentifyDriver( path.toUtf8().constData(), nullptr ); CPLPopErrorHandler(); if ( !hDriver || GDALGetDriverShortName( hDriver ) == QLatin1String( "VRT" ) ) { QgsDebugMsgLevel( QStringLiteral( "Skipping VRT file because root is not a OGR VRT" ), 2 ); return nullptr; } } // Handle collections // Check if the layer has sublayers by comparing the extension QgsDataItem *item = nullptr; if ( ! sOgrSupportedDbLayersExtensions.contains( suffix ) ) { item = new QgsOgrLayerItem( parentItem, name, path, path, QgsLayerItem::Vector ); } else if ( suffix.compare( QLatin1String( "gpkg" ), Qt::CaseInsensitive ) == 0 ) { item = new QgsGeoPackageCollectionItem( parentItem, name, path ); } else { item = new QgsOgrDataCollectionItem( parentItem, name, path ); } if ( item ) return item; } // Slow track: scan file contents QgsDataItem *item = nullptr; // test that file is valid with OGR if ( OGRGetDriverCount() == 0 ) { OGRRegisterAll(); } // do not print errors, but write to debug CPLPushErrorHandler( CPLQuietErrorHandler ); CPLErrorReset(); gdal::dataset_unique_ptr hDS( GDALOpenEx( path.toUtf8().constData(), GDAL_OF_VECTOR, nullptr, nullptr, nullptr ) ); CPLPopErrorHandler(); if ( ! hDS ) { QgsDebugMsg( QStringLiteral( "GDALOpen error # %1 : %2 on %3" ).arg( CPLGetLastErrorNo() ).arg( CPLGetLastErrorMsg() ).arg( path ) ); return nullptr; } GDALDriverH hDriver = GDALGetDatasetDriver( hDS.get() ); QString driverName = GDALGetDriverShortName( hDriver ); QgsDebugMsgLevel( QStringLiteral( "GDAL Driver : %1" ).arg( driverName ), 2 ); int numLayers = GDALDatasetGetLayerCount( hDS.get() ); // GeoPackage needs a specialized data item, mainly because of raster deletion not // yet implemented in GDAL (2.2.1) if ( driverName == QLatin1String( "GPKG" ) ) { item = new QgsGeoPackageCollectionItem( parentItem, name, path ); } else if ( numLayers > 1 || sOgrSupportedDbDriverNames.contains( driverName ) ) { item = new QgsOgrDataCollectionItem( parentItem, name, path ); } else { item = dataItemForLayer( parentItem, name, path, hDS.get(), 0, false, true ); } return item; }