EVOLUTION-MANAGER
Edit File: gdalsrsinfo.cpp
/****************************************************************************** * * Project: GDAL Utilities * Purpose: Command line application to list info about a given CRS. * Outputs a number of formats (WKT, PROJ.4, etc.). * Author: Frank Warmerdam, warmerdam@pobox.com * Etienne Tourigny, etourigny.dev-at-gmail-dot-com * * **************************************************************************** * Copyright (c) 1998, Frank Warmerdam * Copyright (c) 2011-2013, Even Rouault <even dot rouault at mines-paris dot org> * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************/ #include "gdal_priv.h" #include "cpl_string.h" #include "ogr_spatialref.h" #include "ogr_api.h" #include "ogrsf_frmts.h" #include "commonutils.h" CPL_CVSID("$Id: gdalsrsinfo.cpp 36537 2016-11-27 23:51:56Z goatbar $"); bool FindSRS( const char *pszInput, OGRSpatialReference &oSRS ); CPLErr PrintSRS( const OGRSpatialReference &oSRS, const char * pszOutputType, bool bPretty, bool bPrintSep ); void PrintSRSOutputTypes( const OGRSpatialReference &oSRS, const char ** papszOutputTypes ); int FindEPSG( const OGRSpatialReference &oSRS ); int SearchCSVForWKT( const char *pszFileCSV, const char *pszTarget ); /************************************************************************/ /* Usage() */ /************************************************************************/ static void Usage(const char* pszErrorMsg = NULL) { printf( "\nUsage: gdalsrsinfo [options] srs_def\n" "\n" "srs_def may be the filename of a dataset supported by GDAL/OGR " "from which to extract SRS information\n" "OR any of the usual GDAL/OGR forms " "(complete WKT, PROJ.4, EPSG:n or a file containing the SRS)\n" "\n" "Options: \n" " [--help-general] [-h] Show help and exit\n" " [-p] Pretty-print where applicable (e.g. WKT)\n" " [-V] Validate SRS\n" " [-e] Search for EPSG number corresponding to SRS (experimental)\n" " [-o out_type] Output type { default, all, wkt_all,\n" " proj4, epsg,\n" " wkt, wkt_simple, wkt_noct, wkt_esri,\n" " mapinfo, xml }\n\n" ); if( pszErrorMsg != NULL ) fprintf(stderr, "\nFAILURE: %s\n", pszErrorMsg); exit( 1 ); } /************************************************************************/ /* main() */ /************************************************************************/ #define CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(nExtraArg) \ do { if (i + nExtraArg >= argc) \ Usage(CPLSPrintf("%s option requires %d argument(s)", \ argv[i], nExtraArg)); } while( false ) int main( int argc, char ** argv ) { bool bGotSRS = false; bool bPretty = false; bool bValidate = false; bool bFindEPSG = false; int nEPSGCode = -1; const char *pszInput = NULL; const char *pszOutputType = "default"; OGRSpatialReference oSRS; /* Check strict compilation and runtime library version as we use C++ API */ if (! GDAL_CHECK_VERSION(argv[0])) exit(1); EarlySetConfigOptions(argc, argv); /* -------------------------------------------------------------------- */ /* Register standard GDAL and OGR drivers. */ /* -------------------------------------------------------------------- */ GDALAllRegister(); /* -------------------------------------------------------------------- */ /* Register standard GDAL drivers, and process generic GDAL */ /* command options. */ /* -------------------------------------------------------------------- */ argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 ); if( argc < 1 ) exit( -argc ); /* -------------------------------------------------------------------- */ /* Parse arguments. */ /* -------------------------------------------------------------------- */ for( int i = 1; i < argc; i++ ) { CPLDebug( "gdalsrsinfo", "got arg #%d : [%s]", i, argv[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], "-h") || EQUAL(argv[i], "--help") ) Usage(); else if( EQUAL(argv[i], "-e") ) bFindEPSG = true; else if( EQUAL(argv[i], "-o") ) { CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1); pszOutputType = argv[++i]; } else if( EQUAL(argv[i], "-p") ) bPretty = true; else if( EQUAL(argv[i], "-V") ) bValidate = true; else if( argv[i][0] == '-' ) { Usage(CPLSPrintf("Unknown option name '%s'", argv[i])); } else pszInput = argv[i]; } if ( pszInput == NULL ) { CSLDestroy( argv ); Usage("No input specified."); } /* Search for SRS */ /* coverity[tainted_data] */ bGotSRS = FindSRS( pszInput, oSRS ) == TRUE; CPLDebug( "gdalsrsinfo", "bGotSRS: %d bValidate: %d pszOutputType: %s bPretty: %d", static_cast<int>(bGotSRS), static_cast<int>(bValidate), pszOutputType, static_cast<int>(bPretty) ); /* Make sure we got a SRS */ if ( ! bGotSRS ) { CPLError( CE_Failure, CPLE_AppDefined, "ERROR - failed to load SRS definition from %s", pszInput ); } else { /* Find EPSG code - experimental */ if ( EQUAL(pszOutputType,"epsg") ) bFindEPSG = true; if ( bFindEPSG ) { CPLError( CE_Warning, CPLE_AppDefined, "EPSG detection is experimental and requires new data files (see bug #4345)" ); nEPSGCode = FindEPSG( oSRS ); /* If found, replace oSRS based on EPSG code */ if(nEPSGCode != -1) { CPLDebug( "gdalsrsinfo", "Found EPSG code %d", nEPSGCode ); OGRSpatialReference oSRS2; if ( oSRS2.importFromEPSG( nEPSGCode ) == OGRERR_NONE ) oSRS = oSRS2; } } /* Validate - not well tested!*/ if ( bValidate ) { OGRErr eErr = oSRS.Validate( ); if ( eErr != OGRERR_NONE ) { printf( "\nValidate Fails" ); if ( eErr == OGRERR_CORRUPT_DATA ) printf( " - SRS is not well formed"); else if ( eErr == OGRERR_UNSUPPORTED_SRS ) printf(" - contains non-standard PROJECTION[] values"); printf("\n"); } else printf( "\nValidate Succeeds\n" ); } /* Output */ if ( EQUAL("default", pszOutputType ) ) { /* does this work in MSVC? */ const char* papszOutputTypes[] = { "proj4", "wkt", NULL }; if ( bFindEPSG ) printf("\nEPSG:%d\n",nEPSGCode); PrintSRSOutputTypes( oSRS, papszOutputTypes ); } else if ( EQUAL("all", pszOutputType ) ) { if ( bFindEPSG ) printf("\nEPSG:%d\n\n",nEPSGCode); const char* papszOutputTypes[] = {"proj4","wkt","wkt_simple","wkt_noct","wkt_esri","mapinfo","xml",NULL}; PrintSRSOutputTypes( oSRS, papszOutputTypes ); } else if ( EQUAL("wkt_all", pszOutputType ) ) { const char* papszOutputTypes[] = { "wkt", "wkt_simple", "wkt_noct", "wkt_esri", NULL }; PrintSRSOutputTypes( oSRS, papszOutputTypes ); } else { if ( bPretty ) printf( "\n" ); if ( EQUAL(pszOutputType,"epsg") ) printf("EPSG:%d\n",nEPSGCode); else PrintSRS( oSRS, pszOutputType, bPretty, FALSE ); if ( bPretty ) printf( "\n" ); } } /* cleanup anything left */ GDALDestroyDriverManager(); OGRCleanupAll(); CSLDestroy( argv ); return 0; } /************************************************************************/ /* FindSRS() */ /* */ /* Search for SRS from pszInput, update oSRS. */ /************************************************************************/ bool FindSRS( const char *pszInput, OGRSpatialReference &oSRS ) { bool bGotSRS = false; GDALDataset *poGDALDS = NULL; OGRLayer *poLayer = NULL; const char *pszProjection = NULL; CPLErrorHandler oErrorHandler = NULL; bool bIsFile = false; OGRErr eErr = OGRERR_NONE; /* temporarily suppress error messages we may get from xOpen() */ bool bDebug = CPLTestBool(CPLGetConfigOption("CPL_DEBUG", "OFF")); if( !bDebug ) oErrorHandler = CPLSetErrorHandler ( CPLQuietErrorHandler ); /* Test if argument is a file */ VSILFILE *fp = VSIFOpenL( pszInput, "r" ); if ( fp ) { bIsFile = true; VSIFCloseL( fp ); CPLDebug( "gdalsrsinfo", "argument is a file" ); } /* try to open with GDAL */ if( !STARTS_WITH(pszInput, "http://spatialreference.org/") ) { CPLDebug( "gdalsrsinfo", "trying to open with GDAL" ); poGDALDS = (GDALDataset *) GDALOpenEx( pszInput, 0, NULL, NULL, NULL ); } if ( poGDALDS != NULL ) { pszProjection = poGDALDS->GetProjectionRef( ); if( pszProjection != NULL && pszProjection[0] != '\0' ) { char* pszProjectionTmp = (char*) pszProjection; if( oSRS.importFromWkt( &pszProjectionTmp ) == OGRERR_NONE ) { CPLDebug( "gdalsrsinfo", "got SRS from GDAL" ); bGotSRS = true; } } else if( poGDALDS->GetLayerCount() > 0 ) { poLayer = poGDALDS->GetLayer( 0 ); if ( poLayer != NULL ) { OGRSpatialReference *poSRS = poLayer->GetSpatialRef( ); if ( poSRS != NULL ) { CPLDebug( "gdalsrsinfo", "got SRS from OGR" ); bGotSRS = true; OGRSpatialReference* poSRSClone = poSRS->Clone(); oSRS = *poSRSClone; OGRSpatialReference::DestroySpatialReference( poSRSClone ); } } } GDALClose( (GDALDatasetH) poGDALDS ); if ( ! bGotSRS ) CPLDebug( "gdalsrsinfo", "did not open with GDAL" ); } /* Try ESRI file */ if ( ! bGotSRS && bIsFile && (strstr(pszInput,".prj") != NULL) ) { CPLDebug( "gdalsrsinfo", "trying to get SRS from ESRI .prj file [%s]", pszInput ); char **pszTemp; if ( strstr(pszInput,"ESRI::") != NULL ) pszTemp = CSLLoad( pszInput+6 ); else pszTemp = CSLLoad( pszInput ); if( pszTemp ) { eErr = oSRS.importFromESRI( pszTemp ); CSLDestroy( pszTemp ); } else eErr = OGRERR_UNSUPPORTED_SRS; if( eErr != OGRERR_NONE ) { CPLDebug( "gdalsrsinfo", "did not get SRS from ESRI .prj file" ); } else { CPLDebug( "gdalsrsinfo", "got SRS from ESRI .prj file" ); bGotSRS = true; } } /* Last resort, try OSRSetFromUserInput() */ if ( ! bGotSRS ) { CPLDebug( "gdalsrsinfo", "trying to get SRS from user input [%s]", pszInput ); eErr = oSRS.SetFromUserInput( pszInput ); if( eErr != OGRERR_NONE ) { CPLDebug( "gdalsrsinfo", "did not get SRS from user input" ); } else { CPLDebug( "gdalsrsinfo", "got SRS from user input" ); bGotSRS = true; } } /* restore error messages */ if( !bDebug ) CPLSetErrorHandler ( oErrorHandler ); return bGotSRS; } /************************************************************************/ /* PrintSRS() */ /* */ /* Print spatial reference in specified format. */ /************************************************************************/ CPLErr PrintSRS( const OGRSpatialReference &oSRS, const char * pszOutputType, bool bPretty, bool bPrintSep ) { if ( ! pszOutputType || EQUAL(pszOutputType,"")) return CE_None; CPLDebug( "gdalsrsinfo", "PrintSRS( oSRS, %s, %d, %d )\n", pszOutputType, static_cast<int>(bPretty), static_cast<int>(bPrintSep) ); char *pszOutput = NULL; if ( EQUAL("proj4", pszOutputType ) ) { if ( bPrintSep ) printf( "PROJ.4 : "); oSRS.exportToProj4( &pszOutput ); printf( "\'%s\'\n", pszOutput ); } else if ( EQUAL("wkt", pszOutputType ) ) { if ( bPrintSep ) printf("OGC WKT :\n"); if ( bPretty ) oSRS.exportToPrettyWkt( &pszOutput, FALSE ); else oSRS.exportToWkt( &pszOutput ); printf("%s\n",pszOutput); } else if ( EQUAL("wkt_simple", pszOutputType ) ) { if ( bPrintSep ) printf("OGC WKT (simple) :\n"); oSRS.exportToPrettyWkt( &pszOutput, TRUE ); printf("%s\n",pszOutput); } else if ( EQUAL("wkt_noct", pszOutputType ) ) { if ( bPrintSep ) printf("OGC WKT (no CT) :\n"); OGRSpatialReference *poSRS = oSRS.Clone(); poSRS->StripCTParms( ); if ( bPretty ) poSRS->exportToPrettyWkt( &pszOutput, FALSE ); else poSRS->exportToWkt( &pszOutput ); OGRSpatialReference::DestroySpatialReference( poSRS ); printf("%s\n",pszOutput); } else if ( EQUAL("wkt_esri", pszOutputType ) ) { if ( bPrintSep ) printf("ESRI WKT :\n"); OGRSpatialReference *poSRS = oSRS.Clone(); poSRS->morphToESRI( ); if ( bPretty ) poSRS->exportToPrettyWkt( &pszOutput, FALSE ); else poSRS->exportToWkt( &pszOutput ); OGRSpatialReference::DestroySpatialReference( poSRS ); printf("%s\n",pszOutput); } else if ( EQUAL("mapinfo", pszOutputType ) ) { if ( bPrintSep ) printf("MAPINFO : "); oSRS.exportToMICoordSys( &pszOutput ); printf("\'%s\'\n",pszOutput); } else if ( EQUAL("xml", pszOutputType ) ) { if ( bPrintSep ) printf("XML :\n"); oSRS.exportToXML( &pszOutput, NULL ); printf("%s\n",pszOutput); } else { CPLError( CE_Failure, CPLE_AppDefined, "ERROR - %s output not supported", pszOutputType ); return CE_Failure; } CPLFree( pszOutput ); return CE_None; } /************************************************************************/ /* PrintSRSOutputTypes() */ /* */ /* Print spatial reference in specified formats. */ /************************************************************************/ void PrintSRSOutputTypes( const OGRSpatialReference &oSRS, const char ** papszOutputTypes ) { int nOutputTypes = CSLCount((char**)papszOutputTypes); printf( "\n" ); for ( int i=0; i<nOutputTypes; i++ ) { PrintSRS( oSRS, papszOutputTypes[i], true, true ); printf( "\n" ); } } /************************************************************************/ /* SearchCSVForWKT() */ /* */ /* Search CSV file for target WKT, return EPSG code (or -1). */ /* For saving space, the file can be compressed (gz) */ /* If CSV file is absent are absent the function silently exits */ /************************************************************************/ int SearchCSVForWKT( const char *pszFileCSV, const char *pszTarget ) { const char *pszFilename = NULL; const char *pszWKT = NULL; char szTemp[1024]; int nPos = 0; const char *pszTemp = NULL; VSILFILE *fp = NULL; OGRSpatialReference oSRS; int nCode = 0; int nFound = -1; CPLDebug( "gdalsrsinfo", "SearchCSVForWKT()\nfile=%s\nWKT=%s\n", pszFileCSV, pszTarget); /* -------------------------------------------------------------------- */ /* Find and open file. */ /* -------------------------------------------------------------------- */ // pszFilename = pszFileCSV; pszFilename = CPLFindFile( "gdal", pszFileCSV ); if( pszFilename == NULL ) { CPLDebug( "gdalsrsinfo", "could not find support file %s", pszFileCSV ); // return OGRERR_UNSUPPORTED_SRS; return -1; } /* support gzipped file */ if ( strstr( pszFileCSV,".gz") != NULL ) snprintf( szTemp, sizeof(szTemp), "/vsigzip/%s", pszFilename); else snprintf( szTemp, sizeof(szTemp), "%s", pszFilename); CPLDebug( "gdalsrsinfo", "SearchCSVForWKT() using file %s", szTemp ); fp = VSIFOpenL( szTemp, "r" ); if( fp == NULL ) { CPLDebug( "gdalsrsinfo", "could not open support file %s", pszFilename ); // return OGRERR_UNSUPPORTED_SRS; return -1; } /* -------------------------------------------------------------------- */ /* Process lines. */ /* -------------------------------------------------------------------- */ const char *pszLine; while( (pszLine = CPLReadLine2L(fp,-1,NULL)) != NULL ) { // CPLDebug( "gdalsrsinfo", "read line %s", pszLine ); if( pszLine[0] == '#' ) continue; /* do nothing */; // else if( STARTS_WITH_CI(pszLine, "include ") ) // { // eErr = importFromDict( pszLine + 8, pszCode ); // if( eErr != OGRERR_UNSUPPORTED_SRS ) // break; // } // else if( strstr(pszLine,",") == NULL ) // /* do nothing */; pszTemp = strstr(pszLine,","); if (pszTemp) { nPos = static_cast<int>(pszTemp - pszLine); if ( nPos == 0 ) continue; strncpy( szTemp, pszLine, nPos ); szTemp[nPos] = '\0'; nCode = atoi(szTemp); pszWKT = (char *) pszLine + nPos +1; // CPLDebug( "gdalsrsinfo", // "code=%d\nWKT=\n[%s]\ntarget=\n[%s]\n", // nCode,pszWKT, pszTarget ); if ( EQUAL(pszTarget,pszWKT) ) { nFound = nCode; CPLDebug( "gdalsrsinfo", "found EPSG:%d\n" "current=%s\ntarget= %s\n", nCode, pszWKT, pszTarget ); break; } } } VSIFCloseL( fp ); return nFound; } /* TODO - search for well-known values (AutoIdentifyEPSG()) - should we search .override.csv files? - fix precision differences (namely in degree: 17 vs 15) so we can use epsg_ogc_simple target: orig: GEOGCS["SAD69",DATUM["D_South_American_1969",SPHEROID["GRS_1967_Modified",6378160,298.25]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] ESRI: GEOGCS["SAD69",DATUM["D_South_American_1969",SPHEROID["GRS_1967_Truncated",6378160,298.25]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] OGC: GEOGCS["SAD69",DATUM["South_American_Datum_1969",SPHEROID["GRS_1967_Modified",6378160,298.25]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] database: ESRI: GEOGCS["SAD69",DATUM["D_South_American_1969",SPHEROID["GRS_1967_Truncated",6378160,298.25]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] OGC: GEOGCS["SAD69",DATUM["South_American_Datum_1969",SPHEROID["GRS 1967 Modified",6378160,298.25]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433]] */ /************************************************************************/ /* FindEPSG() */ /* */ /* Return EPSG code corresponding to spatial reference (or -1) */ /************************************************************************/ int FindEPSG( const OGRSpatialReference &oSRS ) { char *pszWKT = NULL; char *pszESRI = NULL; OGRSpatialReference *poSRS = NULL; poSRS = oSRS.Clone(); poSRS->StripCTParms(); poSRS->exportToWkt( &pszWKT ); OGRSpatialReference::DestroySpatialReference( poSRS ); poSRS = oSRS.Clone(); poSRS->morphToESRI( ); poSRS->exportToWkt( &pszESRI ); OGRSpatialReference::DestroySpatialReference( poSRS ); CPLDebug( "gdalsrsinfo", "FindEPSG()\nWKT (OGC)= %s\nWKT (ESRI)=%s", pszWKT,pszESRI ); /* search for EPSG code in epsg_*.wkt.gz files */ /* using ESRI WKT for now, as it seems to work best */ int nFound = SearchCSVForWKT( "epsg_esri.wkt.gz", pszESRI ); if ( nFound == -1 ) nFound = SearchCSVForWKT( "epsg_ogc_simple.wkt.gz", pszESRI ); if ( nFound == -1 ) nFound = SearchCSVForWKT( "epsg_ogc.wkt.gz", pszESRI ); CPLFree( pszWKT ); CPLFree( pszESRI ); return nFound; }