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 2 : static void GDALExit(int nCode) 26 : { 27 2 : GDALDestroy(); 28 2 : 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 1 : GDALExit(-argc); 60 : 61 : /* -------------------------------------------------------------------- */ 62 : /* Parse command line */ 63 : /* -------------------------------------------------------------------- */ 64 : 65 13 : GDALFootprintOptionsForBinary sOptionsForBinary; 66 : // coverity[tainted_data] 67 : std::unique_ptr<GDALFootprintOptions, decltype(&GDALFootprintOptionsFree)> 68 : psOptions{GDALFootprintOptionsNew(argv + 1, &sOptionsForBinary), 69 7 : 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 : CSLConstList papszDriverMD = 117 1 : (poDriver) ? poDriver->GetMetadata() : nullptr; 118 2 : if (poDriver == nullptr || 119 1 : !CPLTestBool(CSLFetchNameValueDef(papszDriverMD, GDAL_DCAP_VECTOR, 120 2 : "FALSE")) || 121 1 : !CPLTestBool( 122 : CSLFetchNameValueDef(papszDriverMD, GDAL_DCAP_CREATE, "FALSE"))) 123 : { 124 0 : fprintf(stderr, 125 : "Output driver `%s' not recognised or does not support " 126 : "direct output file creation.\n", 127 : sOptionsForBinary.osFormat.c_str()); 128 0 : fprintf(stderr, "The following format drivers are enable and " 129 : "support direct writing:\n"); 130 : 131 0 : for (int iDriver = 0; iDriver < poDM->GetDriverCount(); iDriver++) 132 : { 133 0 : GDALDriver *poIter = poDM->GetDriver(iDriver); 134 0 : papszDriverMD = poIter->GetMetadata(); 135 0 : if (CPLTestBool(CSLFetchNameValueDef( 136 0 : papszDriverMD, GDAL_DCAP_VECTOR, "FALSE")) && 137 0 : CPLTestBool(CSLFetchNameValueDef( 138 : papszDriverMD, GDAL_DCAP_CREATE, "FALSE"))) 139 : { 140 0 : fprintf(stderr, " -> `%s'\n", poIter->GetDescription()); 141 : } 142 : } 143 0 : GDALExit(1); 144 : } 145 : } 146 : 147 6 : if (hDstDS && sOptionsForBinary.bOverwrite) 148 : { 149 1 : auto poDstDS = GDALDataset::FromHandle(hDstDS); 150 1 : int nLayerCount = poDstDS->GetLayerCount(); 151 1 : int iLayerToDelete = -1; 152 2 : for (int i = 0; i < nLayerCount; ++i) 153 : { 154 1 : auto poLayer = poDstDS->GetLayer(i); 155 2 : if (poLayer && 156 1 : poLayer->GetName() == sOptionsForBinary.osDestLayerName) 157 : { 158 0 : iLayerToDelete = i; 159 0 : break; 160 : } 161 : } 162 1 : bool bDeleteOK = false; 163 1 : if (iLayerToDelete >= 0 && poDstDS->TestCapability(ODsCDeleteLayer)) 164 : { 165 0 : bDeleteOK = poDstDS->DeleteLayer(iLayerToDelete) == OGRERR_NONE; 166 : } 167 1 : if (!bDeleteOK && nLayerCount == 1) 168 : { 169 1 : GDALClose(hDstDS); 170 1 : hDstDS = nullptr; 171 1 : CPLPushErrorHandler(CPLQuietErrorHandler); 172 1 : GDALDeleteDataset(nullptr, sOptionsForBinary.osDest.c_str()); 173 1 : CPLPopErrorHandler(); 174 1 : VSIUnlink(sOptionsForBinary.osDest.c_str()); 175 1 : } 176 : } 177 5 : else if (sOptionsForBinary.bOverwrite) 178 : { 179 0 : CPLPushErrorHandler(CPLQuietErrorHandler); 180 0 : GDALDeleteDataset(nullptr, sOptionsForBinary.osDest.c_str()); 181 0 : CPLPopErrorHandler(); 182 0 : VSIUnlink(sOptionsForBinary.osDest.c_str()); 183 : } 184 : 185 6 : int bUsageError = FALSE; 186 : GDALDatasetH hRetDS = 187 6 : GDALFootprint(sOptionsForBinary.osDest.c_str(), hDstDS, hInDS, 188 6 : psOptions.get(), &bUsageError); 189 6 : if (bUsageError == TRUE) 190 0 : Usage(); 191 : 192 6 : int nRetCode = hRetDS ? 0 : 1; 193 : 194 6 : GDALClose(hInDS); 195 6 : if (GDALClose(hRetDS) != CE_None) 196 0 : nRetCode = 1; 197 : 198 6 : GDALDestroyDriverManager(); 199 : 200 6 : return nRetCode; 201 : } 202 : 203 0 : MAIN_END