LCOV - code coverage report
Current view: top level - apps - gdalwarp_bin.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 96 115 83.5 %
Date: 2025-03-28 11:40:40 Functions: 4 4 100.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             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "cpl_string.h"
      16             : #include "cpl_error_internal.h"
      17             : #include "gdal_version.h"
      18             : #include "commonutils.h"
      19             : #include "gdal_utils_priv.h"
      20             : 
      21             : #include <vector>
      22             : 
      23             : /************************************************************************/
      24             : /*                               GDALExit()                             */
      25             : /*  This function exits and cleans up GDAL and OGR resources            */
      26             : /*  Perhaps it should be added to C api and used in all apps?           */
      27             : /************************************************************************/
      28             : 
      29           6 : static int GDALExit(int nCode)
      30             : {
      31           6 :     const char *pszDebug = CPLGetConfigOption("CPL_DEBUG", nullptr);
      32           6 :     if (pszDebug && (EQUAL(pszDebug, "ON") || EQUAL(pszDebug, "")))
      33             :     {
      34           0 :         GDALDumpOpenDatasets(stderr);
      35           0 :         CPLDumpSharedList(nullptr);
      36             :     }
      37             : 
      38           6 :     GDALDestroyDriverManager();
      39             : 
      40           6 :     OGRCleanupAll();
      41             : 
      42           6 :     exit(nCode);
      43             : }
      44             : 
      45             : /************************************************************************/
      46             : /*                               Usage()                                */
      47             : /************************************************************************/
      48             : 
      49           2 : static void Usage()
      50             : 
      51             : {
      52           2 :     fprintf(stderr, "%s\n", GDALWarpAppGetParserUsage().c_str());
      53           2 :     GDALExit(1);
      54           0 : }
      55             : 
      56             : /************************************************************************/
      57             : /*                          WarpTermProgress()                          */
      58             : /************************************************************************/
      59             : 
      60             : static int gnSrcCount = 0;
      61             : 
      62       14398 : static int CPL_STDCALL WarpTermProgress(double dfProgress,
      63             :                                         const char *pszMessage, void *)
      64             : {
      65       14398 :     static CPLString osLastMsg;
      66             :     static int iSrc = -1;
      67       14398 :     if (pszMessage == nullptr)
      68             :     {
      69           0 :         iSrc = 0;
      70             :     }
      71       14398 :     else if (pszMessage != osLastMsg)
      72             :     {
      73          98 :         if (!osLastMsg.empty())
      74           5 :             GDALTermProgress(1.0, nullptr, nullptr);
      75          98 :         printf("%s : ", pszMessage);
      76          98 :         osLastMsg = pszMessage;
      77          98 :         iSrc++;
      78             :     }
      79       14398 :     return GDALTermProgress(dfProgress * gnSrcCount - iSrc, nullptr, nullptr);
      80             : }
      81             : 
      82             : /************************************************************************/
      83             : /*                                main()                                */
      84             : /************************************************************************/
      85             : 
      86         104 : MAIN_START(argc, argv)
      87             : 
      88             : {
      89         104 :     EarlySetConfigOptions(argc, argv);
      90         104 :     CPLDebugOnly("GDAL", "Start");
      91             : 
      92             :     /* -------------------------------------------------------------------- */
      93             :     /*      Register standard GDAL drivers, and process generic GDAL        */
      94             :     /*      command options.                                                */
      95             :     /* -------------------------------------------------------------------- */
      96         104 :     GDALAllRegister();
      97         104 :     argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
      98         104 :     if (argc < 1)
      99           2 :         GDALExit(-argc);
     100             : 
     101             :     /* -------------------------------------------------------------------- */
     102             :     /*      Set optimal setting for best performance with huge input VRT.   */
     103             :     /*      The rationale for 450 is that typical Linux process allow       */
     104             :     /*      only 1024 file descriptors per process and we need to keep some */
     105             :     /*      spare for shared libraries, etc. so let's go down to 900.       */
     106             :     /*      And some datasets may need 2 file descriptors, so divide by 2   */
     107             :     /*      for security.                                                   */
     108             :     /* -------------------------------------------------------------------- */
     109         102 :     if (CPLGetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", nullptr) == nullptr)
     110             :     {
     111             : #if defined(__MACH__) && defined(__APPLE__)
     112             :         // On Mach, the default limit is 256 files per process
     113             :         // TODO We should eventually dynamically query the limit for all OS
     114             :         CPLSetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "100");
     115             : #else
     116         102 :         CPLSetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "450");
     117             : #endif
     118             :     }
     119             : 
     120         102 :     GDALWarpAppOptionsForBinary sOptionsForBinary;
     121             :     /* coverity[tainted_data] */
     122             :     GDALWarpAppOptions *psOptions =
     123         102 :         GDALWarpAppOptionsNew(argv + 1, &sOptionsForBinary);
     124         102 :     CSLDestroy(argv);
     125             : 
     126         102 :     if (psOptions == nullptr)
     127             :     {
     128           2 :         Usage();
     129             :     }
     130             : 
     131         195 :     if (sOptionsForBinary.aosSrcFiles.size() == 1 &&
     132         195 :         sOptionsForBinary.aosSrcFiles[0] == sOptionsForBinary.osDstFilename &&
     133           0 :         sOptionsForBinary.bOverwrite)
     134             :     {
     135           0 :         CPLError(CE_Failure, CPLE_IllegalArg,
     136             :                  "Source and destination datasets must be different.\n");
     137           0 :         GDALExit(1);
     138             :     }
     139             : 
     140             :     /* -------------------------------------------------------------------- */
     141             :     /*      Open source files.                                              */
     142             :     /* -------------------------------------------------------------------- */
     143         100 :     GDALDatasetH *pahSrcDS = nullptr;
     144         100 :     int nSrcCount = 0;
     145         203 :     for (int i = 0; i < sOptionsForBinary.aosSrcFiles.size(); ++i)
     146             :     {
     147         105 :         nSrcCount++;
     148             :         pahSrcDS = static_cast<GDALDatasetH *>(
     149         105 :             CPLRealloc(pahSrcDS, sizeof(GDALDatasetH) * nSrcCount));
     150         210 :         pahSrcDS[i] =
     151         105 :             GDALOpenEx(sOptionsForBinary.aosSrcFiles[i],
     152             :                        GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
     153         105 :                        sOptionsForBinary.aosAllowedInputDrivers.List(),
     154         105 :                        sOptionsForBinary.aosOpenOptions.List(), nullptr);
     155             : 
     156         105 :         if (pahSrcDS[i] == nullptr)
     157             :         {
     158           2 :             CPLError(CE_Failure, CPLE_OpenFailed,
     159             :                      "Failed to open source file %s\n",
     160             :                      sOptionsForBinary.aosSrcFiles[i]);
     161           4 :             while (nSrcCount--)
     162             :             {
     163           2 :                 GDALClose(pahSrcDS[nSrcCount]);
     164           2 :                 pahSrcDS[nSrcCount] = nullptr;
     165             :             }
     166           2 :             CPLFree(pahSrcDS);
     167           2 :             GDALWarpAppOptionsFree(psOptions);
     168           2 :             GDALExit(2);
     169             :         }
     170             :     }
     171             : 
     172             :     /* -------------------------------------------------------------------- */
     173             :     /*      Does the output dataset already exist?                          */
     174             :     /* -------------------------------------------------------------------- */
     175             : 
     176             :     /* FIXME ? source filename=target filename and -overwrite is definitely */
     177             :     /* an error. But I can't imagine of a valid case (without -overwrite), */
     178             :     /* where it would make sense. In doubt, let's keep that dubious
     179             :      * possibility... */
     180             : 
     181          98 :     bool bOutStreaming = false;
     182          98 :     if (sOptionsForBinary.osDstFilename == "/vsistdout/")
     183             :     {
     184           0 :         sOptionsForBinary.bQuiet = true;
     185           0 :         bOutStreaming = true;
     186             :     }
     187             : #ifdef S_ISFIFO
     188             :     else
     189             :     {
     190             :         VSIStatBufL sStat;
     191          98 :         if (VSIStatExL(sOptionsForBinary.osDstFilename.c_str(), &sStat,
     192         129 :                        VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0 &&
     193          31 :             S_ISFIFO(sStat.st_mode))
     194             :         {
     195           0 :             bOutStreaming = true;
     196             :         }
     197             :     }
     198             : #endif
     199             : 
     200          98 :     GDALDatasetH hDstDS = nullptr;
     201          98 :     if (bOutStreaming)
     202             :     {
     203           0 :         GDALWarpAppOptionsSetWarpOption(psOptions, "STREAMABLE_OUTPUT", "YES");
     204             :     }
     205             :     else
     206             :     {
     207         196 :         CPLErrorAccumulator oErrorAccumulator;
     208             :         {
     209          98 :             auto oAccumulator = oErrorAccumulator.InstallForCurrentScope();
     210          98 :             hDstDS = GDALOpenEx(
     211             :                 sOptionsForBinary.osDstFilename.c_str(),
     212             :                 GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR | GDAL_OF_UPDATE,
     213          98 :                 nullptr, sOptionsForBinary.aosDestOpenOptions.List(), nullptr);
     214             :         }
     215          98 :         if (hDstDS != nullptr)
     216             :         {
     217          31 :             oErrorAccumulator.ReplayErrors();
     218             :         }
     219             :     }
     220             : 
     221          98 :     if (hDstDS != nullptr && sOptionsForBinary.bOverwrite)
     222             :     {
     223          27 :         GDALClose(hDstDS);
     224          27 :         hDstDS = nullptr;
     225             :     }
     226             : 
     227          98 :     bool bCheckExistingDstFile =
     228          98 :         !bOutStreaming && hDstDS == nullptr && !sOptionsForBinary.bOverwrite;
     229             : 
     230          98 :     if (hDstDS != nullptr && sOptionsForBinary.bCreateOutput)
     231             :     {
     232           1 :         if (sOptionsForBinary.aosCreateOptions.FetchBool("APPEND_SUBDATASET",
     233             :                                                          false))
     234             :         {
     235           1 :             GDALClose(hDstDS);
     236           1 :             hDstDS = nullptr;
     237           1 :             bCheckExistingDstFile = false;
     238             :         }
     239             :         else
     240             :         {
     241           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     242             :                      "Output dataset %s exists,\n"
     243             :                      "but some command line options were provided indicating a "
     244             :                      "new dataset\n"
     245             :                      "should be created.  Please delete existing dataset and "
     246             :                      "run again.\n",
     247             :                      sOptionsForBinary.osDstFilename.c_str());
     248           0 :             GDALExit(1);
     249             :         }
     250             :     }
     251             : 
     252             :     /* Avoid overwriting an existing destination file that cannot be opened in
     253             :      */
     254             :     /* update mode with a new GTiff file */
     255          98 :     if (bCheckExistingDstFile)
     256             :     {
     257          41 :         CPLPushErrorHandler(CPLQuietErrorHandler);
     258          41 :         hDstDS = GDALOpen(sOptionsForBinary.osDstFilename.c_str(), GA_ReadOnly);
     259          41 :         CPLPopErrorHandler();
     260             : 
     261          41 :         if (hDstDS)
     262             :         {
     263           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     264             :                      "Output dataset %s exists, but cannot be opened in update "
     265             :                      "mode\n",
     266             :                      sOptionsForBinary.osDstFilename.c_str());
     267           0 :             GDALClose(hDstDS);
     268           0 :             GDALExit(1);
     269             :         }
     270             :     }
     271             : 
     272          98 :     if (!(sOptionsForBinary.bQuiet))
     273             :     {
     274          93 :         gnSrcCount = nSrcCount;
     275          93 :         GDALWarpAppOptionsSetProgress(psOptions, WarpTermProgress, nullptr);
     276          93 :         GDALWarpAppOptionsSetQuiet(psOptions, false);
     277             :     }
     278             : 
     279          98 :     int bUsageError = FALSE;
     280             :     GDALDatasetH hOutDS =
     281          98 :         GDALWarp(sOptionsForBinary.osDstFilename.c_str(), hDstDS, nSrcCount,
     282             :                  pahSrcDS, psOptions, &bUsageError);
     283          98 :     if (bUsageError)
     284           0 :         Usage();
     285          98 :     int nRetCode = (hOutDS) ? 0 : 1;
     286             : 
     287          98 :     GDALWarpAppOptionsFree(psOptions);
     288             : 
     289             :     // Close first hOutDS since it might reference sources (case of VRT)
     290          98 :     if (GDALClose(hOutDS ? hOutDS : hDstDS) != CE_None)
     291           0 :         nRetCode = 1;
     292             : 
     293         201 :     for (int i = 0; i < nSrcCount; i++)
     294             :     {
     295         103 :         GDALClose(pahSrcDS[i]);
     296             :     }
     297          98 :     CPLFree(pahSrcDS);
     298             : 
     299          98 :     GDALDumpOpenDatasets(stderr);
     300             : 
     301          98 :     OGRCleanupAll();
     302             : 
     303          98 :     return nRetCode;
     304             : }
     305             : 
     306           0 : MAIN_END

Generated by: LCOV version 1.14