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