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