Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Utilities
4 : * Purpose: GDAL Image Translator Program
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1998, 2002, Frank Warmerdam
9 : * Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_string.h"
15 : #include "gdal_version.h"
16 : #include "gdal_priv.h"
17 : #include "ogr_spatialref.h"
18 : #include "commonutils.h"
19 : #include "gdal_utils_priv.h"
20 :
21 : /* ******************************************************************* */
22 : /* Usage() */
23 : /* ******************************************************************** */
24 :
25 4 : static void Usage()
26 : {
27 4 : fprintf(stderr, "%s\n", GDALTranslateGetParserUsage().c_str());
28 :
29 4 : exit(1);
30 : }
31 :
32 : /************************************************************************/
33 : /* main() */
34 : /************************************************************************/
35 :
36 150 : MAIN_START(argc, argv)
37 :
38 : {
39 : /* Check strict compilation and runtime library version as we use C++ API */
40 150 : if (!GDAL_CHECK_VERSION(argv[0]))
41 0 : exit(1);
42 :
43 150 : EarlySetConfigOptions(argc, argv);
44 :
45 : /* -------------------------------------------------------------------- */
46 : /* Register standard GDAL drivers, and process generic GDAL */
47 : /* command options. */
48 : /* -------------------------------------------------------------------- */
49 150 : GDALAllRegister();
50 150 : argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
51 150 : if (argc < 1)
52 3 : exit(-argc);
53 :
54 : /* -------------------------------------------------------------------- */
55 : /* Set optimal setting for best performance with huge input VRT. */
56 : /* The rationale for 450 is that typical Linux process allow */
57 : /* only 1024 file descriptors per process and we need to keep some */
58 : /* spare for shared libraries, etc. so let's go down to 900. */
59 : /* And some datasets may need 2 file descriptors, so divide by 2 */
60 : /* for security. */
61 : /* -------------------------------------------------------------------- */
62 147 : if (CPLGetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", nullptr) == nullptr)
63 : {
64 : #if defined(__MACH__) && defined(__APPLE__)
65 : // On Mach, the default limit is 256 files per process
66 : // TODO We should eventually dynamically query the limit for all OS
67 : CPLSetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "100");
68 : #else
69 147 : CPLSetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "450");
70 : #endif
71 : }
72 :
73 286 : GDALTranslateOptionsForBinary sOptionsForBinary;
74 : GDALTranslateOptions *psOptions =
75 147 : GDALTranslateOptionsNew(argv + 1, &sOptionsForBinary);
76 147 : CSLDestroy(argv);
77 :
78 147 : if (psOptions == nullptr)
79 : {
80 4 : Usage();
81 : }
82 :
83 143 : if (sOptionsForBinary.osDest == "/vsistdout/")
84 : {
85 0 : sOptionsForBinary.bQuiet = true;
86 : }
87 :
88 143 : if (!(sOptionsForBinary.bQuiet))
89 : {
90 134 : GDALTranslateOptionsSetProgress(psOptions, GDALTermProgress, nullptr);
91 : }
92 :
93 143 : if (!sOptionsForBinary.osFormat.empty())
94 : {
95 : GDALDriverH hDriver =
96 88 : GDALGetDriverByName(sOptionsForBinary.osFormat.c_str());
97 88 : if (hDriver == nullptr)
98 : {
99 : auto poMissingDriver =
100 0 : GetGDALDriverManager()->GetHiddenDriverByName(
101 : sOptionsForBinary.osFormat.c_str());
102 0 : if (poMissingDriver)
103 : {
104 : const std::string msg =
105 0 : GDALGetMessageAboutMissingPluginDriver(poMissingDriver);
106 0 : fprintf(stderr,
107 : "Output driver `%s' not found but is known. However "
108 : "plugin %s\n",
109 : sOptionsForBinary.osFormat.c_str(), msg.c_str());
110 0 : GDALDestroyDriverManager();
111 0 : exit(1);
112 : }
113 :
114 0 : fprintf(stderr, "Output driver `%s' not recognised.\n",
115 : sOptionsForBinary.osFormat.c_str());
116 0 : fprintf(stderr, "The following format drivers are enabled and "
117 : "support writing:\n");
118 0 : for (int iDr = 0; iDr < GDALGetDriverCount(); iDr++)
119 : {
120 0 : hDriver = GDALGetDriver(iDr);
121 :
122 0 : if (GDALGetMetadataItem(hDriver, GDAL_DCAP_RASTER, nullptr) !=
123 0 : nullptr &&
124 0 : (GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE, nullptr) !=
125 0 : nullptr ||
126 0 : GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATECOPY,
127 : nullptr) != nullptr))
128 : {
129 0 : fprintf(stderr, " %s: %s\n",
130 : GDALGetDriverShortName(hDriver),
131 : GDALGetDriverLongName(hDriver));
132 : }
133 : }
134 :
135 0 : GDALTranslateOptionsFree(psOptions);
136 :
137 0 : GDALDestroyDriverManager();
138 0 : exit(1);
139 : }
140 : }
141 :
142 : /* -------------------------------------------------------------------- */
143 : /* Attempt to open source file. */
144 : /* -------------------------------------------------------------------- */
145 :
146 144 : if (EQUAL(sOptionsForBinary.osFormat.c_str(), "ZARR") &&
147 1 : CPLTestBool(sOptionsForBinary.aosCreateOptions.FetchNameValueDef(
148 : "CONVERT_TO_KERCHUNK_PARQUET_REFERENCE", "FALSE")))
149 : {
150 0 : sOptionsForBinary.osSource = "ZARR_DUMMY:" + sOptionsForBinary.osSource;
151 : }
152 :
153 : GDALDatasetH hDataset =
154 143 : GDALOpenEx(sOptionsForBinary.osSource.c_str(),
155 : GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
156 143 : sOptionsForBinary.aosAllowedInputDrivers.List(),
157 143 : sOptionsForBinary.aosOpenOptions.List(), nullptr);
158 :
159 143 : if (hDataset == nullptr)
160 : {
161 4 : GDALDestroyDriverManager();
162 4 : exit(1);
163 : }
164 :
165 : /* -------------------------------------------------------------------- */
166 : /* Handle subdatasets. */
167 : /* -------------------------------------------------------------------- */
168 416 : if (!sOptionsForBinary.bCopySubDatasets &&
169 138 : GDALGetRasterCount(hDataset) == 0 &&
170 0 : CSLCount(GDALGetMetadata(hDataset, "SUBDATASETS")) > 0 &&
171 : // S104 and S111 drivers know how to handle a source dataset with subdatasets
172 : // and no input bands.
173 277 : !EQUAL(sOptionsForBinary.osFormat.c_str(), "S104") &&
174 0 : !EQUAL(sOptionsForBinary.osFormat.c_str(), "S111"))
175 : {
176 0 : fprintf(stderr, "Input file contains subdatasets. Please, select one "
177 : "of them for reading.\n");
178 0 : GDALClose(hDataset);
179 0 : GDALDestroyDriverManager();
180 0 : exit(1);
181 : }
182 :
183 139 : int bUsageError = FALSE;
184 139 : GDALDatasetH hOutDS = nullptr;
185 139 : GDALDriverH hOutDriver = nullptr;
186 :
187 139 : if (sOptionsForBinary.osFormat.empty())
188 : {
189 51 : hOutDriver = GDALGetDriverByName(
190 102 : GetOutputDriverForRaster(sOptionsForBinary.osDest.c_str()));
191 : }
192 : else
193 : {
194 88 : hOutDriver = GDALGetDriverByName(sOptionsForBinary.osFormat.c_str());
195 : }
196 :
197 139 : if (hOutDriver == nullptr)
198 : {
199 0 : fprintf(stderr, "Output driver not found.\n");
200 0 : GDALClose(hDataset);
201 0 : GDALDestroyDriverManager();
202 0 : exit(1);
203 : }
204 :
205 : bool bCopyCreateSubDatasets =
206 139 : (GDALGetMetadataItem(hOutDriver, GDAL_DCAP_SUBCREATECOPY, nullptr) !=
207 139 : nullptr);
208 :
209 140 : if (sOptionsForBinary.bCopySubDatasets &&
210 1 : CSLCount(GDALGetMetadata(hDataset, "SUBDATASETS")) > 0)
211 : {
212 1 : if (bCopyCreateSubDatasets)
213 : {
214 : // GDAL sets the size of the dataset with subdatasets to 512x512
215 : // this removes the srcwin function from this operation
216 0 : hOutDS = GDALTranslate(sOptionsForBinary.osDest.c_str(), hDataset,
217 : psOptions, &bUsageError);
218 0 : GDALClose(hOutDS);
219 : }
220 : else
221 : {
222 : CSLConstList papszSubdatasets =
223 1 : GDALGetMetadata(hDataset, "SUBDATASETS");
224 1 : const int nSubdatasets = CSLCount(papszSubdatasets) / 2;
225 : char *pszSubDest = static_cast<char *>(
226 1 : CPLMalloc(strlen(sOptionsForBinary.osDest.c_str()) + 32));
227 :
228 : const CPLString osPath =
229 2 : CPLGetPathSafe(sOptionsForBinary.osDest.c_str());
230 : const CPLString osBasename =
231 2 : CPLGetBasenameSafe(sOptionsForBinary.osDest.c_str());
232 : const CPLString osExtension =
233 2 : CPLGetExtensionSafe(sOptionsForBinary.osDest.c_str());
234 2 : CPLString osTemp;
235 :
236 1 : const char *pszFormat = nullptr;
237 1 : if (nSubdatasets < 10)
238 : {
239 1 : pszFormat = "%s_%d";
240 : }
241 0 : else if (nSubdatasets < 100)
242 : {
243 0 : pszFormat = "%s_%002d";
244 : }
245 : else
246 : {
247 0 : pszFormat = "%s_%003d";
248 : }
249 :
250 1 : const char *pszDest = pszSubDest;
251 :
252 2 : for (int i = 0; papszSubdatasets[i] != nullptr; i += 2)
253 : {
254 : char *pszSource =
255 1 : CPLStrdup(strstr(papszSubdatasets[i], "=") + 1);
256 1 : osTemp = CPLSPrintf(pszFormat, osBasename.c_str(), i / 2 + 1);
257 1 : osTemp = CPLFormFilenameSafe(osPath, osTemp, osExtension);
258 1 : strcpy(pszSubDest, osTemp.c_str());
259 1 : hDataset = GDALOpenEx(pszSource, GDAL_OF_RASTER, nullptr,
260 1 : sOptionsForBinary.aosOpenOptions.List(),
261 : nullptr);
262 1 : CPLFree(pszSource);
263 1 : if (!sOptionsForBinary.bQuiet)
264 1 : printf("Input file size is %d, %d\n",
265 : GDALGetRasterXSize(hDataset),
266 : GDALGetRasterYSize(hDataset));
267 : hOutDS =
268 1 : GDALTranslate(pszDest, hDataset, psOptions, &bUsageError);
269 1 : if (hOutDS == nullptr)
270 0 : break;
271 1 : GDALClose(hOutDS);
272 : }
273 :
274 1 : CPLFree(pszSubDest);
275 : }
276 :
277 1 : if (bUsageError == TRUE)
278 0 : Usage();
279 1 : GDALClose(hDataset);
280 1 : GDALTranslateOptionsFree(psOptions);
281 :
282 1 : GDALDestroy();
283 1 : return 0;
284 : }
285 :
286 138 : if (!sOptionsForBinary.bQuiet)
287 130 : printf("Input file size is %d, %d\n", GDALGetRasterXSize(hDataset),
288 : GDALGetRasterYSize(hDataset));
289 :
290 138 : hOutDS = GDALTranslate(sOptionsForBinary.osDest.c_str(), hDataset,
291 : psOptions, &bUsageError);
292 138 : if (bUsageError == TRUE)
293 0 : Usage();
294 138 : int nRetCode = hOutDS ? 0 : 1;
295 :
296 : /* Close hOutDS before hDataset for the -f VRT case */
297 138 : if (GDALClose(hOutDS) != CE_None)
298 : {
299 0 : nRetCode = 1;
300 0 : if (CPLGetLastErrorType() == CE_None)
301 : {
302 0 : CPLError(CE_Failure, CPLE_AppDefined,
303 : "Unknown error occurred in GDALClose()");
304 : }
305 : }
306 138 : GDALClose(hDataset);
307 138 : GDALTranslateOptionsFree(psOptions);
308 :
309 138 : GDALDestroy();
310 :
311 138 : return nRetCode;
312 : }
313 :
314 0 : MAIN_END
|