/src/gdal/apps/ogr2ogr_lib.cpp
Line  | Count  | Source (jump to first uncovered line)  | 
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  |  |  * Copyright (c) 2015, Faza Mahamood  | 
11  |  |  *  | 
12  |  |  * SPDX-License-Identifier: MIT  | 
13  |  |  ****************************************************************************/  | 
14  |  |  | 
15  |  | #include "cpl_port.h"  | 
16  |  | #include "gdal_utils.h"  | 
17  |  | #include "gdal_utils_priv.h"  | 
18  |  | #include "gdalargumentparser.h"  | 
19  |  |  | 
20  |  | #include <cassert>  | 
21  |  | #include <climits>  | 
22  |  | #include <cstdio>  | 
23  |  | #include <cstdlib>  | 
24  |  | #include <cstring>  | 
25  |  |  | 
26  |  | #include <algorithm>  | 
27  |  | #include <atomic>  | 
28  |  | #include <future>  | 
29  |  | #include <limits>  | 
30  |  | #include <map>  | 
31  |  | #include <memory>  | 
32  |  | #include <mutex>  | 
33  |  | #include <set>  | 
34  |  | #include <unordered_set>  | 
35  |  | #include <string>  | 
36  |  | #include <utility>  | 
37  |  | #include <vector>  | 
38  |  |  | 
39  |  | #include "commonutils.h"  | 
40  |  | #include "cpl_conv.h"  | 
41  |  | #include "cpl_error.h"  | 
42  |  | #include "cpl_progress.h"  | 
43  |  | #include "cpl_string.h"  | 
44  |  | #include "cpl_time.h"  | 
45  |  | #include "cpl_vsi.h"  | 
46  |  | #include "gdal.h"  | 
47  |  | #include "gdal_alg.h"  | 
48  |  | #include "gdal_alg_priv.h"  | 
49  |  | #include "gdal_priv.h"  | 
50  |  | #include "ogr_api.h"  | 
51  |  | #include "ogr_core.h"  | 
52  |  | #include "ogr_feature.h"  | 
53  |  | #include "ogr_featurestyle.h"  | 
54  |  | #include "ogr_geometry.h"  | 
55  |  | #include "ogr_p.h"  | 
56  |  | #include "ogr_recordbatch.h"  | 
57  |  | #include "ogr_spatialref.h"  | 
58  |  | #include "ogrlayerarrow.h"  | 
59  |  | #include "ogrlayerdecorator.h"  | 
60  |  | #include "ogrsf_frmts.h"  | 
61  |  | #include "ogr_wkb.h"  | 
62  |  | #include "ogrct_priv.h"  | 
63  |  |  | 
64  |  | typedef enum  | 
65  |  | { | 
66  |  |     GEOMOP_NONE,  | 
67  |  |     GEOMOP_SEGMENTIZE,  | 
68  |  |     GEOMOP_SIMPLIFY_PRESERVE_TOPOLOGY,  | 
69  |  | } GeomOperation;  | 
70  |  |  | 
71  |  | typedef enum  | 
72  |  | { | 
73  |  |     GTC_DEFAULT,  | 
74  |  |     GTC_PROMOTE_TO_MULTI,  | 
75  |  |     GTC_CONVERT_TO_LINEAR,  | 
76  |  |     GTC_CONVERT_TO_CURVE,  | 
77  |  |     GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR,  | 
78  |  | } GeomTypeConversion;  | 
79  |  |  | 
80  | 0  | #define GEOMTYPE_UNCHANGED -2  | 
81  |  |  | 
82  |  | #define COORD_DIM_UNCHANGED -1  | 
83  | 0  | #define COORD_DIM_LAYER_DIM -2  | 
84  | 0  | #define COORD_DIM_XYM -3  | 
85  |  |  | 
86  | 0  | #define TZ_OFFSET_INVALID INT_MIN  | 
87  |  |  | 
88  |  | /************************************************************************/  | 
89  |  | /*                              CopyableGCPs                            */  | 
90  |  | /************************************************************************/  | 
91  |  |  | 
92  |  | namespace gdal::ogr2ogr_lib  | 
93  |  | { | 
94  |  | struct CopyableGCPs  | 
95  |  | { | 
96  |  |     /*! size of the list pasGCPs */  | 
97  |  |     int nGCPCount = 0;  | 
98  |  |  | 
99  |  |     /*! list of ground control points to be added */  | 
100  |  |     GDAL_GCP *pasGCPs = nullptr;  | 
101  |  |  | 
102  | 0  |     CopyableGCPs() = default;  | 
103  |  |  | 
104  |  |     CopyableGCPs(const CopyableGCPs &other)  | 
105  | 0  |     { | 
106  | 0  |         nGCPCount = other.nGCPCount;  | 
107  | 0  |         if (other.nGCPCount)  | 
108  | 0  |             pasGCPs = GDALDuplicateGCPs(other.nGCPCount, other.pasGCPs);  | 
109  | 0  |         else  | 
110  | 0  |             pasGCPs = nullptr;  | 
111  | 0  |     }  | 
112  |  |  | 
113  |  |     ~CopyableGCPs()  | 
114  | 0  |     { | 
115  | 0  |         if (pasGCPs)  | 
116  | 0  |         { | 
117  | 0  |             GDALDeinitGCPs(nGCPCount, pasGCPs);  | 
118  | 0  |             CPLFree(pasGCPs);  | 
119  | 0  |         }  | 
120  | 0  |     }  | 
121  |  |  | 
122  |  |     CopyableGCPs &operator=(const CopyableGCPs &) = delete;  | 
123  |  | };  | 
124  |  | }  // namespace gdal::ogr2ogr_lib  | 
125  |  |  | 
126  |  | using namespace gdal::ogr2ogr_lib;  | 
127  |  |  | 
128  |  | /************************************************************************/  | 
129  |  | /*                        GDALVectorTranslateOptions                    */  | 
130  |  | /************************************************************************/  | 
131  |  |  | 
132  |  | /** Options for use with GDALVectorTranslate(). GDALVectorTranslateOptions* must  | 
133  |  |  * be allocated and freed with GDALVectorTranslateOptionsNew() and  | 
134  |  |  * GDALVectorTranslateOptionsFree() respectively.  | 
135  |  |  */  | 
136  |  | struct GDALVectorTranslateOptions  | 
137  |  | { | 
138  |  |     // All arguments passed to GDALVectorTranslate() except the positional  | 
139  |  |     // ones (that is dataset names and layer names)  | 
140  |  |     CPLStringList aosArguments{}; | 
141  |  |  | 
142  |  |     /*! continue after a failure, skipping the failed feature */  | 
143  |  |     bool bSkipFailures = false;  | 
144  |  |  | 
145  |  |     /*! use layer level transaction. If set to FALSE, then it is interpreted as  | 
146  |  |      * dataset level transaction. */  | 
147  |  |     int nLayerTransaction = -1;  | 
148  |  |  | 
149  |  |     /*! force the use of particular transaction type based on  | 
150  |  |      * GDALVectorTranslate::nLayerTransaction */  | 
151  |  |     bool bForceTransaction = false;  | 
152  |  |  | 
153  |  |     /*! group nGroupTransactions features per transaction.  | 
154  |  |        Increase the value for better performance when writing into DBMS drivers  | 
155  |  |        that have transaction support. nGroupTransactions can be set to -1 to  | 
156  |  |        load the data into a single transaction */  | 
157  |  |     int nGroupTransactions = 100 * 1000;  | 
158  |  |  | 
159  |  |     /*! If provided, only the feature with this feature id will be reported.  | 
160  |  |        Operates exclusive of the spatial or attribute queries. Note: if you want  | 
161  |  |        to select several features based on their feature id, you can also use  | 
162  |  |        the fact the 'fid' is a special field recognized by OGR SQL. So  | 
163  |  |        GDALVectorTranslateOptions::pszWHERE = "fid in (1,3,5)" would select  | 
164  |  |        features 1, 3 and 5. */  | 
165  |  |     GIntBig nFIDToFetch = OGRNullFID;  | 
166  |  |  | 
167  |  |     /*! allow or suppress progress monitor and other non-error output */  | 
168  |  |     bool bQuiet = false;  | 
169  |  |  | 
170  |  |     /*! output file format name */  | 
171  |  |     std::string osFormat{}; | 
172  |  |  | 
173  |  |     /*! list of layers of the source dataset which needs to be selected */  | 
174  |  |     CPLStringList aosLayers{}; | 
175  |  |  | 
176  |  |     /*! dataset creation option (format specific) */  | 
177  |  |     CPLStringList aosDSCO{}; | 
178  |  |  | 
179  |  |     /*! layer creation option (format specific) */  | 
180  |  |     CPLStringList aosLCO{}; | 
181  |  |  | 
182  |  |     /*! access modes */  | 
183  |  |     GDALVectorTranslateAccessMode eAccessMode = ACCESS_CREATION;  | 
184  |  |  | 
185  |  |     /*! whether to use UpsertFeature() instead of CreateFeature() */  | 
186  |  |     bool bUpsert = false;  | 
187  |  |  | 
188  |  |     /*! It has the effect of adding, to existing target layers, the new fields  | 
189  |  |        found in source layers. This option is useful when merging files that  | 
190  |  |        have non-strictly identical structures. This might not work for output  | 
191  |  |        formats that don't support adding fields to existing non-empty layers. */  | 
192  |  |     bool bAddMissingFields = false;  | 
193  |  |  | 
194  |  |     /*! It must be set to true to trigger reprojection, otherwise only SRS  | 
195  |  |      * assignment is done. */  | 
196  |  |     bool bTransform = false;  | 
197  |  |  | 
198  |  |     /*! output SRS. GDALVectorTranslateOptions::bTransform must be set to true  | 
199  |  |        to trigger reprojection, otherwise only SRS assignment is done. */  | 
200  |  |     std::string osOutputSRSDef{}; | 
201  |  |  | 
202  |  |     /*! Coordinate epoch of source SRS */  | 
203  |  |     double dfSourceCoordinateEpoch = 0;  | 
204  |  |  | 
205  |  |     /*! Coordinate epoch of output SRS */  | 
206  |  |     double dfOutputCoordinateEpoch = 0;  | 
207  |  |  | 
208  |  |     /*! override source SRS */  | 
209  |  |     std::string osSourceSRSDef{}; | 
210  |  |  | 
211  |  |     /*! PROJ pipeline */  | 
212  |  |     std::string osCTPipeline{}; | 
213  |  |  | 
214  |  |     /*! Transform options. */  | 
215  |  |     CPLStringList aosCTOptions{}; | 
216  |  |  | 
217  |  |     bool bNullifyOutputSRS = false;  | 
218  |  |  | 
219  |  |     /*! If set to false, then field name matching between source and existing  | 
220  |  |        target layer is done in a more relaxed way if the target driver has an  | 
221  |  |        implementation for it. */  | 
222  |  |     bool bExactFieldNameMatch = true;  | 
223  |  |  | 
224  |  |     /*! an alternate name to the new layer */  | 
225  |  |     std::string osNewLayerName{}; | 
226  |  |  | 
227  |  |     /*! attribute query (like SQL WHERE) */  | 
228  |  |     std::string osWHERE{}; | 
229  |  |  | 
230  |  |     /*! name of the geometry field on which the spatial filter operates on. */  | 
231  |  |     std::string osGeomField{}; | 
232  |  |  | 
233  |  |     /*! whether osGeomField is set (useful for empty strings) */  | 
234  |  |     bool bGeomFieldSet = false;  | 
235  |  |  | 
236  |  |     /*! whether -select has been specified. This is of course true when  | 
237  |  |      * !aosSelFields.empty(), but this can also be set when an empty string  | 
238  |  |      * has been to disable fields. */  | 
239  |  |     bool bSelFieldsSet = false;  | 
240  |  |  | 
241  |  |     /*! list of fields from input layer to copy to the new layer.  | 
242  |  |      * Geometry fields can also be specified in the list. */  | 
243  |  |     CPLStringList aosSelFields{}; | 
244  |  |  | 
245  |  |     /*! SQL statement to execute. The resulting table/layer will be saved to the  | 
246  |  |      * output. */  | 
247  |  |     std::string osSQLStatement{}; | 
248  |  |  | 
249  |  |     /*! SQL dialect. In some cases can be used to use (unoptimized) OGR SQL  | 
250  |  |        instead of the native SQL of an RDBMS by using "OGRSQL". The "SQLITE"  | 
251  |  |        dialect can also be used with any datasource. */  | 
252  |  |     std::string osDialect{}; | 
253  |  |  | 
254  |  |     /*! the geometry type for the created layer */  | 
255  |  |     int eGType = GEOMTYPE_UNCHANGED;  | 
256  |  |  | 
257  |  |     GeomTypeConversion eGeomTypeConversion = GTC_DEFAULT;  | 
258  |  |  | 
259  |  |     /*! Geometric operation to perform */  | 
260  |  |     GeomOperation eGeomOp = GEOMOP_NONE;  | 
261  |  |  | 
262  |  |     /*! the parameter to geometric operation */  | 
263  |  |     double dfGeomOpParam = 0;  | 
264  |  |  | 
265  |  |     /*! Whether to run MakeValid */  | 
266  |  |     bool bMakeValid = false;  | 
267  |  |  | 
268  |  |     /*! Whether to run OGRGeometry::IsValid */  | 
269  |  |     bool bSkipInvalidGeom = false;  | 
270  |  |  | 
271  |  |     /*! list of field types to convert to a field of type string in the  | 
272  |  |        destination layer. Valid types are: Integer, Integer64, Real, String,  | 
273  |  |        Date, Time, DateTime, Binary, IntegerList, Integer64List, RealList,  | 
274  |  |        StringList. Special value "All" can be used to convert all fields to  | 
275  |  |        strings. This is an alternate way to using the CAST operator of OGR SQL,  | 
276  |  |        that may avoid typing a long SQL query. Note that this does not influence  | 
277  |  |        the field types used by the source driver, and is only an afterwards  | 
278  |  |         conversion. */  | 
279  |  |     CPLStringList aosFieldTypesToString{}; | 
280  |  |  | 
281  |  |     /*! list of field types and the field type after conversion in the  | 
282  |  |        destination layer.  | 
283  |  |         ("srctype1=dsttype1","srctype2=dsttype2",...). | 
284  |  |         Valid types are : Integer, Integer64, Real, String, Date, Time,  | 
285  |  |        DateTime, Binary, IntegerList, Integer64List, RealList, StringList. Types  | 
286  |  |        can also include subtype between parenthesis, such as Integer(Boolean),  | 
287  |  |        Real(Float32), ... Special value "All" can be used to convert all fields  | 
288  |  |        to another type. This is an alternate way to using the CAST operator of  | 
289  |  |        OGR SQL, that may avoid typing a long SQL query. This is a generalization  | 
290  |  |        of GDALVectorTranslateOptions::papszFieldTypeToString. Note that this  | 
291  |  |        does not influence the field types used by the source driver, and is only  | 
292  |  |        an afterwards conversion. */  | 
293  |  |     CPLStringList aosMapFieldType{}; | 
294  |  |  | 
295  |  |     /*! set field width and precision to 0 */  | 
296  |  |     bool bUnsetFieldWidth = false;  | 
297  |  |  | 
298  |  |     /*! display progress on terminal. Only works if input layers have the "fast  | 
299  |  |     feature count" capability */  | 
300  |  |     bool bDisplayProgress = false;  | 
301  |  |  | 
302  |  |     /*! split geometries crossing the dateline meridian */  | 
303  |  |     bool bWrapDateline = false;  | 
304  |  |  | 
305  |  |     /*! offset from dateline in degrees (default long. = +/- 10deg, geometries  | 
306  |  |     within 170deg to -170deg will be split) */  | 
307  |  |     double dfDateLineOffset = 10.0;  | 
308  |  |  | 
309  |  |     /*! clip geometries when it is set to true */  | 
310  |  |     bool bClipSrc = false;  | 
311  |  |  | 
312  |  |     std::shared_ptr<OGRGeometry> poClipSrc{}; | 
313  |  |  | 
314  |  |     /*! clip datasource */  | 
315  |  |     std::string osClipSrcDS{}; | 
316  |  |  | 
317  |  |     /*! select desired geometries using an SQL query */  | 
318  |  |     std::string osClipSrcSQL{}; | 
319  |  |  | 
320  |  |     /*! selected named layer from the source clip datasource */  | 
321  |  |     std::string osClipSrcLayer{}; | 
322  |  |  | 
323  |  |     /*! restrict desired geometries based on attribute query */  | 
324  |  |     std::string osClipSrcWhere{}; | 
325  |  |  | 
326  |  |     std::shared_ptr<OGRGeometry> poClipDst{}; | 
327  |  |  | 
328  |  |     /*! destination clip datasource */  | 
329  |  |     std::string osClipDstDS{}; | 
330  |  |  | 
331  |  |     /*! select desired geometries using an SQL query */  | 
332  |  |     std::string osClipDstSQL{}; | 
333  |  |  | 
334  |  |     /*! selected named layer from the destination clip datasource */  | 
335  |  |     std::string osClipDstLayer{}; | 
336  |  |  | 
337  |  |     /*! restrict desired geometries based on attribute query */  | 
338  |  |     std::string osClipDstWhere{}; | 
339  |  |  | 
340  |  |     /*! split fields of type StringList, RealList or IntegerList into as many  | 
341  |  |        fields of type String, Real or Integer as necessary. */  | 
342  |  |     bool bSplitListFields = false;  | 
343  |  |  | 
344  |  |     /*! limit the number of subfields created for each split field. */  | 
345  |  |     int nMaxSplitListSubFields = -1;  | 
346  |  |  | 
347  |  |     /*! produce one feature for each geometry in any kind of geometry collection  | 
348  |  |        in the source file */  | 
349  |  |     bool bExplodeCollections = false;  | 
350  |  |  | 
351  |  |     /*! uses the specified field to fill the Z coordinates of geometries */  | 
352  |  |     std::string osZField{}; | 
353  |  |  | 
354  |  |     /*! the list of field indexes to be copied from the source to the  | 
355  |  |        destination. The (n)th value specified in the list is the index of the  | 
356  |  |        field in the target layer definition in which the n(th) field of the  | 
357  |  |        source layer must be copied. Index count starts at zero. There must be  | 
358  |  |         exactly as many values in the list as the count of the fields in the  | 
359  |  |        source layer. We can use the "identity" option to specify that the fields  | 
360  |  |        should be transferred by using the same order. This option should be used  | 
361  |  |        along with the GDALVectorTranslateOptions::eAccessMode = ACCESS_APPEND  | 
362  |  |        option. */  | 
363  |  |     CPLStringList aosFieldMap{}; | 
364  |  |  | 
365  |  |     /*! force the coordinate dimension to nCoordDim (valid values are 2 or 3).  | 
366  |  |        This affects both the layer geometry type, and feature geometries. */  | 
367  |  |     int nCoordDim = COORD_DIM_UNCHANGED;  | 
368  |  |  | 
369  |  |     /*! destination dataset open option (format specific), only valid in update  | 
370  |  |      * mode */  | 
371  |  |     CPLStringList aosDestOpenOptions{}; | 
372  |  |  | 
373  |  |     /*! If set to true, does not propagate not-nullable constraints to target  | 
374  |  |        layer if they exist in source layer */  | 
375  |  |     bool bForceNullable = false;  | 
376  |  |  | 
377  |  |     /*! If set to true, for each field with a coded field domains, create a  | 
378  |  |        field that contains the description of the coded value. */  | 
379  |  |     bool bResolveDomains = false;  | 
380  |  |  | 
381  |  |     /*! If set to true, empty string values will be treated as null */  | 
382  |  |     bool bEmptyStrAsNull = false;  | 
383  |  |  | 
384  |  |     /*! If set to true, does not propagate default field values to target layer  | 
385  |  |        if they exist in source layer */  | 
386  |  |     bool bUnsetDefault = false;  | 
387  |  |  | 
388  |  |     /*! to prevent the new default behavior that consists in, if the output  | 
389  |  |        driver has a FID layer creation option and we are not in append mode, to  | 
390  |  |        preserve the name of the source FID column and source feature IDs */  | 
391  |  |     bool bUnsetFid = false;  | 
392  |  |  | 
393  |  |     /*! use the FID of the source features instead of letting the output driver  | 
394  |  |        to automatically assign a new one. If not in append mode, this behavior  | 
395  |  |        becomes the default if the output driver has a FID layer creation option.  | 
396  |  |        In which case the name of the source FID column will be used and source  | 
397  |  |        feature IDs will be attempted to be preserved. This behavior can be  | 
398  |  |         disabled by option GDALVectorTranslateOptions::bUnsetFid */  | 
399  |  |     bool bPreserveFID = false;  | 
400  |  |  | 
401  |  |     /*! set it to false to disable copying of metadata from source dataset and  | 
402  |  |        layers into target dataset and layers, when supported by output driver.  | 
403  |  |      */  | 
404  |  |     bool bCopyMD = true;  | 
405  |  |  | 
406  |  |     /*! list of metadata key and value to set on the output dataset, when  | 
407  |  |        supported by output driver.  | 
408  |  |         ("META-TAG1=VALUE1","META-TAG2=VALUE2") */ | 
409  |  |     CPLStringList aosMetadataOptions{}; | 
410  |  |  | 
411  |  |     /*! override spatial filter SRS */  | 
412  |  |     std::string osSpatSRSDef{}; | 
413  |  |  | 
414  |  |     /*! list of ground control points to be added */  | 
415  |  |     CopyableGCPs oGCPs{}; | 
416  |  |  | 
417  |  |     /*! order of polynomial used for warping (1 to 3). The default is to select  | 
418  |  |        a polynomial order based on the number of GCPs */  | 
419  |  |     int nTransformOrder = 0;  | 
420  |  |  | 
421  |  |     /*! spatial query extents, in the SRS of the source layer(s) (or the one  | 
422  |  |        specified with GDALVectorTranslateOptions::pszSpatSRSDef). Only features  | 
423  |  |        whose geometry intersects the extents will be selected. The geometries  | 
424  |  |        will not be clipped unless GDALVectorTranslateOptions::bClipSrc is true.  | 
425  |  |      */  | 
426  |  |     std::shared_ptr<OGRGeometry> poSpatialFilter{}; | 
427  |  |  | 
428  |  |     /*! the progress function to use */  | 
429  |  |     GDALProgressFunc pfnProgress = nullptr;  | 
430  |  |  | 
431  |  |     /*! pointer to the progress data variable */  | 
432  |  |     void *pProgressData = nullptr;  | 
433  |  |  | 
434  |  |     /*! Whether layer and feature native data must be transferred. */  | 
435  |  |     bool bNativeData = true;  | 
436  |  |  | 
437  |  |     /*! Maximum number of features, or -1 if no limit. */  | 
438  |  |     GIntBig nLimit = -1;  | 
439  |  |  | 
440  |  |     /*! Wished offset w.r.t UTC of dateTime */  | 
441  |  |     int nTZOffsetInSec = TZ_OFFSET_INVALID;  | 
442  |  |  | 
443  |  |     /*! Geometry X,Y coordinate resolution */  | 
444  |  |     double dfXYRes = OGRGeomCoordinatePrecision::UNKNOWN;  | 
445  |  |  | 
446  |  |     /*! Unit of dXYRes. empty string, "m", "mm" or "deg" */  | 
447  |  |     std::string osXYResUnit{}; | 
448  |  |  | 
449  |  |     /*! Geometry Z coordinate resolution */  | 
450  |  |     double dfZRes = OGRGeomCoordinatePrecision::UNKNOWN;  | 
451  |  |  | 
452  |  |     /*! Unit of dfZRes. empty string, "m" or "mm" */  | 
453  |  |     std::string osZResUnit{}; | 
454  |  |  | 
455  |  |     /*! Geometry M coordinate resolution */  | 
456  |  |     double dfMRes = OGRGeomCoordinatePrecision::UNKNOWN;  | 
457  |  |  | 
458  |  |     /*! Whether to unset geometry coordinate precision */  | 
459  |  |     bool bUnsetCoordPrecision = false;  | 
460  |  |  | 
461  |  |     /*! set to true to prevent overwriting existing dataset */  | 
462  |  |     bool bNoOverwrite = false;  | 
463  |  |  | 
464  |  |     /*! set to true to prevent if called from "gdal vector convert" */  | 
465  |  |     bool bInvokedFromGdalVectorConvert = false;  | 
466  |  | };  | 
467  |  |  | 
468  |  | struct TargetLayerInfo  | 
469  |  | { | 
470  |  |     OGRLayer *m_poSrcLayer = nullptr;  | 
471  |  |     GIntBig m_nFeaturesRead = 0;  | 
472  |  |     bool m_bPerFeatureCT = 0;  | 
473  |  |     OGRLayer *m_poDstLayer = nullptr;  | 
474  |  |     bool m_bUseWriteArrowBatch = false;  | 
475  |  |  | 
476  |  |     struct ReprojectionInfo  | 
477  |  |     { | 
478  |  |         std::unique_ptr<OGRCoordinateTransformation> m_poCT{}; | 
479  |  |         CPLStringList m_aosTransformOptions{}; | 
480  |  |         bool m_bCanInvalidateValidity = true;  | 
481  |  |         bool m_bWarnAboutDifferentCoordinateOperations = false;  | 
482  |  |         double m_dfLeftX = std::numeric_limits<double>::max();  | 
483  |  |         double m_dfLeftY = 0;  | 
484  |  |         double m_dfLeftZ = 0;  | 
485  |  |         double m_dfRightX = -std::numeric_limits<double>::max();  | 
486  |  |         double m_dfRightY = 0;  | 
487  |  |         double m_dfRightZ = 0;  | 
488  |  |         double m_dfBottomX = 0;  | 
489  |  |         double m_dfBottomY = std::numeric_limits<double>::max();  | 
490  |  |         double m_dfBottomZ = 0;  | 
491  |  |         double m_dfTopX = 0;  | 
492  |  |         double m_dfTopY = -std::numeric_limits<double>::max();  | 
493  |  |         double m_dfTopZ = 0;  | 
494  |  |  | 
495  |  |         void UpdateExtremePoints(double dfX, double dfY, double dfZ)  | 
496  | 0  |         { | 
497  | 0  |             if (dfX < m_dfLeftX)  | 
498  | 0  |             { | 
499  | 0  |                 m_dfLeftX = dfX;  | 
500  | 0  |                 m_dfLeftY = dfY;  | 
501  | 0  |                 m_dfLeftZ = dfZ;  | 
502  | 0  |             }  | 
503  | 0  |             if (dfX > m_dfRightX)  | 
504  | 0  |             { | 
505  | 0  |                 m_dfRightX = dfX;  | 
506  | 0  |                 m_dfRightY = dfY;  | 
507  | 0  |                 m_dfRightZ = dfZ;  | 
508  | 0  |             }  | 
509  | 0  |             if (dfY < m_dfBottomY)  | 
510  | 0  |             { | 
511  | 0  |                 m_dfBottomX = dfX;  | 
512  | 0  |                 m_dfBottomY = dfY;  | 
513  | 0  |                 m_dfBottomZ = dfZ;  | 
514  | 0  |             }  | 
515  | 0  |             if (dfY > m_dfTopY)  | 
516  | 0  |             { | 
517  | 0  |                 m_dfTopX = dfX;  | 
518  | 0  |                 m_dfTopY = dfY;  | 
519  | 0  |                 m_dfTopZ = 0;  | 
520  | 0  |             }  | 
521  | 0  |         }  | 
522  |  |     };  | 
523  |  |  | 
524  |  |     std::vector<ReprojectionInfo> m_aoReprojectionInfo{}; | 
525  |  |  | 
526  |  |     std::vector<int> m_anMap{}; | 
527  |  |  | 
528  |  |     struct ResolvedInfo  | 
529  |  |     { | 
530  |  |         int nSrcField;  | 
531  |  |         const OGRFieldDomain *poDomain;  | 
532  |  |     };  | 
533  |  |  | 
534  |  |     std::map<int, ResolvedInfo> m_oMapResolved{}; | 
535  |  |     std::map<const OGRFieldDomain *, std::map<std::string, std::string>>  | 
536  |  |         m_oMapDomainToKV{}; | 
537  |  |     int m_iSrcZField = -1;  | 
538  |  |     int m_iSrcFIDField = -1;  | 
539  |  |     int m_iRequestedSrcGeomField = -1;  | 
540  |  |     bool m_bPreserveFID = false;  | 
541  |  |     const char *m_pszCTPipeline = nullptr;  | 
542  |  |     CPLStringList m_aosCTOptions{}; | 
543  |  |     bool m_bCanAvoidSetFrom = false;  | 
544  |  |     const char *m_pszSpatSRSDef = nullptr;  | 
545  |  |     OGRGeometryH m_hSpatialFilter = nullptr;  | 
546  |  |     const char *m_pszGeomField = nullptr;  | 
547  |  |     std::vector<int> m_anDateTimeFieldIdx{}; | 
548  |  |     bool m_bSupportCurves = false;  | 
549  |  |     OGRArrowArrayStream m_sArrowArrayStream{}; | 
550  |  |  | 
551  |  |     void CheckSameCoordinateOperation() const;  | 
552  |  | };  | 
553  |  |  | 
554  |  | struct AssociatedLayers  | 
555  |  | { | 
556  |  |     OGRLayer *poSrcLayer = nullptr;  | 
557  |  |     std::unique_ptr<TargetLayerInfo> psInfo{}; | 
558  |  | };  | 
559  |  |  | 
560  |  | class SetupTargetLayer  | 
561  |  | { | 
562  |  |     bool CanUseWriteArrowBatch(OGRLayer *poSrcLayer, OGRLayer *poDstLayer,  | 
563  |  |                                bool bJustCreatedLayer,  | 
564  |  |                                const GDALVectorTranslateOptions *psOptions,  | 
565  |  |                                bool bPreserveFID, bool &bError,  | 
566  |  |                                OGRArrowArrayStream &streamSrc);  | 
567  |  |  | 
568  |  |   public:  | 
569  |  |     GDALDataset *m_poSrcDS = nullptr;  | 
570  |  |     GDALDataset *m_poDstDS = nullptr;  | 
571  |  |     CSLConstList m_papszLCO = nullptr;  | 
572  |  |     const OGRSpatialReference *m_poUserSourceSRS = nullptr;  | 
573  |  |     const OGRSpatialReference *m_poOutputSRS = nullptr;  | 
574  |  |     bool m_bTransform = false;  | 
575  |  |     bool m_bNullifyOutputSRS = false;  | 
576  |  |     bool m_bSelFieldsSet = false;  | 
577  |  |     CSLConstList m_papszSelFields = nullptr;  | 
578  |  |     bool m_bAppend = false;  | 
579  |  |     bool m_bAddMissingFields = false;  | 
580  |  |     int m_eGType = 0;  | 
581  |  |     GeomTypeConversion m_eGeomTypeConversion = GTC_DEFAULT;  | 
582  |  |     int m_nCoordDim = 0;  | 
583  |  |     bool m_bOverwrite = false;  | 
584  |  |     CSLConstList m_papszFieldTypesToString = nullptr;  | 
585  |  |     CSLConstList m_papszMapFieldType = nullptr;  | 
586  |  |     bool m_bUnsetFieldWidth = false;  | 
587  |  |     bool m_bExplodeCollections = false;  | 
588  |  |     const char *m_pszZField = nullptr;  | 
589  |  |     CSLConstList m_papszFieldMap = nullptr;  | 
590  |  |     const char *m_pszWHERE = nullptr;  | 
591  |  |     bool m_bExactFieldNameMatch = false;  | 
592  |  |     bool m_bQuiet = false;  | 
593  |  |     bool m_bForceNullable = false;  | 
594  |  |     bool m_bResolveDomains = false;  | 
595  |  |     bool m_bUnsetDefault = false;  | 
596  |  |     bool m_bUnsetFid = false;  | 
597  |  |     bool m_bPreserveFID = false;  | 
598  |  |     bool m_bCopyMD = false;  | 
599  |  |     bool m_bNativeData = false;  | 
600  |  |     bool m_bNewDataSource = false;  | 
601  |  |     const char *m_pszCTPipeline = nullptr;  | 
602  |  |     CPLStringList m_aosCTOptions{}; | 
603  |  |  | 
604  |  |     std::unique_ptr<TargetLayerInfo>  | 
605  |  |     Setup(OGRLayer *poSrcLayer, const char *pszNewLayerName,  | 
606  |  |           GDALVectorTranslateOptions *psOptions, GIntBig &nTotalEventsDone);  | 
607  |  | };  | 
608  |  |  | 
609  |  | class LayerTranslator  | 
610  |  | { | 
611  |  |     bool TranslateArrow(TargetLayerInfo *psInfo, GIntBig nCountLayerFeatures,  | 
612  |  |                         GIntBig *pnReadFeatureCount,  | 
613  |  |                         GDALProgressFunc pfnProgress, void *pProgressArg,  | 
614  |  |                         const GDALVectorTranslateOptions *psOptions);  | 
615  |  |  | 
616  |  |   public:  | 
617  |  |     GDALDataset *m_poSrcDS = nullptr;  | 
618  |  |     GDALDataset *m_poODS = nullptr;  | 
619  |  |     bool m_bTransform = false;  | 
620  |  |     bool m_bWrapDateline = false;  | 
621  |  |     CPLString m_osDateLineOffset{}; | 
622  |  |     const OGRSpatialReference *m_poOutputSRS = nullptr;  | 
623  |  |     bool m_bNullifyOutputSRS = false;  | 
624  |  |     const OGRSpatialReference *m_poUserSourceSRS = nullptr;  | 
625  |  |     OGRCoordinateTransformation *m_poGCPCoordTrans = nullptr;  | 
626  |  |     int m_eGType = -1;  | 
627  |  |     GeomTypeConversion m_eGeomTypeConversion = GTC_DEFAULT;  | 
628  |  |     bool m_bMakeValid = false;  | 
629  |  |     bool m_bSkipInvalidGeom = false;  | 
630  |  |     int m_nCoordDim = 0;  | 
631  |  |     GeomOperation m_eGeomOp = GEOMOP_NONE;  | 
632  |  |     double m_dfGeomOpParam = 0;  | 
633  |  |  | 
634  |  |     OGRGeometry *m_poClipSrcOri = nullptr;  | 
635  |  |     bool m_bWarnedClipSrcSRS = false;  | 
636  |  |     std::unique_ptr<OGRGeometry> m_poClipSrcReprojectedToSrcSRS{}; | 
637  |  |     const OGRSpatialReference *m_poClipSrcReprojectedToSrcSRS_SRS = nullptr;  | 
638  |  |     OGREnvelope m_oClipSrcEnv{}; | 
639  |  |     bool m_bClipSrcIsRectangle = false;  | 
640  |  |  | 
641  |  |     OGRGeometry *m_poClipDstOri = nullptr;  | 
642  |  |     bool m_bWarnedClipDstSRS = false;  | 
643  |  |     std::unique_ptr<OGRGeometry> m_poClipDstReprojectedToDstSRS{}; | 
644  |  |     const OGRSpatialReference *m_poClipDstReprojectedToDstSRS_SRS = nullptr;  | 
645  |  |     OGREnvelope m_oClipDstEnv{}; | 
646  |  |     bool m_bClipDstIsRectangle = false;  | 
647  |  |  | 
648  |  |     bool m_bExplodeCollections = false;  | 
649  |  |     bool m_bNativeData = false;  | 
650  |  |     GIntBig m_nLimit = -1;  | 
651  |  |     OGRGeometryFactory::TransformWithOptionsCache m_transformWithOptionsCache{}; | 
652  |  |  | 
653  |  |     bool Translate(OGRFeature *poFeatureIn, TargetLayerInfo *psInfo,  | 
654  |  |                    GIntBig nCountLayerFeatures, GIntBig *pnReadFeatureCount,  | 
655  |  |                    GIntBig &nTotalEventsDone, GDALProgressFunc pfnProgress,  | 
656  |  |                    void *pProgressArg,  | 
657  |  |                    const GDALVectorTranslateOptions *psOptions);  | 
658  |  |  | 
659  |  |   private:  | 
660  |  |     struct ClipGeomDesc  | 
661  |  |     { | 
662  |  |         const OGRGeometry *poGeom = nullptr;  | 
663  |  |         const OGREnvelope *poEnv = nullptr;  | 
664  |  |         bool bGeomIsRectangle = false;  | 
665  |  |     };  | 
666  |  |  | 
667  |  |     ClipGeomDesc GetDstClipGeom(const OGRSpatialReference *poGeomSRS);  | 
668  |  |     ClipGeomDesc GetSrcClipGeom(const OGRSpatialReference *poGeomSRS);  | 
669  |  | };  | 
670  |  |  | 
671  |  | static OGRLayer *GetLayerAndOverwriteIfNecessary(GDALDataset *poDstDS,  | 
672  |  |                                                  const char *pszNewLayerName,  | 
673  |  |                                                  bool bOverwrite,  | 
674  |  |                                                  bool *pbErrorOccurred,  | 
675  |  |                                                  bool *pbOverwriteActuallyDone,  | 
676  |  |                                                  bool *pbAddOverwriteLCO);  | 
677  |  |  | 
678  |  | /************************************************************************/  | 
679  |  | /*                           LoadGeometry()                             */  | 
680  |  | /************************************************************************/  | 
681  |  |  | 
682  |  | static std::unique_ptr<OGRGeometry> LoadGeometry(const std::string &osDS,  | 
683  |  |                                                  const std::string &osSQL,  | 
684  |  |                                                  const std::string &osLyr,  | 
685  |  |                                                  const std::string &osWhere,  | 
686  |  |                                                  bool bMakeValid)  | 
687  | 0  | { | 
688  | 0  |     auto poDS = std::unique_ptr<GDALDataset>(  | 
689  | 0  |         GDALDataset::Open(osDS.c_str(), GDAL_OF_VECTOR));  | 
690  | 0  |     if (poDS == nullptr)  | 
691  | 0  |         return nullptr;  | 
692  |  |  | 
693  | 0  |     OGRLayer *poLyr = nullptr;  | 
694  | 0  |     if (!osSQL.empty())  | 
695  | 0  |         poLyr = poDS->ExecuteSQL(osSQL.c_str(), nullptr, nullptr);  | 
696  | 0  |     else if (!osLyr.empty())  | 
697  | 0  |         poLyr = poDS->GetLayerByName(osLyr.c_str());  | 
698  | 0  |     else  | 
699  | 0  |         poLyr = poDS->GetLayer(0);  | 
700  |  | 
  | 
701  | 0  |     if (poLyr == nullptr)  | 
702  | 0  |     { | 
703  | 0  |         CPLError(CE_Failure, CPLE_AppDefined,  | 
704  | 0  |                  "Failed to identify source layer from datasource.");  | 
705  | 0  |         return nullptr;  | 
706  | 0  |     }  | 
707  |  |  | 
708  | 0  |     if (!osWhere.empty())  | 
709  | 0  |         poLyr->SetAttributeFilter(osWhere.c_str());  | 
710  |  | 
  | 
711  | 0  |     OGRGeometryCollection oGC;  | 
712  |  | 
  | 
713  | 0  |     const auto poSRSSrc = poLyr->GetSpatialRef();  | 
714  | 0  |     if (poSRSSrc)  | 
715  | 0  |     { | 
716  | 0  |         auto poSRSClone = poSRSSrc->Clone();  | 
717  | 0  |         oGC.assignSpatialReference(poSRSClone);  | 
718  | 0  |         poSRSClone->Release();  | 
719  | 0  |     }  | 
720  |  | 
  | 
721  | 0  |     for (auto &poFeat : poLyr)  | 
722  | 0  |     { | 
723  | 0  |         auto poSrcGeom = std::unique_ptr<OGRGeometry>(poFeat->StealGeometry());  | 
724  | 0  |         if (poSrcGeom)  | 
725  | 0  |         { | 
726  |  |             // Only take into account areal geometries.  | 
727  | 0  |             if (poSrcGeom->getDimension() == 2)  | 
728  | 0  |             { | 
729  | 0  |                 if (!poSrcGeom->IsValid())  | 
730  | 0  |                 { | 
731  | 0  |                     if (!bMakeValid)  | 
732  | 0  |                     { | 
733  | 0  |                         CPLError(CE_Failure, CPLE_AppDefined,  | 
734  | 0  |                                  "Geometry of feature " CPL_FRMT_GIB " of %s "  | 
735  | 0  |                                  "is invalid. You can try to make it valid by "  | 
736  | 0  |                                  "specifying -makevalid, but the results of "  | 
737  | 0  |                                  "the operation should be manually inspected.",  | 
738  | 0  |                                  poFeat->GetFID(), osDS.c_str());  | 
739  | 0  |                         oGC.empty();  | 
740  | 0  |                         break;  | 
741  | 0  |                     }  | 
742  | 0  |                     auto poValid =  | 
743  | 0  |                         std::unique_ptr<OGRGeometry>(poSrcGeom->MakeValid());  | 
744  | 0  |                     if (poValid)  | 
745  | 0  |                     { | 
746  | 0  |                         CPLError(CE_Warning, CPLE_AppDefined,  | 
747  | 0  |                                  "Geometry of feature " CPL_FRMT_GIB " of %s "  | 
748  | 0  |                                  "was invalid and has been made valid, "  | 
749  | 0  |                                  "but the results of the operation "  | 
750  | 0  |                                  "should be manually inspected.",  | 
751  | 0  |                                  poFeat->GetFID(), osDS.c_str());  | 
752  |  | 
  | 
753  | 0  |                         oGC.addGeometry(std::move(poValid));  | 
754  | 0  |                     }  | 
755  | 0  |                     else  | 
756  | 0  |                     { | 
757  | 0  |                         CPLError(CE_Failure, CPLE_AppDefined,  | 
758  | 0  |                                  "Geometry of feature " CPL_FRMT_GIB " of %s "  | 
759  | 0  |                                  "is invalid, and could not be made valid.",  | 
760  | 0  |                                  poFeat->GetFID(), osDS.c_str());  | 
761  | 0  |                         oGC.empty();  | 
762  | 0  |                         break;  | 
763  | 0  |                     }  | 
764  | 0  |                 }  | 
765  | 0  |                 else  | 
766  | 0  |                 { | 
767  | 0  |                     oGC.addGeometry(std::move(poSrcGeom));  | 
768  | 0  |                 }  | 
769  | 0  |             }  | 
770  | 0  |         }  | 
771  | 0  |     }  | 
772  |  | 
  | 
773  | 0  |     if (!osSQL.empty())  | 
774  | 0  |         poDS->ReleaseResultSet(poLyr);  | 
775  |  | 
  | 
776  | 0  |     if (oGC.IsEmpty())  | 
777  | 0  |         return nullptr;  | 
778  |  |  | 
779  | 0  |     return std::unique_ptr<OGRGeometry>(oGC.UnaryUnion());  | 
780  | 0  | }  | 
781  |  |  | 
782  |  | /************************************************************************/  | 
783  |  | /*                     OGRSplitListFieldLayer                           */  | 
784  |  | /************************************************************************/  | 
785  |  |  | 
786  |  | typedef struct  | 
787  |  | { | 
788  |  |     int iSrcIndex;  | 
789  |  |     OGRFieldType eType;  | 
790  |  |     int nMaxOccurrences;  | 
791  |  |     int nWidth;  | 
792  |  | } ListFieldDesc;  | 
793  |  |  | 
794  |  | class OGRSplitListFieldLayer : public OGRLayer  | 
795  |  | { | 
796  |  |     OGRLayer *poSrcLayer = nullptr;  | 
797  |  |     OGRFeatureDefn *poFeatureDefn = nullptr;  | 
798  |  |     ListFieldDesc *pasListFields = nullptr;  | 
799  |  |     int nListFieldCount = 0;  | 
800  |  |     const int nMaxSplitListSubFields;  | 
801  |  |  | 
802  |  |     std::unique_ptr<OGRFeature>  | 
803  |  |     TranslateFeature(std::unique_ptr<OGRFeature> poSrcFeature);  | 
804  |  |  | 
805  |  |     CPL_DISALLOW_COPY_ASSIGN(OGRSplitListFieldLayer)  | 
806  |  |  | 
807  |  |   public:  | 
808  |  |     OGRSplitListFieldLayer(OGRLayer *poSrcLayer, int nMaxSplitListSubFields);  | 
809  |  |     virtual ~OGRSplitListFieldLayer();  | 
810  |  |  | 
811  |  |     bool BuildLayerDefn(GDALProgressFunc pfnProgress, void *pProgressArg);  | 
812  |  |  | 
813  |  |     virtual OGRFeature *GetNextFeature() override;  | 
814  |  |     virtual OGRFeature *GetFeature(GIntBig nFID) override;  | 
815  |  |     virtual OGRFeatureDefn *GetLayerDefn() override;  | 
816  |  |  | 
817  |  |     virtual void ResetReading() override  | 
818  | 0  |     { | 
819  | 0  |         poSrcLayer->ResetReading();  | 
820  | 0  |     }  | 
821  |  |  | 
822  |  |     virtual int TestCapability(const char *) override  | 
823  | 0  |     { | 
824  | 0  |         return FALSE;  | 
825  | 0  |     }  | 
826  |  |  | 
827  |  |     virtual GIntBig GetFeatureCount(int bForce = TRUE) override  | 
828  | 0  |     { | 
829  | 0  |         return poSrcLayer->GetFeatureCount(bForce);  | 
830  | 0  |     }  | 
831  |  |  | 
832  |  |     virtual OGRSpatialReference *GetSpatialRef() override  | 
833  | 0  |     { | 
834  | 0  |         return poSrcLayer->GetSpatialRef();  | 
835  | 0  |     }  | 
836  |  |  | 
837  |  |     virtual OGRGeometry *GetSpatialFilter() override  | 
838  | 0  |     { | 
839  | 0  |         return poSrcLayer->GetSpatialFilter();  | 
840  | 0  |     }  | 
841  |  |  | 
842  |  |     virtual OGRStyleTable *GetStyleTable() override  | 
843  | 0  |     { | 
844  | 0  |         return poSrcLayer->GetStyleTable();  | 
845  | 0  |     }  | 
846  |  |  | 
847  |  |     virtual OGRErr ISetSpatialFilter(int iGeom,  | 
848  |  |                                      const OGRGeometry *poGeom) override  | 
849  | 0  |     { | 
850  | 0  |         return poSrcLayer->SetSpatialFilter(iGeom, poGeom);  | 
851  | 0  |     }  | 
852  |  |  | 
853  |  |     virtual OGRErr SetAttributeFilter(const char *pszFilter) override  | 
854  | 0  |     { | 
855  | 0  |         return poSrcLayer->SetAttributeFilter(pszFilter);  | 
856  | 0  |     }  | 
857  |  | };  | 
858  |  |  | 
859  |  | /************************************************************************/  | 
860  |  | /*                    OGRSplitListFieldLayer()                          */  | 
861  |  | /************************************************************************/  | 
862  |  |  | 
863  |  | OGRSplitListFieldLayer::OGRSplitListFieldLayer(OGRLayer *poSrcLayerIn,  | 
864  |  |                                                int nMaxSplitListSubFieldsIn)  | 
865  | 0  |     : poSrcLayer(poSrcLayerIn),  | 
866  |  |       nMaxSplitListSubFields(  | 
867  | 0  |           nMaxSplitListSubFieldsIn < 0 ? INT_MAX : nMaxSplitListSubFieldsIn)  | 
868  | 0  | { | 
869  | 0  | }  | 
870  |  |  | 
871  |  | /************************************************************************/  | 
872  |  | /*                   ~OGRSplitListFieldLayer()                          */  | 
873  |  | /************************************************************************/  | 
874  |  |  | 
875  |  | OGRSplitListFieldLayer::~OGRSplitListFieldLayer()  | 
876  | 0  | { | 
877  | 0  |     if (poFeatureDefn)  | 
878  | 0  |         poFeatureDefn->Release();  | 
879  |  | 
  | 
880  | 0  |     CPLFree(pasListFields);  | 
881  | 0  | }  | 
882  |  |  | 
883  |  | /************************************************************************/  | 
884  |  | /*                       BuildLayerDefn()                               */  | 
885  |  | /************************************************************************/  | 
886  |  |  | 
887  |  | bool OGRSplitListFieldLayer::BuildLayerDefn(GDALProgressFunc pfnProgress,  | 
888  |  |                                             void *pProgressArg)  | 
889  | 0  | { | 
890  | 0  |     CPLAssert(poFeatureDefn == nullptr);  | 
891  |  |  | 
892  | 0  |     OGRFeatureDefn *poSrcFeatureDefn = poSrcLayer->GetLayerDefn();  | 
893  |  | 
  | 
894  | 0  |     const int nSrcFields = poSrcFeatureDefn->GetFieldCount();  | 
895  | 0  |     pasListFields = static_cast<ListFieldDesc *>(  | 
896  | 0  |         CPLCalloc(sizeof(ListFieldDesc), nSrcFields));  | 
897  | 0  |     nListFieldCount = 0;  | 
898  |  |  | 
899  |  |     /* Establish the list of fields of list type */  | 
900  | 0  |     for (int i = 0; i < nSrcFields; ++i)  | 
901  | 0  |     { | 
902  | 0  |         OGRFieldType eType = poSrcFeatureDefn->GetFieldDefn(i)->GetType();  | 
903  | 0  |         if (eType == OFTIntegerList || eType == OFTInteger64List ||  | 
904  | 0  |             eType == OFTRealList || eType == OFTStringList)  | 
905  | 0  |         { | 
906  | 0  |             pasListFields[nListFieldCount].iSrcIndex = i;  | 
907  | 0  |             pasListFields[nListFieldCount].eType = eType;  | 
908  | 0  |             if (nMaxSplitListSubFields == 1)  | 
909  | 0  |                 pasListFields[nListFieldCount].nMaxOccurrences = 1;  | 
910  | 0  |             nListFieldCount++;  | 
911  | 0  |         }  | 
912  | 0  |     }  | 
913  |  | 
  | 
914  | 0  |     if (nListFieldCount == 0)  | 
915  | 0  |         return false;  | 
916  |  |  | 
917  |  |     /* No need for full scan if the limit is 1. We just to have to create */  | 
918  |  |     /* one and a single one field */  | 
919  | 0  |     if (nMaxSplitListSubFields != 1)  | 
920  | 0  |     { | 
921  | 0  |         poSrcLayer->ResetReading();  | 
922  |  | 
  | 
923  | 0  |         const GIntBig nFeatureCount =  | 
924  | 0  |             poSrcLayer->TestCapability(OLCFastFeatureCount)  | 
925  | 0  |                 ? poSrcLayer->GetFeatureCount()  | 
926  | 0  |                 : 0;  | 
927  | 0  |         GIntBig nFeatureIndex = 0;  | 
928  |  |  | 
929  |  |         /* Scan the whole layer to compute the maximum number of */  | 
930  |  |         /* items for each field of list type */  | 
931  | 0  |         for (auto &poSrcFeature : poSrcLayer)  | 
932  | 0  |         { | 
933  | 0  |             for (int i = 0; i < nListFieldCount; ++i)  | 
934  | 0  |             { | 
935  | 0  |                 int nCount = 0;  | 
936  | 0  |                 OGRField *psField =  | 
937  | 0  |                     poSrcFeature->GetRawFieldRef(pasListFields[i].iSrcIndex);  | 
938  | 0  |                 switch (pasListFields[i].eType)  | 
939  | 0  |                 { | 
940  | 0  |                     case OFTIntegerList:  | 
941  | 0  |                         nCount = psField->IntegerList.nCount;  | 
942  | 0  |                         break;  | 
943  | 0  |                     case OFTRealList:  | 
944  | 0  |                         nCount = psField->RealList.nCount;  | 
945  | 0  |                         break;  | 
946  | 0  |                     case OFTStringList:  | 
947  | 0  |                     { | 
948  | 0  |                         nCount = psField->StringList.nCount;  | 
949  | 0  |                         char **paList = psField->StringList.paList;  | 
950  | 0  |                         for (int j = 0; j < nCount; j++)  | 
951  | 0  |                         { | 
952  | 0  |                             int nWidth = static_cast<int>(strlen(paList[j]));  | 
953  | 0  |                             if (nWidth > pasListFields[i].nWidth)  | 
954  | 0  |                                 pasListFields[i].nWidth = nWidth;  | 
955  | 0  |                         }  | 
956  | 0  |                         break;  | 
957  | 0  |                     }  | 
958  | 0  |                     default:  | 
959  |  |                         // cppcheck-suppress knownConditionTrueFalse  | 
960  | 0  |                         CPLAssert(false);  | 
961  | 0  |                         break;  | 
962  | 0  |                 }  | 
963  | 0  |                 if (nCount > pasListFields[i].nMaxOccurrences)  | 
964  | 0  |                 { | 
965  | 0  |                     if (nCount > nMaxSplitListSubFields)  | 
966  | 0  |                         nCount = nMaxSplitListSubFields;  | 
967  | 0  |                     pasListFields[i].nMaxOccurrences = nCount;  | 
968  | 0  |                 }  | 
969  | 0  |             }  | 
970  |  |  | 
971  | 0  |             nFeatureIndex++;  | 
972  | 0  |             if (pfnProgress != nullptr && nFeatureCount != 0)  | 
973  | 0  |                 pfnProgress(nFeatureIndex * 1.0 / nFeatureCount, "",  | 
974  | 0  |                             pProgressArg);  | 
975  | 0  |         }  | 
976  | 0  |     }  | 
977  |  |  | 
978  |  |     /* Now let's build the target feature definition */  | 
979  |  |  | 
980  | 0  |     poFeatureDefn =  | 
981  | 0  |         OGRFeatureDefn::CreateFeatureDefn(poSrcFeatureDefn->GetName());  | 
982  | 0  |     poFeatureDefn->Reference();  | 
983  | 0  |     poFeatureDefn->SetGeomType(wkbNone);  | 
984  |  | 
  | 
985  | 0  |     for (const auto poSrcGeomFieldDefn : poSrcFeatureDefn->GetGeomFields())  | 
986  | 0  |     { | 
987  | 0  |         poFeatureDefn->AddGeomFieldDefn(poSrcGeomFieldDefn);  | 
988  | 0  |     }  | 
989  |  | 
  | 
990  | 0  |     int iListField = 0;  | 
991  | 0  |     for (const auto poSrcFieldDefn : poSrcFeatureDefn->GetFields())  | 
992  | 0  |     { | 
993  | 0  |         const OGRFieldType eType = poSrcFieldDefn->GetType();  | 
994  | 0  |         if (eType == OFTIntegerList || eType == OFTInteger64List ||  | 
995  | 0  |             eType == OFTRealList || eType == OFTStringList)  | 
996  | 0  |         { | 
997  | 0  |             const int nMaxOccurrences =  | 
998  | 0  |                 pasListFields[iListField].nMaxOccurrences;  | 
999  | 0  |             const int nWidth = pasListFields[iListField].nWidth;  | 
1000  | 0  |             iListField++;  | 
1001  | 0  |             if (nMaxOccurrences == 1)  | 
1002  | 0  |             { | 
1003  | 0  |                 OGRFieldDefn oFieldDefn(poSrcFieldDefn->GetNameRef(),  | 
1004  | 0  |                                         (eType == OFTIntegerList) ? OFTInteger  | 
1005  | 0  |                                         : (eType == OFTInteger64List)  | 
1006  | 0  |                                             ? OFTInteger64  | 
1007  | 0  |                                         : (eType == OFTRealList) ? OFTReal  | 
1008  | 0  |                                                                  : OFTString);  | 
1009  | 0  |                 poFeatureDefn->AddFieldDefn(&oFieldDefn);  | 
1010  | 0  |             }  | 
1011  | 0  |             else  | 
1012  | 0  |             { | 
1013  | 0  |                 for (int j = 0; j < nMaxOccurrences; j++)  | 
1014  | 0  |                 { | 
1015  | 0  |                     CPLString osFieldName;  | 
1016  | 0  |                     osFieldName.Printf("%s%d", poSrcFieldDefn->GetNameRef(), | 
1017  | 0  |                                        j + 1);  | 
1018  | 0  |                     OGRFieldDefn oFieldDefn(  | 
1019  | 0  |                         osFieldName.c_str(),  | 
1020  | 0  |                         (eType == OFTIntegerList)     ? OFTInteger  | 
1021  | 0  |                         : (eType == OFTInteger64List) ? OFTInteger64  | 
1022  | 0  |                         : (eType == OFTRealList)      ? OFTReal  | 
1023  | 0  |                                                       : OFTString);  | 
1024  | 0  |                     oFieldDefn.SetWidth(nWidth);  | 
1025  | 0  |                     poFeatureDefn->AddFieldDefn(&oFieldDefn);  | 
1026  | 0  |                 }  | 
1027  | 0  |             }  | 
1028  | 0  |         }  | 
1029  | 0  |         else  | 
1030  | 0  |         { | 
1031  | 0  |             poFeatureDefn->AddFieldDefn(poSrcFieldDefn);  | 
1032  | 0  |         }  | 
1033  | 0  |     }  | 
1034  |  | 
  | 
1035  | 0  |     return true;  | 
1036  | 0  | }  | 
1037  |  |  | 
1038  |  | /************************************************************************/  | 
1039  |  | /*                       TranslateFeature()                             */  | 
1040  |  | /************************************************************************/  | 
1041  |  |  | 
1042  |  | std::unique_ptr<OGRFeature> OGRSplitListFieldLayer::TranslateFeature(  | 
1043  |  |     std::unique_ptr<OGRFeature> poSrcFeature)  | 
1044  | 0  | { | 
1045  | 0  |     if (poSrcFeature == nullptr)  | 
1046  | 0  |         return nullptr;  | 
1047  | 0  |     if (poFeatureDefn == nullptr)  | 
1048  | 0  |         return poSrcFeature;  | 
1049  |  |  | 
1050  | 0  |     auto poFeature = std::make_unique<OGRFeature>(poFeatureDefn);  | 
1051  | 0  |     poFeature->SetFID(poSrcFeature->GetFID());  | 
1052  | 0  |     for (int i = 0; i < poFeature->GetGeomFieldCount(); i++)  | 
1053  | 0  |     { | 
1054  | 0  |         poFeature->SetGeomFieldDirectly(i, poSrcFeature->StealGeometry(i));  | 
1055  | 0  |     }  | 
1056  | 0  |     poFeature->SetStyleString(poFeature->GetStyleString());  | 
1057  |  | 
  | 
1058  | 0  |     OGRFeatureDefn *poSrcFieldDefn = poSrcLayer->GetLayerDefn();  | 
1059  | 0  |     int nSrcFields = poSrcFeature->GetFieldCount();  | 
1060  | 0  |     int iDstField = 0;  | 
1061  | 0  |     int iListField = 0;  | 
1062  |  | 
  | 
1063  | 0  |     for (int iSrcField = 0; iSrcField < nSrcFields; ++iSrcField)  | 
1064  | 0  |     { | 
1065  | 0  |         const OGRFieldType eType =  | 
1066  | 0  |             poSrcFieldDefn->GetFieldDefn(iSrcField)->GetType();  | 
1067  | 0  |         OGRField *psField = poSrcFeature->GetRawFieldRef(iSrcField);  | 
1068  | 0  |         switch (eType)  | 
1069  | 0  |         { | 
1070  | 0  |             case OFTIntegerList:  | 
1071  | 0  |             { | 
1072  | 0  |                 const int nCount = std::min(nMaxSplitListSubFields,  | 
1073  | 0  |                                             psField->IntegerList.nCount);  | 
1074  | 0  |                 int *paList = psField->IntegerList.paList;  | 
1075  | 0  |                 for (int j = 0; j < nCount; ++j)  | 
1076  | 0  |                     poFeature->SetField(iDstField + j, paList[j]);  | 
1077  | 0  |                 iDstField += pasListFields[iListField].nMaxOccurrences;  | 
1078  | 0  |                 iListField++;  | 
1079  | 0  |                 break;  | 
1080  | 0  |             }  | 
1081  | 0  |             case OFTInteger64List:  | 
1082  | 0  |             { | 
1083  | 0  |                 const int nCount = std::min(nMaxSplitListSubFields,  | 
1084  | 0  |                                             psField->Integer64List.nCount);  | 
1085  | 0  |                 GIntBig *paList = psField->Integer64List.paList;  | 
1086  | 0  |                 for (int j = 0; j < nCount; ++j)  | 
1087  | 0  |                     poFeature->SetField(iDstField + j, paList[j]);  | 
1088  | 0  |                 iDstField += pasListFields[iListField].nMaxOccurrences;  | 
1089  | 0  |                 iListField++;  | 
1090  | 0  |                 break;  | 
1091  | 0  |             }  | 
1092  | 0  |             case OFTRealList:  | 
1093  | 0  |             { | 
1094  | 0  |                 const int nCount =  | 
1095  | 0  |                     std::min(nMaxSplitListSubFields, psField->RealList.nCount);  | 
1096  | 0  |                 double *paList = psField->RealList.paList;  | 
1097  | 0  |                 for (int j = 0; j < nCount; ++j)  | 
1098  | 0  |                     poFeature->SetField(iDstField + j, paList[j]);  | 
1099  | 0  |                 iDstField += pasListFields[iListField].nMaxOccurrences;  | 
1100  | 0  |                 iListField++;  | 
1101  | 0  |                 break;  | 
1102  | 0  |             }  | 
1103  | 0  |             case OFTStringList:  | 
1104  | 0  |             { | 
1105  | 0  |                 const int nCount = std::min(nMaxSplitListSubFields,  | 
1106  | 0  |                                             psField->StringList.nCount);  | 
1107  | 0  |                 char **paList = psField->StringList.paList;  | 
1108  | 0  |                 for (int j = 0; j < nCount; ++j)  | 
1109  | 0  |                     poFeature->SetField(iDstField + j, paList[j]);  | 
1110  | 0  |                 iDstField += pasListFields[iListField].nMaxOccurrences;  | 
1111  | 0  |                 iListField++;  | 
1112  | 0  |                 break;  | 
1113  | 0  |             }  | 
1114  | 0  |             default:  | 
1115  | 0  |             { | 
1116  | 0  |                 poFeature->SetField(iDstField, psField);  | 
1117  | 0  |                 iDstField++;  | 
1118  | 0  |                 break;  | 
1119  | 0  |             }  | 
1120  | 0  |         }  | 
1121  | 0  |     }  | 
1122  |  |  | 
1123  | 0  |     return poFeature;  | 
1124  | 0  | }  | 
1125  |  |  | 
1126  |  | /************************************************************************/  | 
1127  |  | /*                       GetNextFeature()                               */  | 
1128  |  | /************************************************************************/  | 
1129  |  |  | 
1130  |  | OGRFeature *OGRSplitListFieldLayer::GetNextFeature()  | 
1131  | 0  | { | 
1132  | 0  |     return TranslateFeature(  | 
1133  | 0  |                std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature()))  | 
1134  | 0  |         .release();  | 
1135  | 0  | }  | 
1136  |  |  | 
1137  |  | /************************************************************************/  | 
1138  |  | /*                           GetFeature()                               */  | 
1139  |  | /************************************************************************/  | 
1140  |  |  | 
1141  |  | OGRFeature *OGRSplitListFieldLayer::GetFeature(GIntBig nFID)  | 
1142  | 0  | { | 
1143  | 0  |     return TranslateFeature(  | 
1144  | 0  |                std::unique_ptr<OGRFeature>(poSrcLayer->GetFeature(nFID)))  | 
1145  | 0  |         .release();  | 
1146  | 0  | }  | 
1147  |  |  | 
1148  |  | /************************************************************************/  | 
1149  |  | /*                        GetLayerDefn()                                */  | 
1150  |  | /************************************************************************/  | 
1151  |  |  | 
1152  |  | OGRFeatureDefn *OGRSplitListFieldLayer::GetLayerDefn()  | 
1153  | 0  | { | 
1154  | 0  |     if (poFeatureDefn == nullptr)  | 
1155  | 0  |         return poSrcLayer->GetLayerDefn();  | 
1156  | 0  |     return poFeatureDefn;  | 
1157  | 0  | }  | 
1158  |  |  | 
1159  |  | /************************************************************************/  | 
1160  |  | /*                            GCPCoordTransformation()                  */  | 
1161  |  | /*                                                                      */  | 
1162  |  | /*      Apply GCP Transform to points                                   */  | 
1163  |  | /************************************************************************/  | 
1164  |  |  | 
1165  |  | class GCPCoordTransformation : public OGRCoordinateTransformation  | 
1166  |  | { | 
1167  |  |     GCPCoordTransformation(const GCPCoordTransformation &other)  | 
1168  | 0  |         : hTransformArg(GDALCloneTransformer(other.hTransformArg)),  | 
1169  | 0  |           bUseTPS(other.bUseTPS), poSRS(other.poSRS)  | 
1170  | 0  |     { | 
1171  | 0  |         if (poSRS)  | 
1172  | 0  |             poSRS->Reference();  | 
1173  | 0  |     }  | 
1174  |  |  | 
1175  |  |     GCPCoordTransformation &operator=(const GCPCoordTransformation &) = delete;  | 
1176  |  |  | 
1177  |  |   public:  | 
1178  |  |     void *hTransformArg;  | 
1179  |  |     bool bUseTPS;  | 
1180  |  |     OGRSpatialReference *poSRS;  | 
1181  |  |  | 
1182  |  |     GCPCoordTransformation(int nGCPCount, const GDAL_GCP *pasGCPList,  | 
1183  |  |                            int nReqOrder, OGRSpatialReference *poSRSIn)  | 
1184  | 0  |         : hTransformArg(nullptr), bUseTPS(nReqOrder < 0), poSRS(poSRSIn)  | 
1185  | 0  |     { | 
1186  | 0  |         if (nReqOrder < 0)  | 
1187  | 0  |         { | 
1188  | 0  |             hTransformArg =  | 
1189  | 0  |                 GDALCreateTPSTransformer(nGCPCount, pasGCPList, FALSE);  | 
1190  | 0  |         }  | 
1191  | 0  |         else  | 
1192  | 0  |         { | 
1193  | 0  |             hTransformArg = GDALCreateGCPTransformer(nGCPCount, pasGCPList,  | 
1194  | 0  |                                                      nReqOrder, FALSE);  | 
1195  | 0  |         }  | 
1196  | 0  |         if (poSRS)  | 
1197  | 0  |             poSRS->Reference();  | 
1198  | 0  |     }  | 
1199  |  |  | 
1200  |  |     OGRCoordinateTransformation *Clone() const override  | 
1201  | 0  |     { | 
1202  | 0  |         return new GCPCoordTransformation(*this);  | 
1203  | 0  |     }  | 
1204  |  |  | 
1205  |  |     bool IsValid() const  | 
1206  | 0  |     { | 
1207  | 0  |         return hTransformArg != nullptr;  | 
1208  | 0  |     }  | 
1209  |  |  | 
1210  |  |     ~GCPCoordTransformation() override;  | 
1211  |  |  | 
1212  |  |     virtual const OGRSpatialReference *GetSourceCS() const override  | 
1213  | 0  |     { | 
1214  | 0  |         return poSRS;  | 
1215  | 0  |     }  | 
1216  |  |  | 
1217  |  |     virtual const OGRSpatialReference *GetTargetCS() const override  | 
1218  | 0  |     { | 
1219  | 0  |         return poSRS;  | 
1220  | 0  |     }  | 
1221  |  |  | 
1222  |  |     virtual int Transform(size_t nCount, double *x, double *y, double *z,  | 
1223  |  |                           double * /* t */, int *pabSuccess) override  | 
1224  | 0  |     { | 
1225  | 0  |         CPLAssert(nCount <=  | 
1226  | 0  |                   static_cast<size_t>(std::numeric_limits<int>::max()));  | 
1227  | 0  |         if (bUseTPS)  | 
1228  | 0  |             return GDALTPSTransform(hTransformArg, FALSE,  | 
1229  | 0  |                                     static_cast<int>(nCount), x, y, z,  | 
1230  | 0  |                                     pabSuccess);  | 
1231  | 0  |         else  | 
1232  | 0  |             return GDALGCPTransform(hTransformArg, FALSE,  | 
1233  | 0  |                                     static_cast<int>(nCount), x, y, z,  | 
1234  | 0  |                                     pabSuccess);  | 
1235  | 0  |     }  | 
1236  |  |  | 
1237  |  |     virtual OGRCoordinateTransformation *GetInverse() const override  | 
1238  | 0  |     { | 
1239  | 0  |         static std::once_flag flag;  | 
1240  | 0  |         std::call_once(flag,  | 
1241  | 0  |                        []()  | 
1242  | 0  |                        { | 
1243  | 0  |                            CPLDebug("OGR2OGR", | 
1244  | 0  |                                     "GCPCoordTransformation::GetInverse() "  | 
1245  | 0  |                                     "called, but not implemented");  | 
1246  | 0  |                        });  | 
1247  | 0  |         return nullptr;  | 
1248  | 0  |     }  | 
1249  |  | };  | 
1250  |  |  | 
1251  |  | GCPCoordTransformation::~GCPCoordTransformation()  | 
1252  | 0  | { | 
1253  | 0  |     if (hTransformArg != nullptr)  | 
1254  | 0  |     { | 
1255  | 0  |         GDALDestroyTransformer(hTransformArg);  | 
1256  | 0  |     }  | 
1257  | 0  |     if (poSRS)  | 
1258  | 0  |         poSRS->Dereference();  | 
1259  | 0  | }  | 
1260  |  |  | 
1261  |  | /************************************************************************/  | 
1262  |  | /*                            CompositeCT                               */  | 
1263  |  | /************************************************************************/  | 
1264  |  |  | 
1265  |  | class CompositeCT : public OGRCoordinateTransformation  | 
1266  |  | { | 
1267  |  |     OGRCoordinateTransformation *const poCT1;  | 
1268  |  |     const bool bOwnCT1;  | 
1269  |  |     OGRCoordinateTransformation *const poCT2;  | 
1270  |  |     const bool bOwnCT2;  | 
1271  |  |  | 
1272  |  |     // Working buffer  | 
1273  |  |     std::vector<int> m_anErrorCode{}; | 
1274  |  |  | 
1275  |  |     CompositeCT(const CompositeCT &other)  | 
1276  | 0  |         : poCT1(other.poCT1 ? other.poCT1->Clone() : nullptr), bOwnCT1(true),  | 
1277  | 0  |           poCT2(other.poCT2 ? other.poCT2->Clone() : nullptr), bOwnCT2(true),  | 
1278  | 0  |           m_anErrorCode({}) | 
1279  | 0  |     { | 
1280  | 0  |     }  | 
1281  |  |  | 
1282  |  |     CompositeCT &operator=(const CompositeCT &) = delete;  | 
1283  |  |  | 
1284  |  |   public:  | 
1285  |  |     CompositeCT(OGRCoordinateTransformation *poCT1In, bool bOwnCT1In,  | 
1286  |  |                 OGRCoordinateTransformation *poCT2In, bool bOwnCT2In)  | 
1287  | 0  |         : poCT1(poCT1In), bOwnCT1(bOwnCT1In), poCT2(poCT2In), bOwnCT2(bOwnCT2In)  | 
1288  | 0  |     { | 
1289  | 0  |     }  | 
1290  |  |  | 
1291  |  |     ~CompositeCT() override;  | 
1292  |  |  | 
1293  |  |     OGRCoordinateTransformation *Clone() const override  | 
1294  | 0  |     { | 
1295  | 0  |         return new CompositeCT(*this);  | 
1296  | 0  |     }  | 
1297  |  |  | 
1298  |  |     virtual const OGRSpatialReference *GetSourceCS() const override  | 
1299  | 0  |     { | 
1300  | 0  |         return poCT1   ? poCT1->GetSourceCS()  | 
1301  | 0  |                : poCT2 ? poCT2->GetSourceCS()  | 
1302  | 0  |                        : nullptr;  | 
1303  | 0  |     }  | 
1304  |  |  | 
1305  |  |     virtual const OGRSpatialReference *GetTargetCS() const override  | 
1306  | 0  |     { | 
1307  | 0  |         return poCT2   ? poCT2->GetTargetCS()  | 
1308  | 0  |                : poCT1 ? poCT1->GetTargetCS()  | 
1309  | 0  |                        : nullptr;  | 
1310  | 0  |     }  | 
1311  |  |  | 
1312  |  |     virtual bool GetEmitErrors() const override  | 
1313  | 0  |     { | 
1314  | 0  |         if (poCT1)  | 
1315  | 0  |             return poCT1->GetEmitErrors();  | 
1316  | 0  |         if (poCT2)  | 
1317  | 0  |             return poCT2->GetEmitErrors();  | 
1318  | 0  |         return true;  | 
1319  | 0  |     }  | 
1320  |  |  | 
1321  |  |     virtual void SetEmitErrors(bool bEmitErrors) override  | 
1322  | 0  |     { | 
1323  | 0  |         if (poCT1)  | 
1324  | 0  |             poCT1->SetEmitErrors(bEmitErrors);  | 
1325  | 0  |         if (poCT2)  | 
1326  | 0  |             poCT2->SetEmitErrors(bEmitErrors);  | 
1327  | 0  |     }  | 
1328  |  |  | 
1329  |  |     virtual int Transform(size_t nCount, double *x, double *y, double *z,  | 
1330  |  |                           double *t, int *pabSuccess) override  | 
1331  | 0  |     { | 
1332  | 0  |         int nResult = TRUE;  | 
1333  | 0  |         if (poCT1)  | 
1334  | 0  |             nResult = poCT1->Transform(nCount, x, y, z, t, pabSuccess);  | 
1335  | 0  |         if (nResult && poCT2)  | 
1336  | 0  |             nResult = poCT2->Transform(nCount, x, y, z, t, pabSuccess);  | 
1337  | 0  |         return nResult;  | 
1338  | 0  |     }  | 
1339  |  |  | 
1340  |  |     virtual int TransformWithErrorCodes(size_t nCount, double *x, double *y,  | 
1341  |  |                                         double *z, double *t,  | 
1342  |  |                                         int *panErrorCodes) override  | 
1343  | 0  |     { | 
1344  | 0  |         if (poCT1 && poCT2 && panErrorCodes)  | 
1345  | 0  |         { | 
1346  | 0  |             m_anErrorCode.resize(nCount);  | 
1347  | 0  |             int nResult = poCT1->TransformWithErrorCodes(nCount, x, y, z, t,  | 
1348  | 0  |                                                          m_anErrorCode.data());  | 
1349  | 0  |             if (nResult)  | 
1350  | 0  |                 nResult = poCT2->TransformWithErrorCodes(nCount, x, y, z, t,  | 
1351  | 0  |                                                          panErrorCodes);  | 
1352  | 0  |             for (size_t i = 0; i < nCount; ++i)  | 
1353  | 0  |             { | 
1354  | 0  |                 if (m_anErrorCode[i])  | 
1355  | 0  |                     panErrorCodes[i] = m_anErrorCode[i];  | 
1356  | 0  |             }  | 
1357  | 0  |             return nResult;  | 
1358  | 0  |         }  | 
1359  | 0  |         int nResult = TRUE;  | 
1360  | 0  |         if (poCT1)  | 
1361  | 0  |             nResult = poCT1->TransformWithErrorCodes(nCount, x, y, z, t,  | 
1362  | 0  |                                                      panErrorCodes);  | 
1363  | 0  |         if (nResult && poCT2)  | 
1364  | 0  |             nResult = poCT2->TransformWithErrorCodes(nCount, x, y, z, t,  | 
1365  | 0  |                                                      panErrorCodes);  | 
1366  | 0  |         return nResult;  | 
1367  | 0  |     }  | 
1368  |  |  | 
1369  |  |     virtual OGRCoordinateTransformation *GetInverse() const override  | 
1370  | 0  |     { | 
1371  | 0  |         if (!poCT1 && !poCT2)  | 
1372  | 0  |             return nullptr;  | 
1373  | 0  |         if (!poCT2)  | 
1374  | 0  |             return poCT1->GetInverse();  | 
1375  | 0  |         if (!poCT1)  | 
1376  | 0  |             return poCT2->GetInverse();  | 
1377  | 0  |         auto poInvCT1 =  | 
1378  | 0  |             std::unique_ptr<OGRCoordinateTransformation>(poCT1->GetInverse());  | 
1379  | 0  |         auto poInvCT2 =  | 
1380  | 0  |             std::unique_ptr<OGRCoordinateTransformation>(poCT2->GetInverse());  | 
1381  | 0  |         if (!poInvCT1 || !poInvCT2)  | 
1382  | 0  |             return nullptr;  | 
1383  | 0  |         return std::make_unique<CompositeCT>(poInvCT2.release(), true,  | 
1384  | 0  |                                              poInvCT1.release(), true)  | 
1385  | 0  |             .release();  | 
1386  | 0  |     }  | 
1387  |  | };  | 
1388  |  |  | 
1389  |  | CompositeCT::~CompositeCT()  | 
1390  | 0  | { | 
1391  | 0  |     if (bOwnCT1)  | 
1392  | 0  |         delete poCT1;  | 
1393  | 0  |     if (bOwnCT2)  | 
1394  | 0  |         delete poCT2;  | 
1395  | 0  | }  | 
1396  |  |  | 
1397  |  | /************************************************************************/  | 
1398  |  | /*                    AxisMappingCoordinateTransformation               */  | 
1399  |  | /************************************************************************/  | 
1400  |  |  | 
1401  |  | class AxisMappingCoordinateTransformation : public OGRCoordinateTransformation  | 
1402  |  | { | 
1403  |  |     bool bSwapXY = false;  | 
1404  |  |  | 
1405  |  |     explicit AxisMappingCoordinateTransformation(bool bSwapXYIn)  | 
1406  | 0  |         : bSwapXY(bSwapXYIn)  | 
1407  | 0  |     { | 
1408  | 0  |     }  | 
1409  |  |  | 
1410  |  |     AxisMappingCoordinateTransformation(  | 
1411  | 0  |         const AxisMappingCoordinateTransformation &) = default;  | 
1412  |  |     AxisMappingCoordinateTransformation &  | 
1413  |  |     operator=(const AxisMappingCoordinateTransformation &) = delete;  | 
1414  |  |     AxisMappingCoordinateTransformation(  | 
1415  |  |         AxisMappingCoordinateTransformation &&) = delete;  | 
1416  |  |     AxisMappingCoordinateTransformation &  | 
1417  |  |     operator=(AxisMappingCoordinateTransformation &&) = delete;  | 
1418  |  |  | 
1419  |  |   public:  | 
1420  |  |     AxisMappingCoordinateTransformation(const std::vector<int> &mappingIn,  | 
1421  |  |                                         const std::vector<int> &mappingOut)  | 
1422  | 0  |     { | 
1423  | 0  |         if (mappingIn.size() >= 2 && mappingIn[0] == 1 && mappingIn[1] == 2 &&  | 
1424  | 0  |             mappingOut.size() >= 2 && mappingOut[0] == 2 && mappingOut[1] == 1)  | 
1425  | 0  |         { | 
1426  | 0  |             bSwapXY = true;  | 
1427  | 0  |         }  | 
1428  | 0  |         else if (mappingIn.size() >= 2 && mappingIn[0] == 2 &&  | 
1429  | 0  |                  mappingIn[1] == 1 && mappingOut.size() >= 2 &&  | 
1430  | 0  |                  mappingOut[0] == 1 && mappingOut[1] == 2)  | 
1431  | 0  |         { | 
1432  | 0  |             bSwapXY = true;  | 
1433  | 0  |         }  | 
1434  | 0  |         else  | 
1435  | 0  |         { | 
1436  | 0  |             CPLError(CE_Failure, CPLE_NotSupported,  | 
1437  | 0  |                      "Unsupported axis transformation");  | 
1438  | 0  |         }  | 
1439  | 0  |     }  | 
1440  |  |  | 
1441  |  |     ~AxisMappingCoordinateTransformation() override;  | 
1442  |  |  | 
1443  |  |     virtual OGRCoordinateTransformation *Clone() const override  | 
1444  | 0  |     { | 
1445  | 0  |         return new AxisMappingCoordinateTransformation(*this);  | 
1446  | 0  |     }  | 
1447  |  |  | 
1448  |  |     virtual const OGRSpatialReference *GetSourceCS() const override  | 
1449  | 0  |     { | 
1450  | 0  |         return nullptr;  | 
1451  | 0  |     }  | 
1452  |  |  | 
1453  |  |     virtual const OGRSpatialReference *GetTargetCS() const override  | 
1454  | 0  |     { | 
1455  | 0  |         return nullptr;  | 
1456  | 0  |     }  | 
1457  |  |  | 
1458  |  |     virtual int Transform(size_t nCount, double *x, double *y, double * /*z*/,  | 
1459  |  |                           double * /*t*/, int *pabSuccess) override  | 
1460  | 0  |     { | 
1461  | 0  |         for (size_t i = 0; i < nCount; i++)  | 
1462  | 0  |         { | 
1463  | 0  |             if (pabSuccess)  | 
1464  | 0  |                 pabSuccess[i] = true;  | 
1465  | 0  |             if (bSwapXY)  | 
1466  | 0  |                 std::swap(x[i], y[i]);  | 
1467  | 0  |         }  | 
1468  | 0  |         return true;  | 
1469  | 0  |     }  | 
1470  |  |  | 
1471  |  |     virtual int TransformWithErrorCodes(size_t nCount, double *x, double *y,  | 
1472  |  |                                         double * /*z*/, double * /*t*/,  | 
1473  |  |                                         int *panErrorCodes) override  | 
1474  | 0  |     { | 
1475  | 0  |         for (size_t i = 0; i < nCount; i++)  | 
1476  | 0  |         { | 
1477  | 0  |             if (panErrorCodes)  | 
1478  | 0  |                 panErrorCodes[i] = 0;  | 
1479  | 0  |             if (bSwapXY)  | 
1480  | 0  |                 std::swap(x[i], y[i]);  | 
1481  | 0  |         }  | 
1482  | 0  |         return true;  | 
1483  | 0  |     }  | 
1484  |  |  | 
1485  |  |     virtual OGRCoordinateTransformation *GetInverse() const override  | 
1486  | 0  |     { | 
1487  | 0  |         return new AxisMappingCoordinateTransformation(bSwapXY);  | 
1488  | 0  |     }  | 
1489  |  | };  | 
1490  |  |  | 
1491  | 0  | AxisMappingCoordinateTransformation::~AxisMappingCoordinateTransformation() =  | 
1492  |  |     default;  | 
1493  |  |  | 
1494  |  | /************************************************************************/  | 
1495  |  | /*                        ApplySpatialFilter()                          */  | 
1496  |  | /************************************************************************/  | 
1497  |  |  | 
1498  |  | static void ApplySpatialFilter(OGRLayer *poLayer, OGRGeometry *poSpatialFilter,  | 
1499  |  |                                const OGRSpatialReference *poSpatSRS,  | 
1500  |  |                                const char *pszGeomField,  | 
1501  |  |                                const OGRSpatialReference *poSourceSRS)  | 
1502  | 0  | { | 
1503  | 0  |     if (poSpatialFilter == nullptr)  | 
1504  | 0  |         return;  | 
1505  |  |  | 
1506  | 0  |     OGRGeometry *poSpatialFilterReprojected = nullptr;  | 
1507  | 0  |     if (poSpatSRS)  | 
1508  | 0  |     { | 
1509  | 0  |         poSpatialFilterReprojected = poSpatialFilter->clone();  | 
1510  | 0  |         poSpatialFilterReprojected->assignSpatialReference(poSpatSRS);  | 
1511  | 0  |         const OGRSpatialReference *poSpatialFilterTargetSRS =  | 
1512  | 0  |             poSourceSRS ? poSourceSRS : poLayer->GetSpatialRef();  | 
1513  | 0  |         if (poSpatialFilterTargetSRS)  | 
1514  | 0  |         { | 
1515  |  |             // When transforming the spatial filter from its spat_srs to the  | 
1516  |  |             // layer SRS, make sure to densify it sufficiently to avoid issues  | 
1517  | 0  |             constexpr double SEGMENT_DISTANCE_METRE = 10 * 1000;  | 
1518  | 0  |             if (poSpatSRS->IsGeographic())  | 
1519  | 0  |             { | 
1520  | 0  |                 const double LENGTH_OF_ONE_DEGREE =  | 
1521  | 0  |                     poSpatSRS->GetSemiMajor(nullptr) * M_PI / 180.0;  | 
1522  | 0  |                 poSpatialFilterReprojected->segmentize(SEGMENT_DISTANCE_METRE /  | 
1523  | 0  |                                                        LENGTH_OF_ONE_DEGREE);  | 
1524  | 0  |             }  | 
1525  | 0  |             else if (poSpatSRS->IsProjected())  | 
1526  | 0  |             { | 
1527  | 0  |                 poSpatialFilterReprojected->segmentize(  | 
1528  | 0  |                     SEGMENT_DISTANCE_METRE /  | 
1529  | 0  |                     poSpatSRS->GetLinearUnits(nullptr));  | 
1530  | 0  |             }  | 
1531  | 0  |             poSpatialFilterReprojected->transformTo(poSpatialFilterTargetSRS);  | 
1532  | 0  |         }  | 
1533  | 0  |         else  | 
1534  | 0  |             CPLError(CE_Warning, CPLE_AppDefined,  | 
1535  | 0  |                      "cannot determine layer SRS for %s.",  | 
1536  | 0  |                      poLayer->GetDescription());  | 
1537  | 0  |     }  | 
1538  |  | 
  | 
1539  | 0  |     if (pszGeomField != nullptr)  | 
1540  | 0  |     { | 
1541  | 0  |         const int iGeomField =  | 
1542  | 0  |             poLayer->GetLayerDefn()->GetGeomFieldIndex(pszGeomField);  | 
1543  | 0  |         if (iGeomField >= 0)  | 
1544  | 0  |             poLayer->SetSpatialFilter(iGeomField,  | 
1545  | 0  |                                       poSpatialFilterReprojected  | 
1546  | 0  |                                           ? poSpatialFilterReprojected  | 
1547  | 0  |                                           : poSpatialFilter);  | 
1548  | 0  |         else  | 
1549  | 0  |             CPLError(CE_Warning, CPLE_AppDefined,  | 
1550  | 0  |                      "Cannot find geometry field %s.", pszGeomField);  | 
1551  | 0  |     }  | 
1552  | 0  |     else  | 
1553  | 0  |     { | 
1554  | 0  |         poLayer->SetSpatialFilter(poSpatialFilterReprojected  | 
1555  | 0  |                                       ? poSpatialFilterReprojected  | 
1556  | 0  |                                       : poSpatialFilter);  | 
1557  | 0  |     }  | 
1558  |  | 
  | 
1559  | 0  |     delete poSpatialFilterReprojected;  | 
1560  | 0  | }  | 
1561  |  |  | 
1562  |  | /************************************************************************/  | 
1563  |  | /*                            GetFieldType()                            */  | 
1564  |  | /************************************************************************/  | 
1565  |  |  | 
1566  |  | static int GetFieldType(const char *pszArg, int *pnSubFieldType)  | 
1567  | 0  | { | 
1568  | 0  |     *pnSubFieldType = OFSTNone;  | 
1569  | 0  |     const char *pszOpenParenthesis = strchr(pszArg, '('); | 
1570  | 0  |     const int nLengthBeforeParenthesis =  | 
1571  | 0  |         pszOpenParenthesis ? static_cast<int>(pszOpenParenthesis - pszArg)  | 
1572  | 0  |                            : static_cast<int>(strlen(pszArg));  | 
1573  | 0  |     for (int iType = 0; iType <= static_cast<int>(OFTMaxType); iType++)  | 
1574  | 0  |     { | 
1575  | 0  |         const char *pszFieldTypeName =  | 
1576  | 0  |             OGRFieldDefn::GetFieldTypeName(static_cast<OGRFieldType>(iType));  | 
1577  | 0  |         if (EQUALN(pszArg, pszFieldTypeName, nLengthBeforeParenthesis) &&  | 
1578  | 0  |             pszFieldTypeName[nLengthBeforeParenthesis] == '\0')  | 
1579  | 0  |         { | 
1580  | 0  |             if (pszOpenParenthesis != nullptr)  | 
1581  | 0  |             { | 
1582  | 0  |                 *pnSubFieldType = -1;  | 
1583  | 0  |                 CPLString osArgSubType = pszOpenParenthesis + 1;  | 
1584  | 0  |                 if (!osArgSubType.empty() && osArgSubType.back() == ')')  | 
1585  | 0  |                     osArgSubType.pop_back();  | 
1586  | 0  |                 for (int iSubType = 0;  | 
1587  | 0  |                      iSubType <= static_cast<int>(OFSTMaxSubType); iSubType++)  | 
1588  | 0  |                 { | 
1589  | 0  |                     const char *pszFieldSubTypeName =  | 
1590  | 0  |                         OGRFieldDefn::GetFieldSubTypeName(  | 
1591  | 0  |                             static_cast<OGRFieldSubType>(iSubType));  | 
1592  | 0  |                     if (EQUAL(pszFieldSubTypeName, osArgSubType))  | 
1593  | 0  |                     { | 
1594  | 0  |                         *pnSubFieldType = iSubType;  | 
1595  | 0  |                         break;  | 
1596  | 0  |                     }  | 
1597  | 0  |                 }  | 
1598  | 0  |             }  | 
1599  | 0  |             return iType;  | 
1600  | 0  |         }  | 
1601  | 0  |     }  | 
1602  | 0  |     return -1;  | 
1603  | 0  | }  | 
1604  |  |  | 
1605  |  | /************************************************************************/  | 
1606  |  | /*                           IsFieldType()                              */  | 
1607  |  | /************************************************************************/  | 
1608  |  |  | 
1609  |  | static bool IsFieldType(const char *pszArg)  | 
1610  | 0  | { | 
1611  | 0  |     int iSubType;  | 
1612  | 0  |     return GetFieldType(pszArg, &iSubType) >= 0 && iSubType >= 0;  | 
1613  | 0  | }  | 
1614  |  |  | 
1615  |  | class GDALVectorTranslateWrappedDataset : public GDALDataset  | 
1616  |  | { | 
1617  |  |     std::unique_ptr<GDALDriver> m_poDriverToFree{}; | 
1618  |  |     GDALDataset *m_poBase = nullptr;  | 
1619  |  |     OGRSpatialReference *m_poOutputSRS = nullptr;  | 
1620  |  |     const bool m_bTransform = false;  | 
1621  |  |  | 
1622  |  |     std::vector<std::unique_ptr<OGRLayer>> m_apoLayers{}; | 
1623  |  |     std::vector<std::unique_ptr<OGRLayer>> m_apoHiddenLayers{}; | 
1624  |  |  | 
1625  |  |     GDALVectorTranslateWrappedDataset(GDALDataset *poBase,  | 
1626  |  |                                       OGRSpatialReference *poOutputSRS,  | 
1627  |  |                                       bool bTransform);  | 
1628  |  |  | 
1629  |  |     CPL_DISALLOW_COPY_ASSIGN(GDALVectorTranslateWrappedDataset)  | 
1630  |  |  | 
1631  |  |   public:  | 
1632  |  |     virtual int GetLayerCount() override  | 
1633  | 0  |     { | 
1634  | 0  |         return static_cast<int>(m_apoLayers.size());  | 
1635  | 0  |     }  | 
1636  |  |  | 
1637  |  |     virtual OGRLayer *GetLayer(int nIdx) override;  | 
1638  |  |     virtual OGRLayer *GetLayerByName(const char *pszName) override;  | 
1639  |  |  | 
1640  |  |     virtual OGRLayer *ExecuteSQL(const char *pszStatement,  | 
1641  |  |                                  OGRGeometry *poSpatialFilter,  | 
1642  |  |                                  const char *pszDialect) override;  | 
1643  |  |     virtual void ReleaseResultSet(OGRLayer *poResultsSet) override;  | 
1644  |  |  | 
1645  |  |     static std::unique_ptr<GDALVectorTranslateWrappedDataset>  | 
1646  |  |     New(GDALDataset *poBase, OGRSpatialReference *poOutputSRS, bool bTransform);  | 
1647  |  | };  | 
1648  |  |  | 
1649  |  | class GDALVectorTranslateWrappedLayer : public OGRLayerDecorator  | 
1650  |  | { | 
1651  |  |     std::vector<std::unique_ptr<OGRCoordinateTransformation>> m_apoCT{}; | 
1652  |  |     OGRFeatureDefn *m_poFDefn = nullptr;  | 
1653  |  |  | 
1654  |  |     GDALVectorTranslateWrappedLayer(OGRLayer *poBaseLayer, bool bOwnBaseLayer);  | 
1655  |  |     std::unique_ptr<OGRFeature>  | 
1656  |  |     TranslateFeature(std::unique_ptr<OGRFeature> poSrcFeat);  | 
1657  |  |  | 
1658  |  |     CPL_DISALLOW_COPY_ASSIGN(GDALVectorTranslateWrappedLayer)  | 
1659  |  |  | 
1660  |  |   public:  | 
1661  |  |     virtual ~GDALVectorTranslateWrappedLayer();  | 
1662  |  |  | 
1663  |  |     virtual OGRFeatureDefn *GetLayerDefn() override  | 
1664  | 0  |     { | 
1665  | 0  |         return m_poFDefn;  | 
1666  | 0  |     }  | 
1667  |  |  | 
1668  |  |     virtual OGRFeature *GetNextFeature() override;  | 
1669  |  |     virtual OGRFeature *GetFeature(GIntBig nFID) override;  | 
1670  |  |  | 
1671  |  |     static std::unique_ptr<GDALVectorTranslateWrappedLayer>  | 
1672  |  |     New(OGRLayer *poBaseLayer, bool bOwnBaseLayer,  | 
1673  |  |         OGRSpatialReference *poOutputSRS, bool bTransform);  | 
1674  |  | };  | 
1675  |  |  | 
1676  |  | GDALVectorTranslateWrappedLayer::GDALVectorTranslateWrappedLayer(  | 
1677  |  |     OGRLayer *poBaseLayer, bool bOwnBaseLayer)  | 
1678  | 0  |     : OGRLayerDecorator(poBaseLayer, bOwnBaseLayer),  | 
1679  | 0  |       m_apoCT(poBaseLayer->GetLayerDefn()->GetGeomFieldCount())  | 
1680  | 0  | { | 
1681  | 0  | } Unexecuted instantiation: GDALVectorTranslateWrappedLayer::GDALVectorTranslateWrappedLayer(OGRLayer*, bool) Unexecuted instantiation: GDALVectorTranslateWrappedLayer::GDALVectorTranslateWrappedLayer(OGRLayer*, bool)  | 
1682  |  |  | 
1683  |  | std::unique_ptr<GDALVectorTranslateWrappedLayer>  | 
1684  |  | GDALVectorTranslateWrappedLayer::New(OGRLayer *poBaseLayer, bool bOwnBaseLayer,  | 
1685  |  |                                      OGRSpatialReference *poOutputSRS,  | 
1686  |  |                                      bool bTransform)  | 
1687  | 0  | { | 
1688  | 0  |     auto poNew = std::unique_ptr<GDALVectorTranslateWrappedLayer>(  | 
1689  | 0  |         new GDALVectorTranslateWrappedLayer(poBaseLayer, bOwnBaseLayer));  | 
1690  | 0  |     poNew->m_poFDefn = poBaseLayer->GetLayerDefn()->Clone();  | 
1691  | 0  |     poNew->m_poFDefn->Reference();  | 
1692  | 0  |     if (!poOutputSRS)  | 
1693  | 0  |         return poNew;  | 
1694  |  |  | 
1695  | 0  |     for (int i = 0; i < poNew->m_poFDefn->GetGeomFieldCount(); i++)  | 
1696  | 0  |     { | 
1697  | 0  |         if (bTransform)  | 
1698  | 0  |         { | 
1699  | 0  |             const OGRSpatialReference *poSourceSRS = poBaseLayer->GetLayerDefn()  | 
1700  | 0  |                                                          ->GetGeomFieldDefn(i)  | 
1701  | 0  |                                                          ->GetSpatialRef();  | 
1702  | 0  |             if (poSourceSRS == nullptr)  | 
1703  | 0  |             { | 
1704  | 0  |                 CPLError(CE_Failure, CPLE_AppDefined,  | 
1705  | 0  |                          "Layer %s has no source SRS for geometry field %s",  | 
1706  | 0  |                          poBaseLayer->GetName(),  | 
1707  | 0  |                          poBaseLayer->GetLayerDefn()  | 
1708  | 0  |                              ->GetGeomFieldDefn(i)  | 
1709  | 0  |                              ->GetNameRef());  | 
1710  | 0  |                 return nullptr;  | 
1711  | 0  |             }  | 
1712  | 0  |             else  | 
1713  | 0  |             { | 
1714  | 0  |                 poNew->m_apoCT[i] =  | 
1715  | 0  |                     std::unique_ptr<OGRCoordinateTransformation>(  | 
1716  | 0  |                         OGRCreateCoordinateTransformation(poSourceSRS,  | 
1717  | 0  |                                                           poOutputSRS));  | 
1718  | 0  |                 if (poNew->m_apoCT[i] == nullptr)  | 
1719  | 0  |                 { | 
1720  | 0  |                     CPLError(CE_Failure, CPLE_AppDefined,  | 
1721  | 0  |                              "Failed to create coordinate transformation "  | 
1722  | 0  |                              "between the\n"  | 
1723  | 0  |                              "following coordinate systems.  This may be "  | 
1724  | 0  |                              "because they\n"  | 
1725  | 0  |                              "are not transformable.");  | 
1726  |  | 
  | 
1727  | 0  |                     char *pszWKT = nullptr;  | 
1728  | 0  |                     poSourceSRS->exportToPrettyWkt(&pszWKT, FALSE);  | 
1729  | 0  |                     CPLError(CE_Failure, CPLE_AppDefined, "Source:\n%s",  | 
1730  | 0  |                              pszWKT);  | 
1731  | 0  |                     CPLFree(pszWKT);  | 
1732  |  | 
  | 
1733  | 0  |                     poOutputSRS->exportToPrettyWkt(&pszWKT, FALSE);  | 
1734  | 0  |                     CPLError(CE_Failure, CPLE_AppDefined, "Target:\n%s",  | 
1735  | 0  |                              pszWKT);  | 
1736  | 0  |                     CPLFree(pszWKT);  | 
1737  |  | 
  | 
1738  | 0  |                     return nullptr;  | 
1739  | 0  |                 }  | 
1740  | 0  |             }  | 
1741  | 0  |         }  | 
1742  | 0  |         poNew->m_poFDefn->GetGeomFieldDefn(i)->SetSpatialRef(poOutputSRS);  | 
1743  | 0  |     }  | 
1744  |  |  | 
1745  | 0  |     return poNew;  | 
1746  | 0  | }  | 
1747  |  |  | 
1748  |  | GDALVectorTranslateWrappedLayer::~GDALVectorTranslateWrappedLayer()  | 
1749  | 0  | { | 
1750  | 0  |     if (m_poFDefn)  | 
1751  | 0  |         m_poFDefn->Release();  | 
1752  | 0  | }  | 
1753  |  |  | 
1754  |  | OGRFeature *GDALVectorTranslateWrappedLayer::GetNextFeature()  | 
1755  | 0  | { | 
1756  | 0  |     return TranslateFeature(  | 
1757  | 0  |                std::unique_ptr<OGRFeature>(OGRLayerDecorator::GetNextFeature()))  | 
1758  | 0  |         .release();  | 
1759  | 0  | }  | 
1760  |  |  | 
1761  |  | OGRFeature *GDALVectorTranslateWrappedLayer::GetFeature(GIntBig nFID)  | 
1762  | 0  | { | 
1763  | 0  |     return TranslateFeature(  | 
1764  | 0  |                std::unique_ptr<OGRFeature>(OGRLayerDecorator::GetFeature(nFID)))  | 
1765  | 0  |         .release();  | 
1766  | 0  | }  | 
1767  |  |  | 
1768  |  | std::unique_ptr<OGRFeature> GDALVectorTranslateWrappedLayer::TranslateFeature(  | 
1769  |  |     std::unique_ptr<OGRFeature> poSrcFeat)  | 
1770  | 0  | { | 
1771  | 0  |     if (poSrcFeat == nullptr)  | 
1772  | 0  |         return nullptr;  | 
1773  | 0  |     auto poNewFeat = std::make_unique<OGRFeature>(m_poFDefn);  | 
1774  | 0  |     poNewFeat->SetFrom(poSrcFeat.get());  | 
1775  | 0  |     poNewFeat->SetFID(poSrcFeat->GetFID());  | 
1776  | 0  |     for (int i = 0; i < poNewFeat->GetGeomFieldCount(); i++)  | 
1777  | 0  |     { | 
1778  | 0  |         OGRGeometry *poGeom = poNewFeat->GetGeomFieldRef(i);  | 
1779  | 0  |         if (poGeom)  | 
1780  | 0  |         { | 
1781  | 0  |             if (m_apoCT[i])  | 
1782  | 0  |                 poGeom->transform(m_apoCT[i].get());  | 
1783  | 0  |             poGeom->assignSpatialReference(  | 
1784  | 0  |                 m_poFDefn->GetGeomFieldDefn(i)->GetSpatialRef());  | 
1785  | 0  |         }  | 
1786  | 0  |     }  | 
1787  | 0  |     return poNewFeat;  | 
1788  | 0  | }  | 
1789  |  |  | 
1790  |  | GDALVectorTranslateWrappedDataset::GDALVectorTranslateWrappedDataset(  | 
1791  |  |     GDALDataset *poBase, OGRSpatialReference *poOutputSRS, bool bTransform)  | 
1792  | 0  |     : m_poBase(poBase), m_poOutputSRS(poOutputSRS), m_bTransform(bTransform)  | 
1793  | 0  | { | 
1794  | 0  |     SetDescription(poBase->GetDescription());  | 
1795  | 0  |     if (poBase->GetDriver())  | 
1796  | 0  |     { | 
1797  | 0  |         poDriver = new GDALDriver();  | 
1798  | 0  |         poDriver->SetDescription(poBase->GetDriver()->GetDescription());  | 
1799  | 0  |         m_poDriverToFree.reset(poDriver);  | 
1800  | 0  |     }  | 
1801  | 0  | }  | 
1802  |  |  | 
1803  |  | std::unique_ptr<GDALVectorTranslateWrappedDataset>  | 
1804  |  | GDALVectorTranslateWrappedDataset::New(GDALDataset *poBase,  | 
1805  |  |                                        OGRSpatialReference *poOutputSRS,  | 
1806  |  |                                        bool bTransform)  | 
1807  | 0  | { | 
1808  | 0  |     auto poNew = std::unique_ptr<GDALVectorTranslateWrappedDataset>(  | 
1809  | 0  |         new GDALVectorTranslateWrappedDataset(poBase, poOutputSRS, bTransform));  | 
1810  | 0  |     for (int i = 0; i < poBase->GetLayerCount(); i++)  | 
1811  | 0  |     { | 
1812  | 0  |         auto poLayer = GDALVectorTranslateWrappedLayer::New(  | 
1813  | 0  |             poBase->GetLayer(i), /* bOwnBaseLayer = */ false, poOutputSRS,  | 
1814  | 0  |             bTransform);  | 
1815  | 0  |         if (poLayer == nullptr)  | 
1816  | 0  |         { | 
1817  | 0  |             return nullptr;  | 
1818  | 0  |         }  | 
1819  | 0  |         poNew->m_apoLayers.push_back(std::move(poLayer));  | 
1820  | 0  |     }  | 
1821  | 0  |     return poNew;  | 
1822  | 0  | }  | 
1823  |  |  | 
1824  |  | OGRLayer *GDALVectorTranslateWrappedDataset::GetLayer(int i)  | 
1825  | 0  | { | 
1826  | 0  |     if (i < 0 || i >= static_cast<int>(m_apoLayers.size()))  | 
1827  | 0  |         return nullptr;  | 
1828  | 0  |     return m_apoLayers[i].get();  | 
1829  | 0  | }  | 
1830  |  |  | 
1831  |  | OGRLayer *GDALVectorTranslateWrappedDataset::GetLayerByName(const char *pszName)  | 
1832  | 0  | { | 
1833  | 0  |     for (const auto &poLayer : m_apoLayers)  | 
1834  | 0  |     { | 
1835  | 0  |         if (strcmp(poLayer->GetName(), pszName) == 0)  | 
1836  | 0  |             return poLayer.get();  | 
1837  | 0  |     }  | 
1838  | 0  |     for (const auto &poLayer : m_apoHiddenLayers)  | 
1839  | 0  |     { | 
1840  | 0  |         if (strcmp(poLayer->GetName(), pszName) == 0)  | 
1841  | 0  |             return poLayer.get();  | 
1842  | 0  |     }  | 
1843  | 0  |     for (const auto &poLayer : m_apoLayers)  | 
1844  | 0  |     { | 
1845  | 0  |         if (EQUAL(poLayer->GetName(), pszName))  | 
1846  | 0  |             return poLayer.get();  | 
1847  | 0  |     }  | 
1848  | 0  |     for (const auto &poLayer : m_apoHiddenLayers)  | 
1849  | 0  |     { | 
1850  | 0  |         if (EQUAL(poLayer->GetName(), pszName))  | 
1851  | 0  |             return poLayer.get();  | 
1852  | 0  |     }  | 
1853  |  |  | 
1854  | 0  |     OGRLayer *poLayer = m_poBase->GetLayerByName(pszName);  | 
1855  | 0  |     if (poLayer == nullptr)  | 
1856  | 0  |         return nullptr;  | 
1857  |  |  | 
1858  | 0  |     auto poNewLayer = GDALVectorTranslateWrappedLayer::New(  | 
1859  | 0  |         poLayer, /* bOwnBaseLayer = */ false, m_poOutputSRS, m_bTransform);  | 
1860  | 0  |     if (poNewLayer == nullptr)  | 
1861  | 0  |         return nullptr;  | 
1862  |  |  | 
1863  |  |     // Replicate source dataset behavior: if the fact of calling  | 
1864  |  |     // GetLayerByName() on a initially hidden layer makes it visible through  | 
1865  |  |     // GetLayerCount()/GetLayer(), do the same. Otherwise we are going to  | 
1866  |  |     // maintain it hidden as well.  | 
1867  | 0  |     for (int i = 0; i < m_poBase->GetLayerCount(); i++)  | 
1868  | 0  |     { | 
1869  | 0  |         if (m_poBase->GetLayer(i) == poLayer)  | 
1870  | 0  |         { | 
1871  | 0  |             m_apoLayers.push_back(std::move(poNewLayer));  | 
1872  | 0  |             return m_apoLayers.back().get();  | 
1873  | 0  |         }  | 
1874  | 0  |     }  | 
1875  | 0  |     m_apoHiddenLayers.push_back(std::move(poNewLayer));  | 
1876  | 0  |     return m_apoHiddenLayers.back().get();  | 
1877  | 0  | }  | 
1878  |  |  | 
1879  |  | OGRLayer *  | 
1880  |  | GDALVectorTranslateWrappedDataset::ExecuteSQL(const char *pszStatement,  | 
1881  |  |                                               OGRGeometry *poSpatialFilter,  | 
1882  |  |                                               const char *pszDialect)  | 
1883  | 0  | { | 
1884  | 0  |     OGRLayer *poLayer =  | 
1885  | 0  |         m_poBase->ExecuteSQL(pszStatement, poSpatialFilter, pszDialect);  | 
1886  | 0  |     if (poLayer == nullptr)  | 
1887  | 0  |         return nullptr;  | 
1888  | 0  |     return GDALVectorTranslateWrappedLayer::New(  | 
1889  | 0  |                poLayer, /* bOwnBaseLayer = */ true, m_poOutputSRS, m_bTransform)  | 
1890  | 0  |         .release();  | 
1891  | 0  | }  | 
1892  |  |  | 
1893  |  | void GDALVectorTranslateWrappedDataset::ReleaseResultSet(OGRLayer *poResultsSet)  | 
1894  | 0  | { | 
1895  | 0  |     delete poResultsSet;  | 
1896  | 0  | }  | 
1897  |  |  | 
1898  |  | /************************************************************************/  | 
1899  |  | /*                     OGR2OGRSpatialReferenceHolder                    */  | 
1900  |  | /************************************************************************/  | 
1901  |  |  | 
1902  |  | class OGR2OGRSpatialReferenceHolder  | 
1903  |  | { | 
1904  |  |     OGRSpatialReference *m_poSRS = nullptr;  | 
1905  |  |  | 
1906  |  |     CPL_DISALLOW_COPY_ASSIGN(OGR2OGRSpatialReferenceHolder)  | 
1907  |  |  | 
1908  |  |   public:  | 
1909  | 0  |     OGR2OGRSpatialReferenceHolder() = default;  | 
1910  |  |  | 
1911  |  |     ~OGR2OGRSpatialReferenceHolder()  | 
1912  | 0  |     { | 
1913  | 0  |         if (m_poSRS)  | 
1914  | 0  |             m_poSRS->Release();  | 
1915  | 0  |     }  | 
1916  |  |  | 
1917  |  |     void assignNoRefIncrease(OGRSpatialReference *poSRS)  | 
1918  | 0  |     { | 
1919  | 0  |         CPLAssert(m_poSRS == nullptr);  | 
1920  | 0  |         m_poSRS = poSRS;  | 
1921  | 0  |     }  | 
1922  |  |  | 
1923  |  |     OGRSpatialReference *get()  | 
1924  | 0  |     { | 
1925  | 0  |         return m_poSRS;  | 
1926  | 0  |     }  | 
1927  |  | };  | 
1928  |  |  | 
1929  |  | /************************************************************************/  | 
1930  |  | /*                     GDALVectorTranslateCreateCopy()                  */  | 
1931  |  | /************************************************************************/  | 
1932  |  |  | 
1933  |  | static GDALDataset *  | 
1934  |  | GDALVectorTranslateCreateCopy(GDALDriver *poDriver, const char *pszDest,  | 
1935  |  |                               GDALDataset *poDS,  | 
1936  |  |                               const GDALVectorTranslateOptions *psOptions)  | 
1937  | 0  | { | 
1938  | 0  |     const char *const szErrorMsg = "%s not supported by this output driver";  | 
1939  |  | 
  | 
1940  | 0  |     if (psOptions->bSkipFailures)  | 
1941  | 0  |     { | 
1942  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-skipfailures");  | 
1943  | 0  |         return nullptr;  | 
1944  | 0  |     }  | 
1945  | 0  |     if (psOptions->nLayerTransaction >= 0)  | 
1946  | 0  |     { | 
1947  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg,  | 
1948  | 0  |                  "-lyr_transaction or -ds_transaction");  | 
1949  | 0  |         return nullptr;  | 
1950  | 0  |     }  | 
1951  | 0  |     if (psOptions->nFIDToFetch >= 0)  | 
1952  | 0  |     { | 
1953  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-fid");  | 
1954  | 0  |         return nullptr;  | 
1955  | 0  |     }  | 
1956  | 0  |     if (!psOptions->aosLCO.empty())  | 
1957  | 0  |     { | 
1958  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-lco");  | 
1959  | 0  |         return nullptr;  | 
1960  | 0  |     }  | 
1961  | 0  |     if (psOptions->bAddMissingFields)  | 
1962  | 0  |     { | 
1963  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-addfields");  | 
1964  | 0  |         return nullptr;  | 
1965  | 0  |     }  | 
1966  | 0  |     if (!psOptions->osSourceSRSDef.empty())  | 
1967  | 0  |     { | 
1968  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-s_srs");  | 
1969  | 0  |         return nullptr;  | 
1970  | 0  |     }  | 
1971  | 0  |     if (!psOptions->bExactFieldNameMatch)  | 
1972  | 0  |     { | 
1973  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg,  | 
1974  | 0  |                  "-relaxedFieldNameMatch");  | 
1975  | 0  |         return nullptr;  | 
1976  | 0  |     }  | 
1977  | 0  |     if (!psOptions->osNewLayerName.empty())  | 
1978  | 0  |     { | 
1979  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-nln");  | 
1980  | 0  |         return nullptr;  | 
1981  | 0  |     }  | 
1982  | 0  |     if (psOptions->bSelFieldsSet)  | 
1983  | 0  |     { | 
1984  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-select");  | 
1985  | 0  |         return nullptr;  | 
1986  | 0  |     }  | 
1987  | 0  |     if (!psOptions->osSQLStatement.empty())  | 
1988  | 0  |     { | 
1989  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-sql");  | 
1990  | 0  |         return nullptr;  | 
1991  | 0  |     }  | 
1992  | 0  |     if (!psOptions->osDialect.empty())  | 
1993  | 0  |     { | 
1994  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-dialect");  | 
1995  | 0  |         return nullptr;  | 
1996  | 0  |     }  | 
1997  | 0  |     if (psOptions->eGType != GEOMTYPE_UNCHANGED ||  | 
1998  | 0  |         psOptions->eGeomTypeConversion != GTC_DEFAULT)  | 
1999  | 0  |     { | 
2000  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-nlt");  | 
2001  | 0  |         return nullptr;  | 
2002  | 0  |     }  | 
2003  | 0  |     if (!psOptions->aosFieldTypesToString.empty())  | 
2004  | 0  |     { | 
2005  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg,  | 
2006  | 0  |                  "-fieldTypeToString");  | 
2007  | 0  |         return nullptr;  | 
2008  | 0  |     }  | 
2009  | 0  |     if (!psOptions->aosMapFieldType.empty())  | 
2010  | 0  |     { | 
2011  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-mapFieldType");  | 
2012  | 0  |         return nullptr;  | 
2013  | 0  |     }  | 
2014  | 0  |     if (psOptions->bUnsetFieldWidth)  | 
2015  | 0  |     { | 
2016  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-unsetFieldWidth");  | 
2017  | 0  |         return nullptr;  | 
2018  | 0  |     }  | 
2019  | 0  |     if (psOptions->bWrapDateline)  | 
2020  | 0  |     { | 
2021  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-wrapdateline");  | 
2022  | 0  |         return nullptr;  | 
2023  | 0  |     }  | 
2024  | 0  |     if (psOptions->bClipSrc)  | 
2025  | 0  |     { | 
2026  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipsrc");  | 
2027  | 0  |         return nullptr;  | 
2028  | 0  |     }  | 
2029  | 0  |     if (!psOptions->osClipSrcSQL.empty())  | 
2030  | 0  |     { | 
2031  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipsrcsql");  | 
2032  | 0  |         return nullptr;  | 
2033  | 0  |     }  | 
2034  | 0  |     if (!psOptions->osClipSrcLayer.empty())  | 
2035  | 0  |     { | 
2036  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipsrclayer");  | 
2037  | 0  |         return nullptr;  | 
2038  | 0  |     }  | 
2039  | 0  |     if (!psOptions->osClipSrcWhere.empty())  | 
2040  | 0  |     { | 
2041  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipsrcwhere");  | 
2042  | 0  |         return nullptr;  | 
2043  | 0  |     }  | 
2044  | 0  |     if (!psOptions->osClipDstDS.empty() || psOptions->poClipDst)  | 
2045  | 0  |     { | 
2046  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipdst");  | 
2047  | 0  |         return nullptr;  | 
2048  | 0  |     }  | 
2049  | 0  |     if (!psOptions->osClipDstSQL.empty())  | 
2050  | 0  |     { | 
2051  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipdstsql");  | 
2052  | 0  |         return nullptr;  | 
2053  | 0  |     }  | 
2054  | 0  |     if (!psOptions->osClipDstLayer.empty())  | 
2055  | 0  |     { | 
2056  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipdstlayer");  | 
2057  | 0  |         return nullptr;  | 
2058  | 0  |     }  | 
2059  | 0  |     if (!psOptions->osClipDstWhere.empty())  | 
2060  | 0  |     { | 
2061  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipdstwhere");  | 
2062  | 0  |         return nullptr;  | 
2063  | 0  |     }  | 
2064  | 0  |     if (psOptions->bSplitListFields)  | 
2065  | 0  |     { | 
2066  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-splitlistfields");  | 
2067  | 0  |         return nullptr;  | 
2068  | 0  |     }  | 
2069  | 0  |     if (psOptions->nMaxSplitListSubFields >= 0)  | 
2070  | 0  |     { | 
2071  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-maxsubfields");  | 
2072  | 0  |         return nullptr;  | 
2073  | 0  |     }  | 
2074  | 0  |     if (psOptions->bExplodeCollections)  | 
2075  | 0  |     { | 
2076  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg,  | 
2077  | 0  |                  "-explodecollections");  | 
2078  | 0  |         return nullptr;  | 
2079  | 0  |     }  | 
2080  | 0  |     if (!psOptions->osZField.empty())  | 
2081  | 0  |     { | 
2082  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-zfield");  | 
2083  | 0  |         return nullptr;  | 
2084  | 0  |     }  | 
2085  | 0  |     if (psOptions->oGCPs.nGCPCount)  | 
2086  | 0  |     { | 
2087  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-gcp");  | 
2088  | 0  |         return nullptr;  | 
2089  | 0  |     }  | 
2090  | 0  |     if (!psOptions->aosFieldMap.empty())  | 
2091  | 0  |     { | 
2092  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-fieldmap");  | 
2093  | 0  |         return nullptr;  | 
2094  | 0  |     }  | 
2095  | 0  |     if (psOptions->bForceNullable)  | 
2096  | 0  |     { | 
2097  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-forceNullable");  | 
2098  | 0  |         return nullptr;  | 
2099  | 0  |     }  | 
2100  | 0  |     if (psOptions->bResolveDomains)  | 
2101  | 0  |     { | 
2102  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-forceNullable");  | 
2103  | 0  |         return nullptr;  | 
2104  | 0  |     }  | 
2105  | 0  |     if (psOptions->bEmptyStrAsNull)  | 
2106  | 0  |     { | 
2107  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-emptyStrAsNull");  | 
2108  | 0  |         return nullptr;  | 
2109  | 0  |     }  | 
2110  | 0  |     if (psOptions->bUnsetDefault)  | 
2111  | 0  |     { | 
2112  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-unsetDefault");  | 
2113  | 0  |         return nullptr;  | 
2114  | 0  |     }  | 
2115  | 0  |     if (psOptions->bUnsetFid)  | 
2116  | 0  |     { | 
2117  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-unsetFid");  | 
2118  | 0  |         return nullptr;  | 
2119  | 0  |     }  | 
2120  | 0  |     if (!psOptions->bCopyMD)  | 
2121  | 0  |     { | 
2122  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-nomd");  | 
2123  | 0  |         return nullptr;  | 
2124  | 0  |     }  | 
2125  | 0  |     if (!psOptions->bNativeData)  | 
2126  | 0  |     { | 
2127  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-noNativeData");  | 
2128  | 0  |         return nullptr;  | 
2129  | 0  |     }  | 
2130  | 0  |     if (psOptions->nLimit >= 0)  | 
2131  | 0  |     { | 
2132  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-limit");  | 
2133  | 0  |         return nullptr;  | 
2134  | 0  |     }  | 
2135  | 0  |     if (!psOptions->aosMetadataOptions.empty())  | 
2136  | 0  |     { | 
2137  | 0  |         CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-mo");  | 
2138  | 0  |         return nullptr;  | 
2139  | 0  |     }  | 
2140  |  |  | 
2141  | 0  |     GDALDataset *poWrkSrcDS = poDS;  | 
2142  | 0  |     std::unique_ptr<GDALDataset> poWrkSrcDSToFree;  | 
2143  | 0  |     OGR2OGRSpatialReferenceHolder oOutputSRSHolder;  | 
2144  |  | 
  | 
2145  | 0  |     if (!psOptions->osOutputSRSDef.empty())  | 
2146  | 0  |     { | 
2147  | 0  |         oOutputSRSHolder.assignNoRefIncrease(new OGRSpatialReference());  | 
2148  | 0  |         oOutputSRSHolder.get()->SetAxisMappingStrategy(  | 
2149  | 0  |             OAMS_TRADITIONAL_GIS_ORDER);  | 
2150  | 0  |         if (oOutputSRSHolder.get()->SetFromUserInput(  | 
2151  | 0  |                 psOptions->osOutputSRSDef.c_str()) != OGRERR_NONE)  | 
2152  | 0  |         { | 
2153  | 0  |             CPLError(CE_Failure, CPLE_AppDefined,  | 
2154  | 0  |                      "Failed to process SRS definition: %s",  | 
2155  | 0  |                      psOptions->osOutputSRSDef.c_str());  | 
2156  | 0  |             return nullptr;  | 
2157  | 0  |         }  | 
2158  | 0  |         oOutputSRSHolder.get()->SetCoordinateEpoch(  | 
2159  | 0  |             psOptions->dfOutputCoordinateEpoch);  | 
2160  |  | 
  | 
2161  | 0  |         poWrkSrcDSToFree = GDALVectorTranslateWrappedDataset::New(  | 
2162  | 0  |             poDS, oOutputSRSHolder.get(), psOptions->bTransform);  | 
2163  | 0  |         if (poWrkSrcDSToFree == nullptr)  | 
2164  | 0  |             return nullptr;  | 
2165  | 0  |         poWrkSrcDS = poWrkSrcDSToFree.get();  | 
2166  | 0  |     }  | 
2167  |  |  | 
2168  | 0  |     if (!psOptions->osWHERE.empty())  | 
2169  | 0  |     { | 
2170  |  |         // Hack for GMLAS driver  | 
2171  | 0  |         if (EQUAL(poDriver->GetDescription(), "GMLAS"))  | 
2172  | 0  |         { | 
2173  | 0  |             if (psOptions->aosLayers.empty())  | 
2174  | 0  |             { | 
2175  | 0  |                 CPLError(CE_Failure, CPLE_NotSupported,  | 
2176  | 0  |                          "-where not supported by this output driver "  | 
2177  | 0  |                          "without explicit layer name(s)");  | 
2178  | 0  |                 return nullptr;  | 
2179  | 0  |             }  | 
2180  | 0  |             else  | 
2181  | 0  |             { | 
2182  | 0  |                 for (const char *pszLayer : psOptions->aosLayers)  | 
2183  | 0  |                 { | 
2184  | 0  |                     OGRLayer *poSrcLayer = poDS->GetLayerByName(pszLayer);  | 
2185  | 0  |                     if (poSrcLayer != nullptr)  | 
2186  | 0  |                     { | 
2187  | 0  |                         poSrcLayer->SetAttributeFilter(  | 
2188  | 0  |                             psOptions->osWHERE.c_str());  | 
2189  | 0  |                     }  | 
2190  | 0  |                 }  | 
2191  | 0  |             }  | 
2192  | 0  |         }  | 
2193  | 0  |         else  | 
2194  | 0  |         { | 
2195  | 0  |             CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-where");  | 
2196  | 0  |             return nullptr;  | 
2197  | 0  |         }  | 
2198  | 0  |     }  | 
2199  |  |  | 
2200  | 0  |     if (psOptions->poSpatialFilter)  | 
2201  | 0  |     { | 
2202  | 0  |         for (int i = 0; i < poWrkSrcDS->GetLayerCount(); ++i)  | 
2203  | 0  |         { | 
2204  | 0  |             OGRLayer *poSrcLayer = poWrkSrcDS->GetLayer(i);  | 
2205  | 0  |             if (poSrcLayer &&  | 
2206  | 0  |                 poSrcLayer->GetLayerDefn()->GetGeomFieldCount() > 0 &&  | 
2207  | 0  |                 (psOptions->aosLayers.empty() ||  | 
2208  | 0  |                  psOptions->aosLayers.FindString(poSrcLayer->GetName()) >= 0))  | 
2209  | 0  |             { | 
2210  | 0  |                 if (psOptions->bGeomFieldSet)  | 
2211  | 0  |                 { | 
2212  | 0  |                     const int iGeomField =  | 
2213  | 0  |                         poSrcLayer->GetLayerDefn()->GetGeomFieldIndex(  | 
2214  | 0  |                             psOptions->osGeomField.c_str());  | 
2215  | 0  |                     if (iGeomField >= 0)  | 
2216  | 0  |                         poSrcLayer->SetSpatialFilter(  | 
2217  | 0  |                             iGeomField, psOptions->poSpatialFilter.get());  | 
2218  | 0  |                     else  | 
2219  | 0  |                         CPLError(CE_Warning, CPLE_AppDefined,  | 
2220  | 0  |                                  "Cannot find geometry field %s in layer %s. "  | 
2221  | 0  |                                  "Applying to first geometry field",  | 
2222  | 0  |                                  psOptions->osGeomField.c_str(),  | 
2223  | 0  |                                  poSrcLayer->GetName());  | 
2224  | 0  |                 }  | 
2225  | 0  |                 else  | 
2226  | 0  |                 { | 
2227  | 0  |                     poSrcLayer->SetSpatialFilter(  | 
2228  | 0  |                         psOptions->poSpatialFilter.get());  | 
2229  | 0  |                 }  | 
2230  | 0  |             }  | 
2231  | 0  |         }  | 
2232  | 0  |     }  | 
2233  |  | 
  | 
2234  | 0  |     CPLStringList aosDSCO(psOptions->aosDSCO);  | 
2235  | 0  |     if (!psOptions->aosLayers.empty())  | 
2236  | 0  |     { | 
2237  |  |         // Hack for GMLAS driver  | 
2238  | 0  |         if (EQUAL(poDriver->GetDescription(), "GMLAS"))  | 
2239  | 0  |         { | 
2240  | 0  |             CPLString osLayers;  | 
2241  | 0  |             for (const char *pszLayer : psOptions->aosLayers)  | 
2242  | 0  |             { | 
2243  | 0  |                 if (!osLayers.empty())  | 
2244  | 0  |                     osLayers += ",";  | 
2245  | 0  |                 osLayers += pszLayer;  | 
2246  | 0  |             }  | 
2247  | 0  |             aosDSCO.SetNameValue("LAYERS", osLayers); | 
2248  | 0  |         }  | 
2249  | 0  |         else  | 
2250  | 0  |         { | 
2251  | 0  |             CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg,  | 
2252  | 0  |                      "Specifying layers");  | 
2253  | 0  |             return nullptr;  | 
2254  | 0  |         }  | 
2255  | 0  |     }  | 
2256  |  |  | 
2257  |  |     // Hack for GMLAS driver (this speed up deletion by avoiding the GML  | 
2258  |  |     // driver to try parsing a pre-existing file). Could be potentially  | 
2259  |  |     // removed if the GML driver implemented fast dataset opening (ie  | 
2260  |  |     // without parsing) and GetFileList()  | 
2261  | 0  |     if (EQUAL(poDriver->GetDescription(), "GMLAS"))  | 
2262  | 0  |     { | 
2263  | 0  |         GDALDriverH hIdentifyingDriver = GDALIdentifyDriver(pszDest, nullptr);  | 
2264  | 0  |         if (hIdentifyingDriver != nullptr &&  | 
2265  | 0  |             EQUAL(GDALGetDescription(hIdentifyingDriver), "GML"))  | 
2266  | 0  |         { | 
2267  | 0  |             VSIUnlink(pszDest);  | 
2268  | 0  |             VSIUnlink(CPLResetExtensionSafe(pszDest, "gfs").c_str());  | 
2269  | 0  |         }  | 
2270  | 0  |     }  | 
2271  |  | 
  | 
2272  | 0  |     GDALDataset *poOut =  | 
2273  | 0  |         poDriver->CreateCopy(pszDest, poWrkSrcDS, FALSE, aosDSCO.List(),  | 
2274  | 0  |                              psOptions->pfnProgress, psOptions->pProgressData);  | 
2275  |  | 
  | 
2276  | 0  |     return poOut;  | 
2277  | 0  | }  | 
2278  |  |  | 
2279  |  | /************************************************************************/  | 
2280  |  | /*                           CopyRelationships()                        */  | 
2281  |  | /************************************************************************/  | 
2282  |  |  | 
2283  |  | static void CopyRelationships(GDALDataset *poODS, GDALDataset *poDS)  | 
2284  | 0  | { | 
2285  | 0  |     if (!poODS->GetDriver()->GetMetadataItem(GDAL_DCAP_CREATE_RELATIONSHIP))  | 
2286  | 0  |         return;  | 
2287  |  |  | 
2288  | 0  |     const auto aosRelationshipNames = poDS->GetRelationshipNames();  | 
2289  | 0  |     if (aosRelationshipNames.empty())  | 
2290  | 0  |         return;  | 
2291  |  |  | 
2292  |  |     // Collect target layer names  | 
2293  | 0  |     std::set<std::string> oSetDestLayerNames;  | 
2294  | 0  |     for (const auto &poLayer : poDS->GetLayers())  | 
2295  | 0  |     { | 
2296  | 0  |         oSetDestLayerNames.insert(poLayer->GetName());  | 
2297  | 0  |     }  | 
2298  |  |  | 
2299  |  |     // Iterate over all source relationships  | 
2300  | 0  |     for (const auto &osRelationshipName : aosRelationshipNames)  | 
2301  | 0  |     { | 
2302  | 0  |         const auto poSrcRelationship =  | 
2303  | 0  |             poDS->GetRelationship(osRelationshipName);  | 
2304  | 0  |         if (!poSrcRelationship)  | 
2305  | 0  |             continue;  | 
2306  |  |  | 
2307  |  |         // Skip existing relationship of the same name  | 
2308  | 0  |         if (poODS->GetRelationship(osRelationshipName))  | 
2309  | 0  |             continue;  | 
2310  |  |  | 
2311  | 0  |         bool canAdd = true;  | 
2312  | 0  |         const auto &osLeftTableName = poSrcRelationship->GetLeftTableName();  | 
2313  | 0  |         if (!osLeftTableName.empty() &&  | 
2314  | 0  |             !cpl::contains(oSetDestLayerNames, osLeftTableName))  | 
2315  | 0  |         { | 
2316  | 0  |             CPLDebug("GDALVectorTranslate", | 
2317  | 0  |                      "Skipping relationship %s because its left table (%s) "  | 
2318  | 0  |                      "does not exist in target dataset",  | 
2319  | 0  |                      osRelationshipName.c_str(), osLeftTableName.c_str());  | 
2320  | 0  |             canAdd = false;  | 
2321  | 0  |         }  | 
2322  |  | 
  | 
2323  | 0  |         const auto &osRightTableName = poSrcRelationship->GetRightTableName();  | 
2324  | 0  |         if (!osRightTableName.empty() &&  | 
2325  | 0  |             !cpl::contains(oSetDestLayerNames, osRightTableName))  | 
2326  | 0  |         { | 
2327  | 0  |             CPLDebug("GDALVectorTranslate", | 
2328  | 0  |                      "Skipping relationship %s because its right table (%s) "  | 
2329  | 0  |                      "does not exist in target dataset",  | 
2330  | 0  |                      osRelationshipName.c_str(), osRightTableName.c_str());  | 
2331  | 0  |             canAdd = false;  | 
2332  | 0  |         }  | 
2333  |  | 
  | 
2334  | 0  |         const auto &osMappingTableName =  | 
2335  | 0  |             poSrcRelationship->GetMappingTableName();  | 
2336  | 0  |         if (!osMappingTableName.empty() &&  | 
2337  | 0  |             !cpl::contains(oSetDestLayerNames, osMappingTableName))  | 
2338  | 0  |         { | 
2339  | 0  |             CPLDebug("GDALVectorTranslate", | 
2340  | 0  |                      "Skipping relationship %s because its mapping table (%s) "  | 
2341  | 0  |                      "does not exist in target dataset",  | 
2342  | 0  |                      osRelationshipName.c_str(), osMappingTableName.c_str());  | 
2343  | 0  |             canAdd = false;  | 
2344  | 0  |         }  | 
2345  |  | 
  | 
2346  | 0  |         if (canAdd)  | 
2347  | 0  |         { | 
2348  | 0  |             std::string osFailureReason;  | 
2349  | 0  |             if (!poODS->AddRelationship(  | 
2350  | 0  |                     std::make_unique<GDALRelationship>(*poSrcRelationship),  | 
2351  | 0  |                     osFailureReason))  | 
2352  | 0  |             { | 
2353  | 0  |                 CPLDebug("GDALVectorTranslate", | 
2354  | 0  |                          "Cannot add relationship %s: %s",  | 
2355  | 0  |                          osRelationshipName.c_str(), osFailureReason.c_str());  | 
2356  | 0  |             }  | 
2357  | 0  |         }  | 
2358  | 0  |     }  | 
2359  | 0  | }  | 
2360  |  |  | 
2361  |  | /************************************************************************/  | 
2362  |  | /*                           GDALVectorTranslate()                      */  | 
2363  |  | /************************************************************************/  | 
2364  |  | /**  | 
2365  |  |  * Converts vector data between file formats.  | 
2366  |  |  *  | 
2367  |  |  * This is the equivalent of the <a href="/programs/ogr2ogr.html">ogr2ogr</a>  | 
2368  |  |  * utility.  | 
2369  |  |  *  | 
2370  |  |  * GDALVectorTranslateOptions* must be allocated and freed with  | 
2371  |  |  * GDALVectorTranslateOptionsNew() and GDALVectorTranslateOptionsFree()  | 
2372  |  |  * respectively. pszDest and hDstDS cannot be used at the same time.  | 
2373  |  |  *  | 
2374  |  |  * @param pszDest the destination dataset path or NULL.  | 
2375  |  |  * @param hDstDS the destination dataset or NULL.  | 
2376  |  |  * @param nSrcCount the number of input datasets (only 1 supported currently)  | 
2377  |  |  * @param pahSrcDS the list of input datasets.  | 
2378  |  |  * @param psOptionsIn the options struct returned by  | 
2379  |  |  * GDALVectorTranslateOptionsNew() or NULL.  | 
2380  |  |  * @param pbUsageError pointer to a integer output variable to store if any  | 
2381  |  |  * usage error has occurred, or NULL.  | 
2382  |  |  * @return the output dataset (new dataset that must be closed using  | 
2383  |  |  * GDALClose(), or hDstDS is not NULL) or NULL in case of error.  | 
2384  |  |  *  | 
2385  |  |  * @since GDAL 2.1  | 
2386  |  |  */  | 
2387  |  |  | 
2388  |  | GDALDatasetH GDALVectorTranslate(const char *pszDest, GDALDatasetH hDstDS,  | 
2389  |  |                                  int nSrcCount, GDALDatasetH *pahSrcDS,  | 
2390  |  |                                  const GDALVectorTranslateOptions *psOptionsIn,  | 
2391  |  |                                  int *pbUsageError)  | 
2392  |  |  | 
2393  | 0  | { | 
2394  | 0  |     if (pszDest == nullptr && hDstDS == nullptr)  | 
2395  | 0  |     { | 
2396  | 0  |         CPLError(CE_Failure, CPLE_AppDefined,  | 
2397  | 0  |                  "pszDest == NULL && hDstDS == NULL");  | 
2398  |  | 
  | 
2399  | 0  |         if (pbUsageError)  | 
2400  | 0  |             *pbUsageError = TRUE;  | 
2401  | 0  |         return nullptr;  | 
2402  | 0  |     }  | 
2403  | 0  |     if (nSrcCount != 1)  | 
2404  | 0  |     { | 
2405  | 0  |         CPLError(CE_Failure, CPLE_AppDefined, "nSrcCount != 1");  | 
2406  |  | 
  | 
2407  | 0  |         if (pbUsageError)  | 
2408  | 0  |             *pbUsageError = TRUE;  | 
2409  | 0  |         return nullptr;  | 
2410  | 0  |     }  | 
2411  |  |  | 
2412  | 0  |     GDALDatasetH hSrcDS = pahSrcDS[0];  | 
2413  | 0  |     if (hSrcDS == nullptr)  | 
2414  | 0  |     { | 
2415  | 0  |         CPLError(CE_Failure, CPLE_AppDefined, "hSrcDS == NULL");  | 
2416  |  | 
  | 
2417  | 0  |         if (pbUsageError)  | 
2418  | 0  |             *pbUsageError = TRUE;  | 
2419  | 0  |         return nullptr;  | 
2420  | 0  |     }  | 
2421  |  |  | 
2422  | 0  |     auto psOptions =  | 
2423  | 0  |         psOptionsIn ? std::make_unique<GDALVectorTranslateOptions>(*psOptionsIn)  | 
2424  | 0  |                     : std::make_unique<GDALVectorTranslateOptions>();  | 
2425  |  | 
  | 
2426  | 0  |     bool bAppend = false;  | 
2427  | 0  |     bool bUpdate = false;  | 
2428  | 0  |     bool bOverwrite = false;  | 
2429  |  | 
  | 
2430  | 0  |     if (psOptions->eAccessMode == ACCESS_UPDATE)  | 
2431  | 0  |     { | 
2432  | 0  |         bUpdate = true;  | 
2433  | 0  |     }  | 
2434  | 0  |     else if (psOptions->eAccessMode == ACCESS_APPEND)  | 
2435  | 0  |     { | 
2436  | 0  |         bAppend = true;  | 
2437  | 0  |         bUpdate = true;  | 
2438  | 0  |     }  | 
2439  | 0  |     else if (psOptions->eAccessMode == ACCESS_OVERWRITE)  | 
2440  | 0  |     { | 
2441  | 0  |         bOverwrite = true;  | 
2442  | 0  |         bUpdate = true;  | 
2443  | 0  |     }  | 
2444  | 0  |     else if (hDstDS != nullptr)  | 
2445  | 0  |     { | 
2446  | 0  |         bUpdate = true;  | 
2447  | 0  |     }  | 
2448  |  | 
  | 
2449  | 0  |     if (psOptions->bPreserveFID && psOptions->bExplodeCollections)  | 
2450  | 0  |     { | 
2451  | 0  |         CPLError(CE_Failure, CPLE_IllegalArg,  | 
2452  | 0  |                  "cannot use -preserve_fid and -explodecollections at the same "  | 
2453  | 0  |                  "time.");  | 
2454  | 0  |         if (pbUsageError)  | 
2455  | 0  |             *pbUsageError = TRUE;  | 
2456  | 0  |         return nullptr;  | 
2457  | 0  |     }  | 
2458  |  |  | 
2459  | 0  |     if (!psOptions->aosFieldMap.empty() && !bAppend)  | 
2460  | 0  |     { | 
2461  | 0  |         CPLError(CE_Failure, CPLE_IllegalArg,  | 
2462  | 0  |                  "if -fieldmap is specified, -append must also be specified");  | 
2463  | 0  |         if (pbUsageError)  | 
2464  | 0  |             *pbUsageError = TRUE;  | 
2465  | 0  |         return nullptr;  | 
2466  | 0  |     }  | 
2467  |  |  | 
2468  | 0  |     if (!psOptions->aosFieldMap.empty() && psOptions->bAddMissingFields)  | 
2469  | 0  |     { | 
2470  | 0  |         CPLError(CE_Failure, CPLE_IllegalArg,  | 
2471  | 0  |                  "if -addfields is specified, -fieldmap cannot be used.");  | 
2472  | 0  |         if (pbUsageError)  | 
2473  | 0  |             *pbUsageError = TRUE;  | 
2474  | 0  |         return nullptr;  | 
2475  | 0  |     }  | 
2476  |  |  | 
2477  | 0  |     if (psOptions->bSelFieldsSet && bAppend && !psOptions->bAddMissingFields)  | 
2478  | 0  |     { | 
2479  | 0  |         CPLError(CE_Failure, CPLE_IllegalArg,  | 
2480  | 0  |                  "if -append is specified, -select cannot be used "  | 
2481  | 0  |                  "(use -fieldmap or -sql instead).");  | 
2482  | 0  |         if (pbUsageError)  | 
2483  | 0  |             *pbUsageError = TRUE;  | 
2484  | 0  |         return nullptr;  | 
2485  | 0  |     }  | 
2486  |  |  | 
2487  | 0  |     if (!psOptions->aosFieldTypesToString.empty() &&  | 
2488  | 0  |         !psOptions->aosMapFieldType.empty())  | 
2489  | 0  |     { | 
2490  | 0  |         CPLError(CE_Failure, CPLE_IllegalArg,  | 
2491  | 0  |                  "-fieldTypeToString and -mapFieldType are exclusive.");  | 
2492  | 0  |         if (pbUsageError)  | 
2493  | 0  |             *pbUsageError = TRUE;  | 
2494  | 0  |         return nullptr;  | 
2495  | 0  |     }  | 
2496  |  |  | 
2497  | 0  |     if (!psOptions->osSourceSRSDef.empty() &&  | 
2498  | 0  |         psOptions->osOutputSRSDef.empty() && psOptions->osSpatSRSDef.empty())  | 
2499  | 0  |     { | 
2500  | 0  |         CPLError(CE_Failure, CPLE_IllegalArg,  | 
2501  | 0  |                  "if -s_srs is specified, -t_srs and/or -spat_srs must also be "  | 
2502  | 0  |                  "specified.");  | 
2503  | 0  |         if (pbUsageError)  | 
2504  | 0  |             *pbUsageError = TRUE;  | 
2505  | 0  |         return nullptr;  | 
2506  | 0  |     }  | 
2507  |  |  | 
2508  |  |     /* -------------------------------------------------------------------- */  | 
2509  |  |     /*      Parse spatial filter SRS if needed.                             */  | 
2510  |  |     /* -------------------------------------------------------------------- */  | 
2511  | 0  |     std::unique_ptr<OGRSpatialReference, OGRSpatialReferenceReleaser> poSpatSRS;  | 
2512  | 0  |     if (psOptions->poSpatialFilter && !psOptions->osSpatSRSDef.empty())  | 
2513  | 0  |     { | 
2514  | 0  |         if (!psOptions->osSQLStatement.empty())  | 
2515  | 0  |         { | 
2516  | 0  |             CPLError(CE_Failure, CPLE_IllegalArg,  | 
2517  | 0  |                      "-spat_srs not compatible with -sql.");  | 
2518  | 0  |             return nullptr;  | 
2519  | 0  |         }  | 
2520  | 0  |         OGREnvelope sEnvelope;  | 
2521  | 0  |         psOptions->poSpatialFilter->getEnvelope(&sEnvelope);  | 
2522  | 0  |         poSpatSRS.reset(new OGRSpatialReference());  | 
2523  | 0  |         poSpatSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);  | 
2524  | 0  |         if (poSpatSRS->SetFromUserInput(psOptions->osSpatSRSDef.c_str()) !=  | 
2525  | 0  |             OGRERR_NONE)  | 
2526  | 0  |         { | 
2527  | 0  |             CPLError(CE_Failure, CPLE_AppDefined,  | 
2528  | 0  |                      "Failed to process SRS definition: %s",  | 
2529  | 0  |                      psOptions->osSpatSRSDef.c_str());  | 
2530  | 0  |             return nullptr;  | 
2531  | 0  |         }  | 
2532  | 0  |     }  | 
2533  |  |  | 
2534  | 0  |     if (!psOptions->poClipSrc && !psOptions->osClipSrcDS.empty())  | 
2535  | 0  |     { | 
2536  | 0  |         psOptions->poClipSrc =  | 
2537  | 0  |             LoadGeometry(psOptions->osClipSrcDS, psOptions->osClipSrcSQL,  | 
2538  | 0  |                          psOptions->osClipSrcLayer, psOptions->osClipSrcWhere,  | 
2539  | 0  |                          psOptions->bMakeValid);  | 
2540  | 0  |         if (psOptions->poClipSrc == nullptr)  | 
2541  | 0  |         { | 
2542  | 0  |             CPLError(CE_Failure, CPLE_IllegalArg,  | 
2543  | 0  |                      "cannot load source clip geometry");  | 
2544  | 0  |             return nullptr;  | 
2545  | 0  |         }  | 
2546  | 0  |     }  | 
2547  | 0  |     else if (psOptions->bClipSrc && !psOptions->poClipSrc &&  | 
2548  | 0  |              psOptions->poSpatialFilter)  | 
2549  | 0  |     { | 
2550  | 0  |         psOptions->poClipSrc.reset(psOptions->poSpatialFilter->clone());  | 
2551  | 0  |         if (poSpatSRS)  | 
2552  | 0  |         { | 
2553  | 0  |             psOptions->poClipSrc->assignSpatialReference(poSpatSRS.get());  | 
2554  | 0  |         }  | 
2555  | 0  |     }  | 
2556  | 0  |     else if (psOptions->bClipSrc && !psOptions->poClipSrc)  | 
2557  | 0  |     { | 
2558  | 0  |         CPLError(CE_Failure, CPLE_IllegalArg,  | 
2559  | 0  |                  "-clipsrc must be used with -spat option or a\n"  | 
2560  | 0  |                  "bounding box, WKT string or datasource must be specified");  | 
2561  | 0  |         if (pbUsageError)  | 
2562  | 0  |             *pbUsageError = TRUE;  | 
2563  | 0  |         return nullptr;  | 
2564  | 0  |     }  | 
2565  | 0  |     if (psOptions->poClipSrc && !psOptions->poClipSrc->IsValid())  | 
2566  | 0  |     { | 
2567  | 0  |         if (!psOptions->bMakeValid)  | 
2568  | 0  |         { | 
2569  | 0  |             CPLError(CE_Failure, CPLE_IllegalArg,  | 
2570  | 0  |                      "-clipsrc geometry is invalid. You can try to make it "  | 
2571  | 0  |                      "valid with -makevalid, but the results of the operation "  | 
2572  | 0  |                      "should be manually inspected.");  | 
2573  | 0  |             return nullptr;  | 
2574  | 0  |         }  | 
2575  | 0  |         auto poValid =  | 
2576  | 0  |             std::unique_ptr<OGRGeometry>(psOptions->poClipSrc->MakeValid());  | 
2577  | 0  |         if (!poValid)  | 
2578  | 0  |         { | 
2579  | 0  |             CPLError(CE_Failure, CPLE_IllegalArg,  | 
2580  | 0  |                      "-clipsrc geometry is invalid and cannot be made valid.");  | 
2581  | 0  |             return nullptr;  | 
2582  | 0  |         }  | 
2583  | 0  |         CPLError(CE_Warning, CPLE_AppDefined,  | 
2584  | 0  |                  "-clipsrc geometry was invalid and has been made valid, "  | 
2585  | 0  |                  "but the results of the operation "  | 
2586  | 0  |                  "should be manually inspected.");  | 
2587  | 0  |         psOptions->poClipSrc = std::move(poValid);  | 
2588  | 0  |     }  | 
2589  |  |  | 
2590  | 0  |     if (!psOptions->osClipDstDS.empty())  | 
2591  | 0  |     { | 
2592  | 0  |         psOptions->poClipDst =  | 
2593  | 0  |             LoadGeometry(psOptions->osClipDstDS, psOptions->osClipDstSQL,  | 
2594  | 0  |                          psOptions->osClipDstLayer, psOptions->osClipDstWhere,  | 
2595  | 0  |                          psOptions->bMakeValid);  | 
2596  | 0  |         if (psOptions->poClipDst == nullptr)  | 
2597  | 0  |         { | 
2598  | 0  |             CPLError(CE_Failure, CPLE_IllegalArg,  | 
2599  | 0  |                      "cannot load dest clip geometry");  | 
2600  | 0  |             return nullptr;  | 
2601  | 0  |         }  | 
2602  | 0  |     }  | 
2603  | 0  |     if (psOptions->poClipDst && !psOptions->poClipDst->IsValid())  | 
2604  | 0  |     { | 
2605  | 0  |         if (!psOptions->bMakeValid)  | 
2606  | 0  |         { | 
2607  | 0  |             CPLError(CE_Failure, CPLE_IllegalArg,  | 
2608  | 0  |                      "-clipdst geometry is invalid. You can try to make it "  | 
2609  | 0  |                      "valid with -makevalid, but the results of the operation "  | 
2610  | 0  |                      "should be manually inspected.");  | 
2611  | 0  |             return nullptr;  | 
2612  | 0  |         }  | 
2613  | 0  |         auto poValid =  | 
2614  | 0  |             std::unique_ptr<OGRGeometry>(psOptions->poClipDst->MakeValid());  | 
2615  | 0  |         if (!poValid)  | 
2616  | 0  |         { | 
2617  | 0  |             CPLError(CE_Failure, CPLE_IllegalArg,  | 
2618  | 0  |                      "-clipdst geometry is invalid and cannot be made valid.");  | 
2619  | 0  |             return nullptr;  | 
2620  | 0  |         }  | 
2621  | 0  |         CPLError(CE_Warning, CPLE_AppDefined,  | 
2622  | 0  |                  "-clipdst geometry was invalid and has been made valid, "  | 
2623  | 0  |                  "but the results of the operation "  | 
2624  | 0  |                  "should be manually inspected.");  | 
2625  | 0  |         psOptions->poClipDst = std::move(poValid);  | 
2626  | 0  |     }  | 
2627  |  |  | 
2628  | 0  |     GDALDataset *poDS = GDALDataset::FromHandle(hSrcDS);  | 
2629  | 0  |     GDALDataset *poODS = nullptr;  | 
2630  | 0  |     GDALDriver *poDriver = nullptr;  | 
2631  | 0  |     CPLString osDestFilename;  | 
2632  |  | 
  | 
2633  | 0  |     if (hDstDS)  | 
2634  | 0  |     { | 
2635  | 0  |         poODS = GDALDataset::FromHandle(hDstDS);  | 
2636  | 0  |         osDestFilename = poODS->GetDescription();  | 
2637  | 0  |     }  | 
2638  | 0  |     else  | 
2639  | 0  |     { | 
2640  | 0  |         osDestFilename = pszDest;  | 
2641  | 0  |     }  | 
2642  |  |  | 
2643  |  |     /* Various tests to avoid overwriting the source layer(s) */  | 
2644  |  |     /* or to avoid appending a layer to itself */  | 
2645  | 0  |     if (bUpdate && strcmp(osDestFilename, poDS->GetDescription()) == 0 &&  | 
2646  | 0  |         !EQUAL(poDS->GetDriverName(), "MEM") &&  | 
2647  | 0  |         !EQUAL(poDS->GetDriverName(), "Memory") && (bOverwrite || bAppend))  | 
2648  | 0  |     { | 
2649  | 0  |         bool bError = false;  | 
2650  | 0  |         if (psOptions->osNewLayerName.empty())  | 
2651  | 0  |             bError = true;  | 
2652  | 0  |         else if (psOptions->aosLayers.size() == 1)  | 
2653  | 0  |             bError = strcmp(psOptions->osNewLayerName.c_str(),  | 
2654  | 0  |                             psOptions->aosLayers[0]) == 0;  | 
2655  | 0  |         else if (psOptions->osSQLStatement.empty())  | 
2656  | 0  |         { | 
2657  | 0  |             if (psOptions->aosLayers.empty() && poDS->GetLayerCount() == 1)  | 
2658  | 0  |             { | 
2659  | 0  |                 bError = strcmp(psOptions->osNewLayerName.c_str(),  | 
2660  | 0  |                                 poDS->GetLayer(0)->GetName()) == 0;  | 
2661  | 0  |             }  | 
2662  | 0  |             else  | 
2663  | 0  |             { | 
2664  | 0  |                 bError = true;  | 
2665  | 0  |             }  | 
2666  | 0  |         }  | 
2667  | 0  |         if (bError)  | 
2668  | 0  |         { | 
2669  | 0  |             CPLError(CE_Failure, CPLE_IllegalArg,  | 
2670  | 0  |                      "-nln name must be specified combined with "  | 
2671  | 0  |                      "a single source layer name,\nor a -sql statement, and "  | 
2672  | 0  |                      "name must be different from an existing layer.");  | 
2673  | 0  |             return nullptr;  | 
2674  | 0  |         }  | 
2675  | 0  |     }  | 
2676  | 0  |     else if (!bUpdate && strcmp(osDestFilename, poDS->GetDescription()) == 0 &&  | 
2677  | 0  |              (psOptions->osFormat.empty() ||  | 
2678  | 0  |               (!EQUAL(psOptions->osFormat.c_str(), "MEM") &&  | 
2679  | 0  |                !EQUAL(psOptions->osFormat.c_str(), "Memory"))))  | 
2680  | 0  |     { | 
2681  | 0  |         CPLError(CE_Failure, CPLE_AppDefined,  | 
2682  | 0  |                  "Source and destination datasets must be different "  | 
2683  | 0  |                  "in non-update mode.");  | 
2684  | 0  |         return nullptr;  | 
2685  | 0  |     }  | 
2686  |  |  | 
2687  |  |     /* -------------------------------------------------------------------- */  | 
2688  |  |     /*      Try opening the output datasource as an existing, writable      */  | 
2689  |  |     /* -------------------------------------------------------------------- */  | 
2690  | 0  |     std::vector<std::string> aoDrivers;  | 
2691  | 0  |     if (poODS == nullptr && psOptions->osFormat.empty())  | 
2692  | 0  |     { | 
2693  | 0  |         const auto nErrorCount = CPLGetErrorCounter();  | 
2694  | 0  |         aoDrivers = CPLStringList(GDALGetOutputDriversForDatasetName(  | 
2695  | 0  |             pszDest, GDAL_OF_VECTOR, /* bSingleMatch = */ true,  | 
2696  | 0  |             /* bWarn = */ true));  | 
2697  | 0  |         if (!bUpdate && aoDrivers.size() == 1)  | 
2698  | 0  |         { | 
2699  | 0  |             GDALDriverH hDriver = GDALGetDriverByName(aoDrivers[0].c_str());  | 
2700  | 0  |             const char *pszPrefix = GDALGetMetadataItem(  | 
2701  | 0  |                 hDriver, GDAL_DMD_CONNECTION_PREFIX, nullptr);  | 
2702  | 0  |             if (pszPrefix && STARTS_WITH_CI(pszDest, pszPrefix))  | 
2703  | 0  |             { | 
2704  | 0  |                 bUpdate = true;  | 
2705  | 0  |             }  | 
2706  | 0  |         }  | 
2707  | 0  |         else if (aoDrivers.empty() && CPLGetErrorCounter() > nErrorCount &&  | 
2708  | 0  |                  CPLGetLastErrorType() == CE_Failure)  | 
2709  | 0  |         { | 
2710  | 0  |             return nullptr;  | 
2711  | 0  |         }  | 
2712  | 0  |     }  | 
2713  |  |  | 
2714  | 0  |     if (bUpdate && poODS == nullptr)  | 
2715  | 0  |     { | 
2716  | 0  |         poODS = GDALDataset::Open(  | 
2717  | 0  |             osDestFilename, GDAL_OF_UPDATE | GDAL_OF_VECTOR, nullptr,  | 
2718  | 0  |             psOptions->aosDestOpenOptions.List(), nullptr);  | 
2719  |  | 
  | 
2720  | 0  |         if (poODS == nullptr)  | 
2721  | 0  |         { | 
2722  | 0  |             if (bOverwrite || bAppend)  | 
2723  | 0  |             { | 
2724  | 0  |                 poODS = GDALDataset::Open(  | 
2725  | 0  |                     osDestFilename, GDAL_OF_VECTOR, nullptr,  | 
2726  | 0  |                     psOptions->aosDestOpenOptions.List(), nullptr);  | 
2727  | 0  |                 if (poODS == nullptr)  | 
2728  | 0  |                 { | 
2729  |  |                     /* OK the datasource doesn't exist at all */  | 
2730  | 0  |                     bUpdate = false;  | 
2731  | 0  |                 }  | 
2732  | 0  |                 else  | 
2733  | 0  |                 { | 
2734  | 0  |                     poDriver = poODS->GetDriver();  | 
2735  | 0  |                     GDALClose(poODS);  | 
2736  | 0  |                     poODS = nullptr;  | 
2737  | 0  |                 }  | 
2738  | 0  |             }  | 
2739  |  | 
  | 
2740  | 0  |             if (bUpdate)  | 
2741  | 0  |             { | 
2742  | 0  |                 CPLError(CE_Failure, CPLE_AppDefined,  | 
2743  | 0  |                          "Unable to open existing output datasource `%s'.",  | 
2744  | 0  |                          osDestFilename.c_str());  | 
2745  | 0  |                 return nullptr;  | 
2746  | 0  |             }  | 
2747  | 0  |         }  | 
2748  | 0  |         else if (psOptions->aosDSCO.size() > 0)  | 
2749  | 0  |         { | 
2750  | 0  |             CPLError(CE_Warning, CPLE_AppDefined,  | 
2751  | 0  |                      "Datasource creation options ignored since an existing "  | 
2752  | 0  |                      "datasource\n"  | 
2753  | 0  |                      "         being updated.");  | 
2754  | 0  |         }  | 
2755  | 0  |     }  | 
2756  |  |  | 
2757  | 0  |     if (poODS)  | 
2758  | 0  |         poDriver = poODS->GetDriver();  | 
2759  |  |  | 
2760  |  |     /* -------------------------------------------------------------------- */  | 
2761  |  |     /*      Find the output driver.                                         */  | 
2762  |  |     /* -------------------------------------------------------------------- */  | 
2763  | 0  |     bool bNewDataSource = false;  | 
2764  | 0  |     if (!bUpdate)  | 
2765  | 0  |     { | 
2766  | 0  |         GDALDriverManager *poDM = GetGDALDriverManager();  | 
2767  |  | 
  | 
2768  | 0  |         if (psOptions->bNoOverwrite && !EQUAL(pszDest, ""))  | 
2769  | 0  |         { | 
2770  | 0  |             const char *pszType = "";  | 
2771  | 0  |             if (GDALDoesFileOrDatasetExist(pszDest, &pszType))  | 
2772  | 0  |             { | 
2773  | 0  |                 CPLError(CE_Failure, CPLE_AppDefined,  | 
2774  | 0  |                          "%s '%s' already exists. Specify the --overwrite "  | 
2775  | 0  |                          "option to overwrite it.",  | 
2776  | 0  |                          pszType, pszDest);  | 
2777  | 0  |                 return nullptr;  | 
2778  | 0  |             }  | 
2779  | 0  |         }  | 
2780  |  |  | 
2781  | 0  |         if (psOptions->osFormat.empty())  | 
2782  | 0  |         { | 
2783  | 0  |             if (aoDrivers.empty())  | 
2784  | 0  |             { | 
2785  | 0  |                 if (CPLGetExtensionSafe(pszDest).empty())  | 
2786  | 0  |                 { | 
2787  | 0  |                     psOptions->osFormat = "ESRI Shapefile";  | 
2788  | 0  |                 }  | 
2789  | 0  |                 else  | 
2790  | 0  |                 { | 
2791  | 0  |                     CPLError(CE_Failure, CPLE_AppDefined,  | 
2792  | 0  |                              "Cannot guess driver for %s", pszDest);  | 
2793  | 0  |                     return nullptr;  | 
2794  | 0  |                 }  | 
2795  | 0  |             }  | 
2796  | 0  |             else  | 
2797  | 0  |             { | 
2798  | 0  |                 psOptions->osFormat = aoDrivers[0];  | 
2799  | 0  |             }  | 
2800  | 0  |             CPLDebug("GDAL", "Using %s driver", psOptions->osFormat.c_str()); | 
2801  | 0  |         }  | 
2802  |  |  | 
2803  | 0  |         CPLString osOGRCompatFormat(psOptions->osFormat);  | 
2804  |  |         // Special processing for non-unified drivers that have the same name  | 
2805  |  |         // as GDAL and OGR drivers. GMT should become OGR_GMT.  | 
2806  |  |         // Other candidates could be VRT, SDTS and PDS, but they don't  | 
2807  |  |         // have write capabilities. But do the substitution to get a sensible  | 
2808  |  |         // error message  | 
2809  | 0  |         if (EQUAL(osOGRCompatFormat, "GMT") ||  | 
2810  | 0  |             EQUAL(osOGRCompatFormat, "VRT") ||  | 
2811  | 0  |             EQUAL(osOGRCompatFormat, "SDTS") || EQUAL(osOGRCompatFormat, "PDS"))  | 
2812  | 0  |         { | 
2813  | 0  |             osOGRCompatFormat = "OGR_" + osOGRCompatFormat;  | 
2814  | 0  |         }  | 
2815  | 0  |         poDriver = poDM->GetDriverByName(osOGRCompatFormat);  | 
2816  | 0  |         if (poDriver == nullptr)  | 
2817  | 0  |         { | 
2818  | 0  |             CPLError(CE_Failure, CPLE_AppDefined, "Unable to find driver `%s'.",  | 
2819  | 0  |                      psOptions->osFormat.c_str());  | 
2820  | 0  |             return nullptr;  | 
2821  | 0  |         }  | 
2822  |  |  | 
2823  | 0  |         char **papszDriverMD = poDriver->GetMetadata();  | 
2824  | 0  |         if (!CPLTestBool(  | 
2825  | 0  |                 CSLFetchNameValueDef(papszDriverMD, GDAL_DCAP_VECTOR, "FALSE")))  | 
2826  | 0  |         { | 
2827  | 0  |             CPLError(CE_Failure, CPLE_AppDefined,  | 
2828  | 0  |                      "%s driver has no vector capabilities.",  | 
2829  | 0  |                      psOptions->osFormat.c_str());  | 
2830  | 0  |             return nullptr;  | 
2831  | 0  |         }  | 
2832  |  |  | 
2833  | 0  |         if (poDriver->CanVectorTranslateFrom(  | 
2834  | 0  |                 pszDest, poDS, psOptions->aosArguments.List(), nullptr))  | 
2835  | 0  |         { | 
2836  | 0  |             return poDriver->VectorTranslateFrom(  | 
2837  | 0  |                 pszDest, poDS, psOptions->aosArguments.List(),  | 
2838  | 0  |                 psOptions->pfnProgress, psOptions->pProgressData);  | 
2839  | 0  |         }  | 
2840  |  |  | 
2841  | 0  |         if (!CPLTestBool(  | 
2842  | 0  |                 CSLFetchNameValueDef(papszDriverMD, GDAL_DCAP_CREATE, "FALSE")))  | 
2843  | 0  |         { | 
2844  | 0  |             if (CPLTestBool(CSLFetchNameValueDef(  | 
2845  | 0  |                     papszDriverMD, GDAL_DCAP_CREATECOPY, "FALSE")))  | 
2846  | 0  |             { | 
2847  | 0  |                 poODS = GDALVectorTranslateCreateCopy(poDriver, pszDest, poDS,  | 
2848  | 0  |                                                       psOptions.get());  | 
2849  | 0  |                 return poODS;  | 
2850  | 0  |             }  | 
2851  |  |  | 
2852  | 0  |             CPLError(CE_Failure, CPLE_AppDefined,  | 
2853  | 0  |                      "%s driver does not support data source creation.",  | 
2854  | 0  |                      psOptions->osFormat.c_str());  | 
2855  | 0  |             return nullptr;  | 
2856  | 0  |         }  | 
2857  |  |  | 
2858  | 0  |         if (!psOptions->aosDestOpenOptions.empty())  | 
2859  | 0  |         { | 
2860  | 0  |             CPLError(CE_Warning, CPLE_AppDefined,  | 
2861  | 0  |                      "-doo ignored when creating the output datasource.");  | 
2862  | 0  |         }  | 
2863  |  |  | 
2864  |  |         /* --------------------------------------------------------------------  | 
2865  |  |          */  | 
2866  |  |         /*      Special case to improve user experience when translating */  | 
2867  |  |         /*      a datasource with multiple layers into a shapefile. If the */  | 
2868  |  |         /*      user gives a target datasource with .shp and it does not exist,  | 
2869  |  |          */  | 
2870  |  |         /*      the shapefile driver will try to create a file, but this is not  | 
2871  |  |          */  | 
2872  |  |         /*      appropriate because here we have several layers, so create */  | 
2873  |  |         /*      a directory instead. */  | 
2874  |  |         /* --------------------------------------------------------------------  | 
2875  |  |          */  | 
2876  | 0  |         VSIStatBufL sStat;  | 
2877  | 0  |         if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&  | 
2878  | 0  |             psOptions->osSQLStatement.empty() &&  | 
2879  | 0  |             (psOptions->aosLayers.size() > 1 ||  | 
2880  | 0  |              (psOptions->aosLayers.empty() && poDS->GetLayerCount() > 1)) &&  | 
2881  | 0  |             psOptions->osNewLayerName.empty() &&  | 
2882  | 0  |             EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "SHP") &&  | 
2883  | 0  |             VSIStatL(osDestFilename, &sStat) != 0)  | 
2884  | 0  |         { | 
2885  | 0  |             if (VSIMkdir(osDestFilename, 0755) != 0)  | 
2886  | 0  |             { | 
2887  | 0  |                 CPLError(CE_Failure, CPLE_AppDefined,  | 
2888  | 0  |                          "Failed to create directory %s\n"  | 
2889  | 0  |                          "for shapefile datastore.",  | 
2890  | 0  |                          osDestFilename.c_str());  | 
2891  | 0  |                 return nullptr;  | 
2892  | 0  |             }  | 
2893  | 0  |         }  | 
2894  |  |  | 
2895  | 0  |         CPLStringList aosDSCO(psOptions->aosDSCO);  | 
2896  |  | 
  | 
2897  | 0  |         if (!aosDSCO.FetchNameValue("SINGLE_LAYER")) | 
2898  | 0  |         { | 
2899  |  |             // Informs the target driver (e.g. JSONFG) if a single layer  | 
2900  |  |             // will be created  | 
2901  | 0  |             const char *pszCOList =  | 
2902  | 0  |                 poDriver->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);  | 
2903  | 0  |             if (pszCOList && strstr(pszCOList, "SINGLE_LAYER") &&  | 
2904  | 0  |                 (!psOptions->osSQLStatement.empty() ||  | 
2905  | 0  |                  psOptions->aosLayers.size() == 1 ||  | 
2906  | 0  |                  (psOptions->aosLayers.empty() && poDS->GetLayerCount() == 1)))  | 
2907  | 0  |             { | 
2908  | 0  |                 aosDSCO.SetNameValue("SINGLE_LAYER", "YES"); | 
2909  | 0  |             }  | 
2910  | 0  |         }  | 
2911  |  |  | 
2912  |  |         /* --------------------------------------------------------------------  | 
2913  |  |          */  | 
2914  |  |         /*      Create the output data source. */  | 
2915  |  |         /* --------------------------------------------------------------------  | 
2916  |  |          */  | 
2917  | 0  |         poODS = poDriver->Create(osDestFilename, 0, 0, 0, GDT_Unknown,  | 
2918  | 0  |                                  aosDSCO.List());  | 
2919  | 0  |         if (poODS == nullptr)  | 
2920  | 0  |         { | 
2921  | 0  |             CPLError(CE_Failure, CPLE_AppDefined,  | 
2922  | 0  |                      "%s driver failed to create %s",  | 
2923  | 0  |                      psOptions->osFormat.c_str(), osDestFilename.c_str());  | 
2924  | 0  |             return nullptr;  | 
2925  | 0  |         }  | 
2926  | 0  |         bNewDataSource = true;  | 
2927  |  | 
  | 
2928  | 0  |         if (psOptions->bCopyMD)  | 
2929  | 0  |         { | 
2930  | 0  |             const CPLStringList aosDomains(poDS->GetMetadataDomainList());  | 
2931  | 0  |             for (const char *pszMD : aosDomains)  | 
2932  | 0  |             { | 
2933  | 0  |                 if (char **papszMD = poDS->GetMetadata(pszMD))  | 
2934  | 0  |                     poODS->SetMetadata(papszMD, pszMD);  | 
2935  | 0  |             }  | 
2936  | 0  |         }  | 
2937  | 0  |         for (const auto &[pszKey, pszValue] :  | 
2938  | 0  |              cpl::IterateNameValue(psOptions->aosMetadataOptions))  | 
2939  | 0  |         { | 
2940  | 0  |             poODS->SetMetadataItem(pszKey, pszValue);  | 
2941  | 0  |         }  | 
2942  |  |  | 
2943  |  |         // When writing to GeoJSON and using -nln, set the @NAME layer  | 
2944  |  |         // creation option to avoid the GeoJSON driver to potentially reuse  | 
2945  |  |         // the source feature collection name if the input is also GeoJSON.  | 
2946  | 0  |         if (!psOptions->osNewLayerName.empty() &&  | 
2947  | 0  |             EQUAL(psOptions->osFormat.c_str(), "GeoJSON"))  | 
2948  | 0  |         { | 
2949  | 0  |             psOptions->aosLCO.SetNameValue("@NAME", | 
2950  | 0  |                                            psOptions->osNewLayerName.c_str());  | 
2951  | 0  |         }  | 
2952  | 0  |     }  | 
2953  |  |  | 
2954  |  |     // Automatically close poODS on error, if it has been created by this  | 
2955  |  |     // method.  | 
2956  | 0  |     GDALDatasetUniquePtr poODSUniquePtr(hDstDS == nullptr ? poODS : nullptr);  | 
2957  |  |  | 
2958  |  |     // Some syntaxic sugar to make "ogr2ogr [-f PostgreSQL] PG:dbname=....  | 
2959  |  |     // source [srclayer] -lco OVERWRITE=YES" work like "ogr2ogr -overwrite  | 
2960  |  |     // PG:dbname=.... source [srclayer]" The former syntax used to work at  | 
2961  |  |     // GDAL 1.1.8 time when it was documented in the PG driver, but was broken  | 
2962  |  |     // starting with GDAL 1.3.2  | 
2963  |  |     // (https://github.com/OSGeo/gdal/commit/29c108a6c9f651dfebae6d1313ba0e707a77c1aa)  | 
2964  |  |     // This could probably be generalized to other drivers that support the  | 
2965  |  |     // OVERWRITE layer creation option, but we'd need to make sure that they  | 
2966  |  |     // just do a DeleteLayer() call. The CARTO driver is an exception regarding  | 
2967  |  |     // that.  | 
2968  | 0  |     if (EQUAL(poODS->GetDriver()->GetDescription(), "PostgreSQL") &&  | 
2969  | 0  |         CPLTestBool(psOptions->aosLCO.FetchNameValueDef("OVERWRITE", "NO"))) | 
2970  | 0  |     { | 
2971  | 0  |         if (bAppend)  | 
2972  | 0  |         { | 
2973  | 0  |             CPLError(CE_Failure, CPLE_AppDefined,  | 
2974  | 0  |                      "-append and -lco OVERWRITE=YES are mutually exclusive");  | 
2975  | 0  |             return nullptr;  | 
2976  | 0  |         }  | 
2977  | 0  |         bOverwrite = true;  | 
2978  | 0  |     }  | 
2979  |  |  | 
2980  |  |     /* -------------------------------------------------------------------- */  | 
2981  |  |     /*      For random reading                                              */  | 
2982  |  |     /* -------------------------------------------------------------------- */  | 
2983  | 0  |     const bool bRandomLayerReading =  | 
2984  | 0  |         CPL_TO_BOOL(poDS->TestCapability(ODsCRandomLayerRead));  | 
2985  | 0  |     if (bRandomLayerReading && !poODS->TestCapability(ODsCRandomLayerWrite) &&  | 
2986  | 0  |         psOptions->aosLayers.size() != 1 && psOptions->osSQLStatement.empty() &&  | 
2987  | 0  |         !psOptions->bQuiet)  | 
2988  | 0  |     { | 
2989  | 0  |         CPLError(CE_Warning, CPLE_AppDefined,  | 
2990  | 0  |                  "Input datasource uses random layer reading, but "  | 
2991  | 0  |                  "output datasource does not support random layer writing");  | 
2992  | 0  |     }  | 
2993  |  | 
  | 
2994  | 0  |     if (psOptions->nLayerTransaction < 0)  | 
2995  | 0  |     { | 
2996  | 0  |         if (bRandomLayerReading)  | 
2997  | 0  |             psOptions->nLayerTransaction = FALSE;  | 
2998  | 0  |         else  | 
2999  | 0  |             psOptions->nLayerTransaction =  | 
3000  | 0  |                 !poODS->TestCapability(ODsCTransactions);  | 
3001  | 0  |     }  | 
3002  | 0  |     else if (psOptions->nLayerTransaction && bRandomLayerReading)  | 
3003  | 0  |     { | 
3004  | 0  |         psOptions->nLayerTransaction = false;  | 
3005  | 0  |     }  | 
3006  |  |  | 
3007  |  |     /* -------------------------------------------------------------------- */  | 
3008  |  |     /*      Parse the output SRS definition if possible.                    */  | 
3009  |  |     /* -------------------------------------------------------------------- */  | 
3010  | 0  |     OGR2OGRSpatialReferenceHolder oOutputSRSHolder;  | 
3011  | 0  |     if (!psOptions->osOutputSRSDef.empty())  | 
3012  | 0  |     { | 
3013  | 0  |         oOutputSRSHolder.assignNoRefIncrease(new OGRSpatialReference());  | 
3014  | 0  |         oOutputSRSHolder.get()->SetAxisMappingStrategy(  | 
3015  | 0  |             OAMS_TRADITIONAL_GIS_ORDER);  | 
3016  | 0  |         if (oOutputSRSHolder.get()->SetFromUserInput(  | 
3017  | 0  |                 psOptions->osOutputSRSDef.c_str()) != OGRERR_NONE)  | 
3018  | 0  |         { | 
3019  | 0  |             CPLError(CE_Failure, CPLE_AppDefined,  | 
3020  | 0  |                      "Failed to process SRS definition: %s",  | 
3021  | 0  |                      psOptions->osOutputSRSDef.c_str());  | 
3022  | 0  |             return nullptr;  | 
3023  | 0  |         }  | 
3024  | 0  |         oOutputSRSHolder.get()->SetCoordinateEpoch(  | 
3025  | 0  |             psOptions->dfOutputCoordinateEpoch);  | 
3026  | 0  |     }  | 
3027  |  |  | 
3028  |  |     /* -------------------------------------------------------------------- */  | 
3029  |  |     /*      Parse the source SRS definition if possible.                    */  | 
3030  |  |     /* -------------------------------------------------------------------- */  | 
3031  | 0  |     OGRSpatialReference oSourceSRS;  | 
3032  | 0  |     OGRSpatialReference *poSourceSRS = nullptr;  | 
3033  | 0  |     if (!psOptions->osSourceSRSDef.empty())  | 
3034  | 0  |     { | 
3035  | 0  |         oSourceSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);  | 
3036  | 0  |         if (oSourceSRS.SetFromUserInput(psOptions->osSourceSRSDef.c_str()) !=  | 
3037  | 0  |             OGRERR_NONE)  | 
3038  | 0  |         { | 
3039  | 0  |             CPLError(CE_Failure, CPLE_AppDefined,  | 
3040  | 0  |                      "Failed to process SRS definition: %s",  | 
3041  | 0  |                      psOptions->osSourceSRSDef.c_str());  | 
3042  | 0  |             return nullptr;  | 
3043  | 0  |         }  | 
3044  | 0  |         oSourceSRS.SetCoordinateEpoch(psOptions->dfSourceCoordinateEpoch);  | 
3045  | 0  |         poSourceSRS = &oSourceSRS;  | 
3046  | 0  |     }  | 
3047  |  |  | 
3048  |  |     /* -------------------------------------------------------------------- */  | 
3049  |  |     /*      Create a transformation object from the source to               */  | 
3050  |  |     /*      destination coordinate system.                                  */  | 
3051  |  |     /* -------------------------------------------------------------------- */  | 
3052  | 0  |     std::unique_ptr<GCPCoordTransformation> poGCPCoordTrans;  | 
3053  | 0  |     if (psOptions->oGCPs.nGCPCount > 0)  | 
3054  | 0  |     { | 
3055  | 0  |         poGCPCoordTrans = std::make_unique<GCPCoordTransformation>(  | 
3056  | 0  |             psOptions->oGCPs.nGCPCount, psOptions->oGCPs.pasGCPs,  | 
3057  | 0  |             psOptions->nTransformOrder,  | 
3058  | 0  |             poSourceSRS ? poSourceSRS : oOutputSRSHolder.get());  | 
3059  | 0  |         if (!(poGCPCoordTrans->IsValid()))  | 
3060  | 0  |         { | 
3061  | 0  |             return nullptr;  | 
3062  | 0  |         }  | 
3063  | 0  |     }  | 
3064  |  |  | 
3065  |  |     /* -------------------------------------------------------------------- */  | 
3066  |  |     /*      Create layer setup and transformer objects.                     */  | 
3067  |  |     /* -------------------------------------------------------------------- */  | 
3068  | 0  |     SetupTargetLayer oSetup;  | 
3069  | 0  |     oSetup.m_poSrcDS = poDS;  | 
3070  | 0  |     oSetup.m_poDstDS = poODS;  | 
3071  | 0  |     oSetup.m_papszLCO = psOptions->aosLCO.List();  | 
3072  | 0  |     oSetup.m_poOutputSRS = oOutputSRSHolder.get();  | 
3073  | 0  |     oSetup.m_bTransform = psOptions->bTransform;  | 
3074  | 0  |     oSetup.m_bNullifyOutputSRS = psOptions->bNullifyOutputSRS;  | 
3075  | 0  |     oSetup.m_poUserSourceSRS = poSourceSRS;  | 
3076  | 0  |     oSetup.m_bSelFieldsSet = psOptions->bSelFieldsSet;  | 
3077  | 0  |     oSetup.m_papszSelFields = psOptions->aosSelFields.List();  | 
3078  | 0  |     oSetup.m_bAppend = bAppend;  | 
3079  | 0  |     oSetup.m_bAddMissingFields = psOptions->bAddMissingFields;  | 
3080  | 0  |     oSetup.m_eGType = psOptions->eGType;  | 
3081  | 0  |     oSetup.m_eGeomTypeConversion = psOptions->eGeomTypeConversion;  | 
3082  | 0  |     oSetup.m_nCoordDim = psOptions->nCoordDim;  | 
3083  | 0  |     oSetup.m_bOverwrite = bOverwrite;  | 
3084  | 0  |     oSetup.m_papszFieldTypesToString = psOptions->aosFieldTypesToString.List();  | 
3085  | 0  |     oSetup.m_papszMapFieldType = psOptions->aosMapFieldType.List();  | 
3086  | 0  |     oSetup.m_bUnsetFieldWidth = psOptions->bUnsetFieldWidth;  | 
3087  | 0  |     oSetup.m_bExplodeCollections = psOptions->bExplodeCollections;  | 
3088  | 0  |     oSetup.m_pszZField =  | 
3089  | 0  |         psOptions->osZField.empty() ? nullptr : psOptions->osZField.c_str();  | 
3090  | 0  |     oSetup.m_papszFieldMap = psOptions->aosFieldMap.List();  | 
3091  | 0  |     oSetup.m_pszWHERE =  | 
3092  | 0  |         psOptions->osWHERE.empty() ? nullptr : psOptions->osWHERE.c_str();  | 
3093  | 0  |     oSetup.m_bExactFieldNameMatch = psOptions->bExactFieldNameMatch;  | 
3094  | 0  |     oSetup.m_bQuiet = psOptions->bQuiet;  | 
3095  | 0  |     oSetup.m_bForceNullable = psOptions->bForceNullable;  | 
3096  | 0  |     oSetup.m_bResolveDomains = psOptions->bResolveDomains;  | 
3097  | 0  |     oSetup.m_bUnsetDefault = psOptions->bUnsetDefault;  | 
3098  | 0  |     oSetup.m_bUnsetFid = psOptions->bUnsetFid;  | 
3099  | 0  |     oSetup.m_bPreserveFID = psOptions->bPreserveFID;  | 
3100  | 0  |     oSetup.m_bCopyMD = psOptions->bCopyMD;  | 
3101  | 0  |     oSetup.m_bNativeData = psOptions->bNativeData;  | 
3102  | 0  |     oSetup.m_bNewDataSource = bNewDataSource;  | 
3103  | 0  |     oSetup.m_pszCTPipeline = psOptions->osCTPipeline.empty()  | 
3104  | 0  |                                  ? nullptr  | 
3105  | 0  |                                  : psOptions->osCTPipeline.c_str();  | 
3106  | 0  |     oSetup.m_aosCTOptions = psOptions->aosCTOptions;  | 
3107  |  | 
  | 
3108  | 0  |     LayerTranslator oTranslator;  | 
3109  | 0  |     oTranslator.m_poSrcDS = poDS;  | 
3110  | 0  |     oTranslator.m_poODS = poODS;  | 
3111  | 0  |     oTranslator.m_bTransform = psOptions->bTransform;  | 
3112  | 0  |     oTranslator.m_bWrapDateline = psOptions->bWrapDateline;  | 
3113  | 0  |     oTranslator.m_osDateLineOffset =  | 
3114  | 0  |         CPLOPrintf("%g", psOptions->dfDateLineOffset); | 
3115  | 0  |     oTranslator.m_poOutputSRS = oOutputSRSHolder.get();  | 
3116  | 0  |     oTranslator.m_bNullifyOutputSRS = psOptions->bNullifyOutputSRS;  | 
3117  | 0  |     oTranslator.m_poUserSourceSRS = poSourceSRS;  | 
3118  | 0  |     oTranslator.m_poGCPCoordTrans = poGCPCoordTrans.get();  | 
3119  | 0  |     oTranslator.m_eGType = psOptions->eGType;  | 
3120  | 0  |     oTranslator.m_eGeomTypeConversion = psOptions->eGeomTypeConversion;  | 
3121  | 0  |     oTranslator.m_bMakeValid = psOptions->bMakeValid;  | 
3122  | 0  |     oTranslator.m_bSkipInvalidGeom = psOptions->bSkipInvalidGeom;  | 
3123  | 0  |     oTranslator.m_nCoordDim = psOptions->nCoordDim;  | 
3124  | 0  |     oTranslator.m_eGeomOp = psOptions->eGeomOp;  | 
3125  | 0  |     oTranslator.m_dfGeomOpParam = psOptions->dfGeomOpParam;  | 
3126  |  |     // Do not emit warning if the user specified directly the clip source geom  | 
3127  | 0  |     if (psOptions->osClipSrcDS.empty())  | 
3128  | 0  |         oTranslator.m_bWarnedClipSrcSRS = true;  | 
3129  | 0  |     oTranslator.m_poClipSrcOri = psOptions->poClipSrc.get();  | 
3130  |  |     // Do not emit warning if the user specified directly the clip dest geom  | 
3131  | 0  |     if (psOptions->osClipDstDS.empty())  | 
3132  | 0  |         oTranslator.m_bWarnedClipDstSRS = true;  | 
3133  | 0  |     oTranslator.m_poClipDstOri = psOptions->poClipDst.get();  | 
3134  | 0  |     oTranslator.m_bExplodeCollections = psOptions->bExplodeCollections;  | 
3135  | 0  |     oTranslator.m_bNativeData = psOptions->bNativeData;  | 
3136  | 0  |     oTranslator.m_nLimit = psOptions->nLimit;  | 
3137  |  | 
  | 
3138  | 0  |     if (psOptions->nGroupTransactions)  | 
3139  | 0  |     { | 
3140  | 0  |         if (!psOptions->nLayerTransaction)  | 
3141  | 0  |             poODS->StartTransaction(psOptions->bForceTransaction);  | 
3142  | 0  |     }  | 
3143  |  | 
  | 
3144  | 0  |     GIntBig nTotalEventsDone = 0;  | 
3145  |  |  | 
3146  |  |     /* -------------------------------------------------------------------- */  | 
3147  |  |     /*      Special case for -sql clause.  No source layers required.       */  | 
3148  |  |     /* -------------------------------------------------------------------- */  | 
3149  | 0  |     int nRetCode = 0;  | 
3150  |  | 
  | 
3151  | 0  |     if (!psOptions->osSQLStatement.empty())  | 
3152  | 0  |     { | 
3153  |  |         /* Special case: if output=input, then we must likely destroy the */  | 
3154  |  |         /* old table before to avoid transaction issues. */  | 
3155  | 0  |         if (poDS == poODS && !psOptions->osNewLayerName.empty() && bOverwrite)  | 
3156  | 0  |             GetLayerAndOverwriteIfNecessary(  | 
3157  | 0  |                 poODS, psOptions->osNewLayerName.c_str(), bOverwrite, nullptr,  | 
3158  | 0  |                 nullptr, nullptr);  | 
3159  |  | 
  | 
3160  | 0  |         if (!psOptions->osWHERE.empty())  | 
3161  | 0  |             CPLError(CE_Warning, CPLE_AppDefined,  | 
3162  | 0  |                      "-where clause ignored in combination with -sql.");  | 
3163  | 0  |         if (psOptions->aosLayers.size() > 0)  | 
3164  | 0  |             CPLError(CE_Warning, CPLE_AppDefined,  | 
3165  | 0  |                      "layer names ignored in combination with -sql.");  | 
3166  |  | 
  | 
3167  | 0  |         OGRLayer *poResultSet = poDS->ExecuteSQL(  | 
3168  | 0  |             psOptions->osSQLStatement.c_str(),  | 
3169  | 0  |             (!psOptions->bGeomFieldSet) ? psOptions->poSpatialFilter.get()  | 
3170  | 0  |                                         : nullptr,  | 
3171  | 0  |             psOptions->osDialect.empty() ? nullptr  | 
3172  | 0  |                                          : psOptions->osDialect.c_str());  | 
3173  |  | 
  | 
3174  | 0  |         if (poResultSet != nullptr)  | 
3175  | 0  |         { | 
3176  | 0  |             if (psOptions->poSpatialFilter && psOptions->bGeomFieldSet)  | 
3177  | 0  |             { | 
3178  | 0  |                 int iGeomField = poResultSet->GetLayerDefn()->GetGeomFieldIndex(  | 
3179  | 0  |                     psOptions->osGeomField.c_str());  | 
3180  | 0  |                 if (iGeomField >= 0)  | 
3181  | 0  |                     poResultSet->SetSpatialFilter(  | 
3182  | 0  |                         iGeomField, psOptions->poSpatialFilter.get());  | 
3183  | 0  |                 else  | 
3184  | 0  |                     CPLError(CE_Warning, CPLE_AppDefined,  | 
3185  | 0  |                              "Cannot find geometry field %s.",  | 
3186  | 0  |                              psOptions->osGeomField.c_str());  | 
3187  | 0  |             }  | 
3188  |  | 
  | 
3189  | 0  |             GIntBig nCountLayerFeatures = 0;  | 
3190  | 0  |             GDALProgressFunc pfnProgress = nullptr;  | 
3191  | 0  |             void *pProgressArg = nullptr;  | 
3192  | 0  |             if (psOptions->bDisplayProgress)  | 
3193  | 0  |             { | 
3194  | 0  |                 if (bRandomLayerReading)  | 
3195  | 0  |                 { | 
3196  | 0  |                     pfnProgress = psOptions->pfnProgress;  | 
3197  | 0  |                     pProgressArg = psOptions->pProgressData;  | 
3198  | 0  |                 }  | 
3199  | 0  |                 else if (!poResultSet->TestCapability(OLCFastFeatureCount))  | 
3200  | 0  |                 { | 
3201  | 0  |                     CPLError(CE_Warning, CPLE_AppDefined,  | 
3202  | 0  |                              "Progress turned off as fast feature count is not "  | 
3203  | 0  |                              "available.");  | 
3204  | 0  |                     psOptions->bDisplayProgress = false;  | 
3205  | 0  |                 }  | 
3206  | 0  |                 else  | 
3207  | 0  |                 { | 
3208  | 0  |                     nCountLayerFeatures = poResultSet->GetFeatureCount();  | 
3209  | 0  |                     pfnProgress = psOptions->pfnProgress;  | 
3210  | 0  |                     pProgressArg = psOptions->pProgressData;  | 
3211  | 0  |                 }  | 
3212  | 0  |             }  | 
3213  |  | 
  | 
3214  | 0  |             OGRLayer *poPassedLayer = poResultSet;  | 
3215  | 0  |             if (psOptions->bSplitListFields)  | 
3216  | 0  |             { | 
3217  | 0  |                 auto poLayer = new OGRSplitListFieldLayer(  | 
3218  | 0  |                     poPassedLayer, psOptions->nMaxSplitListSubFields);  | 
3219  | 0  |                 poPassedLayer = poLayer;  | 
3220  | 0  |                 int nRet = poLayer->BuildLayerDefn(nullptr, nullptr);  | 
3221  | 0  |                 if (!nRet)  | 
3222  | 0  |                 { | 
3223  | 0  |                     delete poPassedLayer;  | 
3224  | 0  |                     poPassedLayer = poResultSet;  | 
3225  | 0  |                 }  | 
3226  | 0  |             }  | 
3227  |  |  | 
3228  |  |             /* --------------------------------------------------------------------  | 
3229  |  |              */  | 
3230  |  |             /*      Special case to improve user experience when translating  | 
3231  |  |              * into   */  | 
3232  |  |             /*      single file shapefile and source has only one layer, and  | 
3233  |  |              * that   */  | 
3234  |  |             /*      the layer name isn't specified */  | 
3235  |  |             /* --------------------------------------------------------------------  | 
3236  |  |              */  | 
3237  | 0  |             VSIStatBufL sStat;  | 
3238  | 0  |             if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&  | 
3239  | 0  |                 psOptions->osNewLayerName.empty() &&  | 
3240  | 0  |                 VSIStatL(osDestFilename, &sStat) == 0 &&  | 
3241  | 0  |                 VSI_ISREG(sStat.st_mode) &&  | 
3242  | 0  |                 (EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "shp") ||  | 
3243  | 0  |                  EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "shz") ||  | 
3244  | 0  |                  EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "dbf")))  | 
3245  | 0  |             { | 
3246  | 0  |                 psOptions->osNewLayerName = CPLGetBasenameSafe(osDestFilename);  | 
3247  | 0  |             }  | 
3248  |  | 
  | 
3249  | 0  |             auto psInfo = oSetup.Setup(poPassedLayer,  | 
3250  | 0  |                                        psOptions->osNewLayerName.empty()  | 
3251  | 0  |                                            ? nullptr  | 
3252  | 0  |                                            : psOptions->osNewLayerName.c_str(),  | 
3253  | 0  |                                        psOptions.get(), nTotalEventsDone);  | 
3254  |  | 
  | 
3255  | 0  |             poPassedLayer->ResetReading();  | 
3256  |  | 
  | 
3257  | 0  |             if (psInfo == nullptr ||  | 
3258  | 0  |                 !oTranslator.Translate(nullptr, psInfo.get(),  | 
3259  | 0  |                                        nCountLayerFeatures, nullptr,  | 
3260  | 0  |                                        nTotalEventsDone, pfnProgress,  | 
3261  | 0  |                                        pProgressArg, psOptions.get()))  | 
3262  | 0  |             { | 
3263  | 0  |                 CPLError(CE_Failure, CPLE_AppDefined,  | 
3264  | 0  |                          "Terminating translation prematurely after failed\n"  | 
3265  | 0  |                          "translation from sql statement.");  | 
3266  |  | 
  | 
3267  | 0  |                 nRetCode = 1;  | 
3268  | 0  |             }  | 
3269  | 0  |             else  | 
3270  | 0  |             { | 
3271  | 0  |                 psInfo->CheckSameCoordinateOperation();  | 
3272  | 0  |             }  | 
3273  |  | 
  | 
3274  | 0  |             if (poPassedLayer != poResultSet)  | 
3275  | 0  |                 delete poPassedLayer;  | 
3276  |  | 
  | 
3277  | 0  |             poDS->ReleaseResultSet(poResultSet);  | 
3278  | 0  |         }  | 
3279  | 0  |         else  | 
3280  | 0  |         { | 
3281  | 0  |             if (CPLGetLastErrorNo() != 0)  | 
3282  | 0  |                 nRetCode = 1;  | 
3283  | 0  |         }  | 
3284  | 0  |     }  | 
3285  |  |  | 
3286  |  |     /* -------------------------------------------------------------------- */  | 
3287  |  |     /*      Special case for layer interleaving mode.                       */  | 
3288  |  |     /* -------------------------------------------------------------------- */  | 
3289  | 0  |     else if (bRandomLayerReading)  | 
3290  | 0  |     { | 
3291  | 0  |         if (psOptions->bSplitListFields)  | 
3292  | 0  |         { | 
3293  | 0  |             CPLError(CE_Failure, CPLE_AppDefined,  | 
3294  | 0  |                      "-splitlistfields not supported in this mode");  | 
3295  | 0  |             return nullptr;  | 
3296  | 0  |         }  | 
3297  |  |  | 
3298  |  |         // Make sure to probe all layers in case some are by default invisible  | 
3299  | 0  |         for (const char *pszLayer : psOptions->aosLayers)  | 
3300  | 0  |         { | 
3301  | 0  |             OGRLayer *poLayer = poDS->GetLayerByName(pszLayer);  | 
3302  |  | 
  | 
3303  | 0  |             if (poLayer == nullptr)  | 
3304  | 0  |             { | 
3305  | 0  |                 CPLError(CE_Failure, CPLE_AppDefined,  | 
3306  | 0  |                          "Couldn't fetch requested layer %s!", pszLayer);  | 
3307  | 0  |                 return nullptr;  | 
3308  | 0  |             }  | 
3309  | 0  |         }  | 
3310  |  |  | 
3311  | 0  |         const int nSrcLayerCount = poDS->GetLayerCount();  | 
3312  | 0  |         std::vector<AssociatedLayers> pasAssocLayers(nSrcLayerCount);  | 
3313  |  |  | 
3314  |  |         /* --------------------------------------------------------------------  | 
3315  |  |          */  | 
3316  |  |         /*      Special case to improve user experience when translating into */  | 
3317  |  |         /*      single file shapefile and source has only one layer, and that */  | 
3318  |  |         /*      the layer name isn't specified */  | 
3319  |  |         /* --------------------------------------------------------------------  | 
3320  |  |          */  | 
3321  | 0  |         VSIStatBufL sStat;  | 
3322  | 0  |         if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&  | 
3323  | 0  |             (psOptions->aosLayers.size() == 1 || nSrcLayerCount == 1) &&  | 
3324  | 0  |             psOptions->osNewLayerName.empty() &&  | 
3325  | 0  |             VSIStatL(osDestFilename, &sStat) == 0 && VSI_ISREG(sStat.st_mode) &&  | 
3326  | 0  |             (EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "shp") ||  | 
3327  | 0  |              EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "shz") ||  | 
3328  | 0  |              EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "dbf")))  | 
3329  | 0  |         { | 
3330  | 0  |             psOptions->osNewLayerName = CPLGetBasenameSafe(osDestFilename);  | 
3331  | 0  |         }  | 
3332  |  | 
  | 
3333  | 0  |         GDALProgressFunc pfnProgress = nullptr;  | 
3334  | 0  |         void *pProgressArg = nullptr;  | 
3335  | 0  |         if (!psOptions->bQuiet)  | 
3336  | 0  |         { | 
3337  | 0  |             pfnProgress = psOptions->pfnProgress;  | 
3338  | 0  |             pProgressArg = psOptions->pProgressData;  | 
3339  | 0  |         }  | 
3340  |  |  | 
3341  |  |         /* --------------------------------------------------------------------  | 
3342  |  |          */  | 
3343  |  |         /*      If no target layer specified, use all source layers. */  | 
3344  |  |         /* --------------------------------------------------------------------  | 
3345  |  |          */  | 
3346  | 0  |         if (psOptions->aosLayers.empty())  | 
3347  | 0  |         { | 
3348  | 0  |             for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)  | 
3349  | 0  |             { | 
3350  | 0  |                 OGRLayer *poLayer = poDS->GetLayer(iLayer);  | 
3351  |  | 
  | 
3352  | 0  |                 if (poLayer == nullptr)  | 
3353  | 0  |                 { | 
3354  | 0  |                     CPLError(CE_Failure, CPLE_AppDefined,  | 
3355  | 0  |                              "Couldn't fetch advertised layer %d!", iLayer);  | 
3356  | 0  |                     return nullptr;  | 
3357  | 0  |                 }  | 
3358  |  |  | 
3359  | 0  |                 psOptions->aosLayers.AddString(poLayer->GetName());  | 
3360  | 0  |             }  | 
3361  | 0  |         }  | 
3362  | 0  |         else  | 
3363  | 0  |         { | 
3364  | 0  |             const bool bSrcIsOSM = (strcmp(poDS->GetDriverName(), "OSM") == 0);  | 
3365  | 0  |             if (bSrcIsOSM)  | 
3366  | 0  |             { | 
3367  | 0  |                 CPLString osInterestLayers = "SET interest_layers =";  | 
3368  | 0  |                 for (int iLayer = 0; iLayer < psOptions->aosLayers.size();  | 
3369  | 0  |                      iLayer++)  | 
3370  | 0  |                 { | 
3371  | 0  |                     if (iLayer != 0)  | 
3372  | 0  |                         osInterestLayers += ",";  | 
3373  | 0  |                     osInterestLayers += psOptions->aosLayers[iLayer];  | 
3374  | 0  |                 }  | 
3375  |  | 
  | 
3376  | 0  |                 poDS->ExecuteSQL(osInterestLayers.c_str(), nullptr, nullptr);  | 
3377  | 0  |             }  | 
3378  | 0  |         }  | 
3379  |  |  | 
3380  |  |         /* --------------------------------------------------------------------  | 
3381  |  |          */  | 
3382  |  |         /*      First pass to set filters. */  | 
3383  |  |         /* --------------------------------------------------------------------  | 
3384  |  |          */  | 
3385  | 0  |         std::map<OGRLayer *, int> oMapLayerToIdx;  | 
3386  |  | 
  | 
3387  | 0  |         for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)  | 
3388  | 0  |         { | 
3389  | 0  |             OGRLayer *poLayer = poDS->GetLayer(iLayer);  | 
3390  | 0  |             if (poLayer == nullptr)  | 
3391  | 0  |             { | 
3392  | 0  |                 CPLError(CE_Failure, CPLE_AppDefined,  | 
3393  | 0  |                          "Couldn't fetch advertised layer %d!", iLayer);  | 
3394  | 0  |                 return nullptr;  | 
3395  | 0  |             }  | 
3396  |  |  | 
3397  | 0  |             pasAssocLayers[iLayer].poSrcLayer = poLayer;  | 
3398  |  | 
  | 
3399  | 0  |             if (psOptions->aosLayers.FindString(poLayer->GetName()) >= 0)  | 
3400  | 0  |             { | 
3401  | 0  |                 if (!psOptions->osWHERE.empty())  | 
3402  | 0  |                 { | 
3403  | 0  |                     if (poLayer->SetAttributeFilter(  | 
3404  | 0  |                             psOptions->osWHERE.c_str()) != OGRERR_NONE)  | 
3405  | 0  |                     { | 
3406  | 0  |                         CPLError(CE_Failure, CPLE_AppDefined,  | 
3407  | 0  |                                  "SetAttributeFilter(%s) on layer '%s' failed.",  | 
3408  | 0  |                                  psOptions->osWHERE.c_str(),  | 
3409  | 0  |                                  poLayer->GetName());  | 
3410  | 0  |                         if (!psOptions->bSkipFailures)  | 
3411  | 0  |                         { | 
3412  | 0  |                             return nullptr;  | 
3413  | 0  |                         }  | 
3414  | 0  |                     }  | 
3415  | 0  |                 }  | 
3416  |  |  | 
3417  | 0  |                 ApplySpatialFilter(  | 
3418  | 0  |                     poLayer, psOptions->poSpatialFilter.get(), poSpatSRS.get(),  | 
3419  | 0  |                     psOptions->bGeomFieldSet ? psOptions->osGeomField.c_str()  | 
3420  | 0  |                                              : nullptr,  | 
3421  | 0  |                     poSourceSRS);  | 
3422  |  | 
  | 
3423  | 0  |                 oMapLayerToIdx[poLayer] = iLayer;  | 
3424  | 0  |             }  | 
3425  | 0  |         }  | 
3426  |  |  | 
3427  |  |         /* --------------------------------------------------------------------  | 
3428  |  |          */  | 
3429  |  |         /*      Second pass to process features in a interleaved layer mode. */  | 
3430  |  |         /* --------------------------------------------------------------------  | 
3431  |  |          */  | 
3432  | 0  |         bool bTargetLayersHaveBeenCreated = false;  | 
3433  | 0  |         while (true)  | 
3434  | 0  |         { | 
3435  | 0  |             OGRLayer *poFeatureLayer = nullptr;  | 
3436  | 0  |             auto poFeature = std::unique_ptr<OGRFeature>(poDS->GetNextFeature(  | 
3437  | 0  |                 &poFeatureLayer, nullptr, pfnProgress, pProgressArg));  | 
3438  | 0  |             if (poFeature == nullptr)  | 
3439  | 0  |                 break;  | 
3440  | 0  |             std::map<OGRLayer *, int>::const_iterator oIter =  | 
3441  | 0  |                 oMapLayerToIdx.find(poFeatureLayer);  | 
3442  | 0  |             if (oIter == oMapLayerToIdx.end())  | 
3443  | 0  |             { | 
3444  |  |                 // Feature in a layer that is not a layer of interest.  | 
3445  |  |                 // nothing to do  | 
3446  | 0  |             }  | 
3447  | 0  |             else  | 
3448  | 0  |             { | 
3449  | 0  |                 if (!bTargetLayersHaveBeenCreated)  | 
3450  | 0  |                 { | 
3451  |  |                     // We defer target layer creation at the first feature  | 
3452  |  |                     // retrieved since getting the layer definition can be  | 
3453  |  |                     // costly (case of the GMLAS driver) and thus we'd better  | 
3454  |  |                     // taking advantage from the progress callback of  | 
3455  |  |                     // GetNextFeature.  | 
3456  | 0  |                     bTargetLayersHaveBeenCreated = true;  | 
3457  | 0  |                     for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)  | 
3458  | 0  |                     { | 
3459  | 0  |                         OGRLayer *poLayer = poDS->GetLayer(iLayer);  | 
3460  | 0  |                         if (psOptions->aosLayers.FindString(  | 
3461  | 0  |                                 poLayer->GetName()) < 0)  | 
3462  | 0  |                             continue;  | 
3463  |  |  | 
3464  | 0  |                         auto psInfo = oSetup.Setup(  | 
3465  | 0  |                             poLayer,  | 
3466  | 0  |                             psOptions->osNewLayerName.empty()  | 
3467  | 0  |                                 ? nullptr  | 
3468  | 0  |                                 : psOptions->osNewLayerName.c_str(),  | 
3469  | 0  |                             psOptions.get(), nTotalEventsDone);  | 
3470  |  | 
  | 
3471  | 0  |                         if (psInfo == nullptr && !psOptions->bSkipFailures)  | 
3472  | 0  |                         { | 
3473  | 0  |                             return nullptr;  | 
3474  | 0  |                         }  | 
3475  |  |  | 
3476  | 0  |                         pasAssocLayers[iLayer].psInfo = std::move(psInfo);  | 
3477  | 0  |                     }  | 
3478  | 0  |                     if (nRetCode)  | 
3479  | 0  |                         break;  | 
3480  | 0  |                 }  | 
3481  |  |  | 
3482  | 0  |                 int iLayer = oIter->second;  | 
3483  | 0  |                 TargetLayerInfo *psInfo = pasAssocLayers[iLayer].psInfo.get();  | 
3484  | 0  |                 if ((psInfo == nullptr ||  | 
3485  | 0  |                      !oTranslator.Translate(poFeature.release(), psInfo, 0,  | 
3486  | 0  |                                             nullptr, nTotalEventsDone, nullptr,  | 
3487  | 0  |                                             nullptr, psOptions.get())) &&  | 
3488  | 0  |                     !psOptions->bSkipFailures)  | 
3489  | 0  |                 { | 
3490  | 0  |                     CPLError(  | 
3491  | 0  |                         CE_Failure, CPLE_AppDefined,  | 
3492  | 0  |                         "Terminating translation prematurely after failed\n"  | 
3493  | 0  |                         "translation of layer %s (use -skipfailures to skip "  | 
3494  | 0  |                         "errors)",  | 
3495  | 0  |                         poFeatureLayer->GetName());  | 
3496  |  | 
  | 
3497  | 0  |                     nRetCode = 1;  | 
3498  | 0  |                     break;  | 
3499  | 0  |                 }  | 
3500  | 0  |             }  | 
3501  | 0  |         }  // while true  | 
3502  |  |  | 
3503  | 0  |         if (pfnProgress)  | 
3504  | 0  |         { | 
3505  | 0  |             pfnProgress(1.0, "", pProgressArg);  | 
3506  | 0  |         }  | 
3507  |  | 
  | 
3508  | 0  |         for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)  | 
3509  | 0  |         { | 
3510  | 0  |             if (pasAssocLayers[iLayer].psInfo)  | 
3511  | 0  |                 pasAssocLayers[iLayer].psInfo->CheckSameCoordinateOperation();  | 
3512  | 0  |         }  | 
3513  |  | 
  | 
3514  | 0  |         if (!bTargetLayersHaveBeenCreated)  | 
3515  | 0  |         { | 
3516  |  |             // bTargetLayersHaveBeenCreated not used after here.  | 
3517  |  |             // bTargetLayersHaveBeenCreated = true;  | 
3518  | 0  |             for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)  | 
3519  | 0  |             { | 
3520  | 0  |                 OGRLayer *poLayer = poDS->GetLayer(iLayer);  | 
3521  | 0  |                 if (psOptions->aosLayers.FindString(poLayer->GetName()) < 0)  | 
3522  | 0  |                     continue;  | 
3523  |  |  | 
3524  | 0  |                 auto psInfo =  | 
3525  | 0  |                     oSetup.Setup(poLayer,  | 
3526  | 0  |                                  psOptions->osNewLayerName.empty()  | 
3527  | 0  |                                      ? nullptr  | 
3528  | 0  |                                      : psOptions->osNewLayerName.c_str(),  | 
3529  | 0  |                                  psOptions.get(), nTotalEventsDone);  | 
3530  |  | 
  | 
3531  | 0  |                 if (psInfo == nullptr && !psOptions->bSkipFailures)  | 
3532  | 0  |                 { | 
3533  | 0  |                     return nullptr;  | 
3534  | 0  |                 }  | 
3535  |  |  | 
3536  | 0  |                 pasAssocLayers[iLayer].psInfo = std::move(psInfo);  | 
3537  | 0  |             }  | 
3538  | 0  |         }  | 
3539  | 0  |     }  | 
3540  |  |  | 
3541  | 0  |     else  | 
3542  | 0  |     { | 
3543  | 0  |         std::vector<OGRLayer *> apoLayers;  | 
3544  |  |  | 
3545  |  |         /* --------------------------------------------------------------------  | 
3546  |  |          */  | 
3547  |  |         /*      Process each data source layer. */  | 
3548  |  |         /* --------------------------------------------------------------------  | 
3549  |  |          */  | 
3550  | 0  |         if (psOptions->aosLayers.empty())  | 
3551  | 0  |         { | 
3552  | 0  |             const int nLayerCount = poDS->GetLayerCount();  | 
3553  |  | 
  | 
3554  | 0  |             for (int iLayer = 0; iLayer < nLayerCount; iLayer++)  | 
3555  | 0  |             { | 
3556  | 0  |                 OGRLayer *poLayer = poDS->GetLayer(iLayer);  | 
3557  |  | 
  | 
3558  | 0  |                 if (poLayer == nullptr)  | 
3559  | 0  |                 { | 
3560  | 0  |                     CPLError(CE_Failure, CPLE_AppDefined,  | 
3561  | 0  |                              "Couldn't fetch advertised layer %d!", iLayer);  | 
3562  | 0  |                     return nullptr;  | 
3563  | 0  |                 }  | 
3564  | 0  |                 if (!poDS->IsLayerPrivate(iLayer))  | 
3565  | 0  |                 { | 
3566  | 0  |                     apoLayers.push_back(poLayer);  | 
3567  | 0  |                 }  | 
3568  | 0  |             }  | 
3569  | 0  |         }  | 
3570  |  |         /* --------------------------------------------------------------------  | 
3571  |  |          */  | 
3572  |  |         /*      Process specified data source layers. */  | 
3573  |  |         /* --------------------------------------------------------------------  | 
3574  |  |          */  | 
3575  | 0  |         else  | 
3576  | 0  |         { | 
3577  |  | 
  | 
3578  | 0  |             for (int iLayer = 0; psOptions->aosLayers[iLayer] != nullptr;  | 
3579  | 0  |                  iLayer++)  | 
3580  | 0  |             { | 
3581  | 0  |                 OGRLayer *poLayer =  | 
3582  | 0  |                     poDS->GetLayerByName(psOptions->aosLayers[iLayer]);  | 
3583  |  | 
  | 
3584  | 0  |                 if (poLayer == nullptr)  | 
3585  | 0  |                 { | 
3586  | 0  |                     CPLError(CE_Failure, CPLE_AppDefined,  | 
3587  | 0  |                              "Couldn't fetch requested layer '%s'!",  | 
3588  | 0  |                              psOptions->aosLayers[iLayer]);  | 
3589  | 0  |                     if (!psOptions->bSkipFailures)  | 
3590  | 0  |                     { | 
3591  | 0  |                         return nullptr;  | 
3592  | 0  |                     }  | 
3593  | 0  |                 }  | 
3594  |  |  | 
3595  | 0  |                 apoLayers.emplace_back(poLayer);  | 
3596  | 0  |             }  | 
3597  | 0  |         }  | 
3598  |  |  | 
3599  |  |         /* --------------------------------------------------------------------  | 
3600  |  |          */  | 
3601  |  |         /*      Special case to improve user experience when translating into */  | 
3602  |  |         /*      single file shapefile and source has only one layer, and that */  | 
3603  |  |         /*      the layer name isn't specified */  | 
3604  |  |         /* --------------------------------------------------------------------  | 
3605  |  |          */  | 
3606  | 0  |         VSIStatBufL sStat;  | 
3607  | 0  |         const int nLayerCount = static_cast<int>(apoLayers.size());  | 
3608  | 0  |         if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&  | 
3609  | 0  |             nLayerCount == 1 && psOptions->osNewLayerName.empty() &&  | 
3610  | 0  |             VSIStatL(osDestFilename, &sStat) == 0 && VSI_ISREG(sStat.st_mode) &&  | 
3611  | 0  |             (EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "shp") ||  | 
3612  | 0  |              EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "shz") ||  | 
3613  | 0  |              EQUAL(CPLGetExtensionSafe(osDestFilename).c_str(), "dbf")))  | 
3614  | 0  |         { | 
3615  | 0  |             psOptions->osNewLayerName = CPLGetBasenameSafe(osDestFilename);  | 
3616  | 0  |         }  | 
3617  |  | 
  | 
3618  | 0  |         std::vector<GIntBig> anLayerCountFeatures(nLayerCount);  | 
3619  | 0  |         GIntBig nCountLayersFeatures = 0;  | 
3620  | 0  |         GIntBig nAccCountFeatures = 0;  | 
3621  |  |  | 
3622  |  |         /* First pass to apply filters and count all features if necessary */  | 
3623  | 0  |         for (int iLayer = 0; iLayer < nLayerCount; iLayer++)  | 
3624  | 0  |         { | 
3625  | 0  |             OGRLayer *poLayer = apoLayers[iLayer];  | 
3626  | 0  |             if (poLayer == nullptr)  | 
3627  | 0  |                 continue;  | 
3628  |  |  | 
3629  | 0  |             if (!psOptions->osWHERE.empty())  | 
3630  | 0  |             { | 
3631  | 0  |                 if (poLayer->SetAttributeFilter(psOptions->osWHERE.c_str()) !=  | 
3632  | 0  |                     OGRERR_NONE)  | 
3633  | 0  |                 { | 
3634  | 0  |                     CPLError(CE_Failure, CPLE_AppDefined,  | 
3635  | 0  |                              "SetAttributeFilter(%s) on layer '%s' failed.",  | 
3636  | 0  |                              psOptions->osWHERE.c_str(), poLayer->GetName());  | 
3637  | 0  |                     if (!psOptions->bSkipFailures)  | 
3638  | 0  |                     { | 
3639  | 0  |                         return nullptr;  | 
3640  | 0  |                     }  | 
3641  | 0  |                 }  | 
3642  | 0  |             }  | 
3643  |  |  | 
3644  | 0  |             ApplySpatialFilter(  | 
3645  | 0  |                 poLayer, psOptions->poSpatialFilter.get(), poSpatSRS.get(),  | 
3646  | 0  |                 psOptions->bGeomFieldSet ? psOptions->osGeomField.c_str()  | 
3647  | 0  |                                          : nullptr,  | 
3648  | 0  |                 poSourceSRS);  | 
3649  |  | 
  | 
3650  | 0  |             if (psOptions->bDisplayProgress)  | 
3651  | 0  |             { | 
3652  | 0  |                 if (!poLayer->TestCapability(OLCFastFeatureCount))  | 
3653  | 0  |                 { | 
3654  | 0  |                     CPLError(CE_Warning, CPLE_NotSupported,  | 
3655  | 0  |                              "Progress turned off as fast feature count is not "  | 
3656  | 0  |                              "available.");  | 
3657  | 0  |                     psOptions->bDisplayProgress = false;  | 
3658  | 0  |                 }  | 
3659  | 0  |                 else  | 
3660  | 0  |                 { | 
3661  | 0  |                     anLayerCountFeatures[iLayer] = poLayer->GetFeatureCount();  | 
3662  | 0  |                     if (psOptions->nLimit >= 0)  | 
3663  | 0  |                         anLayerCountFeatures[iLayer] = std::min(  | 
3664  | 0  |                             anLayerCountFeatures[iLayer], psOptions->nLimit);  | 
3665  | 0  |                     if (anLayerCountFeatures[iLayer] >= 0 &&  | 
3666  | 0  |                         anLayerCountFeatures[iLayer] <=  | 
3667  | 0  |                             std::numeric_limits<GIntBig>::max() -  | 
3668  | 0  |                                 nCountLayersFeatures)  | 
3669  | 0  |                     { | 
3670  | 0  |                         nCountLayersFeatures += anLayerCountFeatures[iLayer];  | 
3671  | 0  |                     }  | 
3672  | 0  |                     else  | 
3673  | 0  |                     { | 
3674  | 0  |                         nCountLayersFeatures = 0;  | 
3675  | 0  |                         psOptions->bDisplayProgress = false;  | 
3676  | 0  |                     }  | 
3677  | 0  |                 }  | 
3678  | 0  |             }  | 
3679  | 0  |         }  | 
3680  |  |  | 
3681  |  |         /* Second pass to do the real job */  | 
3682  | 0  |         for (int iLayer = 0; iLayer < nLayerCount && nRetCode == 0; iLayer++)  | 
3683  | 0  |         { | 
3684  | 0  |             OGRLayer *poLayer = apoLayers[iLayer];  | 
3685  | 0  |             if (poLayer == nullptr)  | 
3686  | 0  |                 continue;  | 
3687  |  |  | 
3688  | 0  |             GDALProgressFunc pfnProgress = nullptr;  | 
3689  | 0  |             void *pProgressArg = nullptr;  | 
3690  |  | 
  | 
3691  | 0  |             OGRLayer *poPassedLayer = poLayer;  | 
3692  | 0  |             if (psOptions->bSplitListFields)  | 
3693  | 0  |             { | 
3694  | 0  |                 auto poSLFLayer = new OGRSplitListFieldLayer(  | 
3695  | 0  |                     poPassedLayer, psOptions->nMaxSplitListSubFields);  | 
3696  | 0  |                 poPassedLayer = poSLFLayer;  | 
3697  |  | 
  | 
3698  | 0  |                 if (psOptions->bDisplayProgress &&  | 
3699  | 0  |                     psOptions->nMaxSplitListSubFields != 1 &&  | 
3700  | 0  |                     nCountLayersFeatures != 0)  | 
3701  | 0  |                 { | 
3702  | 0  |                     pfnProgress = GDALScaledProgress;  | 
3703  | 0  |                     pProgressArg = GDALCreateScaledProgress(  | 
3704  | 0  |                         nAccCountFeatures * 1.0 / nCountLayersFeatures,  | 
3705  | 0  |                         (nAccCountFeatures + anLayerCountFeatures[iLayer] / 2) *  | 
3706  | 0  |                             1.0 / nCountLayersFeatures,  | 
3707  | 0  |                         psOptions->pfnProgress, psOptions->pProgressData);  | 
3708  | 0  |                 }  | 
3709  | 0  |                 else  | 
3710  | 0  |                 { | 
3711  | 0  |                     pfnProgress = nullptr;  | 
3712  | 0  |                     pProgressArg = nullptr;  | 
3713  | 0  |                 }  | 
3714  |  | 
  | 
3715  | 0  |                 int nRet =  | 
3716  | 0  |                     poSLFLayer->BuildLayerDefn(pfnProgress, pProgressArg);  | 
3717  | 0  |                 if (!nRet)  | 
3718  | 0  |                 { | 
3719  | 0  |                     delete poPassedLayer;  | 
3720  | 0  |                     poPassedLayer = poLayer;  | 
3721  | 0  |                 }  | 
3722  |  | 
  | 
3723  | 0  |                 if (psOptions->bDisplayProgress)  | 
3724  | 0  |                     GDALDestroyScaledProgress(pProgressArg);  | 
3725  | 0  |                 pfnProgress = nullptr;  | 
3726  | 0  |                 pProgressArg = nullptr;  | 
3727  | 0  |             }  | 
3728  |  | 
  | 
3729  | 0  |             if (psOptions->bDisplayProgress)  | 
3730  | 0  |             { | 
3731  | 0  |                 if (nCountLayersFeatures != 0)  | 
3732  | 0  |                 { | 
3733  | 0  |                     pfnProgress = GDALScaledProgress;  | 
3734  | 0  |                     GIntBig nStart = 0;  | 
3735  | 0  |                     if (poPassedLayer != poLayer &&  | 
3736  | 0  |                         psOptions->nMaxSplitListSubFields != 1)  | 
3737  | 0  |                         nStart = anLayerCountFeatures[iLayer] / 2;  | 
3738  | 0  |                     pProgressArg = GDALCreateScaledProgress(  | 
3739  | 0  |                         (nAccCountFeatures + nStart) * 1.0 /  | 
3740  | 0  |                             nCountLayersFeatures,  | 
3741  | 0  |                         (nAccCountFeatures + anLayerCountFeatures[iLayer]) *  | 
3742  | 0  |                             1.0 / nCountLayersFeatures,  | 
3743  | 0  |                         psOptions->pfnProgress, psOptions->pProgressData);  | 
3744  | 0  |                 }  | 
3745  |  | 
  | 
3746  | 0  |                 nAccCountFeatures += anLayerCountFeatures[iLayer];  | 
3747  | 0  |             }  | 
3748  |  | 
  | 
3749  | 0  |             auto psInfo = oSetup.Setup(poPassedLayer,  | 
3750  | 0  |                                        psOptions->osNewLayerName.empty()  | 
3751  | 0  |                                            ? nullptr  | 
3752  | 0  |                                            : psOptions->osNewLayerName.c_str(),  | 
3753  | 0  |                                        psOptions.get(), nTotalEventsDone);  | 
3754  |  | 
  | 
3755  | 0  |             poPassedLayer->ResetReading();  | 
3756  |  | 
  | 
3757  | 0  |             if ((psInfo == nullptr ||  | 
3758  | 0  |                  !oTranslator.Translate(nullptr, psInfo.get(),  | 
3759  | 0  |                                         anLayerCountFeatures[iLayer], nullptr,  | 
3760  | 0  |                                         nTotalEventsDone, pfnProgress,  | 
3761  | 0  |                                         pProgressArg, psOptions.get())) &&  | 
3762  | 0  |                 !psOptions->bSkipFailures)  | 
3763  | 0  |             { | 
3764  | 0  |                 CPLError(CE_Failure, CPLE_AppDefined,  | 
3765  | 0  |                          "Terminating translation prematurely after failed\n"  | 
3766  | 0  |                          "translation of layer %s (use -skipfailures to skip "  | 
3767  | 0  |                          "errors)",  | 
3768  | 0  |                          poLayer->GetName());  | 
3769  |  | 
  | 
3770  | 0  |                 nRetCode = 1;  | 
3771  | 0  |             }  | 
3772  |  | 
  | 
3773  | 0  |             if (psInfo)  | 
3774  | 0  |                 psInfo->CheckSameCoordinateOperation();  | 
3775  |  | 
  | 
3776  | 0  |             if (poPassedLayer != poLayer)  | 
3777  | 0  |                 delete poPassedLayer;  | 
3778  |  | 
  | 
3779  | 0  |             if (psOptions->bDisplayProgress)  | 
3780  | 0  |                 GDALDestroyScaledProgress(pProgressArg);  | 
3781  | 0  |         }  | 
3782  | 0  |     }  | 
3783  |  |  | 
3784  | 0  |     CopyRelationships(poODS, poDS);  | 
3785  |  |  | 
3786  |  |     /* -------------------------------------------------------------------- */  | 
3787  |  |     /*      Process DS style table                                          */  | 
3788  |  |     /* -------------------------------------------------------------------- */  | 
3789  |  | 
  | 
3790  | 0  |     poODS->SetStyleTable(poDS->GetStyleTable());  | 
3791  |  | 
  | 
3792  | 0  |     if (psOptions->nGroupTransactions)  | 
3793  | 0  |     { | 
3794  | 0  |         if (!psOptions->nLayerTransaction)  | 
3795  | 0  |         { | 
3796  | 0  |             if (nRetCode != 0 && !psOptions->bSkipFailures)  | 
3797  | 0  |                 poODS->RollbackTransaction();  | 
3798  | 0  |             else  | 
3799  | 0  |             { | 
3800  | 0  |                 OGRErr eRet = poODS->CommitTransaction();  | 
3801  | 0  |                 if (eRet != OGRERR_NONE && eRet != OGRERR_UNSUPPORTED_OPERATION)  | 
3802  | 0  |                 { | 
3803  | 0  |                     nRetCode = 1;  | 
3804  | 0  |                 }  | 
3805  | 0  |             }  | 
3806  | 0  |         }  | 
3807  | 0  |     }  | 
3808  |  |  | 
3809  |  |     // Note: this guarantees that the file can be opened in a consistent state,  | 
3810  |  |     // without requiring to close poODS, only if the driver declares  | 
3811  |  |     // DCAP_FLUSHCACHE_CONSISTENT_STATE  | 
3812  | 0  |     if (poODS->FlushCache() != CE_None)  | 
3813  | 0  |         nRetCode = 1;  | 
3814  |  | 
  | 
3815  | 0  |     if (nRetCode == 0)  | 
3816  | 0  |     { | 
3817  | 0  |         if (hDstDS)  | 
3818  | 0  |             return hDstDS;  | 
3819  | 0  |         else  | 
3820  | 0  |             return GDALDataset::ToHandle(poODSUniquePtr.release());  | 
3821  | 0  |     }  | 
3822  |  |  | 
3823  | 0  |     return nullptr;  | 
3824  | 0  | }  | 
3825  |  |  | 
3826  |  | /************************************************************************/  | 
3827  |  | /*                               SetZ()                                 */  | 
3828  |  | /************************************************************************/  | 
3829  |  |  | 
3830  |  | namespace  | 
3831  |  | { | 
3832  |  | class SetZVisitor : public OGRDefaultGeometryVisitor  | 
3833  |  | { | 
3834  |  |     double m_dfZ;  | 
3835  |  |  | 
3836  |  |   public:  | 
3837  | 0  |     explicit SetZVisitor(double dfZ) : m_dfZ(dfZ)  | 
3838  | 0  |     { | 
3839  | 0  |     }  | 
3840  |  |  | 
3841  |  |     using OGRDefaultGeometryVisitor::visit;  | 
3842  |  |  | 
3843  |  |     void visit(OGRPoint *poPoint) override  | 
3844  | 0  |     { | 
3845  | 0  |         poPoint->setZ(m_dfZ);  | 
3846  | 0  |     }  | 
3847  |  | };  | 
3848  |  | }  // namespace  | 
3849  |  |  | 
3850  |  | static void SetZ(OGRGeometry *poGeom, double dfZ)  | 
3851  | 0  | { | 
3852  | 0  |     if (poGeom == nullptr)  | 
3853  | 0  |         return;  | 
3854  | 0  |     SetZVisitor visitor(dfZ);  | 
3855  | 0  |     poGeom->set3D(true);  | 
3856  | 0  |     poGeom->accept(&visitor);  | 
3857  | 0  | }  | 
3858  |  |  | 
3859  |  | /************************************************************************/  | 
3860  |  | /*                       ForceCoordDimension()                          */  | 
3861  |  | /************************************************************************/  | 
3862  |  |  | 
3863  |  | static int ForceCoordDimension(int eGType, int nCoordDim)  | 
3864  | 0  | { | 
3865  | 0  |     if (nCoordDim == 2 && eGType != wkbNone)  | 
3866  | 0  |         return wkbFlatten(eGType);  | 
3867  | 0  |     else if (nCoordDim == 3 && eGType != wkbNone)  | 
3868  | 0  |         return wkbSetZ(wkbFlatten(eGType));  | 
3869  | 0  |     else if (nCoordDim == COORD_DIM_XYM && eGType != wkbNone)  | 
3870  | 0  |         return wkbSetM(wkbFlatten(eGType));  | 
3871  | 0  |     else if (nCoordDim == 4 && eGType != wkbNone)  | 
3872  | 0  |         return OGR_GT_SetModifier(static_cast<OGRwkbGeometryType>(eGType), TRUE,  | 
3873  | 0  |                                   TRUE);  | 
3874  | 0  |     else  | 
3875  | 0  |         return eGType;  | 
3876  | 0  | }  | 
3877  |  |  | 
3878  |  | /************************************************************************/  | 
3879  |  | /*                   GetLayerAndOverwriteIfNecessary()                  */  | 
3880  |  | /************************************************************************/  | 
3881  |  |  | 
3882  |  | static OGRLayer *GetLayerAndOverwriteIfNecessary(GDALDataset *poDstDS,  | 
3883  |  |                                                  const char *pszNewLayerName,  | 
3884  |  |                                                  bool bOverwrite,  | 
3885  |  |                                                  bool *pbErrorOccurred,  | 
3886  |  |                                                  bool *pbOverwriteActuallyDone,  | 
3887  |  |                                                  bool *pbAddOverwriteLCO)  | 
3888  | 0  | { | 
3889  | 0  |     if (pbErrorOccurred)  | 
3890  | 0  |         *pbErrorOccurred = false;  | 
3891  | 0  |     if (pbOverwriteActuallyDone)  | 
3892  | 0  |         *pbOverwriteActuallyDone = false;  | 
3893  | 0  |     if (pbAddOverwriteLCO)  | 
3894  | 0  |         *pbAddOverwriteLCO = false;  | 
3895  |  |  | 
3896  |  |     /* GetLayerByName() can instantiate layers that would have been */  | 
3897  |  |     /* 'hidden' otherwise, for example, non-spatial tables in a */  | 
3898  |  |     /* PostGIS-enabled database, so this apparently useless command is */  | 
3899  |  |     /* not useless. (#4012) */  | 
3900  | 0  |     CPLPushErrorHandler(CPLQuietErrorHandler);  | 
3901  | 0  |     OGRLayer *poDstLayer = poDstDS->GetLayerByName(pszNewLayerName);  | 
3902  | 0  |     CPLPopErrorHandler();  | 
3903  | 0  |     CPLErrorReset();  | 
3904  |  | 
  | 
3905  | 0  |     int iLayer = -1;  | 
3906  | 0  |     if (poDstLayer != nullptr)  | 
3907  | 0  |     { | 
3908  | 0  |         const int nLayerCount = poDstDS->GetLayerCount();  | 
3909  | 0  |         for (iLayer = 0; iLayer < nLayerCount; iLayer++)  | 
3910  | 0  |         { | 
3911  | 0  |             OGRLayer *poLayer = poDstDS->GetLayer(iLayer);  | 
3912  | 0  |             if (poLayer == poDstLayer)  | 
3913  | 0  |                 break;  | 
3914  | 0  |         }  | 
3915  |  | 
  | 
3916  | 0  |         if (iLayer == nLayerCount)  | 
3917  |  |             /* should not happen with an ideal driver */  | 
3918  | 0  |             poDstLayer = nullptr;  | 
3919  | 0  |     }  | 
3920  |  |  | 
3921  |  |     /* -------------------------------------------------------------------- */  | 
3922  |  |     /*      If the user requested overwrite, and we have the layer in       */  | 
3923  |  |     /*      question we need to delete it now so it will get recreated      */  | 
3924  |  |     /*      (overwritten).                                                  */  | 
3925  |  |     /* -------------------------------------------------------------------- */  | 
3926  | 0  |     if (poDstLayer != nullptr && bOverwrite)  | 
3927  | 0  |     { | 
3928  |  |         /* When using the CARTO driver we don't want to delete the layer if */  | 
3929  |  |         /* it's going to be recreated. Instead we mark it to be overwritten */  | 
3930  |  |         /* when the new creation is requested */  | 
3931  | 0  |         if (poDstDS->GetDriver()->GetMetadataItem(  | 
3932  | 0  |                 GDAL_DS_LAYER_CREATIONOPTIONLIST) != nullptr &&  | 
3933  | 0  |             strstr(poDstDS->GetDriver()->GetMetadataItem(  | 
3934  | 0  |                        GDAL_DS_LAYER_CREATIONOPTIONLIST),  | 
3935  | 0  |                    "CARTODBFY") != nullptr)  | 
3936  | 0  |         { | 
3937  | 0  |             if (pbAddOverwriteLCO)  | 
3938  | 0  |                 *pbAddOverwriteLCO = true;  | 
3939  | 0  |             if (pbOverwriteActuallyDone)  | 
3940  | 0  |                 *pbOverwriteActuallyDone = true;  | 
3941  | 0  |         }  | 
3942  | 0  |         else if (poDstDS->DeleteLayer(iLayer) != OGRERR_NONE)  | 
3943  | 0  |         { | 
3944  | 0  |             CPLError(CE_Failure, CPLE_AppDefined,  | 
3945  | 0  |                      "DeleteLayer() failed when overwrite requested.");  | 
3946  | 0  |             if (pbErrorOccurred)  | 
3947  | 0  |                 *pbErrorOccurred = true;  | 
3948  | 0  |         }  | 
3949  | 0  |         else  | 
3950  | 0  |         { | 
3951  | 0  |             if (pbOverwriteActuallyDone)  | 
3952  | 0  |                 *pbOverwriteActuallyDone = true;  | 
3953  | 0  |         }  | 
3954  | 0  |         poDstLayer = nullptr;  | 
3955  | 0  |     }  | 
3956  |  | 
  | 
3957  | 0  |     return poDstLayer;  | 
3958  | 0  | }  | 
3959  |  |  | 
3960  |  | /************************************************************************/  | 
3961  |  | /*                          ConvertType()                               */  | 
3962  |  | /************************************************************************/  | 
3963  |  |  | 
3964  |  | static OGRwkbGeometryType ConvertType(GeomTypeConversion eGeomTypeConversion,  | 
3965  |  |                                       OGRwkbGeometryType eGType)  | 
3966  | 0  | { | 
3967  | 0  |     OGRwkbGeometryType eRetType = eGType;  | 
3968  |  | 
  | 
3969  | 0  |     if (eGeomTypeConversion == GTC_CONVERT_TO_LINEAR ||  | 
3970  | 0  |         eGeomTypeConversion == GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR)  | 
3971  | 0  |     { | 
3972  | 0  |         eRetType = OGR_GT_GetLinear(eRetType);  | 
3973  | 0  |     }  | 
3974  |  | 
  | 
3975  | 0  |     if (eGeomTypeConversion == GTC_PROMOTE_TO_MULTI ||  | 
3976  | 0  |         eGeomTypeConversion == GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR)  | 
3977  | 0  |     { | 
3978  | 0  |         if (eRetType == wkbTriangle || eRetType == wkbTIN ||  | 
3979  | 0  |             eRetType == wkbPolyhedralSurface)  | 
3980  | 0  |         { | 
3981  | 0  |             eRetType = wkbMultiPolygon;  | 
3982  | 0  |         }  | 
3983  | 0  |         else if (!OGR_GT_IsSubClassOf(eRetType, wkbGeometryCollection))  | 
3984  | 0  |         { | 
3985  | 0  |             eRetType = OGR_GT_GetCollection(eRetType);  | 
3986  | 0  |         }  | 
3987  | 0  |     }  | 
3988  |  | 
  | 
3989  | 0  |     if (eGeomTypeConversion == GTC_CONVERT_TO_CURVE)  | 
3990  | 0  |         eRetType = OGR_GT_GetCurve(eRetType);  | 
3991  |  | 
  | 
3992  | 0  |     return eRetType;  | 
3993  | 0  | }  | 
3994  |  |  | 
3995  |  | /************************************************************************/  | 
3996  |  | /*                        DoFieldTypeConversion()                       */  | 
3997  |  | /************************************************************************/  | 
3998  |  |  | 
3999  |  | static void DoFieldTypeConversion(GDALDataset *poDstDS,  | 
4000  |  |                                   OGRFieldDefn &oFieldDefn,  | 
4001  |  |                                   CSLConstList papszFieldTypesToString,  | 
4002  |  |                                   CSLConstList papszMapFieldType,  | 
4003  |  |                                   bool bUnsetFieldWidth, bool bQuiet,  | 
4004  |  |                                   bool bForceNullable, bool bUnsetDefault)  | 
4005  | 0  | { | 
4006  | 0  |     if (papszFieldTypesToString != nullptr)  | 
4007  | 0  |     { | 
4008  | 0  |         CPLString osLookupString;  | 
4009  | 0  |         osLookupString.Printf(  | 
4010  | 0  |             "%s(%s)", OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),  | 
4011  | 0  |             OGRFieldDefn::GetFieldSubTypeName(oFieldDefn.GetSubType()));  | 
4012  |  | 
  | 
4013  | 0  |         int iIdx = CSLFindString(papszFieldTypesToString, osLookupString);  | 
4014  | 0  |         if (iIdx < 0)  | 
4015  | 0  |             iIdx = CSLFindString(  | 
4016  | 0  |                 papszFieldTypesToString,  | 
4017  | 0  |                 OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()));  | 
4018  | 0  |         if (iIdx < 0)  | 
4019  | 0  |             iIdx = CSLFindString(papszFieldTypesToString, "All");  | 
4020  | 0  |         if (iIdx >= 0)  | 
4021  | 0  |         { | 
4022  | 0  |             oFieldDefn.SetSubType(OFSTNone);  | 
4023  | 0  |             oFieldDefn.SetType(OFTString);  | 
4024  | 0  |         }  | 
4025  | 0  |     }  | 
4026  | 0  |     else if (papszMapFieldType != nullptr)  | 
4027  | 0  |     { | 
4028  | 0  |         CPLString osLookupString;  | 
4029  | 0  |         osLookupString.Printf(  | 
4030  | 0  |             "%s(%s)", OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),  | 
4031  | 0  |             OGRFieldDefn::GetFieldSubTypeName(oFieldDefn.GetSubType()));  | 
4032  |  | 
  | 
4033  | 0  |         const char *pszType =  | 
4034  | 0  |             CSLFetchNameValue(papszMapFieldType, osLookupString);  | 
4035  | 0  |         if (pszType == nullptr)  | 
4036  | 0  |             pszType = CSLFetchNameValue(  | 
4037  | 0  |                 papszMapFieldType,  | 
4038  | 0  |                 OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()));  | 
4039  | 0  |         if (pszType == nullptr)  | 
4040  | 0  |             pszType = CSLFetchNameValue(papszMapFieldType, "All");  | 
4041  | 0  |         if (pszType != nullptr)  | 
4042  | 0  |         { | 
4043  | 0  |             int iSubType;  | 
4044  | 0  |             int iType = GetFieldType(pszType, &iSubType);  | 
4045  | 0  |             if (iType >= 0 && iSubType >= 0)  | 
4046  | 0  |             { | 
4047  | 0  |                 oFieldDefn.SetSubType(OFSTNone);  | 
4048  | 0  |                 oFieldDefn.SetType(static_cast<OGRFieldType>(iType));  | 
4049  | 0  |                 oFieldDefn.SetSubType(static_cast<OGRFieldSubType>(iSubType));  | 
4050  | 0  |                 if (iType == OFTInteger)  | 
4051  | 0  |                     oFieldDefn.SetWidth(0);  | 
4052  | 0  |             }  | 
4053  | 0  |         }  | 
4054  | 0  |     }  | 
4055  | 0  |     if (bUnsetFieldWidth)  | 
4056  | 0  |     { | 
4057  | 0  |         oFieldDefn.SetWidth(0);  | 
4058  | 0  |         oFieldDefn.SetPrecision(0);  | 
4059  | 0  |     }  | 
4060  | 0  |     if (bForceNullable)  | 
4061  | 0  |         oFieldDefn.SetNullable(TRUE);  | 
4062  | 0  |     if (bUnsetDefault)  | 
4063  | 0  |         oFieldDefn.SetDefault(nullptr);  | 
4064  |  | 
  | 
4065  | 0  |     const auto poDstDriver = poDstDS->GetDriver();  | 
4066  | 0  |     const char *pszCreationFieldDataTypes =  | 
4067  | 0  |         poDstDriver  | 
4068  | 0  |             ? poDstDriver->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES)  | 
4069  | 0  |             : nullptr;  | 
4070  | 0  |     const char *pszCreationFieldDataSubtypes =  | 
4071  | 0  |         poDstDriver  | 
4072  | 0  |             ? poDstDriver->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES)  | 
4073  | 0  |             : nullptr;  | 
4074  | 0  |     if (pszCreationFieldDataTypes &&  | 
4075  | 0  |         strstr(pszCreationFieldDataTypes,  | 
4076  | 0  |                OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType())) == nullptr)  | 
4077  | 0  |     { | 
4078  | 0  |         if (pszCreationFieldDataSubtypes &&  | 
4079  | 0  |             (oFieldDefn.GetType() == OFTIntegerList ||  | 
4080  | 0  |              oFieldDefn.GetType() == OFTInteger64List ||  | 
4081  | 0  |              oFieldDefn.GetType() == OFTRealList ||  | 
4082  | 0  |              oFieldDefn.GetType() == OFTStringList) &&  | 
4083  | 0  |             strstr(pszCreationFieldDataSubtypes, "JSON"))  | 
4084  | 0  |         { | 
4085  | 0  |             if (!bQuiet)  | 
4086  | 0  |             { | 
4087  | 0  |                 CPLError(  | 
4088  | 0  |                     CE_Warning, CPLE_AppDefined,  | 
4089  | 0  |                     "The output driver does not seem to natively support %s "  | 
4090  | 0  |                     "type for field %s. Converting it to String(JSON) instead. "  | 
4091  | 0  |                     "-mapFieldType can be used to control field type "  | 
4092  | 0  |                     "conversion.",  | 
4093  | 0  |                     OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),  | 
4094  | 0  |                     oFieldDefn.GetNameRef());  | 
4095  | 0  |             }  | 
4096  | 0  |             oFieldDefn.SetSubType(OFSTNone);  | 
4097  | 0  |             oFieldDefn.SetType(OFTString);  | 
4098  | 0  |             oFieldDefn.SetSubType(OFSTJSON);  | 
4099  | 0  |         }  | 
4100  | 0  |         else if (oFieldDefn.GetType() == OFTInteger64)  | 
4101  | 0  |         { | 
4102  | 0  |             if (!bQuiet)  | 
4103  | 0  |             { | 
4104  | 0  |                 CPLError(  | 
4105  | 0  |                     CE_Warning, CPLE_AppDefined,  | 
4106  | 0  |                     "The output driver does not seem to natively support %s "  | 
4107  | 0  |                     "type for field %s. Converting it to Real instead. "  | 
4108  | 0  |                     "-mapFieldType can be used to control field type "  | 
4109  | 0  |                     "conversion.",  | 
4110  | 0  |                     OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),  | 
4111  | 0  |                     oFieldDefn.GetNameRef());  | 
4112  | 0  |             }  | 
4113  | 0  |             oFieldDefn.SetType(OFTReal);  | 
4114  | 0  |         }  | 
4115  | 0  |         else if (oFieldDefn.GetType() == OFTDateTime && poDstDriver &&  | 
4116  | 0  |                  EQUAL(poDstDriver->GetDescription(), "ESRI Shapefile"))  | 
4117  | 0  |         { | 
4118  |  |             // Just be silent. The shapefile driver will itself emit a  | 
4119  |  |             // warning mentioning it converts DateTime to String.  | 
4120  | 0  |         }  | 
4121  | 0  |         else if (!bQuiet)  | 
4122  | 0  |         { | 
4123  | 0  |             CPLError(  | 
4124  | 0  |                 CE_Warning, CPLE_AppDefined,  | 
4125  | 0  |                 "The output driver does not natively support %s type for "  | 
4126  | 0  |                 "field %s. Misconversion can happen. "  | 
4127  | 0  |                 "-mapFieldType can be used to control field type conversion.",  | 
4128  | 0  |                 OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),  | 
4129  | 0  |                 oFieldDefn.GetNameRef());  | 
4130  | 0  |         }  | 
4131  | 0  |     }  | 
4132  | 0  |     else if (!pszCreationFieldDataTypes)  | 
4133  | 0  |     { | 
4134  |  |         // All drivers supporting OFTInteger64 should advertise it theoretically  | 
4135  | 0  |         if (oFieldDefn.GetType() == OFTInteger64)  | 
4136  | 0  |         { | 
4137  | 0  |             if (!bQuiet)  | 
4138  | 0  |             { | 
4139  | 0  |                 CPLError(CE_Warning, CPLE_AppDefined,  | 
4140  | 0  |                          "The output driver does not seem to natively support "  | 
4141  | 0  |                          "%s type "  | 
4142  | 0  |                          "for field %s. Converting it to Real instead. "  | 
4143  | 0  |                          "-mapFieldType can be used to control field type "  | 
4144  | 0  |                          "conversion.",  | 
4145  | 0  |                          OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),  | 
4146  | 0  |                          oFieldDefn.GetNameRef());  | 
4147  | 0  |             }  | 
4148  | 0  |             oFieldDefn.SetType(OFTReal);  | 
4149  | 0  |         }  | 
4150  | 0  |     }  | 
4151  | 0  | }  | 
4152  |  |  | 
4153  |  | /************************************************************************/  | 
4154  |  | /*                        GetArrowGeomFieldIndex()                      */  | 
4155  |  | /************************************************************************/  | 
4156  |  |  | 
4157  |  | static int GetArrowGeomFieldIndex(const struct ArrowSchema *psLayerSchema,  | 
4158  |  |                                   const char *pszFieldName)  | 
4159  | 0  | { | 
4160  | 0  |     if (strcmp(psLayerSchema->format, "+s") == 0)  // struct  | 
4161  | 0  |     { | 
4162  | 0  |         for (int i = 0; i < psLayerSchema->n_children; ++i)  | 
4163  | 0  |         { | 
4164  | 0  |             const auto psSchema = psLayerSchema->children[i];  | 
4165  | 0  |             if (strcmp(psSchema->format, "z") == 0)  // binary  | 
4166  | 0  |             { | 
4167  | 0  |                 if (strcmp(psSchema->name, pszFieldName) == 0)  | 
4168  | 0  |                 { | 
4169  | 0  |                     return i;  | 
4170  | 0  |                 }  | 
4171  | 0  |                 else  | 
4172  | 0  |                 { | 
4173  |  |                     // Check if ARROW:extension:name = ogc.wkb or geoarrow.wkb  | 
4174  | 0  |                     const char *pabyMetadata = psSchema->metadata;  | 
4175  | 0  |                     if (pabyMetadata)  | 
4176  | 0  |                     { | 
4177  | 0  |                         const auto oMetadata =  | 
4178  | 0  |                             OGRParseArrowMetadata(pabyMetadata);  | 
4179  | 0  |                         auto oIter = oMetadata.find(ARROW_EXTENSION_NAME_KEY);  | 
4180  | 0  |                         if (oIter != oMetadata.end() &&  | 
4181  | 0  |                             (oIter->second == EXTENSION_NAME_OGC_WKB ||  | 
4182  | 0  |                              oIter->second == EXTENSION_NAME_GEOARROW_WKB))  | 
4183  | 0  |                         { | 
4184  | 0  |                             return i;  | 
4185  | 0  |                         }  | 
4186  | 0  |                     }  | 
4187  | 0  |                 }  | 
4188  | 0  |             }  | 
4189  | 0  |         }  | 
4190  | 0  |     }  | 
4191  | 0  |     return -1;  | 
4192  | 0  | }  | 
4193  |  |  | 
4194  |  | /************************************************************************/  | 
4195  |  | /*                        BuildGetArrowStreamOptions()                  */  | 
4196  |  | /************************************************************************/  | 
4197  |  |  | 
4198  |  | static CPLStringList  | 
4199  |  | BuildGetArrowStreamOptions(OGRLayer *poSrcLayer, OGRLayer *poDstLayer,  | 
4200  |  |                            const GDALVectorTranslateOptions *psOptions,  | 
4201  |  |                            bool bPreserveFID)  | 
4202  | 0  | { | 
4203  | 0  |     CPLStringList aosOptionsGetArrowStream;  | 
4204  | 0  |     aosOptionsGetArrowStream.SetNameValue("SILENCE_GET_SCHEMA_ERROR", "YES"); | 
4205  | 0  |     aosOptionsGetArrowStream.SetNameValue("GEOMETRY_ENCODING", "WKB"); | 
4206  | 0  |     if (!bPreserveFID)  | 
4207  | 0  |         aosOptionsGetArrowStream.SetNameValue("INCLUDE_FID", "NO"); | 
4208  | 0  |     if (psOptions->nLimit >= 0)  | 
4209  | 0  |     { | 
4210  | 0  |         aosOptionsGetArrowStream.SetNameValue(  | 
4211  | 0  |             "MAX_FEATURES_IN_BATCH",  | 
4212  | 0  |             CPLSPrintf(CPL_FRMT_GIB,  | 
4213  | 0  |                        std::min<GIntBig>(psOptions->nLimit,  | 
4214  | 0  |                                          (psOptions->nGroupTransactions > 0  | 
4215  | 0  |                                               ? psOptions->nGroupTransactions  | 
4216  | 0  |                                               : 65536))));  | 
4217  | 0  |     }  | 
4218  | 0  |     else if (psOptions->nGroupTransactions > 0)  | 
4219  | 0  |     { | 
4220  | 0  |         aosOptionsGetArrowStream.SetNameValue(  | 
4221  | 0  |             "MAX_FEATURES_IN_BATCH",  | 
4222  | 0  |             CPLSPrintf("%d", psOptions->nGroupTransactions)); | 
4223  | 0  |     }  | 
4224  |  | 
  | 
4225  | 0  |     auto poSrcDS = poSrcLayer->GetDataset();  | 
4226  | 0  |     auto poDstDS = poDstLayer->GetDataset();  | 
4227  | 0  |     if (poSrcDS && poDstDS)  | 
4228  | 0  |     { | 
4229  | 0  |         auto poSrcDriver = poSrcDS->GetDriver();  | 
4230  | 0  |         auto poDstDriver = poDstDS->GetDriver();  | 
4231  |  | 
  | 
4232  | 0  |         const auto IsArrowNativeDriver = [](GDALDriver *poDriver)  | 
4233  | 0  |         { | 
4234  | 0  |             return EQUAL(poDriver->GetDescription(), "ARROW") ||  | 
4235  | 0  |                    EQUAL(poDriver->GetDescription(), "PARQUET") ||  | 
4236  | 0  |                    EQUAL(poDriver->GetDescription(), "ADBC");  | 
4237  | 0  |         };  | 
4238  |  | 
  | 
4239  | 0  |         if (poSrcDriver && poDstDriver && !IsArrowNativeDriver(poSrcDriver) &&  | 
4240  | 0  |             !IsArrowNativeDriver(poDstDriver))  | 
4241  | 0  |         { | 
4242  |  |             // For non-Arrow-native drivers, request DateTime as string, to  | 
4243  |  |             // allow mix of timezones  | 
4244  | 0  |             aosOptionsGetArrowStream.SetNameValue(GAS_OPT_DATETIME_AS_STRING,  | 
4245  | 0  |                                                   "YES");  | 
4246  | 0  |         }  | 
4247  | 0  |     }  | 
4248  |  | 
  | 
4249  | 0  |     return aosOptionsGetArrowStream;  | 
4250  | 0  | }  | 
4251  |  |  | 
4252  |  | /************************************************************************/  | 
4253  |  | /*                 SetupTargetLayer::CanUseWriteArrowBatch()            */  | 
4254  |  | /************************************************************************/  | 
4255  |  |  | 
4256  |  | bool SetupTargetLayer::CanUseWriteArrowBatch(  | 
4257  |  |     OGRLayer *poSrcLayer, OGRLayer *poDstLayer, bool bJustCreatedLayer,  | 
4258  |  |     const GDALVectorTranslateOptions *psOptions, bool bPreserveFID,  | 
4259  |  |     bool &bError, OGRArrowArrayStream &streamSrc)  | 
4260  | 0  | { | 
4261  | 0  |     bError = false;  | 
4262  |  |  | 
4263  |  |     // Check if we can use the Arrow interface to get and write features  | 
4264  |  |     // as it will be faster if the input driver has a fast  | 
4265  |  |     // implementation of GetArrowStream().  | 
4266  |  |     // We also can only do that only if using ogr2ogr without options that  | 
4267  |  |     // alter features.  | 
4268  |  |     // OGR2OGR_USE_ARROW_API config option is mostly for testing purposes  | 
4269  |  |     // or as a safety belt if things turned bad...  | 
4270  | 0  |     bool bUseWriteArrowBatch = false;  | 
4271  | 0  |     if (((poSrcLayer->TestCapability(OLCFastGetArrowStream) &&  | 
4272  |  |           // As we don't control the input array size when the input or output  | 
4273  |  |           // drivers are Arrow/Parquet (as they don't use the generic  | 
4274  |  |           // implementation), we can't guarantee that ROW_GROUP_SIZE/BATCH_SIZE  | 
4275  |  |           // layer creation options will be honored.  | 
4276  | 0  |           !psOptions->aosLCO.FetchNameValue("ROW_GROUP_SIZE") && | 
4277  | 0  |           !psOptions->aosLCO.FetchNameValue("BATCH_SIZE") && | 
4278  | 0  |           CPLTestBool(CPLGetConfigOption("OGR2OGR_USE_ARROW_API", "YES"))) || | 
4279  | 0  |          CPLTestBool(CPLGetConfigOption("OGR2OGR_USE_ARROW_API", "NO"))) && | 
4280  | 0  |         !psOptions->bUpsert && !psOptions->bSkipFailures &&  | 
4281  | 0  |         !psOptions->poClipSrc && !psOptions->poClipDst &&  | 
4282  | 0  |         psOptions->oGCPs.nGCPCount == 0 && !psOptions->bWrapDateline &&  | 
4283  | 0  |         !m_papszSelFields && !m_bAddMissingFields &&  | 
4284  | 0  |         m_eGType == GEOMTYPE_UNCHANGED && psOptions->eGeomOp == GEOMOP_NONE &&  | 
4285  | 0  |         m_eGeomTypeConversion == GTC_DEFAULT && m_nCoordDim < 0 &&  | 
4286  | 0  |         !m_papszFieldTypesToString && !m_papszMapFieldType &&  | 
4287  | 0  |         !m_bUnsetFieldWidth && !m_bExplodeCollections && !m_pszZField &&  | 
4288  | 0  |         m_bExactFieldNameMatch && !m_bForceNullable && !m_bResolveDomains &&  | 
4289  | 0  |         !m_bUnsetDefault && psOptions->nFIDToFetch == OGRNullFID &&  | 
4290  | 0  |         psOptions->dfXYRes == OGRGeomCoordinatePrecision::UNKNOWN &&  | 
4291  | 0  |         !psOptions->bMakeValid && !psOptions->bSkipInvalidGeom)  | 
4292  | 0  |     { | 
4293  | 0  |         if (psOptions->bTransform)  | 
4294  | 0  |         { | 
4295  |  |             // To simplify implementation for now  | 
4296  | 0  |             if (poSrcLayer->GetLayerDefn()->GetGeomFieldCount() != 1 ||  | 
4297  | 0  |                 poDstLayer->GetLayerDefn()->GetGeomFieldCount() != 1)  | 
4298  | 0  |             { | 
4299  | 0  |                 return false;  | 
4300  | 0  |             }  | 
4301  | 0  |             const auto poSrcSRS = m_poUserSourceSRS ? m_poUserSourceSRS  | 
4302  | 0  |                                                     : poSrcLayer->GetLayerDefn()  | 
4303  | 0  |                                                           ->GetGeomFieldDefn(0)  | 
4304  | 0  |                                                           ->GetSpatialRef();  | 
4305  | 0  |             if (!OGRGeometryFactory::isTransformWithOptionsRegularTransform(  | 
4306  | 0  |                     poSrcSRS, m_poOutputSRS, nullptr))  | 
4307  | 0  |             { | 
4308  | 0  |                 return false;  | 
4309  | 0  |             }  | 
4310  | 0  |         }  | 
4311  |  |  | 
4312  | 0  |         const CPLStringList aosGetArrowStreamOptions(BuildGetArrowStreamOptions(  | 
4313  | 0  |             poSrcLayer, poDstLayer, psOptions, bPreserveFID));  | 
4314  | 0  |         if (poSrcLayer->GetArrowStream(streamSrc.get(),  | 
4315  | 0  |                                        aosGetArrowStreamOptions.List()))  | 
4316  | 0  |         { | 
4317  | 0  |             struct ArrowSchema schemaSrc;  | 
4318  | 0  |             if (streamSrc.get_schema(&schemaSrc) == 0)  | 
4319  | 0  |             { | 
4320  | 0  |                 if (psOptions->bTransform &&  | 
4321  | 0  |                     GetArrowGeomFieldIndex(&schemaSrc,  | 
4322  | 0  |                                            poSrcLayer->GetGeometryColumn()) < 0)  | 
4323  | 0  |                 { | 
4324  | 0  |                     schemaSrc.release(&schemaSrc);  | 
4325  | 0  |                     streamSrc.clear();  | 
4326  | 0  |                     return false;  | 
4327  | 0  |                 }  | 
4328  |  |  | 
4329  | 0  |                 std::string osErrorMsg;  | 
4330  | 0  |                 if (poDstLayer->IsArrowSchemaSupported(&schemaSrc, nullptr,  | 
4331  | 0  |                                                        osErrorMsg))  | 
4332  | 0  |                 { | 
4333  | 0  |                     const OGRFeatureDefn *poSrcFDefn =  | 
4334  | 0  |                         poSrcLayer->GetLayerDefn();  | 
4335  | 0  |                     const OGRFeatureDefn *poDstFDefn =  | 
4336  | 0  |                         poDstLayer->GetLayerDefn();  | 
4337  | 0  |                     if (bJustCreatedLayer && poDstFDefn &&  | 
4338  | 0  |                         poDstFDefn->GetFieldCount() == 0 &&  | 
4339  | 0  |                         poDstFDefn->GetGeomFieldCount() ==  | 
4340  | 0  |                             poSrcFDefn->GetGeomFieldCount())  | 
4341  | 0  |                     { | 
4342  |  |                         // Create output fields using CreateFieldFromArrowSchema()  | 
4343  | 0  |                         for (int i = 0; i < schemaSrc.n_children; ++i)  | 
4344  | 0  |                         { | 
4345  | 0  |                             const char *pszFieldName =  | 
4346  | 0  |                                 schemaSrc.children[i]->name;  | 
4347  |  | 
  | 
4348  | 0  |                             const auto iSrcField =  | 
4349  | 0  |                                 poSrcFDefn->GetFieldIndex(pszFieldName);  | 
4350  | 0  |                             if (iSrcField >= 0)  | 
4351  | 0  |                             { | 
4352  | 0  |                                 const auto poSrcFieldDefn =  | 
4353  | 0  |                                     poSrcFDefn->GetFieldDefn(iSrcField);  | 
4354  |  |                                 // Create field domain in output dataset if not already existing.  | 
4355  | 0  |                                 const std::string osDomainName(  | 
4356  | 0  |                                     poSrcFieldDefn->GetDomainName());  | 
4357  | 0  |                                 if (!osDomainName.empty())  | 
4358  | 0  |                                 { | 
4359  | 0  |                                     if (m_poDstDS->TestCapability(  | 
4360  | 0  |                                             ODsCAddFieldDomain) &&  | 
4361  | 0  |                                         m_poDstDS->GetFieldDomain(  | 
4362  | 0  |                                             osDomainName) == nullptr)  | 
4363  | 0  |                                     { | 
4364  | 0  |                                         const auto poSrcDomain =  | 
4365  | 0  |                                             m_poSrcDS->GetFieldDomain(  | 
4366  | 0  |                                                 osDomainName);  | 
4367  | 0  |                                         if (poSrcDomain)  | 
4368  | 0  |                                         { | 
4369  | 0  |                                             std::string failureReason;  | 
4370  | 0  |                                             if (!m_poDstDS->AddFieldDomain(  | 
4371  | 0  |                                                     std::unique_ptr<  | 
4372  | 0  |                                                         OGRFieldDomain>(  | 
4373  | 0  |                                                         poSrcDomain->Clone()),  | 
4374  | 0  |                                                     failureReason))  | 
4375  | 0  |                                             { | 
4376  | 0  |                                                 CPLDebug("OGR2OGR", | 
4377  | 0  |                                                          "Cannot create domain "  | 
4378  | 0  |                                                          "%s: %s",  | 
4379  | 0  |                                                          osDomainName.c_str(),  | 
4380  | 0  |                                                          failureReason.c_str());  | 
4381  | 0  |                                             }  | 
4382  | 0  |                                         }  | 
4383  | 0  |                                         else  | 
4384  | 0  |                                         { | 
4385  | 0  |                                             CPLDebug("OGR2OGR", | 
4386  | 0  |                                                      "Cannot find domain %s in "  | 
4387  | 0  |                                                      "source dataset",  | 
4388  | 0  |                                                      osDomainName.c_str());  | 
4389  | 0  |                                         }  | 
4390  | 0  |                                     }  | 
4391  | 0  |                                 }  | 
4392  | 0  |                             }  | 
4393  |  | 
  | 
4394  | 0  |                             if (!EQUAL(pszFieldName, "OGC_FID") &&  | 
4395  | 0  |                                 !EQUAL(pszFieldName, "wkb_geometry") &&  | 
4396  | 0  |                                 !EQUAL(pszFieldName,  | 
4397  | 0  |                                        poSrcLayer->GetFIDColumn()) &&  | 
4398  | 0  |                                 poSrcFDefn->GetGeomFieldIndex(pszFieldName) <  | 
4399  | 0  |                                     0 &&  | 
4400  | 0  |                                 !poDstLayer->CreateFieldFromArrowSchema(  | 
4401  | 0  |                                     schemaSrc.children[i], nullptr))  | 
4402  | 0  |                             { | 
4403  | 0  |                                 CPLError(CE_Failure, CPLE_AppDefined,  | 
4404  | 0  |                                          "Cannot create field %s",  | 
4405  | 0  |                                          pszFieldName);  | 
4406  | 0  |                                 schemaSrc.release(&schemaSrc);  | 
4407  | 0  |                                 streamSrc.clear();  | 
4408  | 0  |                                 return false;  | 
4409  | 0  |                             }  | 
4410  | 0  |                         }  | 
4411  | 0  |                         bUseWriteArrowBatch = true;  | 
4412  | 0  |                     }  | 
4413  | 0  |                     else if (!bJustCreatedLayer)  | 
4414  | 0  |                     { | 
4415  |  |                         // If the layer already exist, get its schema, and  | 
4416  |  |                         // check that it looks to be the same as the source  | 
4417  |  |                         // one  | 
4418  | 0  |                         struct ArrowArrayStream streamDst;  | 
4419  | 0  |                         if (poDstLayer->GetArrowStream(  | 
4420  | 0  |                                 &streamDst, aosGetArrowStreamOptions.List()))  | 
4421  | 0  |                         { | 
4422  | 0  |                             struct ArrowSchema schemaDst;  | 
4423  | 0  |                             if (streamDst.get_schema(&streamDst, &schemaDst) ==  | 
4424  | 0  |                                 0)  | 
4425  | 0  |                             { | 
4426  | 0  |                                 if (schemaDst.n_children ==  | 
4427  | 0  |                                     schemaSrc.n_children)  | 
4428  | 0  |                                 { | 
4429  | 0  |                                     bUseWriteArrowBatch = true;  | 
4430  | 0  |                                 }  | 
4431  | 0  |                                 schemaDst.release(&schemaDst);  | 
4432  | 0  |                             }  | 
4433  | 0  |                             streamDst.release(&streamDst);  | 
4434  | 0  |                         }  | 
4435  | 0  |                     }  | 
4436  | 0  |                     if (bUseWriteArrowBatch)  | 
4437  | 0  |                     { | 
4438  | 0  |                         CPLDebug("OGR2OGR", "Using WriteArrowBatch()"); | 
4439  | 0  |                     }  | 
4440  | 0  |                 }  | 
4441  | 0  |                 else  | 
4442  | 0  |                 { | 
4443  | 0  |                     CPLDebug("OGR2OGR", | 
4444  | 0  |                              "Cannot use WriteArrowBatch() because "  | 
4445  | 0  |                              "input layer schema is not supported by output "  | 
4446  | 0  |                              "layer: %s",  | 
4447  | 0  |                              osErrorMsg.c_str());  | 
4448  | 0  |                 }  | 
4449  | 0  |                 schemaSrc.release(&schemaSrc);  | 
4450  | 0  |             }  | 
4451  | 0  |             if (!bUseWriteArrowBatch)  | 
4452  | 0  |                 streamSrc.clear();  | 
4453  | 0  |         }  | 
4454  | 0  |     }  | 
4455  | 0  |     return bUseWriteArrowBatch;  | 
4456  | 0  | }  | 
4457  |  |  | 
4458  |  | /************************************************************************/  | 
4459  |  | /*                   SetupTargetLayer::Setup()                          */  | 
4460  |  | /************************************************************************/  | 
4461  |  |  | 
4462  |  | std::unique_ptr<TargetLayerInfo>  | 
4463  |  | SetupTargetLayer::Setup(OGRLayer *poSrcLayer, const char *pszNewLayerName,  | 
4464  |  |                         GDALVectorTranslateOptions *psOptions,  | 
4465  |  |                         GIntBig &nTotalEventsDone)  | 
4466  | 0  | { | 
4467  | 0  |     int eGType = m_eGType;  | 
4468  | 0  |     bool bPreserveFID = m_bPreserveFID;  | 
4469  | 0  |     bool bAppend = m_bAppend;  | 
4470  |  | 
  | 
4471  | 0  |     if (pszNewLayerName == nullptr)  | 
4472  | 0  |         pszNewLayerName = poSrcLayer->GetName();  | 
4473  |  |  | 
4474  |  |     /* -------------------------------------------------------------------- */  | 
4475  |  |     /*      Get other info.                                                 */  | 
4476  |  |     /* -------------------------------------------------------------------- */  | 
4477  | 0  |     OGRFeatureDefn *poSrcFDefn = poSrcLayer->GetLayerDefn();  | 
4478  |  |  | 
4479  |  |     /* -------------------------------------------------------------------- */  | 
4480  |  |     /*      Find requested geometry fields.                                 */  | 
4481  |  |     /* -------------------------------------------------------------------- */  | 
4482  | 0  |     std::vector<int> anRequestedGeomFields;  | 
4483  | 0  |     const int nSrcGeomFieldCount = poSrcFDefn->GetGeomFieldCount();  | 
4484  | 0  |     if (m_bSelFieldsSet && !bAppend)  | 
4485  | 0  |     { | 
4486  | 0  |         for (int iField = 0; m_papszSelFields && m_papszSelFields[iField];  | 
4487  | 0  |              iField++)  | 
4488  | 0  |         { | 
4489  | 0  |             int iSrcField = poSrcFDefn->GetFieldIndex(m_papszSelFields[iField]);  | 
4490  | 0  |             if (iSrcField >= 0)  | 
4491  | 0  |             { | 
4492  |  |                 /* do nothing */  | 
4493  | 0  |             }  | 
4494  | 0  |             else  | 
4495  | 0  |             { | 
4496  | 0  |                 iSrcField =  | 
4497  | 0  |                     poSrcFDefn->GetGeomFieldIndex(m_papszSelFields[iField]);  | 
4498  | 0  |                 if (iSrcField >= 0)  | 
4499  | 0  |                 { | 
4500  | 0  |                     anRequestedGeomFields.push_back(iSrcField);  | 
4501  | 0  |                 }  | 
4502  | 0  |                 else  | 
4503  | 0  |                 { | 
4504  | 0  |                     CPLError(CE_Failure, CPLE_AppDefined,  | 
4505  | 0  |                              "Field '%s' not found in source layer.",  | 
4506  | 0  |                              m_papszSelFields[iField]);  | 
4507  | 0  |                     if (!psOptions->bSkipFailures)  | 
4508  | 0  |                         return nullptr;  | 
4509  | 0  |                 }  | 
4510  | 0  |             }  | 
4511  | 0  |         }  | 
4512  |  |  | 
4513  | 0  |         if (anRequestedGeomFields.size() > 1 &&  | 
4514  | 0  |             !m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))  | 
4515  | 0  |         { | 
4516  | 0  |             CPLError(CE_Failure, CPLE_AppDefined,  | 
4517  | 0  |                      "Several geometry fields requested, but output "  | 
4518  | 0  |                      "datasource does not support multiple geometry "  | 
4519  | 0  |                      "fields.");  | 
4520  | 0  |             if (!psOptions->bSkipFailures)  | 
4521  | 0  |                 return nullptr;  | 
4522  | 0  |             else  | 
4523  | 0  |                 anRequestedGeomFields.resize(0);  | 
4524  | 0  |         }  | 
4525  | 0  |     }  | 
4526  |  |  | 
4527  | 0  |     const OGRSpatialReference *poOutputSRS = m_poOutputSRS;  | 
4528  | 0  |     if (poOutputSRS == nullptr && !m_bNullifyOutputSRS)  | 
4529  | 0  |     { | 
4530  | 0  |         if (nSrcGeomFieldCount == 1 || anRequestedGeomFields.empty())  | 
4531  | 0  |             poOutputSRS = poSrcLayer->GetSpatialRef();  | 
4532  | 0  |         else if (anRequestedGeomFields.size() == 1)  | 
4533  | 0  |         { | 
4534  | 0  |             int iSrcGeomField = anRequestedGeomFields[0];  | 
4535  | 0  |             poOutputSRS =  | 
4536  | 0  |                 poSrcFDefn->GetGeomFieldDefn(iSrcGeomField)->GetSpatialRef();  | 
4537  | 0  |         }  | 
4538  | 0  |     }  | 
4539  |  | 
  | 
4540  | 0  |     int iSrcZField = -1;  | 
4541  | 0  |     if (m_pszZField != nullptr)  | 
4542  | 0  |     { | 
4543  | 0  |         iSrcZField = poSrcFDefn->GetFieldIndex(m_pszZField);  | 
4544  | 0  |         if (iSrcZField < 0)  | 
4545  | 0  |         { | 
4546  | 0  |             CPLError(CE_Warning, CPLE_AppDefined,  | 
4547  | 0  |                      "zfield '%s' does not exist in layer %s", m_pszZField,  | 
4548  | 0  |                      poSrcLayer->GetName());  | 
4549  | 0  |         }  | 
4550  | 0  |     }  | 
4551  |  |  | 
4552  |  |     /* -------------------------------------------------------------------- */  | 
4553  |  |     /*      Find the layer.                                                 */  | 
4554  |  |     /* -------------------------------------------------------------------- */  | 
4555  |  | 
  | 
4556  | 0  |     bool bErrorOccurred;  | 
4557  | 0  |     bool bOverwriteActuallyDone;  | 
4558  | 0  |     bool bAddOverwriteLCO;  | 
4559  | 0  |     OGRLayer *poDstLayer = GetLayerAndOverwriteIfNecessary(  | 
4560  | 0  |         m_poDstDS, pszNewLayerName, m_bOverwrite, &bErrorOccurred,  | 
4561  | 0  |         &bOverwriteActuallyDone, &bAddOverwriteLCO);  | 
4562  | 0  |     const bool bJustCreatedLayer = (poDstLayer == nullptr);  | 
4563  | 0  |     if (bErrorOccurred)  | 
4564  | 0  |         return nullptr;  | 
4565  |  |  | 
4566  |  |     /* -------------------------------------------------------------------- */  | 
4567  |  |     /*      If the layer does not exist, then create it.                    */  | 
4568  |  |     /* -------------------------------------------------------------------- */  | 
4569  | 0  |     if (poDstLayer == nullptr)  | 
4570  | 0  |     { | 
4571  | 0  |         if (!m_poDstDS->TestCapability(ODsCCreateLayer))  | 
4572  | 0  |         { | 
4573  | 0  |             CPLError(  | 
4574  | 0  |                 CE_Failure, CPLE_AppDefined,  | 
4575  | 0  |                 "Layer '%s' does not already exist in the output dataset, and "  | 
4576  | 0  |                 "cannot be created by the output driver.",  | 
4577  | 0  |                 pszNewLayerName);  | 
4578  | 0  |             return nullptr;  | 
4579  | 0  |         }  | 
4580  |  |  | 
4581  | 0  |         bool bForceGType = (eGType != GEOMTYPE_UNCHANGED);  | 
4582  | 0  |         if (!bForceGType)  | 
4583  | 0  |         { | 
4584  | 0  |             if (anRequestedGeomFields.empty())  | 
4585  | 0  |             { | 
4586  | 0  |                 eGType = poSrcFDefn->GetGeomType();  | 
4587  | 0  |             }  | 
4588  | 0  |             else if (anRequestedGeomFields.size() == 1)  | 
4589  | 0  |             { | 
4590  | 0  |                 int iSrcGeomField = anRequestedGeomFields[0];  | 
4591  | 0  |                 eGType = poSrcFDefn->GetGeomFieldDefn(iSrcGeomField)->GetType();  | 
4592  | 0  |             }  | 
4593  | 0  |             else  | 
4594  | 0  |             { | 
4595  | 0  |                 eGType = wkbNone;  | 
4596  | 0  |             }  | 
4597  |  | 
  | 
4598  | 0  |             bool bHasZ =  | 
4599  | 0  |                 CPL_TO_BOOL(wkbHasZ(static_cast<OGRwkbGeometryType>(eGType)));  | 
4600  | 0  |             eGType = ConvertType(m_eGeomTypeConversion,  | 
4601  | 0  |                                  static_cast<OGRwkbGeometryType>(eGType));  | 
4602  |  | 
  | 
4603  | 0  |             if (m_bExplodeCollections)  | 
4604  | 0  |             { | 
4605  | 0  |                 const OGRwkbGeometryType eFGType = wkbFlatten(eGType);  | 
4606  | 0  |                 if (eFGType == wkbMultiPoint)  | 
4607  | 0  |                 { | 
4608  | 0  |                     eGType = wkbPoint;  | 
4609  | 0  |                 }  | 
4610  | 0  |                 else if (eFGType == wkbMultiLineString)  | 
4611  | 0  |                 { | 
4612  | 0  |                     eGType = wkbLineString;  | 
4613  | 0  |                 }  | 
4614  | 0  |                 else if (eFGType == wkbMultiPolygon)  | 
4615  | 0  |                 { | 
4616  | 0  |                     eGType = wkbPolygon;  | 
4617  | 0  |                 }  | 
4618  | 0  |                 else if (eFGType == wkbGeometryCollection ||  | 
4619  | 0  |                          eFGType == wkbMultiCurve || eFGType == wkbMultiSurface)  | 
4620  | 0  |                 { | 
4621  | 0  |                     eGType = wkbUnknown;  | 
4622  | 0  |                 }  | 
4623  | 0  |             }  | 
4624  |  | 
  | 
4625  | 0  |             if (bHasZ || (iSrcZField >= 0 && eGType != wkbNone))  | 
4626  | 0  |                 eGType = wkbSetZ(static_cast<OGRwkbGeometryType>(eGType));  | 
4627  | 0  |         }  | 
4628  |  | 
  | 
4629  | 0  |         eGType = ForceCoordDimension(eGType, m_nCoordDim);  | 
4630  |  | 
  | 
4631  | 0  |         CPLErrorReset();  | 
4632  |  | 
  | 
4633  | 0  |         char **papszLCOTemp = CSLDuplicate(m_papszLCO);  | 
4634  | 0  |         const char *pszDestCreationOptions =  | 
4635  | 0  |             m_poDstDS->GetDriver()->GetMetadataItem(  | 
4636  | 0  |                 GDAL_DS_LAYER_CREATIONOPTIONLIST);  | 
4637  |  | 
  | 
4638  | 0  |         int eGCreateLayerType = eGType;  | 
4639  | 0  |         if (anRequestedGeomFields.empty() && nSrcGeomFieldCount > 1 &&  | 
4640  | 0  |             m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))  | 
4641  | 0  |         { | 
4642  | 0  |             eGCreateLayerType = wkbNone;  | 
4643  | 0  |         }  | 
4644  |  |         // If the source layer has a single geometry column that is not nullable  | 
4645  |  |         // and that ODsCCreateGeomFieldAfterCreateLayer is available, use it  | 
4646  |  |         // so as to be able to set the not null constraint (if the driver  | 
4647  |  |         // supports it) and that the output driver has no GEOMETRY_NULLABLE  | 
4648  |  |         // layer creation option. Same if the source geometry column has a non  | 
4649  |  |         // empty name that is not overridden, and that the output driver has no  | 
4650  |  |         // GEOMETRY_NAME layer creation option, but no LAUNDER option (if  | 
4651  |  |         // laundering is available, then we might want to launder the geometry  | 
4652  |  |         // column name as well)  | 
4653  | 0  |         else if (eGType != wkbNone && anRequestedGeomFields.empty() &&  | 
4654  | 0  |                  nSrcGeomFieldCount == 1 &&  | 
4655  | 0  |                  m_poDstDS->TestCapability(  | 
4656  | 0  |                      ODsCCreateGeomFieldAfterCreateLayer) &&  | 
4657  | 0  |                  ((!poSrcFDefn->GetGeomFieldDefn(0)->IsNullable() &&  | 
4658  | 0  |                    CSLFetchNameValue(m_papszLCO, "GEOMETRY_NULLABLE") ==  | 
4659  | 0  |                        nullptr &&  | 
4660  | 0  |                    (pszDestCreationOptions == nullptr ||  | 
4661  | 0  |                     strstr(pszDestCreationOptions, "GEOMETRY_NULLABLE") !=  | 
4662  | 0  |                         nullptr) &&  | 
4663  | 0  |                    !m_bForceNullable) ||  | 
4664  | 0  |                   (poSrcLayer->GetGeometryColumn() != nullptr &&  | 
4665  | 0  |                    CSLFetchNameValue(m_papszLCO, "GEOMETRY_NAME") == nullptr &&  | 
4666  | 0  |                    !EQUAL(poSrcLayer->GetGeometryColumn(), "") &&  | 
4667  | 0  |                    (pszDestCreationOptions == nullptr ||  | 
4668  | 0  |                     strstr(pszDestCreationOptions, "GEOMETRY_NAME") ==  | 
4669  | 0  |                         nullptr ||  | 
4670  | 0  |                     strstr(pszDestCreationOptions, "LAUNDER") != nullptr) &&  | 
4671  | 0  |                    poSrcFDefn->GetFieldIndex(poSrcLayer->GetGeometryColumn()) <  | 
4672  | 0  |                        0)))  | 
4673  | 0  |         { | 
4674  | 0  |             anRequestedGeomFields.push_back(0);  | 
4675  | 0  |             eGCreateLayerType = wkbNone;  | 
4676  | 0  |         }  | 
4677  | 0  |         else if (anRequestedGeomFields.size() == 1 &&  | 
4678  | 0  |                  m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))  | 
4679  | 0  |         { | 
4680  | 0  |             eGCreateLayerType = wkbNone;  | 
4681  | 0  |         }  | 
4682  |  | 
  | 
4683  | 0  |         OGRGeomCoordinatePrecision oCoordPrec;  | 
4684  | 0  |         std::string osGeomFieldName;  | 
4685  | 0  |         bool bGeomFieldNullable = true;  | 
4686  |  | 
  | 
4687  | 0  |         { | 
4688  | 0  |             int iSrcGeomField = -1;  | 
4689  | 0  |             if (anRequestedGeomFields.empty() &&  | 
4690  | 0  |                 (nSrcGeomFieldCount == 1 ||  | 
4691  | 0  |                  (!m_poDstDS->TestCapability(  | 
4692  | 0  |                       ODsCCreateGeomFieldAfterCreateLayer) &&  | 
4693  | 0  |                   nSrcGeomFieldCount > 1)))  | 
4694  | 0  |             { | 
4695  | 0  |                 iSrcGeomField = 0;  | 
4696  | 0  |             }  | 
4697  | 0  |             else if (anRequestedGeomFields.size() == 1)  | 
4698  | 0  |             { | 
4699  | 0  |                 iSrcGeomField = anRequestedGeomFields[0];  | 
4700  | 0  |             }  | 
4701  |  | 
  | 
4702  | 0  |             if (iSrcGeomField >= 0)  | 
4703  | 0  |             { | 
4704  | 0  |                 const auto poSrcGeomFieldDefn =  | 
4705  | 0  |                     poSrcFDefn->GetGeomFieldDefn(iSrcGeomField);  | 
4706  | 0  |                 if (!psOptions->bUnsetCoordPrecision)  | 
4707  | 0  |                 { | 
4708  | 0  |                     oCoordPrec = poSrcGeomFieldDefn->GetCoordinatePrecision()  | 
4709  | 0  |                                      .ConvertToOtherSRS(  | 
4710  | 0  |                                          poSrcGeomFieldDefn->GetSpatialRef(),  | 
4711  | 0  |                                          poOutputSRS);  | 
4712  | 0  |                 }  | 
4713  |  | 
  | 
4714  | 0  |                 bGeomFieldNullable =  | 
4715  | 0  |                     CPL_TO_BOOL(poSrcGeomFieldDefn->IsNullable());  | 
4716  |  | 
  | 
4717  | 0  |                 const char *pszGFldName = poSrcGeomFieldDefn->GetNameRef();  | 
4718  | 0  |                 if (pszGFldName != nullptr && !EQUAL(pszGFldName, "") &&  | 
4719  | 0  |                     poSrcFDefn->GetFieldIndex(pszGFldName) < 0)  | 
4720  | 0  |                 { | 
4721  | 0  |                     osGeomFieldName = pszGFldName;  | 
4722  |  |  | 
4723  |  |                     // Use source geometry field name as much as possible  | 
4724  | 0  |                     if (eGType != wkbNone && pszDestCreationOptions &&  | 
4725  | 0  |                         strstr(pszDestCreationOptions, "GEOMETRY_NAME") !=  | 
4726  | 0  |                             nullptr &&  | 
4727  | 0  |                         CSLFetchNameValue(m_papszLCO, "GEOMETRY_NAME") ==  | 
4728  | 0  |                             nullptr)  | 
4729  | 0  |                     { | 
4730  | 0  |                         papszLCOTemp = CSLSetNameValue(  | 
4731  | 0  |                             papszLCOTemp, "GEOMETRY_NAME", pszGFldName);  | 
4732  | 0  |                     }  | 
4733  | 0  |                 }  | 
4734  | 0  |             }  | 
4735  | 0  |         }  | 
4736  |  |  | 
4737  |  |         // If the source feature first geometry column is not nullable  | 
4738  |  |         // and that GEOMETRY_NULLABLE creation option is available, use it  | 
4739  |  |         // so as to be able to set the not null constraint (if the driver  | 
4740  |  |         // supports it)  | 
4741  | 0  |         if (eGType != wkbNone && anRequestedGeomFields.empty() &&  | 
4742  | 0  |             nSrcGeomFieldCount >= 1 &&  | 
4743  | 0  |             !poSrcFDefn->GetGeomFieldDefn(0)->IsNullable() &&  | 
4744  | 0  |             pszDestCreationOptions != nullptr &&  | 
4745  | 0  |             strstr(pszDestCreationOptions, "GEOMETRY_NULLABLE") != nullptr &&  | 
4746  | 0  |             CSLFetchNameValue(m_papszLCO, "GEOMETRY_NULLABLE") == nullptr &&  | 
4747  | 0  |             !m_bForceNullable)  | 
4748  | 0  |         { | 
4749  | 0  |             bGeomFieldNullable = false;  | 
4750  | 0  |             papszLCOTemp =  | 
4751  | 0  |                 CSLSetNameValue(papszLCOTemp, "GEOMETRY_NULLABLE", "NO");  | 
4752  | 0  |             CPLDebug("GDALVectorTranslate", "Using GEOMETRY_NULLABLE=NO"); | 
4753  | 0  |         }  | 
4754  |  | 
  | 
4755  | 0  |         if (psOptions->dfXYRes != OGRGeomCoordinatePrecision::UNKNOWN)  | 
4756  | 0  |         { | 
4757  | 0  |             if (m_poDstDS->GetDriver()->GetMetadataItem(  | 
4758  | 0  |                     GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION) == nullptr &&  | 
4759  | 0  |                 !OGRGeometryFactory::haveGEOS())  | 
4760  | 0  |             { | 
4761  | 0  |                 CPLError(CE_Warning, CPLE_AppDefined,  | 
4762  | 0  |                          "-xyRes specified, but driver does not expose the "  | 
4763  | 0  |                          "DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, "  | 
4764  | 0  |                          "and this build has no GEOS support");  | 
4765  | 0  |             }  | 
4766  |  | 
  | 
4767  | 0  |             oCoordPrec.dfXYResolution = psOptions->dfXYRes;  | 
4768  | 0  |             if (!psOptions->osXYResUnit.empty())  | 
4769  | 0  |             { | 
4770  | 0  |                 if (!poOutputSRS)  | 
4771  | 0  |                 { | 
4772  | 0  |                     CSLDestroy(papszLCOTemp);  | 
4773  | 0  |                     CPLError(CE_Failure, CPLE_AppDefined,  | 
4774  | 0  |                              "Unit suffix for -xyRes cannot be used with an "  | 
4775  | 0  |                              "unknown destination SRS");  | 
4776  | 0  |                     return nullptr;  | 
4777  | 0  |                 }  | 
4778  |  |  | 
4779  | 0  |                 if (psOptions->osXYResUnit == "mm")  | 
4780  | 0  |                 { | 
4781  | 0  |                     oCoordPrec.dfXYResolution *= 1e-3;  | 
4782  | 0  |                 }  | 
4783  | 0  |                 else if (psOptions->osXYResUnit == "deg")  | 
4784  | 0  |                 { | 
4785  | 0  |                     double dfFactorDegToMeter =  | 
4786  | 0  |                         poOutputSRS->GetSemiMajor(nullptr) * M_PI / 180;  | 
4787  | 0  |                     oCoordPrec.dfXYResolution *= dfFactorDegToMeter;  | 
4788  | 0  |                 }  | 
4789  | 0  |                 else  | 
4790  | 0  |                 { | 
4791  |  |                     // Checked at argument parsing time  | 
4792  | 0  |                     CPLAssert(psOptions->osXYResUnit == "m");  | 
4793  | 0  |                 }  | 
4794  |  |  | 
4795  | 0  |                 OGRGeomCoordinatePrecision tmp;  | 
4796  | 0  |                 tmp.SetFromMeter(poOutputSRS, oCoordPrec.dfXYResolution, 0, 0);  | 
4797  | 0  |                 oCoordPrec.dfXYResolution = tmp.dfXYResolution;  | 
4798  | 0  |             }  | 
4799  | 0  |         }  | 
4800  |  |  | 
4801  | 0  |         if (psOptions->dfZRes != OGRGeomCoordinatePrecision::UNKNOWN)  | 
4802  | 0  |         { | 
4803  | 0  |             if (m_poDstDS->GetDriver()->GetMetadataItem(  | 
4804  | 0  |                     GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION) == nullptr)  | 
4805  | 0  |             { | 
4806  | 0  |                 CPLError(CE_Warning, CPLE_AppDefined,  | 
4807  | 0  |                          "-zRes specified, but driver does not expose the "  | 
4808  | 0  |                          "DCAP_HONOR_GEOM_COORDINATE_PRECISION capability");  | 
4809  | 0  |             }  | 
4810  |  | 
  | 
4811  | 0  |             oCoordPrec.dfZResolution = psOptions->dfZRes;  | 
4812  | 0  |             if (!psOptions->osZResUnit.empty())  | 
4813  | 0  |             { | 
4814  | 0  |                 if (!poOutputSRS)  | 
4815  | 0  |                 { | 
4816  | 0  |                     CSLDestroy(papszLCOTemp);  | 
4817  | 0  |                     CPLError(CE_Failure, CPLE_AppDefined,  | 
4818  | 0  |                              "Unit suffix for -zRes cannot be used with an "  | 
4819  | 0  |                              "unknown destination SRS");  | 
4820  | 0  |                     return nullptr;  | 
4821  | 0  |                 }  | 
4822  |  |  | 
4823  | 0  |                 if (psOptions->osZResUnit == "mm")  | 
4824  | 0  |                 { | 
4825  | 0  |                     oCoordPrec.dfZResolution *= 1e-3;  | 
4826  | 0  |                 }  | 
4827  | 0  |                 else  | 
4828  | 0  |                 { | 
4829  |  |                     // Checked at argument parsing time  | 
4830  | 0  |                     CPLAssert(psOptions->osZResUnit == "m");  | 
4831  | 0  |                 }  | 
4832  |  |  | 
4833  | 0  |                 OGRGeomCoordinatePrecision tmp;  | 
4834  | 0  |                 tmp.SetFromMeter(poOutputSRS, 0, oCoordPrec.dfZResolution, 0);  | 
4835  | 0  |                 oCoordPrec.dfZResolution = tmp.dfZResolution;  | 
4836  | 0  |             }  | 
4837  | 0  |         }  | 
4838  |  |  | 
4839  | 0  |         if (psOptions->dfMRes != OGRGeomCoordinatePrecision::UNKNOWN)  | 
4840  | 0  |         { | 
4841  | 0  |             if (m_poDstDS->GetDriver()->GetMetadataItem(  | 
4842  | 0  |                     GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION) == nullptr)  | 
4843  | 0  |             { | 
4844  | 0  |                 CPLError(CE_Warning, CPLE_AppDefined,  | 
4845  | 0  |                          "-mRes specified, but driver does not expose the "  | 
4846  | 0  |                          "DCAP_HONOR_GEOM_COORDINATE_PRECISION capability");  | 
4847  | 0  |             }  | 
4848  |  | 
  | 
4849  | 0  |             oCoordPrec.dfMResolution = psOptions->dfMRes;  | 
4850  | 0  |         }  | 
4851  |  | 
  | 
4852  | 0  |         auto poSrcDriver = m_poSrcDS->GetDriver();  | 
4853  |  |  | 
4854  |  |         // Force FID column as 64 bit if the source feature has a 64 bit FID,  | 
4855  |  |         // the target driver supports 64 bit FID and the user didn't set it  | 
4856  |  |         // manually.  | 
4857  | 0  |         if (poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&  | 
4858  | 0  |             EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES") &&  | 
4859  | 0  |             pszDestCreationOptions &&  | 
4860  | 0  |             strstr(pszDestCreationOptions, "FID64") != nullptr &&  | 
4861  | 0  |             CSLFetchNameValue(m_papszLCO, "FID64") == nullptr)  | 
4862  | 0  |         { | 
4863  | 0  |             papszLCOTemp = CSLSetNameValue(papszLCOTemp, "FID64", "YES");  | 
4864  | 0  |             CPLDebug("GDALVectorTranslate", "Using FID64=YES"); | 
4865  | 0  |         }  | 
4866  |  |  | 
4867  |  |         // If output driver supports FID layer creation option, set it with  | 
4868  |  |         // the FID column name of the source layer  | 
4869  | 0  |         if (!m_bUnsetFid && !bAppend && poSrcLayer->GetFIDColumn() != nullptr &&  | 
4870  | 0  |             !EQUAL(poSrcLayer->GetFIDColumn(), "") &&  | 
4871  | 0  |             pszDestCreationOptions != nullptr &&  | 
4872  | 0  |             (strstr(pszDestCreationOptions, "='FID'") != nullptr ||  | 
4873  | 0  |              strstr(pszDestCreationOptions, "=\"FID\"") != nullptr) &&  | 
4874  | 0  |             CSLFetchNameValue(m_papszLCO, "FID") == nullptr)  | 
4875  | 0  |         { | 
4876  | 0  |             papszLCOTemp = CSLSetNameValue(papszLCOTemp, "FID",  | 
4877  | 0  |                                            poSrcLayer->GetFIDColumn());  | 
4878  | 0  |             if (!psOptions->bExplodeCollections)  | 
4879  | 0  |             { | 
4880  | 0  |                 CPLDebug("GDALVectorTranslate", | 
4881  | 0  |                          "Using FID=%s and -preserve_fid",  | 
4882  | 0  |                          poSrcLayer->GetFIDColumn());  | 
4883  | 0  |                 bPreserveFID = true;  | 
4884  | 0  |             }  | 
4885  | 0  |             else  | 
4886  | 0  |             { | 
4887  | 0  |                 CPLDebug("GDALVectorTranslate", | 
4888  | 0  |                          "Using FID=%s and disable -preserve_fid because not "  | 
4889  | 0  |                          "compatible with -explodecollection",  | 
4890  | 0  |                          poSrcLayer->GetFIDColumn());  | 
4891  | 0  |                 bPreserveFID = false;  | 
4892  | 0  |             }  | 
4893  | 0  |         }  | 
4894  |  |         // Detect scenario of converting from GPX to a format like GPKG  | 
4895  |  |         // Cf https://github.com/OSGeo/gdal/issues/9225  | 
4896  | 0  |         else if (!bPreserveFID && !m_bUnsetFid && !bAppend && poSrcDriver &&  | 
4897  | 0  |                  EQUAL(poSrcDriver->GetDescription(), "GPX") &&  | 
4898  | 0  |                  pszDestCreationOptions &&  | 
4899  | 0  |                  (strstr(pszDestCreationOptions, "='FID'") != nullptr ||  | 
4900  | 0  |                   strstr(pszDestCreationOptions, "=\"FID\"") != nullptr) &&  | 
4901  | 0  |                  CSLFetchNameValue(m_papszLCO, "FID") == nullptr)  | 
4902  | 0  |         { | 
4903  | 0  |             CPLDebug("GDALVectorTranslate", | 
4904  | 0  |                      "Forcing -preserve_fid because source is GPX and layers "  | 
4905  | 0  |                      "have FID cross references");  | 
4906  | 0  |             bPreserveFID = true;  | 
4907  | 0  |         }  | 
4908  |  |         // Detect scenario of converting GML2 with fid attribute to GPKG  | 
4909  | 0  |         else if (EQUAL(m_poDstDS->GetDriver()->GetDescription(), "GPKG") &&  | 
4910  | 0  |                  CSLFetchNameValue(m_papszLCO, "FID") == nullptr)  | 
4911  | 0  |         { | 
4912  | 0  |             int nFieldIdx = poSrcLayer->GetLayerDefn()->GetFieldIndex("fid"); | 
4913  | 0  |             if (nFieldIdx >= 0 && poSrcLayer->GetLayerDefn()  | 
4914  | 0  |                                           ->GetFieldDefn(nFieldIdx)  | 
4915  | 0  |                                           ->GetType() == OFTString)  | 
4916  | 0  |             { | 
4917  | 0  |                 CPLDebug("GDALVectorTranslate", | 
4918  | 0  |                          "Source layer has a non-string 'fid' column. Using "  | 
4919  | 0  |                          "FID=gpkg_fid for GeoPackage");  | 
4920  | 0  |                 papszLCOTemp = CSLSetNameValue(papszLCOTemp, "FID", "gpkg_fid");  | 
4921  | 0  |             }  | 
4922  | 0  |         }  | 
4923  |  |  | 
4924  |  |         // If bAddOverwriteLCO is ON (set up when overwriting a CARTO layer),  | 
4925  |  |         // set OVERWRITE to YES so the new layer overwrites the old one  | 
4926  | 0  |         if (bAddOverwriteLCO)  | 
4927  | 0  |         { | 
4928  | 0  |             papszLCOTemp = CSLSetNameValue(papszLCOTemp, "OVERWRITE", "ON");  | 
4929  | 0  |             CPLDebug("GDALVectorTranslate", "Using OVERWRITE=ON"); | 
4930  | 0  |         }  | 
4931  |  | 
  | 
4932  | 0  |         if (m_bNativeData &&  | 
4933  | 0  |             poSrcLayer->GetMetadataItem("NATIVE_DATA", "NATIVE_DATA") != | 
4934  | 0  |                 nullptr &&  | 
4935  | 0  |             poSrcLayer->GetMetadataItem("NATIVE_MEDIA_TYPE", "NATIVE_DATA") != | 
4936  | 0  |                 nullptr &&  | 
4937  | 0  |             pszDestCreationOptions != nullptr &&  | 
4938  | 0  |             strstr(pszDestCreationOptions, "NATIVE_DATA") != nullptr &&  | 
4939  | 0  |             strstr(pszDestCreationOptions, "NATIVE_MEDIA_TYPE") != nullptr)  | 
4940  | 0  |         { | 
4941  | 0  |             papszLCOTemp = CSLSetNameValue(  | 
4942  | 0  |                 papszLCOTemp, "NATIVE_DATA",  | 
4943  | 0  |                 poSrcLayer->GetMetadataItem("NATIVE_DATA", "NATIVE_DATA")); | 
4944  | 0  |             papszLCOTemp =  | 
4945  | 0  |                 CSLSetNameValue(papszLCOTemp, "NATIVE_MEDIA_TYPE",  | 
4946  | 0  |                                 poSrcLayer->GetMetadataItem("NATIVE_MEDIA_TYPE", | 
4947  | 0  |                                                             "NATIVE_DATA"));  | 
4948  | 0  |             CPLDebug("GDALVectorTranslate", "Transferring layer NATIVE_DATA"); | 
4949  | 0  |         }  | 
4950  |  |  | 
4951  |  |         // For FileGeodatabase, automatically set  | 
4952  |  |         // CREATE_SHAPE_AREA_AND_LENGTH_FIELDS=YES creation option if the source  | 
4953  |  |         // layer has a Shape_Area/Shape_Length field  | 
4954  | 0  |         if (pszDestCreationOptions &&  | 
4955  | 0  |             strstr(pszDestCreationOptions,  | 
4956  | 0  |                    "CREATE_SHAPE_AREA_AND_LENGTH_FIELDS") != nullptr &&  | 
4957  | 0  |             CSLFetchNameValue(m_papszLCO,  | 
4958  | 0  |                               "CREATE_SHAPE_AREA_AND_LENGTH_FIELDS") == nullptr)  | 
4959  | 0  |         { | 
4960  | 0  |             const auto poSrcLayerDefn = poSrcLayer->GetLayerDefn();  | 
4961  | 0  |             const int nIdxShapeArea =  | 
4962  | 0  |                 poSrcLayerDefn->GetFieldIndex("Shape_Area"); | 
4963  | 0  |             const int nIdxShapeLength =  | 
4964  | 0  |                 poSrcLayerDefn->GetFieldIndex("Shape_Length"); | 
4965  | 0  |             if ((nIdxShapeArea >= 0 &&  | 
4966  | 0  |                  poSrcLayerDefn->GetFieldDefn(nIdxShapeArea)->GetDefault() !=  | 
4967  | 0  |                      nullptr &&  | 
4968  | 0  |                  EQUAL(  | 
4969  | 0  |                      poSrcLayerDefn->GetFieldDefn(nIdxShapeArea)->GetDefault(),  | 
4970  | 0  |                      "FILEGEODATABASE_SHAPE_AREA") &&  | 
4971  | 0  |                  (m_papszSelFields == nullptr ||  | 
4972  | 0  |                   CSLFindString(m_papszSelFields, "Shape_Area") >= 0)) ||  | 
4973  | 0  |                 (nIdxShapeLength >= 0 &&  | 
4974  | 0  |                  poSrcLayerDefn->GetFieldDefn(nIdxShapeLength)->GetDefault() !=  | 
4975  | 0  |                      nullptr &&  | 
4976  | 0  |                  EQUAL(poSrcLayerDefn->GetFieldDefn(nIdxShapeLength)  | 
4977  | 0  |                            ->GetDefault(),  | 
4978  | 0  |                        "FILEGEODATABASE_SHAPE_LENGTH") &&  | 
4979  | 0  |                  (m_papszSelFields == nullptr ||  | 
4980  | 0  |                   CSLFindString(m_papszSelFields, "Shape_Length") >= 0)))  | 
4981  | 0  |             { | 
4982  | 0  |                 papszLCOTemp = CSLSetNameValue(  | 
4983  | 0  |                     papszLCOTemp, "CREATE_SHAPE_AREA_AND_LENGTH_FIELDS", "YES");  | 
4984  | 0  |                 CPLDebug("GDALVectorTranslate", | 
4985  | 0  |                          "Setting CREATE_SHAPE_AREA_AND_LENGTH_FIELDS=YES");  | 
4986  | 0  |             }  | 
4987  | 0  |         }  | 
4988  |  |  | 
4989  |  |         // Use case of https://github.com/OSGeo/gdal/issues/11057#issuecomment-2495479779  | 
4990  |  |         // Conversion from GPKG to OCI.  | 
4991  |  |         // OCI distinguishes between TIMESTAMP and TIMESTAMP WITH TIME ZONE  | 
4992  |  |         // GeoPackage is supposed to have DateTime in UTC, so we set  | 
4993  |  |         // TIMESTAMP_WITH_TIME_ZONE=YES  | 
4994  | 0  |         if (poSrcDriver && pszDestCreationOptions &&  | 
4995  | 0  |             strstr(pszDestCreationOptions, "TIMESTAMP_WITH_TIME_ZONE") &&  | 
4996  | 0  |             CSLFetchNameValue(m_papszLCO, "TIMESTAMP_WITH_TIME_ZONE") ==  | 
4997  | 0  |                 nullptr &&  | 
4998  | 0  |             EQUAL(poSrcDriver->GetDescription(), "GPKG"))  | 
4999  | 0  |         { | 
5000  | 0  |             papszLCOTemp = CSLSetNameValue(papszLCOTemp,  | 
5001  | 0  |                                            "TIMESTAMP_WITH_TIME_ZONE", "YES");  | 
5002  | 0  |             CPLDebug("GDALVectorTranslate", | 
5003  | 0  |                      "Setting TIMESTAMP_WITH_TIME_ZONE=YES");  | 
5004  | 0  |         }  | 
5005  |  | 
  | 
5006  | 0  |         OGRGeomFieldDefn oGeomFieldDefn(  | 
5007  | 0  |             osGeomFieldName.c_str(),  | 
5008  | 0  |             static_cast<OGRwkbGeometryType>(eGCreateLayerType));  | 
5009  | 0  |         oGeomFieldDefn.SetSpatialRef(poOutputSRS);  | 
5010  | 0  |         oGeomFieldDefn.SetCoordinatePrecision(oCoordPrec);  | 
5011  | 0  |         oGeomFieldDefn.SetNullable(bGeomFieldNullable);  | 
5012  | 0  |         poDstLayer = m_poDstDS->CreateLayer(  | 
5013  | 0  |             pszNewLayerName,  | 
5014  | 0  |             eGCreateLayerType == wkbNone ? nullptr : &oGeomFieldDefn,  | 
5015  | 0  |             papszLCOTemp);  | 
5016  | 0  |         CSLDestroy(papszLCOTemp);  | 
5017  |  | 
  | 
5018  | 0  |         if (poDstLayer == nullptr)  | 
5019  | 0  |         { | 
5020  | 0  |             return nullptr;  | 
5021  | 0  |         }  | 
5022  |  |  | 
5023  |  |         // Cf https://github.com/OSGeo/gdal/issues/6859  | 
5024  |  |         // warn if the user requests -t_srs but the driver uses a different SRS.  | 
5025  | 0  |         if (m_poOutputSRS != nullptr && m_bTransform && !psOptions->bQuiet &&  | 
5026  |  |             // MapInfo is somewhat lossy regarding SRS, so do not warn  | 
5027  | 0  |             !EQUAL(m_poDstDS->GetDriver()->GetDescription(), "MapInfo File"))  | 
5028  | 0  |         { | 
5029  | 0  |             auto poCreatedSRS = poDstLayer->GetSpatialRef();  | 
5030  | 0  |             if (poCreatedSRS != nullptr)  | 
5031  | 0  |             { | 
5032  | 0  |                 const char *const apszOptions[] = { | 
5033  | 0  |                     "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES",  | 
5034  | 0  |                     "CRITERION=EQUIVALENT", nullptr};  | 
5035  | 0  |                 if (!poCreatedSRS->IsSame(m_poOutputSRS, apszOptions))  | 
5036  | 0  |                 { | 
5037  | 0  |                     const char *pszTargetSRSName = m_poOutputSRS->GetName();  | 
5038  | 0  |                     const char *pszCreatedSRSName = poCreatedSRS->GetName();  | 
5039  | 0  |                     CPLError(CE_Warning, CPLE_AppDefined,  | 
5040  | 0  |                              "Target SRS %s not taken into account as target "  | 
5041  | 0  |                              "driver likely implements on-the-fly reprojection "  | 
5042  | 0  |                              "to %s",  | 
5043  | 0  |                              pszTargetSRSName ? pszTargetSRSName : "",  | 
5044  | 0  |                              pszCreatedSRSName ? pszCreatedSRSName : "");  | 
5045  | 0  |                 }  | 
5046  | 0  |             }  | 
5047  | 0  |         }  | 
5048  |  | 
  | 
5049  | 0  |         if (m_bCopyMD)  | 
5050  | 0  |         { | 
5051  | 0  |             const CPLStringList aosDomains(poSrcLayer->GetMetadataDomainList());  | 
5052  | 0  |             for (const char *pszMD : aosDomains)  | 
5053  | 0  |             { | 
5054  | 0  |                 if (!EQUAL(pszMD, "IMAGE_STRUCTURE") &&  | 
5055  | 0  |                     !EQUAL(pszMD, "SUBDATASETS"))  | 
5056  | 0  |                 { | 
5057  | 0  |                     if (char **papszMD = poSrcLayer->GetMetadata(pszMD))  | 
5058  | 0  |                         poDstLayer->SetMetadata(papszMD, pszMD);  | 
5059  | 0  |                 }  | 
5060  | 0  |             }  | 
5061  | 0  |         }  | 
5062  |  | 
  | 
5063  | 0  |         if (anRequestedGeomFields.empty() && nSrcGeomFieldCount > 1 &&  | 
5064  | 0  |             m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))  | 
5065  | 0  |         { | 
5066  | 0  |             for (int i = 0; i < nSrcGeomFieldCount; i++)  | 
5067  | 0  |             { | 
5068  | 0  |                 anRequestedGeomFields.push_back(i);  | 
5069  | 0  |             }  | 
5070  | 0  |         }  | 
5071  |  | 
  | 
5072  | 0  |         if (anRequestedGeomFields.size() > 1 ||  | 
5073  | 0  |             (anRequestedGeomFields.size() == 1 &&  | 
5074  | 0  |              m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer)))  | 
5075  | 0  |         { | 
5076  | 0  |             for (int i = 0; i < static_cast<int>(anRequestedGeomFields.size());  | 
5077  | 0  |                  i++)  | 
5078  | 0  |             { | 
5079  | 0  |                 const int iSrcGeomField = anRequestedGeomFields[i];  | 
5080  | 0  |                 OGRGeomFieldDefn oGFldDefn(  | 
5081  | 0  |                     poSrcFDefn->GetGeomFieldDefn(iSrcGeomField));  | 
5082  | 0  |                 if (m_poOutputSRS != nullptr)  | 
5083  | 0  |                 { | 
5084  | 0  |                     auto poOutputSRSClone = m_poOutputSRS->Clone();  | 
5085  | 0  |                     oGFldDefn.SetSpatialRef(poOutputSRSClone);  | 
5086  | 0  |                     poOutputSRSClone->Release();  | 
5087  | 0  |                 }  | 
5088  | 0  |                 if (bForceGType)  | 
5089  | 0  |                 { | 
5090  | 0  |                     oGFldDefn.SetType(static_cast<OGRwkbGeometryType>(eGType));  | 
5091  | 0  |                 }  | 
5092  | 0  |                 else  | 
5093  | 0  |                 { | 
5094  | 0  |                     eGType = oGFldDefn.GetType();  | 
5095  | 0  |                     eGType =  | 
5096  | 0  |                         ConvertType(m_eGeomTypeConversion,  | 
5097  | 0  |                                     static_cast<OGRwkbGeometryType>(eGType));  | 
5098  | 0  |                     eGType = ForceCoordDimension(eGType, m_nCoordDim);  | 
5099  | 0  |                     oGFldDefn.SetType(static_cast<OGRwkbGeometryType>(eGType));  | 
5100  | 0  |                 }  | 
5101  | 0  |                 if (m_bForceNullable)  | 
5102  | 0  |                     oGFldDefn.SetNullable(TRUE);  | 
5103  | 0  |                 poDstLayer->CreateGeomField(&oGFldDefn);  | 
5104  | 0  |             }  | 
5105  | 0  |         }  | 
5106  |  | 
  | 
5107  | 0  |         bAppend = false;  | 
5108  | 0  |     }  | 
5109  |  |  | 
5110  |  |     /* -------------------------------------------------------------------- */  | 
5111  |  |     /*      Otherwise we will append to it, if append was requested.        */  | 
5112  |  |     /* -------------------------------------------------------------------- */  | 
5113  | 0  |     else if (!bAppend && !m_bNewDataSource)  | 
5114  | 0  |     { | 
5115  | 0  |         if (psOptions->bInvokedFromGdalVectorConvert)  | 
5116  | 0  |         { | 
5117  | 0  |             CPLError(CE_Failure, CPLE_AppDefined,  | 
5118  | 0  |                      "Layer %s already exists, and --append not specified. "  | 
5119  | 0  |                      "Consider using --append, or --overwrite-layer.",  | 
5120  | 0  |                      pszNewLayerName);  | 
5121  | 0  |         }  | 
5122  | 0  |         else  | 
5123  | 0  |         { | 
5124  | 0  |             CPLError(CE_Failure, CPLE_AppDefined,  | 
5125  | 0  |                      "Layer %s already exists, and -append not specified.\n"  | 
5126  | 0  |                      "        Consider using -append, or -overwrite.",  | 
5127  | 0  |                      pszNewLayerName);  | 
5128  | 0  |         }  | 
5129  | 0  |         return nullptr;  | 
5130  | 0  |     }  | 
5131  | 0  |     else  | 
5132  | 0  |     { | 
5133  | 0  |         if (CSLCount(m_papszLCO) > 0)  | 
5134  | 0  |         { | 
5135  | 0  |             CPLError(  | 
5136  | 0  |                 CE_Warning, CPLE_AppDefined,  | 
5137  | 0  |                 "Layer creation options ignored since an existing layer is\n"  | 
5138  | 0  |                 "         being appended to.");  | 
5139  | 0  |         }  | 
5140  | 0  |     }  | 
5141  |  |  | 
5142  |  |     /* -------------------------------------------------------------------- */  | 
5143  |  |     /*      Process Layer style table                                       */  | 
5144  |  |     /* -------------------------------------------------------------------- */  | 
5145  |  |  | 
5146  | 0  |     poDstLayer->SetStyleTable(poSrcLayer->GetStyleTable());  | 
5147  |  |     /* -------------------------------------------------------------------- */  | 
5148  |  |     /*      Add fields.  Default to copy all field.                         */  | 
5149  |  |     /*      If only a subset of all fields requested, then output only      */  | 
5150  |  |     /*      the selected fields, and in the order that they were            */  | 
5151  |  |     /*      selected.                                                       */  | 
5152  |  |     /* -------------------------------------------------------------------- */  | 
5153  | 0  |     const int nSrcFieldCount = poSrcFDefn->GetFieldCount();  | 
5154  | 0  |     int iSrcFIDField = -1;  | 
5155  |  |  | 
5156  |  |     // Initialize the index-to-index map to -1's  | 
5157  | 0  |     std::vector<int> anMap(nSrcFieldCount, -1);  | 
5158  |  | 
  | 
5159  | 0  |     std::map<int, TargetLayerInfo::ResolvedInfo> oMapResolved;  | 
5160  |  |  | 
5161  |  |     /* Determine if NUMERIC field width narrowing is allowed */  | 
5162  | 0  |     auto poSrcDriver = m_poSrcDS->GetDriver();  | 
5163  | 0  |     const char *pszSrcWidthIncludesDecimalSeparator{ | 
5164  | 0  |         poSrcDriver ? poSrcDriver->GetMetadataItem(  | 
5165  | 0  |                           "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_DECIMAL_SEPARATOR")  | 
5166  | 0  |                     : nullptr};  | 
5167  | 0  |     const bool bSrcWidthIncludesDecimalSeparator{ | 
5168  | 0  |         pszSrcWidthIncludesDecimalSeparator &&  | 
5169  | 0  |         EQUAL(pszSrcWidthIncludesDecimalSeparator, "YES")};  | 
5170  | 0  |     const char *pszDstWidthIncludesDecimalSeparator{ | 
5171  | 0  |         m_poDstDS->GetDriver()->GetMetadataItem(  | 
5172  | 0  |             "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_DECIMAL_SEPARATOR")};  | 
5173  | 0  |     const bool bDstWidthIncludesDecimalSeparator{ | 
5174  | 0  |         pszDstWidthIncludesDecimalSeparator &&  | 
5175  | 0  |         EQUAL(pszDstWidthIncludesDecimalSeparator, "YES")};  | 
5176  | 0  |     const char *pszSrcWidthIncludesMinusSign{ | 
5177  | 0  |         poSrcDriver ? poSrcDriver->GetMetadataItem(  | 
5178  | 0  |                           "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_SIGN")  | 
5179  | 0  |                     : nullptr};  | 
5180  | 0  |     const bool bSrcWidthIncludesMinusSign{ | 
5181  | 0  |         pszSrcWidthIncludesMinusSign &&  | 
5182  | 0  |         EQUAL(pszSrcWidthIncludesMinusSign, "YES")};  | 
5183  | 0  |     const char *pszDstWidthIncludesMinusSign{ | 
5184  | 0  |         m_poDstDS->GetDriver()->GetMetadataItem(  | 
5185  | 0  |             "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_SIGN")};  | 
5186  | 0  |     const bool bDstWidthIncludesMinusSign{ | 
5187  | 0  |         pszDstWidthIncludesMinusSign &&  | 
5188  | 0  |         EQUAL(pszDstWidthIncludesMinusSign, "YES")};  | 
5189  |  |  | 
5190  |  |     // Calculate width delta  | 
5191  | 0  |     int iChangeWidthBy{0}; | 
5192  |  | 
  | 
5193  | 0  |     if (bSrcWidthIncludesDecimalSeparator && !bDstWidthIncludesDecimalSeparator)  | 
5194  | 0  |     { | 
5195  | 0  |         iChangeWidthBy--;  | 
5196  | 0  |     }  | 
5197  | 0  |     else if (!bSrcWidthIncludesDecimalSeparator &&  | 
5198  | 0  |              bDstWidthIncludesDecimalSeparator)  | 
5199  | 0  |     { | 
5200  | 0  |         iChangeWidthBy++;  | 
5201  | 0  |     }  | 
5202  |  |  | 
5203  |  |     // We cannot assume there is no minus sign, we can only inflate here  | 
5204  | 0  |     if (!bSrcWidthIncludesMinusSign && bDstWidthIncludesMinusSign)  | 
5205  | 0  |     { | 
5206  | 0  |         iChangeWidthBy++;  | 
5207  | 0  |     }  | 
5208  |  | 
  | 
5209  | 0  |     bool bError = false;  | 
5210  | 0  |     OGRArrowArrayStream streamSrc;  | 
5211  |  | 
  | 
5212  | 0  |     const bool bUseWriteArrowBatch =  | 
5213  | 0  |         !EQUAL(m_poDstDS->GetDriver()->GetDescription(), "OCI") &&  | 
5214  | 0  |         CanUseWriteArrowBatch(poSrcLayer, poDstLayer, bJustCreatedLayer,  | 
5215  | 0  |                               psOptions, bPreserveFID, bError, streamSrc);  | 
5216  | 0  |     if (bError)  | 
5217  | 0  |         return nullptr;  | 
5218  |  |  | 
5219  |  |     /* Caution : at the time of writing, the MapInfo driver */  | 
5220  |  |     /* returns NULL until a field has been added */  | 
5221  | 0  |     OGRFeatureDefn *poDstFDefn = poDstLayer->GetLayerDefn();  | 
5222  |  | 
  | 
5223  | 0  |     if (bUseWriteArrowBatch)  | 
5224  | 0  |     { | 
5225  |  |         // Fields created above  | 
5226  | 0  |     }  | 
5227  | 0  |     else if (m_papszFieldMap && bAppend)  | 
5228  | 0  |     { | 
5229  | 0  |         bool bIdentity = false;  | 
5230  |  | 
  | 
5231  | 0  |         if (EQUAL(m_papszFieldMap[0], "identity"))  | 
5232  | 0  |             bIdentity = true;  | 
5233  | 0  |         else if (CSLCount(m_papszFieldMap) != nSrcFieldCount)  | 
5234  | 0  |         { | 
5235  | 0  |             CPLError(  | 
5236  | 0  |                 CE_Failure, CPLE_AppDefined,  | 
5237  | 0  |                 "Field map should contain the value 'identity' or "  | 
5238  | 0  |                 "the same number of integer values as the source field count.");  | 
5239  | 0  |             return nullptr;  | 
5240  | 0  |         }  | 
5241  |  |  | 
5242  | 0  |         for (int iField = 0; iField < nSrcFieldCount; iField++)  | 
5243  | 0  |         { | 
5244  | 0  |             anMap[iField] = bIdentity ? iField : atoi(m_papszFieldMap[iField]);  | 
5245  | 0  |             if (anMap[iField] >= poDstFDefn->GetFieldCount())  | 
5246  | 0  |             { | 
5247  | 0  |                 CPLError(CE_Failure, CPLE_AppDefined,  | 
5248  | 0  |                          "Invalid destination field index %d.", anMap[iField]);  | 
5249  | 0  |                 return nullptr;  | 
5250  | 0  |             }  | 
5251  | 0  |         }  | 
5252  | 0  |     }  | 
5253  | 0  |     else if (m_bSelFieldsSet && !bAppend)  | 
5254  | 0  |     { | 
5255  | 0  |         int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;  | 
5256  | 0  |         for (int iField = 0; m_papszSelFields && m_papszSelFields[iField];  | 
5257  | 0  |              iField++)  | 
5258  | 0  |         { | 
5259  | 0  |             const int iSrcField =  | 
5260  | 0  |                 poSrcFDefn->GetFieldIndex(m_papszSelFields[iField]);  | 
5261  | 0  |             if (iSrcField >= 0)  | 
5262  | 0  |             { | 
5263  | 0  |                 OGRFieldDefn *poSrcFieldDefn =  | 
5264  | 0  |                     poSrcFDefn->GetFieldDefn(iSrcField);  | 
5265  | 0  |                 OGRFieldDefn oFieldDefn(poSrcFieldDefn);  | 
5266  |  | 
  | 
5267  | 0  |                 DoFieldTypeConversion(  | 
5268  | 0  |                     m_poDstDS, oFieldDefn, m_papszFieldTypesToString,  | 
5269  | 0  |                     m_papszMapFieldType, m_bUnsetFieldWidth, psOptions->bQuiet,  | 
5270  | 0  |                     m_bForceNullable, m_bUnsetDefault);  | 
5271  |  | 
  | 
5272  | 0  |                 if (iChangeWidthBy != 0 && oFieldDefn.GetType() == OFTReal &&  | 
5273  | 0  |                     oFieldDefn.GetWidth() != 0)  | 
5274  | 0  |                 { | 
5275  | 0  |                     oFieldDefn.SetWidth(oFieldDefn.GetWidth() + iChangeWidthBy);  | 
5276  | 0  |                 }  | 
5277  |  |  | 
5278  |  |                 /* The field may have been already created at layer creation */  | 
5279  | 0  |                 const int iDstField =  | 
5280  | 0  |                     poDstFDefn  | 
5281  | 0  |                         ? poDstFDefn->GetFieldIndex(oFieldDefn.GetNameRef())  | 
5282  | 0  |                         : -1;  | 
5283  | 0  |                 if (iDstField >= 0)  | 
5284  | 0  |                 { | 
5285  | 0  |                     anMap[iSrcField] = iDstField;  | 
5286  | 0  |                 }  | 
5287  | 0  |                 else if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)  | 
5288  | 0  |                 { | 
5289  |  |                     /* now that we've created a field, GetLayerDefn() won't  | 
5290  |  |                      * return NULL */  | 
5291  | 0  |                     if (poDstFDefn == nullptr)  | 
5292  | 0  |                         poDstFDefn = poDstLayer->GetLayerDefn();  | 
5293  |  |  | 
5294  |  |                     /* Sanity check : if it fails, the driver is buggy */  | 
5295  | 0  |                     if (poDstFDefn != nullptr &&  | 
5296  | 0  |                         poDstFDefn->GetFieldCount() != nDstFieldCount + 1)  | 
5297  | 0  |                     { | 
5298  | 0  |                         CPLError(CE_Warning, CPLE_AppDefined,  | 
5299  | 0  |                                  "The output driver has claimed to have added "  | 
5300  | 0  |                                  "the %s field, but it did not!",  | 
5301  | 0  |                                  oFieldDefn.GetNameRef());  | 
5302  | 0  |                     }  | 
5303  | 0  |                     else  | 
5304  | 0  |                     { | 
5305  | 0  |                         anMap[iSrcField] = nDstFieldCount;  | 
5306  | 0  |                         nDstFieldCount++;  | 
5307  | 0  |                     }  | 
5308  | 0  |                 }  | 
5309  | 0  |             }  | 
5310  | 0  |         }  | 
5311  |  |  | 
5312  |  |         /* --------------------------------------------------------------------  | 
5313  |  |          */  | 
5314  |  |         /* Use SetIgnoredFields() on source layer if available */  | 
5315  |  |         /* --------------------------------------------------------------------  | 
5316  |  |          */  | 
5317  | 0  |         if (poSrcLayer->TestCapability(OLCIgnoreFields))  | 
5318  | 0  |         { | 
5319  | 0  |             bool bUseIgnoredFields = true;  | 
5320  | 0  |             char **papszWHEREUsedFields = nullptr;  | 
5321  |  | 
  | 
5322  | 0  |             if (m_pszWHERE)  | 
5323  | 0  |             { | 
5324  |  |                 /* We must not ignore fields used in the -where expression  | 
5325  |  |                  * (#4015) */  | 
5326  | 0  |                 OGRFeatureQuery oFeatureQuery;  | 
5327  | 0  |                 if (oFeatureQuery.Compile(poSrcLayer->GetLayerDefn(),  | 
5328  | 0  |                                           m_pszWHERE, FALSE,  | 
5329  | 0  |                                           nullptr) == OGRERR_NONE)  | 
5330  | 0  |                 { | 
5331  | 0  |                     papszWHEREUsedFields = oFeatureQuery.GetUsedFields();  | 
5332  | 0  |                 }  | 
5333  | 0  |                 else  | 
5334  | 0  |                 { | 
5335  | 0  |                     bUseIgnoredFields = false;  | 
5336  | 0  |                 }  | 
5337  | 0  |             }  | 
5338  |  | 
  | 
5339  | 0  |             char **papszIgnoredFields = nullptr;  | 
5340  |  | 
  | 
5341  | 0  |             for (int iSrcField = 0;  | 
5342  | 0  |                  bUseIgnoredFields && iSrcField < poSrcFDefn->GetFieldCount();  | 
5343  | 0  |                  iSrcField++)  | 
5344  | 0  |             { | 
5345  | 0  |                 const char *pszFieldName =  | 
5346  | 0  |                     poSrcFDefn->GetFieldDefn(iSrcField)->GetNameRef();  | 
5347  | 0  |                 bool bFieldRequested = false;  | 
5348  | 0  |                 for (int iField = 0;  | 
5349  | 0  |                      m_papszSelFields && m_papszSelFields[iField]; iField++)  | 
5350  | 0  |                 { | 
5351  | 0  |                     if (EQUAL(pszFieldName, m_papszSelFields[iField]))  | 
5352  | 0  |                     { | 
5353  | 0  |                         bFieldRequested = true;  | 
5354  | 0  |                         break;  | 
5355  | 0  |                     }  | 
5356  | 0  |                 }  | 
5357  | 0  |                 bFieldRequested |=  | 
5358  | 0  |                     CSLFindString(papszWHEREUsedFields, pszFieldName) >= 0;  | 
5359  | 0  |                 bFieldRequested |= (m_pszZField != nullptr &&  | 
5360  | 0  |                                     EQUAL(pszFieldName, m_pszZField));  | 
5361  |  |  | 
5362  |  |                 /* If source field not requested, add it to ignored files list  | 
5363  |  |                  */  | 
5364  | 0  |                 if (!bFieldRequested)  | 
5365  | 0  |                     papszIgnoredFields =  | 
5366  | 0  |                         CSLAddString(papszIgnoredFields, pszFieldName);  | 
5367  | 0  |             }  | 
5368  | 0  |             if (bUseIgnoredFields)  | 
5369  | 0  |                 poSrcLayer->SetIgnoredFields(  | 
5370  | 0  |                     const_cast<const char **>(papszIgnoredFields));  | 
5371  | 0  |             CSLDestroy(papszIgnoredFields);  | 
5372  | 0  |             CSLDestroy(papszWHEREUsedFields);  | 
5373  | 0  |         }  | 
5374  | 0  |     }  | 
5375  | 0  |     else if (!bAppend || m_bAddMissingFields)  | 
5376  | 0  |     { | 
5377  | 0  |         int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;  | 
5378  |  | 
  | 
5379  | 0  |         const bool caseInsensitive =  | 
5380  | 0  |             !EQUAL(m_poDstDS->GetDriver()->GetDescription(), "GeoJSON");  | 
5381  | 0  |         const auto formatName = [caseInsensitive](const char *name)  | 
5382  | 0  |         { | 
5383  | 0  |             if (caseInsensitive)  | 
5384  | 0  |             { | 
5385  | 0  |                 return CPLString(name).toupper();  | 
5386  | 0  |             }  | 
5387  | 0  |             else  | 
5388  | 0  |             { | 
5389  | 0  |                 return CPLString(name);  | 
5390  | 0  |             }  | 
5391  | 0  |         };  | 
5392  |  |  | 
5393  |  |         /* Save the map of existing fields, before creating new ones */  | 
5394  |  |         /* This helps when converting a source layer that has duplicated field  | 
5395  |  |          * names */  | 
5396  |  |         /* which is a bad idea */  | 
5397  | 0  |         std::map<CPLString, int> oMapPreExistingFields;  | 
5398  | 0  |         std::unordered_set<std::string> oSetDstFieldNames;  | 
5399  | 0  |         for (int iField = 0; iField < nDstFieldCount; iField++)  | 
5400  | 0  |         { | 
5401  | 0  |             const char *pszFieldName =  | 
5402  | 0  |                 poDstFDefn->GetFieldDefn(iField)->GetNameRef();  | 
5403  | 0  |             CPLString osUpperFieldName(formatName(pszFieldName));  | 
5404  | 0  |             oSetDstFieldNames.insert(osUpperFieldName);  | 
5405  | 0  |             if (oMapPreExistingFields.find(osUpperFieldName) ==  | 
5406  | 0  |                 oMapPreExistingFields.end())  | 
5407  | 0  |                 oMapPreExistingFields[osUpperFieldName] = iField;  | 
5408  |  |             /*else  | 
5409  |  |                 CPLError(CE_Warning, CPLE_AppDefined,  | 
5410  |  |                          "The target layer has already a duplicated field name  | 
5411  |  |                '%s' before " "adding the fields of the source layer",  | 
5412  |  |                pszFieldName); */  | 
5413  | 0  |         }  | 
5414  |  | 
  | 
5415  | 0  |         const char *pszFIDColumn = poDstLayer->GetFIDColumn();  | 
5416  |  | 
  | 
5417  | 0  |         std::vector<int> anSrcFieldIndices;  | 
5418  | 0  |         if (m_bSelFieldsSet)  | 
5419  | 0  |         { | 
5420  | 0  |             for (int iField = 0; m_papszSelFields && m_papszSelFields[iField];  | 
5421  | 0  |                  iField++)  | 
5422  | 0  |             { | 
5423  | 0  |                 const int iSrcField =  | 
5424  | 0  |                     poSrcFDefn->GetFieldIndex(m_papszSelFields[iField]);  | 
5425  | 0  |                 if (iSrcField >= 0)  | 
5426  | 0  |                 { | 
5427  | 0  |                     anSrcFieldIndices.push_back(iSrcField);  | 
5428  | 0  |                 }  | 
5429  | 0  |             }  | 
5430  | 0  |         }  | 
5431  | 0  |         else  | 
5432  | 0  |         { | 
5433  | 0  |             for (int iField = 0; iField < nSrcFieldCount; iField++)  | 
5434  | 0  |             { | 
5435  | 0  |                 anSrcFieldIndices.push_back(iField);  | 
5436  | 0  |             }  | 
5437  | 0  |         }  | 
5438  |  | 
  | 
5439  | 0  |         std::unordered_set<std::string> oSetSrcFieldNames;  | 
5440  | 0  |         for (int i = 0; i < poSrcFDefn->GetFieldCount(); i++)  | 
5441  | 0  |         { | 
5442  | 0  |             oSetSrcFieldNames.insert(  | 
5443  | 0  |                 formatName(poSrcFDefn->GetFieldDefn(i)->GetNameRef()));  | 
5444  | 0  |         }  | 
5445  |  |  | 
5446  |  |         // For each source field name, memorize the last number suffix to have  | 
5447  |  |         // unique field names in the target. Let's imagine we have a source  | 
5448  |  |         // layer with the field name foo repeated twice After dealing the first  | 
5449  |  |         // field, oMapFieldNameToLastSuffix["foo"] will be 1, so when starting a  | 
5450  |  |         // unique name for the second field, we'll be able to start at 2. This  | 
5451  |  |         // avoids quadratic complexity if a big number of source field names are  | 
5452  |  |         // identical. Like in  | 
5453  |  |         // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=37768  | 
5454  | 0  |         std::map<std::string, int> oMapFieldNameToLastSuffix;  | 
5455  |  | 
  | 
5456  | 0  |         for (size_t i = 0; i < anSrcFieldIndices.size(); i++)  | 
5457  | 0  |         { | 
5458  | 0  |             const int iField = anSrcFieldIndices[i];  | 
5459  | 0  |             const OGRFieldDefn *poSrcFieldDefn =  | 
5460  | 0  |                 poSrcFDefn->GetFieldDefn(iField);  | 
5461  | 0  |             OGRFieldDefn oFieldDefn(poSrcFieldDefn);  | 
5462  |  |  | 
5463  |  |             // Avoid creating a field with the same name as the FID column  | 
5464  | 0  |             if (pszFIDColumn != nullptr &&  | 
5465  | 0  |                 EQUAL(pszFIDColumn, oFieldDefn.GetNameRef()) &&  | 
5466  | 0  |                 (oFieldDefn.GetType() == OFTInteger ||  | 
5467  | 0  |                  oFieldDefn.GetType() == OFTInteger64))  | 
5468  | 0  |             { | 
5469  | 0  |                 iSrcFIDField = iField;  | 
5470  | 0  |                 continue;  | 
5471  | 0  |             }  | 
5472  |  |  | 
5473  | 0  |             DoFieldTypeConversion(  | 
5474  | 0  |                 m_poDstDS, oFieldDefn, m_papszFieldTypesToString,  | 
5475  | 0  |                 m_papszMapFieldType, m_bUnsetFieldWidth, psOptions->bQuiet,  | 
5476  | 0  |                 m_bForceNullable, m_bUnsetDefault);  | 
5477  |  | 
  | 
5478  | 0  |             if (iChangeWidthBy != 0 && oFieldDefn.GetType() == OFTReal &&  | 
5479  | 0  |                 oFieldDefn.GetWidth() != 0)  | 
5480  | 0  |             { | 
5481  | 0  |                 oFieldDefn.SetWidth(oFieldDefn.GetWidth() + iChangeWidthBy);  | 
5482  | 0  |             }  | 
5483  |  |  | 
5484  |  |             /* The field may have been already created at layer creation */  | 
5485  | 0  |             { | 
5486  | 0  |                 const auto oIter = oMapPreExistingFields.find(  | 
5487  | 0  |                     formatName(oFieldDefn.GetNameRef()));  | 
5488  | 0  |                 if (oIter != oMapPreExistingFields.end())  | 
5489  | 0  |                 { | 
5490  | 0  |                     anMap[iField] = oIter->second;  | 
5491  | 0  |                     continue;  | 
5492  | 0  |                 }  | 
5493  | 0  |             }  | 
5494  |  |  | 
5495  | 0  |             bool bHasRenamed = false;  | 
5496  |  |             /* In case the field name already exists in the target layer, */  | 
5497  |  |             /* build a unique field name */  | 
5498  | 0  |             if (oSetDstFieldNames.find(formatName(oFieldDefn.GetNameRef())) !=  | 
5499  | 0  |                 oSetDstFieldNames.end())  | 
5500  | 0  |             { | 
5501  | 0  |                 const CPLString osTmpNameRaddixUC(  | 
5502  | 0  |                     formatName(oFieldDefn.GetNameRef()));  | 
5503  | 0  |                 int nTry = 1;  | 
5504  | 0  |                 const auto oIter =  | 
5505  | 0  |                     oMapFieldNameToLastSuffix.find(osTmpNameRaddixUC);  | 
5506  | 0  |                 if (oIter != oMapFieldNameToLastSuffix.end())  | 
5507  | 0  |                     nTry = oIter->second;  | 
5508  | 0  |                 CPLString osTmpNameUC = osTmpNameRaddixUC;  | 
5509  | 0  |                 osTmpNameUC.reserve(osTmpNameUC.size() + 10);  | 
5510  | 0  |                 while (true)  | 
5511  | 0  |                 { | 
5512  | 0  |                     ++nTry;  | 
5513  | 0  |                     char szTry[32];  | 
5514  | 0  |                     snprintf(szTry, sizeof(szTry), "%d", nTry);  | 
5515  | 0  |                     osTmpNameUC.replace(osTmpNameRaddixUC.size(),  | 
5516  | 0  |                                         std::string::npos, szTry);  | 
5517  |  |  | 
5518  |  |                     /* Check that the proposed name doesn't exist either in the  | 
5519  |  |                      * already */  | 
5520  |  |                     /* created fields or in the source fields */  | 
5521  | 0  |                     if (oSetDstFieldNames.find(osTmpNameUC) ==  | 
5522  | 0  |                             oSetDstFieldNames.end() &&  | 
5523  | 0  |                         oSetSrcFieldNames.find(osTmpNameUC) ==  | 
5524  | 0  |                             oSetSrcFieldNames.end())  | 
5525  | 0  |                     { | 
5526  | 0  |                         bHasRenamed = true;  | 
5527  | 0  |                         oFieldDefn.SetName(  | 
5528  | 0  |                             (CPLString(oFieldDefn.GetNameRef()) + szTry)  | 
5529  | 0  |                                 .c_str());  | 
5530  | 0  |                         oMapFieldNameToLastSuffix[osTmpNameRaddixUC] = nTry;  | 
5531  | 0  |                         break;  | 
5532  | 0  |                     }  | 
5533  | 0  |                 }  | 
5534  | 0  |             }  | 
5535  |  |  | 
5536  |  |             // Create field domain in output dataset if not already existing.  | 
5537  | 0  |             const std::string osDomainName(oFieldDefn.GetDomainName());  | 
5538  | 0  |             if (!osDomainName.empty())  | 
5539  | 0  |             { | 
5540  | 0  |                 if (m_poDstDS->TestCapability(ODsCAddFieldDomain) &&  | 
5541  | 0  |                     m_poDstDS->GetFieldDomain(osDomainName) == nullptr)  | 
5542  | 0  |                 { | 
5543  | 0  |                     const auto poSrcDomain =  | 
5544  | 0  |                         m_poSrcDS->GetFieldDomain(osDomainName);  | 
5545  | 0  |                     if (poSrcDomain)  | 
5546  | 0  |                     { | 
5547  | 0  |                         std::string failureReason;  | 
5548  | 0  |                         if (!m_poDstDS->AddFieldDomain(  | 
5549  | 0  |                                 std::unique_ptr<OGRFieldDomain>(  | 
5550  | 0  |                                     poSrcDomain->Clone()),  | 
5551  | 0  |                                 failureReason))  | 
5552  | 0  |                         { | 
5553  | 0  |                             oFieldDefn.SetDomainName(std::string());  | 
5554  | 0  |                             CPLDebug("OGR2OGR", "Cannot create domain %s: %s", | 
5555  | 0  |                                      osDomainName.c_str(),  | 
5556  | 0  |                                      failureReason.c_str());  | 
5557  | 0  |                         }  | 
5558  | 0  |                     }  | 
5559  | 0  |                     else  | 
5560  | 0  |                     { | 
5561  | 0  |                         CPLDebug("OGR2OGR", | 
5562  | 0  |                                  "Cannot find domain %s in source dataset",  | 
5563  | 0  |                                  osDomainName.c_str());  | 
5564  | 0  |                     }  | 
5565  | 0  |                 }  | 
5566  | 0  |                 if (m_poDstDS->GetFieldDomain(osDomainName) == nullptr)  | 
5567  | 0  |                 { | 
5568  | 0  |                     oFieldDefn.SetDomainName(std::string());  | 
5569  | 0  |                 }  | 
5570  | 0  |             }  | 
5571  |  | 
  | 
5572  | 0  |             if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)  | 
5573  | 0  |             { | 
5574  |  |                 /* now that we've created a field, GetLayerDefn() won't return  | 
5575  |  |                  * NULL */  | 
5576  | 0  |                 if (poDstFDefn == nullptr)  | 
5577  | 0  |                     poDstFDefn = poDstLayer->GetLayerDefn();  | 
5578  |  |  | 
5579  |  |                 /* Sanity check : if it fails, the driver is buggy */  | 
5580  | 0  |                 if (poDstFDefn != nullptr &&  | 
5581  | 0  |                     poDstFDefn->GetFieldCount() != nDstFieldCount + 1)  | 
5582  | 0  |                 { | 
5583  | 0  |                     CPLError(CE_Warning, CPLE_AppDefined,  | 
5584  | 0  |                              "The output driver has claimed to have added the "  | 
5585  | 0  |                              "%s field, but it did not!",  | 
5586  | 0  |                              oFieldDefn.GetNameRef());  | 
5587  | 0  |                 }  | 
5588  | 0  |                 else  | 
5589  | 0  |                 { | 
5590  | 0  |                     if (poDstFDefn != nullptr)  | 
5591  | 0  |                     { | 
5592  | 0  |                         const char *pszNewFieldName =  | 
5593  | 0  |                             poDstFDefn->GetFieldDefn(nDstFieldCount)  | 
5594  | 0  |                                 ->GetNameRef();  | 
5595  | 0  |                         if (bHasRenamed)  | 
5596  | 0  |                         { | 
5597  | 0  |                             CPLError(CE_Warning, CPLE_AppDefined,  | 
5598  | 0  |                                      "Field '%s' already exists. Renaming it "  | 
5599  | 0  |                                      "as '%s'",  | 
5600  | 0  |                                      poSrcFieldDefn->GetNameRef(),  | 
5601  | 0  |                                      pszNewFieldName);  | 
5602  | 0  |                         }  | 
5603  | 0  |                         oSetDstFieldNames.insert(formatName(pszNewFieldName));  | 
5604  | 0  |                     }  | 
5605  |  | 
  | 
5606  | 0  |                     anMap[iField] = nDstFieldCount;  | 
5607  | 0  |                     nDstFieldCount++;  | 
5608  | 0  |                 }  | 
5609  | 0  |             }  | 
5610  |  | 
  | 
5611  | 0  |             if (m_bResolveDomains && !osDomainName.empty())  | 
5612  | 0  |             { | 
5613  | 0  |                 const auto poSrcDomain =  | 
5614  | 0  |                     m_poSrcDS->GetFieldDomain(osDomainName);  | 
5615  | 0  |                 if (poSrcDomain && poSrcDomain->GetDomainType() == OFDT_CODED)  | 
5616  | 0  |                 { | 
5617  | 0  |                     OGRFieldDefn oResolvedField(  | 
5618  | 0  |                         CPLSPrintf("%s_resolved", oFieldDefn.GetNameRef()), | 
5619  | 0  |                         OFTString);  | 
5620  | 0  |                     if (poDstLayer->CreateField(&oResolvedField) == OGRERR_NONE)  | 
5621  | 0  |                     { | 
5622  | 0  |                         TargetLayerInfo::ResolvedInfo resolvedInfo;  | 
5623  | 0  |                         resolvedInfo.nSrcField = iField;  | 
5624  | 0  |                         resolvedInfo.poDomain = poSrcDomain;  | 
5625  | 0  |                         oMapResolved[nDstFieldCount] = resolvedInfo;  | 
5626  | 0  |                         nDstFieldCount++;  | 
5627  | 0  |                     }  | 
5628  | 0  |                 }  | 
5629  | 0  |             }  | 
5630  | 0  |         }  | 
5631  | 0  |     }  | 
5632  | 0  |     else  | 
5633  | 0  |     { | 
5634  |  |         /* For an existing layer, build the map by fetching the index in the  | 
5635  |  |          * destination */  | 
5636  |  |         /* layer for each source field */  | 
5637  | 0  |         if (poDstFDefn == nullptr)  | 
5638  | 0  |         { | 
5639  | 0  |             CPLError(CE_Failure, CPLE_AppDefined, "poDstFDefn == NULL.");  | 
5640  | 0  |             return nullptr;  | 
5641  | 0  |         }  | 
5642  |  |  | 
5643  | 0  |         for (int iField = 0; iField < nSrcFieldCount; iField++)  | 
5644  | 0  |         { | 
5645  | 0  |             OGRFieldDefn *poSrcFieldDefn = poSrcFDefn->GetFieldDefn(iField);  | 
5646  | 0  |             const int iDstField = poDstLayer->FindFieldIndex(  | 
5647  | 0  |                 poSrcFieldDefn->GetNameRef(), m_bExactFieldNameMatch);  | 
5648  | 0  |             if (iDstField >= 0)  | 
5649  | 0  |                 anMap[iField] = iDstField;  | 
5650  | 0  |             else  | 
5651  | 0  |             { | 
5652  | 0  |                 if (m_bExactFieldNameMatch)  | 
5653  | 0  |                 { | 
5654  | 0  |                     const int iDstFieldCandidate = poDstLayer->FindFieldIndex(  | 
5655  | 0  |                         poSrcFieldDefn->GetNameRef(), false);  | 
5656  | 0  |                     if (iDstFieldCandidate >= 0)  | 
5657  | 0  |                     { | 
5658  | 0  |                         CPLError(CE_Warning, CPLE_AppDefined,  | 
5659  | 0  |                                  "Source field '%s' could have been identified "  | 
5660  | 0  |                                  "with existing field '%s' of destination "  | 
5661  | 0  |                                  "layer '%s' if the -relaxedFieldNameMatch "  | 
5662  | 0  |                                  "option had been specified.",  | 
5663  | 0  |                                  poSrcFieldDefn->GetNameRef(),  | 
5664  | 0  |                                  poDstLayer->GetLayerDefn()  | 
5665  | 0  |                                      ->GetFieldDefn(iDstFieldCandidate)  | 
5666  | 0  |                                      ->GetNameRef(),  | 
5667  | 0  |                                  poDstLayer->GetName());  | 
5668  | 0  |                     }  | 
5669  | 0  |                 }  | 
5670  |  | 
  | 
5671  | 0  |                 CPLDebug(  | 
5672  | 0  |                     "GDALVectorTranslate",  | 
5673  | 0  |                     "Skipping field '%s' not found in destination layer '%s'.",  | 
5674  | 0  |                     poSrcFieldDefn->GetNameRef(), poDstLayer->GetName());  | 
5675  | 0  |             }  | 
5676  | 0  |         }  | 
5677  | 0  |     }  | 
5678  |  |  | 
5679  | 0  |     if (bOverwriteActuallyDone && !bAddOverwriteLCO &&  | 
5680  | 0  |         EQUAL(m_poDstDS->GetDriver()->GetDescription(), "PostgreSQL") &&  | 
5681  | 0  |         !psOptions->nLayerTransaction && psOptions->nGroupTransactions > 0 &&  | 
5682  | 0  |         CPLTestBool(CPLGetConfigOption("PG_COMMIT_WHEN_OVERWRITING", "YES"))) | 
5683  | 0  |     { | 
5684  | 0  |         CPLDebug("GDALVectorTranslate", | 
5685  | 0  |                  "Forcing transaction commit as table overwriting occurred");  | 
5686  |  |         // Commit when overwriting as this consumes a lot of PG resources  | 
5687  |  |         // and could result in """out of shared memory.  | 
5688  |  |         // You might need to increase max_locks_per_transaction."""" errors  | 
5689  | 0  |         if (m_poDstDS->CommitTransaction() == OGRERR_FAILURE ||  | 
5690  | 0  |             m_poDstDS->StartTransaction(psOptions->bForceTransaction) ==  | 
5691  | 0  |                 OGRERR_FAILURE)  | 
5692  | 0  |         { | 
5693  | 0  |             return nullptr;  | 
5694  | 0  |         }  | 
5695  | 0  |         nTotalEventsDone = 0;  | 
5696  | 0  |     }  | 
5697  |  |  | 
5698  | 0  |     auto psInfo = std::make_unique<TargetLayerInfo>();  | 
5699  | 0  |     psInfo->m_bUseWriteArrowBatch = bUseWriteArrowBatch;  | 
5700  | 0  |     psInfo->m_nFeaturesRead = 0;  | 
5701  | 0  |     psInfo->m_bPerFeatureCT = false;  | 
5702  | 0  |     psInfo->m_poSrcLayer = poSrcLayer;  | 
5703  | 0  |     psInfo->m_poDstLayer = poDstLayer;  | 
5704  | 0  |     psInfo->m_aoReprojectionInfo.resize(  | 
5705  | 0  |         poDstLayer->GetLayerDefn()->GetGeomFieldCount());  | 
5706  | 0  |     psInfo->m_anMap = std::move(anMap);  | 
5707  | 0  |     psInfo->m_iSrcZField = iSrcZField;  | 
5708  | 0  |     psInfo->m_iSrcFIDField = iSrcFIDField;  | 
5709  | 0  |     if (anRequestedGeomFields.size() == 1)  | 
5710  | 0  |         psInfo->m_iRequestedSrcGeomField = anRequestedGeomFields[0];  | 
5711  | 0  |     else  | 
5712  | 0  |         psInfo->m_iRequestedSrcGeomField = -1;  | 
5713  | 0  |     psInfo->m_bPreserveFID = bPreserveFID;  | 
5714  | 0  |     psInfo->m_pszCTPipeline = m_pszCTPipeline;  | 
5715  | 0  |     psInfo->m_aosCTOptions = m_aosCTOptions;  | 
5716  | 0  |     psInfo->m_oMapResolved = std::move(oMapResolved);  | 
5717  | 0  |     for (const auto &kv : psInfo->m_oMapResolved)  | 
5718  | 0  |     { | 
5719  | 0  |         const auto poDomain = kv.second.poDomain;  | 
5720  | 0  |         const auto poCodedDomain =  | 
5721  | 0  |             cpl::down_cast<const OGRCodedFieldDomain *>(poDomain);  | 
5722  | 0  |         const auto enumeration = poCodedDomain->GetEnumeration();  | 
5723  | 0  |         std::map<std::string, std::string> oMapCodeValue;  | 
5724  | 0  |         for (int i = 0; enumeration[i].pszCode != nullptr; ++i)  | 
5725  | 0  |         { | 
5726  | 0  |             oMapCodeValue[enumeration[i].pszCode] =  | 
5727  | 0  |                 enumeration[i].pszValue ? enumeration[i].pszValue : "";  | 
5728  | 0  |         }  | 
5729  | 0  |         psInfo->m_oMapDomainToKV[poDomain] = std::move(oMapCodeValue);  | 
5730  | 0  |     }  | 
5731  |  |  | 
5732  |  |     // Detect if we can directly pass the source feature to the CreateFeature()  | 
5733  |  |     // method of the target layer, without doing any copying of field content.  | 
5734  | 0  |     psInfo->m_bCanAvoidSetFrom = false;  | 
5735  | 0  |     if (!m_bExplodeCollections && iSrcZField == -1 && poDstFDefn != nullptr)  | 
5736  | 0  |     { | 
5737  | 0  |         psInfo->m_bCanAvoidSetFrom = true;  | 
5738  | 0  |         const int nDstGeomFieldCount = poDstFDefn->GetGeomFieldCount();  | 
5739  | 0  |         if (nSrcFieldCount != poDstFDefn->GetFieldCount() ||  | 
5740  | 0  |             nSrcGeomFieldCount != nDstGeomFieldCount)  | 
5741  | 0  |         { | 
5742  | 0  |             psInfo->m_bCanAvoidSetFrom = false;  | 
5743  | 0  |         }  | 
5744  | 0  |         else  | 
5745  | 0  |         { | 
5746  | 0  |             for (int i = 0; i < nSrcFieldCount; ++i)  | 
5747  | 0  |             { | 
5748  | 0  |                 auto poSrcFieldDefn = poSrcFDefn->GetFieldDefn(i);  | 
5749  | 0  |                 auto poDstFieldDefn = poDstFDefn->GetFieldDefn(i);  | 
5750  | 0  |                 if (poSrcFieldDefn->GetType() != poDstFieldDefn->GetType() ||  | 
5751  | 0  |                     psInfo->m_anMap[i] != i)  | 
5752  | 0  |                 { | 
5753  | 0  |                     psInfo->m_bCanAvoidSetFrom = false;  | 
5754  | 0  |                     break;  | 
5755  | 0  |                 }  | 
5756  | 0  |             }  | 
5757  | 0  |             if (!psInfo->m_bCanAvoidSetFrom && nSrcGeomFieldCount > 1)  | 
5758  | 0  |             { | 
5759  | 0  |                 for (int i = 0; i < nSrcGeomFieldCount; ++i)  | 
5760  | 0  |                 { | 
5761  | 0  |                     auto poSrcGeomFieldDefn = poSrcFDefn->GetGeomFieldDefn(i);  | 
5762  | 0  |                     auto poDstGeomFieldDefn = poDstFDefn->GetGeomFieldDefn(i);  | 
5763  | 0  |                     if (!EQUAL(poSrcGeomFieldDefn->GetNameRef(),  | 
5764  | 0  |                                poDstGeomFieldDefn->GetNameRef()))  | 
5765  | 0  |                     { | 
5766  | 0  |                         psInfo->m_bCanAvoidSetFrom = false;  | 
5767  | 0  |                         break;  | 
5768  | 0  |                     }  | 
5769  | 0  |                 }  | 
5770  | 0  |             }  | 
5771  | 0  |         }  | 
5772  | 0  |     }  | 
5773  |  | 
  | 
5774  | 0  |     psInfo->m_pszSpatSRSDef = psOptions->osSpatSRSDef.empty()  | 
5775  | 0  |                                   ? nullptr  | 
5776  | 0  |                                   : psOptions->osSpatSRSDef.c_str();  | 
5777  | 0  |     psInfo->m_hSpatialFilter =  | 
5778  | 0  |         OGRGeometry::ToHandle(psOptions->poSpatialFilter.get());  | 
5779  | 0  |     psInfo->m_pszGeomField =  | 
5780  | 0  |         psOptions->bGeomFieldSet ? psOptions->osGeomField.c_str() : nullptr;  | 
5781  |  | 
  | 
5782  | 0  |     if (psOptions->nTZOffsetInSec != TZ_OFFSET_INVALID && poDstFDefn)  | 
5783  | 0  |     { | 
5784  | 0  |         for (int i = 0; i < poDstFDefn->GetFieldCount(); ++i)  | 
5785  | 0  |         { | 
5786  | 0  |             if (poDstFDefn->GetFieldDefn(i)->GetType() == OFTDateTime)  | 
5787  | 0  |             { | 
5788  | 0  |                 psInfo->m_anDateTimeFieldIdx.push_back(i);  | 
5789  | 0  |             }  | 
5790  | 0  |         }  | 
5791  | 0  |     }  | 
5792  |  | 
  | 
5793  | 0  |     psInfo->m_bSupportCurves =  | 
5794  | 0  |         CPL_TO_BOOL(poDstLayer->TestCapability(OLCCurveGeometries));  | 
5795  |  | 
  | 
5796  | 0  |     psInfo->m_sArrowArrayStream = std::move(streamSrc);  | 
5797  |  | 
  | 
5798  | 0  |     return psInfo;  | 
5799  | 0  | }  | 
5800  |  |  | 
5801  |  | /************************************************************************/  | 
5802  |  | /*                               SetupCT()                              */  | 
5803  |  | /************************************************************************/  | 
5804  |  |  | 
5805  |  | static bool  | 
5806  |  | SetupCT(TargetLayerInfo *psInfo, OGRLayer *poSrcLayer, bool bTransform,  | 
5807  |  |         bool bWrapDateline, const CPLString &osDateLineOffset,  | 
5808  |  |         const OGRSpatialReference *poUserSourceSRS, OGRFeature *poFeature,  | 
5809  |  |         const OGRSpatialReference *poOutputSRS,  | 
5810  |  |         OGRCoordinateTransformation *poGCPCoordTrans, bool bVerboseError)  | 
5811  | 0  | { | 
5812  | 0  |     OGRLayer *poDstLayer = psInfo->m_poDstLayer;  | 
5813  | 0  |     const int nDstGeomFieldCount =  | 
5814  | 0  |         poDstLayer->GetLayerDefn()->GetGeomFieldCount();  | 
5815  | 0  |     for (int iGeom = 0; iGeom < nDstGeomFieldCount; iGeom++)  | 
5816  | 0  |     { | 
5817  |  |         /* --------------------------------------------------------------------  | 
5818  |  |          */  | 
5819  |  |         /*      Setup coordinate transformation if we need it. */  | 
5820  |  |         /* --------------------------------------------------------------------  | 
5821  |  |          */  | 
5822  | 0  |         const OGRSpatialReference *poSourceSRS = nullptr;  | 
5823  | 0  |         OGRCoordinateTransformation *poCT = nullptr;  | 
5824  | 0  |         char **papszTransformOptions = nullptr;  | 
5825  |  | 
  | 
5826  | 0  |         int iSrcGeomField;  | 
5827  | 0  |         auto poDstGeomFieldDefn =  | 
5828  | 0  |             poDstLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom);  | 
5829  | 0  |         if (psInfo->m_iRequestedSrcGeomField >= 0)  | 
5830  | 0  |         { | 
5831  | 0  |             iSrcGeomField = psInfo->m_iRequestedSrcGeomField;  | 
5832  | 0  |         }  | 
5833  | 0  |         else  | 
5834  | 0  |         { | 
5835  | 0  |             iSrcGeomField = poSrcLayer->GetLayerDefn()->GetGeomFieldIndex(  | 
5836  | 0  |                 poDstGeomFieldDefn->GetNameRef());  | 
5837  | 0  |             if (iSrcGeomField < 0)  | 
5838  | 0  |             { | 
5839  | 0  |                 if (nDstGeomFieldCount == 1 &&  | 
5840  | 0  |                     poSrcLayer->GetLayerDefn()->GetGeomFieldCount() > 0)  | 
5841  | 0  |                 { | 
5842  | 0  |                     iSrcGeomField = 0;  | 
5843  | 0  |                 }  | 
5844  | 0  |                 else  | 
5845  | 0  |                 { | 
5846  | 0  |                     continue;  | 
5847  | 0  |                 }  | 
5848  | 0  |             }  | 
5849  | 0  |         }  | 
5850  |  |  | 
5851  | 0  |         if (psInfo->m_nFeaturesRead == 0)  | 
5852  | 0  |         { | 
5853  | 0  |             poSourceSRS = poUserSourceSRS;  | 
5854  | 0  |             if (poSourceSRS == nullptr)  | 
5855  | 0  |             { | 
5856  | 0  |                 if (iSrcGeomField > 0)  | 
5857  | 0  |                     poSourceSRS = poSrcLayer->GetLayerDefn()  | 
5858  | 0  |                                       ->GetGeomFieldDefn(iSrcGeomField)  | 
5859  | 0  |                                       ->GetSpatialRef();  | 
5860  | 0  |                 else  | 
5861  | 0  |                     poSourceSRS = poSrcLayer->GetSpatialRef();  | 
5862  | 0  |             }  | 
5863  | 0  |         }  | 
5864  | 0  |         if (poSourceSRS == nullptr)  | 
5865  | 0  |         { | 
5866  | 0  |             if (poFeature == nullptr)  | 
5867  | 0  |             { | 
5868  | 0  |                 if (bVerboseError)  | 
5869  | 0  |                 { | 
5870  | 0  |                     CPLError(CE_Failure, CPLE_AppDefined,  | 
5871  | 0  |                              "Non-null feature expected to set transformation");  | 
5872  | 0  |                 }  | 
5873  | 0  |                 return false;  | 
5874  | 0  |             }  | 
5875  | 0  |             OGRGeometry *poSrcGeometry =  | 
5876  | 0  |                 poFeature->GetGeomFieldRef(iSrcGeomField);  | 
5877  | 0  |             if (poSrcGeometry)  | 
5878  | 0  |                 poSourceSRS = poSrcGeometry->getSpatialReference();  | 
5879  | 0  |             psInfo->m_bPerFeatureCT = (bTransform || bWrapDateline);  | 
5880  | 0  |         }  | 
5881  |  |  | 
5882  | 0  |         if (bTransform)  | 
5883  | 0  |         { | 
5884  | 0  |             if (poSourceSRS == nullptr && psInfo->m_pszCTPipeline == nullptr)  | 
5885  | 0  |             { | 
5886  | 0  |                 CPLError(CE_Failure, CPLE_AppDefined,  | 
5887  | 0  |                          "Can't transform coordinates, source layer has no\n"  | 
5888  | 0  |                          "coordinate system.  Use -s_srs to set one.");  | 
5889  |  | 
  | 
5890  | 0  |                 return false;  | 
5891  | 0  |             }  | 
5892  |  |  | 
5893  | 0  |             if (psInfo->m_pszCTPipeline == nullptr)  | 
5894  | 0  |             { | 
5895  | 0  |                 CPLAssert(nullptr != poSourceSRS);  | 
5896  | 0  |                 CPLAssert(nullptr != poOutputSRS);  | 
5897  | 0  |             }  | 
5898  |  |  | 
5899  | 0  |             if (psInfo->m_nFeaturesRead == 0 && !psInfo->m_bPerFeatureCT)  | 
5900  | 0  |             { | 
5901  | 0  |                 const auto &supportedSRSList =  | 
5902  | 0  |                     poSrcLayer->GetSupportedSRSList(iGeom);  | 
5903  | 0  |                 if (!supportedSRSList.empty())  | 
5904  | 0  |                 { | 
5905  | 0  |                     const char *const apszOptions[] = { | 
5906  | 0  |                         "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES", nullptr};  | 
5907  | 0  |                     for (const auto &poSRS : supportedSRSList)  | 
5908  | 0  |                     { | 
5909  | 0  |                         if (poSRS->IsSame(poOutputSRS, apszOptions))  | 
5910  | 0  |                         { | 
5911  | 0  |                             OGRSpatialReference oSourceSRSBackup;  | 
5912  | 0  |                             if (poSourceSRS)  | 
5913  | 0  |                                 oSourceSRSBackup = *poSourceSRS;  | 
5914  | 0  |                             if (poSrcLayer->SetActiveSRS(iGeom, poSRS.get()) ==  | 
5915  | 0  |                                 OGRERR_NONE)  | 
5916  | 0  |                             { | 
5917  | 0  |                                 CPLDebug("ogr2ogr", | 
5918  | 0  |                                          "Switching layer active SRS to %s",  | 
5919  | 0  |                                          poSRS->GetName());  | 
5920  |  | 
  | 
5921  | 0  |                                 if (psInfo->m_hSpatialFilter != nullptr &&  | 
5922  | 0  |                                     ((psInfo->m_iRequestedSrcGeomField < 0 &&  | 
5923  | 0  |                                       iGeom == 0) ||  | 
5924  | 0  |                                      (iGeom ==  | 
5925  | 0  |                                       psInfo->m_iRequestedSrcGeomField)))  | 
5926  | 0  |                                 { | 
5927  | 0  |                                     OGRSpatialReference oSpatSRS;  | 
5928  | 0  |                                     oSpatSRS.SetAxisMappingStrategy(  | 
5929  | 0  |                                         OAMS_TRADITIONAL_GIS_ORDER);  | 
5930  | 0  |                                     if (psInfo->m_pszSpatSRSDef)  | 
5931  | 0  |                                         oSpatSRS.SetFromUserInput(  | 
5932  | 0  |                                             psInfo->m_pszSpatSRSDef);  | 
5933  | 0  |                                     ApplySpatialFilter(  | 
5934  | 0  |                                         poSrcLayer,  | 
5935  | 0  |                                         OGRGeometry::FromHandle(  | 
5936  | 0  |                                             psInfo->m_hSpatialFilter),  | 
5937  | 0  |                                         !oSpatSRS.IsEmpty() ? &oSpatSRS  | 
5938  | 0  |                                         : !oSourceSRSBackup.IsEmpty()  | 
5939  | 0  |                                             ? &oSourceSRSBackup  | 
5940  | 0  |                                             : nullptr,  | 
5941  | 0  |                                         psInfo->m_pszGeomField, poOutputSRS);  | 
5942  | 0  |                                 }  | 
5943  |  | 
  | 
5944  | 0  |                                 bTransform = false;  | 
5945  | 0  |                             }  | 
5946  | 0  |                             break;  | 
5947  | 0  |                         }  | 
5948  | 0  |                     }  | 
5949  | 0  |                 }  | 
5950  | 0  |             }  | 
5951  |  | 
  | 
5952  | 0  |             if (!bTransform)  | 
5953  | 0  |             { | 
5954  |  |                 // do nothing  | 
5955  | 0  |             }  | 
5956  | 0  |             else if (psInfo->m_aoReprojectionInfo[iGeom].m_poCT != nullptr &&  | 
5957  | 0  |                      psInfo->m_aoReprojectionInfo[iGeom]  | 
5958  | 0  |                              .m_poCT->GetSourceCS() == poSourceSRS)  | 
5959  | 0  |             { | 
5960  | 0  |                 poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();  | 
5961  | 0  |             }  | 
5962  | 0  |             else  | 
5963  | 0  |             { | 
5964  | 0  |                 OGRCoordinateTransformationOptions options;  | 
5965  | 0  |                 if (psInfo->m_pszCTPipeline)  | 
5966  | 0  |                 { | 
5967  | 0  |                     options.SetCoordinateOperation(psInfo->m_pszCTPipeline,  | 
5968  | 0  |                                                    false);  | 
5969  | 0  |                 }  | 
5970  |  | 
  | 
5971  | 0  |                 bool bWarnAboutDifferentCoordinateOperations =  | 
5972  | 0  |                     poGCPCoordTrans == nullptr &&  | 
5973  | 0  |                     !(poSourceSRS && poSourceSRS->IsGeocentric());  | 
5974  |  | 
  | 
5975  | 0  |                 for (const auto &[key, value] :  | 
5976  | 0  |                      cpl::IterateNameValue(psInfo->m_aosCTOptions))  | 
5977  | 0  |                 { | 
5978  | 0  |                     if (EQUAL(key, "ALLOW_BALLPARK"))  | 
5979  | 0  |                     { | 
5980  | 0  |                         options.SetBallparkAllowed(CPLTestBool(value));  | 
5981  | 0  |                     }  | 
5982  | 0  |                     else if (EQUAL(key, "ONLY_BEST"))  | 
5983  | 0  |                     { | 
5984  | 0  |                         options.SetOnlyBest(CPLTestBool(value));  | 
5985  | 0  |                     }  | 
5986  | 0  |                     else if (EQUAL(key, "WARN_ABOUT_DIFFERENT_COORD_OP"))  | 
5987  | 0  |                     { | 
5988  | 0  |                         if (!CPLTestBool(value))  | 
5989  | 0  |                             bWarnAboutDifferentCoordinateOperations = false;  | 
5990  | 0  |                     }  | 
5991  | 0  |                     else  | 
5992  | 0  |                     { | 
5993  | 0  |                         CPLError(CE_Warning, CPLE_AppDefined,  | 
5994  | 0  |                                  "Unknown coordinate transform option: %s",  | 
5995  | 0  |                                  key);  | 
5996  | 0  |                     }  | 
5997  | 0  |                 }  | 
5998  |  | 
  | 
5999  | 0  |                 poCT = OGRCreateCoordinateTransformation(poSourceSRS,  | 
6000  | 0  |                                                          poOutputSRS, options);  | 
6001  | 0  |                 if (poCT == nullptr)  | 
6002  | 0  |                 { | 
6003  | 0  |                     char *pszWKT = nullptr;  | 
6004  |  | 
  | 
6005  | 0  |                     CPLError(CE_Failure, CPLE_AppDefined,  | 
6006  | 0  |                              "Failed to create coordinate transformation "  | 
6007  | 0  |                              "between the\n"  | 
6008  | 0  |                              "following coordinate systems.  This may be "  | 
6009  | 0  |                              "because they\n"  | 
6010  | 0  |                              "are not transformable.");  | 
6011  |  | 
  | 
6012  | 0  |                     if (poSourceSRS)  | 
6013  | 0  |                     { | 
6014  | 0  |                         poSourceSRS->exportToPrettyWkt(&pszWKT, FALSE);  | 
6015  | 0  |                         CPLError(CE_Failure, CPLE_AppDefined, "Source:\n%s",  | 
6016  | 0  |                                  pszWKT);  | 
6017  | 0  |                         CPLFree(pszWKT);  | 
6018  | 0  |                     }  | 
6019  |  | 
  | 
6020  | 0  |                     if (poOutputSRS)  | 
6021  | 0  |                     { | 
6022  | 0  |                         poOutputSRS->exportToPrettyWkt(&pszWKT, FALSE);  | 
6023  | 0  |                         CPLError(CE_Failure, CPLE_AppDefined, "Target:\n%s",  | 
6024  | 0  |                                  pszWKT);  | 
6025  | 0  |                         CPLFree(pszWKT);  | 
6026  | 0  |                     }  | 
6027  |  | 
  | 
6028  | 0  |                     return false;  | 
6029  | 0  |                 }  | 
6030  | 0  |                 if (poGCPCoordTrans)  | 
6031  | 0  |                     poCT = new CompositeCT(poGCPCoordTrans, false, poCT, true);  | 
6032  | 0  |                 else  | 
6033  | 0  |                     psInfo->m_aoReprojectionInfo[iGeom]  | 
6034  | 0  |                         .m_bWarnAboutDifferentCoordinateOperations =  | 
6035  | 0  |                         bWarnAboutDifferentCoordinateOperations;  | 
6036  | 0  |                 psInfo->m_aoReprojectionInfo[iGeom].m_poCT.reset(poCT);  | 
6037  | 0  |                 psInfo->m_aoReprojectionInfo[iGeom].m_bCanInvalidateValidity =  | 
6038  | 0  |                     !(poGCPCoordTrans == nullptr && poSourceSRS &&  | 
6039  | 0  |                       poSourceSRS->IsGeographic() && poOutputSRS &&  | 
6040  | 0  |                       poOutputSRS->IsGeographic());  | 
6041  | 0  |             }  | 
6042  | 0  |         }  | 
6043  | 0  |         else  | 
6044  | 0  |         { | 
6045  | 0  |             const char *const apszOptions[] = { | 
6046  | 0  |                 "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES",  | 
6047  | 0  |                 "CRITERION=EQUIVALENT", nullptr};  | 
6048  | 0  |             auto poDstGeomFieldDefnSpatialRef =  | 
6049  | 0  |                 poDstGeomFieldDefn->GetSpatialRef();  | 
6050  | 0  |             if (poSourceSRS && poDstGeomFieldDefnSpatialRef &&  | 
6051  | 0  |                 poSourceSRS->GetDataAxisToSRSAxisMapping() !=  | 
6052  | 0  |                     poDstGeomFieldDefnSpatialRef  | 
6053  | 0  |                         ->GetDataAxisToSRSAxisMapping() &&  | 
6054  | 0  |                 poSourceSRS->IsSame(poDstGeomFieldDefnSpatialRef, apszOptions))  | 
6055  | 0  |             { | 
6056  | 0  |                 psInfo->m_aoReprojectionInfo[iGeom].m_poCT.reset(  | 
6057  | 0  |                     new CompositeCT(  | 
6058  | 0  |                         new AxisMappingCoordinateTransformation(  | 
6059  | 0  |                             poSourceSRS->GetDataAxisToSRSAxisMapping(),  | 
6060  | 0  |                             poDstGeomFieldDefnSpatialRef  | 
6061  | 0  |                                 ->GetDataAxisToSRSAxisMapping()),  | 
6062  | 0  |                         true, poGCPCoordTrans, false));  | 
6063  | 0  |                 poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();  | 
6064  | 0  |             }  | 
6065  | 0  |             else if (poGCPCoordTrans)  | 
6066  | 0  |             { | 
6067  | 0  |                 psInfo->m_aoReprojectionInfo[iGeom].m_poCT.reset(  | 
6068  | 0  |                     new CompositeCT(poGCPCoordTrans, false, nullptr, false));  | 
6069  | 0  |                 poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();  | 
6070  | 0  |             }  | 
6071  | 0  |         }  | 
6072  |  |  | 
6073  | 0  |         if (bWrapDateline)  | 
6074  | 0  |         { | 
6075  | 0  |             if (bTransform && poCT != nullptr && poOutputSRS != nullptr &&  | 
6076  | 0  |                 poOutputSRS->IsGeographic())  | 
6077  | 0  |             { | 
6078  | 0  |                 papszTransformOptions =  | 
6079  | 0  |                     CSLAddString(papszTransformOptions, "WRAPDATELINE=YES");  | 
6080  | 0  |                 if (!osDateLineOffset.empty())  | 
6081  | 0  |                 { | 
6082  | 0  |                     CPLString soOffset("DATELINEOFFSET="); | 
6083  | 0  |                     soOffset += osDateLineOffset;  | 
6084  | 0  |                     papszTransformOptions =  | 
6085  | 0  |                         CSLAddString(papszTransformOptions, soOffset);  | 
6086  | 0  |                 }  | 
6087  | 0  |             }  | 
6088  | 0  |             else if (poSourceSRS != nullptr && poSourceSRS->IsGeographic())  | 
6089  | 0  |             { | 
6090  | 0  |                 papszTransformOptions =  | 
6091  | 0  |                     CSLAddString(papszTransformOptions, "WRAPDATELINE=YES");  | 
6092  | 0  |                 if (!osDateLineOffset.empty())  | 
6093  | 0  |                 { | 
6094  | 0  |                     CPLString soOffset("DATELINEOFFSET="); | 
6095  | 0  |                     soOffset += osDateLineOffset;  | 
6096  | 0  |                     papszTransformOptions =  | 
6097  | 0  |                         CSLAddString(papszTransformOptions, soOffset);  | 
6098  | 0  |                 }  | 
6099  | 0  |             }  | 
6100  | 0  |             else  | 
6101  | 0  |             { | 
6102  | 0  |                 CPLErrorOnce(CE_Failure, CPLE_IllegalArg,  | 
6103  | 0  |                              "-wrapdateline option only works when "  | 
6104  | 0  |                              "reprojecting to a geographic SRS");  | 
6105  | 0  |             }  | 
6106  |  | 
  | 
6107  | 0  |             psInfo->m_aoReprojectionInfo[iGeom].m_aosTransformOptions.Assign(  | 
6108  | 0  |                 papszTransformOptions);  | 
6109  | 0  |         }  | 
6110  | 0  |     }  | 
6111  | 0  |     return true;  | 
6112  | 0  | }  | 
6113  |  |  | 
6114  |  | /************************************************************************/  | 
6115  |  | /*                 LayerTranslator::TranslateArrow()                    */  | 
6116  |  | /************************************************************************/  | 
6117  |  |  | 
6118  |  | bool LayerTranslator::TranslateArrow(  | 
6119  |  |     TargetLayerInfo *psInfo, GIntBig nCountLayerFeatures,  | 
6120  |  |     GIntBig *pnReadFeatureCount, GDALProgressFunc pfnProgress,  | 
6121  |  |     void *pProgressArg, const GDALVectorTranslateOptions *psOptions)  | 
6122  | 0  | { | 
6123  | 0  |     struct ArrowSchema schema;  | 
6124  | 0  |     CPLStringList aosOptionsWriteArrowBatch;  | 
6125  | 0  |     if (psInfo->m_bPreserveFID)  | 
6126  | 0  |     { | 
6127  | 0  |         aosOptionsWriteArrowBatch.SetNameValue(  | 
6128  | 0  |             "FID", psInfo->m_poSrcLayer->GetFIDColumn());  | 
6129  | 0  |         aosOptionsWriteArrowBatch.SetNameValue("IF_FID_NOT_PRESERVED", | 
6130  | 0  |                                                "WARNING");  | 
6131  | 0  |     }  | 
6132  |  | 
  | 
6133  | 0  |     if (psInfo->m_sArrowArrayStream.get_schema(&schema) != 0)  | 
6134  | 0  |     { | 
6135  | 0  |         CPLError(CE_Failure, CPLE_AppDefined, "stream.get_schema() failed");  | 
6136  | 0  |         return false;  | 
6137  | 0  |     }  | 
6138  |  |  | 
6139  | 0  |     int iArrowGeomFieldIndex = -1;  | 
6140  | 0  |     if (m_bTransform)  | 
6141  | 0  |     { | 
6142  | 0  |         iArrowGeomFieldIndex = GetArrowGeomFieldIndex(  | 
6143  | 0  |             &schema, psInfo->m_poSrcLayer->GetGeometryColumn());  | 
6144  | 0  |         if (!SetupCT(psInfo, psInfo->m_poSrcLayer, m_bTransform,  | 
6145  | 0  |                      m_bWrapDateline, m_osDateLineOffset, m_poUserSourceSRS,  | 
6146  | 0  |                      nullptr, m_poOutputSRS, m_poGCPCoordTrans, false))  | 
6147  | 0  |         { | 
6148  | 0  |             return false;  | 
6149  | 0  |         }  | 
6150  | 0  |     }  | 
6151  |  |  | 
6152  | 0  |     bool bRet = true;  | 
6153  |  | 
  | 
6154  | 0  |     GIntBig nCount = 0;  | 
6155  | 0  |     bool bGoOn = true;  | 
6156  | 0  |     std::vector<GByte> abyModifiedWKB;  | 
6157  | 0  |     const int nNumReprojectionThreads = []()  | 
6158  | 0  |     { | 
6159  | 0  |         const int nNumCPUs = CPLGetNumCPUs();  | 
6160  | 0  |         if (nNumCPUs <= 1)  | 
6161  | 0  |         { | 
6162  | 0  |             return 1;  | 
6163  | 0  |         }  | 
6164  | 0  |         else  | 
6165  | 0  |         { | 
6166  | 0  |             const char *pszNumThreads =  | 
6167  | 0  |                 CPLGetConfigOption("GDAL_NUM_THREADS", nullptr); | 
6168  | 0  |             if (pszNumThreads)  | 
6169  | 0  |             { | 
6170  | 0  |                 if (EQUAL(pszNumThreads, "ALL_CPUS"))  | 
6171  | 0  |                     return CPLGetNumCPUs();  | 
6172  | 0  |                 return std::min(atoi(pszNumThreads), 1024);  | 
6173  | 0  |             }  | 
6174  | 0  |             else  | 
6175  | 0  |             { | 
6176  | 0  |                 return std::max(2, nNumCPUs / 2);  | 
6177  | 0  |             }  | 
6178  | 0  |         }  | 
6179  | 0  |     }();  | 
6180  |  |  | 
6181  |  |     // Somewhat arbitrary threshold (config option only/mostly for autotest purposes)  | 
6182  | 0  |     const int MIN_FEATURES_FOR_THREADED_REPROJ = atoi(CPLGetConfigOption(  | 
6183  | 0  |         "OGR2OGR_MIN_FEATURES_FOR_THREADED_REPROJ", "10000"));  | 
6184  |  | 
  | 
6185  | 0  |     while (bGoOn)  | 
6186  | 0  |     { | 
6187  | 0  |         struct ArrowArray array;  | 
6188  |  |         // Acquire source batch  | 
6189  | 0  |         if (psInfo->m_sArrowArrayStream.get_next(&array) != 0)  | 
6190  | 0  |         { | 
6191  | 0  |             CPLError(CE_Failure, CPLE_AppDefined, "stream.get_next() failed");  | 
6192  | 0  |             bRet = false;  | 
6193  | 0  |             break;  | 
6194  | 0  |         }  | 
6195  |  |  | 
6196  | 0  |         if (array.release == nullptr)  | 
6197  | 0  |         { | 
6198  |  |             // End of stream  | 
6199  | 0  |             break;  | 
6200  | 0  |         }  | 
6201  |  |  | 
6202  |  |         // Limit number of features in batch if needed  | 
6203  | 0  |         if (psOptions->nLimit >= 0 &&  | 
6204  | 0  |             nCount + array.length >= psOptions->nLimit)  | 
6205  | 0  |         { | 
6206  | 0  |             const auto nAdjustedLength = psOptions->nLimit - nCount;  | 
6207  | 0  |             for (int i = 0; i < array.n_children; ++i)  | 
6208  | 0  |             { | 
6209  | 0  |                 if (array.children[i]->length == array.length)  | 
6210  | 0  |                     array.children[i]->length = nAdjustedLength;  | 
6211  | 0  |             }  | 
6212  | 0  |             array.length = nAdjustedLength;  | 
6213  | 0  |             nCount = psOptions->nLimit;  | 
6214  | 0  |             bGoOn = false;  | 
6215  | 0  |         }  | 
6216  | 0  |         else  | 
6217  | 0  |         { | 
6218  | 0  |             nCount += array.length;  | 
6219  | 0  |         }  | 
6220  |  | 
  | 
6221  | 0  |         const auto nArrayLength = array.length;  | 
6222  |  |  | 
6223  |  |         // Coordinate reprojection  | 
6224  | 0  |         if (m_bTransform)  | 
6225  | 0  |         { | 
6226  | 0  |             struct GeomArrayReleaser  | 
6227  | 0  |             { | 
6228  | 0  |                 const void *origin_buffers_2 = nullptr;  | 
6229  | 0  |                 void (*origin_release)(struct ArrowArray *) = nullptr;  | 
6230  | 0  |                 void *origin_private_data = nullptr;  | 
6231  |  | 
  | 
6232  | 0  |                 static void init(struct ArrowArray *psGeomArray)  | 
6233  | 0  |                 { | 
6234  | 0  |                     GeomArrayReleaser *releaser = new GeomArrayReleaser();  | 
6235  | 0  |                     CPLAssert(psGeomArray->n_buffers >= 3);  | 
6236  | 0  |                     releaser->origin_buffers_2 = psGeomArray->buffers[2];  | 
6237  | 0  |                     releaser->origin_private_data = psGeomArray->private_data;  | 
6238  | 0  |                     releaser->origin_release = psGeomArray->release;  | 
6239  | 0  |                     psGeomArray->release = GeomArrayReleaser::release;  | 
6240  | 0  |                     psGeomArray->private_data = releaser;  | 
6241  | 0  |                 }  | 
6242  |  | 
  | 
6243  | 0  |                 static void release(struct ArrowArray *psGeomArray)  | 
6244  | 0  |                 { | 
6245  | 0  |                     GeomArrayReleaser *releaser =  | 
6246  | 0  |                         static_cast<GeomArrayReleaser *>(  | 
6247  | 0  |                             psGeomArray->private_data);  | 
6248  | 0  |                     psGeomArray->buffers[2] = releaser->origin_buffers_2;  | 
6249  | 0  |                     psGeomArray->private_data = releaser->origin_private_data;  | 
6250  | 0  |                     psGeomArray->release = releaser->origin_release;  | 
6251  | 0  |                     if (psGeomArray->release)  | 
6252  | 0  |                         psGeomArray->release(psGeomArray);  | 
6253  | 0  |                     delete releaser;  | 
6254  | 0  |                 }  | 
6255  | 0  |             };  | 
6256  |  | 
  | 
6257  | 0  |             auto *psGeomArray = array.children[iArrowGeomFieldIndex];  | 
6258  | 0  |             GeomArrayReleaser::init(psGeomArray);  | 
6259  |  | 
  | 
6260  | 0  |             GByte *pabyWKB = static_cast<GByte *>(  | 
6261  | 0  |                 const_cast<void *>(psGeomArray->buffers[2]));  | 
6262  | 0  |             const uint32_t *panOffsets =  | 
6263  | 0  |                 static_cast<const uint32_t *>(psGeomArray->buffers[1]);  | 
6264  | 0  |             auto poCT = psInfo->m_aoReprojectionInfo[0].m_poCT.get();  | 
6265  |  | 
  | 
6266  | 0  |             try  | 
6267  | 0  |             { | 
6268  | 0  |                 abyModifiedWKB.resize(panOffsets[nArrayLength]);  | 
6269  | 0  |             }  | 
6270  | 0  |             catch (const std::exception &)  | 
6271  | 0  |             { | 
6272  | 0  |                 CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");  | 
6273  | 0  |                 bRet = false;  | 
6274  | 0  |                 if (array.release)  | 
6275  | 0  |                     array.release(&array);  | 
6276  | 0  |                 break;  | 
6277  | 0  |             }  | 
6278  | 0  |             memcpy(abyModifiedWKB.data(), pabyWKB, panOffsets[nArrayLength]);  | 
6279  | 0  |             psGeomArray->buffers[2] = abyModifiedWKB.data();  | 
6280  |  |  | 
6281  |  |             // Collect left-most, right-most, top-most, bottom-most coordinates.  | 
6282  | 0  |             if (psInfo->m_aoReprojectionInfo[0]  | 
6283  | 0  |                     .m_bWarnAboutDifferentCoordinateOperations)  | 
6284  | 0  |             { | 
6285  | 0  |                 struct OGRWKBPointVisitor final : public OGRWKBPointUpdater  | 
6286  | 0  |                 { | 
6287  | 0  |                     TargetLayerInfo::ReprojectionInfo &m_info;  | 
6288  |  | 
  | 
6289  | 0  |                     explicit OGRWKBPointVisitor(  | 
6290  | 0  |                         TargetLayerInfo::ReprojectionInfo &info)  | 
6291  | 0  |                         : m_info(info)  | 
6292  | 0  |                     { | 
6293  | 0  |                     }  | 
6294  |  | 
  | 
6295  | 0  |                     bool update(bool bNeedSwap, void *x, void *y, void *z,  | 
6296  | 0  |                                 void * /* m */) override  | 
6297  | 0  |                     { | 
6298  | 0  |                         double dfX, dfY, dfZ;  | 
6299  | 0  |                         memcpy(&dfX, x, sizeof(double));  | 
6300  | 0  |                         memcpy(&dfY, y, sizeof(double));  | 
6301  | 0  |                         if (bNeedSwap)  | 
6302  | 0  |                         { | 
6303  | 0  |                             CPL_SWAP64PTR(&dfX);  | 
6304  | 0  |                             CPL_SWAP64PTR(&dfY);  | 
6305  | 0  |                         }  | 
6306  | 0  |                         if (z)  | 
6307  | 0  |                         { | 
6308  | 0  |                             memcpy(&dfZ, z, sizeof(double));  | 
6309  | 0  |                             if (bNeedSwap)  | 
6310  | 0  |                             { | 
6311  | 0  |                                 CPL_SWAP64PTR(&dfZ);  | 
6312  | 0  |                             }  | 
6313  | 0  |                         }  | 
6314  | 0  |                         else  | 
6315  | 0  |                             dfZ = 0;  | 
6316  | 0  |                         m_info.UpdateExtremePoints(dfX, dfY, dfZ);  | 
6317  | 0  |                         return true;  | 
6318  | 0  |                     }  | 
6319  | 0  |                 };  | 
6320  |  | 
  | 
6321  | 0  |                 OGRWKBPointVisitor oVisitor(psInfo->m_aoReprojectionInfo[0]);  | 
6322  | 0  |                 const GByte *pabyValidity =  | 
6323  | 0  |                     static_cast<const GByte *>(psGeomArray->buffers[0]);  | 
6324  |  | 
  | 
6325  | 0  |                 for (size_t i = 0; i < static_cast<size_t>(nArrayLength); ++i)  | 
6326  | 0  |                 { | 
6327  | 0  |                     const size_t iShifted =  | 
6328  | 0  |                         static_cast<size_t>(i + psGeomArray->offset);  | 
6329  | 0  |                     if (!pabyValidity || (pabyValidity[iShifted >> 8] &  | 
6330  | 0  |                                           (1 << (iShifted % 8))) != 0)  | 
6331  | 0  |                     { | 
6332  | 0  |                         const auto nWKBSize =  | 
6333  | 0  |                             panOffsets[iShifted + 1] - panOffsets[iShifted];  | 
6334  | 0  |                         OGRWKBUpdatePoints(abyModifiedWKB.data() +  | 
6335  | 0  |                                                panOffsets[iShifted],  | 
6336  | 0  |                                            nWKBSize, oVisitor);  | 
6337  | 0  |                     }  | 
6338  | 0  |                 }  | 
6339  | 0  |             }  | 
6340  |  | 
  | 
6341  | 0  |             std::atomic<bool> atomicRet{true}; | 
6342  | 0  |             const auto oReprojectionLambda =  | 
6343  | 0  |                 [psGeomArray, nArrayLength, panOffsets, &atomicRet,  | 
6344  | 0  |                  &abyModifiedWKB, &poCT](int iThread, int nThreads)  | 
6345  | 0  |             { | 
6346  | 0  |                 OGRWKBTransformCache oCache;  | 
6347  | 0  |                 OGREnvelope3D sEnv3D;  | 
6348  | 0  |                 auto poThisCT =  | 
6349  | 0  |                     std::unique_ptr<OGRCoordinateTransformation>(poCT->Clone());  | 
6350  | 0  |                 if (!poThisCT)  | 
6351  | 0  |                 { | 
6352  | 0  |                     CPLError(CE_Failure, CPLE_AppDefined,  | 
6353  | 0  |                              "Cannot clone OGRCoordinateTransformation");  | 
6354  | 0  |                     atomicRet = false;  | 
6355  | 0  |                     return;  | 
6356  | 0  |                 }  | 
6357  |  |  | 
6358  | 0  |                 const GByte *pabyValidity =  | 
6359  | 0  |                     static_cast<const GByte *>(psGeomArray->buffers[0]);  | 
6360  | 0  |                 const size_t iStart =  | 
6361  | 0  |                     static_cast<size_t>(iThread * nArrayLength / nThreads);  | 
6362  | 0  |                 const size_t iMax = static_cast<size_t>(  | 
6363  | 0  |                     (iThread + 1) * nArrayLength / nThreads);  | 
6364  | 0  |                 for (size_t i = iStart; i < iMax; ++i)  | 
6365  | 0  |                 { | 
6366  | 0  |                     const size_t iShifted =  | 
6367  | 0  |                         static_cast<size_t>(i + psGeomArray->offset);  | 
6368  | 0  |                     if (!pabyValidity || (pabyValidity[iShifted >> 8] &  | 
6369  | 0  |                                           (1 << (iShifted % 8))) != 0)  | 
6370  | 0  |                     { | 
6371  | 0  |                         const auto nWKBSize =  | 
6372  | 0  |                             panOffsets[iShifted + 1] - panOffsets[iShifted];  | 
6373  | 0  |                         if (!OGRWKBTransform(  | 
6374  | 0  |                                 abyModifiedWKB.data() + panOffsets[iShifted],  | 
6375  | 0  |                                 nWKBSize, poThisCT.get(), oCache, sEnv3D))  | 
6376  | 0  |                         { | 
6377  | 0  |                             CPLError(CE_Failure, CPLE_AppDefined,  | 
6378  | 0  |                                      "Reprojection failed");  | 
6379  | 0  |                             atomicRet = false;  | 
6380  | 0  |                             break;  | 
6381  | 0  |                         }  | 
6382  | 0  |                     }  | 
6383  | 0  |                 }  | 
6384  | 0  |             };  | 
6385  |  | 
  | 
6386  | 0  |             if (nArrayLength >= MIN_FEATURES_FOR_THREADED_REPROJ &&  | 
6387  | 0  |                 nNumReprojectionThreads >= 2)  | 
6388  | 0  |             { | 
6389  | 0  |                 std::vector<std::future<void>> oTasks;  | 
6390  | 0  |                 for (int iThread = 0; iThread < nNumReprojectionThreads;  | 
6391  | 0  |                      ++iThread)  | 
6392  | 0  |                 { | 
6393  | 0  |                     oTasks.emplace_back(std::async(std::launch::async,  | 
6394  | 0  |                                                    oReprojectionLambda, iThread,  | 
6395  | 0  |                                                    nNumReprojectionThreads));  | 
6396  | 0  |                 }  | 
6397  | 0  |                 for (auto &oTask : oTasks)  | 
6398  | 0  |                 { | 
6399  | 0  |                     oTask.get();  | 
6400  | 0  |                 }  | 
6401  | 0  |             }  | 
6402  | 0  |             else  | 
6403  | 0  |             { | 
6404  | 0  |                 oReprojectionLambda(0, 1);  | 
6405  | 0  |             }  | 
6406  |  | 
  | 
6407  | 0  |             bRet = atomicRet;  | 
6408  | 0  |             if (!bRet)  | 
6409  | 0  |             { | 
6410  | 0  |                 if (array.release)  | 
6411  | 0  |                     array.release(&array);  | 
6412  | 0  |                 break;  | 
6413  | 0  |             }  | 
6414  | 0  |         }  | 
6415  |  |  | 
6416  |  |         // Write batch to target layer  | 
6417  | 0  |         const bool bWriteOK = psInfo->m_poDstLayer->WriteArrowBatch(  | 
6418  | 0  |             &schema, &array, aosOptionsWriteArrowBatch.List());  | 
6419  |  | 
  | 
6420  | 0  |         if (array.release)  | 
6421  | 0  |             array.release(&array);  | 
6422  |  | 
  | 
6423  | 0  |         if (!bWriteOK)  | 
6424  | 0  |         { | 
6425  | 0  |             CPLError(CE_Failure, CPLE_AppDefined, "WriteArrowBatch() failed");  | 
6426  | 0  |             bRet = false;  | 
6427  | 0  |             break;  | 
6428  | 0  |         }  | 
6429  |  |  | 
6430  |  |         /* Report progress */  | 
6431  | 0  |         if (pfnProgress)  | 
6432  | 0  |         { | 
6433  | 0  |             if (!pfnProgress(nCountLayerFeatures  | 
6434  | 0  |                                  ? nCount * 1.0 / nCountLayerFeatures  | 
6435  | 0  |                                  : 1.0,  | 
6436  | 0  |                              "", pProgressArg))  | 
6437  | 0  |             { | 
6438  | 0  |                 bGoOn = false;  | 
6439  | 0  |                 bRet = false;  | 
6440  | 0  |             }  | 
6441  | 0  |         }  | 
6442  |  | 
  | 
6443  | 0  |         if (pnReadFeatureCount)  | 
6444  | 0  |             *pnReadFeatureCount = nCount;  | 
6445  | 0  |     }  | 
6446  |  |  | 
6447  | 0  |     schema.release(&schema);  | 
6448  |  | 
  | 
6449  | 0  |     return bRet;  | 
6450  | 0  | }  | 
6451  |  |  | 
6452  |  | /************************************************************************/  | 
6453  |  | /*                     LayerTranslator::Translate()                     */  | 
6454  |  | /************************************************************************/  | 
6455  |  |  | 
6456  |  | bool LayerTranslator::Translate(  | 
6457  |  |     OGRFeature *poFeatureIn, TargetLayerInfo *psInfo,  | 
6458  |  |     GIntBig nCountLayerFeatures, GIntBig *pnReadFeatureCount,  | 
6459  |  |     GIntBig &nTotalEventsDone, GDALProgressFunc pfnProgress, void *pProgressArg,  | 
6460  |  |     const GDALVectorTranslateOptions *psOptions)  | 
6461  | 0  | { | 
6462  | 0  |     if (psInfo->m_bUseWriteArrowBatch)  | 
6463  | 0  |     { | 
6464  | 0  |         return TranslateArrow(psInfo, nCountLayerFeatures, pnReadFeatureCount,  | 
6465  | 0  |                               pfnProgress, pProgressArg, psOptions);  | 
6466  | 0  |     }  | 
6467  |  |  | 
6468  | 0  |     const int eGType = m_eGType;  | 
6469  | 0  |     const OGRSpatialReference *poOutputSRS = m_poOutputSRS;  | 
6470  |  | 
  | 
6471  | 0  |     OGRLayer *poSrcLayer = psInfo->m_poSrcLayer;  | 
6472  | 0  |     OGRLayer *poDstLayer = psInfo->m_poDstLayer;  | 
6473  | 0  |     const int *const panMap = psInfo->m_anMap.data();  | 
6474  | 0  |     const int iSrcZField = psInfo->m_iSrcZField;  | 
6475  | 0  |     const bool bPreserveFID = psInfo->m_bPreserveFID;  | 
6476  | 0  |     const auto poSrcFDefn = poSrcLayer->GetLayerDefn();  | 
6477  | 0  |     const auto poDstFDefn = poDstLayer->GetLayerDefn();  | 
6478  | 0  |     const int nSrcGeomFieldCount = poSrcFDefn->GetGeomFieldCount();  | 
6479  | 0  |     const int nDstGeomFieldCount = poDstFDefn->GetGeomFieldCount();  | 
6480  | 0  |     const bool bExplodeCollections =  | 
6481  | 0  |         m_bExplodeCollections && nDstGeomFieldCount <= 1;  | 
6482  | 0  |     const int iRequestedSrcGeomField = psInfo->m_iRequestedSrcGeomField;  | 
6483  |  | 
  | 
6484  | 0  |     if (poOutputSRS == nullptr && !m_bNullifyOutputSRS)  | 
6485  | 0  |     { | 
6486  | 0  |         if (nSrcGeomFieldCount == 1)  | 
6487  | 0  |         { | 
6488  | 0  |             poOutputSRS = poSrcLayer->GetSpatialRef();  | 
6489  | 0  |         }  | 
6490  | 0  |         else if (iRequestedSrcGeomField > 0)  | 
6491  | 0  |         { | 
6492  | 0  |             poOutputSRS = poSrcLayer->GetLayerDefn()  | 
6493  | 0  |                               ->GetGeomFieldDefn(iRequestedSrcGeomField)  | 
6494  | 0  |                               ->GetSpatialRef();  | 
6495  | 0  |         }  | 
6496  | 0  |     }  | 
6497  |  |  | 
6498  |  |     /* -------------------------------------------------------------------- */  | 
6499  |  |     /*      Transfer features.                                              */  | 
6500  |  |     /* -------------------------------------------------------------------- */  | 
6501  | 0  |     if (psOptions->nGroupTransactions)  | 
6502  | 0  |     { | 
6503  | 0  |         if (psOptions->nLayerTransaction)  | 
6504  | 0  |         { | 
6505  | 0  |             if (poDstLayer->StartTransaction() == OGRERR_FAILURE)  | 
6506  | 0  |             { | 
6507  | 0  |                 delete poFeatureIn;  | 
6508  | 0  |                 return false;  | 
6509  | 0  |             }  | 
6510  | 0  |         }  | 
6511  | 0  |     }  | 
6512  |  |  | 
6513  | 0  |     std::unique_ptr<OGRFeature> poFeature;  | 
6514  | 0  |     std::unique_ptr<OGRFeature> poDstFeature(new OGRFeature(poDstFDefn));  | 
6515  | 0  |     int nFeaturesInTransaction = 0;  | 
6516  | 0  |     GIntBig nCount = 0; /* written + failed */  | 
6517  | 0  |     GIntBig nFeaturesWritten = 0;  | 
6518  | 0  |     bool bRunSetPrecisionEvaluated = false;  | 
6519  | 0  |     bool bRunSetPrecision = false;  | 
6520  |  | 
  | 
6521  | 0  |     bool bRet = true;  | 
6522  | 0  |     CPLErrorReset();  | 
6523  |  | 
  | 
6524  | 0  |     bool bSetupCTOK = false;  | 
6525  | 0  |     if (m_bTransform && psInfo->m_nFeaturesRead == 0 &&  | 
6526  | 0  |         !psInfo->m_bPerFeatureCT)  | 
6527  | 0  |     { | 
6528  | 0  |         bSetupCTOK = SetupCT(psInfo, poSrcLayer, m_bTransform, m_bWrapDateline,  | 
6529  | 0  |                              m_osDateLineOffset, m_poUserSourceSRS, nullptr,  | 
6530  | 0  |                              poOutputSRS, m_poGCPCoordTrans, false);  | 
6531  | 0  |     }  | 
6532  |  | 
  | 
6533  | 0  |     while (true)  | 
6534  | 0  |     { | 
6535  | 0  |         if (m_nLimit >= 0 && psInfo->m_nFeaturesRead >= m_nLimit)  | 
6536  | 0  |         { | 
6537  | 0  |             break;  | 
6538  | 0  |         }  | 
6539  |  |  | 
6540  | 0  |         if (poFeatureIn != nullptr)  | 
6541  | 0  |             poFeature.reset(poFeatureIn);  | 
6542  | 0  |         else if (psOptions->nFIDToFetch != OGRNullFID)  | 
6543  | 0  |             poFeature.reset(poSrcLayer->GetFeature(psOptions->nFIDToFetch));  | 
6544  | 0  |         else  | 
6545  | 0  |             poFeature.reset(poSrcLayer->GetNextFeature());  | 
6546  |  | 
  | 
6547  | 0  |         if (poFeature == nullptr)  | 
6548  | 0  |         { | 
6549  | 0  |             if (CPLGetLastErrorType() == CE_Failure)  | 
6550  | 0  |             { | 
6551  | 0  |                 bRet = false;  | 
6552  | 0  |             }  | 
6553  | 0  |             break;  | 
6554  | 0  |         }  | 
6555  |  |  | 
6556  | 0  |         if (!bSetupCTOK &&  | 
6557  | 0  |             (psInfo->m_nFeaturesRead == 0 || psInfo->m_bPerFeatureCT))  | 
6558  | 0  |         { | 
6559  | 0  |             if (!SetupCT(psInfo, poSrcLayer, m_bTransform, m_bWrapDateline,  | 
6560  | 0  |                          m_osDateLineOffset, m_poUserSourceSRS, poFeature.get(),  | 
6561  | 0  |                          poOutputSRS, m_poGCPCoordTrans, true))  | 
6562  | 0  |             { | 
6563  | 0  |                 return false;  | 
6564  | 0  |             }  | 
6565  | 0  |         }  | 
6566  |  |  | 
6567  | 0  |         psInfo->m_nFeaturesRead++;  | 
6568  |  | 
  | 
6569  | 0  |         int nIters = 1;  | 
6570  | 0  |         std::unique_ptr<OGRGeometryCollection> poCollToExplode;  | 
6571  | 0  |         int iGeomCollToExplode = -1;  | 
6572  | 0  |         OGRGeometry *poSrcGeometry = nullptr;  | 
6573  | 0  |         if (bExplodeCollections)  | 
6574  | 0  |         { | 
6575  | 0  |             if (iRequestedSrcGeomField >= 0)  | 
6576  | 0  |                 poSrcGeometry =  | 
6577  | 0  |                     poFeature->GetGeomFieldRef(iRequestedSrcGeomField);  | 
6578  | 0  |             else  | 
6579  | 0  |                 poSrcGeometry = poFeature->GetGeometryRef();  | 
6580  | 0  |             if (poSrcGeometry &&  | 
6581  | 0  |                 OGR_GT_IsSubClassOf(poSrcGeometry->getGeometryType(),  | 
6582  | 0  |                                     wkbGeometryCollection))  | 
6583  | 0  |             { | 
6584  | 0  |                 const int nParts =  | 
6585  | 0  |                     poSrcGeometry->toGeometryCollection()->getNumGeometries();  | 
6586  | 0  |                 if (nParts > 0 ||  | 
6587  | 0  |                     wkbFlatten(poSrcGeometry->getGeometryType()) !=  | 
6588  | 0  |                         wkbGeometryCollection)  | 
6589  | 0  |                 { | 
6590  | 0  |                     iGeomCollToExplode = iRequestedSrcGeomField >= 0  | 
6591  | 0  |                                              ? iRequestedSrcGeomField  | 
6592  | 0  |                                              : 0;  | 
6593  | 0  |                     poCollToExplode.reset(  | 
6594  | 0  |                         poFeature->StealGeometry(iGeomCollToExplode)  | 
6595  | 0  |                             ->toGeometryCollection());  | 
6596  | 0  |                     nIters = std::max(1, nParts);  | 
6597  | 0  |                 }  | 
6598  | 0  |             }  | 
6599  | 0  |         }  | 
6600  |  | 
  | 
6601  | 0  |         const GIntBig nSrcFID = poFeature->GetFID();  | 
6602  | 0  |         GIntBig nDesiredFID = OGRNullFID;  | 
6603  | 0  |         if (bPreserveFID)  | 
6604  | 0  |             nDesiredFID = nSrcFID;  | 
6605  | 0  |         else if (psInfo->m_iSrcFIDField >= 0 &&  | 
6606  | 0  |                  poFeature->IsFieldSetAndNotNull(psInfo->m_iSrcFIDField))  | 
6607  | 0  |             nDesiredFID =  | 
6608  | 0  |                 poFeature->GetFieldAsInteger64(psInfo->m_iSrcFIDField);  | 
6609  |  | 
  | 
6610  | 0  |         for (int iPart = 0; iPart < nIters; iPart++)  | 
6611  | 0  |         { | 
6612  | 0  |             if (psOptions->nLayerTransaction &&  | 
6613  | 0  |                 ++nFeaturesInTransaction == psOptions->nGroupTransactions)  | 
6614  | 0  |             { | 
6615  | 0  |                 if (poDstLayer->CommitTransaction() == OGRERR_FAILURE ||  | 
6616  | 0  |                     poDstLayer->StartTransaction() == OGRERR_FAILURE)  | 
6617  | 0  |                 { | 
6618  | 0  |                     return false;  | 
6619  | 0  |                 }  | 
6620  | 0  |                 nFeaturesInTransaction = 0;  | 
6621  | 0  |             }  | 
6622  | 0  |             else if (!psOptions->nLayerTransaction &&  | 
6623  | 0  |                      psOptions->nGroupTransactions > 0 &&  | 
6624  | 0  |                      ++nTotalEventsDone >= psOptions->nGroupTransactions)  | 
6625  | 0  |             { | 
6626  | 0  |                 if (m_poODS->CommitTransaction() == OGRERR_FAILURE ||  | 
6627  | 0  |                     m_poODS->StartTransaction(psOptions->bForceTransaction) ==  | 
6628  | 0  |                         OGRERR_FAILURE)  | 
6629  | 0  |                 { | 
6630  | 0  |                     return false;  | 
6631  | 0  |                 }  | 
6632  | 0  |                 nTotalEventsDone = 0;  | 
6633  | 0  |             }  | 
6634  |  |  | 
6635  | 0  |             CPLErrorReset();  | 
6636  | 0  |             if (psInfo->m_bCanAvoidSetFrom)  | 
6637  | 0  |             { | 
6638  | 0  |                 poDstFeature = std::move(poFeature);  | 
6639  |  |                 // From now on, poFeature is null !  | 
6640  | 0  |                 poDstFeature->SetFDefnUnsafe(poDstFDefn);  | 
6641  | 0  |                 poDstFeature->SetFID(nDesiredFID);  | 
6642  | 0  |             }  | 
6643  | 0  |             else  | 
6644  | 0  |             { | 
6645  |  |                 /* Optimization to avoid duplicating the source geometry in the  | 
6646  |  |                  */  | 
6647  |  |                 /* target feature : we steal it from the source feature for  | 
6648  |  |                  * now... */  | 
6649  | 0  |                 std::unique_ptr<OGRGeometry> poStolenGeometry;  | 
6650  | 0  |                 if (!bExplodeCollections && nSrcGeomFieldCount == 1 &&  | 
6651  | 0  |                     (nDstGeomFieldCount == 1 ||  | 
6652  | 0  |                      (nDstGeomFieldCount == 0 && m_poClipSrcOri)))  | 
6653  | 0  |                 { | 
6654  | 0  |                     poStolenGeometry.reset(poFeature->StealGeometry());  | 
6655  | 0  |                 }  | 
6656  | 0  |                 else if (!bExplodeCollections && iRequestedSrcGeomField >= 0)  | 
6657  | 0  |                 { | 
6658  | 0  |                     poStolenGeometry.reset(  | 
6659  | 0  |                         poFeature->StealGeometry(iRequestedSrcGeomField));  | 
6660  | 0  |                 }  | 
6661  |  | 
  | 
6662  | 0  |                 if (nDstGeomFieldCount == 0 && poStolenGeometry &&  | 
6663  | 0  |                     m_poClipSrcOri)  | 
6664  | 0  |                 { | 
6665  | 0  |                     if (poStolenGeometry->IsEmpty())  | 
6666  | 0  |                         goto end_loop;  | 
6667  |  |  | 
6668  | 0  |                     const auto clipGeomDesc =  | 
6669  | 0  |                         GetSrcClipGeom(poStolenGeometry->getSpatialReference());  | 
6670  |  | 
  | 
6671  | 0  |                     if (clipGeomDesc.poGeom && clipGeomDesc.poEnv)  | 
6672  | 0  |                     { | 
6673  | 0  |                         OGREnvelope oEnv;  | 
6674  | 0  |                         poStolenGeometry->getEnvelope(&oEnv);  | 
6675  | 0  |                         if (!clipGeomDesc.poEnv->Contains(oEnv) &&  | 
6676  | 0  |                             !(clipGeomDesc.poEnv->Intersects(oEnv) &&  | 
6677  | 0  |                               clipGeomDesc.poGeom->Intersects(  | 
6678  | 0  |                                   poStolenGeometry.get())))  | 
6679  | 0  |                         { | 
6680  | 0  |                             goto end_loop;  | 
6681  | 0  |                         }  | 
6682  | 0  |                     }  | 
6683  | 0  |                 }  | 
6684  |  |  | 
6685  | 0  |                 poDstFeature->Reset();  | 
6686  |  | 
  | 
6687  | 0  |                 if (poDstFeature->SetFrom(  | 
6688  | 0  |                         poFeature.get(), panMap, /* bForgiving = */ TRUE,  | 
6689  | 0  |                         /* bUseISO8601ForDateTimeAsString = */ true) !=  | 
6690  | 0  |                     OGRERR_NONE)  | 
6691  | 0  |                 { | 
6692  | 0  |                     if (psOptions->nGroupTransactions)  | 
6693  | 0  |                     { | 
6694  | 0  |                         if (psOptions->nLayerTransaction)  | 
6695  | 0  |                         { | 
6696  | 0  |                             if (poDstLayer->CommitTransaction() != OGRERR_NONE)  | 
6697  | 0  |                             { | 
6698  | 0  |                                 return false;  | 
6699  | 0  |                             }  | 
6700  | 0  |                         }  | 
6701  | 0  |                     }  | 
6702  |  |  | 
6703  | 0  |                     CPLError(CE_Failure, CPLE_AppDefined,  | 
6704  | 0  |                              "Unable to translate feature " CPL_FRMT_GIB  | 
6705  | 0  |                              " from layer %s.",  | 
6706  | 0  |                              nSrcFID, poSrcLayer->GetName());  | 
6707  |  | 
  | 
6708  | 0  |                     return false;  | 
6709  | 0  |                 }  | 
6710  |  |  | 
6711  |  |                 /* ... and now we can attach the stolen geometry */  | 
6712  | 0  |                 if (poStolenGeometry)  | 
6713  | 0  |                 { | 
6714  | 0  |                     poDstFeature->SetGeometryDirectly(  | 
6715  | 0  |                         poStolenGeometry.release());  | 
6716  | 0  |                 }  | 
6717  |  | 
  | 
6718  | 0  |                 if (!psInfo->m_oMapResolved.empty())  | 
6719  | 0  |                 { | 
6720  | 0  |                     for (const auto &kv : psInfo->m_oMapResolved)  | 
6721  | 0  |                     { | 
6722  | 0  |                         const int nDstField = kv.first;  | 
6723  | 0  |                         const int nSrcField = kv.second.nSrcField;  | 
6724  | 0  |                         if (poFeature->IsFieldSetAndNotNull(nSrcField))  | 
6725  | 0  |                         { | 
6726  | 0  |                             const auto poDomain = kv.second.poDomain;  | 
6727  | 0  |                             const auto &oMapKV =  | 
6728  | 0  |                                 psInfo->m_oMapDomainToKV[poDomain];  | 
6729  | 0  |                             const auto iter = oMapKV.find(  | 
6730  | 0  |                                 poFeature->GetFieldAsString(nSrcField));  | 
6731  | 0  |                             if (iter != oMapKV.end())  | 
6732  | 0  |                             { | 
6733  | 0  |                                 poDstFeature->SetField(nDstField,  | 
6734  | 0  |                                                        iter->second.c_str());  | 
6735  | 0  |                             }  | 
6736  | 0  |                         }  | 
6737  | 0  |                     }  | 
6738  | 0  |                 }  | 
6739  |  | 
  | 
6740  | 0  |                 if (nDesiredFID != OGRNullFID)  | 
6741  | 0  |                     poDstFeature->SetFID(nDesiredFID);  | 
6742  | 0  |             }  | 
6743  |  |  | 
6744  | 0  |             if (psOptions->bEmptyStrAsNull)  | 
6745  | 0  |             { | 
6746  | 0  |                 for (int i = 0; i < poDstFeature->GetFieldCount(); i++)  | 
6747  | 0  |                 { | 
6748  | 0  |                     if (!poDstFeature->IsFieldSetAndNotNull(i))  | 
6749  | 0  |                         continue;  | 
6750  | 0  |                     auto fieldDef = poDstFeature->GetFieldDefnRef(i);  | 
6751  | 0  |                     if (fieldDef->GetType() != OGRFieldType::OFTString)  | 
6752  | 0  |                         continue;  | 
6753  | 0  |                     auto str = poDstFeature->GetFieldAsString(i);  | 
6754  | 0  |                     if (strcmp(str, "") == 0)  | 
6755  | 0  |                         poDstFeature->SetFieldNull(i);  | 
6756  | 0  |                 }  | 
6757  | 0  |             }  | 
6758  |  | 
  | 
6759  | 0  |             if (!psInfo->m_anDateTimeFieldIdx.empty())  | 
6760  | 0  |             { | 
6761  | 0  |                 for (int i : psInfo->m_anDateTimeFieldIdx)  | 
6762  | 0  |                 { | 
6763  | 0  |                     if (!poDstFeature->IsFieldSetAndNotNull(i))  | 
6764  | 0  |                         continue;  | 
6765  | 0  |                     auto psField = poDstFeature->GetRawFieldRef(i);  | 
6766  | 0  |                     if (psField->Date.TZFlag == 0 || psField->Date.TZFlag == 1)  | 
6767  | 0  |                         continue;  | 
6768  |  |  | 
6769  | 0  |                     const int nTZOffsetInSec =  | 
6770  | 0  |                         (psField->Date.TZFlag - 100) * 15 * 60;  | 
6771  | 0  |                     if (nTZOffsetInSec == psOptions->nTZOffsetInSec)  | 
6772  | 0  |                         continue;  | 
6773  |  |  | 
6774  | 0  |                     struct tm brokendowntime;  | 
6775  | 0  |                     memset(&brokendowntime, 0, sizeof(brokendowntime));  | 
6776  | 0  |                     brokendowntime.tm_year = psField->Date.Year - 1900;  | 
6777  | 0  |                     brokendowntime.tm_mon = psField->Date.Month - 1;  | 
6778  | 0  |                     brokendowntime.tm_mday = psField->Date.Day;  | 
6779  | 0  |                     GIntBig nUnixTime = CPLYMDHMSToUnixTime(&brokendowntime);  | 
6780  | 0  |                     int nSec = psField->Date.Hour * 3600 +  | 
6781  | 0  |                                psField->Date.Minute * 60 +  | 
6782  | 0  |                                static_cast<int>(psField->Date.Second);  | 
6783  | 0  |                     nSec += psOptions->nTZOffsetInSec - nTZOffsetInSec;  | 
6784  | 0  |                     nUnixTime += nSec;  | 
6785  | 0  |                     CPLUnixTimeToYMDHMS(nUnixTime, &brokendowntime);  | 
6786  |  | 
  | 
6787  | 0  |                     psField->Date.Year =  | 
6788  | 0  |                         static_cast<GInt16>(brokendowntime.tm_year + 1900);  | 
6789  | 0  |                     psField->Date.Month =  | 
6790  | 0  |                         static_cast<GByte>(brokendowntime.tm_mon + 1);  | 
6791  | 0  |                     psField->Date.Day =  | 
6792  | 0  |                         static_cast<GByte>(brokendowntime.tm_mday);  | 
6793  | 0  |                     psField->Date.Hour =  | 
6794  | 0  |                         static_cast<GByte>(brokendowntime.tm_hour);  | 
6795  | 0  |                     psField->Date.Minute =  | 
6796  | 0  |                         static_cast<GByte>(brokendowntime.tm_min);  | 
6797  | 0  |                     psField->Date.Second = static_cast<float>(  | 
6798  | 0  |                         brokendowntime.tm_sec + fmod(psField->Date.Second, 1));  | 
6799  | 0  |                     psField->Date.TZFlag = static_cast<GByte>(  | 
6800  | 0  |                         100 + psOptions->nTZOffsetInSec / (15 * 60));  | 
6801  | 0  |                 }  | 
6802  | 0  |             }  | 
6803  |  |  | 
6804  |  |             /* Erase native data if asked explicitly */  | 
6805  | 0  |             if (!m_bNativeData)  | 
6806  | 0  |             { | 
6807  | 0  |                 poDstFeature->SetNativeData(nullptr);  | 
6808  | 0  |                 poDstFeature->SetNativeMediaType(nullptr);  | 
6809  | 0  |             }  | 
6810  |  | 
  | 
6811  | 0  |             for (int iGeom = 0; iGeom < nDstGeomFieldCount; iGeom++)  | 
6812  | 0  |             { | 
6813  | 0  |                 std::unique_ptr<OGRGeometry> poDstGeometry;  | 
6814  |  | 
  | 
6815  | 0  |                 if (poCollToExplode && iGeom == iGeomCollToExplode)  | 
6816  | 0  |                 { | 
6817  | 0  |                     if (poSrcGeometry && poCollToExplode->IsEmpty())  | 
6818  | 0  |                     { | 
6819  | 0  |                         const OGRwkbGeometryType eSrcType =  | 
6820  | 0  |                             poSrcGeometry->getGeometryType();  | 
6821  | 0  |                         const OGRwkbGeometryType eSrcFlattenType =  | 
6822  | 0  |                             wkbFlatten(eSrcType);  | 
6823  | 0  |                         OGRwkbGeometryType eDstType = eSrcType;  | 
6824  | 0  |                         switch (eSrcFlattenType)  | 
6825  | 0  |                         { | 
6826  | 0  |                             case wkbMultiPoint:  | 
6827  | 0  |                                 eDstType = wkbPoint;  | 
6828  | 0  |                                 break;  | 
6829  | 0  |                             case wkbMultiLineString:  | 
6830  | 0  |                                 eDstType = wkbLineString;  | 
6831  | 0  |                                 break;  | 
6832  | 0  |                             case wkbMultiPolygon:  | 
6833  | 0  |                                 eDstType = wkbPolygon;  | 
6834  | 0  |                                 break;  | 
6835  | 0  |                             case wkbMultiCurve:  | 
6836  | 0  |                                 eDstType = wkbCompoundCurve;  | 
6837  | 0  |                                 break;  | 
6838  | 0  |                             case wkbMultiSurface:  | 
6839  | 0  |                                 eDstType = wkbCurvePolygon;  | 
6840  | 0  |                                 break;  | 
6841  | 0  |                             default:  | 
6842  | 0  |                                 break;  | 
6843  | 0  |                         }  | 
6844  | 0  |                         eDstType =  | 
6845  | 0  |                             OGR_GT_SetModifier(eDstType, OGR_GT_HasZ(eSrcType),  | 
6846  | 0  |                                                OGR_GT_HasM(eSrcType));  | 
6847  | 0  |                         poDstGeometry.reset(  | 
6848  | 0  |                             OGRGeometryFactory::createGeometry(eDstType));  | 
6849  | 0  |                     }  | 
6850  | 0  |                     else  | 
6851  | 0  |                     { | 
6852  | 0  |                         OGRGeometry *poPart =  | 
6853  | 0  |                             poCollToExplode->getGeometryRef(0);  | 
6854  | 0  |                         poCollToExplode->removeGeometry(0, FALSE);  | 
6855  | 0  |                         poDstGeometry.reset(poPart);  | 
6856  | 0  |                     }  | 
6857  | 0  |                 }  | 
6858  | 0  |                 else  | 
6859  | 0  |                 { | 
6860  | 0  |                     poDstGeometry.reset(poDstFeature->StealGeometry(iGeom));  | 
6861  | 0  |                 }  | 
6862  | 0  |                 if (poDstGeometry == nullptr)  | 
6863  | 0  |                     continue;  | 
6864  |  |  | 
6865  |  |                 // poFeature hasn't been moved if iSrcZField != -1  | 
6866  |  |                 // cppcheck-suppress accessMoved  | 
6867  | 0  |                 if (iSrcZField != -1 && poFeature != nullptr)  | 
6868  | 0  |                 { | 
6869  | 0  |                     SetZ(poDstGeometry.get(),  | 
6870  | 0  |                          poFeature->GetFieldAsDouble(iSrcZField));  | 
6871  |  |                     /* This will correct the coordinate dimension to 3 */  | 
6872  | 0  |                     poDstGeometry.reset(poDstGeometry->clone());  | 
6873  | 0  |                 }  | 
6874  |  | 
  | 
6875  | 0  |                 if (m_nCoordDim == 2 || m_nCoordDim == 3)  | 
6876  | 0  |                 { | 
6877  | 0  |                     poDstGeometry->setCoordinateDimension(m_nCoordDim);  | 
6878  | 0  |                 }  | 
6879  | 0  |                 else if (m_nCoordDim == 4)  | 
6880  | 0  |                 { | 
6881  | 0  |                     poDstGeometry->set3D(TRUE);  | 
6882  | 0  |                     poDstGeometry->setMeasured(TRUE);  | 
6883  | 0  |                 }  | 
6884  | 0  |                 else if (m_nCoordDim == COORD_DIM_XYM)  | 
6885  | 0  |                 { | 
6886  | 0  |                     poDstGeometry->set3D(FALSE);  | 
6887  | 0  |                     poDstGeometry->setMeasured(TRUE);  | 
6888  | 0  |                 }  | 
6889  | 0  |                 else if (m_nCoordDim == COORD_DIM_LAYER_DIM)  | 
6890  | 0  |                 { | 
6891  | 0  |                     const OGRwkbGeometryType eDstLayerGeomType =  | 
6892  | 0  |                         poDstLayer->GetLayerDefn()  | 
6893  | 0  |                             ->GetGeomFieldDefn(iGeom)  | 
6894  | 0  |                             ->GetType();  | 
6895  | 0  |                     poDstGeometry->set3D(wkbHasZ(eDstLayerGeomType));  | 
6896  | 0  |                     poDstGeometry->setMeasured(wkbHasM(eDstLayerGeomType));  | 
6897  | 0  |                 }  | 
6898  |  | 
  | 
6899  | 0  |                 if (m_eGeomOp == GEOMOP_SEGMENTIZE)  | 
6900  | 0  |                 { | 
6901  | 0  |                     if (m_dfGeomOpParam > 0)  | 
6902  | 0  |                         poDstGeometry->segmentize(m_dfGeomOpParam);  | 
6903  | 0  |                 }  | 
6904  | 0  |                 else if (m_eGeomOp == GEOMOP_SIMPLIFY_PRESERVE_TOPOLOGY)  | 
6905  | 0  |                 { | 
6906  | 0  |                     if (m_dfGeomOpParam > 0)  | 
6907  | 0  |                     { | 
6908  | 0  |                         auto poNewGeom = std::unique_ptr<OGRGeometry>(  | 
6909  | 0  |                             poDstGeometry->SimplifyPreserveTopology(  | 
6910  | 0  |                                 m_dfGeomOpParam));  | 
6911  | 0  |                         if (poNewGeom)  | 
6912  | 0  |                         { | 
6913  | 0  |                             poDstGeometry = std::move(poNewGeom);  | 
6914  | 0  |                         }  | 
6915  | 0  |                     }  | 
6916  | 0  |                 }  | 
6917  |  | 
  | 
6918  | 0  |                 if (m_poClipSrcOri)  | 
6919  | 0  |                 { | 
6920  | 0  |                     if (poDstGeometry->IsEmpty())  | 
6921  | 0  |                         goto end_loop;  | 
6922  |  |  | 
6923  | 0  |                     const auto clipGeomDesc =  | 
6924  | 0  |                         GetSrcClipGeom(poDstGeometry->getSpatialReference());  | 
6925  |  | 
  | 
6926  | 0  |                     if (!(clipGeomDesc.poGeom && clipGeomDesc.poEnv))  | 
6927  | 0  |                         goto end_loop;  | 
6928  |  |  | 
6929  | 0  |                     OGREnvelope oDstEnv;  | 
6930  | 0  |                     poDstGeometry->getEnvelope(&oDstEnv);  | 
6931  |  | 
  | 
6932  | 0  |                     if (!(clipGeomDesc.bGeomIsRectangle &&  | 
6933  | 0  |                           clipGeomDesc.poEnv->Contains(oDstEnv)))  | 
6934  | 0  |                     { | 
6935  | 0  |                         std::unique_ptr<OGRGeometry> poClipped;  | 
6936  | 0  |                         if (clipGeomDesc.poEnv->Intersects(oDstEnv))  | 
6937  | 0  |                         { | 
6938  | 0  |                             poClipped.reset(clipGeomDesc.poGeom->Intersection(  | 
6939  | 0  |                                 poDstGeometry.get()));  | 
6940  | 0  |                         }  | 
6941  | 0  |                         if (poClipped == nullptr || poClipped->IsEmpty())  | 
6942  | 0  |                         { | 
6943  | 0  |                             goto end_loop;  | 
6944  | 0  |                         }  | 
6945  |  |  | 
6946  | 0  |                         const int nDim = poDstGeometry->getDimension();  | 
6947  | 0  |                         if (poClipped->getDimension() < nDim &&  | 
6948  | 0  |                             wkbFlatten(poDstFDefn->GetGeomFieldDefn(iGeom)  | 
6949  | 0  |                                            ->GetType()) != wkbUnknown)  | 
6950  | 0  |                         { | 
6951  | 0  |                             CPLDebug(  | 
6952  | 0  |                                 "OGR2OGR",  | 
6953  | 0  |                                 "Discarding feature " CPL_FRMT_GIB  | 
6954  | 0  |                                 " of layer %s, "  | 
6955  | 0  |                                 "as its intersection with -clipsrc is a %s "  | 
6956  | 0  |                                 "whereas the input is a %s",  | 
6957  | 0  |                                 nSrcFID, poSrcLayer->GetName(),  | 
6958  | 0  |                                 OGRToOGCGeomType(poClipped->getGeometryType()),  | 
6959  | 0  |                                 OGRToOGCGeomType(  | 
6960  | 0  |                                     poDstGeometry->getGeometryType()));  | 
6961  | 0  |                             goto end_loop;  | 
6962  | 0  |                         }  | 
6963  |  |  | 
6964  | 0  |                         poDstGeometry = std::move(poClipped);  | 
6965  | 0  |                     }  | 
6966  | 0  |                 }  | 
6967  |  |  | 
6968  | 0  |                 OGRCoordinateTransformation *const poCT =  | 
6969  | 0  |                     psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();  | 
6970  | 0  |                 char **const papszTransformOptions =  | 
6971  | 0  |                     psInfo->m_aoReprojectionInfo[iGeom]  | 
6972  | 0  |                         .m_aosTransformOptions.List();  | 
6973  | 0  |                 const bool bReprojCanInvalidateValidity =  | 
6974  | 0  |                     psInfo->m_aoReprojectionInfo[iGeom]  | 
6975  | 0  |                         .m_bCanInvalidateValidity;  | 
6976  |  | 
  | 
6977  | 0  |                 if (poCT != nullptr || papszTransformOptions != nullptr)  | 
6978  | 0  |                 { | 
6979  |  |                     // If we need to change the geometry type to linear, and  | 
6980  |  |                     // we have a geometry with curves, then convert it to  | 
6981  |  |                     // linear first, to avoid invalidities due to the fact  | 
6982  |  |                     // that validity of arc portions isn't always kept while  | 
6983  |  |                     // reprojecting and then discretizing.  | 
6984  | 0  |                     if (bReprojCanInvalidateValidity &&  | 
6985  | 0  |                         (!psInfo->m_bSupportCurves ||  | 
6986  | 0  |                          m_eGeomTypeConversion == GTC_CONVERT_TO_LINEAR ||  | 
6987  | 0  |                          m_eGeomTypeConversion ==  | 
6988  | 0  |                              GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR))  | 
6989  | 0  |                     { | 
6990  | 0  |                         if (poDstGeometry->hasCurveGeometry(TRUE))  | 
6991  | 0  |                         { | 
6992  | 0  |                             OGRwkbGeometryType eTargetType = OGR_GT_GetLinear(  | 
6993  | 0  |                                 poDstGeometry->getGeometryType());  | 
6994  | 0  |                             poDstGeometry.reset(OGRGeometryFactory::forceTo(  | 
6995  | 0  |                                 poDstGeometry.release(), eTargetType));  | 
6996  | 0  |                         }  | 
6997  | 0  |                     }  | 
6998  | 0  |                     else if (bReprojCanInvalidateValidity &&  | 
6999  | 0  |                              eGType != GEOMTYPE_UNCHANGED &&  | 
7000  | 0  |                              !OGR_GT_IsNonLinear(  | 
7001  | 0  |                                  static_cast<OGRwkbGeometryType>(eGType)) &&  | 
7002  | 0  |                              poDstGeometry->hasCurveGeometry(TRUE))  | 
7003  | 0  |                     { | 
7004  | 0  |                         poDstGeometry.reset(OGRGeometryFactory::forceTo(  | 
7005  | 0  |                             poDstGeometry.release(),  | 
7006  | 0  |                             static_cast<OGRwkbGeometryType>(eGType)));  | 
7007  | 0  |                     }  | 
7008  |  |  | 
7009  |  |                     // Collect left-most, right-most, top-most, bottom-most coordinates.  | 
7010  | 0  |                     if (psInfo->m_aoReprojectionInfo[iGeom]  | 
7011  | 0  |                             .m_bWarnAboutDifferentCoordinateOperations)  | 
7012  | 0  |                     { | 
7013  | 0  |                         struct Visitor : public OGRDefaultConstGeometryVisitor  | 
7014  | 0  |                         { | 
7015  | 0  |                             TargetLayerInfo::ReprojectionInfo &m_info;  | 
7016  |  | 
  | 
7017  | 0  |                             explicit Visitor(  | 
7018  | 0  |                                 TargetLayerInfo::ReprojectionInfo &info)  | 
7019  | 0  |                                 : m_info(info)  | 
7020  | 0  |                             { | 
7021  | 0  |                             }  | 
7022  |  | 
  | 
7023  | 0  |                             using OGRDefaultConstGeometryVisitor::visit;  | 
7024  |  | 
  | 
7025  | 0  |                             void visit(const OGRPoint *point) override  | 
7026  | 0  |                             { | 
7027  | 0  |                                 m_info.UpdateExtremePoints(point->getX(),  | 
7028  | 0  |                                                            point->getY(),  | 
7029  | 0  |                                                            point->getZ());  | 
7030  | 0  |                             }  | 
7031  | 0  |                         };  | 
7032  |  | 
  | 
7033  | 0  |                         Visitor oVisit(psInfo->m_aoReprojectionInfo[iGeom]);  | 
7034  | 0  |                         poDstGeometry->accept(&oVisit);  | 
7035  | 0  |                     }  | 
7036  |  | 
  | 
7037  | 0  |                     for (int iIter = 0; iIter < 2; ++iIter)  | 
7038  | 0  |                     { | 
7039  | 0  |                         auto poReprojectedGeom = std::unique_ptr<OGRGeometry>(  | 
7040  | 0  |                             OGRGeometryFactory::transformWithOptions(  | 
7041  | 0  |                                 poDstGeometry.get(), poCT,  | 
7042  | 0  |                                 papszTransformOptions,  | 
7043  | 0  |                                 m_transformWithOptionsCache));  | 
7044  | 0  |                         if (poReprojectedGeom == nullptr)  | 
7045  | 0  |                         { | 
7046  | 0  |                             if (psOptions->nGroupTransactions)  | 
7047  | 0  |                             { | 
7048  | 0  |                                 if (psOptions->nLayerTransaction)  | 
7049  | 0  |                                 { | 
7050  | 0  |                                     if (poDstLayer->CommitTransaction() !=  | 
7051  | 0  |                                             OGRERR_NONE &&  | 
7052  | 0  |                                         !psOptions->bSkipFailures)  | 
7053  | 0  |                                     { | 
7054  | 0  |                                         return false;  | 
7055  | 0  |                                     }  | 
7056  | 0  |                                 }  | 
7057  | 0  |                             }  | 
7058  |  |  | 
7059  | 0  |                             CPLError(CE_Failure, CPLE_AppDefined,  | 
7060  | 0  |                                      "Failed to reproject feature " CPL_FRMT_GIB  | 
7061  | 0  |                                      " (geometry probably out of source or "  | 
7062  | 0  |                                      "destination SRS).",  | 
7063  | 0  |                                      nSrcFID);  | 
7064  | 0  |                             if (!psOptions->bSkipFailures)  | 
7065  | 0  |                             { | 
7066  | 0  |                                 return false;  | 
7067  | 0  |                             }  | 
7068  | 0  |                         }  | 
7069  |  |  | 
7070  |  |                         // Check if a curve geometry is no longer valid after  | 
7071  |  |                         // reprojection  | 
7072  | 0  |                         const auto eType = poDstGeometry->getGeometryType();  | 
7073  | 0  |                         const auto eFlatType = wkbFlatten(eType);  | 
7074  |  | 
  | 
7075  | 0  |                         const auto IsValid = [](const OGRGeometry *poGeom)  | 
7076  | 0  |                         { | 
7077  | 0  |                             CPLErrorHandlerPusher oErrorHandler(  | 
7078  | 0  |                                 CPLQuietErrorHandler);  | 
7079  | 0  |                             return poGeom->IsValid();  | 
7080  | 0  |                         };  | 
7081  |  | 
  | 
7082  | 0  |                         if (iIter == 0 && bReprojCanInvalidateValidity &&  | 
7083  | 0  |                             OGRGeometryFactory::haveGEOS() &&  | 
7084  | 0  |                             (eFlatType == wkbCurvePolygon ||  | 
7085  | 0  |                              eFlatType == wkbCompoundCurve ||  | 
7086  | 0  |                              eFlatType == wkbMultiCurve ||  | 
7087  | 0  |                              eFlatType == wkbMultiSurface) &&  | 
7088  | 0  |                             poDstGeometry->hasCurveGeometry(TRUE) &&  | 
7089  | 0  |                             IsValid(poDstGeometry.get()))  | 
7090  | 0  |                         { | 
7091  | 0  |                             OGRwkbGeometryType eTargetType = OGR_GT_GetLinear(  | 
7092  | 0  |                                 poDstGeometry->getGeometryType());  | 
7093  | 0  |                             auto poDstGeometryTmp =  | 
7094  | 0  |                                 std::unique_ptr<OGRGeometry>(  | 
7095  | 0  |                                     OGRGeometryFactory::forceTo(  | 
7096  | 0  |                                         poReprojectedGeom->clone(),  | 
7097  | 0  |                                         eTargetType));  | 
7098  | 0  |                             if (!IsValid(poDstGeometryTmp.get()))  | 
7099  | 0  |                             { | 
7100  | 0  |                                 CPLDebug("OGR2OGR", | 
7101  | 0  |                                          "Curve geometry no longer valid after "  | 
7102  | 0  |                                          "reprojection: transforming it into "  | 
7103  | 0  |                                          "linear one before reprojecting");  | 
7104  | 0  |                                 poDstGeometry.reset(OGRGeometryFactory::forceTo(  | 
7105  | 0  |                                     poDstGeometry.release(), eTargetType));  | 
7106  | 0  |                                 poDstGeometry.reset(OGRGeometryFactory::forceTo(  | 
7107  | 0  |                                     poDstGeometry.release(), eType));  | 
7108  | 0  |                             }  | 
7109  | 0  |                             else  | 
7110  | 0  |                             { | 
7111  | 0  |                                 poDstGeometry = std::move(poReprojectedGeom);  | 
7112  | 0  |                                 break;  | 
7113  | 0  |                             }  | 
7114  | 0  |                         }  | 
7115  | 0  |                         else  | 
7116  | 0  |                         { | 
7117  | 0  |                             poDstGeometry = std::move(poReprojectedGeom);  | 
7118  | 0  |                             break;  | 
7119  | 0  |                         }  | 
7120  | 0  |                     }  | 
7121  | 0  |                 }  | 
7122  | 0  |                 else if (poOutputSRS != nullptr)  | 
7123  | 0  |                 { | 
7124  | 0  |                     poDstGeometry->assignSpatialReference(poOutputSRS);  | 
7125  | 0  |                 }  | 
7126  |  |  | 
7127  | 0  |                 if (poDstGeometry != nullptr)  | 
7128  | 0  |                 { | 
7129  | 0  |                     if (m_poClipDstOri)  | 
7130  | 0  |                     { | 
7131  | 0  |                         if (poDstGeometry->IsEmpty())  | 
7132  | 0  |                             goto end_loop;  | 
7133  |  |  | 
7134  | 0  |                         const auto clipGeomDesc = GetDstClipGeom(  | 
7135  | 0  |                             poDstGeometry->getSpatialReference());  | 
7136  | 0  |                         if (!clipGeomDesc.poGeom || !clipGeomDesc.poEnv)  | 
7137  | 0  |                         { | 
7138  | 0  |                             goto end_loop;  | 
7139  | 0  |                         }  | 
7140  |  |  | 
7141  | 0  |                         OGREnvelope oDstEnv;  | 
7142  | 0  |                         poDstGeometry->getEnvelope(&oDstEnv);  | 
7143  |  | 
  | 
7144  | 0  |                         if (!(clipGeomDesc.bGeomIsRectangle &&  | 
7145  | 0  |                               clipGeomDesc.poEnv->Contains(oDstEnv)))  | 
7146  | 0  |                         { | 
7147  | 0  |                             std::unique_ptr<OGRGeometry> poClipped;  | 
7148  | 0  |                             if (clipGeomDesc.poEnv->Intersects(oDstEnv))  | 
7149  | 0  |                             { | 
7150  | 0  |                                 poClipped.reset(  | 
7151  | 0  |                                     clipGeomDesc.poGeom->Intersection(  | 
7152  | 0  |                                         poDstGeometry.get()));  | 
7153  | 0  |                             }  | 
7154  |  | 
  | 
7155  | 0  |                             if (poClipped == nullptr || poClipped->IsEmpty())  | 
7156  | 0  |                             { | 
7157  | 0  |                                 goto end_loop;  | 
7158  | 0  |                             }  | 
7159  |  |  | 
7160  | 0  |                             const int nDim = poDstGeometry->getDimension();  | 
7161  | 0  |                             if (poClipped->getDimension() < nDim &&  | 
7162  | 0  |                                 wkbFlatten(poDstFDefn->GetGeomFieldDefn(iGeom)  | 
7163  | 0  |                                                ->GetType()) != wkbUnknown)  | 
7164  | 0  |                             { | 
7165  | 0  |                                 CPLDebug(  | 
7166  | 0  |                                     "OGR2OGR",  | 
7167  | 0  |                                     "Discarding feature " CPL_FRMT_GIB  | 
7168  | 0  |                                     " of layer %s, "  | 
7169  | 0  |                                     "as its intersection with -clipdst is a %s "  | 
7170  | 0  |                                     "whereas the input is a %s",  | 
7171  | 0  |                                     nSrcFID, poSrcLayer->GetName(),  | 
7172  | 0  |                                     OGRToOGCGeomType(  | 
7173  | 0  |                                         poClipped->getGeometryType()),  | 
7174  | 0  |                                     OGRToOGCGeomType(  | 
7175  | 0  |                                         poDstGeometry->getGeometryType()));  | 
7176  | 0  |                                 goto end_loop;  | 
7177  | 0  |                             }  | 
7178  |  |  | 
7179  | 0  |                             poDstGeometry = std::move(poClipped);  | 
7180  | 0  |                         }  | 
7181  | 0  |                     }  | 
7182  |  |  | 
7183  | 0  |                     if (psOptions->dfXYRes !=  | 
7184  | 0  |                             OGRGeomCoordinatePrecision::UNKNOWN &&  | 
7185  | 0  |                         OGRGeometryFactory::haveGEOS() &&  | 
7186  | 0  |                         !poDstGeometry->hasCurveGeometry())  | 
7187  | 0  |                     { | 
7188  |  |                         // OGR_APPLY_GEOM_SET_PRECISION default value for  | 
7189  |  |                         // OGRLayer::CreateFeature() purposes, but here in the  | 
7190  |  |                         // ogr2ogr -xyRes context, we force calling SetPrecision(),  | 
7191  |  |                         // unless the user explicitly asks not to do it by  | 
7192  |  |                         // setting the config option to NO.  | 
7193  | 0  |                         if (!bRunSetPrecisionEvaluated)  | 
7194  | 0  |                         { | 
7195  | 0  |                             bRunSetPrecisionEvaluated = true;  | 
7196  | 0  |                             bRunSetPrecision = CPLTestBool(CPLGetConfigOption(  | 
7197  | 0  |                                 "OGR_APPLY_GEOM_SET_PRECISION", "YES"));  | 
7198  | 0  |                         }  | 
7199  | 0  |                         if (bRunSetPrecision)  | 
7200  | 0  |                         { | 
7201  | 0  |                             auto poNewGeom = std::unique_ptr<OGRGeometry>(  | 
7202  | 0  |                                 poDstGeometry->SetPrecision(psOptions->dfXYRes,  | 
7203  | 0  |                                                             /* nFlags = */ 0));  | 
7204  | 0  |                             if (!poNewGeom)  | 
7205  | 0  |                                 goto end_loop;  | 
7206  | 0  |                             poDstGeometry = std::move(poNewGeom);  | 
7207  | 0  |                         }  | 
7208  | 0  |                     }  | 
7209  |  |  | 
7210  | 0  |                     if (m_bMakeValid)  | 
7211  | 0  |                     { | 
7212  | 0  |                         const bool bIsGeomCollection =  | 
7213  | 0  |                             wkbFlatten(poDstGeometry->getGeometryType()) ==  | 
7214  | 0  |                             wkbGeometryCollection;  | 
7215  | 0  |                         auto poNewGeom = std::unique_ptr<OGRGeometry>(  | 
7216  | 0  |                             poDstGeometry->MakeValid());  | 
7217  | 0  |                         if (!poNewGeom)  | 
7218  | 0  |                             goto end_loop;  | 
7219  | 0  |                         poDstGeometry = std::move(poNewGeom);  | 
7220  | 0  |                         if (!bIsGeomCollection)  | 
7221  | 0  |                         { | 
7222  | 0  |                             poDstGeometry.reset(  | 
7223  | 0  |                                 OGRGeometryFactory::  | 
7224  | 0  |                                     removeLowerDimensionSubGeoms(  | 
7225  | 0  |                                         poDstGeometry.get()));  | 
7226  | 0  |                         }  | 
7227  | 0  |                     }  | 
7228  |  |  | 
7229  | 0  |                     if (m_bSkipInvalidGeom && !poDstGeometry->IsValid())  | 
7230  | 0  |                         goto end_loop;  | 
7231  |  |  | 
7232  | 0  |                     if (m_eGeomTypeConversion != GTC_DEFAULT)  | 
7233  | 0  |                     { | 
7234  | 0  |                         OGRwkbGeometryType eTargetType =  | 
7235  | 0  |                             poDstGeometry->getGeometryType();  | 
7236  | 0  |                         eTargetType =  | 
7237  | 0  |                             ConvertType(m_eGeomTypeConversion, eTargetType);  | 
7238  | 0  |                         poDstGeometry.reset(OGRGeometryFactory::forceTo(  | 
7239  | 0  |                             poDstGeometry.release(), eTargetType));  | 
7240  | 0  |                     }  | 
7241  | 0  |                     else if (eGType != GEOMTYPE_UNCHANGED)  | 
7242  | 0  |                     { | 
7243  | 0  |                         poDstGeometry.reset(OGRGeometryFactory::forceTo(  | 
7244  | 0  |                             poDstGeometry.release(),  | 
7245  | 0  |                             static_cast<OGRwkbGeometryType>(eGType)));  | 
7246  | 0  |                     }  | 
7247  | 0  |                 }  | 
7248  |  |  | 
7249  | 0  |                 poDstFeature->SetGeomFieldDirectly(iGeom,  | 
7250  | 0  |                                                    poDstGeometry.release());  | 
7251  | 0  |             }  | 
7252  |  |  | 
7253  | 0  |             CPLErrorReset();  | 
7254  | 0  |             if ((psOptions->bUpsert  | 
7255  | 0  |                      ? poDstLayer->UpsertFeature(poDstFeature.get())  | 
7256  | 0  |                      : poDstLayer->CreateFeature(poDstFeature.get())) ==  | 
7257  | 0  |                 OGRERR_NONE)  | 
7258  | 0  |             { | 
7259  | 0  |                 nFeaturesWritten++;  | 
7260  | 0  |                 if (nDesiredFID != OGRNullFID &&  | 
7261  | 0  |                     poDstFeature->GetFID() != nDesiredFID)  | 
7262  | 0  |                 { | 
7263  | 0  |                     CPLError(CE_Warning, CPLE_AppDefined,  | 
7264  | 0  |                              "Feature id " CPL_FRMT_GIB " not preserved",  | 
7265  | 0  |                              nDesiredFID);  | 
7266  | 0  |                 }  | 
7267  | 0  |             }  | 
7268  | 0  |             else if (!psOptions->bSkipFailures)  | 
7269  | 0  |             { | 
7270  | 0  |                 if (psOptions->nGroupTransactions)  | 
7271  | 0  |                 { | 
7272  | 0  |                     if (psOptions->nLayerTransaction)  | 
7273  | 0  |                         poDstLayer->RollbackTransaction();  | 
7274  | 0  |                 }  | 
7275  |  | 
  | 
7276  | 0  |                 CPLError(CE_Failure, CPLE_AppDefined,  | 
7277  | 0  |                          "Unable to write feature " CPL_FRMT_GIB  | 
7278  | 0  |                          " from layer %s.",  | 
7279  | 0  |                          nSrcFID, poSrcLayer->GetName());  | 
7280  |  | 
  | 
7281  | 0  |                 return false;  | 
7282  | 0  |             }  | 
7283  | 0  |             else  | 
7284  | 0  |             { | 
7285  | 0  |                 CPLDebug("GDALVectorTranslate", | 
7286  | 0  |                          "Unable to write feature " CPL_FRMT_GIB  | 
7287  | 0  |                          " into layer %s.",  | 
7288  | 0  |                          nSrcFID, poSrcLayer->GetName());  | 
7289  | 0  |                 if (psOptions->nGroupTransactions)  | 
7290  | 0  |                 { | 
7291  | 0  |                     if (psOptions->nLayerTransaction)  | 
7292  | 0  |                     { | 
7293  | 0  |                         poDstLayer->RollbackTransaction();  | 
7294  | 0  |                         CPL_IGNORE_RET_VAL(poDstLayer->StartTransaction());  | 
7295  | 0  |                     }  | 
7296  | 0  |                     else  | 
7297  | 0  |                     { | 
7298  | 0  |                         m_poODS->RollbackTransaction();  | 
7299  | 0  |                         m_poODS->StartTransaction(psOptions->bForceTransaction);  | 
7300  | 0  |                     }  | 
7301  | 0  |                 }  | 
7302  | 0  |             }  | 
7303  |  |  | 
7304  | 0  |         end_loop:;  // nothing  | 
7305  | 0  |         }  | 
7306  |  |  | 
7307  |  |         /* Report progress */  | 
7308  | 0  |         nCount++;  | 
7309  | 0  |         bool bGoOn = true;  | 
7310  | 0  |         if (pfnProgress)  | 
7311  | 0  |         { | 
7312  | 0  |             bGoOn = pfnProgress(nCountLayerFeatures  | 
7313  | 0  |                                     ? nCount * 1.0 / nCountLayerFeatures  | 
7314  | 0  |                                     : 1.0,  | 
7315  | 0  |                                 "", pProgressArg) != FALSE;  | 
7316  | 0  |         }  | 
7317  | 0  |         if (!bGoOn)  | 
7318  | 0  |         { | 
7319  | 0  |             bRet = false;  | 
7320  | 0  |             break;  | 
7321  | 0  |         }  | 
7322  |  |  | 
7323  | 0  |         if (pnReadFeatureCount)  | 
7324  | 0  |             *pnReadFeatureCount = nCount;  | 
7325  |  | 
  | 
7326  | 0  |         if (psOptions->nFIDToFetch != OGRNullFID)  | 
7327  | 0  |             break;  | 
7328  | 0  |         if (poFeatureIn != nullptr)  | 
7329  | 0  |             break;  | 
7330  | 0  |     }  | 
7331  |  |  | 
7332  | 0  |     if (psOptions->nGroupTransactions)  | 
7333  | 0  |     { | 
7334  | 0  |         if (psOptions->nLayerTransaction)  | 
7335  | 0  |         { | 
7336  | 0  |             if (poDstLayer->CommitTransaction() != OGRERR_NONE)  | 
7337  | 0  |                 bRet = false;  | 
7338  | 0  |         }  | 
7339  | 0  |     }  | 
7340  |  | 
  | 
7341  | 0  |     if (poFeatureIn == nullptr)  | 
7342  | 0  |     { | 
7343  | 0  |         CPLDebug("GDALVectorTranslate", | 
7344  | 0  |                  CPL_FRMT_GIB " features written in layer '%s'",  | 
7345  | 0  |                  nFeaturesWritten, poDstLayer->GetName());  | 
7346  | 0  |     }  | 
7347  |  | 
  | 
7348  | 0  |     return bRet;  | 
7349  | 0  | }  | 
7350  |  |  | 
7351  |  | /************************************************************************/  | 
7352  |  | /*                LayerTranslator::GetDstClipGeom()                     */  | 
7353  |  | /************************************************************************/  | 
7354  |  |  | 
7355  |  | /** Returns the destination clip geometry and its envelope  | 
7356  |  |  *  | 
7357  |  |  * @param poGeomSRS The SRS into which the destination clip geometry should be  | 
7358  |  |  *                  expressed.  | 
7359  |  |  * @return the destination clip geometry and its envelope, or (nullptr, nullptr)  | 
7360  |  |  */  | 
7361  |  | LayerTranslator::ClipGeomDesc  | 
7362  |  | LayerTranslator::GetDstClipGeom(const OGRSpatialReference *poGeomSRS)  | 
7363  | 0  | { | 
7364  | 0  |     if (m_poClipDstReprojectedToDstSRS_SRS != poGeomSRS)  | 
7365  | 0  |     { | 
7366  | 0  |         auto poClipDstSRS = m_poClipDstOri->getSpatialReference();  | 
7367  | 0  |         if (poClipDstSRS && poGeomSRS && !poClipDstSRS->IsSame(poGeomSRS))  | 
7368  | 0  |         { | 
7369  |  |             // Transform clip geom to geometry SRS  | 
7370  | 0  |             m_poClipDstReprojectedToDstSRS.reset(m_poClipDstOri->clone());  | 
7371  | 0  |             if (m_poClipDstReprojectedToDstSRS->transformTo(poGeomSRS) !=  | 
7372  | 0  |                 OGRERR_NONE)  | 
7373  | 0  |             { | 
7374  | 0  |                 return ClipGeomDesc();  | 
7375  | 0  |             }  | 
7376  | 0  |             m_poClipDstReprojectedToDstSRS_SRS = poGeomSRS;  | 
7377  | 0  |         }  | 
7378  | 0  |         else if (!poClipDstSRS && poGeomSRS)  | 
7379  | 0  |         { | 
7380  | 0  |             if (!m_bWarnedClipDstSRS)  | 
7381  | 0  |             { | 
7382  | 0  |                 m_bWarnedClipDstSRS = true;  | 
7383  | 0  |                 CPLError(CE_Warning, CPLE_AppDefined,  | 
7384  | 0  |                          "Clip destination geometry has no "  | 
7385  | 0  |                          "attached SRS, but the feature's "  | 
7386  | 0  |                          "geometry has one. Assuming clip "  | 
7387  | 0  |                          "destination geometry SRS is the "  | 
7388  | 0  |                          "same as the feature's geometry");  | 
7389  | 0  |             }  | 
7390  | 0  |         }  | 
7391  | 0  |         m_oClipDstEnv = OGREnvelope();  | 
7392  | 0  |     }  | 
7393  |  |  | 
7394  | 0  |     const auto poGeom = m_poClipDstReprojectedToDstSRS  | 
7395  | 0  |                             ? m_poClipDstReprojectedToDstSRS.get()  | 
7396  | 0  |                             : m_poClipDstOri;  | 
7397  | 0  |     if (poGeom && !m_oClipDstEnv.IsInit())  | 
7398  | 0  |     { | 
7399  | 0  |         poGeom->getEnvelope(&m_oClipDstEnv);  | 
7400  | 0  |         m_bClipDstIsRectangle = poGeom->IsRectangle();  | 
7401  | 0  |     }  | 
7402  | 0  |     ClipGeomDesc ret;  | 
7403  | 0  |     ret.poGeom = poGeom;  | 
7404  | 0  |     ret.poEnv = poGeom ? &m_oClipDstEnv : nullptr;  | 
7405  | 0  |     ret.bGeomIsRectangle = m_bClipDstIsRectangle;  | 
7406  | 0  |     return ret;  | 
7407  | 0  | }  | 
7408  |  |  | 
7409  |  | /************************************************************************/  | 
7410  |  | /*                LayerTranslator::GetSrcClipGeom()                     */  | 
7411  |  | /************************************************************************/  | 
7412  |  |  | 
7413  |  | /** Returns the source clip geometry and its envelope  | 
7414  |  |  *  | 
7415  |  |  * @param poGeomSRS The SRS into which the source clip geometry should be  | 
7416  |  |  *                  expressed.  | 
7417  |  |  * @return the source clip geometry and its envelope, or (nullptr, nullptr)  | 
7418  |  |  */  | 
7419  |  | LayerTranslator::ClipGeomDesc  | 
7420  |  | LayerTranslator::GetSrcClipGeom(const OGRSpatialReference *poGeomSRS)  | 
7421  | 0  | { | 
7422  | 0  |     if (m_poClipSrcReprojectedToSrcSRS_SRS != poGeomSRS)  | 
7423  | 0  |     { | 
7424  | 0  |         auto poClipSrcSRS = m_poClipSrcOri->getSpatialReference();  | 
7425  | 0  |         if (poClipSrcSRS && poGeomSRS && !poClipSrcSRS->IsSame(poGeomSRS))  | 
7426  | 0  |         { | 
7427  |  |             // Transform clip geom to geometry SRS  | 
7428  | 0  |             m_poClipSrcReprojectedToSrcSRS.reset(m_poClipSrcOri->clone());  | 
7429  | 0  |             if (m_poClipSrcReprojectedToSrcSRS->transformTo(poGeomSRS) !=  | 
7430  | 0  |                 OGRERR_NONE)  | 
7431  | 0  |             { | 
7432  | 0  |                 return ClipGeomDesc();  | 
7433  | 0  |             }  | 
7434  | 0  |             m_poClipSrcReprojectedToSrcSRS_SRS = poGeomSRS;  | 
7435  | 0  |         }  | 
7436  | 0  |         else if (!poClipSrcSRS && poGeomSRS)  | 
7437  | 0  |         { | 
7438  | 0  |             if (!m_bWarnedClipSrcSRS)  | 
7439  | 0  |             { | 
7440  | 0  |                 m_bWarnedClipSrcSRS = true;  | 
7441  | 0  |                 CPLError(CE_Warning, CPLE_AppDefined,  | 
7442  | 0  |                          "Clip source geometry has no attached SRS, "  | 
7443  | 0  |                          "but the feature's geometry has one. "  | 
7444  | 0  |                          "Assuming clip source geometry SRS is the "  | 
7445  | 0  |                          "same as the feature's geometry");  | 
7446  | 0  |             }  | 
7447  | 0  |         }  | 
7448  | 0  |         m_oClipSrcEnv = OGREnvelope();  | 
7449  | 0  |     }  | 
7450  |  |  | 
7451  | 0  |     const auto poGeom = m_poClipSrcReprojectedToSrcSRS  | 
7452  | 0  |                             ? m_poClipSrcReprojectedToSrcSRS.get()  | 
7453  | 0  |                             : m_poClipSrcOri;  | 
7454  | 0  |     if (poGeom && !m_oClipSrcEnv.IsInit())  | 
7455  | 0  |     { | 
7456  | 0  |         poGeom->getEnvelope(&m_oClipSrcEnv);  | 
7457  | 0  |         m_bClipSrcIsRectangle = poGeom->IsRectangle();  | 
7458  | 0  |     }  | 
7459  | 0  |     ClipGeomDesc ret;  | 
7460  | 0  |     ret.poGeom = poGeom;  | 
7461  | 0  |     ret.poEnv = poGeom ? &m_oClipSrcEnv : nullptr;  | 
7462  | 0  |     ret.bGeomIsRectangle = m_bClipDstIsRectangle;  | 
7463  | 0  |     return ret;  | 
7464  | 0  | }  | 
7465  |  |  | 
7466  |  | /************************************************************************/  | 
7467  |  | /*               TargetLayerInfo::CheckSameCoordinateOperation()        */  | 
7468  |  | /************************************************************************/  | 
7469  |  |  | 
7470  |  | void TargetLayerInfo::CheckSameCoordinateOperation() const  | 
7471  | 0  | { | 
7472  | 0  |     for (auto &info : m_aoReprojectionInfo)  | 
7473  | 0  |     { | 
7474  | 0  |         if (info.m_bWarnAboutDifferentCoordinateOperations &&  | 
7475  | 0  |             info.m_dfLeftX <= info.m_dfRightX)  | 
7476  | 0  |         { | 
7477  |  |             // Start recording if different coordinate operations are  | 
7478  |  |             // going to be used  | 
7479  | 0  |             OGRProjCTDifferentOperationsStart(info.m_poCT.get());  | 
7480  |  | 
  | 
7481  | 0  |             { | 
7482  | 0  |                 CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);  | 
7483  | 0  |                 { | 
7484  | 0  |                     double dfX = info.m_dfLeftX;  | 
7485  | 0  |                     double dfY = info.m_dfLeftY;  | 
7486  | 0  |                     double dfZ = info.m_dfLeftZ;  | 
7487  | 0  |                     info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);  | 
7488  | 0  |                 }  | 
7489  |  | 
  | 
7490  | 0  |                 { | 
7491  | 0  |                     double dfX = info.m_dfRightX;  | 
7492  | 0  |                     double dfY = info.m_dfRightY;  | 
7493  | 0  |                     double dfZ = info.m_dfRightZ;  | 
7494  | 0  |                     info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);  | 
7495  | 0  |                 }  | 
7496  |  | 
  | 
7497  | 0  |                 { | 
7498  | 0  |                     double dfX = info.m_dfTopX;  | 
7499  | 0  |                     double dfY = info.m_dfTopY;  | 
7500  | 0  |                     double dfZ = info.m_dfTopZ;  | 
7501  | 0  |                     info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);  | 
7502  | 0  |                 }  | 
7503  |  | 
  | 
7504  | 0  |                 { | 
7505  | 0  |                     double dfX = info.m_dfBottomX;  | 
7506  | 0  |                     double dfY = info.m_dfBottomY;  | 
7507  | 0  |                     double dfZ = info.m_dfBottomZ;  | 
7508  | 0  |                     info.m_poCT->Transform(1, &dfX, &dfY, &dfZ);  | 
7509  | 0  |                 }  | 
7510  | 0  |             }  | 
7511  |  | 
  | 
7512  | 0  |             if (OGRProjCTDifferentOperationsUsed(info.m_poCT.get()))  | 
7513  | 0  |             { | 
7514  | 0  |                 CPLError(  | 
7515  | 0  |                     CE_Warning, CPLE_AppDefined,  | 
7516  | 0  |                     "Several coordinate operations have been used to transform "  | 
7517  | 0  |                     "layer %s. Artifacts may appear. You may consider "  | 
7518  | 0  |                     "using the -ct_opt ALLOW_BALLPARK=NO and/or "  | 
7519  | 0  |                     "-ct_opt ONLY_BEST=YES warping options, or specify "  | 
7520  | 0  |                     "a particular coordinate operation with -ct. "  | 
7521  | 0  |                     "This warning can be silenced with "  | 
7522  | 0  |                     "-ct_opt WARN_ABOUT_DIFFERENT_COORD_OP=NO.",  | 
7523  | 0  |                     m_poSrcLayer->GetName());  | 
7524  | 0  |             }  | 
7525  |  |  | 
7526  |  |             // Stop recording  | 
7527  | 0  |             OGRProjCTDifferentOperationsStop(info.m_poCT.get());  | 
7528  | 0  |         }  | 
7529  | 0  |     }  | 
7530  | 0  | }  | 
7531  |  |  | 
7532  |  | /************************************************************************/  | 
7533  |  | /*                   GDALVectorTranslateOptionsGetParser()              */  | 
7534  |  | /************************************************************************/  | 
7535  |  |  | 
7536  |  | static std::unique_ptr<GDALArgumentParser> GDALVectorTranslateOptionsGetParser(  | 
7537  |  |     GDALVectorTranslateOptions *psOptions,  | 
7538  |  |     GDALVectorTranslateOptionsForBinary *psOptionsForBinary, int nCountClipSrc,  | 
7539  |  |     int nCountClipDst)  | 
7540  | 0  | { | 
7541  | 0  |     auto argParser = std::make_unique<GDALArgumentParser>(  | 
7542  | 0  |         "ogr2ogr", /* bForBinary=*/psOptionsForBinary != nullptr);  | 
7543  |  | 
  | 
7544  | 0  |     argParser->add_description(  | 
7545  | 0  |         _("Converts simple features data between file formats.")); | 
7546  |  | 
  | 
7547  | 0  |     argParser->add_epilog(  | 
7548  | 0  |         _("For more details, consult https://gdal.org/programs/ogr2ogr.html")); | 
7549  |  | 
  | 
7550  | 0  |     argParser->add_output_format_argument(psOptions->osFormat);  | 
7551  |  | 
  | 
7552  | 0  |     argParser->add_dataset_creation_options_argument(psOptions->aosDSCO);  | 
7553  |  | 
  | 
7554  | 0  |     argParser->add_layer_creation_options_argument(psOptions->aosLCO);  | 
7555  |  | 
  | 
7556  | 0  |     argParser->add_usage_newline();  | 
7557  |  | 
  | 
7558  | 0  |     { | 
7559  | 0  |         auto &group = argParser->add_mutually_exclusive_group();  | 
7560  | 0  |         group.add_argument("-append") | 
7561  | 0  |             .flag()  | 
7562  | 0  |             .action([psOptions](const std::string &)  | 
7563  | 0  |                     { psOptions->eAccessMode = ACCESS_APPEND; }) | 
7564  | 0  |             .help(_("Append to existing layer instead of creating new.")); | 
7565  |  | 
  | 
7566  | 0  |         group.add_argument("-upsert") | 
7567  | 0  |             .flag()  | 
7568  | 0  |             .action(  | 
7569  | 0  |                 [psOptions](const std::string &)  | 
7570  | 0  |                 { | 
7571  | 0  |                     psOptions->eAccessMode = ACCESS_APPEND;  | 
7572  | 0  |                     psOptions->bUpsert = true;  | 
7573  | 0  |                 })  | 
7574  | 0  |             .help(_("Variant of -append where the UpsertFeature() operation is " | 
7575  | 0  |                     "used to insert or update features."));  | 
7576  |  | 
  | 
7577  | 0  |         group.add_argument("-overwrite") | 
7578  | 0  |             .flag()  | 
7579  | 0  |             .action([psOptions](const std::string &)  | 
7580  | 0  |                     { psOptions->eAccessMode = ACCESS_OVERWRITE; }) | 
7581  | 0  |             .help(_("Delete the output layer and recreate it empty.")); | 
7582  | 0  |     }  | 
7583  |  | 
  | 
7584  | 0  |     argParser->add_argument("-update") | 
7585  | 0  |         .flag()  | 
7586  | 0  |         .action(  | 
7587  | 0  |             [psOptions](const std::string &)  | 
7588  | 0  |             { | 
7589  |  |                 /* Don't reset -append or -overwrite */  | 
7590  | 0  |                 if (psOptions->eAccessMode != ACCESS_APPEND &&  | 
7591  | 0  |                     psOptions->eAccessMode != ACCESS_OVERWRITE)  | 
7592  | 0  |                     psOptions->eAccessMode = ACCESS_UPDATE;  | 
7593  | 0  |             })  | 
7594  | 0  |         .help(_("Open existing output datasource in update mode rather than " | 
7595  | 0  |                 "trying to create a new one."));  | 
7596  |  | 
  | 
7597  | 0  |     argParser->add_argument("-sql") | 
7598  | 0  |         .metavar("<statement>|@<filename>") | 
7599  | 0  |         .action(  | 
7600  | 0  |             [psOptions](const std::string &s)  | 
7601  | 0  |             { | 
7602  | 0  |                 GByte *pabyRet = nullptr;  | 
7603  | 0  |                 if (!s.empty() && s.front() == '@' &&  | 
7604  | 0  |                     VSIIngestFile(nullptr, s.c_str() + 1, &pabyRet, nullptr,  | 
7605  | 0  |                                   1024 * 1024))  | 
7606  | 0  |                 { | 
7607  | 0  |                     GDALRemoveBOM(pabyRet);  | 
7608  | 0  |                     char *pszSQLStatement = reinterpret_cast<char *>(pabyRet);  | 
7609  | 0  |                     psOptions->osSQLStatement =  | 
7610  | 0  |                         CPLRemoveSQLComments(pszSQLStatement);  | 
7611  | 0  |                     VSIFree(pszSQLStatement);  | 
7612  | 0  |                 }  | 
7613  | 0  |                 else  | 
7614  | 0  |                 { | 
7615  | 0  |                     psOptions->osSQLStatement = s;  | 
7616  | 0  |                 }  | 
7617  | 0  |             })  | 
7618  | 0  |         .help(_("SQL statement to execute.")); | 
7619  |  | 
  | 
7620  | 0  |     argParser->add_argument("-dialect") | 
7621  | 0  |         .metavar("<dialect>") | 
7622  | 0  |         .store_into(psOptions->osDialect)  | 
7623  | 0  |         .help(_("SQL dialect.")); | 
7624  |  | 
  | 
7625  | 0  |     argParser->add_argument("-spat") | 
7626  | 0  |         .metavar("<xmin> <ymin> <xmax> <ymax>") | 
7627  | 0  |         .nargs(4)  | 
7628  | 0  |         .scan<'g', double>()  | 
7629  | 0  |         .help(_("Spatial query extents, in the SRS of the source layer(s) (or " | 
7630  | 0  |                 "the one specified with -spat_srs."));  | 
7631  |  | 
  | 
7632  | 0  |     argParser->add_argument("-where") | 
7633  | 0  |         .metavar("<restricted_where>|@<filename>") | 
7634  | 0  |         .action(  | 
7635  | 0  |             [psOptions](const std::string &s)  | 
7636  | 0  |             { | 
7637  | 0  |                 GByte *pabyRet = nullptr;  | 
7638  | 0  |                 if (!s.empty() && s.front() == '@' &&  | 
7639  | 0  |                     VSIIngestFile(nullptr, s.c_str() + 1, &pabyRet, nullptr,  | 
7640  | 0  |                                   1024 * 1024))  | 
7641  | 0  |                 { | 
7642  | 0  |                     GDALRemoveBOM(pabyRet);  | 
7643  | 0  |                     char *pszWHERE = reinterpret_cast<char *>(pabyRet);  | 
7644  | 0  |                     psOptions->osWHERE = pszWHERE;  | 
7645  | 0  |                     VSIFree(pszWHERE);  | 
7646  | 0  |                 }  | 
7647  | 0  |                 else  | 
7648  | 0  |                 { | 
7649  | 0  |                     psOptions->osWHERE = s;  | 
7650  | 0  |                 }  | 
7651  | 0  |             })  | 
7652  | 0  |         .help(_("Attribute query (like SQL WHERE).")); | 
7653  |  | 
  | 
7654  | 0  |     argParser->add_argument("-select") | 
7655  | 0  |         .metavar("<field_list>") | 
7656  | 0  |         .action(  | 
7657  | 0  |             [psOptions](const std::string &s)  | 
7658  | 0  |             { | 
7659  | 0  |                 psOptions->bSelFieldsSet = true;  | 
7660  | 0  |                 psOptions->aosSelFields =  | 
7661  | 0  |                     CSLTokenizeStringComplex(s.c_str(), ",", TRUE, FALSE);  | 
7662  | 0  |             })  | 
7663  | 0  |         .help(_("Comma-delimited list of fields from input layer to copy to " | 
7664  | 0  |                 "the new layer."));  | 
7665  |  | 
  | 
7666  | 0  |     argParser->add_argument("-nln") | 
7667  | 0  |         .metavar("<name>") | 
7668  | 0  |         .store_into(psOptions->osNewLayerName)  | 
7669  | 0  |         .help(_("Assign an alternate name to the new layer.")); | 
7670  |  | 
  | 
7671  | 0  |     argParser->add_argument("-nlt") | 
7672  | 0  |         .metavar("<type>") | 
7673  | 0  |         .append()  | 
7674  | 0  |         .action(  | 
7675  | 0  |             [psOptions](const std::string &osGeomNameIn)  | 
7676  | 0  |             { | 
7677  | 0  |                 bool bIs3D = false;  | 
7678  | 0  |                 std::string osGeomName(osGeomNameIn);  | 
7679  | 0  |                 if (osGeomName.size() > 3 &&  | 
7680  | 0  |                     STARTS_WITH_CI(osGeomName.c_str() + osGeomName.size() - 3,  | 
7681  | 0  |                                    "25D"))  | 
7682  | 0  |                 { | 
7683  | 0  |                     bIs3D = true;  | 
7684  | 0  |                     osGeomName.resize(osGeomName.size() - 3);  | 
7685  | 0  |                 }  | 
7686  | 0  |                 else if (osGeomName.size() > 1 &&  | 
7687  | 0  |                          STARTS_WITH_CI(  | 
7688  | 0  |                              osGeomName.c_str() + osGeomName.size() - 1, "Z"))  | 
7689  | 0  |                 { | 
7690  | 0  |                     bIs3D = true;  | 
7691  | 0  |                     osGeomName.pop_back();  | 
7692  | 0  |                 }  | 
7693  | 0  |                 if (EQUAL(osGeomName.c_str(), "NONE"))  | 
7694  | 0  |                 { | 
7695  | 0  |                     if (psOptions->eGType != GEOMTYPE_UNCHANGED)  | 
7696  | 0  |                     { | 
7697  | 0  |                         throw std::invalid_argument(  | 
7698  | 0  |                             "Unsupported combination of -nlt arguments.");  | 
7699  | 0  |                     }  | 
7700  | 0  |                     psOptions->eGType = wkbNone;  | 
7701  | 0  |                 }  | 
7702  | 0  |                 else if (EQUAL(osGeomName.c_str(), "GEOMETRY"))  | 
7703  | 0  |                 { | 
7704  | 0  |                     if (psOptions->eGType != GEOMTYPE_UNCHANGED)  | 
7705  | 0  |                     { | 
7706  | 0  |                         throw std::invalid_argument(  | 
7707  | 0  |                             "Unsupported combination of -nlt arguments.");  | 
7708  | 0  |                     }  | 
7709  | 0  |                     psOptions->eGType = wkbUnknown;  | 
7710  | 0  |                 }  | 
7711  | 0  |                 else if (EQUAL(osGeomName.c_str(), "PROMOTE_TO_MULTI"))  | 
7712  | 0  |                 { | 
7713  | 0  |                     if (psOptions->eGeomTypeConversion == GTC_CONVERT_TO_LINEAR)  | 
7714  | 0  |                         psOptions->eGeomTypeConversion =  | 
7715  | 0  |                             GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR;  | 
7716  | 0  |                     else if (psOptions->eGeomTypeConversion == GTC_DEFAULT)  | 
7717  | 0  |                         psOptions->eGeomTypeConversion = GTC_PROMOTE_TO_MULTI;  | 
7718  | 0  |                     else  | 
7719  | 0  |                     { | 
7720  | 0  |                         throw std::invalid_argument(  | 
7721  | 0  |                             "Unsupported combination of -nlt arguments.");  | 
7722  | 0  |                     }  | 
7723  | 0  |                 }  | 
7724  | 0  |                 else if (EQUAL(osGeomName.c_str(), "CONVERT_TO_LINEAR"))  | 
7725  | 0  |                 { | 
7726  | 0  |                     if (psOptions->eGeomTypeConversion == GTC_PROMOTE_TO_MULTI)  | 
7727  | 0  |                         psOptions->eGeomTypeConversion =  | 
7728  | 0  |                             GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR;  | 
7729  | 0  |                     else if (psOptions->eGeomTypeConversion == GTC_DEFAULT)  | 
7730  | 0  |                         psOptions->eGeomTypeConversion = GTC_CONVERT_TO_LINEAR;  | 
7731  | 0  |                     else  | 
7732  | 0  |                     { | 
7733  | 0  |                         throw std::invalid_argument(  | 
7734  | 0  |                             "Unsupported combination of -nlt arguments.");  | 
7735  | 0  |                     }  | 
7736  | 0  |                 }  | 
7737  | 0  |                 else if (EQUAL(osGeomName.c_str(), "CONVERT_TO_CURVE"))  | 
7738  | 0  |                 { | 
7739  | 0  |                     if (psOptions->eGeomTypeConversion == GTC_DEFAULT)  | 
7740  | 0  |                         psOptions->eGeomTypeConversion = GTC_CONVERT_TO_CURVE;  | 
7741  | 0  |                     else  | 
7742  | 0  |                     { | 
7743  | 0  |                         throw std::invalid_argument(  | 
7744  | 0  |                             "Unsupported combination of -nlt arguments.");  | 
7745  | 0  |                     }  | 
7746  | 0  |                 }  | 
7747  | 0  |                 else  | 
7748  | 0  |                 { | 
7749  | 0  |                     if (psOptions->eGType != GEOMTYPE_UNCHANGED)  | 
7750  | 0  |                     { | 
7751  | 0  |                         throw std::invalid_argument(  | 
7752  | 0  |                             "Unsupported combination of -nlt arguments.");  | 
7753  | 0  |                     }  | 
7754  | 0  |                     psOptions->eGType = OGRFromOGCGeomType(osGeomName.c_str());  | 
7755  | 0  |                     if (psOptions->eGType == wkbUnknown)  | 
7756  | 0  |                     { | 
7757  | 0  |                         throw std::invalid_argument(  | 
7758  | 0  |                             CPLSPrintf("-nlt %s: type not recognised.", | 
7759  | 0  |                                        osGeomName.c_str()));  | 
7760  | 0  |                     }  | 
7761  | 0  |                 }  | 
7762  | 0  |                 if (psOptions->eGType != GEOMTYPE_UNCHANGED &&  | 
7763  | 0  |                     psOptions->eGType != wkbNone && bIs3D)  | 
7764  | 0  |                     psOptions->eGType = wkbSetZ(  | 
7765  | 0  |                         static_cast<OGRwkbGeometryType>(psOptions->eGType));  | 
7766  | 0  |             })  | 
7767  | 0  |         .help(_("Define the geometry type for the created layer.")); | 
7768  |  | 
  | 
7769  | 0  |     argParser->add_argument("-s_srs") | 
7770  | 0  |         .metavar("<srs_def>") | 
7771  | 0  |         .store_into(psOptions->osSourceSRSDef)  | 
7772  | 0  |         .help(_("Set/override source SRS.")); | 
7773  |  | 
  | 
7774  | 0  |     { | 
7775  | 0  |         auto &group = argParser->add_mutually_exclusive_group();  | 
7776  | 0  |         group.add_argument("-a_srs") | 
7777  | 0  |             .metavar("<srs_def>") | 
7778  | 0  |             .action(  | 
7779  | 0  |                 [psOptions](const std::string &osOutputSRSDef)  | 
7780  | 0  |                 { | 
7781  | 0  |                     psOptions->osOutputSRSDef = osOutputSRSDef;  | 
7782  | 0  |                     if (EQUAL(psOptions->osOutputSRSDef.c_str(), "NULL") ||  | 
7783  | 0  |                         EQUAL(psOptions->osOutputSRSDef.c_str(), "NONE"))  | 
7784  | 0  |                     { | 
7785  | 0  |                         psOptions->osOutputSRSDef.clear();  | 
7786  | 0  |                         psOptions->bNullifyOutputSRS = true;  | 
7787  | 0  |                     }  | 
7788  | 0  |                 })  | 
7789  | 0  |             .help(_("Assign an output SRS, but without reprojecting.")); | 
7790  |  | 
  | 
7791  | 0  |         group.add_argument("-t_srs") | 
7792  | 0  |             .metavar("<srs_def>") | 
7793  | 0  |             .action(  | 
7794  | 0  |                 [psOptions](const std::string &osOutputSRSDef)  | 
7795  | 0  |                 { | 
7796  | 0  |                     psOptions->osOutputSRSDef = osOutputSRSDef;  | 
7797  | 0  |                     psOptions->bTransform = true;  | 
7798  | 0  |                 })  | 
7799  | 0  |             .help(_("Reproject/transform to this SRS on output, and assign it " | 
7800  | 0  |                     "as output SRS."));  | 
7801  | 0  |     }  | 
7802  |  |  | 
7803  |  |     ///////////////////////////////////////////////////////////////////////  | 
7804  | 0  |     argParser->add_group("Field related options"); | 
7805  |  | 
  | 
7806  | 0  |     argParser->add_argument("-addfields") | 
7807  | 0  |         .flag()  | 
7808  | 0  |         .action(  | 
7809  | 0  |             [psOptions](const std::string &)  | 
7810  | 0  |             { | 
7811  | 0  |                 psOptions->bAddMissingFields = true;  | 
7812  | 0  |                 psOptions->eAccessMode = ACCESS_APPEND;  | 
7813  | 0  |             })  | 
7814  | 0  |         .help(_("Same as append, but add also any new fields.")); | 
7815  |  | 
  | 
7816  | 0  |     argParser->add_argument("-relaxedFieldNameMatch") | 
7817  | 0  |         .flag()  | 
7818  | 0  |         .action([psOptions](const std::string &)  | 
7819  | 0  |                 { psOptions->bExactFieldNameMatch = false; }) | 
7820  | 0  |         .help(_("Do field name matching between source and existing target " | 
7821  | 0  |                 "layer in a more relaxed way."));  | 
7822  |  | 
  | 
7823  | 0  |     argParser->add_argument("-fieldTypeToString") | 
7824  | 0  |         .metavar("All|<type1>[,<type2>]...") | 
7825  | 0  |         .action(  | 
7826  | 0  |             [psOptions](const std::string &s)  | 
7827  | 0  |             { | 
7828  | 0  |                 psOptions->aosFieldTypesToString =  | 
7829  | 0  |                     CSLTokenizeStringComplex(s.c_str(), " ,", FALSE, FALSE);  | 
7830  | 0  |                 CSLConstList iter = psOptions->aosFieldTypesToString.List();  | 
7831  | 0  |                 while (*iter)  | 
7832  | 0  |                 { | 
7833  | 0  |                     if (IsFieldType(*iter))  | 
7834  | 0  |                     { | 
7835  |  |                         /* Do nothing */  | 
7836  | 0  |                     }  | 
7837  | 0  |                     else if (EQUAL(*iter, "All"))  | 
7838  | 0  |                     { | 
7839  | 0  |                         psOptions->aosFieldTypesToString.Clear();  | 
7840  | 0  |                         psOptions->aosFieldTypesToString.AddString("All"); | 
7841  | 0  |                         break;  | 
7842  | 0  |                     }  | 
7843  | 0  |                     else  | 
7844  | 0  |                     { | 
7845  | 0  |                         throw std::invalid_argument(CPLSPrintf(  | 
7846  | 0  |                             "Unhandled type for fieldTypeToString option : %s",  | 
7847  | 0  |                             *iter));  | 
7848  | 0  |                     }  | 
7849  | 0  |                     iter++;  | 
7850  | 0  |                 }  | 
7851  | 0  |             })  | 
7852  | 0  |         .help(_("Converts any field of the specified type to a field of type " | 
7853  | 0  |                 "string in the destination layer."));  | 
7854  |  | 
  | 
7855  | 0  |     argParser->add_argument("-mapFieldType") | 
7856  | 0  |         .metavar("<srctype>|All=<dsttype>[,<srctype2>=<dsttype2>]...") | 
7857  | 0  |         .action(  | 
7858  | 0  |             [psOptions](const std::string &s)  | 
7859  | 0  |             { | 
7860  | 0  |                 psOptions->aosMapFieldType =  | 
7861  | 0  |                     CSLTokenizeStringComplex(s.c_str(), " ,", FALSE, FALSE);  | 
7862  | 0  |                 CSLConstList iter = psOptions->aosMapFieldType.List();  | 
7863  | 0  |                 while (*iter)  | 
7864  | 0  |                 { | 
7865  | 0  |                     char *pszKey = nullptr;  | 
7866  | 0  |                     const char *pszValue = CPLParseNameValue(*iter, &pszKey);  | 
7867  | 0  |                     if (pszKey && pszValue)  | 
7868  | 0  |                     { | 
7869  | 0  |                         if (!((IsFieldType(pszKey) || EQUAL(pszKey, "All")) &&  | 
7870  | 0  |                               IsFieldType(pszValue)))  | 
7871  | 0  |                         { | 
7872  | 0  |                             CPLFree(pszKey);  | 
7873  | 0  |                             throw std::invalid_argument(CPLSPrintf(  | 
7874  | 0  |                                 "Invalid value for -mapFieldType : %s", *iter));  | 
7875  | 0  |                         }  | 
7876  | 0  |                     }  | 
7877  | 0  |                     CPLFree(pszKey);  | 
7878  | 0  |                     iter++;  | 
7879  | 0  |                 }  | 
7880  | 0  |             })  | 
7881  | 0  |         .help(_("Converts any field of the specified type to another type.")); | 
7882  |  | 
  | 
7883  | 0  |     argParser->add_argument("-fieldmap") | 
7884  | 0  |         .metavar("<field_1>[,<field_2>]...") | 
7885  | 0  |         .action(  | 
7886  | 0  |             [psOptions](const std::string &s)  | 
7887  | 0  |             { | 
7888  | 0  |                 psOptions->aosFieldMap =  | 
7889  | 0  |                     CSLTokenizeStringComplex(s.c_str(), ",", FALSE, FALSE);  | 
7890  | 0  |             })  | 
7891  | 0  |         .help(_("Specifies the list of field indexes to be copied from the " | 
7892  | 0  |                 "source to the destination."));  | 
7893  |  | 
  | 
7894  | 0  |     argParser->add_argument("-splitlistfields") | 
7895  | 0  |         .store_into(psOptions->bSplitListFields)  | 
7896  | 0  |         .help(_("Split fields of type list type into as many fields of scalar " | 
7897  | 0  |                 "type as necessary."));  | 
7898  |  | 
  | 
7899  | 0  |     argParser->add_argument("-maxsubfields") | 
7900  | 0  |         .metavar("<n>") | 
7901  | 0  |         .scan<'i', int>()  | 
7902  | 0  |         .action(  | 
7903  | 0  |             [psOptions](const std::string &s)  | 
7904  | 0  |             { | 
7905  | 0  |                 const int nVal = atoi(s.c_str());  | 
7906  | 0  |                 if (nVal > 0)  | 
7907  | 0  |                 { | 
7908  | 0  |                     psOptions->nMaxSplitListSubFields = nVal;  | 
7909  | 0  |                 }  | 
7910  | 0  |             })  | 
7911  | 0  |         .help(_("To be combined with -splitlistfields to limit the number of " | 
7912  | 0  |                 "subfields created for each split field."));  | 
7913  |  | 
  | 
7914  | 0  |     argParser->add_argument("-emptyStrAsNull") | 
7915  | 0  |         .store_into(psOptions->bEmptyStrAsNull)  | 
7916  | 0  |         .help(_("Treat empty string values as null.")); | 
7917  |  | 
  | 
7918  | 0  |     argParser->add_argument("-forceNullable") | 
7919  | 0  |         .store_into(psOptions->bForceNullable)  | 
7920  | 0  |         .help(_("Do not propagate not-nullable constraints to target layer if " | 
7921  | 0  |                 "they exist in source layer."));  | 
7922  |  | 
  | 
7923  | 0  |     argParser->add_argument("-unsetFieldWidth") | 
7924  | 0  |         .store_into(psOptions->bUnsetFieldWidth)  | 
7925  | 0  |         .help(_("Set field width and precision to 0.")); | 
7926  |  | 
  | 
7927  | 0  |     argParser->add_argument("-unsetDefault") | 
7928  | 0  |         .store_into(psOptions->bUnsetDefault)  | 
7929  | 0  |         .help(_("Do not propagate default field values to target layer if they " | 
7930  | 0  |                 "exist in source layer."));  | 
7931  |  | 
  | 
7932  | 0  |     argParser->add_argument("-resolveDomains") | 
7933  | 0  |         .store_into(psOptions->bResolveDomains)  | 
7934  | 0  |         .help(_("Cause any selected field that is linked to a coded field " | 
7935  | 0  |                 "domain will be accompanied by an additional field."));  | 
7936  |  | 
  | 
7937  | 0  |     argParser->add_argument("-dateTimeTo") | 
7938  | 0  |         .metavar("UTC|UTC(+|-)<HH>|UTC(+|-)<HH>:<MM>") | 
7939  | 0  |         .action(  | 
7940  | 0  |             [psOptions](const std::string &s)  | 
7941  | 0  |             { | 
7942  | 0  |                 const char *pszFormat = s.c_str();  | 
7943  | 0  |                 if (EQUAL(pszFormat, "UTC"))  | 
7944  | 0  |                 { | 
7945  | 0  |                     psOptions->nTZOffsetInSec = 0;  | 
7946  | 0  |                 }  | 
7947  | 0  |                 else if (STARTS_WITH_CI(pszFormat, "UTC") &&  | 
7948  | 0  |                          (strlen(pszFormat) == strlen("UTC+HH") || | 
7949  | 0  |                           strlen(pszFormat) == strlen("UTC+HH:MM")) && | 
7950  | 0  |                          (pszFormat[3] == '+' || pszFormat[3] == '-'))  | 
7951  | 0  |                 { | 
7952  | 0  |                     const int nHour = atoi(pszFormat + strlen("UTC+")); | 
7953  | 0  |                     if (nHour < 0 || nHour > 14)  | 
7954  | 0  |                     { | 
7955  | 0  |                         throw std::invalid_argument("Invalid UTC hour offset."); | 
7956  | 0  |                     }  | 
7957  | 0  |                     else if (strlen(pszFormat) == strlen("UTC+HH")) | 
7958  | 0  |                     { | 
7959  | 0  |                         psOptions->nTZOffsetInSec = nHour * 3600;  | 
7960  | 0  |                         if (pszFormat[3] == '-')  | 
7961  | 0  |                             psOptions->nTZOffsetInSec =  | 
7962  | 0  |                                 -psOptions->nTZOffsetInSec;  | 
7963  | 0  |                     }  | 
7964  | 0  |                     else  // if( strlen(pszFormat) == strlen("UTC+HH:MM") ) | 
7965  | 0  |                     { | 
7966  | 0  |                         const int nMin = atoi(pszFormat + strlen("UTC+HH:")); | 
7967  | 0  |                         if (nMin == 0 || nMin == 15 || nMin == 30 || nMin == 45)  | 
7968  | 0  |                         { | 
7969  | 0  |                             psOptions->nTZOffsetInSec =  | 
7970  | 0  |                                 nHour * 3600 + nMin * 60;  | 
7971  | 0  |                             if (pszFormat[3] == '-')  | 
7972  | 0  |                                 psOptions->nTZOffsetInSec =  | 
7973  | 0  |                                     -psOptions->nTZOffsetInSec;  | 
7974  | 0  |                         }  | 
7975  | 0  |                     }  | 
7976  | 0  |                 }  | 
7977  | 0  |                 if (psOptions->nTZOffsetInSec == TZ_OFFSET_INVALID)  | 
7978  | 0  |                 { | 
7979  | 0  |                     throw std::invalid_argument(  | 
7980  | 0  |                         "Value of -dateTimeTo should be UTC, UTC(+|-)HH or "  | 
7981  | 0  |                         "UTC(+|-)HH:MM with HH in [0,14] and MM=00,15,30,45");  | 
7982  | 0  |                 }  | 
7983  | 0  |             })  | 
7984  | 0  |         .help(_("Converts date time values from the timezone specified in the " | 
7985  | 0  |                 "source value to the target timezone."));  | 
7986  |  | 
  | 
7987  | 0  |     argParser->add_argument("-noNativeData") | 
7988  | 0  |         .flag()  | 
7989  | 0  |         .action([psOptions](const std::string &)  | 
7990  | 0  |                 { psOptions->bNativeData = false; }) | 
7991  | 0  |         .help(_("Disable copying of native data.")); | 
7992  |  |  | 
7993  |  |     ///////////////////////////////////////////////////////////////////////  | 
7994  | 0  |     argParser->add_group("Advanced geometry and SRS related options"); | 
7995  |  | 
  | 
7996  | 0  |     argParser->add_argument("-dim") | 
7997  | 0  |         .metavar("layer_dim|2|XY|3|XYZ|XYM|XYZM") | 
7998  | 0  |         .action(  | 
7999  | 0  |             [psOptions](const std::string &osDim)  | 
8000  | 0  |             { | 
8001  | 0  |                 if (EQUAL(osDim.c_str(), "layer_dim"))  | 
8002  | 0  |                     psOptions->nCoordDim = COORD_DIM_LAYER_DIM;  | 
8003  | 0  |                 else if (EQUAL(osDim.c_str(), "XY") ||  | 
8004  | 0  |                          EQUAL(osDim.c_str(), "2"))  | 
8005  | 0  |                     psOptions->nCoordDim = 2;  | 
8006  | 0  |                 else if (EQUAL(osDim.c_str(), "XYZ") ||  | 
8007  | 0  |                          EQUAL(osDim.c_str(), "3"))  | 
8008  | 0  |                     psOptions->nCoordDim = 3;  | 
8009  | 0  |                 else if (EQUAL(osDim.c_str(), "XYM"))  | 
8010  | 0  |                     psOptions->nCoordDim = COORD_DIM_XYM;  | 
8011  | 0  |                 else if (EQUAL(osDim.c_str(), "XYZM"))  | 
8012  | 0  |                     psOptions->nCoordDim = 4;  | 
8013  | 0  |                 else  | 
8014  | 0  |                 { | 
8015  | 0  |                     throw std::invalid_argument(CPLSPrintf(  | 
8016  | 0  |                         "-dim %s: value not handled.", osDim.c_str()));  | 
8017  | 0  |                 }  | 
8018  | 0  |             })  | 
8019  | 0  |         .help(_("Force the coordinate dimension.")); | 
8020  |  | 
  | 
8021  | 0  |     argParser->add_argument("-s_coord_epoch") | 
8022  | 0  |         .metavar("<epoch>") | 
8023  | 0  |         .store_into(psOptions->dfSourceCoordinateEpoch)  | 
8024  | 0  |         .help(_("Assign a coordinate epoch, linked with the source SRS.")); | 
8025  |  | 
  | 
8026  | 0  |     argParser->add_argument("-a_coord_epoch") | 
8027  | 0  |         .metavar("<epoch>") | 
8028  | 0  |         .store_into(psOptions->dfOutputCoordinateEpoch)  | 
8029  | 0  |         .help(_("Assign a coordinate epoch, linked with the output SRS when " | 
8030  | 0  |                 "-a_srs is used."));  | 
8031  |  | 
  | 
8032  | 0  |     argParser->add_argument("-t_coord_epoch") | 
8033  | 0  |         .metavar("<epoch>") | 
8034  | 0  |         .store_into(psOptions->dfOutputCoordinateEpoch)  | 
8035  | 0  |         .help(_("Assign a coordinate epoch, linked with the output SRS when " | 
8036  | 0  |                 "-t_srs is used."));  | 
8037  |  | 
  | 
8038  | 0  |     argParser->add_argument("-ct") | 
8039  | 0  |         .metavar("<pipeline_def>") | 
8040  | 0  |         .action(  | 
8041  | 0  |             [psOptions](const std::string &s)  | 
8042  | 0  |             { | 
8043  | 0  |                 psOptions->osCTPipeline = s;  | 
8044  | 0  |                 psOptions->bTransform = true;  | 
8045  | 0  |             })  | 
8046  | 0  |         .help(_("Override the default transformation from the source to the " | 
8047  | 0  |                 "target CRS."));  | 
8048  |  | 
  | 
8049  | 0  |     argParser->add_argument("-ct_opt") | 
8050  | 0  |         .metavar("<NAME>=<VALUE>") | 
8051  | 0  |         .append()  | 
8052  | 0  |         .action([psOptions](const std::string &s)  | 
8053  | 0  |                 { psOptions->aosCTOptions.AddString(s.c_str()); }) | 
8054  | 0  |         .help(_("Coordinate transform option(s).")); | 
8055  |  | 
  | 
8056  | 0  |     argParser->add_argument("-spat_srs") | 
8057  | 0  |         .metavar("<srs_def>") | 
8058  | 0  |         .store_into(psOptions->osSpatSRSDef)  | 
8059  | 0  |         .help(_("Override spatial filter SRS.")); | 
8060  |  | 
  | 
8061  | 0  |     argParser->add_argument("-geomfield") | 
8062  | 0  |         .metavar("<name>") | 
8063  | 0  |         .action(  | 
8064  | 0  |             [psOptions](const std::string &s)  | 
8065  | 0  |             { | 
8066  | 0  |                 psOptions->osGeomField = s;  | 
8067  | 0  |                 psOptions->bGeomFieldSet = true;  | 
8068  | 0  |             })  | 
8069  | 0  |         .help(_("Name of the geometry field on which the spatial filter " | 
8070  | 0  |                 "operates on."));  | 
8071  |  | 
  | 
8072  | 0  |     argParser->add_argument("-segmentize") | 
8073  | 0  |         .metavar("<max_dist>") | 
8074  | 0  |         .store_into(psOptions->dfGeomOpParam)  | 
8075  | 0  |         .action([psOptions](const std::string &)  | 
8076  | 0  |                 { psOptions->eGeomOp = GEOMOP_SEGMENTIZE; }) | 
8077  | 0  |         .help(_("Maximum distance between 2 nodes.")); | 
8078  |  | 
  | 
8079  | 0  |     argParser->add_argument("-simplify") | 
8080  | 0  |         .metavar("<tolerance>") | 
8081  | 0  |         .store_into(psOptions->dfGeomOpParam)  | 
8082  | 0  |         .action([psOptions](const std::string &)  | 
8083  | 0  |                 { psOptions->eGeomOp = GEOMOP_SIMPLIFY_PRESERVE_TOPOLOGY; }) | 
8084  | 0  |         .help(_("Distance tolerance for simplification.")); | 
8085  |  | 
  | 
8086  | 0  |     argParser->add_argument("-makevalid") | 
8087  | 0  |         .flag()  | 
8088  | 0  |         .action(  | 
8089  | 0  |             [psOptions](const std::string &)  | 
8090  | 0  |             { | 
8091  | 0  |                 if (!OGRGeometryFactory::haveGEOS())  | 
8092  | 0  |                 { | 
8093  | 0  |                     throw std::invalid_argument(  | 
8094  | 0  |                         "-makevalid only supported for builds against GEOS");  | 
8095  | 0  |                 }  | 
8096  | 0  |                 psOptions->bMakeValid = true;  | 
8097  | 0  |             })  | 
8098  | 0  |         .help(_("Fix geometries to be valid regarding the rules of the Simple " | 
8099  | 0  |                 "Features specification."));  | 
8100  |  | 
  | 
8101  | 0  |     argParser->add_argument("-skipinvalid") | 
8102  | 0  |         .flag()  | 
8103  | 0  |         .action(  | 
8104  | 0  |             [psOptions](const std::string &)  | 
8105  | 0  |             { | 
8106  | 0  |                 if (!OGRGeometryFactory::haveGEOS())  | 
8107  | 0  |                 { | 
8108  | 0  |                     throw std::invalid_argument(  | 
8109  | 0  |                         "-skipinvalid only supported for builds against GEOS");  | 
8110  | 0  |                 }  | 
8111  | 0  |                 psOptions->bSkipInvalidGeom = true;  | 
8112  | 0  |             })  | 
8113  | 0  |         .help(_("Whether to skip features with invalid geometries regarding the" | 
8114  | 0  |                 "rules of the Simple Features specification."));  | 
8115  |  | 
  | 
8116  | 0  |     argParser->add_argument("-wrapdateline") | 
8117  | 0  |         .store_into(psOptions->bWrapDateline)  | 
8118  | 0  |         .help(_("Split geometries crossing the dateline meridian.")); | 
8119  |  | 
  | 
8120  | 0  |     argParser->add_argument("-datelineoffset") | 
8121  | 0  |         .metavar("<val_in_degree>") | 
8122  | 0  |         .default_value(psOptions->dfDateLineOffset)  | 
8123  | 0  |         .store_into(psOptions->dfDateLineOffset)  | 
8124  | 0  |         .help(_("Offset from dateline in degrees.")); | 
8125  |  | 
  | 
8126  | 0  |     auto &clipsrcArg =  | 
8127  | 0  |         argParser->add_argument("-clipsrc") | 
8128  | 0  |             .metavar(  | 
8129  | 0  |                 "[<xmin> <ymin> <xmax> <ymax>]|<WKT>|<datasource>|spat_extent")  | 
8130  | 0  |             .help(_("Clip geometries (in source SRS).")); | 
8131  | 0  |     if (nCountClipSrc > 1)  | 
8132  | 0  |         clipsrcArg.nargs(nCountClipSrc);  | 
8133  |  | 
  | 
8134  | 0  |     argParser->add_argument("-clipsrcsql") | 
8135  | 0  |         .metavar("<sql_statement>") | 
8136  | 0  |         .store_into(psOptions->osClipSrcSQL)  | 
8137  | 0  |         .help(_("Select desired geometries from the source clip datasource " | 
8138  | 0  |                 "using an SQL query."));  | 
8139  |  | 
  | 
8140  | 0  |     argParser->add_argument("-clipsrclayer") | 
8141  | 0  |         .metavar("<layername>") | 
8142  | 0  |         .store_into(psOptions->osClipSrcLayer)  | 
8143  | 0  |         .help(_("Select the named layer from the source clip datasource.")); | 
8144  |  | 
  | 
8145  | 0  |     argParser->add_argument("-clipsrcwhere") | 
8146  | 0  |         .metavar("<expression>") | 
8147  | 0  |         .store_into(psOptions->osClipSrcWhere)  | 
8148  | 0  |         .help(_("Restrict desired geometries from the source clip layer based " | 
8149  | 0  |                 "on an attribute query."));  | 
8150  |  | 
  | 
8151  | 0  |     auto &clipdstArg =  | 
8152  | 0  |         argParser->add_argument("-clipdst") | 
8153  | 0  |             .metavar("[<xmin> <ymin> <xmax> <ymax>]|<WKT>|<datasource>") | 
8154  | 0  |             .help(_("Clip geometries (in target SRS).")); | 
8155  | 0  |     if (nCountClipDst > 1)  | 
8156  | 0  |         clipdstArg.nargs(nCountClipDst);  | 
8157  |  | 
  | 
8158  | 0  |     argParser->add_argument("-clipdstsql") | 
8159  | 0  |         .metavar("<sql_statement>") | 
8160  | 0  |         .store_into(psOptions->osClipDstSQL)  | 
8161  | 0  |         .help(_("Select desired geometries from the destination clip " | 
8162  | 0  |                 "datasource using an SQL query."));  | 
8163  |  | 
  | 
8164  | 0  |     argParser->add_argument("-clipdstlayer") | 
8165  | 0  |         .metavar("<layername>") | 
8166  | 0  |         .store_into(psOptions->osClipDstLayer)  | 
8167  | 0  |         .help(  | 
8168  | 0  |             _("Select the named layer from the destination clip datasource.")); | 
8169  |  | 
  | 
8170  | 0  |     argParser->add_argument("-clipdstwhere") | 
8171  | 0  |         .metavar("<expression>") | 
8172  | 0  |         .store_into(psOptions->osClipDstWhere)  | 
8173  | 0  |         .help(_("Restrict desired geometries from the destination clip layer " | 
8174  | 0  |                 "based on an attribute query."));  | 
8175  |  | 
  | 
8176  | 0  |     argParser->add_argument("-explodecollections") | 
8177  | 0  |         .store_into(psOptions->bExplodeCollections)  | 
8178  | 0  |         .help(_("Produce one feature for each geometry in any kind of geometry " | 
8179  | 0  |                 "collection in the source file."));  | 
8180  |  | 
  | 
8181  | 0  |     argParser->add_argument("-zfield") | 
8182  | 0  |         .metavar("<name>") | 
8183  | 0  |         .store_into(psOptions->osZField)  | 
8184  | 0  |         .help(_("Uses the specified field to fill the Z coordinate of " | 
8185  | 0  |                 "geometries."));  | 
8186  |  | 
  | 
8187  | 0  |     argParser->add_argument("-gcp") | 
8188  | 0  |         .metavar(  | 
8189  | 0  |             "<ungeoref_x> <ungeoref_y> <georef_x> <georef_y> [<elevation>]")  | 
8190  | 0  |         .nargs(4, 5)  | 
8191  | 0  |         .append()  | 
8192  | 0  |         .scan<'g', double>()  | 
8193  | 0  |         .help(_("Add the indicated ground control point.")); | 
8194  |  | 
  | 
8195  | 0  |     argParser->add_argument("-tps") | 
8196  | 0  |         .flag()  | 
8197  | 0  |         .action([psOptions](const std::string &)  | 
8198  | 0  |                 { psOptions->nTransformOrder = -1; }) | 
8199  | 0  |         .help(_("Force use of thin plate spline transformer based on available " | 
8200  | 0  |                 "GCPs."));  | 
8201  |  | 
  | 
8202  | 0  |     argParser->add_argument("-order") | 
8203  | 0  |         .metavar("1|2|3") | 
8204  | 0  |         .store_into(psOptions->nTransformOrder)  | 
8205  | 0  |         .help(_("Order of polynomial used for warping.")); | 
8206  |  | 
  | 
8207  | 0  |     argParser->add_argument("-xyRes") | 
8208  | 0  |         .metavar("<val>[ m|mm|deg]") | 
8209  | 0  |         .action(  | 
8210  | 0  |             [psOptions](const std::string &s)  | 
8211  | 0  |             { | 
8212  | 0  |                 const char *pszVal = s.c_str();  | 
8213  |  | 
  | 
8214  | 0  |                 char *endptr = nullptr;  | 
8215  | 0  |                 psOptions->dfXYRes = CPLStrtodM(pszVal, &endptr);  | 
8216  | 0  |                 if (!endptr)  | 
8217  | 0  |                 { | 
8218  | 0  |                     throw std::invalid_argument(  | 
8219  | 0  |                         "Invalid value for -xyRes. Must be of the form "  | 
8220  | 0  |                         "{numeric_value}[ ]?[m|mm|deg]?"); | 
8221  | 0  |                 }  | 
8222  | 0  |                 if (*endptr == ' ')  | 
8223  | 0  |                     ++endptr;  | 
8224  | 0  |                 if (*endptr != 0 && strcmp(endptr, "m") != 0 &&  | 
8225  | 0  |                     strcmp(endptr, "mm") != 0 && strcmp(endptr, "deg") != 0)  | 
8226  | 0  |                 { | 
8227  | 0  |                     throw std::invalid_argument(  | 
8228  | 0  |                         "Invalid value for -xyRes. Must be of the form "  | 
8229  | 0  |                         "{numeric_value}[ ]?[m|mm|deg]?"); | 
8230  | 0  |                 }  | 
8231  | 0  |                 psOptions->osXYResUnit = endptr;  | 
8232  | 0  |             })  | 
8233  | 0  |         .help(_("Set/override the geometry X/Y coordinate resolution.")); | 
8234  |  | 
  | 
8235  | 0  |     argParser->add_argument("-zRes") | 
8236  | 0  |         .metavar("<val>[ m|mm]") | 
8237  | 0  |         .action(  | 
8238  | 0  |             [psOptions](const std::string &s)  | 
8239  | 0  |             { | 
8240  | 0  |                 const char *pszVal = s.c_str();  | 
8241  |  | 
  | 
8242  | 0  |                 char *endptr = nullptr;  | 
8243  | 0  |                 psOptions->dfZRes = CPLStrtodM(pszVal, &endptr);  | 
8244  | 0  |                 if (!endptr)  | 
8245  | 0  |                 { | 
8246  | 0  |                     throw std::invalid_argument(  | 
8247  | 0  |                         "Invalid value for -zRes. Must be of the form "  | 
8248  | 0  |                         "{numeric_value}[ ]?[m|mm]?"); | 
8249  | 0  |                 }  | 
8250  | 0  |                 if (*endptr == ' ')  | 
8251  | 0  |                     ++endptr;  | 
8252  | 0  |                 if (*endptr != 0 && strcmp(endptr, "m") != 0 &&  | 
8253  | 0  |                     strcmp(endptr, "mm") != 0 && strcmp(endptr, "deg") != 0)  | 
8254  | 0  |                 { | 
8255  | 0  |                     throw std::invalid_argument(  | 
8256  | 0  |                         "Invalid value for -zRes. Must be of the form "  | 
8257  | 0  |                         "{numeric_value}[ ]?[m|mm]?"); | 
8258  | 0  |                 }  | 
8259  | 0  |                 psOptions->osZResUnit = endptr;  | 
8260  | 0  |             })  | 
8261  | 0  |         .help(_("Set/override the geometry Z coordinate resolution.")); | 
8262  |  | 
  | 
8263  | 0  |     argParser->add_argument("-mRes") | 
8264  | 0  |         .metavar("<val>") | 
8265  | 0  |         .store_into(psOptions->dfMRes)  | 
8266  | 0  |         .help(_("Set/override the geometry M coordinate resolution.")); | 
8267  |  | 
  | 
8268  | 0  |     argParser->add_argument("-unsetCoordPrecision") | 
8269  | 0  |         .store_into(psOptions->bUnsetCoordPrecision)  | 
8270  | 0  |         .help(_("Prevent the geometry coordinate resolution from being set on " | 
8271  | 0  |                 "target layer(s)."));  | 
8272  |  |  | 
8273  |  |     ///////////////////////////////////////////////////////////////////////  | 
8274  | 0  |     argParser->add_group("Other options"); | 
8275  |  | 
  | 
8276  | 0  |     argParser->add_quiet_argument(&psOptions->bQuiet);  | 
8277  |  | 
  | 
8278  | 0  |     argParser->add_argument("-progress") | 
8279  | 0  |         .store_into(psOptions->bDisplayProgress)  | 
8280  | 0  |         .help(_("Display progress on terminal. Only works if input layers have " | 
8281  | 0  |                 "the 'fast feature count' capability."));  | 
8282  |  | 
  | 
8283  | 0  |     argParser->add_input_format_argument(  | 
8284  | 0  |         psOptionsForBinary ? &psOptionsForBinary->aosAllowInputDrivers  | 
8285  | 0  |                            : nullptr);  | 
8286  |  | 
  | 
8287  | 0  |     argParser->add_open_options_argument(  | 
8288  | 0  |         psOptionsForBinary ? &(psOptionsForBinary->aosOpenOptions) : nullptr);  | 
8289  |  | 
  | 
8290  | 0  |     argParser->add_argument("-doo") | 
8291  | 0  |         .metavar("<NAME>=<VALUE>") | 
8292  | 0  |         .append()  | 
8293  | 0  |         .action([psOptions](const std::string &s)  | 
8294  | 0  |                 { psOptions->aosDestOpenOptions.AddString(s.c_str()); }) | 
8295  | 0  |         .help(_("Open option(s) for output dataset.")); | 
8296  |  | 
  | 
8297  | 0  |     argParser->add_usage_newline();  | 
8298  |  | 
  | 
8299  | 0  |     argParser->add_argument("-fid") | 
8300  | 0  |         .metavar("<FID>") | 
8301  | 0  |         .store_into(psOptions->nFIDToFetch)  | 
8302  | 0  |         .help(_("If provided, only the feature with the specified feature id " | 
8303  | 0  |                 "will be processed."));  | 
8304  |  | 
  | 
8305  | 0  |     argParser->add_argument("-preserve_fid") | 
8306  | 0  |         .store_into(psOptions->bPreserveFID)  | 
8307  | 0  |         .help(_("Use the FID of the source features instead of letting the " | 
8308  | 0  |                 "output driver automatically assign a new one."));  | 
8309  |  | 
  | 
8310  | 0  |     argParser->add_argument("-unsetFid") | 
8311  | 0  |         .store_into(psOptions->bUnsetFid)  | 
8312  | 0  |         .help(_("Prevent the name of the source FID column and source feature " | 
8313  | 0  |                 "IDs from being re-used."));  | 
8314  |  | 
  | 
8315  | 0  |     { | 
8316  | 0  |         auto &group = argParser->add_mutually_exclusive_group();  | 
8317  | 0  |         group.add_argument("-skip", "-skipfailures") | 
8318  | 0  |             .flag()  | 
8319  | 0  |             .action(  | 
8320  | 0  |                 [psOptions](const std::string &)  | 
8321  | 0  |                 { | 
8322  | 0  |                     psOptions->bSkipFailures = true;  | 
8323  | 0  |                     psOptions->nGroupTransactions = 1; /* #2409 */  | 
8324  | 0  |                 })  | 
8325  | 0  |             .help(_("Continue after a failure, skipping the failed feature.")); | 
8326  |  | 
  | 
8327  | 0  |         auto &arg = group.add_argument("-gt") | 
8328  | 0  |                         .metavar("<n>|unlimited") | 
8329  | 0  |                         .action(  | 
8330  | 0  |                             [psOptions](const std::string &s)  | 
8331  | 0  |                             { | 
8332  |  |                                 /* If skipfailures is already set we should not  | 
8333  |  |                modify nGroupTransactions = 1  #2409 */  | 
8334  | 0  |                                 if (!psOptions->bSkipFailures)  | 
8335  | 0  |                                 { | 
8336  | 0  |                                     if (EQUAL(s.c_str(), "unlimited"))  | 
8337  | 0  |                                         psOptions->nGroupTransactions = -1;  | 
8338  | 0  |                                     else  | 
8339  | 0  |                                         psOptions->nGroupTransactions =  | 
8340  | 0  |                                             atoi(s.c_str());  | 
8341  | 0  |                                 }  | 
8342  | 0  |                             })  | 
8343  | 0  |                         .help(_("Group <n> features per transaction ")); | 
8344  |  | 
  | 
8345  | 0  |         argParser->add_hidden_alias_for(arg, "tg");  | 
8346  | 0  |     }  | 
8347  |  | 
  | 
8348  | 0  |     argParser->add_argument("-limit") | 
8349  | 0  |         .metavar("<nb_features>") | 
8350  | 0  |         .store_into(psOptions->nLimit)  | 
8351  | 0  |         .help(_("Limit the number of features per layer.")); | 
8352  |  | 
  | 
8353  | 0  |     argParser->add_argument("-ds_transaction") | 
8354  | 0  |         .flag()  | 
8355  | 0  |         .action(  | 
8356  | 0  |             [psOptions](const std::string &)  | 
8357  | 0  |             { | 
8358  | 0  |                 psOptions->nLayerTransaction = FALSE;  | 
8359  | 0  |                 psOptions->bForceTransaction = true;  | 
8360  | 0  |             })  | 
8361  | 0  |         .help(_("Force the use of a dataset level transaction.")); | 
8362  |  |  | 
8363  |  |     /* Undocumented. Just a provision. Default behavior should be OK */  | 
8364  | 0  |     argParser->add_argument("-lyr_transaction") | 
8365  | 0  |         .flag()  | 
8366  | 0  |         .hidden()  | 
8367  | 0  |         .action([psOptions](const std::string &)  | 
8368  | 0  |                 { psOptions->nLayerTransaction = TRUE; }) | 
8369  | 0  |         .help(_("Force the use of a layer level transaction.")); | 
8370  |  | 
  | 
8371  | 0  |     argParser->add_metadata_item_options_argument(  | 
8372  | 0  |         psOptions->aosMetadataOptions);  | 
8373  |  | 
  | 
8374  | 0  |     argParser->add_argument("-nomd") | 
8375  | 0  |         .flag()  | 
8376  | 0  |         .action([psOptions](const std::string &)  | 
8377  | 0  |                 { psOptions->bCopyMD = false; }) | 
8378  | 0  |         .help(_("Disable copying of metadata from source dataset and layers " | 
8379  | 0  |                 "into target dataset and layers."));  | 
8380  |  |  | 
8381  |  |     // Undocumented option used by gdal vector convert  | 
8382  | 0  |     argParser->add_argument("--no-overwrite") | 
8383  | 0  |         .store_into(psOptions->bNoOverwrite)  | 
8384  | 0  |         .hidden();  | 
8385  |  |  | 
8386  |  |     // Undocumented option used by gdal vector convert  | 
8387  | 0  |     argParser->add_argument("--invoked-from-gdal-vector-convert") | 
8388  | 0  |         .store_into(psOptions->bInvokedFromGdalVectorConvert)  | 
8389  | 0  |         .hidden();  | 
8390  |  | 
  | 
8391  | 0  |     if (psOptionsForBinary)  | 
8392  | 0  |     { | 
8393  | 0  |         argParser->add_argument("dst_dataset_name") | 
8394  | 0  |             .metavar("<dst_dataset_name>") | 
8395  | 0  |             .store_into(psOptionsForBinary->osDestDataSource)  | 
8396  | 0  |             .help(_("Output dataset.")); | 
8397  |  | 
  | 
8398  | 0  |         argParser->add_argument("src_dataset_name") | 
8399  | 0  |             .metavar("<src_dataset_name>") | 
8400  | 0  |             .store_into(psOptionsForBinary->osDataSource)  | 
8401  | 0  |             .help(_("Input dataset.")); | 
8402  | 0  |     }  | 
8403  |  | 
  | 
8404  | 0  |     argParser->add_argument("layer") | 
8405  | 0  |         .remaining()  | 
8406  | 0  |         .metavar("<layer_name>") | 
8407  | 0  |         .help(_("Layer name")); | 
8408  | 0  |     return argParser;  | 
8409  | 0  | }  | 
8410  |  |  | 
8411  |  | /************************************************************************/  | 
8412  |  | /*                    GDALVectorTranslateGetParserUsage()               */  | 
8413  |  | /************************************************************************/  | 
8414  |  |  | 
8415  |  | std::string GDALVectorTranslateGetParserUsage()  | 
8416  | 0  | { | 
8417  | 0  |     try  | 
8418  | 0  |     { | 
8419  | 0  |         GDALVectorTranslateOptions sOptions;  | 
8420  | 0  |         GDALVectorTranslateOptionsForBinary sOptionsForBinary;  | 
8421  | 0  |         auto argParser = GDALVectorTranslateOptionsGetParser(  | 
8422  | 0  |             &sOptions, &sOptionsForBinary, 1, 1);  | 
8423  | 0  |         return argParser->usage();  | 
8424  | 0  |     }  | 
8425  | 0  |     catch (const std::exception &err)  | 
8426  | 0  |     { | 
8427  | 0  |         CPLError(CE_Failure, CPLE_AppDefined, "Unexpected exception: %s",  | 
8428  | 0  |                  err.what());  | 
8429  | 0  |         return std::string();  | 
8430  | 0  |     }  | 
8431  | 0  | }  | 
8432  |  |  | 
8433  |  | /************************************************************************/  | 
8434  |  | /*                   CHECK_HAS_ENOUGH_ADDITIONAL_ARGS()                 */  | 
8435  |  | /************************************************************************/  | 
8436  |  |  | 
8437  |  | #ifndef CheckHasEnoughAdditionalArgs_defined  | 
8438  |  | #define CheckHasEnoughAdditionalArgs_defined  | 
8439  |  |  | 
8440  |  | static bool CheckHasEnoughAdditionalArgs(CSLConstList papszArgv, int i,  | 
8441  |  |                                          int nExtraArg, int nArgc)  | 
8442  | 0  | { | 
8443  | 0  |     if (i + nExtraArg >= nArgc)  | 
8444  | 0  |     { | 
8445  | 0  |         CPLError(CE_Failure, CPLE_IllegalArg,  | 
8446  | 0  |                  "%s option requires %d argument%s", papszArgv[i], nExtraArg,  | 
8447  | 0  |                  nExtraArg == 1 ? "" : "s");  | 
8448  | 0  |         return false;  | 
8449  | 0  |     }  | 
8450  | 0  |     return true;  | 
8451  | 0  | }  | 
8452  |  | #endif  | 
8453  |  |  | 
8454  |  | #define CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(nExtraArg)                            \  | 
8455  | 0  |     if (!CheckHasEnoughAdditionalArgs(papszArgv, i, nExtraArg, nArgc))         \  | 
8456  | 0  |     {                                                                          \ | 
8457  | 0  |         return nullptr;                                                        \  | 
8458  | 0  |     }  | 
8459  |  |  | 
8460  |  | /************************************************************************/  | 
8461  |  | /*                       GDALVectorTranslateOptionsNew()                */  | 
8462  |  | /************************************************************************/  | 
8463  |  |  | 
8464  |  | /**  | 
8465  |  |  * allocates a GDALVectorTranslateOptions struct.  | 
8466  |  |  *  | 
8467  |  |  * @param papszArgv NULL terminated list of options (potentially including  | 
8468  |  |  * filename and open options too), or NULL. The accepted options are the ones of  | 
8469  |  |  * the <a href="/programs/ogr2ogr.html">ogr2ogr</a> utility.  | 
8470  |  |  * @param psOptionsForBinary (output) may be NULL (and should generally be  | 
8471  |  |  * NULL), otherwise (gdal_translate_bin.cpp use case) must be allocated with  | 
8472  |  |  *                           GDALVectorTranslateOptionsForBinaryNew() prior to  | 
8473  |  |  * this function. Will be filled with potentially present filename, open  | 
8474  |  |  * options,...  | 
8475  |  |  * @return pointer to the allocated GDALVectorTranslateOptions struct. Must be  | 
8476  |  |  * freed with GDALVectorTranslateOptionsFree().  | 
8477  |  |  *  | 
8478  |  |  * @since GDAL 2.1  | 
8479  |  |  */  | 
8480  |  | GDALVectorTranslateOptions *GDALVectorTranslateOptionsNew(  | 
8481  |  |     char **papszArgv, GDALVectorTranslateOptionsForBinary *psOptionsForBinary)  | 
8482  | 0  | { | 
8483  | 0  |     auto psOptions = std::make_unique<GDALVectorTranslateOptions>();  | 
8484  |  |  | 
8485  |  |     /* -------------------------------------------------------------------- */  | 
8486  |  |     /*      Pre-processing for custom syntax that ArgumentParser does not   */  | 
8487  |  |     /*      support.                                                        */  | 
8488  |  |     /* -------------------------------------------------------------------- */  | 
8489  |  | 
  | 
8490  | 0  |     CPLStringList aosArgv;  | 
8491  | 0  |     const int nArgc = CSLCount(papszArgv);  | 
8492  | 0  |     int nCountClipSrc = 0;  | 
8493  | 0  |     int nCountClipDst = 0;  | 
8494  | 0  |     for (int i = 0;  | 
8495  | 0  |          i < nArgc && papszArgv != nullptr && papszArgv[i] != nullptr; i++)  | 
8496  | 0  |     { | 
8497  | 0  |         if (EQUAL(papszArgv[i], "-gcp"))  | 
8498  | 0  |         { | 
8499  |  |             // repeated argument of varying size: not handled by argparse.  | 
8500  |  | 
  | 
8501  | 0  |             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(4);  | 
8502  | 0  |             char *endptr = nullptr;  | 
8503  |  |             /* -gcp pixel line easting northing [elev] */  | 
8504  |  | 
  | 
8505  | 0  |             psOptions->oGCPs.nGCPCount++;  | 
8506  | 0  |             psOptions->oGCPs.pasGCPs = static_cast<GDAL_GCP *>(  | 
8507  | 0  |                 CPLRealloc(psOptions->oGCPs.pasGCPs,  | 
8508  | 0  |                            sizeof(GDAL_GCP) * psOptions->oGCPs.nGCPCount));  | 
8509  | 0  |             GDALInitGCPs(1, psOptions->oGCPs.pasGCPs +  | 
8510  | 0  |                                 psOptions->oGCPs.nGCPCount - 1);  | 
8511  |  | 
  | 
8512  | 0  |             psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1]  | 
8513  | 0  |                 .dfGCPPixel = CPLAtof(papszArgv[++i]);  | 
8514  | 0  |             psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1].dfGCPLine =  | 
8515  | 0  |                 CPLAtof(papszArgv[++i]);  | 
8516  | 0  |             psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1].dfGCPX =  | 
8517  | 0  |                 CPLAtof(papszArgv[++i]);  | 
8518  | 0  |             psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1].dfGCPY =  | 
8519  | 0  |                 CPLAtof(papszArgv[++i]);  | 
8520  | 0  |             if (papszArgv[i + 1] != nullptr &&  | 
8521  | 0  |                 (CPLStrtod(papszArgv[i + 1], &endptr) != 0.0 ||  | 
8522  | 0  |                  papszArgv[i + 1][0] == '0'))  | 
8523  | 0  |             { | 
8524  |  |                 /* Check that last argument is really a number and not a  | 
8525  |  |                  * filename */  | 
8526  |  |                 /* looking like a number (see ticket #863) */  | 
8527  | 0  |                 if (endptr && *endptr == 0)  | 
8528  | 0  |                     psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1]  | 
8529  | 0  |                         .dfGCPZ = CPLAtof(papszArgv[++i]);  | 
8530  | 0  |             }  | 
8531  |  |  | 
8532  |  |             /* should set id and info? */  | 
8533  | 0  |         }  | 
8534  |  |  | 
8535  | 0  |         else if (EQUAL(papszArgv[i], "-clipsrc"))  | 
8536  | 0  |         { | 
8537  | 0  |             if (nCountClipSrc)  | 
8538  | 0  |             { | 
8539  | 0  |                 CPLError(CE_Failure, CPLE_AppDefined, "Duplicate argument %s",  | 
8540  | 0  |                          papszArgv[i]);  | 
8541  | 0  |                 return nullptr;  | 
8542  | 0  |             }  | 
8543  |  |             // argparse doesn't handle well variable number of values  | 
8544  |  |             // just before the positional arguments, so we have to detect  | 
8545  |  |             // it manually and set the correct number.  | 
8546  | 0  |             nCountClipSrc = 1;  | 
8547  | 0  |             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);  | 
8548  | 0  |             if (CPLGetValueType(papszArgv[i + 1]) != CPL_VALUE_STRING &&  | 
8549  | 0  |                 i + 4 < nArgc)  | 
8550  | 0  |             { | 
8551  | 0  |                 nCountClipSrc = 4;  | 
8552  | 0  |             }  | 
8553  |  | 
  | 
8554  | 0  |             for (int j = 0; j < 1 + nCountClipSrc; ++j)  | 
8555  | 0  |             { | 
8556  | 0  |                 aosArgv.AddString(papszArgv[i]);  | 
8557  | 0  |                 ++i;  | 
8558  | 0  |             }  | 
8559  | 0  |             --i;  | 
8560  | 0  |         }  | 
8561  |  |  | 
8562  | 0  |         else if (EQUAL(papszArgv[i], "-clipdst"))  | 
8563  | 0  |         { | 
8564  | 0  |             if (nCountClipDst)  | 
8565  | 0  |             { | 
8566  | 0  |                 CPLError(CE_Failure, CPLE_AppDefined, "Duplicate argument %s",  | 
8567  | 0  |                          papszArgv[i]);  | 
8568  | 0  |                 return nullptr;  | 
8569  | 0  |             }  | 
8570  |  |             // argparse doesn't handle well variable number of values  | 
8571  |  |             // just before the positional arguments, so we have to detect  | 
8572  |  |             // it manually and set the correct number.  | 
8573  | 0  |             nCountClipDst = 1;  | 
8574  | 0  |             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);  | 
8575  | 0  |             if (CPLGetValueType(papszArgv[i + 1]) != CPL_VALUE_STRING &&  | 
8576  | 0  |                 i + 4 < nArgc)  | 
8577  | 0  |             { | 
8578  | 0  |                 nCountClipDst = 4;  | 
8579  | 0  |             }  | 
8580  |  | 
  | 
8581  | 0  |             for (int j = 0; j < 1 + nCountClipDst; ++j)  | 
8582  | 0  |             { | 
8583  | 0  |                 aosArgv.AddString(papszArgv[i]);  | 
8584  | 0  |                 ++i;  | 
8585  | 0  |             }  | 
8586  | 0  |             --i;  | 
8587  | 0  |         }  | 
8588  |  |  | 
8589  | 0  |         else  | 
8590  | 0  |         { | 
8591  | 0  |             aosArgv.AddString(papszArgv[i]);  | 
8592  | 0  |         }  | 
8593  | 0  |     }  | 
8594  |  |  | 
8595  | 0  |     try  | 
8596  | 0  |     { | 
8597  | 0  |         auto argParser = GDALVectorTranslateOptionsGetParser(  | 
8598  | 0  |             psOptions.get(), psOptionsForBinary, nCountClipSrc, nCountClipDst);  | 
8599  |  |  | 
8600  |  |         // Collect non-positional arguments for VectorTranslateFrom() case  | 
8601  | 0  |         psOptions->aosArguments =  | 
8602  | 0  |             argParser->get_non_positional_arguments(aosArgv);  | 
8603  |  | 
  | 
8604  | 0  |         argParser->parse_args_without_binary_name(aosArgv.List());  | 
8605  |  | 
  | 
8606  | 0  |         if (psOptionsForBinary)  | 
8607  | 0  |             psOptionsForBinary->bQuiet = psOptions->bQuiet;  | 
8608  |  | 
  | 
8609  | 0  |         if (auto oSpat = argParser->present<std::vector<double>>("-spat")) | 
8610  | 0  |         { | 
8611  | 0  |             OGRLinearRing oRing;  | 
8612  | 0  |             const double dfMinX = (*oSpat)[0];  | 
8613  | 0  |             const double dfMinY = (*oSpat)[1];  | 
8614  | 0  |             const double dfMaxX = (*oSpat)[2];  | 
8615  | 0  |             const double dfMaxY = (*oSpat)[3];  | 
8616  |  | 
  | 
8617  | 0  |             oRing.addPoint(dfMinX, dfMinY);  | 
8618  | 0  |             oRing.addPoint(dfMinX, dfMaxY);  | 
8619  | 0  |             oRing.addPoint(dfMaxX, dfMaxY);  | 
8620  | 0  |             oRing.addPoint(dfMaxX, dfMinY);  | 
8621  | 0  |             oRing.addPoint(dfMinX, dfMinY);  | 
8622  |  | 
  | 
8623  | 0  |             auto poSpatialFilter = std::make_shared<OGRPolygon>();  | 
8624  | 0  |             poSpatialFilter->addRing(&oRing);  | 
8625  | 0  |             psOptions->poSpatialFilter = poSpatialFilter;  | 
8626  | 0  |         }  | 
8627  |  | 
  | 
8628  | 0  |         if (auto oClipSrc =  | 
8629  | 0  |                 argParser->present<std::vector<std::string>>("-clipsrc")) | 
8630  | 0  |         { | 
8631  | 0  |             const std::string &osVal = (*oClipSrc)[0];  | 
8632  |  | 
  | 
8633  | 0  |             psOptions->poClipSrc.reset();  | 
8634  | 0  |             psOptions->osClipSrcDS.clear();  | 
8635  |  | 
  | 
8636  | 0  |             VSIStatBufL sStat;  | 
8637  | 0  |             psOptions->bClipSrc = true;  | 
8638  | 0  |             if (oClipSrc->size() == 4)  | 
8639  | 0  |             { | 
8640  | 0  |                 const double dfMinX = CPLAtofM((*oClipSrc)[0].c_str());  | 
8641  | 0  |                 const double dfMinY = CPLAtofM((*oClipSrc)[1].c_str());  | 
8642  | 0  |                 const double dfMaxX = CPLAtofM((*oClipSrc)[2].c_str());  | 
8643  | 0  |                 const double dfMaxY = CPLAtofM((*oClipSrc)[3].c_str());  | 
8644  |  | 
  | 
8645  | 0  |                 OGRLinearRing oRing;  | 
8646  |  | 
  | 
8647  | 0  |                 oRing.addPoint(dfMinX, dfMinY);  | 
8648  | 0  |                 oRing.addPoint(dfMinX, dfMaxY);  | 
8649  | 0  |                 oRing.addPoint(dfMaxX, dfMaxY);  | 
8650  | 0  |                 oRing.addPoint(dfMaxX, dfMinY);  | 
8651  | 0  |                 oRing.addPoint(dfMinX, dfMinY);  | 
8652  |  | 
  | 
8653  | 0  |                 auto poPoly = std::make_shared<OGRPolygon>();  | 
8654  | 0  |                 psOptions->poClipSrc = poPoly;  | 
8655  | 0  |                 poPoly->addRing(&oRing);  | 
8656  | 0  |             }  | 
8657  | 0  |             else if ((STARTS_WITH_CI(osVal.c_str(), "POLYGON") ||  | 
8658  | 0  |                       STARTS_WITH_CI(osVal.c_str(), "MULTIPOLYGON")) &&  | 
8659  | 0  |                      VSIStatL(osVal.c_str(), &sStat) != 0)  | 
8660  | 0  |             { | 
8661  | 0  |                 psOptions->poClipSrc =  | 
8662  | 0  |                     OGRGeometryFactory::createFromWkt(osVal.c_str()).first;  | 
8663  | 0  |                 if (psOptions->poClipSrc == nullptr)  | 
8664  | 0  |                 { | 
8665  | 0  |                     CPLError(  | 
8666  | 0  |                         CE_Failure, CPLE_IllegalArg,  | 
8667  | 0  |                         "Invalid -clipsrc geometry. Must be a valid POLYGON or "  | 
8668  | 0  |                         "MULTIPOLYGON WKT");  | 
8669  | 0  |                     return nullptr;  | 
8670  | 0  |                 }  | 
8671  | 0  |             }  | 
8672  | 0  |             else if (EQUAL(osVal.c_str(), "spat_extent"))  | 
8673  | 0  |             { | 
8674  |  |                 // Nothing to do  | 
8675  | 0  |             }  | 
8676  | 0  |             else  | 
8677  | 0  |             { | 
8678  | 0  |                 psOptions->osClipSrcDS = osVal;  | 
8679  | 0  |             }  | 
8680  | 0  |         }  | 
8681  |  |  | 
8682  | 0  |         if (auto oClipDst =  | 
8683  | 0  |                 argParser->present<std::vector<std::string>>("-clipdst")) | 
8684  | 0  |         { | 
8685  | 0  |             const std::string &osVal = (*oClipDst)[0];  | 
8686  |  | 
  | 
8687  | 0  |             psOptions->poClipDst.reset();  | 
8688  | 0  |             psOptions->osClipDstDS.clear();  | 
8689  |  | 
  | 
8690  | 0  |             VSIStatBufL sStat;  | 
8691  | 0  |             if (oClipDst->size() == 4)  | 
8692  | 0  |             { | 
8693  | 0  |                 const double dfMinX = CPLAtofM((*oClipDst)[0].c_str());  | 
8694  | 0  |                 const double dfMinY = CPLAtofM((*oClipDst)[1].c_str());  | 
8695  | 0  |                 const double dfMaxX = CPLAtofM((*oClipDst)[2].c_str());  | 
8696  | 0  |                 const double dfMaxY = CPLAtofM((*oClipDst)[3].c_str());  | 
8697  |  | 
  | 
8698  | 0  |                 OGRLinearRing oRing;  | 
8699  |  | 
  | 
8700  | 0  |                 oRing.addPoint(dfMinX, dfMinY);  | 
8701  | 0  |                 oRing.addPoint(dfMinX, dfMaxY);  | 
8702  | 0  |                 oRing.addPoint(dfMaxX, dfMaxY);  | 
8703  | 0  |                 oRing.addPoint(dfMaxX, dfMinY);  | 
8704  | 0  |                 oRing.addPoint(dfMinX, dfMinY);  | 
8705  |  | 
  | 
8706  | 0  |                 auto poPoly = std::make_shared<OGRPolygon>();  | 
8707  | 0  |                 psOptions->poClipDst = poPoly;  | 
8708  | 0  |                 poPoly->addRing(&oRing);  | 
8709  | 0  |             }  | 
8710  | 0  |             else if ((STARTS_WITH_CI(osVal.c_str(), "POLYGON") ||  | 
8711  | 0  |                       STARTS_WITH_CI(osVal.c_str(), "MULTIPOLYGON")) &&  | 
8712  | 0  |                      VSIStatL(osVal.c_str(), &sStat) != 0)  | 
8713  | 0  |             { | 
8714  | 0  |                 psOptions->poClipDst =  | 
8715  | 0  |                     OGRGeometryFactory::createFromWkt(osVal.c_str()).first;  | 
8716  | 0  |                 if (psOptions->poClipDst == nullptr)  | 
8717  | 0  |                 { | 
8718  | 0  |                     CPLError(  | 
8719  | 0  |                         CE_Failure, CPLE_IllegalArg,  | 
8720  | 0  |                         "Invalid -clipdst geometry. Must be a valid POLYGON or "  | 
8721  | 0  |                         "MULTIPOLYGON WKT");  | 
8722  | 0  |                     return nullptr;  | 
8723  | 0  |                 }  | 
8724  | 0  |             }  | 
8725  | 0  |             else  | 
8726  | 0  |             { | 
8727  | 0  |                 psOptions->osClipDstDS = osVal;  | 
8728  | 0  |             }  | 
8729  | 0  |         }  | 
8730  |  |  | 
8731  | 0  |         auto layers = argParser->present<std::vector<std::string>>("layer"); | 
8732  | 0  |         if (layers)  | 
8733  | 0  |         { | 
8734  | 0  |             for (const auto &layer : *layers)  | 
8735  | 0  |             { | 
8736  | 0  |                 psOptions->aosLayers.AddString(layer.c_str());  | 
8737  | 0  |             }  | 
8738  | 0  |         }  | 
8739  | 0  |         if (psOptionsForBinary)  | 
8740  | 0  |         { | 
8741  | 0  |             psOptionsForBinary->eAccessMode = psOptions->eAccessMode;  | 
8742  | 0  |             psOptionsForBinary->osFormat = psOptions->osFormat;  | 
8743  |  | 
  | 
8744  | 0  |             if (!(CPLTestBool(  | 
8745  | 0  |                     psOptionsForBinary->aosOpenOptions.FetchNameValueDef(  | 
8746  | 0  |                         "NATIVE_DATA",  | 
8747  | 0  |                         psOptionsForBinary->aosOpenOptions.FetchNameValueDef(  | 
8748  | 0  |                             "@NATIVE_DATA", "TRUE")))))  | 
8749  | 0  |             { | 
8750  | 0  |                 psOptions->bNativeData = false;  | 
8751  | 0  |             }  | 
8752  |  | 
  | 
8753  | 0  |             if (psOptions->bNativeData &&  | 
8754  | 0  |                 psOptionsForBinary->aosOpenOptions.FetchNameValue(  | 
8755  | 0  |                     "NATIVE_DATA") == nullptr &&  | 
8756  | 0  |                 psOptionsForBinary->aosOpenOptions.FetchNameValue(  | 
8757  | 0  |                     "@NATIVE_DATA") == nullptr)  | 
8758  | 0  |             { | 
8759  | 0  |                 psOptionsForBinary->aosOpenOptions.AddString(  | 
8760  | 0  |                     "@NATIVE_DATA=YES");  | 
8761  | 0  |             }  | 
8762  | 0  |         }  | 
8763  |  | 
  | 
8764  | 0  |         return psOptions.release();  | 
8765  | 0  |     }  | 
8766  | 0  |     catch (const std::exception &err)  | 
8767  | 0  |     { | 
8768  | 0  |         CPLError(CE_Failure, CPLE_AppDefined, "%s", err.what());  | 
8769  | 0  |         if (psOptionsForBinary)  | 
8770  | 0  |             psOptionsForBinary->bShowUsageIfError = true;  | 
8771  | 0  |         return nullptr;  | 
8772  | 0  |     }  | 
8773  | 0  | }  | 
8774  |  |  | 
8775  |  | /************************************************************************/  | 
8776  |  | /*                      GDALVectorTranslateOptionsFree()                */  | 
8777  |  | /************************************************************************/  | 
8778  |  |  | 
8779  |  | /**  | 
8780  |  |  * Frees the GDALVectorTranslateOptions struct.  | 
8781  |  |  *  | 
8782  |  |  * @param psOptions the options struct for GDALVectorTranslate().  | 
8783  |  |  * @since GDAL 2.1  | 
8784  |  |  */  | 
8785  |  |  | 
8786  |  | void GDALVectorTranslateOptionsFree(GDALVectorTranslateOptions *psOptions)  | 
8787  | 0  | { | 
8788  | 0  |     delete psOptions;  | 
8789  | 0  | }  | 
8790  |  |  | 
8791  |  | /************************************************************************/  | 
8792  |  | /*                 GDALVectorTranslateOptionsSetProgress()              */  | 
8793  |  | /************************************************************************/  | 
8794  |  |  | 
8795  |  | /**  | 
8796  |  |  * Set a progress function.  | 
8797  |  |  *  | 
8798  |  |  * @param psOptions the options struct for GDALVectorTranslate().  | 
8799  |  |  * @param pfnProgress the progress callback.  | 
8800  |  |  * @param pProgressData the user data for the progress callback.  | 
8801  |  |  *  | 
8802  |  |  * @since GDAL 2.1  | 
8803  |  |  */  | 
8804  |  |  | 
8805  |  | void GDALVectorTranslateOptionsSetProgress(  | 
8806  |  |     GDALVectorTranslateOptions *psOptions, GDALProgressFunc pfnProgress,  | 
8807  |  |     void *pProgressData)  | 
8808  | 0  | { | 
8809  | 0  |     psOptions->pfnProgress = pfnProgress ? pfnProgress : GDALDummyProgress;  | 
8810  | 0  |     psOptions->pProgressData = pProgressData;  | 
8811  | 0  |     if (pfnProgress == GDALTermProgress)  | 
8812  | 0  |         psOptions->bQuiet = false;  | 
8813  | 0  | }  | 
8814  |  |  | 
8815  |  | #undef CHECK_HAS_ENOUGH_ADDITIONAL_ARGS  |