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 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "cpl_string.h"
30 : #include "gdal_version.h"
31 : #include "commonutils.h"
32 : #include "gdal_utils_priv.h"
33 : #include "gdal_priv.h"
34 : #include "ogrsf_frmts.h"
35 :
36 : /************************************************************************/
37 : /* Usage() */
38 : /************************************************************************/
39 :
40 0 : static void Usage(bool bIsError, const char *pszErrorMsg = nullptr)
41 :
42 : {
43 0 : fprintf(bIsError ? stderr : stdout,
44 : "Usage: gdal_footprint [--help] [--help-general]\n"
45 : " [-b <band>]... [-combine_bands union|intersection]\n"
46 : " [-oo <NAME>=<VALUE>]... [-ovr <index>]\n"
47 : " [-srcnodata \"<value>[ <value>]...\"]\n"
48 : " [-t_cs pixel|georef] [-t_srs <srs_def>] [-split_polys]\n"
49 : " [-convex_hull] [-densify <value>] [-simplify <value>]\n"
50 : " [-min_ring_area <value>] [-max_points <value>|unlimited]\n"
51 : " [-of <ogr_format>] [-lyr_name <dst_layername>]\n"
52 : " [-location_field_name <field_name>] [-no_location]\n"
53 : " [-write_absolute_path]\n"
54 : " [-dsco <name>=<value>]... [-lco <name>=<value>]... "
55 : "[-overwrite] [-q]\n"
56 : " <src_filename> <dst_filename>\n");
57 :
58 0 : if (pszErrorMsg != nullptr)
59 0 : fprintf(stderr, "\nFAILURE: %s\n", pszErrorMsg);
60 0 : exit(bIsError ? 1 : 0);
61 : }
62 :
63 : /************************************************************************/
64 : /* main() */
65 : /************************************************************************/
66 :
67 8 : MAIN_START(argc, argv)
68 : {
69 : /* Check strict compilation and runtime library version as we use C++ API */
70 8 : if (!GDAL_CHECK_VERSION(argv[0]))
71 0 : exit(1);
72 :
73 8 : EarlySetConfigOptions(argc, argv);
74 :
75 : /* -------------------------------------------------------------------- */
76 : /* Generic arg processing. */
77 : /* -------------------------------------------------------------------- */
78 8 : GDALAllRegister();
79 8 : argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
80 8 : if (argc < 1)
81 0 : exit(-argc);
82 :
83 34 : for (int i = 0; i < argc; i++)
84 : {
85 27 : if (EQUAL(argv[i], "--utility_version"))
86 : {
87 1 : printf("%s was compiled against GDAL %s and "
88 : "is running against GDAL %s\n",
89 : argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
90 1 : CSLDestroy(argv);
91 1 : return 0;
92 : }
93 26 : else if (EQUAL(argv[i], "--help"))
94 : {
95 0 : Usage(false);
96 : }
97 : }
98 :
99 7 : GDALFootprintOptionsForBinary sOptionsForBinary;
100 : // coverity[tainted_data]
101 : GDALFootprintOptions *psOptions =
102 7 : GDALFootprintOptionsNew(argv + 1, &sOptionsForBinary);
103 7 : CSLDestroy(argv);
104 :
105 7 : if (psOptions == nullptr)
106 : {
107 0 : Usage(true);
108 : }
109 :
110 7 : if (!(sOptionsForBinary.bQuiet))
111 : {
112 6 : GDALFootprintOptionsSetProgress(psOptions, GDALTermProgress, nullptr);
113 : }
114 :
115 7 : if (sOptionsForBinary.osSource.empty())
116 0 : Usage(true, "No input file specified.");
117 :
118 7 : if (!sOptionsForBinary.bDestSpecified)
119 0 : Usage(true, "No output file specified.");
120 :
121 : /* -------------------------------------------------------------------- */
122 : /* Open input file. */
123 : /* -------------------------------------------------------------------- */
124 7 : GDALDatasetH hInDS = GDALOpenEx(sOptionsForBinary.osSource.c_str(),
125 : GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
126 : /*papszAllowedDrivers=*/nullptr,
127 7 : sOptionsForBinary.aosOpenOptions.List(),
128 : /*papszSiblingFiles=*/nullptr);
129 :
130 7 : if (hInDS == nullptr)
131 1 : exit(1);
132 :
133 : /* -------------------------------------------------------------------- */
134 : /* Open output file if it exists. */
135 : /* -------------------------------------------------------------------- */
136 6 : GDALDatasetH hDstDS = nullptr;
137 6 : if (!(sOptionsForBinary.bCreateOutput))
138 : {
139 5 : CPLPushErrorHandler(CPLQuietErrorHandler);
140 : hDstDS =
141 5 : GDALOpenEx(sOptionsForBinary.osDest.c_str(),
142 : GDAL_OF_VECTOR | GDAL_OF_VERBOSE_ERROR | GDAL_OF_UPDATE,
143 : nullptr, nullptr, nullptr);
144 5 : CPLPopErrorHandler();
145 : }
146 :
147 7 : if (!sOptionsForBinary.osFormat.empty() &&
148 1 : (sOptionsForBinary.bCreateOutput || hDstDS == nullptr))
149 : {
150 1 : GDALDriverManager *poDM = GetGDALDriverManager();
151 : GDALDriver *poDriver =
152 1 : poDM->GetDriverByName(sOptionsForBinary.osFormat.c_str());
153 1 : char **papszDriverMD = (poDriver) ? poDriver->GetMetadata() : nullptr;
154 2 : if (poDriver == nullptr ||
155 1 : !CPLTestBool(CSLFetchNameValueDef(papszDriverMD, GDAL_DCAP_VECTOR,
156 2 : "FALSE")) ||
157 1 : !CPLTestBool(
158 : CSLFetchNameValueDef(papszDriverMD, GDAL_DCAP_CREATE, "FALSE")))
159 : {
160 0 : fprintf(stderr,
161 : "Output driver `%s' not recognised or does not support "
162 : "direct output file creation.\n",
163 : sOptionsForBinary.osFormat.c_str());
164 0 : fprintf(stderr, "The following format drivers are configured and "
165 : "support direct output:\n");
166 :
167 0 : for (int iDriver = 0; iDriver < poDM->GetDriverCount(); iDriver++)
168 : {
169 0 : GDALDriver *poIter = poDM->GetDriver(iDriver);
170 0 : papszDriverMD = poIter->GetMetadata();
171 0 : if (CPLTestBool(CSLFetchNameValueDef(
172 0 : papszDriverMD, GDAL_DCAP_VECTOR, "FALSE")) &&
173 0 : CPLTestBool(CSLFetchNameValueDef(
174 : papszDriverMD, GDAL_DCAP_CREATE, "FALSE")))
175 : {
176 0 : fprintf(stderr, " -> `%s'\n", poIter->GetDescription());
177 : }
178 : }
179 0 : exit(1);
180 : }
181 : }
182 :
183 6 : if (hDstDS && sOptionsForBinary.bOverwrite)
184 : {
185 1 : auto poDstDS = GDALDataset::FromHandle(hDstDS);
186 1 : int nLayerCount = poDstDS->GetLayerCount();
187 1 : int iLayerToDelete = -1;
188 2 : for (int i = 0; i < nLayerCount; ++i)
189 : {
190 1 : auto poLayer = poDstDS->GetLayer(i);
191 2 : if (poLayer &&
192 1 : poLayer->GetName() == sOptionsForBinary.osDestLayerName)
193 : {
194 0 : iLayerToDelete = i;
195 0 : break;
196 : }
197 : }
198 1 : bool bDeleteOK = false;
199 1 : if (iLayerToDelete >= 0 && poDstDS->TestCapability(ODsCDeleteLayer))
200 : {
201 0 : bDeleteOK = poDstDS->DeleteLayer(iLayerToDelete) == OGRERR_NONE;
202 : }
203 1 : if (!bDeleteOK && nLayerCount == 1)
204 : {
205 1 : GDALClose(hDstDS);
206 1 : hDstDS = nullptr;
207 1 : CPLPushErrorHandler(CPLQuietErrorHandler);
208 1 : GDALDeleteDataset(nullptr, sOptionsForBinary.osDest.c_str());
209 1 : CPLPopErrorHandler();
210 1 : VSIUnlink(sOptionsForBinary.osDest.c_str());
211 1 : }
212 : }
213 5 : else if (sOptionsForBinary.bOverwrite)
214 : {
215 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
216 0 : GDALDeleteDataset(nullptr, sOptionsForBinary.osDest.c_str());
217 0 : CPLPopErrorHandler();
218 0 : VSIUnlink(sOptionsForBinary.osDest.c_str());
219 : }
220 :
221 6 : int bUsageError = FALSE;
222 6 : GDALDatasetH hRetDS = GDALFootprint(sOptionsForBinary.osDest.c_str(),
223 : hDstDS, hInDS, psOptions, &bUsageError);
224 6 : if (bUsageError == TRUE)
225 0 : Usage(true);
226 6 : int nRetCode = hRetDS ? 0 : 1;
227 :
228 6 : GDALClose(hInDS);
229 6 : if (GDALClose(hRetDS) != CE_None)
230 0 : nRetCode = 1;
231 6 : GDALFootprintOptionsFree(psOptions);
232 :
233 6 : GDALDestroyDriverManager();
234 :
235 6 : return nRetCode;
236 : }
237 :
238 0 : MAIN_END
|