1 /******************************************************************************
2 *
3 * Project: OpenGIS Simple Features Reference Implementation
4 * Purpose: Simple client for translating between formats.
5 * Author: Frank Warmerdam, warmerdam@pobox.com
6 *
7 ******************************************************************************
8 * Copyright (c) 1999, Frank Warmerdam
9 * Copyright (c) 2008-2015, Even Rouault <even dot rouault at spatialys.com>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29
30 #include "cpl_port.h"
31
32 #include <cstddef>
33 #include <cstdio>
34 #include <cstdlib>
35 #include <cstring>
36 #include <algorithm>
37 #include <memory>
38 #include <vector>
39
40 #include "commonutils.h"
41 #include "cpl_conv.h"
42 #include "cpl_error.h"
43 #include "cpl_progress.h"
44 #include "cpl_string.h"
45 #include "gdal_version.h"
46 #include "gdal.h"
47 #include "gdal_priv.h"
48 #include "gdal_utils.h"
49 #include "gdal_utils_priv.h"
50 #include "gdal_version.h"
51 #include "ogr_api.h"
52 #include "ogr_core.h"
53 #include "ogr_p.h"
54 #include "ogrsf_frmts.h"
55
56 CPL_CVSID("$Id: ogr2ogr_bin.cpp 4548fc91ad259c4d2f3ff0ea47dbd74f0f13ed08 2021-04-02 22:24:34 +0200 Even Rouault $")
57
58 /************************************************************************/
59 /* Usage() */
60 /************************************************************************/
61
StringCISortFunction(const CPLString & a,const CPLString & b)62 static bool StringCISortFunction( const CPLString& a, const CPLString& b )
63 {
64 return STRCASECMP(a.c_str(), b.c_str()) < 0;
65 }
66
Usage(const char * pszAdditionalMsg=nullptr,bool bShort=true)67 static void Usage( const char* pszAdditionalMsg = nullptr, bool bShort = true )
68 {
69 printf(
70 "Usage: ogr2ogr [--help-general] [-skipfailures] [-append] [-update]\n"
71 " [-select field_list] [-where restricted_where|@filename]\n"
72 " [-progress] [-sql <sql statement>|@filename] [-dialect dialect]\n"
73 " [-preserve_fid] [-fid FID] [-limit nb_features]\n"
74 " [-spat xmin ymin xmax ymax] [-spat_srs srs_def] [-geomfield field]\n"
75 " [-a_srs srs_def] [-t_srs srs_def] [-s_srs srs_def] [-ct string]\n"
76 " [-f format_name] [-overwrite] [[-dsco NAME=VALUE] ...]\n"
77 " dst_datasource_name src_datasource_name\n"
78 " [-lco NAME=VALUE] [-nln name] \n"
79 " [-nlt type|PROMOTE_TO_MULTI|CONVERT_TO_LINEAR|CONVERT_TO_CURVE]\n"
80 " [-dim XY|XYZ|XYM|XYZM|layer_dim] [layer [layer ...]]\n"
81 "\n"
82 "Advanced options :\n"
83 " [-gt n] [-ds_transaction]\n"
84 " [[-oo NAME=VALUE] ...] [[-doo NAME=VALUE] ...]\n"
85 " [-clipsrc [xmin ymin xmax ymax]|WKT|datasource|spat_extent]\n"
86 " [-clipsrcsql sql_statement] [-clipsrclayer layer]\n"
87 " [-clipsrcwhere expression]\n"
88 " [-clipdst [xmin ymin xmax ymax]|WKT|datasource]\n"
89 " [-clipdstsql sql_statement] [-clipdstlayer layer]\n"
90 " [-clipdstwhere expression]\n"
91 " [-wrapdateline][-datelineoffset val]\n"
92 " [[-simplify tolerance] | [-segmentize max_dist]]\n"
93 " [-makevalid]\n"
94 " [-addfields] [-unsetFid] [-emptyStrAsNull]\n"
95 " [-relaxedFieldNameMatch] [-forceNullable] [-unsetDefault]\n"
96 " [-fieldTypeToString All|(type1[,type2]*)] [-unsetFieldWidth]\n"
97 " [-mapFieldType srctype|All=dsttype[,srctype2=dsttype2]*]\n"
98 " [-fieldmap identity | index1[,index2]*]\n"
99 " [-splitlistfields] [-maxsubfields val]\n"
100 " [-resolveDomains]\n"
101 " [-explodecollections] [-zfield field_name]\n"
102 " [-gcp ungeoref_x ungeoref_y georef_x georef_y [elevation]]* [-order n | -tps]\n"
103 " [-nomd] [-mo \"META-TAG=VALUE\"]* [-noNativeData]\n");
104
105 if( bShort )
106 {
107 printf("\nNote: ogr2ogr --long-usage for full help.\n");
108 if( pszAdditionalMsg )
109 fprintf(stderr, "\nFAILURE: %s\n", pszAdditionalMsg);
110 exit(1);
111 }
112
113 printf(
114 "\n -f format_name: output file format name, possible values are:\n");
115
116 std::vector<CPLString> aoSetDrivers;
117 OGRSFDriverRegistrar *poR = OGRSFDriverRegistrar::GetRegistrar();
118 for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
119 {
120 GDALDriver *poDriver = poR->GetDriver(iDriver);
121
122 if( CPLTestBool( CSLFetchNameValueDef(poDriver->GetMetadata(),
123 GDAL_DCAP_CREATE, "FALSE")) )
124 aoSetDrivers.push_back(poDriver->GetDescription());
125 }
126 std::sort(aoSetDrivers.begin(), aoSetDrivers.end(), StringCISortFunction);
127 for( const auto &oDriver : aoSetDrivers )
128 {
129 printf(" -f \"%s\"\n", oDriver.c_str());
130 }
131
132 printf(
133 " -append: Append to existing layer instead of creating new if it exists\n"
134 " -overwrite: delete the output layer and recreate it empty\n"
135 " -update: Open existing output datasource in update mode\n"
136 " -progress: Display progress on terminal. Only works if input layers have the \n"
137 " \"fast feature count\" capability\n"
138 " -select field_list: Comma-delimited list of fields from input layer to\n"
139 " copy to the new layer (defaults to all)\n"
140 " -where restricted_where: Attribute query (like SQL WHERE)\n"
141 " -wrapdateline: split geometries crossing the dateline meridian\n"
142 " (long. = +/- 180deg)\n"
143 " -datelineoffset: offset from dateline in degrees\n"
144 " (default long. = +/- 10deg,\n"
145 " geometries within 170deg to -170deg will be split)\n"
146 " -sql statement: Execute given SQL statement and save result.\n"
147 " -dialect value: select a dialect, usually OGRSQL to avoid native sql.\n"
148 " -skipfailures: skip features or layers that fail to convert\n"
149 " -gt n: group n features per transaction (default 20000). n can be set to unlimited\n"
150 " -spat xmin ymin xmax ymax: spatial query extents\n"
151 " -simplify tolerance: distance tolerance for simplification.\n"
152 " -segmentize max_dist: maximum distance between 2 nodes.\n"
153 " Used to create intermediate points\n"
154 " -dsco NAME=VALUE: Dataset creation option (format specific)\n"
155 " -lco NAME=VALUE: Layer creation option (format specific)\n"
156 " -oo NAME=VALUE: Input dataset open option (format specific)\n"
157 " -doo NAME=VALUE: Destination dataset open option (format specific)\n"
158 " -nln name: Assign an alternate name to the new layer\n"
159 " -nlt type: Force a geometry type for new layer. One of NONE, GEOMETRY,\n"
160 " POINT, LINESTRING, POLYGON, GEOMETRYCOLLECTION, MULTIPOINT,\n"
161 " MULTIPOLYGON, or MULTILINESTRING, or PROMOTE_TO_MULTI or CONVERT_TO_LINEAR. Add \"25D\" for 3D layers.\n"
162 " Default is type of source layer.\n"
163 " -dim dimension: Force the coordinate dimension to the specified value.\n"
164 " -fieldTypeToString type1,...: Converts fields of specified types to\n"
165 " fields of type string in the new layer. Valid types are : Integer,\n"
166 " Integer64, Real, String, Date, Time, DateTime, Binary, IntegerList, Integer64List, RealList,\n"
167 " StringList. Special value All will convert all fields to strings.\n"
168 " -fieldmap index1,index2,...: Specifies the list of field indexes to be\n"
169 " copied from the source to the destination. The (n)th value specified\n"
170 " in the list is the index of the field in the target layer definition\n"
171 " in which the n(th) field of the source layer must be copied. Index count\n"
172 " starts at zero. There must be exactly as many values in the list as\n"
173 " the count of the fields in the source layer. We can use the 'identity'\n"
174 " setting to specify that the fields should be transferred by using the\n"
175 " same order. This setting should be used along with the append setting.\n");
176
177 printf(" -a_srs srs_def: Assign an output SRS\n"
178 " -t_srs srs_def: Reproject/transform to this SRS on output\n"
179 " -s_srs srs_def: Override source SRS\n"
180 "\n"
181 " Srs_def can be a full WKT definition (hard to escape properly),\n"
182 " or a well known definition (i.e. EPSG:4326) or a file with a WKT\n"
183 " definition.\n" );
184
185 if( pszAdditionalMsg )
186 fprintf(stderr, "\nFAILURE: %s\n", pszAdditionalMsg);
187 }
188
189 /************************************************************************/
190 /* GDALVectorTranslateOptionsForBinaryNew() */
191 /************************************************************************/
192
193 static GDALVectorTranslateOptionsForBinary *
GDALVectorTranslateOptionsForBinaryNew()194 GDALVectorTranslateOptionsForBinaryNew()
195 {
196 return static_cast<GDALVectorTranslateOptionsForBinary *>(
197 CPLCalloc(1, sizeof(GDALVectorTranslateOptionsForBinary)));
198 }
199
200 /************************************************************************/
201 /* GDALVectorTranslateOptionsForBinaryFree() */
202 /************************************************************************/
203
GDALVectorTranslateOptionsForBinaryFree(GDALVectorTranslateOptionsForBinary * psOptionsForBinary)204 static void GDALVectorTranslateOptionsForBinaryFree(
205 GDALVectorTranslateOptionsForBinary* psOptionsForBinary )
206 {
207 if( psOptionsForBinary )
208 {
209 CPLFree(psOptionsForBinary->pszDataSource);
210 CPLFree(psOptionsForBinary->pszDestDataSource);
211 CSLDestroy(psOptionsForBinary->papszOpenOptions);
212 CPLFree(psOptionsForBinary->pszFormat);
213 CPLFree(psOptionsForBinary);
214 }
215 }
216
217 /************************************************************************/
218 /* main() */
219 /************************************************************************/
220
MAIN_START(nArgc,papszArgv)221 MAIN_START( nArgc, papszArgv )
222 {
223 // Check strict compilation and runtime library version as we use C++ API.
224 if( !GDAL_CHECK_VERSION(papszArgv[0]) )
225 exit(1);
226
227 EarlySetConfigOptions(nArgc, papszArgv);
228
229 /* -------------------------------------------------------------------- */
230 /* Register format(s). */
231 /* -------------------------------------------------------------------- */
232 OGRRegisterAll();
233
234 /* -------------------------------------------------------------------- */
235 /* Processing command line arguments. */
236 /* -------------------------------------------------------------------- */
237 GDALDatasetH hDS = nullptr;
238 GDALDatasetH hODS = nullptr;
239 bool bCloseODS = true;
240 GDALDatasetH hDstDS = nullptr;
241 int nRetCode = 1;
242 GDALVectorTranslateOptionsForBinary* psOptionsForBinary = nullptr;
243 GDALVectorTranslateOptions *psOptions = nullptr;
244
245 nArgc = OGRGeneralCmdLineProcessor( nArgc, &papszArgv, 0 );
246
247 if( nArgc < 1 )
248 {
249 papszArgv = nullptr;
250 nRetCode = -nArgc;
251 goto exit;
252 }
253
254 for( int iArg = 1; iArg < nArgc; iArg++ )
255 {
256 if( EQUAL(papszArgv[iArg], "--utility_version") )
257 {
258 printf("%s was compiled against GDAL %s and "
259 "is running against GDAL %s\n",
260 papszArgv[0], GDAL_RELEASE_NAME,
261 GDALVersionInfo("RELEASE_NAME"));
262 nRetCode = 0;
263 goto exit;
264 }
265 else if( EQUAL(papszArgv[iArg], "--help") )
266 {
267 Usage();
268 goto exit;
269 }
270 else if ( EQUAL(papszArgv[iArg], "--long-usage") )
271 {
272 Usage(nullptr, false);
273 goto exit;
274 }
275 }
276
277 psOptionsForBinary = GDALVectorTranslateOptionsForBinaryNew();
278 psOptions =
279 GDALVectorTranslateOptionsNew(papszArgv + 1, psOptionsForBinary);
280
281 if( psOptions == nullptr )
282 {
283 Usage();
284 GDALVectorTranslateOptionsForBinaryFree(psOptionsForBinary);
285 goto exit;
286 }
287
288 if( psOptionsForBinary->pszDataSource == nullptr ||
289 psOptionsForBinary->pszDestDataSource == nullptr )
290 {
291 if( psOptionsForBinary->pszDestDataSource == nullptr )
292 Usage("no target datasource provided");
293 else
294 Usage("no source datasource provided");
295 GDALVectorTranslateOptionsFree(psOptions);
296 GDALVectorTranslateOptionsForBinaryFree(psOptionsForBinary);
297 goto exit;
298 }
299
300 if( strcmp(psOptionsForBinary->pszDestDataSource, "/vsistdout/") == 0 )
301 psOptionsForBinary->bQuiet = TRUE;
302
303 /* -------------------------------------------------------------------- */
304 /* Open data source. */
305 /* -------------------------------------------------------------------- */
306
307 // Avoid opening twice the same datasource if it is both the input and
308 // output Known to cause problems with at least FGdb, SQlite and GPKG
309 // drivers. See #4270
310 if (psOptionsForBinary->eAccessMode != ACCESS_CREATION &&
311 strcmp(psOptionsForBinary->pszDestDataSource,
312 psOptionsForBinary->pszDataSource) == 0)
313 {
314 hODS = GDALOpenEx(
315 psOptionsForBinary->pszDataSource,
316 GDAL_OF_UPDATE | GDAL_OF_VECTOR, nullptr,
317 psOptionsForBinary->papszOpenOptions, nullptr);
318
319 GDALDriverH hDriver =
320 hODS != nullptr ? GDALGetDatasetDriver(hODS) : nullptr;
321
322 // Restrict to those 3 drivers. For example it is known to break with
323 // the PG driver due to the way it manages transactions.
324 if( hDriver && !(EQUAL(GDALGetDescription(hDriver), "FileGDB") ||
325 EQUAL(GDALGetDescription(hDriver), "SQLite") ||
326 EQUAL(GDALGetDescription(hDriver), "GPKG")) )
327 {
328 hDS = GDALOpenEx(psOptionsForBinary->pszDataSource,
329 GDAL_OF_VECTOR, nullptr,
330 psOptionsForBinary->papszOpenOptions, nullptr);
331 }
332 else
333 {
334 hDS = hODS;
335 bCloseODS = false;
336 }
337 }
338 else
339 {
340 hDS = GDALOpenEx(psOptionsForBinary->pszDataSource,
341 GDAL_OF_VECTOR, nullptr,
342 psOptionsForBinary->papszOpenOptions, nullptr);
343 }
344
345 /* -------------------------------------------------------------------- */
346 /* Report failure */
347 /* -------------------------------------------------------------------- */
348 if( hDS == nullptr )
349 {
350 GDALDriverManager *poDM = GetGDALDriverManager();
351
352 fprintf(stderr, "FAILURE:\n"
353 "Unable to open datasource `%s' with the following drivers.\n",
354 psOptionsForBinary->pszDataSource );
355
356 for( int iDriver = 0; iDriver < poDM->GetDriverCount(); iDriver++ )
357 {
358 GDALDriver* poIter = poDM->GetDriver(iDriver);
359 char** papszDriverMD = poIter->GetMetadata();
360 if( CPLTestBool(CSLFetchNameValueDef(papszDriverMD,
361 GDAL_DCAP_VECTOR, "FALSE")) )
362 {
363 fprintf(stderr, " -> `%s'\n", poIter->GetDescription());
364 }
365 }
366
367 GDALVectorTranslateOptionsFree(psOptions);
368 GDALVectorTranslateOptionsForBinaryFree(psOptionsForBinary);
369 goto exit;
370 }
371
372 if( hODS != nullptr && psOptionsForBinary->pszFormat != nullptr )
373 {
374 GDALDriverManager *poDM = GetGDALDriverManager();
375
376 GDALDriver* poDriver =
377 poDM->GetDriverByName(psOptionsForBinary->pszFormat);
378 if( poDriver == nullptr )
379 {
380 fprintf(stderr, "Unable to find driver `%s'.\n",
381 psOptionsForBinary->pszFormat);
382 fprintf(stderr, "The following drivers are available:\n");
383
384 for( int iDriver = 0; iDriver < poDM->GetDriverCount(); iDriver++ )
385 {
386 GDALDriver* poIter = poDM->GetDriver(iDriver);
387 char** papszDriverMD = poIter->GetMetadata();
388 if( CPLTestBool(CSLFetchNameValueDef(
389 papszDriverMD, GDAL_DCAP_VECTOR, "FALSE")) &&
390 (CPLTestBool(CSLFetchNameValueDef(
391 papszDriverMD, GDAL_DCAP_CREATE, "FALSE")) ||
392 CPLTestBool(CSLFetchNameValueDef(
393 papszDriverMD, GDAL_DCAP_CREATECOPY, "FALSE"))) )
394 {
395 fprintf( stderr, " -> `%s'\n", poIter->GetDescription() );
396 }
397 }
398 GDALVectorTranslateOptionsFree(psOptions);
399 GDALVectorTranslateOptionsForBinaryFree(psOptionsForBinary);
400 goto exit;
401 }
402 }
403
404 if( !(psOptionsForBinary->bQuiet) )
405 {
406 GDALVectorTranslateOptionsSetProgress(psOptions, GDALTermProgress,
407 nullptr);
408 }
409
410 {
411 // TODO(schwehr): Remove scope after removing gotos
412 int bUsageError = FALSE;
413 hDstDS = GDALVectorTranslate(psOptionsForBinary->pszDestDataSource,
414 hODS, 1, &hDS, psOptions, &bUsageError);
415 if( bUsageError )
416 Usage();
417 else
418 nRetCode = hDstDS ? 0 : 1;
419 }
420
421 GDALVectorTranslateOptionsFree(psOptions);
422 GDALVectorTranslateOptionsForBinaryFree(psOptionsForBinary);
423
424 if( hDS )
425 GDALClose(hDS);
426 if( bCloseODS )
427 GDALClose(hDstDS);
428
429 exit:
430 CSLDestroy(papszArgv);
431 GDALDestroy();
432
433 return nRetCode;
434 }
435 MAIN_END
436