LCOV - code coverage report
Current view: top level - apps - gdalwarp_bin.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 92 118 78.0 %
Date: 2024-05-03 15:49:35 Functions: 3 4 75.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  High Performance Image Reprojector
       4             :  * Purpose:  Test program for high performance warper API.
       5             :  * Author:   Frank Warmerdam <warmerdam@pobox.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2002, i3 - information integration and imaging
       9             :  *                          Fort Collin, CO
      10             :  * Copyright (c) 2007-2015, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * Permission is hereby granted, free of charge, to any person obtaining a
      13             :  * copy of this software and associated documentation files (the "Software"),
      14             :  * to deal in the Software without restriction, including without limitation
      15             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16             :  * and/or sell copies of the Software, and to permit persons to whom the
      17             :  * Software is furnished to do so, subject to the following conditions:
      18             :  *
      19             :  * The above copyright notice and this permission notice shall be included
      20             :  * in all copies or substantial portions of the Software.
      21             :  *
      22             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28             :  * DEALINGS IN THE SOFTWARE.
      29             :  ****************************************************************************/
      30             : 
      31             : #include "cpl_string.h"
      32             : #include "cpl_error_internal.h"
      33             : #include "gdal_version.h"
      34             : #include "commonutils.h"
      35             : #include "gdal_utils_priv.h"
      36             : 
      37             : #include <vector>
      38             : 
      39             : /************************************************************************/
      40             : /*                               GDALExit()                             */
      41             : /*  This function exits and cleans up GDAL and OGR resources            */
      42             : /*  Perhaps it should be added to C api and used in all apps?           */
      43             : /************************************************************************/
      44             : 
      45           2 : static int GDALExit(int nCode)
      46             : {
      47           2 :     const char *pszDebug = CPLGetConfigOption("CPL_DEBUG", nullptr);
      48           2 :     if (pszDebug && (EQUAL(pszDebug, "ON") || EQUAL(pszDebug, "")))
      49             :     {
      50           0 :         GDALDumpOpenDatasets(stderr);
      51           0 :         CPLDumpSharedList(nullptr);
      52             :     }
      53             : 
      54           2 :     GDALDestroyDriverManager();
      55             : 
      56           2 :     OGRCleanupAll();
      57             : 
      58           2 :     exit(nCode);
      59             : }
      60             : 
      61             : /************************************************************************/
      62             : /*                               Usage()                                */
      63             : /************************************************************************/
      64             : 
      65           0 : static void Usage()
      66             : 
      67             : {
      68           0 :     fprintf(stderr, "%s\n", GDALWarpAppGetParserUsage().c_str());
      69           0 :     GDALExit(1);
      70           0 : }
      71             : 
      72             : /************************************************************************/
      73             : /*                          WarpTermProgress()                          */
      74             : /************************************************************************/
      75             : 
      76             : static int gnSrcCount = 0;
      77             : 
      78       13614 : static int CPL_STDCALL WarpTermProgress(double dfProgress,
      79             :                                         const char *pszMessage, void *)
      80             : {
      81       13614 :     static CPLString osLastMsg;
      82             :     static int iSrc = -1;
      83       13614 :     if (pszMessage == nullptr)
      84             :     {
      85           0 :         iSrc = 0;
      86             :     }
      87       13614 :     else if (pszMessage != osLastMsg)
      88             :     {
      89          86 :         if (!osLastMsg.empty())
      90           4 :             GDALTermProgress(1.0, nullptr, nullptr);
      91          86 :         printf("%s : ", pszMessage);
      92          86 :         osLastMsg = pszMessage;
      93          86 :         iSrc++;
      94             :     }
      95       13614 :     return GDALTermProgress(dfProgress * gnSrcCount - iSrc, nullptr, nullptr);
      96             : }
      97             : 
      98             : /************************************************************************/
      99             : /*                                main()                                */
     100             : /************************************************************************/
     101             : 
     102          91 : MAIN_START(argc, argv)
     103             : 
     104             : {
     105          91 :     EarlySetConfigOptions(argc, argv);
     106          91 :     CPLDebugOnly("GDAL", "Start");
     107             : 
     108             :     /* -------------------------------------------------------------------- */
     109             :     /*      Register standard GDAL drivers, and process generic GDAL        */
     110             :     /*      command options.                                                */
     111             :     /* -------------------------------------------------------------------- */
     112          91 :     GDALAllRegister();
     113          91 :     argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
     114          91 :     if (argc < 1)
     115           0 :         GDALExit(-argc);
     116             : 
     117             :     /* -------------------------------------------------------------------- */
     118             :     /*      Set optimal setting for best performance with huge input VRT.   */
     119             :     /*      The rationale for 450 is that typical Linux process allow       */
     120             :     /*      only 1024 file descriptors per process and we need to keep some */
     121             :     /*      spare for shared libraries, etc. so let's go down to 900.       */
     122             :     /*      And some datasets may need 2 file descriptors, so divide by 2   */
     123             :     /*      for security.                                                   */
     124             :     /* -------------------------------------------------------------------- */
     125          91 :     if (CPLGetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", nullptr) == nullptr)
     126             :     {
     127             : #if defined(__MACH__) && defined(__APPLE__)
     128             :         // On Mach, the default limit is 256 files per process
     129             :         // TODO We should eventually dynamically query the limit for all OS
     130             :         CPLSetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "100");
     131             : #else
     132          91 :         CPLSetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "450");
     133             : #endif
     134             :     }
     135             : 
     136          91 :     GDALWarpAppOptionsForBinary sOptionsForBinary;
     137             :     /* coverity[tainted_data] */
     138             :     GDALWarpAppOptions *psOptions =
     139          91 :         GDALWarpAppOptionsNew(argv + 1, &sOptionsForBinary);
     140          89 :     CSLDestroy(argv);
     141             : 
     142          89 :     if (psOptions == nullptr)
     143             :     {
     144           0 :         Usage();
     145             :     }
     146             : 
     147         174 :     if (sOptionsForBinary.aosSrcFiles.size() == 1 &&
     148         174 :         sOptionsForBinary.aosSrcFiles[0] == sOptionsForBinary.osDstFilename &&
     149           0 :         sOptionsForBinary.bOverwrite)
     150             :     {
     151           0 :         CPLError(CE_Failure, CPLE_IllegalArg,
     152             :                  "Source and destination datasets must be different.\n");
     153           0 :         GDALExit(1);
     154             :     }
     155             : 
     156             :     /* -------------------------------------------------------------------- */
     157             :     /*      Open source files.                                              */
     158             :     /* -------------------------------------------------------------------- */
     159          89 :     GDALDatasetH *pahSrcDS = nullptr;
     160          89 :     int nSrcCount = 0;
     161         180 :     for (int i = 0; i < sOptionsForBinary.aosSrcFiles.size(); ++i)
     162             :     {
     163          93 :         nSrcCount++;
     164             :         pahSrcDS = static_cast<GDALDatasetH *>(
     165          93 :             CPLRealloc(pahSrcDS, sizeof(GDALDatasetH) * nSrcCount));
     166         186 :         pahSrcDS[i] =
     167          93 :             GDALOpenEx(sOptionsForBinary.aosSrcFiles[i],
     168             :                        GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
     169          93 :                        sOptionsForBinary.aosAllowedInputDrivers.List(),
     170          93 :                        sOptionsForBinary.aosOpenOptions.List(), nullptr);
     171             : 
     172          93 :         if (pahSrcDS[i] == nullptr)
     173             :         {
     174           2 :             CPLError(CE_Failure, CPLE_OpenFailed,
     175             :                      "Failed to open source file %s\n",
     176             :                      sOptionsForBinary.aosSrcFiles[i]);
     177           4 :             while (nSrcCount--)
     178             :             {
     179           2 :                 GDALClose(pahSrcDS[nSrcCount]);
     180           2 :                 pahSrcDS[nSrcCount] = nullptr;
     181             :             }
     182           2 :             CPLFree(pahSrcDS);
     183           2 :             GDALWarpAppOptionsFree(psOptions);
     184           2 :             GDALExit(2);
     185             :         }
     186             :     }
     187             : 
     188             :     /* -------------------------------------------------------------------- */
     189             :     /*      Does the output dataset already exist?                          */
     190             :     /* -------------------------------------------------------------------- */
     191             : 
     192             :     /* FIXME ? source filename=target filename and -overwrite is definitely */
     193             :     /* an error. But I can't imagine of a valid case (without -overwrite), */
     194             :     /* where it would make sense. In doubt, let's keep that dubious
     195             :      * possibility... */
     196             : 
     197          87 :     bool bOutStreaming = false;
     198          87 :     if (sOptionsForBinary.osDstFilename == "/vsistdout/")
     199             :     {
     200           0 :         sOptionsForBinary.bQuiet = true;
     201           0 :         bOutStreaming = true;
     202             :     }
     203             : #ifdef S_ISFIFO
     204             :     else
     205             :     {
     206             :         VSIStatBufL sStat;
     207          87 :         if (VSIStatExL(sOptionsForBinary.osDstFilename.c_str(), &sStat,
     208         114 :                        VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0 &&
     209          27 :             S_ISFIFO(sStat.st_mode))
     210             :         {
     211           0 :             bOutStreaming = true;
     212             :         }
     213             :     }
     214             : #endif
     215             : 
     216          87 :     GDALDatasetH hDstDS = nullptr;
     217          87 :     if (bOutStreaming)
     218             :     {
     219           0 :         GDALWarpAppOptionsSetWarpOption(psOptions, "STREAMABLE_OUTPUT", "YES");
     220             :     }
     221             :     else
     222             :     {
     223         174 :         std::vector<CPLErrorHandlerAccumulatorStruct> aoErrors;
     224          87 :         CPLInstallErrorHandlerAccumulator(aoErrors);
     225          87 :         hDstDS = GDALOpenEx(
     226             :             sOptionsForBinary.osDstFilename.c_str(),
     227             :             GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR | GDAL_OF_UPDATE, nullptr,
     228          87 :             sOptionsForBinary.aosDestOpenOptions.List(), nullptr);
     229          87 :         CPLUninstallErrorHandlerAccumulator();
     230          87 :         if (hDstDS != nullptr)
     231             :         {
     232          27 :             for (size_t i = 0; i < aoErrors.size(); i++)
     233             :             {
     234           0 :                 CPLError(aoErrors[i].type, aoErrors[i].no, "%s",
     235           0 :                          aoErrors[i].msg.c_str());
     236             :             }
     237             :         }
     238             :     }
     239             : 
     240          87 :     if (hDstDS != nullptr && sOptionsForBinary.bOverwrite)
     241             :     {
     242          24 :         GDALClose(hDstDS);
     243          24 :         hDstDS = nullptr;
     244             :     }
     245             : 
     246          87 :     bool bCheckExistingDstFile =
     247          87 :         !bOutStreaming && hDstDS == nullptr && !sOptionsForBinary.bOverwrite;
     248             : 
     249          87 :     if (hDstDS != nullptr && sOptionsForBinary.bCreateOutput)
     250             :     {
     251           1 :         if (sOptionsForBinary.aosCreateOptions.FetchBool("APPEND_SUBDATASET",
     252             :                                                          false))
     253             :         {
     254           1 :             GDALClose(hDstDS);
     255           1 :             hDstDS = nullptr;
     256           1 :             bCheckExistingDstFile = false;
     257             :         }
     258             :         else
     259             :         {
     260           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     261             :                      "Output dataset %s exists,\n"
     262             :                      "but some command line options were provided indicating a "
     263             :                      "new dataset\n"
     264             :                      "should be created.  Please delete existing dataset and "
     265             :                      "run again.\n",
     266             :                      sOptionsForBinary.osDstFilename.c_str());
     267           0 :             GDALExit(1);
     268             :         }
     269             :     }
     270             : 
     271             :     /* Avoid overwriting an existing destination file that cannot be opened in
     272             :      */
     273             :     /* update mode with a new GTiff file */
     274          87 :     if (bCheckExistingDstFile)
     275             :     {
     276          39 :         CPLPushErrorHandler(CPLQuietErrorHandler);
     277          39 :         hDstDS = GDALOpen(sOptionsForBinary.osDstFilename.c_str(), GA_ReadOnly);
     278          39 :         CPLPopErrorHandler();
     279             : 
     280          39 :         if (hDstDS)
     281             :         {
     282           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     283             :                      "Output dataset %s exists, but cannot be opened in update "
     284             :                      "mode\n",
     285             :                      sOptionsForBinary.osDstFilename.c_str());
     286           0 :             GDALClose(hDstDS);
     287           0 :             GDALExit(1);
     288             :         }
     289             :     }
     290             : 
     291          87 :     if (!(sOptionsForBinary.bQuiet))
     292             :     {
     293          82 :         gnSrcCount = nSrcCount;
     294          82 :         GDALWarpAppOptionsSetProgress(psOptions, WarpTermProgress, nullptr);
     295          82 :         GDALWarpAppOptionsSetQuiet(psOptions, false);
     296             :     }
     297             : 
     298          87 :     int bUsageError = FALSE;
     299             :     GDALDatasetH hOutDS =
     300          87 :         GDALWarp(sOptionsForBinary.osDstFilename.c_str(), hDstDS, nSrcCount,
     301             :                  pahSrcDS, psOptions, &bUsageError);
     302          87 :     if (bUsageError)
     303           0 :         Usage();
     304          87 :     int nRetCode = (hOutDS) ? 0 : 1;
     305             : 
     306          87 :     GDALWarpAppOptionsFree(psOptions);
     307             : 
     308             :     // Close first hOutDS since it might reference sources (case of VRT)
     309          87 :     if (GDALClose(hOutDS ? hOutDS : hDstDS) != CE_None)
     310           0 :         nRetCode = 1;
     311             : 
     312         178 :     for (int i = 0; i < nSrcCount; i++)
     313             :     {
     314          91 :         GDALClose(pahSrcDS[i]);
     315             :     }
     316          87 :     CPLFree(pahSrcDS);
     317             : 
     318          87 :     GDALDumpOpenDatasets(stderr);
     319             : 
     320          87 :     OGRCleanupAll();
     321             : 
     322          87 :     return nRetCode;
     323             : }
     324             : 
     325           0 : MAIN_END

Generated by: LCOV version 1.14