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
|