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 166 : MAIN_START(argc, argv)
37 :
38 : {
39 : /* Check strict compilation and runtime library version as we use C++ API */
40 166 : if (!GDAL_CHECK_VERSION(argv[0]))
41 0 : exit(1);
42 :
43 166 : EarlySetConfigOptions(argc, argv);
44 :
45 : /* -------------------------------------------------------------------- */
46 : /* Register standard GDAL drivers, and process generic GDAL */
47 : /* command options. */
48 : /* -------------------------------------------------------------------- */
49 166 : GDALAllRegister();
50 166 : argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
51 166 : if (argc < 1)
52 0 : 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 166 : 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 166 : CPLSetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "450");
70 : #endif
71 : }
72 :
73 320 : GDALTranslateOptionsForBinary sOptionsForBinary;
74 : GDALTranslateOptions *psOptions =
75 166 : GDALTranslateOptionsNew(argv + 1, &sOptionsForBinary);
76 163 : CSLDestroy(argv);
77 :
78 163 : if (psOptions == nullptr)
79 : {
80 4 : Usage();
81 : }
82 :
83 159 : if (sOptionsForBinary.osDest == "/vsistdout/")
84 : {
85 0 : sOptionsForBinary.bQuiet = true;
86 : }
87 :
88 159 : if (!(sOptionsForBinary.bQuiet))
89 : {
90 148 : GDALTranslateOptionsSetProgress(psOptions, GDALTermProgress, nullptr);
91 : }
92 :
93 159 : if (!sOptionsForBinary.osFormat.empty())
94 : {
95 : GDALDriverH hDriver =
96 102 : GDALGetDriverByName(sOptionsForBinary.osFormat.c_str());
97 102 : if (hDriver == nullptr)
98 : {
99 0 : fprintf(stderr, "Output driver `%s' not recognised.\n",
100 : sOptionsForBinary.osFormat.c_str());
101 0 : fprintf(stderr, "The following format drivers are configured and "
102 : "support output:\n");
103 0 : for (int iDr = 0; iDr < GDALGetDriverCount(); iDr++)
104 : {
105 0 : hDriver = GDALGetDriver(iDr);
106 :
107 0 : if (GDALGetMetadataItem(hDriver, GDAL_DCAP_RASTER, nullptr) !=
108 0 : nullptr &&
109 0 : (GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE, nullptr) !=
110 0 : nullptr ||
111 0 : GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATECOPY,
112 : nullptr) != nullptr))
113 : {
114 0 : fprintf(stderr, " %s: %s\n",
115 : GDALGetDriverShortName(hDriver),
116 : GDALGetDriverLongName(hDriver));
117 : }
118 : }
119 :
120 0 : GDALTranslateOptionsFree(psOptions);
121 :
122 0 : GDALDestroyDriverManager();
123 0 : exit(1);
124 : }
125 : }
126 :
127 : /* -------------------------------------------------------------------- */
128 : /* Attempt to open source file. */
129 : /* -------------------------------------------------------------------- */
130 :
131 : GDALDatasetH hDataset =
132 159 : GDALOpenEx(sOptionsForBinary.osSource.c_str(),
133 : GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
134 159 : sOptionsForBinary.aosAllowedInputDrivers.List(),
135 159 : sOptionsForBinary.aosOpenOptions.List(), nullptr);
136 :
137 159 : if (hDataset == nullptr)
138 : {
139 5 : GDALDestroyDriverManager();
140 5 : exit(1);
141 : }
142 :
143 : /* -------------------------------------------------------------------- */
144 : /* Handle subdatasets. */
145 : /* -------------------------------------------------------------------- */
146 461 : if (!sOptionsForBinary.bCopySubDatasets &&
147 154 : GDALGetRasterCount(hDataset) == 0 &&
148 0 : CSLCount(GDALGetMetadata(hDataset, "SUBDATASETS")) > 0)
149 : {
150 0 : fprintf(stderr, "Input file contains subdatasets. Please, select one "
151 : "of them for reading.\n");
152 0 : GDALClose(hDataset);
153 0 : GDALDestroyDriverManager();
154 0 : exit(1);
155 : }
156 :
157 154 : int bUsageError = FALSE;
158 154 : GDALDatasetH hOutDS = nullptr;
159 154 : GDALDriverH hOutDriver = nullptr;
160 :
161 154 : if (sOptionsForBinary.osFormat.empty())
162 : {
163 52 : hOutDriver = GDALGetDriverByName(
164 104 : GetOutputDriverForRaster(sOptionsForBinary.osDest.c_str()));
165 : }
166 : else
167 : {
168 102 : hOutDriver = GDALGetDriverByName(sOptionsForBinary.osFormat.c_str());
169 : }
170 :
171 154 : if (hOutDriver == nullptr)
172 : {
173 0 : fprintf(stderr, "Output driver not found.\n");
174 0 : GDALClose(hDataset);
175 0 : GDALDestroyDriverManager();
176 0 : exit(1);
177 : }
178 :
179 : bool bCopyCreateSubDatasets =
180 154 : (GDALGetMetadataItem(hOutDriver, GDAL_DCAP_SUBCREATECOPY, nullptr) !=
181 154 : nullptr);
182 :
183 155 : if (sOptionsForBinary.bCopySubDatasets &&
184 1 : CSLCount(GDALGetMetadata(hDataset, "SUBDATASETS")) > 0)
185 : {
186 1 : if (bCopyCreateSubDatasets)
187 : {
188 : // GDAL sets the size of the dataset with subdatasets to 512x512
189 : // this removes the srcwin function from this operation
190 0 : hOutDS = GDALTranslate(sOptionsForBinary.osDest.c_str(), hDataset,
191 : psOptions, &bUsageError);
192 0 : GDALClose(hOutDS);
193 : }
194 : else
195 : {
196 1 : char **papszSubdatasets = GDALGetMetadata(hDataset, "SUBDATASETS");
197 1 : const int nSubdatasets = CSLCount(papszSubdatasets) / 2;
198 : char *pszSubDest = static_cast<char *>(
199 1 : CPLMalloc(strlen(sOptionsForBinary.osDest.c_str()) + 32));
200 :
201 2 : CPLString osPath = CPLGetPath(sOptionsForBinary.osDest.c_str());
202 : CPLString osBasename =
203 2 : CPLGetBasename(sOptionsForBinary.osDest.c_str());
204 : CPLString osExtension =
205 2 : CPLGetExtension(sOptionsForBinary.osDest.c_str());
206 2 : CPLString osTemp;
207 :
208 1 : const char *pszFormat = nullptr;
209 1 : if (nSubdatasets < 10)
210 : {
211 1 : pszFormat = "%s_%d";
212 : }
213 0 : else if (nSubdatasets < 100)
214 : {
215 0 : pszFormat = "%s_%002d";
216 : }
217 : else
218 : {
219 0 : pszFormat = "%s_%003d";
220 : }
221 :
222 1 : const char *pszDest = pszSubDest;
223 :
224 2 : for (int i = 0; papszSubdatasets[i] != nullptr; i += 2)
225 : {
226 : char *pszSource =
227 1 : CPLStrdup(strstr(papszSubdatasets[i], "=") + 1);
228 1 : osTemp = CPLSPrintf(pszFormat, osBasename.c_str(), i / 2 + 1);
229 1 : osTemp = CPLFormFilename(osPath, osTemp, osExtension);
230 1 : strcpy(pszSubDest, osTemp.c_str());
231 1 : hDataset = GDALOpenEx(pszSource, GDAL_OF_RASTER, nullptr,
232 1 : sOptionsForBinary.aosOpenOptions.List(),
233 : nullptr);
234 1 : CPLFree(pszSource);
235 1 : if (!sOptionsForBinary.bQuiet)
236 1 : printf("Input file size is %d, %d\n",
237 : GDALGetRasterXSize(hDataset),
238 : GDALGetRasterYSize(hDataset));
239 : hOutDS =
240 1 : GDALTranslate(pszDest, hDataset, psOptions, &bUsageError);
241 1 : if (hOutDS == nullptr)
242 0 : break;
243 1 : GDALClose(hOutDS);
244 : }
245 :
246 1 : CPLFree(pszSubDest);
247 : }
248 :
249 1 : if (bUsageError == TRUE)
250 0 : Usage();
251 1 : GDALClose(hDataset);
252 1 : GDALTranslateOptionsFree(psOptions);
253 :
254 1 : GDALDestroy();
255 1 : return 0;
256 : }
257 :
258 153 : if (!sOptionsForBinary.bQuiet)
259 144 : printf("Input file size is %d, %d\n", GDALGetRasterXSize(hDataset),
260 : GDALGetRasterYSize(hDataset));
261 :
262 153 : hOutDS = GDALTranslate(sOptionsForBinary.osDest.c_str(), hDataset,
263 : psOptions, &bUsageError);
264 153 : if (bUsageError == TRUE)
265 0 : Usage();
266 153 : int nRetCode = hOutDS ? 0 : 1;
267 :
268 : /* Close hOutDS before hDataset for the -f VRT case */
269 153 : if (GDALClose(hOutDS) != CE_None)
270 : {
271 0 : nRetCode = 1;
272 0 : if (CPLGetLastErrorType() == CE_None)
273 : {
274 0 : CPLError(CE_Failure, CPLE_AppDefined,
275 : "Unknown error occurred in GDALClose()");
276 : }
277 : }
278 153 : GDALClose(hDataset);
279 153 : GDALTranslateOptionsFree(psOptions);
280 :
281 153 : GDALDestroy();
282 :
283 153 : return nRetCode;
284 : }
285 :
286 0 : MAIN_END
|