LCOV - code coverage report
Current view: top level - apps - gdaltransform.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 199 235 84.7 %
Date: 2024-05-03 15:49:35 Functions: 2 3 66.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Command line point transformer.
       5             :  * Author:   Frank Warmerdam <warmerdam@pobox.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2007, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #include "cpl_port.h"
      31             : 
      32             : #include <cstdio>
      33             : #include <cstdlib>
      34             : #include <cctype>
      35             : 
      36             : #include "cpl_conv.h"
      37             : #include "cpl_error.h"
      38             : #include "cpl_string.h"
      39             : #include "gdal_version.h"
      40             : #include "gdal_alg.h"
      41             : #include "gdalwarper.h"
      42             : #include "gdal.h"
      43             : #include "gdal_version.h"
      44             : #include "ogr_api.h"
      45             : #include "ogr_core.h"
      46             : #include "ogr_spatialref.h"
      47             : #include "ogr_srs_api.h"
      48             : #include "commonutils.h"
      49             : 
      50             : #ifdef _WIN32
      51             : #include <io.h>
      52             : #else
      53             : #include <unistd.h>
      54             : #endif
      55             : 
      56             : /************************************************************************/
      57             : /*                               Usage()                                */
      58             : /************************************************************************/
      59             : 
      60           0 : static void Usage(bool bIsError, const char *pszErrorMsg = nullptr)
      61             : 
      62             : {
      63           0 :     fprintf(bIsError ? stderr : stdout,
      64             :             "Usage: gdaltransform [--help] [--help-general]\n"
      65             :             "    [-i] [-s_srs <srs_def>] [-t_srs <srs_def>] [-to "
      66             :             ">NAME>=<VALUE>]...\n"
      67             :             "    [-s_coord_epoch <epoch>] [-t_coord_epoch <epoch>]\n"
      68             :             "    [-ct <proj_string>] [-order <n>] [-tps] [-rpc] [-geoloc] \n"
      69             :             "    [-gcp <pixel> <line> <easting> <northing> [elevation]]...\n"
      70             :             "    [-output_xy] [-E] [-field_sep <sep>] [-ignore_extra_input]\n"
      71             :             "    [<srcfile> [<dstfile>]]\n"
      72             :             "\n");
      73             : 
      74           0 :     if (pszErrorMsg != nullptr)
      75           0 :         fprintf(stderr, "\nFAILURE: %s\n", pszErrorMsg);
      76             : 
      77           0 :     exit(bIsError ? 1 : 0);
      78             : }
      79             : 
      80             : /************************************************************************/
      81             : /*                             IsValidSRS                               */
      82             : /************************************************************************/
      83             : 
      84           8 : static bool IsValidSRS(const char *pszUserInput)
      85             : 
      86             : {
      87             :     OGRSpatialReferenceH hSRS;
      88           8 :     bool bRes = true;
      89             : 
      90           8 :     CPLErrorReset();
      91             : 
      92           8 :     hSRS = OSRNewSpatialReference(nullptr);
      93           8 :     if (OSRSetFromUserInput(hSRS, pszUserInput) != OGRERR_NONE)
      94             :     {
      95           0 :         bRes = false;
      96           0 :         CPLError(CE_Failure, CPLE_AppDefined,
      97             :                  "Translating source or target SRS failed:\n%s", pszUserInput);
      98             :     }
      99             : 
     100           8 :     OSRDestroySpatialReference(hSRS);
     101             : 
     102           8 :     return bRes;
     103             : }
     104             : 
     105             : /************************************************************************/
     106             : /*                                main()                                */
     107             : /************************************************************************/
     108             : 
     109             : #define CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(nExtraArg)                            \
     110             :     do                                                                         \
     111             :     {                                                                          \
     112             :         if (i + nExtraArg >= argc)                                             \
     113             :             Usage(true, CPLSPrintf("%s option requires %d argument(s)",        \
     114             :                                    argv[i], nExtraArg));                       \
     115             :     } while (false)
     116             : 
     117          15 : MAIN_START(argc, argv)
     118             : 
     119             : {
     120             :     // Check that we are running against at least GDAL 1.5.
     121             :     // Note to developers: if we use newer API, please change the requirement.
     122          15 :     if (atoi(GDALVersionInfo("VERSION_NUM")) < 1500)
     123             :     {
     124           0 :         fprintf(stderr,
     125             :                 "At least, GDAL >= 1.5.0 is required for this version of %s, "
     126             :                 "which was compiled against GDAL %s\n",
     127             :                 argv[0], GDAL_RELEASE_NAME);
     128           0 :         exit(1);
     129             :     }
     130             : 
     131          15 :     GDALAllRegister();
     132          15 :     argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
     133          15 :     if (argc < 1)
     134           0 :         exit(-argc);
     135             : 
     136          15 :     const char *pszSrcFilename = nullptr;
     137          15 :     const char *pszDstFilename = nullptr;
     138          15 :     int nOrder = 0;
     139             :     void *hTransformArg;
     140          15 :     GDALTransformerFunc pfnTransformer = nullptr;
     141          15 :     int nGCPCount = 0;
     142          15 :     GDAL_GCP *pasGCPs = nullptr;
     143          15 :     int bInverse = FALSE;
     144          30 :     CPLStringList aosTO;
     145          15 :     int bOutputXY = FALSE;
     146          15 :     double dfX = 0.0;
     147          15 :     double dfY = 0.0;
     148          15 :     double dfZ = 0.0;
     149          15 :     double dfT = 0.0;
     150          15 :     bool bCoordOnCommandLine = false;
     151          15 :     bool bIgnoreExtraInput = false;
     152          15 :     bool bEchoInput = false;
     153          30 :     std::string osFieldSep = " ";
     154             : 
     155             :     /* -------------------------------------------------------------------- */
     156             :     /*      Parse arguments.                                                */
     157             :     /* -------------------------------------------------------------------- */
     158          54 :     for (int i = 1; i < argc && argv[i] != nullptr; i++)
     159             :     {
     160          40 :         if (EQUAL(argv[i], "--utility_version"))
     161             :         {
     162           1 :             printf("%s was compiled against GDAL %s and "
     163             :                    "is running against GDAL %s\n",
     164             :                    argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
     165           1 :             CSLDestroy(argv);
     166           1 :             return 0;
     167             :         }
     168          39 :         else if (EQUAL(argv[i], "--help"))
     169             :         {
     170           0 :             Usage(false);
     171             :         }
     172          39 :         else if (EQUAL(argv[i], "-t_srs"))
     173             :         {
     174           5 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
     175           5 :             const char *pszSRS = argv[++i];
     176           5 :             if (!IsValidSRS(pszSRS))
     177           0 :                 exit(1);
     178           5 :             aosTO.SetNameValue("DST_SRS", pszSRS);
     179             :         }
     180          34 :         else if (EQUAL(argv[i], "-s_srs"))
     181             :         {
     182           3 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
     183           3 :             const char *pszSRS = argv[++i];
     184             :             // coverity[tainted_data]
     185           3 :             if (!IsValidSRS(pszSRS))
     186           0 :                 exit(1);
     187           3 :             aosTO.SetNameValue("SRC_SRS", pszSRS);
     188             :         }
     189          31 :         else if (EQUAL(argv[i], "-s_coord_epoch"))
     190             :         {
     191           0 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
     192           0 :             const char *pszCoordinateEpoch = argv[++i];
     193           0 :             aosTO.SetNameValue("SRC_COORDINATE_EPOCH", pszCoordinateEpoch);
     194             :         }
     195          31 :         else if (EQUAL(argv[i], "-t_coord_epoch"))
     196             :         {
     197           0 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
     198           0 :             const char *pszCoordinateEpoch = argv[++i];
     199           0 :             aosTO.SetNameValue("DST_COORDINATE_EPOCH", pszCoordinateEpoch);
     200             :         }
     201          31 :         else if (EQUAL(argv[i], "-ct"))
     202             :         {
     203           1 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
     204           1 :             const char *pszCT = argv[++i];
     205           1 :             aosTO.SetNameValue("COORDINATE_OPERATION", pszCT);
     206             :         }
     207          30 :         else if (EQUAL(argv[i], "-order"))
     208             :         {
     209           1 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
     210           1 :             nOrder = atoi(argv[++i]);
     211           1 :             aosTO.SetNameValue("MAX_GCP_ORDER", argv[i]);
     212             :         }
     213          29 :         else if (EQUAL(argv[i], "-tps"))
     214             :         {
     215           1 :             aosTO.SetNameValue("METHOD", "GCP_TPS");
     216           1 :             nOrder = -1;
     217             :         }
     218          28 :         else if (EQUAL(argv[i], "-rpc"))
     219             :         {
     220           0 :             aosTO.SetNameValue("METHOD", "RPC");
     221             :         }
     222          28 :         else if (EQUAL(argv[i], "-geoloc"))
     223             :         {
     224           0 :             aosTO.SetNameValue("METHOD", "GEOLOC_ARRAY");
     225             :         }
     226          28 :         else if (EQUAL(argv[i], "-i"))
     227             :         {
     228           1 :             bInverse = TRUE;
     229             :         }
     230          27 :         else if (EQUAL(argv[i], "-to"))
     231             :         {
     232           2 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
     233           2 :             aosTO.AddString(argv[++i]);
     234             :         }
     235          25 :         else if (EQUAL(argv[i], "-gcp"))
     236             :         {
     237          12 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(4);
     238          12 :             char *endptr = nullptr;
     239             :             /* -gcp pixel line easting northing [elev] */
     240             : 
     241          12 :             nGCPCount++;
     242             :             pasGCPs = static_cast<GDAL_GCP *>(
     243          12 :                 CPLRealloc(pasGCPs, sizeof(GDAL_GCP) * nGCPCount));
     244          12 :             GDALInitGCPs(1, pasGCPs + nGCPCount - 1);
     245             : 
     246             :             // coverity[tainted_data]
     247          12 :             pasGCPs[nGCPCount - 1].dfGCPPixel = CPLAtof(argv[++i]);
     248             :             // coverity[tainted_data]
     249          12 :             pasGCPs[nGCPCount - 1].dfGCPLine = CPLAtof(argv[++i]);
     250             :             // coverity[tainted_data]
     251          12 :             pasGCPs[nGCPCount - 1].dfGCPX = CPLAtof(argv[++i]);
     252             :             // coverity[tainted_data]
     253          12 :             pasGCPs[nGCPCount - 1].dfGCPY = CPLAtof(argv[++i]);
     254          21 :             if (argv[i + 1] != nullptr &&
     255           9 :                 (CPLStrtod(argv[i + 1], &endptr) != 0.0 ||
     256           9 :                  argv[i + 1][0] == '0'))
     257             :             {
     258             :                 // Check that last argument is really a number and not a
     259             :                 // filename looking like a number (see ticket #863).
     260           3 :                 if (endptr && *endptr == 0)
     261             :                 {
     262             :                     // coverity[tainted_data]
     263           3 :                     pasGCPs[nGCPCount - 1].dfGCPZ = CPLAtof(argv[++i]);
     264             :                 }
     265             :             }
     266             : 
     267             :             /* should set id and info? */
     268             :         }
     269          13 :         else if (EQUAL(argv[i], "-output_xy"))
     270             :         {
     271           2 :             bOutputXY = TRUE;
     272             :         }
     273          11 :         else if (EQUAL(argv[i], "-ignore_extra_input"))
     274             :         {
     275           1 :             bIgnoreExtraInput = true;
     276             :         }
     277          10 :         else if (EQUAL(argv[i], "-E"))
     278             :         {
     279           2 :             bEchoInput = true;
     280             :         }
     281           8 :         else if (i < argc - 1 && EQUAL(argv[i], "-field_sep"))
     282             :         {
     283           4 :             osFieldSep = CPLString(argv[++i])
     284           4 :                              .replaceAll("\\t", '\t')
     285           4 :                              .replaceAll("\\r", '\r')
     286           2 :                              .replaceAll("\\n", '\n');
     287             :         }
     288           6 :         else if (EQUAL(argv[i], "-coord") && i + 2 < argc)
     289             :         {
     290           1 :             bCoordOnCommandLine = true;
     291           1 :             dfX = CPLAtof(argv[++i]);
     292           1 :             dfY = CPLAtof(argv[++i]);
     293           2 :             if (i + 1 < argc &&
     294           1 :                 CPLGetValueType(argv[i + 1]) != CPL_VALUE_STRING)
     295           1 :                 dfZ = CPLAtof(argv[++i]);
     296           2 :             if (i + 1 < argc &&
     297           1 :                 CPLGetValueType(argv[i + 1]) != CPL_VALUE_STRING)
     298           1 :                 dfT = CPLAtof(argv[++i]);
     299             :         }
     300           5 :         else if (argv[i][0] == '-')
     301             :         {
     302           0 :             Usage(true, CPLSPrintf("Unknown option name '%s'", argv[i]));
     303             :         }
     304           5 :         else if (pszSrcFilename == nullptr)
     305             :         {
     306           4 :             pszSrcFilename = argv[i];
     307             :         }
     308           1 :         else if (pszDstFilename == nullptr)
     309             :         {
     310           1 :             pszDstFilename = argv[i];
     311             :         }
     312             :         else
     313             :         {
     314           0 :             Usage(true, "Too many command options.");
     315             :         }
     316             :     }
     317             : 
     318             :     /* -------------------------------------------------------------------- */
     319             :     /*      Open src and destination file, if appropriate.                  */
     320             :     /* -------------------------------------------------------------------- */
     321          14 :     GDALDatasetH hSrcDS = nullptr;
     322          14 :     if (pszSrcFilename != nullptr)
     323             :     {
     324           4 :         hSrcDS = GDALOpen(pszSrcFilename, GA_ReadOnly);
     325           4 :         if (hSrcDS == nullptr)
     326           0 :             exit(1);
     327             :     }
     328             : 
     329          14 :     GDALDatasetH hDstDS = nullptr;
     330          14 :     if (pszDstFilename != nullptr)
     331             :     {
     332           1 :         hDstDS = GDALOpen(pszDstFilename, GA_ReadOnly);
     333           1 :         if (hDstDS == nullptr)
     334           0 :             exit(1);
     335             :     }
     336             : 
     337          14 :     if (hSrcDS != nullptr && nGCPCount > 0)
     338             :     {
     339           0 :         fprintf(stderr, "Command line GCPs and input file specified, "
     340             :                         "specify one or the other.\n");
     341           0 :         exit(1);
     342             :     }
     343             : 
     344             :     /* -------------------------------------------------------------------- */
     345             :     /*      Create a transformation object from the source to               */
     346             :     /*      destination coordinate system.                                  */
     347             :     /* -------------------------------------------------------------------- */
     348          14 :     if (nGCPCount != 0 && nOrder == -1)
     349             :     {
     350           1 :         pfnTransformer = GDALTPSTransform;
     351           1 :         hTransformArg = GDALCreateTPSTransformer(nGCPCount, pasGCPs, FALSE);
     352             :     }
     353          13 :     else if (nGCPCount != 0)
     354             :     {
     355           2 :         pfnTransformer = GDALGCPTransform;
     356             :         hTransformArg =
     357           2 :             GDALCreateGCPTransformer(nGCPCount, pasGCPs, nOrder, FALSE);
     358             :     }
     359             :     else
     360             :     {
     361          11 :         pfnTransformer = GDALGenImgProjTransform;
     362             :         hTransformArg =
     363          11 :             GDALCreateGenImgProjTransformer2(hSrcDS, hDstDS, aosTO.List());
     364             :     }
     365             : 
     366          14 :     if (hTransformArg == nullptr)
     367             :     {
     368           0 :         exit(1);
     369             :     }
     370             : 
     371             :     /* -------------------------------------------------------------------- */
     372             :     /*      Read points from stdin, transform and write to stdout.          */
     373             :     /* -------------------------------------------------------------------- */
     374          14 :     double dfLastT = 0.0;
     375             : 
     376          14 :     if (!bCoordOnCommandLine)
     377             :     {
     378             :         // Is it an interactive terminal ?
     379          13 :         if (isatty(static_cast<int>(fileno(stdin))))
     380             :         {
     381           0 :             if (pszSrcFilename != nullptr)
     382             :             {
     383           0 :                 fprintf(stderr, "Enter column line values separated by space, "
     384             :                                 "and press Return.\n");
     385             :             }
     386             :             else
     387             :             {
     388           0 :                 fprintf(stderr, "Enter X Y [Z [T]] values separated by space, "
     389             :                                 "and press Return.\n");
     390             :             }
     391             :         }
     392             :     }
     393             : 
     394          14 :     int nLine = 0;
     395          39 :     while (bCoordOnCommandLine || !feof(stdin))
     396             :     {
     397          39 :         std::string osExtraContent;
     398          39 :         if (!bCoordOnCommandLine)
     399             :         {
     400             :             char szLine[1024];
     401             : 
     402          38 :             if (fgets(szLine, sizeof(szLine) - 1, stdin) == nullptr)
     403          13 :                 break;
     404             : 
     405          25 :             const CPLStringList aosTokens(CSLTokenizeString(szLine));
     406          25 :             const int nCount = aosTokens.size();
     407             : 
     408          25 :             ++nLine;
     409          25 :             if (nCount < 2)
     410             :             {
     411           0 :                 fprintf(stderr, "Not enough values at line %d\n", nLine);
     412           0 :                 continue;
     413             :             }
     414             : 
     415          25 :             dfX = CPLAtof(aosTokens[0]);
     416          25 :             dfY = CPLAtof(aosTokens[1]);
     417          25 :             dfZ = 0.0;
     418          25 :             dfT = 0.0;
     419          25 :             int iStartExtraContent = nCount;
     420          25 :             if (nCount >= 3)
     421             :             {
     422          10 :                 if (CPLGetValueType(aosTokens[2]) == CPL_VALUE_STRING)
     423             :                 {
     424           1 :                     iStartExtraContent = 2;
     425             :                 }
     426             :                 else
     427             :                 {
     428           9 :                     dfZ = CPLAtof(aosTokens[2]);
     429             : 
     430           9 :                     if (nCount >= 4)
     431             :                     {
     432           5 :                         if (CPLGetValueType(aosTokens[3]) == CPL_VALUE_STRING)
     433             :                         {
     434           4 :                             iStartExtraContent = 3;
     435             :                         }
     436             :                         else
     437             :                         {
     438           1 :                             dfT = CPLAtof(aosTokens[3]);
     439           1 :                             iStartExtraContent = 4;
     440             :                         }
     441             :                     }
     442             :                 }
     443             :             }
     444             : 
     445          25 :             if (!bIgnoreExtraInput)
     446             :             {
     447          37 :                 for (int i = iStartExtraContent; i < nCount; ++i)
     448             :                 {
     449          13 :                     if (!osExtraContent.empty())
     450           8 :                         osExtraContent += ' ';
     451          13 :                     osExtraContent += aosTokens[i];
     452             :                 }
     453          39 :                 while (!osExtraContent.empty() &&
     454          10 :                        isspace(static_cast<int>(osExtraContent.back())))
     455             :                 {
     456           5 :                     osExtraContent.pop_back();
     457             :                 }
     458          24 :                 if (!osExtraContent.empty())
     459           5 :                     osExtraContent = osFieldSep + osExtraContent;
     460             :             }
     461             :         }
     462          26 :         if (dfT != dfLastT && nGCPCount == 0)
     463             :         {
     464           2 :             if (dfT != 0.0)
     465             :             {
     466           2 :                 aosTO.SetNameValue("COORDINATE_EPOCH", CPLSPrintf("%g", dfT));
     467             :             }
     468             :             else
     469             :             {
     470           0 :                 aosTO.SetNameValue("COORDINATE_EPOCH", nullptr);
     471             :             }
     472           2 :             GDALDestroyGenImgProjTransformer(hTransformArg);
     473             :             hTransformArg =
     474           2 :                 GDALCreateGenImgProjTransformer2(hSrcDS, hDstDS, aosTO.List());
     475             :         }
     476             : 
     477          26 :         int bSuccess = TRUE;
     478          26 :         const double dfXBefore = dfX;
     479          26 :         const double dfYBefore = dfY;
     480          26 :         const double dfZBefore = dfZ;
     481          26 :         if (pfnTransformer(hTransformArg, bInverse, 1, &dfX, &dfY, &dfZ,
     482          52 :                            &bSuccess) &&
     483          26 :             bSuccess)
     484             :         {
     485          26 :             if (bEchoInput)
     486             :             {
     487           2 :                 if (bOutputXY)
     488           1 :                     CPLprintf("%.15g%s%.15g%s", dfXBefore, osFieldSep.c_str(),
     489             :                               dfYBefore, osFieldSep.c_str());
     490             :                 else
     491           1 :                     CPLprintf("%.15g%s%.15g%s%.15g%s", dfXBefore,
     492             :                               osFieldSep.c_str(), dfYBefore, osFieldSep.c_str(),
     493             :                               dfZBefore, osFieldSep.c_str());
     494             :             }
     495          26 :             if (bOutputXY)
     496           2 :                 CPLprintf("%.15g%s%.15g%s\n", dfX, osFieldSep.c_str(), dfY,
     497             :                           osExtraContent.c_str());
     498             :             else
     499          24 :                 CPLprintf("%.15g%s%.15g%s%.15g%s\n", dfX, osFieldSep.c_str(),
     500             :                           dfY, osFieldSep.c_str(), dfZ, osExtraContent.c_str());
     501             :         }
     502             :         else
     503             :         {
     504           0 :             printf("transformation failed.\n");
     505             :         }
     506             : 
     507          26 :         if (bCoordOnCommandLine)
     508           1 :             break;
     509          25 :         dfLastT = dfT;
     510             :     }
     511             : 
     512          14 :     if (nGCPCount != 0 && nOrder == -1)
     513             :     {
     514           1 :         GDALDestroyTPSTransformer(hTransformArg);
     515             :     }
     516          13 :     else if (nGCPCount != 0)
     517             :     {
     518           2 :         GDALDestroyGCPTransformer(hTransformArg);
     519             :     }
     520             :     else
     521             :     {
     522          11 :         GDALDestroyGenImgProjTransformer(hTransformArg);
     523             :     }
     524             : 
     525          14 :     if (nGCPCount)
     526             :     {
     527           3 :         GDALDeinitGCPs(nGCPCount, pasGCPs);
     528           3 :         CPLFree(pasGCPs);
     529             :     }
     530             : 
     531          14 :     if (hSrcDS)
     532           4 :         GDALClose(hSrcDS);
     533             : 
     534          14 :     if (hDstDS)
     535           1 :         GDALClose(hDstDS);
     536             : 
     537          14 :     GDALDumpOpenDatasets(stderr);
     538          14 :     GDALDestroyDriverManager();
     539             : 
     540          14 :     CSLDestroy(argv);
     541             : 
     542          14 :     return 0;
     543             : }
     544             : 
     545           0 : MAIN_END

Generated by: LCOV version 1.14