Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: GDAL Utilities 4 : * Purpose: Computes the footprint of a GDAL raster 5 : * Authors: Even Rouault, <even dot rouault at spatialys dot com> 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2023, Even Rouault <even dot rouault at spatialys dot com> 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #include "cpl_string.h" 14 : #include "gdal_version.h" 15 : #include "commonutils.h" 16 : #include "gdal_utils_priv.h" 17 : #include "gdal_priv.h" 18 : #include "ogrsf_frmts.h" 19 : 20 : /** 21 : * @brief Makes sure the GDAL library is properly cleaned up before exiting. 22 : * @param nCode exit code 23 : * @todo Move to API 24 : */ 25 1 : static void GDALExit(int nCode) 26 : { 27 1 : GDALDestroy(); 28 1 : exit(nCode); 29 : } 30 : 31 : /************************************************************************/ 32 : /* Usage() */ 33 : /************************************************************************/ 34 : 35 0 : static void Usage() 36 : { 37 0 : fprintf(stderr, "%s\n", GDALFootprintAppGetParserUsage().c_str()); 38 0 : GDALExit(1); 39 0 : } 40 : 41 : /************************************************************************/ 42 : /* main() */ 43 : /************************************************************************/ 44 : 45 8 : MAIN_START(argc, argv) 46 : { 47 : /* Check strict compilation and runtime library version as we use C++ API */ 48 8 : if (!GDAL_CHECK_VERSION(argv[0])) 49 0 : GDALExit(1); 50 : 51 8 : EarlySetConfigOptions(argc, argv); 52 : 53 : /* -------------------------------------------------------------------- */ 54 : /* Generic arg processing. */ 55 : /* -------------------------------------------------------------------- */ 56 8 : GDALAllRegister(); 57 8 : argc = GDALGeneralCmdLineProcessor(argc, &argv, 0); 58 8 : if (argc < 1) 59 0 : GDALExit(-argc); 60 : 61 : /* -------------------------------------------------------------------- */ 62 : /* Parse command line */ 63 : /* -------------------------------------------------------------------- */ 64 : 65 14 : GDALFootprintOptionsForBinary sOptionsForBinary; 66 : // coverity[tainted_data] 67 : std::unique_ptr<GDALFootprintOptions, decltype(&GDALFootprintOptionsFree)> 68 : psOptions{GDALFootprintOptionsNew(argv + 1, &sOptionsForBinary), 69 8 : GDALFootprintOptionsFree}; 70 : 71 7 : CSLDestroy(argv); 72 : 73 7 : if (psOptions == nullptr) 74 : { 75 0 : Usage(); 76 : } 77 : 78 7 : if (!(sOptionsForBinary.bQuiet)) 79 : { 80 6 : GDALFootprintOptionsSetProgress(psOptions.get(), GDALTermProgress, 81 : nullptr); 82 : } 83 : 84 : /* -------------------------------------------------------------------- */ 85 : /* Open input file. */ 86 : /* -------------------------------------------------------------------- */ 87 7 : GDALDatasetH hInDS = GDALOpenEx(sOptionsForBinary.osSource.c_str(), 88 : GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR, 89 : /*papszAllowedDrivers=*/nullptr, 90 7 : sOptionsForBinary.aosOpenOptions.List(), 91 : /*papszSiblingFiles=*/nullptr); 92 : 93 7 : if (hInDS == nullptr) 94 1 : GDALExit(1); 95 : 96 : /* -------------------------------------------------------------------- */ 97 : /* Open output file if it exists. */ 98 : /* -------------------------------------------------------------------- */ 99 6 : GDALDatasetH hDstDS = nullptr; 100 6 : if (!(sOptionsForBinary.bCreateOutput)) 101 : { 102 5 : CPLPushErrorHandler(CPLQuietErrorHandler); 103 : hDstDS = 104 5 : GDALOpenEx(sOptionsForBinary.osDest.c_str(), 105 : GDAL_OF_VECTOR | GDAL_OF_VERBOSE_ERROR | GDAL_OF_UPDATE, 106 : nullptr, nullptr, nullptr); 107 5 : CPLPopErrorHandler(); 108 : } 109 : 110 7 : if (!sOptionsForBinary.osFormat.empty() && 111 1 : (sOptionsForBinary.bCreateOutput || hDstDS == nullptr)) 112 : { 113 1 : GDALDriverManager *poDM = GetGDALDriverManager(); 114 : GDALDriver *poDriver = 115 1 : poDM->GetDriverByName(sOptionsForBinary.osFormat.c_str()); 116 1 : char **papszDriverMD = (poDriver) ? poDriver->GetMetadata() : nullptr; 117 2 : if (poDriver == nullptr || 118 1 : !CPLTestBool(CSLFetchNameValueDef(papszDriverMD, GDAL_DCAP_VECTOR, 119 2 : "FALSE")) || 120 1 : !CPLTestBool( 121 : CSLFetchNameValueDef(papszDriverMD, GDAL_DCAP_CREATE, "FALSE"))) 122 : { 123 0 : fprintf(stderr, 124 : "Output driver `%s' not recognised or does not support " 125 : "direct output file creation.\n", 126 : sOptionsForBinary.osFormat.c_str()); 127 0 : fprintf(stderr, "The following format drivers are configured and " 128 : "support direct output:\n"); 129 : 130 0 : for (int iDriver = 0; iDriver < poDM->GetDriverCount(); iDriver++) 131 : { 132 0 : GDALDriver *poIter = poDM->GetDriver(iDriver); 133 0 : papszDriverMD = poIter->GetMetadata(); 134 0 : if (CPLTestBool(CSLFetchNameValueDef( 135 0 : papszDriverMD, GDAL_DCAP_VECTOR, "FALSE")) && 136 0 : CPLTestBool(CSLFetchNameValueDef( 137 : papszDriverMD, GDAL_DCAP_CREATE, "FALSE"))) 138 : { 139 0 : fprintf(stderr, " -> `%s'\n", poIter->GetDescription()); 140 : } 141 : } 142 0 : GDALExit(1); 143 : } 144 : } 145 : 146 6 : if (hDstDS && sOptionsForBinary.bOverwrite) 147 : { 148 1 : auto poDstDS = GDALDataset::FromHandle(hDstDS); 149 1 : int nLayerCount = poDstDS->GetLayerCount(); 150 1 : int iLayerToDelete = -1; 151 2 : for (int i = 0; i < nLayerCount; ++i) 152 : { 153 1 : auto poLayer = poDstDS->GetLayer(i); 154 2 : if (poLayer && 155 1 : poLayer->GetName() == sOptionsForBinary.osDestLayerName) 156 : { 157 0 : iLayerToDelete = i; 158 0 : break; 159 : } 160 : } 161 1 : bool bDeleteOK = false; 162 1 : if (iLayerToDelete >= 0 && poDstDS->TestCapability(ODsCDeleteLayer)) 163 : { 164 0 : bDeleteOK = poDstDS->DeleteLayer(iLayerToDelete) == OGRERR_NONE; 165 : } 166 1 : if (!bDeleteOK && nLayerCount == 1) 167 : { 168 1 : GDALClose(hDstDS); 169 1 : hDstDS = nullptr; 170 1 : CPLPushErrorHandler(CPLQuietErrorHandler); 171 1 : GDALDeleteDataset(nullptr, sOptionsForBinary.osDest.c_str()); 172 1 : CPLPopErrorHandler(); 173 1 : VSIUnlink(sOptionsForBinary.osDest.c_str()); 174 1 : } 175 : } 176 5 : else if (sOptionsForBinary.bOverwrite) 177 : { 178 0 : CPLPushErrorHandler(CPLQuietErrorHandler); 179 0 : GDALDeleteDataset(nullptr, sOptionsForBinary.osDest.c_str()); 180 0 : CPLPopErrorHandler(); 181 0 : VSIUnlink(sOptionsForBinary.osDest.c_str()); 182 : } 183 : 184 6 : int bUsageError = FALSE; 185 : GDALDatasetH hRetDS = 186 6 : GDALFootprint(sOptionsForBinary.osDest.c_str(), hDstDS, hInDS, 187 6 : psOptions.get(), &bUsageError); 188 6 : if (bUsageError == TRUE) 189 0 : Usage(); 190 : 191 6 : int nRetCode = hRetDS ? 0 : 1; 192 : 193 6 : GDALClose(hInDS); 194 6 : if (GDALClose(hRetDS) != CE_None) 195 0 : nRetCode = 1; 196 : 197 6 : GDALDestroyDriverManager(); 198 : 199 6 : return nRetCode; 200 : } 201 : 202 0 : MAIN_END