LCOV - code coverage report
Current view: top level - apps - gdallocationinfo.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 310 374 82.9 %
Date: 2025-05-15 13:16:46 Functions: 4 5 80.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Command line raster query tool.
       5             :  * Author:   Frank Warmerdam <warmerdam@pobox.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2010, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_string.h"
      15             : #include "cpl_minixml.h"
      16             : #include "gdal_version.h"
      17             : #include "gdal.h"
      18             : #include "gdal_priv.h"
      19             : #include "commonutils.h"
      20             : #include "ogr_spatialref.h"
      21             : #include "gdalargumentparser.h"
      22             : 
      23             : #include <cmath>
      24             : #include <limits>
      25             : #include <vector>
      26             : 
      27             : #include <cctype>
      28             : 
      29             : /************************************************************************/
      30             : /*                             GetSRSAsWKT                              */
      31             : /************************************************************************/
      32             : 
      33           1 : static std::string GetSRSAsWKT(const char *pszUserInput)
      34             : 
      35             : {
      36           2 :     OGRSpatialReference oSRS;
      37           1 :     oSRS.SetFromUserInput(pszUserInput);
      38           2 :     return oSRS.exportToWkt();
      39             : }
      40             : 
      41             : /************************************************************************/
      42             : /*                                main()                                */
      43             : /************************************************************************/
      44             : 
      45          35 : MAIN_START(argc, argv)
      46             : 
      47             : {
      48          35 :     double dfGeoX = std::numeric_limits<double>::quiet_NaN();
      49          35 :     double dfGeoY = std::numeric_limits<double>::quiet_NaN();
      50          66 :     std::string osSrcFilename;
      51          66 :     std::string osSourceSRS;
      52          66 :     std::vector<int> anBandList;
      53          35 :     bool bAsXML = false, bLIFOnly = false;
      54          35 :     bool bQuiet = false, bValOnly = false;
      55          35 :     int nOverview = 0;
      56          66 :     CPLStringList aosOpenOptions;
      57          66 :     std::string osFieldSep;
      58          35 :     bool bIgnoreExtraInput = false;
      59          35 :     bool bEcho = false;
      60             : 
      61          35 :     GDALAllRegister();
      62          35 :     argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
      63          35 :     if (argc < 1)
      64           1 :         exit(-argc);
      65          65 :     CPLStringList aosArgv;
      66          34 :     aosArgv.Assign(argv, /* bAssign = */ true);
      67             : 
      68          99 :     GDALArgumentParser argParser(aosArgv[0], /* bForBinary=*/true);
      69             : 
      70          34 :     argParser.add_description(_("Raster query tool."));
      71             : 
      72          34 :     const char *pszEpilog =
      73             :         _("For more details, consult "
      74             :           "https://gdal.org/programs/gdallocationinfo.html");
      75          34 :     argParser.add_epilog(pszEpilog);
      76             : 
      77          34 :     argParser.add_argument("-xml").flag().store_into(bAsXML).help(
      78          34 :         _("Format the output report as XML."));
      79             : 
      80          34 :     argParser.add_argument("-lifonly")
      81          34 :         .flag()
      82          34 :         .store_into(bLIFOnly)
      83             :         .help(_("Only outputs filenames from the LocationInfo request against "
      84          34 :                 "the database."));
      85             : 
      86          34 :     argParser.add_argument("-valonly")
      87          34 :         .flag()
      88          34 :         .store_into(bValOnly)
      89             :         .help(_("Only outputs pixel values of the selected pixel on each of "
      90          34 :                 "the selected bands."));
      91             : 
      92          34 :     argParser.add_argument("-E").flag().store_into(bEcho).help(
      93             :         _("Enable Echo mode, where input coordinates are prepended to the "
      94          34 :           "output lines in -valonly mode."));
      95             : 
      96          34 :     argParser.add_argument("-field_sep")
      97          68 :         .metavar("<sep>")
      98          34 :         .store_into(osFieldSep)
      99             :         .help(_("Defines the field separator, used in -valonly mode, to "
     100          34 :                 "separate different values."));
     101             : 
     102          34 :     argParser.add_argument("-ignore_extra_input")
     103          34 :         .flag()
     104          34 :         .store_into(bIgnoreExtraInput)
     105             :         .help(_("Set this flag to avoid extra non-numeric content at end of "
     106          34 :                 "input lines."));
     107             : 
     108          34 :     argParser.add_argument("-b")
     109          34 :         .append()
     110          68 :         .metavar("<band>")
     111          34 :         .store_into(anBandList)
     112          34 :         .help(_("Select band(s)."));
     113             : 
     114          34 :     argParser.add_argument("-overview")
     115          68 :         .metavar("<overview_level>")
     116          34 :         .store_into(nOverview)
     117             :         .help(_("Query the (overview_level)th overview (overview_level=1 is "
     118          34 :                 "the 1st overview)."));
     119             : 
     120          65 :     std::string osResampling;
     121          34 :     argParser.add_argument("-r")
     122          34 :         .store_into(osResampling)
     123          68 :         .metavar("nearest|bilinear|cubic|cubicspline")
     124          34 :         .help(_("Select an interpolation algorithm."));
     125             : 
     126             :     {
     127          34 :         auto &group = argParser.add_mutually_exclusive_group();
     128             : 
     129          34 :         group.add_argument("-l_srs")
     130          68 :             .metavar("<srs_def>")
     131          34 :             .store_into(osSourceSRS)
     132          34 :             .help(_("Coordinate system of the input x, y location."));
     133             : 
     134          34 :         group.add_argument("-geoloc")
     135          34 :             .flag()
     136           5 :             .action([&osSourceSRS](const std::string &)
     137          39 :                     { osSourceSRS = "-geoloc"; })
     138             :             .help(_("Indicates input x,y points are in the georeferencing "
     139          34 :                     "system of the image."));
     140             : 
     141          34 :         group.add_argument("-wgs84")
     142          34 :             .flag()
     143           2 :             .action([&osSourceSRS](const std::string &)
     144          35 :                     { osSourceSRS = GetSRSAsWKT("WGS84"); })
     145          34 :             .help(_("Indicates input x,y points are WGS84 long, lat."));
     146             :     }
     147             : 
     148          34 :     argParser.add_open_options_argument(&aosOpenOptions);
     149             : 
     150          34 :     argParser.add_argument("srcfile")
     151          68 :         .metavar("<srcfile>")
     152          34 :         .nargs(1)
     153          34 :         .store_into(osSrcFilename)
     154          34 :         .help(_("The source GDAL raster datasource name."));
     155             : 
     156          34 :     argParser.add_argument("x")
     157          68 :         .metavar("<x>")
     158          34 :         .nargs(argparse::nargs_pattern::optional)
     159          34 :         .store_into(dfGeoX)
     160          34 :         .help(_("X location of target pixel."));
     161             : 
     162          34 :     argParser.add_argument("y")
     163          68 :         .metavar("<y>")
     164          34 :         .nargs(argparse::nargs_pattern::optional)
     165          34 :         .store_into(dfGeoY)
     166          34 :         .help(_("Y location of target pixel."));
     167             : 
     168           0 :     const auto displayUsage = [&argParser]()
     169             :     {
     170           0 :         std::stringstream usageStringStream;
     171           0 :         usageStringStream << argParser.usage();
     172           0 :         std::cerr << CPLString(usageStringStream.str())
     173           0 :                          .replaceAll("<x> <y>", "[<x> <y>]")
     174           0 :                   << std::endl
     175           0 :                   << std::endl;
     176             :         std::cout << _("Note: ") << "gdallocationinfo"
     177           0 :                   << _(" --long-usage for full help.") << std::endl;
     178           0 :     };
     179             : 
     180             :     try
     181             :     {
     182          34 :         argParser.parse_args(aosArgv);
     183             :     }
     184           0 :     catch (const std::exception &err)
     185             :     {
     186           0 :         std::cerr << _("Error: ") << err.what() << std::endl;
     187           0 :         displayUsage();
     188           0 :         std::exit(1);
     189             :     }
     190             : 
     191          34 :     if (bLIFOnly || bValOnly)
     192          23 :         bQuiet = true;
     193             : 
     194             :     // User specifies with 1-based index, but internally we use 0-based index
     195          34 :     --nOverview;
     196             : 
     197             :     // Deal with special characters
     198          34 :     osFieldSep = CPLString(osFieldSep)
     199          68 :                      .replaceAll("\\t", '\t')
     200          68 :                      .replaceAll("\\r", '\r')
     201          34 :                      .replaceAll("\\n", '\n');
     202             : 
     203          34 :     if (!std::isnan(dfGeoX) && std::isnan(dfGeoY))
     204             :     {
     205           0 :         fprintf(stderr, "<y> should be specified when <x> is specified\n\n");
     206           0 :         displayUsage();
     207           0 :         exit(1);
     208             :     }
     209             : 
     210          34 :     const bool bIsXYSpecifiedAsArgument = !std::isnan(dfGeoX);
     211             : 
     212          34 :     if (bEcho && !bValOnly)
     213             :     {
     214           1 :         fprintf(stderr, "-E can only be used with -valonly\n");
     215           1 :         exit(1);
     216             :     }
     217          33 :     if (bEcho && osFieldSep.empty())
     218             :     {
     219           1 :         fprintf(stderr, "-E can only be used if -field_sep is specified (to a "
     220             :                         "non-newline value)\n");
     221           1 :         exit(1);
     222             :     }
     223             : 
     224          32 :     if (osFieldSep.empty())
     225             :     {
     226          23 :         osFieldSep = "\n";
     227             :     }
     228           9 :     else if (!bValOnly)
     229             :     {
     230           0 :         fprintf(stderr, "-field_sep can only be used with -valonly\n");
     231           0 :         exit(1);
     232             :     }
     233             : 
     234             :     const GDALRIOResampleAlg eInterpolation =
     235          32 :         osResampling.empty() ? GRIORA_NearestNeighbour
     236          10 :                              : GDALRasterIOGetResampleAlg(osResampling.c_str());
     237          32 :     if (eInterpolation != GRIORA_NearestNeighbour &&
     238           4 :         eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
     239             :         eInterpolation != GRIORA_CubicSpline)
     240             :     {
     241           1 :         fprintf(stderr, "-r can only be used with values nearest, bilinear, "
     242             :                         "cubic and cubicspline\n");
     243           1 :         exit(1);
     244             :     }
     245             : 
     246             :     /* -------------------------------------------------------------------- */
     247             :     /*      Open source file.                                               */
     248             :     /* -------------------------------------------------------------------- */
     249          31 :     GDALDatasetH hSrcDS = GDALOpenEx(osSrcFilename.c_str(),
     250             :                                      GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
     251          31 :                                      nullptr, aosOpenOptions.List(), nullptr);
     252          31 :     if (hSrcDS == nullptr)
     253           0 :         exit(1);
     254             : 
     255             :     /* -------------------------------------------------------------------- */
     256             :     /*      Setup coordinate transformation, if required                    */
     257             :     /* -------------------------------------------------------------------- */
     258          31 :     OGRSpatialReferenceH hSrcSRS = nullptr;
     259          31 :     OGRCoordinateTransformationH hCT = nullptr;
     260          31 :     if (!osSourceSRS.empty() && !EQUAL(osSourceSRS.c_str(), "-geoloc"))
     261             :     {
     262           4 :         hSrcSRS = OSRNewSpatialReference(nullptr);
     263           4 :         OGRErr err = OSRSetFromUserInput(hSrcSRS, osSourceSRS.c_str());
     264           4 :         if (err != OGRERR_NONE)
     265           0 :             exit(1);
     266           4 :         OSRSetAxisMappingStrategy(hSrcSRS, OAMS_TRADITIONAL_GIS_ORDER);
     267           4 :         auto hTrgSRS = GDALGetSpatialRef(hSrcDS);
     268           4 :         if (!hTrgSRS)
     269           0 :             exit(1);
     270             : 
     271           4 :         hCT = OCTNewCoordinateTransformation(hSrcSRS, hTrgSRS);
     272           4 :         if (hCT == nullptr)
     273           0 :             exit(1);
     274             :     }
     275             : 
     276             :     /* -------------------------------------------------------------------- */
     277             :     /*      If no bands were requested, we will query them all.             */
     278             :     /* -------------------------------------------------------------------- */
     279          31 :     if (anBandList.empty())
     280             :     {
     281          66 :         for (int i = 0; i < GDALGetRasterCount(hSrcDS); i++)
     282          36 :             anBandList.push_back(i + 1);
     283             :     }
     284             : 
     285             :     /* -------------------------------------------------------------------- */
     286             :     /*      Turn the location into a pixel and line location.               */
     287             :     /* -------------------------------------------------------------------- */
     288          31 :     bool inputAvailable = true;
     289          62 :     CPLString osXML;
     290             :     char szLine[1024];
     291          31 :     int nLine = 0;
     292          31 :     std::string osExtraContent;
     293             : 
     294          31 :     if (std::isnan(dfGeoX))
     295             :     {
     296             :         // Is it an interactive terminal ?
     297          14 :         if (CPLIsInteractive(stdin))
     298             :         {
     299           0 :             if (!osSourceSRS.empty())
     300             :             {
     301           0 :                 fprintf(stderr, "Enter X Y values separated by space, and "
     302             :                                 "press Return.\n");
     303             :             }
     304             :             else
     305             :             {
     306           0 :                 fprintf(stderr, "Enter pixel line values separated by space, "
     307             :                                 "and press Return.\n");
     308             :             }
     309             :         }
     310             : 
     311          14 :         if (fgets(szLine, sizeof(szLine) - 1, stdin))
     312             :         {
     313          28 :             const CPLStringList aosTokens(CSLTokenizeString(szLine));
     314          14 :             const int nCount = aosTokens.size();
     315             : 
     316          14 :             ++nLine;
     317          14 :             if (nCount < 2)
     318             :             {
     319           0 :                 fprintf(stderr, "Not enough values at line %d\n", nLine);
     320           0 :                 inputAvailable = false;
     321             :             }
     322             :             else
     323             :             {
     324          14 :                 dfGeoX = CPLAtof(aosTokens[0]);
     325          14 :                 dfGeoY = CPLAtof(aosTokens[1]);
     326          14 :                 if (!bIgnoreExtraInput)
     327             :                 {
     328          22 :                     for (int i = 2; i < nCount; ++i)
     329             :                     {
     330           9 :                         if (!osExtraContent.empty())
     331           4 :                             osExtraContent += ' ';
     332           9 :                         osExtraContent += aosTokens[i];
     333             :                     }
     334          18 :                     while (!osExtraContent.empty() &&
     335           5 :                            isspace(static_cast<int>(osExtraContent.back())))
     336             :                     {
     337           0 :                         osExtraContent.pop_back();
     338             :                     }
     339             :                 }
     340             :             }
     341             :         }
     342             :         else
     343             :         {
     344           0 :             inputAvailable = false;
     345             :         }
     346             :     }
     347             : 
     348          31 :     int nRetCode = 0;
     349          39 :     while (inputAvailable)
     350             :     {
     351             :         int iPixel, iLine;
     352          39 :         double dfPixel{0}, dfLine{0};
     353          39 :         const double dfXIn = dfGeoX;
     354          39 :         const double dfYIn = dfGeoY;
     355             : 
     356          39 :         if (hCT)
     357             :         {
     358           4 :             if (!OCTTransform(hCT, 1, &dfGeoX, &dfGeoY, nullptr))
     359           0 :                 exit(1);
     360             :         }
     361             : 
     362          39 :         if (!osSourceSRS.empty())
     363             :         {
     364           9 :             double adfGeoTransform[6] = {};
     365           9 :             if (GDALGetGeoTransform(hSrcDS, adfGeoTransform) != CE_None)
     366             :             {
     367           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     368             :                          "Cannot get geotransform");
     369           0 :                 exit(1);
     370             :             }
     371             : 
     372           9 :             double adfInvGeoTransform[6] = {};
     373           9 :             if (!GDALInvGeoTransform(adfGeoTransform, adfInvGeoTransform))
     374             :             {
     375           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     376             :                          "Cannot invert geotransform");
     377           0 :                 exit(1);
     378             :             }
     379             : 
     380           9 :             dfPixel = adfInvGeoTransform[0] + adfInvGeoTransform[1] * dfGeoX +
     381           9 :                       adfInvGeoTransform[2] * dfGeoY;
     382           9 :             dfLine = adfInvGeoTransform[3] + adfInvGeoTransform[4] * dfGeoX +
     383           9 :                      adfInvGeoTransform[5] * dfGeoY;
     384             :         }
     385             :         else
     386             :         {
     387          30 :             dfPixel = dfGeoX;
     388          30 :             dfLine = dfGeoY;
     389             :         }
     390          39 :         iPixel = static_cast<int>(floor(dfPixel));
     391          39 :         iLine = static_cast<int>(floor(dfLine));
     392             : 
     393             :         /* --------------------------------------------------------------------
     394             :          */
     395             :         /*      Prepare report. */
     396             :         /* --------------------------------------------------------------------
     397             :          */
     398          39 :         CPLString osXmlLine;
     399             : 
     400          39 :         if (bAsXML)
     401             :         {
     402             :             osXmlLine.Printf("<Report pixel=\"%d\" line=\"%d\">", iPixel,
     403           2 :                              iLine);
     404           2 :             osXML += osXmlLine;
     405           2 :             if (!osExtraContent.empty())
     406             :             {
     407             :                 char *pszEscaped =
     408           1 :                     CPLEscapeString(osExtraContent.c_str(), -1, CPLES_XML);
     409           2 :                 osXML += CPLString().Printf("  <ExtraInput>%s</ExtraInput>",
     410           1 :                                             pszEscaped);
     411           1 :                 CPLFree(pszEscaped);
     412             :             }
     413             :         }
     414          37 :         else if (!bQuiet)
     415             :         {
     416           8 :             printf("Report:\n");
     417          16 :             CPLString osPixel, osLine;
     418           8 :             if (eInterpolation == GRIORA_NearestNeighbour)
     419             :             {
     420           5 :                 osPixel.Printf("%d", iPixel);
     421           5 :                 osLine.Printf("%d", iLine);
     422             :             }
     423             :             else
     424             :             {
     425           3 :                 osPixel.Printf("%.15g", dfPixel);
     426           3 :                 osLine.Printf("%.15g", dfLine);
     427             :             }
     428           8 :             printf("  Location: (%sP,%sL)\n", osPixel.c_str(), osLine.c_str());
     429           8 :             if (!osExtraContent.empty())
     430             :             {
     431           1 :                 printf("  Extra input: %s\n", osExtraContent.c_str());
     432             :             }
     433             :         }
     434          29 :         else if (bEcho)
     435             :         {
     436           9 :             printf("%.15g%s%.15g%s", dfXIn, osFieldSep.c_str(), dfYIn,
     437             :                    osFieldSep.c_str());
     438             :         }
     439             : 
     440          39 :         bool bPixelReport = true;
     441             : 
     442          35 :         if (iPixel < 0 || iLine < 0 ||
     443         109 :             dfPixel > static_cast<double>(GDALGetRasterXSize(hSrcDS) + 1e-5) ||
     444          35 :             dfLine > static_cast<double>(GDALGetRasterYSize(hSrcDS) + 1e-5))
     445             :         {
     446           4 :             if (bAsXML)
     447             :                 osXML += "<Alert>Location is off this file! No further details "
     448           0 :                          "to report.</Alert>";
     449           4 :             else if (bValOnly)
     450             :             {
     451           8 :                 for (int i = 1; i < static_cast<int>(anBandList.size()); i++)
     452             :                 {
     453           4 :                     printf("%s", osFieldSep.c_str());
     454             :                 }
     455             :             }
     456           0 :             else if (!bQuiet)
     457           0 :                 printf("\nLocation is off this file! No further details to "
     458             :                        "report.\n");
     459           4 :             bPixelReport = false;
     460           4 :             nRetCode = 1;
     461             :         }
     462             : 
     463             :         /* --------------------------------------------------------------------
     464             :          */
     465             :         /*      Process each band. */
     466             :         /* --------------------------------------------------------------------
     467             :          */
     468          84 :         for (int i = 0; bPixelReport && i < static_cast<int>(anBandList.size());
     469             :              i++)
     470             :         {
     471          45 :             GDALRasterBandH hBand = GDALGetRasterBand(hSrcDS, anBandList[i]);
     472             : 
     473          45 :             int iPixelToQuery = iPixel;
     474          45 :             int iLineToQuery = iLine;
     475             : 
     476          45 :             double dfPixelToQuery = dfPixel;
     477          45 :             double dfLineToQuery = dfLine;
     478             : 
     479          45 :             if (nOverview >= 0 && hBand != nullptr)
     480             :             {
     481           1 :                 GDALRasterBandH hOvrBand = GDALGetOverview(hBand, nOverview);
     482           1 :                 if (hOvrBand != nullptr)
     483             :                 {
     484           1 :                     int nOvrXSize = GDALGetRasterBandXSize(hOvrBand);
     485           1 :                     int nOvrYSize = GDALGetRasterBandYSize(hOvrBand);
     486           1 :                     iPixelToQuery = static_cast<int>(
     487           1 :                         0.5 +
     488           1 :                         1.0 * iPixel / GDALGetRasterXSize(hSrcDS) * nOvrXSize);
     489           1 :                     iLineToQuery = static_cast<int>(
     490           1 :                         0.5 +
     491           1 :                         1.0 * iLine / GDALGetRasterYSize(hSrcDS) * nOvrYSize);
     492           1 :                     if (iPixelToQuery >= nOvrXSize)
     493           0 :                         iPixelToQuery = nOvrXSize - 1;
     494           1 :                     if (iLineToQuery >= nOvrYSize)
     495           0 :                         iLineToQuery = nOvrYSize - 1;
     496           1 :                     dfPixelToQuery =
     497           1 :                         dfPixel / GDALGetRasterXSize(hSrcDS) * nOvrXSize;
     498           1 :                     dfLineToQuery =
     499           1 :                         dfLine / GDALGetRasterYSize(hSrcDS) * nOvrYSize;
     500             :                 }
     501             :                 else
     502             :                 {
     503           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     504             :                              "Cannot get overview %d of band %d", nOverview + 1,
     505           0 :                              anBandList[i]);
     506             :                 }
     507           1 :                 hBand = hOvrBand;
     508             :             }
     509             : 
     510          45 :             if (hBand == nullptr)
     511           0 :                 continue;
     512             : 
     513          45 :             if (bAsXML)
     514             :             {
     515           2 :                 osXmlLine.Printf("<BandReport band=\"%d\">", anBandList[i]);
     516           2 :                 osXML += osXmlLine;
     517             :             }
     518          43 :             else if (!bQuiet)
     519             :             {
     520           8 :                 printf("  Band %d:\n", anBandList[i]);
     521             :             }
     522             : 
     523             :             /* --------------------------------------------------------------------
     524             :              */
     525             :             /*      Request location info for this location.  It is possible */
     526             :             /*      only the VRT driver actually supports this. */
     527             :             /* --------------------------------------------------------------------
     528             :              */
     529          90 :             CPLString osItem;
     530             : 
     531          45 :             osItem.Printf("Pixel_%d_%d", iPixelToQuery, iLineToQuery);
     532             : 
     533             :             const char *pszLI =
     534          45 :                 GDALGetMetadataItem(hBand, osItem, "LocationInfo");
     535             : 
     536          45 :             if (pszLI != nullptr)
     537             :             {
     538           1 :                 if (bAsXML)
     539           0 :                     osXML += pszLI;
     540           1 :                 else if (!bQuiet)
     541           0 :                     printf("    %s\n", pszLI);
     542           1 :                 else if (bLIFOnly)
     543             :                 {
     544             :                     /* Extract all files, if any. */
     545             : 
     546           1 :                     CPLXMLNode *psRoot = CPLParseXMLString(pszLI);
     547             : 
     548           1 :                     if (psRoot != nullptr && psRoot->psChild != nullptr &&
     549           1 :                         psRoot->eType == CXT_Element &&
     550           1 :                         EQUAL(psRoot->pszValue, "LocationInfo"))
     551             :                     {
     552           1 :                         for (CPLXMLNode *psNode = psRoot->psChild;
     553           2 :                              psNode != nullptr; psNode = psNode->psNext)
     554             :                         {
     555           1 :                             if (psNode->eType == CXT_Element &&
     556           1 :                                 EQUAL(psNode->pszValue, "File") &&
     557           1 :                                 psNode->psChild != nullptr)
     558             :                             {
     559             :                                 char *pszUnescaped =
     560           1 :                                     CPLUnescapeString(psNode->psChild->pszValue,
     561             :                                                       nullptr, CPLES_XML);
     562           1 :                                 printf("%s\n", pszUnescaped);
     563           1 :                                 CPLFree(pszUnescaped);
     564             :                             }
     565             :                         }
     566             :                     }
     567           1 :                     CPLDestroyXMLNode(psRoot);
     568             :                 }
     569             :             }
     570             : 
     571             :             /* --------------------------------------------------------------------
     572             :              */
     573             :             /*      Report the pixel value of this band. */
     574             :             /* --------------------------------------------------------------------
     575             :              */
     576          45 :             double adfPixel[2] = {0, 0};
     577          45 :             const bool bIsComplex = CPL_TO_BOOL(
     578             :                 GDALDataTypeIsComplex(GDALGetRasterDataType(hBand)));
     579             : 
     580             :             CPLErr err;
     581          45 :             err = GDALRasterInterpolateAtPoint(hBand, dfPixelToQuery,
     582             :                                                dfLineToQuery, eInterpolation,
     583             :                                                &adfPixel[0], &adfPixel[1]);
     584             : 
     585          45 :             if (err == CE_None)
     586             :             {
     587          88 :                 CPLString osValue;
     588             : 
     589          44 :                 if (bIsComplex)
     590           0 :                     osValue.Printf("%.15g+%.15gi", adfPixel[0], adfPixel[1]);
     591             :                 else
     592          44 :                     osValue.Printf("%.15g", adfPixel[0]);
     593             : 
     594          44 :                 if (bAsXML)
     595             :                 {
     596           2 :                     osXML += "<Value>";
     597           2 :                     osXML += osValue;
     598           2 :                     osXML += "</Value>";
     599             :                 }
     600          42 :                 else if (!bQuiet)
     601           8 :                     printf("    Value: %s\n", osValue.c_str());
     602          34 :                 else if (bValOnly)
     603             :                 {
     604          34 :                     if (i > 0)
     605          10 :                         printf("%s", osFieldSep.c_str());
     606          34 :                     printf("%s", osValue.c_str());
     607             :                 }
     608             : 
     609             :                 // Report unscaled if we have scale/offset values.
     610             :                 int bSuccess;
     611             : 
     612          44 :                 double dfOffset = GDALGetRasterOffset(hBand, &bSuccess);
     613             :                 // TODO: Should we turn on checking of bSuccess?
     614             :                 // Alternatively, delete these checks and put a comment as to
     615             :                 // why checking bSuccess does not matter.
     616             : #if 0
     617             :                 if (bSuccess == FALSE)
     618             :                 {
     619             :                     CPLError( CE_Debug, CPLE_AppDefined,
     620             :                               "Unable to get raster offset." );
     621             :                 }
     622             : #endif
     623          44 :                 double dfScale = GDALGetRasterScale(hBand, &bSuccess);
     624             : #if 0
     625             :                 if (bSuccess == FALSE)
     626             :                 {
     627             :                     CPLError( CE_Debug, CPLE_AppDefined,
     628             :                               "Unable to get raster scale." );
     629             :                 }
     630             : #endif
     631          44 :                 if (dfOffset != 0.0 || dfScale != 1.0)
     632             :                 {
     633           0 :                     adfPixel[0] = adfPixel[0] * dfScale + dfOffset;
     634             : 
     635           0 :                     if (bIsComplex)
     636             :                     {
     637           0 :                         adfPixel[1] = adfPixel[1] * dfScale + dfOffset;
     638             :                         osValue.Printf("%.15g+%.15gi", adfPixel[0],
     639           0 :                                        adfPixel[1]);
     640             :                     }
     641             :                     else
     642           0 :                         osValue.Printf("%.15g", adfPixel[0]);
     643             : 
     644           0 :                     if (bAsXML)
     645             :                     {
     646           0 :                         osXML += "<DescaledValue>";
     647           0 :                         osXML += osValue;
     648           0 :                         osXML += "</DescaledValue>";
     649             :                     }
     650           0 :                     else if (!bQuiet)
     651           0 :                         printf("    Descaled Value: %s\n", osValue.c_str());
     652             :                 }
     653             :             }
     654             : 
     655          45 :             if (bAsXML)
     656           2 :                 osXML += "</BandReport>";
     657             :         }
     658             : 
     659          39 :         osXML += "</Report>";
     660             : 
     661          39 :         if (bValOnly)
     662             :         {
     663          28 :             if (!osExtraContent.empty() && osFieldSep != "\n")
     664           2 :                 printf("%s%s", osFieldSep.c_str(), osExtraContent.c_str());
     665          28 :             printf("\n");
     666             :         }
     667             : 
     668          39 :         if (bIsXYSpecifiedAsArgument)
     669          17 :             break;
     670             : 
     671          22 :         osExtraContent.clear();
     672          22 :         if (fgets(szLine, sizeof(szLine) - 1, stdin))
     673             :         {
     674           8 :             const CPLStringList aosTokens(CSLTokenizeString(szLine));
     675           8 :             const int nCount = aosTokens.size();
     676             : 
     677           8 :             ++nLine;
     678           8 :             if (nCount < 2)
     679             :             {
     680           0 :                 fprintf(stderr, "Not enough values at line %d\n", nLine);
     681           0 :                 continue;
     682             :             }
     683             :             else
     684             :             {
     685           8 :                 dfGeoX = CPLAtof(aosTokens[0]);
     686           8 :                 dfGeoY = CPLAtof(aosTokens[1]);
     687           8 :                 if (!bIgnoreExtraInput)
     688             :                 {
     689           8 :                     for (int i = 2; i < nCount; ++i)
     690             :                     {
     691           0 :                         if (!osExtraContent.empty())
     692           0 :                             osExtraContent += ' ';
     693           0 :                         osExtraContent += aosTokens[i];
     694             :                     }
     695           8 :                     while (!osExtraContent.empty() &&
     696           0 :                            isspace(static_cast<int>(osExtraContent.back())))
     697             :                     {
     698           0 :                         osExtraContent.pop_back();
     699             :                     }
     700             :                 }
     701             :             }
     702             :         }
     703             :         else
     704             :         {
     705          14 :             break;
     706             :         }
     707             :     }
     708             : 
     709             :     /* -------------------------------------------------------------------- */
     710             :     /*      Finalize xml report and print.                                  */
     711             :     /* -------------------------------------------------------------------- */
     712          31 :     if (bAsXML)
     713             :     {
     714           2 :         CPLXMLNode *psRoot = CPLParseXMLString(osXML);
     715           2 :         char *pszFormattedXML = CPLSerializeXMLTree(psRoot);
     716           2 :         CPLDestroyXMLNode(psRoot);
     717             : 
     718           2 :         printf("%s", pszFormattedXML);
     719           2 :         CPLFree(pszFormattedXML);
     720             :     }
     721             : 
     722             :     /* -------------------------------------------------------------------- */
     723             :     /*      Cleanup                                                         */
     724             :     /* -------------------------------------------------------------------- */
     725          31 :     if (hCT)
     726             :     {
     727           4 :         OSRDestroySpatialReference(hSrcSRS);
     728           4 :         OCTDestroyCoordinateTransformation(hCT);
     729             :     }
     730             : 
     731          31 :     GDALClose(hSrcDS);
     732             : 
     733          31 :     GDALDumpOpenDatasets(stderr);
     734          31 :     GDALDestroyDriverManager();
     735             : 
     736          31 :     return nRetCode;
     737             : }
     738             : 
     739           0 : MAIN_END

Generated by: LCOV version 1.14