Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Utilities
4 : * Purpose: Command line application to list info about a given CRS.
5 : * Outputs a number of formats (WKT, PROJ.4, etc.).
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : * Etienne Tourigny, etourigny.dev-at-gmail-dot-com
8 : *
9 : * ****************************************************************************
10 : * Copyright (c) 1998, Frank Warmerdam
11 : * Copyright (c) 2011-2013, Even Rouault <even dot rouault at spatialys.com>
12 : *
13 : * Permission is hereby granted, free of charge, to any person obtaining a
14 : * copy of this software and associated documentation files (the "Software"),
15 : * to deal in the Software without restriction, including without limitation
16 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 : * and/or sell copies of the Software, and to permit persons to whom the
18 : * Software is furnished to do so, subject to the following conditions:
19 : *
20 : * The above copyright notice and this permission notice shall be included
21 : * in all copies or substantial portions of the Software.
22 : *
23 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 : * DEALINGS IN THE SOFTWARE.
30 : ****************************************************************************/
31 :
32 : #include "cpl_string.h"
33 : #include "gdal_version.h"
34 : #include "gdal_priv.h"
35 : #include "ogr_spatialref.h"
36 : #include "ogr_api.h"
37 : #include "ogrsf_frmts.h"
38 : #include "commonutils.h"
39 :
40 : #include "proj.h"
41 :
42 : bool FindSRS(const char *pszInput, OGRSpatialReference &oSRS);
43 : CPLErr PrintSRS(const OGRSpatialReference &oSRS, const char *pszOutputType,
44 : bool bPretty, bool bPrintSep);
45 : void PrintSRSOutputTypes(const OGRSpatialReference &oSRS,
46 : const char *const *papszOutputTypes, bool bPretty);
47 :
48 : /************************************************************************/
49 : /* Usage() */
50 : /************************************************************************/
51 :
52 0 : static void Usage(bool bIsError, const char *pszErrorMsg = nullptr)
53 :
54 : {
55 0 : fprintf(bIsError ? stderr : stdout,
56 : "Usage: gdalsrsinfo [options] <srs_def>\n"
57 : "\n"
58 : "srs_def may be the filename of a dataset supported by GDAL/OGR "
59 : "from which to extract SRS information\n"
60 : "OR any of the usual GDAL/OGR forms "
61 : "(complete WKT, PROJ.4, EPSG:n or a file containing the SRS)\n"
62 : "\n"
63 : "Options: \n"
64 : " [--help-general] Show help on general options and exit\n"
65 : " [--help] [-h] Show help and exit\n"
66 : " [--single-line] Print WKT on single line\n"
67 : " [-V] Validate SRS\n"
68 : " [-e] Search for EPSG number(s) corresponding "
69 : "to SRS\n"
70 : " [-o <out_type>] Output type { default, all, wkt_all,\n"
71 : #if PROJ_VERSION_MAJOR > 6 || PROJ_VERSION_MINOR >= 2
72 : " PROJJSON, proj4, epsg,\n"
73 : #else
74 : " proj4, epsg,\n"
75 : #endif
76 : " wkt1, wkt_simple, "
77 : "wkt_noct, wkt_esri,\n"
78 : " wkt2, wkt2_2015, "
79 : "wkt2_2019, mapinfo, xml }\n\n");
80 :
81 0 : if (pszErrorMsg != nullptr)
82 0 : fprintf(stderr, "\nFAILURE: %s\n", pszErrorMsg);
83 :
84 0 : exit(bIsError ? 1 : 0);
85 : }
86 :
87 : /************************************************************************/
88 : /* main() */
89 : /************************************************************************/
90 :
91 : #define CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(nExtraArg) \
92 : do \
93 : { \
94 : if (i + nExtraArg >= argc) \
95 : Usage(true, CPLSPrintf("%s option requires %d argument(s)", \
96 : argv[i], nExtraArg)); \
97 : } while (false)
98 :
99 21 : MAIN_START(argc, argv)
100 :
101 : {
102 21 : bool bGotSRS = false;
103 21 : bool bPretty = true;
104 21 : bool bValidate = false;
105 21 : bool bFindEPSG = false;
106 41 : std::string osIdentifiedCode = "EPSG:-1";
107 21 : const char *pszInput = nullptr;
108 21 : const char *pszOutputType = "default";
109 41 : OGRSpatialReference oSRS;
110 :
111 : /* Check strict compilation and runtime library version as we use C++ API */
112 21 : if (!GDAL_CHECK_VERSION(argv[0]))
113 0 : exit(1);
114 :
115 21 : EarlySetConfigOptions(argc, argv);
116 :
117 : /* -------------------------------------------------------------------- */
118 : /* Register standard GDAL and OGR drivers. */
119 : /* -------------------------------------------------------------------- */
120 21 : GDALAllRegister();
121 :
122 : /* -------------------------------------------------------------------- */
123 : /* Register standard GDAL drivers, and process generic GDAL */
124 : /* command options. */
125 : /* -------------------------------------------------------------------- */
126 21 : argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
127 21 : if (argc < 1)
128 0 : exit(-argc);
129 :
130 : /* -------------------------------------------------------------------- */
131 : /* Parse arguments. */
132 : /* -------------------------------------------------------------------- */
133 66 : for (int i = 1; i < argc; i++)
134 : {
135 46 : CPLDebug("gdalsrsinfo", "got arg #%d : [%s]", i, argv[i]);
136 :
137 46 : if (EQUAL(argv[i], "--utility_version"))
138 : {
139 1 : printf("%s was compiled against GDAL %s and is running against "
140 : "GDAL %s\n",
141 : argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
142 1 : CSLDestroy(argv);
143 1 : return 0;
144 : }
145 45 : else if (EQUAL(argv[i], "-h") || EQUAL(argv[i], "--help"))
146 0 : Usage(false);
147 45 : else if (EQUAL(argv[i], "-e"))
148 3 : bFindEPSG = true;
149 42 : else if (EQUAL(argv[i], "-o"))
150 : {
151 14 : CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
152 14 : pszOutputType = argv[++i];
153 : }
154 28 : else if (EQUAL(argv[i], "-p"))
155 0 : bPretty = true;
156 28 : else if (EQUAL(argv[i], "--single-line"))
157 6 : bPretty = false;
158 22 : else if (EQUAL(argv[i], "-V"))
159 2 : bValidate = true;
160 20 : else if (argv[i][0] == '-')
161 : {
162 0 : Usage(true, CPLSPrintf("Unknown option name '%s'", argv[i]));
163 : }
164 : else
165 20 : pszInput = argv[i];
166 : }
167 :
168 20 : if (pszInput == nullptr)
169 : {
170 0 : CSLDestroy(argv);
171 0 : Usage(true, "No input specified.");
172 : }
173 :
174 : /* Search for SRS */
175 : /* coverity[tainted_data] */
176 20 : bGotSRS = FindSRS(pszInput, oSRS) == TRUE;
177 :
178 20 : CPLDebug("gdalsrsinfo",
179 : "bGotSRS: %d bValidate: %d pszOutputType: %s bPretty: %d",
180 : static_cast<int>(bGotSRS), static_cast<int>(bValidate),
181 : pszOutputType, static_cast<int>(bPretty));
182 :
183 : /* Make sure we got a SRS */
184 20 : if (!bGotSRS)
185 : {
186 1 : CPLError(CE_Failure, CPLE_AppDefined,
187 : "ERROR - failed to load SRS definition from %s", pszInput);
188 1 : exit(1);
189 : }
190 :
191 : else
192 : {
193 19 : int nEntries = 0;
194 19 : int *panConfidence = nullptr;
195 19 : OGRSpatialReferenceH *pahSRS = nullptr;
196 :
197 : /* Find EPSG code */
198 19 : if (EQUAL(pszOutputType, "epsg"))
199 0 : bFindEPSG = true;
200 :
201 19 : if (bFindEPSG)
202 : {
203 :
204 : pahSRS =
205 3 : OSRFindMatches(reinterpret_cast<OGRSpatialReferenceH>(
206 : const_cast<OGRSpatialReference *>(&oSRS)),
207 : nullptr, &nEntries, &panConfidence);
208 : }
209 :
210 38 : for (int i = 0; i < (nEntries ? nEntries : 1); i++)
211 : {
212 19 : if (nEntries)
213 : {
214 2 : oSRS = *reinterpret_cast<OGRSpatialReference *>(pahSRS[i]);
215 2 : if (panConfidence[i] != 100)
216 : {
217 2 : printf("Confidence in this match: %d %%\n",
218 2 : panConfidence[i]);
219 : }
220 :
221 2 : const char *pszAuthorityName = oSRS.GetAuthorityName(nullptr);
222 2 : const char *pszAuthorityCode = oSRS.GetAuthorityCode(nullptr);
223 2 : if (pszAuthorityName && pszAuthorityCode)
224 : {
225 2 : osIdentifiedCode = pszAuthorityName;
226 2 : osIdentifiedCode += ':';
227 2 : osIdentifiedCode += pszAuthorityCode;
228 : }
229 : }
230 :
231 : /* Validate - not well tested!*/
232 19 : if (bValidate)
233 : {
234 2 : OGRErr eErr = oSRS.Validate();
235 2 : if (eErr != OGRERR_NONE)
236 : {
237 1 : printf("\nValidate Fails");
238 1 : if (eErr == OGRERR_CORRUPT_DATA)
239 1 : printf(" - SRS is not well formed");
240 0 : else if (eErr == OGRERR_UNSUPPORTED_SRS)
241 0 : printf(" - contains non-standard PROJECTION[] values");
242 1 : printf("\n");
243 : }
244 : else
245 1 : printf("\nValidate Succeeds\n");
246 : }
247 :
248 : /* Output */
249 19 : if (EQUAL("default", pszOutputType))
250 : {
251 5 : const char *papszOutputTypes[] = {"proj4", "wkt2", nullptr};
252 5 : if (bFindEPSG)
253 3 : printf("\n%s\n", osIdentifiedCode.c_str());
254 5 : PrintSRSOutputTypes(oSRS, papszOutputTypes, bPretty);
255 : }
256 14 : else if (EQUAL("all", pszOutputType))
257 : {
258 1 : if (bFindEPSG)
259 0 : printf("\n%s\n", osIdentifiedCode.c_str());
260 1 : const char *papszOutputTypes[] = {
261 : "proj4",
262 : "wkt1",
263 : "wkt2_2015",
264 : "wkt2_2019",
265 : "wkt_simple",
266 : "wkt_noct",
267 : "wkt_esri",
268 : "mapinfo",
269 : "xml",
270 : #if PROJ_VERSION_MAJOR > 6 || PROJ_VERSION_MINOR >= 2
271 : "PROJJSON",
272 : #endif
273 : nullptr
274 : };
275 1 : PrintSRSOutputTypes(oSRS, papszOutputTypes, bPretty);
276 : }
277 13 : else if (EQUAL("wkt_all", pszOutputType))
278 : {
279 0 : const char *papszOutputTypes[] = {
280 : "wkt1", "wkt2_2015", "wkt2_2019", "wkt_simple",
281 : "wkt_noct", "wkt_esri", nullptr};
282 0 : PrintSRSOutputTypes(oSRS, papszOutputTypes, bPretty);
283 : }
284 : else
285 : {
286 13 : if (bPretty)
287 7 : printf("\n");
288 13 : if (EQUAL(pszOutputType, "epsg"))
289 0 : printf("\n%s\n", osIdentifiedCode.c_str());
290 : else
291 13 : PrintSRS(oSRS, pszOutputType, bPretty, FALSE);
292 13 : if (bPretty)
293 7 : printf("\n");
294 : }
295 : }
296 :
297 19 : OSRFreeSRSArray(pahSRS);
298 19 : CPLFree(panConfidence);
299 : }
300 :
301 : /* cleanup anything left */
302 19 : GDALDestroyDriverManager();
303 19 : OGRCleanupAll();
304 19 : CSLDestroy(argv);
305 :
306 19 : return 0;
307 : }
308 :
309 0 : MAIN_END
310 :
311 : /************************************************************************/
312 : /* FindSRS() */
313 : /* */
314 : /* Search for SRS from pszInput, update oSRS. */
315 : /************************************************************************/
316 20 : bool FindSRS(const char *pszInput, OGRSpatialReference &oSRS)
317 :
318 : {
319 20 : bool bGotSRS = false;
320 20 : GDALDataset *poGDALDS = nullptr;
321 20 : OGRLayer *poLayer = nullptr;
322 20 : bool bIsFile = false;
323 :
324 : /* temporarily suppress error messages we may get from xOpen() */
325 20 : bool bDebug = CPLTestBool(CPLGetConfigOption("CPL_DEBUG", "OFF"));
326 20 : if (!bDebug)
327 20 : CPLPushErrorHandler(CPLQuietErrorHandler);
328 :
329 : /* Test if argument is a file */
330 20 : VSILFILE *fp = VSIFOpenL(pszInput, "r");
331 20 : if (fp)
332 : {
333 13 : bIsFile = true;
334 13 : VSIFCloseL(fp);
335 13 : CPLDebug("gdalsrsinfo", "argument is a file");
336 : }
337 :
338 : /* try to open with GDAL */
339 20 : if (!STARTS_WITH(pszInput, "http://spatialreference.org/"))
340 : {
341 20 : CPLDebug("gdalsrsinfo", "trying to open with GDAL");
342 : poGDALDS = static_cast<GDALDataset *>(
343 20 : GDALOpenEx(pszInput, 0, nullptr, nullptr, nullptr));
344 : }
345 20 : if (poGDALDS != nullptr)
346 : {
347 11 : const OGRSpatialReference *poSRS = poGDALDS->GetSpatialRef();
348 11 : if (poSRS)
349 : {
350 10 : oSRS = *poSRS;
351 10 : CPLDebug("gdalsrsinfo", "got SRS from GDAL");
352 10 : bGotSRS = true;
353 : }
354 1 : else if (poGDALDS->GetLayerCount() > 0)
355 : {
356 1 : poLayer = poGDALDS->GetLayer(0);
357 1 : if (poLayer != nullptr)
358 : {
359 1 : poSRS = poLayer->GetSpatialRef();
360 1 : if (poSRS != nullptr)
361 : {
362 1 : CPLDebug("gdalsrsinfo", "got SRS from OGR");
363 1 : bGotSRS = true;
364 1 : oSRS = *poSRS;
365 : }
366 : }
367 : }
368 11 : GDALClose(poGDALDS);
369 11 : if (!bGotSRS)
370 0 : CPLDebug("gdalsrsinfo", "did not open with GDAL");
371 : }
372 :
373 : /* Try ESRI file */
374 20 : if (!bGotSRS && bIsFile && (strstr(pszInput, ".prj") != nullptr))
375 : {
376 2 : CPLDebug("gdalsrsinfo", "trying to get SRS from ESRI .prj file [%s]",
377 : pszInput);
378 :
379 : char **pszTemp;
380 2 : if (strstr(pszInput, "ESRI::") != nullptr)
381 0 : pszTemp = CSLLoad(pszInput + 6);
382 : else
383 2 : pszTemp = CSLLoad(pszInput);
384 :
385 2 : OGRErr eErr = OGRERR_UNSUPPORTED_SRS;
386 2 : if (pszTemp)
387 : {
388 2 : eErr = oSRS.importFromESRI(pszTemp);
389 2 : CSLDestroy(pszTemp);
390 : }
391 :
392 2 : if (eErr != OGRERR_NONE)
393 : {
394 2 : CPLDebug("gdalsrsinfo", "did not get SRS from ESRI .prj file");
395 : }
396 : else
397 : {
398 0 : CPLDebug("gdalsrsinfo", "got SRS from ESRI .prj file");
399 0 : bGotSRS = true;
400 : }
401 : }
402 :
403 : /* restore error messages */
404 20 : if (!bDebug)
405 20 : CPLPopErrorHandler();
406 :
407 : /* Last resort, try OSRSetFromUserInput() */
408 20 : if (!bGotSRS)
409 : {
410 9 : CPLDebug("gdalsrsinfo", "trying to get SRS from user input [%s]",
411 : pszInput);
412 :
413 9 : if (CPLGetConfigOption("CPL_ALLOW_VSISTDIN", nullptr) == nullptr)
414 9 : CPLSetConfigOption("CPL_ALLOW_VSISTDIN", "YES");
415 :
416 9 : const OGRErr eErr = oSRS.SetFromUserInput(pszInput);
417 :
418 9 : if (eErr != OGRERR_NONE)
419 : {
420 1 : CPLDebug("gdalsrsinfo", "did not get SRS from user input");
421 : }
422 : else
423 : {
424 8 : CPLDebug("gdalsrsinfo", "got SRS from user input");
425 8 : bGotSRS = true;
426 : }
427 : }
428 :
429 20 : return bGotSRS;
430 : }
431 :
432 : /************************************************************************/
433 : /* PrintSRS() */
434 : /* */
435 : /* Print spatial reference in specified format. */
436 : /************************************************************************/
437 33 : CPLErr PrintSRS(const OGRSpatialReference &oSRS, const char *pszOutputType,
438 : bool bPretty, bool bPrintSep)
439 :
440 : {
441 33 : if (!pszOutputType || EQUAL(pszOutputType, ""))
442 0 : return CE_None;
443 :
444 33 : CPLDebug("gdalsrsinfo", "PrintSRS( oSRS, %s, %d, %d )\n", pszOutputType,
445 : static_cast<int>(bPretty), static_cast<int>(bPrintSep));
446 :
447 33 : char *pszOutput = nullptr;
448 :
449 33 : if (EQUAL("proj4", pszOutputType))
450 : {
451 12 : if (bPrintSep)
452 6 : printf("PROJ.4 : ");
453 12 : oSRS.exportToProj4(&pszOutput);
454 12 : printf("%s\n", pszOutput ? pszOutput : "(error)");
455 : }
456 :
457 21 : else if (EQUAL("PROJJSON", pszOutputType))
458 : {
459 1 : if (bPrintSep)
460 1 : printf("PROJJSON :\n");
461 1 : const char *const apszOptions[] = {
462 1 : bPretty ? "MULTILINE=YES" : "MULTILINE=NO", nullptr};
463 1 : oSRS.exportToPROJJSON(&pszOutput, apszOptions);
464 1 : printf("%s\n", pszOutput ? pszOutput : "(error)");
465 : }
466 :
467 20 : else if (EQUAL("wkt1", pszOutputType))
468 : {
469 4 : if (bPrintSep)
470 1 : printf("OGC WKT1 :\n");
471 4 : const char *const apszOptions[] = {
472 4 : "FORMAT=WKT1_GDAL", bPretty ? "MULTILINE=YES" : nullptr, nullptr};
473 4 : oSRS.exportToWkt(&pszOutput, apszOptions);
474 4 : printf("%s\n", pszOutput ? pszOutput : "(error)");
475 : }
476 :
477 16 : else if (EQUAL("wkt_simple", pszOutputType))
478 : {
479 2 : if (bPrintSep)
480 1 : printf("OGC WKT1 (simple) :\n");
481 2 : const char *const apszOptions[] = {
482 2 : "FORMAT=WKT1_SIMPLE", bPretty ? "MULTILINE=YES" : nullptr, nullptr};
483 2 : oSRS.exportToWkt(&pszOutput, apszOptions);
484 2 : printf("%s\n", pszOutput ? pszOutput : "(error)");
485 : }
486 :
487 14 : else if (EQUAL("wkt_noct", pszOutputType))
488 : {
489 2 : if (bPrintSep)
490 1 : printf("OGC WKT1 (no CT) :\n");
491 2 : const char *const apszOptions[] = {
492 2 : "FORMAT=SFSQL", bPretty ? "MULTILINE=YES" : nullptr, nullptr};
493 2 : oSRS.exportToWkt(&pszOutput, apszOptions);
494 2 : printf("%s\n", pszOutput ? pszOutput : "(error)");
495 : }
496 :
497 12 : else if (EQUAL("wkt_esri", pszOutputType))
498 : {
499 2 : if (bPrintSep)
500 1 : printf("ESRI WKT :\n");
501 2 : const char *const apszOptions[] = {
502 2 : "FORMAT=WKT1_ESRI", bPretty ? "MULTILINE=YES" : nullptr, nullptr};
503 2 : oSRS.exportToWkt(&pszOutput, apszOptions);
504 2 : printf("%s\n", pszOutput ? pszOutput : "(error)");
505 : }
506 :
507 10 : else if (EQUAL("wkt2_2015", pszOutputType))
508 : {
509 1 : if (bPrintSep)
510 1 : printf("OGC WKT2:2015 :\n");
511 1 : const char *const apszOptions[] = {
512 1 : "FORMAT=WKT2_2015", bPretty ? "MULTILINE=YES" : nullptr, nullptr};
513 1 : oSRS.exportToWkt(&pszOutput, apszOptions);
514 1 : printf("%s\n", pszOutput ? pszOutput : "(error)");
515 : }
516 :
517 9 : else if (EQUAL("wkt", pszOutputType) || EQUAL("wkt2", pszOutputType) ||
518 4 : EQUAL("wkt2_2018", pszOutputType) ||
519 4 : EQUAL("wkt2_2019", pszOutputType))
520 : {
521 6 : if (bPrintSep)
522 6 : printf("OGC WKT2:2019 :\n");
523 6 : const char *const apszOptions[] = {
524 6 : "FORMAT=WKT2_2018", bPretty ? "MULTILINE=YES" : nullptr, nullptr};
525 6 : oSRS.exportToWkt(&pszOutput, apszOptions);
526 6 : printf("%s\n", pszOutput ? pszOutput : "(error)");
527 : }
528 :
529 3 : else if (EQUAL("mapinfo", pszOutputType))
530 : {
531 2 : if (bPrintSep)
532 1 : printf("MAPINFO : ");
533 2 : oSRS.exportToMICoordSys(&pszOutput);
534 2 : printf("\'%s\'\n", pszOutput ? pszOutput : "(error)");
535 : }
536 :
537 1 : else if (EQUAL("xml", pszOutputType))
538 : {
539 1 : if (bPrintSep)
540 1 : printf("XML :\n");
541 1 : oSRS.exportToXML(&pszOutput, nullptr);
542 1 : printf("%s\n", pszOutput ? pszOutput : "(error)");
543 : }
544 :
545 : else
546 : {
547 0 : CPLError(CE_Failure, CPLE_AppDefined, "ERROR - %s output not supported",
548 : pszOutputType);
549 0 : return CE_Failure;
550 : }
551 :
552 33 : CPLFree(pszOutput);
553 :
554 33 : return CE_None;
555 : }
556 :
557 : /************************************************************************/
558 : /* PrintSRSOutputTypes() */
559 : /* */
560 : /* Print spatial reference in specified formats. */
561 : /************************************************************************/
562 6 : void PrintSRSOutputTypes(const OGRSpatialReference &oSRS,
563 : const char *const *papszOutputTypes, bool bPretty)
564 :
565 : {
566 6 : int nOutputTypes = CSLCount(papszOutputTypes);
567 6 : printf("\n");
568 26 : for (int i = 0; i < nOutputTypes; i++)
569 : {
570 20 : PrintSRS(oSRS, papszOutputTypes[i], bPretty, true);
571 20 : printf("\n");
572 : }
573 6 : }
|