Line data Source code
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 :
63 : typedef enum
64 : {
65 : GEOMOP_NONE,
66 : GEOMOP_SEGMENTIZE,
67 : GEOMOP_SIMPLIFY_PRESERVE_TOPOLOGY,
68 : } GeomOperation;
69 :
70 : typedef enum
71 : {
72 : GTC_DEFAULT,
73 : GTC_PROMOTE_TO_MULTI,
74 : GTC_CONVERT_TO_LINEAR,
75 : GTC_CONVERT_TO_CURVE,
76 : GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR,
77 : } GeomTypeConversion;
78 :
79 : #define GEOMTYPE_UNCHANGED -2
80 :
81 : #define COORD_DIM_UNCHANGED -1
82 : #define COORD_DIM_LAYER_DIM -2
83 : #define COORD_DIM_XYM -3
84 :
85 : #define TZ_OFFSET_INVALID INT_MIN
86 :
87 : /************************************************************************/
88 : /* CopyableGCPs */
89 : /************************************************************************/
90 :
91 : namespace gdal::ogr2ogr_lib
92 : {
93 : struct CopyableGCPs
94 : {
95 : /*! size of the list pasGCPs */
96 : int nGCPCount = 0;
97 :
98 : /*! list of ground control points to be added */
99 : GDAL_GCP *pasGCPs = nullptr;
100 :
101 762 : CopyableGCPs() = default;
102 :
103 717 : CopyableGCPs(const CopyableGCPs &other)
104 717 : {
105 717 : nGCPCount = other.nGCPCount;
106 717 : if (other.nGCPCount)
107 7 : pasGCPs = GDALDuplicateGCPs(other.nGCPCount, other.pasGCPs);
108 : else
109 710 : pasGCPs = nullptr;
110 717 : }
111 :
112 1476 : ~CopyableGCPs()
113 1476 : {
114 1476 : if (pasGCPs)
115 : {
116 14 : GDALDeinitGCPs(nGCPCount, pasGCPs);
117 14 : CPLFree(pasGCPs);
118 : }
119 1476 : }
120 :
121 : CopyableGCPs &operator=(const CopyableGCPs &) = delete;
122 : };
123 : } // namespace gdal::ogr2ogr_lib
124 :
125 : using namespace gdal::ogr2ogr_lib;
126 :
127 : /************************************************************************/
128 : /* GDALVectorTranslateOptions */
129 : /************************************************************************/
130 :
131 : /** Options for use with GDALVectorTranslate(). GDALVectorTranslateOptions* must
132 : * be allocated and freed with GDALVectorTranslateOptionsNew() and
133 : * GDALVectorTranslateOptionsFree() respectively.
134 : */
135 : struct GDALVectorTranslateOptions
136 : {
137 : // All arguments passed to GDALVectorTranslate() except the positional
138 : // ones (that is dataset names and layer names)
139 : CPLStringList aosArguments{};
140 :
141 : /*! continue after a failure, skipping the failed feature */
142 : bool bSkipFailures = false;
143 :
144 : /*! use layer level transaction. If set to FALSE, then it is interpreted as
145 : * dataset level transaction. */
146 : int nLayerTransaction = -1;
147 :
148 : /*! force the use of particular transaction type based on
149 : * GDALVectorTranslate::nLayerTransaction */
150 : bool bForceTransaction = false;
151 :
152 : /*! group nGroupTransactions features per transaction.
153 : Increase the value for better performance when writing into DBMS drivers
154 : that have transaction support. nGroupTransactions can be set to -1 to
155 : load the data into a single transaction */
156 : int nGroupTransactions = 100 * 1000;
157 :
158 : /*! If provided, only the feature with this feature id will be reported.
159 : Operates exclusive of the spatial or attribute queries. Note: if you want
160 : to select several features based on their feature id, you can also use
161 : the fact the 'fid' is a special field recognized by OGR SQL. So
162 : GDALVectorTranslateOptions::pszWHERE = "fid in (1,3,5)" would select
163 : features 1, 3 and 5. */
164 : GIntBig nFIDToFetch = OGRNullFID;
165 :
166 : /*! allow or suppress progress monitor and other non-error output */
167 : bool bQuiet = false;
168 :
169 : /*! output file format name */
170 : std::string osFormat{};
171 :
172 : /*! list of layers of the source dataset which needs to be selected */
173 : CPLStringList aosLayers{};
174 :
175 : /*! dataset creation option (format specific) */
176 : CPLStringList aosDSCO{};
177 :
178 : /*! layer creation option (format specific) */
179 : CPLStringList aosLCO{};
180 :
181 : /*! access modes */
182 : GDALVectorTranslateAccessMode eAccessMode = ACCESS_CREATION;
183 :
184 : /*! whether to use UpsertFeature() instead of CreateFeature() */
185 : bool bUpsert = false;
186 :
187 : /*! It has the effect of adding, to existing target layers, the new fields
188 : found in source layers. This option is useful when merging files that
189 : have non-strictly identical structures. This might not work for output
190 : formats that don't support adding fields to existing non-empty layers. */
191 : bool bAddMissingFields = false;
192 :
193 : /*! It must be set to true to trigger reprojection, otherwise only SRS
194 : * assignment is done. */
195 : bool bTransform = false;
196 :
197 : /*! output SRS. GDALVectorTranslateOptions::bTransform must be set to true
198 : to trigger reprojection, otherwise only SRS assignment is done. */
199 : std::string osOutputSRSDef{};
200 :
201 : /*! Coordinate epoch of source SRS */
202 : double dfSourceCoordinateEpoch = 0;
203 :
204 : /*! Coordinate epoch of output SRS */
205 : double dfOutputCoordinateEpoch = 0;
206 :
207 : /*! override source SRS */
208 : std::string osSourceSRSDef{};
209 :
210 : /*! PROJ pipeline */
211 : std::string osCTPipeline{};
212 :
213 : bool bNullifyOutputSRS = false;
214 :
215 : /*! If set to false, then field name matching between source and existing
216 : target layer is done in a more relaxed way if the target driver has an
217 : implementation for it. */
218 : bool bExactFieldNameMatch = true;
219 :
220 : /*! an alternate name to the new layer */
221 : std::string osNewLayerName{};
222 :
223 : /*! attribute query (like SQL WHERE) */
224 : std::string osWHERE{};
225 :
226 : /*! name of the geometry field on which the spatial filter operates on. */
227 : std::string osGeomField{};
228 :
229 : /*! whether osGeomField is set (useful for empty strings) */
230 : bool bGeomFieldSet = false;
231 :
232 : /*! whether -select has been specified. This is of course true when
233 : * !aosSelFields.empty(), but this can also be set when an empty string
234 : * has been to disable fields. */
235 : bool bSelFieldsSet = false;
236 :
237 : /*! list of fields from input layer to copy to the new layer.
238 : * Geometry fields can also be specified in the list. */
239 : CPLStringList aosSelFields{};
240 :
241 : /*! SQL statement to execute. The resulting table/layer will be saved to the
242 : * output. */
243 : std::string osSQLStatement{};
244 :
245 : /*! SQL dialect. In some cases can be used to use (unoptimized) OGR SQL
246 : instead of the native SQL of an RDBMS by using "OGRSQL". The "SQLITE"
247 : dialect can also be used with any datasource. */
248 : std::string osDialect{};
249 :
250 : /*! the geometry type for the created layer */
251 : int eGType = GEOMTYPE_UNCHANGED;
252 :
253 : GeomTypeConversion eGeomTypeConversion = GTC_DEFAULT;
254 :
255 : /*! Geometric operation to perform */
256 : GeomOperation eGeomOp = GEOMOP_NONE;
257 :
258 : /*! the parameter to geometric operation */
259 : double dfGeomOpParam = 0;
260 :
261 : /*! Whether to run MakeValid */
262 : bool bMakeValid = false;
263 :
264 : /*! Whether to run OGRGeometry::IsValid */
265 : bool bSkipInvalidGeom = false;
266 :
267 : /*! list of field types to convert to a field of type string in the
268 : destination layer. Valid types are: Integer, Integer64, Real, String,
269 : Date, Time, DateTime, Binary, IntegerList, Integer64List, RealList,
270 : StringList. Special value "All" can be used to convert all fields to
271 : strings. This is an alternate way to using the CAST operator of OGR SQL,
272 : that may avoid typing a long SQL query. Note that this does not influence
273 : the field types used by the source driver, and is only an afterwards
274 : conversion. */
275 : CPLStringList aosFieldTypesToString{};
276 :
277 : /*! list of field types and the field type after conversion in the
278 : destination layer.
279 : ("srctype1=dsttype1","srctype2=dsttype2",...).
280 : Valid types are : Integer, Integer64, Real, String, Date, Time,
281 : DateTime, Binary, IntegerList, Integer64List, RealList, StringList. Types
282 : can also include subtype between parenthesis, such as Integer(Boolean),
283 : Real(Float32), ... Special value "All" can be used to convert all fields
284 : to another type. This is an alternate way to using the CAST operator of
285 : OGR SQL, that may avoid typing a long SQL query. This is a generalization
286 : of GDALVectorTranslateOptions::papszFieldTypeToString. Note that this
287 : does not influence the field types used by the source driver, and is only
288 : an afterwards conversion. */
289 : CPLStringList aosMapFieldType{};
290 :
291 : /*! set field width and precision to 0 */
292 : bool bUnsetFieldWidth = false;
293 :
294 : /*! display progress on terminal. Only works if input layers have the "fast
295 : feature count" capability */
296 : bool bDisplayProgress = false;
297 :
298 : /*! split geometries crossing the dateline meridian */
299 : bool bWrapDateline = false;
300 :
301 : /*! offset from dateline in degrees (default long. = +/- 10deg, geometries
302 : within 170deg to -170deg will be split) */
303 : double dfDateLineOffset = 10.0;
304 :
305 : /*! clip geometries when it is set to true */
306 : bool bClipSrc = false;
307 :
308 : std::shared_ptr<OGRGeometry> poClipSrc{};
309 :
310 : /*! clip datasource */
311 : std::string osClipSrcDS{};
312 :
313 : /*! select desired geometries using an SQL query */
314 : std::string osClipSrcSQL{};
315 :
316 : /*! selected named layer from the source clip datasource */
317 : std::string osClipSrcLayer{};
318 :
319 : /*! restrict desired geometries based on attribute query */
320 : std::string osClipSrcWhere{};
321 :
322 : std::shared_ptr<OGRGeometry> poClipDst{};
323 :
324 : /*! destination clip datasource */
325 : std::string osClipDstDS{};
326 :
327 : /*! select desired geometries using an SQL query */
328 : std::string osClipDstSQL{};
329 :
330 : /*! selected named layer from the destination clip datasource */
331 : std::string osClipDstLayer{};
332 :
333 : /*! restrict desired geometries based on attribute query */
334 : std::string osClipDstWhere{};
335 :
336 : /*! split fields of type StringList, RealList or IntegerList into as many
337 : fields of type String, Real or Integer as necessary. */
338 : bool bSplitListFields = false;
339 :
340 : /*! limit the number of subfields created for each split field. */
341 : int nMaxSplitListSubFields = -1;
342 :
343 : /*! produce one feature for each geometry in any kind of geometry collection
344 : in the source file */
345 : bool bExplodeCollections = false;
346 :
347 : /*! uses the specified field to fill the Z coordinates of geometries */
348 : std::string osZField{};
349 :
350 : /*! the list of field indexes to be copied from the source to the
351 : destination. The (n)th value specified in the list is the index of the
352 : field in the target layer definition in which the n(th) field of the
353 : source layer must be copied. Index count starts at zero. There must be
354 : exactly as many values in the list as the count of the fields in the
355 : source layer. We can use the "identity" option to specify that the fields
356 : should be transferred by using the same order. This option should be used
357 : along with the GDALVectorTranslateOptions::eAccessMode = ACCESS_APPEND
358 : option. */
359 : CPLStringList aosFieldMap{};
360 :
361 : /*! force the coordinate dimension to nCoordDim (valid values are 2 or 3).
362 : This affects both the layer geometry type, and feature geometries. */
363 : int nCoordDim = COORD_DIM_UNCHANGED;
364 :
365 : /*! destination dataset open option (format specific), only valid in update
366 : * mode */
367 : CPLStringList aosDestOpenOptions{};
368 :
369 : /*! If set to true, does not propagate not-nullable constraints to target
370 : layer if they exist in source layer */
371 : bool bForceNullable = false;
372 :
373 : /*! If set to true, for each field with a coded field domains, create a
374 : field that contains the description of the coded value. */
375 : bool bResolveDomains = false;
376 :
377 : /*! If set to true, empty string values will be treated as null */
378 : bool bEmptyStrAsNull = false;
379 :
380 : /*! If set to true, does not propagate default field values to target layer
381 : if they exist in source layer */
382 : bool bUnsetDefault = false;
383 :
384 : /*! to prevent the new default behavior that consists in, if the output
385 : driver has a FID layer creation option and we are not in append mode, to
386 : preserve the name of the source FID column and source feature IDs */
387 : bool bUnsetFid = false;
388 :
389 : /*! use the FID of the source features instead of letting the output driver
390 : to automatically assign a new one. If not in append mode, this behavior
391 : becomes the default if the output driver has a FID layer creation option.
392 : In which case the name of the source FID column will be used and source
393 : feature IDs will be attempted to be preserved. This behavior can be
394 : disabled by option GDALVectorTranslateOptions::bUnsetFid */
395 : bool bPreserveFID = false;
396 :
397 : /*! set it to false to disable copying of metadata from source dataset and
398 : layers into target dataset and layers, when supported by output driver.
399 : */
400 : bool bCopyMD = true;
401 :
402 : /*! list of metadata key and value to set on the output dataset, when
403 : supported by output driver.
404 : ("META-TAG1=VALUE1","META-TAG2=VALUE2") */
405 : CPLStringList aosMetadataOptions{};
406 :
407 : /*! override spatial filter SRS */
408 : std::string osSpatSRSDef{};
409 :
410 : /*! list of ground control points to be added */
411 : CopyableGCPs oGCPs{};
412 :
413 : /*! order of polynomial used for warping (1 to 3). The default is to select
414 : a polynomial order based on the number of GCPs */
415 : int nTransformOrder = 0;
416 :
417 : /*! spatial query extents, in the SRS of the source layer(s) (or the one
418 : specified with GDALVectorTranslateOptions::pszSpatSRSDef). Only features
419 : whose geometry intersects the extents will be selected. The geometries
420 : will not be clipped unless GDALVectorTranslateOptions::bClipSrc is true.
421 : */
422 : std::shared_ptr<OGRGeometry> poSpatialFilter{};
423 :
424 : /*! the progress function to use */
425 : GDALProgressFunc pfnProgress = nullptr;
426 :
427 : /*! pointer to the progress data variable */
428 : void *pProgressData = nullptr;
429 :
430 : /*! Whether layer and feature native data must be transferred. */
431 : bool bNativeData = true;
432 :
433 : /*! Maximum number of features, or -1 if no limit. */
434 : GIntBig nLimit = -1;
435 :
436 : /*! Wished offset w.r.t UTC of dateTime */
437 : int nTZOffsetInSec = TZ_OFFSET_INVALID;
438 :
439 : /*! Geometry X,Y coordinate resolution */
440 : double dfXYRes = OGRGeomCoordinatePrecision::UNKNOWN;
441 :
442 : /*! Unit of dXYRes. empty string, "m", "mm" or "deg" */
443 : std::string osXYResUnit{};
444 :
445 : /*! Geometry Z coordinate resolution */
446 : double dfZRes = OGRGeomCoordinatePrecision::UNKNOWN;
447 :
448 : /*! Unit of dfZRes. empty string, "m" or "mm" */
449 : std::string osZResUnit{};
450 :
451 : /*! Geometry M coordinate resolution */
452 : double dfMRes = OGRGeomCoordinatePrecision::UNKNOWN;
453 :
454 : /*! Whether to unset geometry coordinate precision */
455 : bool bUnsetCoordPrecision = false;
456 : };
457 :
458 : struct TargetLayerInfo
459 : {
460 : OGRLayer *m_poSrcLayer = nullptr;
461 : GIntBig m_nFeaturesRead = 0;
462 : bool m_bPerFeatureCT = 0;
463 : OGRLayer *m_poDstLayer = nullptr;
464 : bool m_bUseWriteArrowBatch = false;
465 :
466 : struct ReprojectionInfo
467 : {
468 : std::unique_ptr<OGRCoordinateTransformation> m_poCT{};
469 : CPLStringList m_aosTransformOptions{};
470 : bool m_bCanInvalidateValidity = true;
471 : };
472 :
473 : std::vector<ReprojectionInfo> m_aoReprojectionInfo{};
474 :
475 : std::vector<int> m_anMap{};
476 :
477 : struct ResolvedInfo
478 : {
479 : int nSrcField;
480 : const OGRFieldDomain *poDomain;
481 : };
482 :
483 : std::map<int, ResolvedInfo> m_oMapResolved{};
484 : std::map<const OGRFieldDomain *, std::map<std::string, std::string>>
485 : m_oMapDomainToKV{};
486 : int m_iSrcZField = -1;
487 : int m_iSrcFIDField = -1;
488 : int m_iRequestedSrcGeomField = -1;
489 : bool m_bPreserveFID = false;
490 : const char *m_pszCTPipeline = nullptr;
491 : bool m_bCanAvoidSetFrom = false;
492 : const char *m_pszSpatSRSDef = nullptr;
493 : OGRGeometryH m_hSpatialFilter = nullptr;
494 : const char *m_pszGeomField = nullptr;
495 : std::vector<int> m_anDateTimeFieldIdx{};
496 : bool m_bSupportCurves = false;
497 : OGRArrowArrayStream m_sArrowArrayStream{};
498 : };
499 :
500 : struct AssociatedLayers
501 : {
502 : OGRLayer *poSrcLayer = nullptr;
503 : std::unique_ptr<TargetLayerInfo> psInfo{};
504 : };
505 :
506 : class SetupTargetLayer
507 : {
508 : bool CanUseWriteArrowBatch(OGRLayer *poSrcLayer, OGRLayer *poDstLayer,
509 : bool bJustCreatedLayer,
510 : const GDALVectorTranslateOptions *psOptions,
511 : bool bPreserveFID, bool &bError,
512 : OGRArrowArrayStream &streamSrc);
513 :
514 : public:
515 : GDALDataset *m_poSrcDS = nullptr;
516 : GDALDataset *m_poDstDS = nullptr;
517 : CSLConstList m_papszLCO = nullptr;
518 : const OGRSpatialReference *m_poUserSourceSRS = nullptr;
519 : const OGRSpatialReference *m_poOutputSRS = nullptr;
520 : bool m_bTransform = false;
521 : bool m_bNullifyOutputSRS = false;
522 : bool m_bSelFieldsSet = false;
523 : CSLConstList m_papszSelFields = nullptr;
524 : bool m_bAppend = false;
525 : bool m_bAddMissingFields = false;
526 : int m_eGType = 0;
527 : GeomTypeConversion m_eGeomTypeConversion = GTC_DEFAULT;
528 : int m_nCoordDim = 0;
529 : bool m_bOverwrite = false;
530 : CSLConstList m_papszFieldTypesToString = nullptr;
531 : CSLConstList m_papszMapFieldType = nullptr;
532 : bool m_bUnsetFieldWidth = false;
533 : bool m_bExplodeCollections = false;
534 : const char *m_pszZField = nullptr;
535 : CSLConstList m_papszFieldMap = nullptr;
536 : const char *m_pszWHERE = nullptr;
537 : bool m_bExactFieldNameMatch = false;
538 : bool m_bQuiet = false;
539 : bool m_bForceNullable = false;
540 : bool m_bResolveDomains = false;
541 : bool m_bUnsetDefault = false;
542 : bool m_bUnsetFid = false;
543 : bool m_bPreserveFID = false;
544 : bool m_bCopyMD = false;
545 : bool m_bNativeData = false;
546 : bool m_bNewDataSource = false;
547 : const char *m_pszCTPipeline = nullptr;
548 :
549 : std::unique_ptr<TargetLayerInfo>
550 : Setup(OGRLayer *poSrcLayer, const char *pszNewLayerName,
551 : GDALVectorTranslateOptions *psOptions, GIntBig &nTotalEventsDone);
552 : };
553 :
554 : class LayerTranslator
555 : {
556 : bool TranslateArrow(TargetLayerInfo *psInfo, GIntBig nCountLayerFeatures,
557 : GIntBig *pnReadFeatureCount,
558 : GDALProgressFunc pfnProgress, void *pProgressArg,
559 : const GDALVectorTranslateOptions *psOptions);
560 :
561 : public:
562 : GDALDataset *m_poSrcDS = nullptr;
563 : GDALDataset *m_poODS = nullptr;
564 : bool m_bTransform = false;
565 : bool m_bWrapDateline = false;
566 : CPLString m_osDateLineOffset{};
567 : const OGRSpatialReference *m_poOutputSRS = nullptr;
568 : bool m_bNullifyOutputSRS = false;
569 : const OGRSpatialReference *m_poUserSourceSRS = nullptr;
570 : OGRCoordinateTransformation *m_poGCPCoordTrans = nullptr;
571 : int m_eGType = -1;
572 : GeomTypeConversion m_eGeomTypeConversion = GTC_DEFAULT;
573 : bool m_bMakeValid = false;
574 : bool m_bSkipInvalidGeom = false;
575 : int m_nCoordDim = 0;
576 : GeomOperation m_eGeomOp = GEOMOP_NONE;
577 : double m_dfGeomOpParam = 0;
578 :
579 : OGRGeometry *m_poClipSrcOri = nullptr;
580 : bool m_bWarnedClipSrcSRS = false;
581 : std::unique_ptr<OGRGeometry> m_poClipSrcReprojectedToSrcSRS{};
582 : const OGRSpatialReference *m_poClipSrcReprojectedToSrcSRS_SRS = nullptr;
583 : OGREnvelope m_oClipSrcEnv{};
584 :
585 : OGRGeometry *m_poClipDstOri = nullptr;
586 : bool m_bWarnedClipDstSRS = false;
587 : std::unique_ptr<OGRGeometry> m_poClipDstReprojectedToDstSRS{};
588 : const OGRSpatialReference *m_poClipDstReprojectedToDstSRS_SRS = nullptr;
589 : OGREnvelope m_oClipDstEnv{};
590 :
591 : bool m_bExplodeCollections = false;
592 : bool m_bNativeData = false;
593 : GIntBig m_nLimit = -1;
594 : OGRGeometryFactory::TransformWithOptionsCache m_transformWithOptionsCache{};
595 :
596 : bool Translate(OGRFeature *poFeatureIn, TargetLayerInfo *psInfo,
597 : GIntBig nCountLayerFeatures, GIntBig *pnReadFeatureCount,
598 : GIntBig &nTotalEventsDone, GDALProgressFunc pfnProgress,
599 : void *pProgressArg,
600 : const GDALVectorTranslateOptions *psOptions);
601 :
602 : private:
603 : std::pair<const OGRGeometry *, const OGREnvelope *>
604 : GetDstClipGeom(const OGRSpatialReference *poGeomSRS);
605 : std::pair<const OGRGeometry *, const OGREnvelope *>
606 : GetSrcClipGeom(const OGRSpatialReference *poGeomSRS);
607 : };
608 :
609 : static OGRLayer *GetLayerAndOverwriteIfNecessary(GDALDataset *poDstDS,
610 : const char *pszNewLayerName,
611 : bool bOverwrite,
612 : bool *pbErrorOccurred,
613 : bool *pbOverwriteActuallyDone,
614 : bool *pbAddOverwriteLCO);
615 :
616 : /************************************************************************/
617 : /* LoadGeometry() */
618 : /************************************************************************/
619 :
620 18 : static std::unique_ptr<OGRGeometry> LoadGeometry(const std::string &osDS,
621 : const std::string &osSQL,
622 : const std::string &osLyr,
623 : const std::string &osWhere,
624 : bool bMakeValid)
625 : {
626 : auto poDS = std::unique_ptr<GDALDataset>(
627 36 : GDALDataset::Open(osDS.c_str(), GDAL_OF_VECTOR));
628 18 : if (poDS == nullptr)
629 3 : return nullptr;
630 :
631 15 : OGRLayer *poLyr = nullptr;
632 15 : if (!osSQL.empty())
633 3 : poLyr = poDS->ExecuteSQL(osSQL.c_str(), nullptr, nullptr);
634 12 : else if (!osLyr.empty())
635 2 : poLyr = poDS->GetLayerByName(osLyr.c_str());
636 : else
637 10 : poLyr = poDS->GetLayer(0);
638 :
639 15 : if (poLyr == nullptr)
640 : {
641 0 : CPLError(CE_Failure, CPLE_AppDefined,
642 : "Failed to identify source layer from datasource.");
643 0 : return nullptr;
644 : }
645 :
646 15 : if (!osWhere.empty())
647 5 : poLyr->SetAttributeFilter(osWhere.c_str());
648 :
649 30 : OGRGeometryCollection oGC;
650 :
651 15 : const auto poSRSSrc = poLyr->GetSpatialRef();
652 15 : if (poSRSSrc)
653 : {
654 2 : auto poSRSClone = poSRSSrc->Clone();
655 2 : oGC.assignSpatialReference(poSRSClone);
656 2 : poSRSClone->Release();
657 : }
658 :
659 30 : for (auto &poFeat : poLyr)
660 : {
661 15 : auto poSrcGeom = std::unique_ptr<OGRGeometry>(poFeat->StealGeometry());
662 15 : if (poSrcGeom)
663 : {
664 : // Only take into account areal geometries.
665 15 : if (poSrcGeom->getDimension() == 2)
666 : {
667 15 : if (!poSrcGeom->IsValid())
668 : {
669 4 : if (!bMakeValid)
670 : {
671 2 : CPLError(CE_Failure, CPLE_AppDefined,
672 : "Geometry of feature " CPL_FRMT_GIB " of %s "
673 : "is invalid. You can try to make it valid by "
674 : "specifying -makevalid, but the results of "
675 : "the operation should be manually inspected.",
676 : poFeat->GetFID(), osDS.c_str());
677 2 : oGC.empty();
678 2 : break;
679 : }
680 : auto poValid =
681 2 : std::unique_ptr<OGRGeometry>(poSrcGeom->MakeValid());
682 2 : if (poValid)
683 : {
684 2 : CPLError(CE_Warning, CPLE_AppDefined,
685 : "Geometry of feature " CPL_FRMT_GIB " of %s "
686 : "was invalid and has been made valid, "
687 : "but the results of the operation "
688 : "should be manually inspected.",
689 : poFeat->GetFID(), osDS.c_str());
690 :
691 2 : oGC.addGeometry(std::move(poValid));
692 : }
693 : else
694 : {
695 0 : CPLError(CE_Failure, CPLE_AppDefined,
696 : "Geometry of feature " CPL_FRMT_GIB " of %s "
697 : "is invalid, and could not be made valid.",
698 : poFeat->GetFID(), osDS.c_str());
699 0 : oGC.empty();
700 0 : break;
701 : }
702 : }
703 : else
704 : {
705 11 : oGC.addGeometry(std::move(poSrcGeom));
706 : }
707 : }
708 : }
709 : }
710 :
711 15 : if (!osSQL.empty())
712 3 : poDS->ReleaseResultSet(poLyr);
713 :
714 15 : if (oGC.IsEmpty())
715 2 : return nullptr;
716 :
717 13 : return std::unique_ptr<OGRGeometry>(oGC.UnaryUnion());
718 : }
719 :
720 : /************************************************************************/
721 : /* OGRSplitListFieldLayer */
722 : /************************************************************************/
723 :
724 : typedef struct
725 : {
726 : int iSrcIndex;
727 : OGRFieldType eType;
728 : int nMaxOccurrences;
729 : int nWidth;
730 : } ListFieldDesc;
731 :
732 : class OGRSplitListFieldLayer : public OGRLayer
733 : {
734 : OGRLayer *poSrcLayer = nullptr;
735 : OGRFeatureDefn *poFeatureDefn = nullptr;
736 : ListFieldDesc *pasListFields = nullptr;
737 : int nListFieldCount = 0;
738 : const int nMaxSplitListSubFields;
739 :
740 : std::unique_ptr<OGRFeature>
741 : TranslateFeature(std::unique_ptr<OGRFeature> poSrcFeature);
742 :
743 : CPL_DISALLOW_COPY_ASSIGN(OGRSplitListFieldLayer)
744 :
745 : public:
746 : OGRSplitListFieldLayer(OGRLayer *poSrcLayer, int nMaxSplitListSubFields);
747 : virtual ~OGRSplitListFieldLayer();
748 :
749 : bool BuildLayerDefn(GDALProgressFunc pfnProgress, void *pProgressArg);
750 :
751 : virtual OGRFeature *GetNextFeature() override;
752 : virtual OGRFeature *GetFeature(GIntBig nFID) override;
753 : virtual OGRFeatureDefn *GetLayerDefn() override;
754 :
755 1 : virtual void ResetReading() override
756 : {
757 1 : poSrcLayer->ResetReading();
758 1 : }
759 :
760 1 : virtual int TestCapability(const char *) override
761 : {
762 1 : return FALSE;
763 : }
764 :
765 0 : virtual GIntBig GetFeatureCount(int bForce = TRUE) override
766 : {
767 0 : return poSrcLayer->GetFeatureCount(bForce);
768 : }
769 :
770 1 : virtual OGRSpatialReference *GetSpatialRef() override
771 : {
772 1 : return poSrcLayer->GetSpatialRef();
773 : }
774 :
775 0 : virtual OGRGeometry *GetSpatialFilter() override
776 : {
777 0 : return poSrcLayer->GetSpatialFilter();
778 : }
779 :
780 1 : virtual OGRStyleTable *GetStyleTable() override
781 : {
782 1 : return poSrcLayer->GetStyleTable();
783 : }
784 :
785 0 : virtual void SetSpatialFilter(OGRGeometry *poGeom) override
786 : {
787 0 : poSrcLayer->SetSpatialFilter(poGeom);
788 0 : }
789 :
790 0 : virtual void SetSpatialFilter(int iGeom, OGRGeometry *poGeom) override
791 : {
792 0 : poSrcLayer->SetSpatialFilter(iGeom, poGeom);
793 0 : }
794 :
795 0 : virtual void SetSpatialFilterRect(double dfMinX, double dfMinY,
796 : double dfMaxX, double dfMaxY) override
797 : {
798 0 : poSrcLayer->SetSpatialFilterRect(dfMinX, dfMinY, dfMaxX, dfMaxY);
799 0 : }
800 :
801 0 : virtual void SetSpatialFilterRect(int iGeom, double dfMinX, double dfMinY,
802 : double dfMaxX, double dfMaxY) override
803 : {
804 0 : poSrcLayer->SetSpatialFilterRect(iGeom, dfMinX, dfMinY, dfMaxX, dfMaxY);
805 0 : }
806 :
807 0 : virtual OGRErr SetAttributeFilter(const char *pszFilter) override
808 : {
809 0 : return poSrcLayer->SetAttributeFilter(pszFilter);
810 : }
811 : };
812 :
813 : /************************************************************************/
814 : /* OGRSplitListFieldLayer() */
815 : /************************************************************************/
816 :
817 1 : OGRSplitListFieldLayer::OGRSplitListFieldLayer(OGRLayer *poSrcLayerIn,
818 1 : int nMaxSplitListSubFieldsIn)
819 : : poSrcLayer(poSrcLayerIn),
820 : nMaxSplitListSubFields(
821 1 : nMaxSplitListSubFieldsIn < 0 ? INT_MAX : nMaxSplitListSubFieldsIn)
822 : {
823 1 : }
824 :
825 : /************************************************************************/
826 : /* ~OGRSplitListFieldLayer() */
827 : /************************************************************************/
828 :
829 2 : OGRSplitListFieldLayer::~OGRSplitListFieldLayer()
830 : {
831 1 : if (poFeatureDefn)
832 1 : poFeatureDefn->Release();
833 :
834 1 : CPLFree(pasListFields);
835 2 : }
836 :
837 : /************************************************************************/
838 : /* BuildLayerDefn() */
839 : /************************************************************************/
840 :
841 1 : bool OGRSplitListFieldLayer::BuildLayerDefn(GDALProgressFunc pfnProgress,
842 : void *pProgressArg)
843 : {
844 1 : CPLAssert(poFeatureDefn == nullptr);
845 :
846 1 : OGRFeatureDefn *poSrcFieldDefn = poSrcLayer->GetLayerDefn();
847 :
848 1 : int nSrcFields = poSrcFieldDefn->GetFieldCount();
849 1 : pasListFields = static_cast<ListFieldDesc *>(
850 1 : CPLCalloc(sizeof(ListFieldDesc), nSrcFields));
851 1 : nListFieldCount = 0;
852 :
853 : /* Establish the list of fields of list type */
854 6 : for (int i = 0; i < nSrcFields; ++i)
855 : {
856 5 : OGRFieldType eType = poSrcFieldDefn->GetFieldDefn(i)->GetType();
857 5 : if (eType == OFTIntegerList || eType == OFTInteger64List ||
858 3 : eType == OFTRealList || eType == OFTStringList)
859 : {
860 3 : pasListFields[nListFieldCount].iSrcIndex = i;
861 3 : pasListFields[nListFieldCount].eType = eType;
862 3 : if (nMaxSplitListSubFields == 1)
863 0 : pasListFields[nListFieldCount].nMaxOccurrences = 1;
864 3 : nListFieldCount++;
865 : }
866 : }
867 :
868 1 : if (nListFieldCount == 0)
869 0 : return false;
870 :
871 : /* No need for full scan if the limit is 1. We just to have to create */
872 : /* one and a single one field */
873 1 : if (nMaxSplitListSubFields != 1)
874 : {
875 1 : poSrcLayer->ResetReading();
876 :
877 : const GIntBig nFeatureCount =
878 1 : poSrcLayer->TestCapability(OLCFastFeatureCount)
879 1 : ? poSrcLayer->GetFeatureCount()
880 1 : : 0;
881 1 : GIntBig nFeatureIndex = 0;
882 :
883 : /* Scan the whole layer to compute the maximum number of */
884 : /* items for each field of list type */
885 2 : for (auto &poSrcFeature : poSrcLayer)
886 : {
887 4 : for (int i = 0; i < nListFieldCount; ++i)
888 : {
889 3 : int nCount = 0;
890 : OGRField *psField =
891 3 : poSrcFeature->GetRawFieldRef(pasListFields[i].iSrcIndex);
892 3 : switch (pasListFields[i].eType)
893 : {
894 1 : case OFTIntegerList:
895 1 : nCount = psField->IntegerList.nCount;
896 1 : break;
897 1 : case OFTRealList:
898 1 : nCount = psField->RealList.nCount;
899 1 : break;
900 1 : case OFTStringList:
901 : {
902 1 : nCount = psField->StringList.nCount;
903 1 : char **paList = psField->StringList.paList;
904 3 : for (int j = 0; j < nCount; j++)
905 : {
906 2 : int nWidth = static_cast<int>(strlen(paList[j]));
907 2 : if (nWidth > pasListFields[i].nWidth)
908 1 : pasListFields[i].nWidth = nWidth;
909 : }
910 1 : break;
911 : }
912 0 : default:
913 : // cppcheck-suppress knownConditionTrueFalse
914 0 : CPLAssert(false);
915 : break;
916 : }
917 3 : if (nCount > pasListFields[i].nMaxOccurrences)
918 : {
919 3 : if (nCount > nMaxSplitListSubFields)
920 0 : nCount = nMaxSplitListSubFields;
921 3 : pasListFields[i].nMaxOccurrences = nCount;
922 : }
923 : }
924 :
925 1 : nFeatureIndex++;
926 1 : if (pfnProgress != nullptr && nFeatureCount != 0)
927 0 : pfnProgress(nFeatureIndex * 1.0 / nFeatureCount, "",
928 : pProgressArg);
929 : }
930 : }
931 :
932 : /* Now let's build the target feature definition */
933 :
934 1 : poFeatureDefn =
935 1 : OGRFeatureDefn::CreateFeatureDefn(poSrcFieldDefn->GetName());
936 1 : poFeatureDefn->Reference();
937 1 : poFeatureDefn->SetGeomType(wkbNone);
938 :
939 1 : for (int i = 0; i < poSrcFieldDefn->GetGeomFieldCount(); ++i)
940 : {
941 0 : poFeatureDefn->AddGeomFieldDefn(poSrcFieldDefn->GetGeomFieldDefn(i));
942 : }
943 :
944 1 : int iListField = 0;
945 6 : for (int i = 0; i < nSrcFields; ++i)
946 : {
947 5 : const OGRFieldType eType = poSrcFieldDefn->GetFieldDefn(i)->GetType();
948 5 : if (eType == OFTIntegerList || eType == OFTInteger64List ||
949 3 : eType == OFTRealList || eType == OFTStringList)
950 : {
951 3 : const int nMaxOccurrences =
952 3 : pasListFields[iListField].nMaxOccurrences;
953 3 : const int nWidth = pasListFields[iListField].nWidth;
954 3 : iListField++;
955 3 : if (nMaxOccurrences == 1)
956 : {
957 : OGRFieldDefn oFieldDefn(
958 0 : poSrcFieldDefn->GetFieldDefn(i)->GetNameRef(),
959 : (eType == OFTIntegerList) ? OFTInteger
960 0 : : (eType == OFTInteger64List) ? OFTInteger64
961 0 : : (eType == OFTRealList) ? OFTReal
962 0 : : OFTString);
963 0 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
964 : }
965 : else
966 : {
967 9 : for (int j = 0; j < nMaxOccurrences; j++)
968 : {
969 12 : CPLString osFieldName;
970 : osFieldName.Printf(
971 6 : "%s%d", poSrcFieldDefn->GetFieldDefn(i)->GetNameRef(),
972 6 : j + 1);
973 : OGRFieldDefn oFieldDefn(
974 : osFieldName.c_str(),
975 : (eType == OFTIntegerList) ? OFTInteger
976 8 : : (eType == OFTInteger64List) ? OFTInteger64
977 4 : : (eType == OFTRealList) ? OFTReal
978 16 : : OFTString);
979 6 : oFieldDefn.SetWidth(nWidth);
980 6 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
981 : }
982 3 : }
983 : }
984 : else
985 : {
986 2 : poFeatureDefn->AddFieldDefn(poSrcFieldDefn->GetFieldDefn(i));
987 : }
988 : }
989 :
990 1 : return true;
991 : }
992 :
993 : /************************************************************************/
994 : /* TranslateFeature() */
995 : /************************************************************************/
996 :
997 2 : std::unique_ptr<OGRFeature> OGRSplitListFieldLayer::TranslateFeature(
998 : std::unique_ptr<OGRFeature> poSrcFeature)
999 : {
1000 2 : if (poSrcFeature == nullptr)
1001 1 : return nullptr;
1002 1 : if (poFeatureDefn == nullptr)
1003 0 : return poSrcFeature;
1004 :
1005 2 : auto poFeature = std::make_unique<OGRFeature>(poFeatureDefn);
1006 1 : poFeature->SetFID(poSrcFeature->GetFID());
1007 1 : for (int i = 0; i < poFeature->GetGeomFieldCount(); i++)
1008 : {
1009 0 : poFeature->SetGeomFieldDirectly(i, poSrcFeature->StealGeometry(i));
1010 : }
1011 1 : poFeature->SetStyleString(poFeature->GetStyleString());
1012 :
1013 1 : OGRFeatureDefn *poSrcFieldDefn = poSrcLayer->GetLayerDefn();
1014 1 : int nSrcFields = poSrcFeature->GetFieldCount();
1015 1 : int iDstField = 0;
1016 1 : int iListField = 0;
1017 :
1018 6 : for (int iSrcField = 0; iSrcField < nSrcFields; ++iSrcField)
1019 : {
1020 : const OGRFieldType eType =
1021 5 : poSrcFieldDefn->GetFieldDefn(iSrcField)->GetType();
1022 5 : OGRField *psField = poSrcFeature->GetRawFieldRef(iSrcField);
1023 5 : switch (eType)
1024 : {
1025 1 : case OFTIntegerList:
1026 : {
1027 1 : const int nCount = std::min(nMaxSplitListSubFields,
1028 1 : psField->IntegerList.nCount);
1029 1 : int *paList = psField->IntegerList.paList;
1030 3 : for (int j = 0; j < nCount; ++j)
1031 2 : poFeature->SetField(iDstField + j, paList[j]);
1032 1 : iDstField += pasListFields[iListField].nMaxOccurrences;
1033 1 : iListField++;
1034 1 : break;
1035 : }
1036 0 : case OFTInteger64List:
1037 : {
1038 0 : const int nCount = std::min(nMaxSplitListSubFields,
1039 0 : psField->Integer64List.nCount);
1040 0 : GIntBig *paList = psField->Integer64List.paList;
1041 0 : for (int j = 0; j < nCount; ++j)
1042 0 : poFeature->SetField(iDstField + j, paList[j]);
1043 0 : iDstField += pasListFields[iListField].nMaxOccurrences;
1044 0 : iListField++;
1045 0 : break;
1046 : }
1047 1 : case OFTRealList:
1048 : {
1049 : const int nCount =
1050 1 : std::min(nMaxSplitListSubFields, psField->RealList.nCount);
1051 1 : double *paList = psField->RealList.paList;
1052 3 : for (int j = 0; j < nCount; ++j)
1053 2 : poFeature->SetField(iDstField + j, paList[j]);
1054 1 : iDstField += pasListFields[iListField].nMaxOccurrences;
1055 1 : iListField++;
1056 1 : break;
1057 : }
1058 1 : case OFTStringList:
1059 : {
1060 1 : const int nCount = std::min(nMaxSplitListSubFields,
1061 1 : psField->StringList.nCount);
1062 1 : char **paList = psField->StringList.paList;
1063 3 : for (int j = 0; j < nCount; ++j)
1064 2 : poFeature->SetField(iDstField + j, paList[j]);
1065 1 : iDstField += pasListFields[iListField].nMaxOccurrences;
1066 1 : iListField++;
1067 1 : break;
1068 : }
1069 2 : default:
1070 : {
1071 2 : poFeature->SetField(iDstField, psField);
1072 2 : iDstField++;
1073 2 : break;
1074 : }
1075 : }
1076 : }
1077 :
1078 1 : return poFeature;
1079 : }
1080 :
1081 : /************************************************************************/
1082 : /* GetNextFeature() */
1083 : /************************************************************************/
1084 :
1085 2 : OGRFeature *OGRSplitListFieldLayer::GetNextFeature()
1086 : {
1087 4 : return TranslateFeature(
1088 4 : std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature()))
1089 4 : .release();
1090 : }
1091 :
1092 : /************************************************************************/
1093 : /* GetFeature() */
1094 : /************************************************************************/
1095 :
1096 0 : OGRFeature *OGRSplitListFieldLayer::GetFeature(GIntBig nFID)
1097 : {
1098 0 : return TranslateFeature(
1099 0 : std::unique_ptr<OGRFeature>(poSrcLayer->GetFeature(nFID)))
1100 0 : .release();
1101 : }
1102 :
1103 : /************************************************************************/
1104 : /* GetLayerDefn() */
1105 : /************************************************************************/
1106 :
1107 3 : OGRFeatureDefn *OGRSplitListFieldLayer::GetLayerDefn()
1108 : {
1109 3 : if (poFeatureDefn == nullptr)
1110 0 : return poSrcLayer->GetLayerDefn();
1111 3 : return poFeatureDefn;
1112 : }
1113 :
1114 : /************************************************************************/
1115 : /* GCPCoordTransformation() */
1116 : /* */
1117 : /* Apply GCP Transform to points */
1118 : /************************************************************************/
1119 :
1120 : class GCPCoordTransformation : public OGRCoordinateTransformation
1121 : {
1122 0 : GCPCoordTransformation(const GCPCoordTransformation &other)
1123 0 : : hTransformArg(GDALCloneTransformer(other.hTransformArg)),
1124 0 : bUseTPS(other.bUseTPS), poSRS(other.poSRS)
1125 : {
1126 0 : if (poSRS)
1127 0 : poSRS->Reference();
1128 0 : }
1129 :
1130 : GCPCoordTransformation &operator=(const GCPCoordTransformation &) = delete;
1131 :
1132 : public:
1133 : void *hTransformArg;
1134 : bool bUseTPS;
1135 : OGRSpatialReference *poSRS;
1136 :
1137 7 : GCPCoordTransformation(int nGCPCount, const GDAL_GCP *pasGCPList,
1138 : int nReqOrder, OGRSpatialReference *poSRSIn)
1139 7 : : hTransformArg(nullptr), bUseTPS(nReqOrder < 0), poSRS(poSRSIn)
1140 : {
1141 7 : if (nReqOrder < 0)
1142 : {
1143 1 : hTransformArg =
1144 1 : GDALCreateTPSTransformer(nGCPCount, pasGCPList, FALSE);
1145 : }
1146 : else
1147 : {
1148 6 : hTransformArg = GDALCreateGCPTransformer(nGCPCount, pasGCPList,
1149 : nReqOrder, FALSE);
1150 : }
1151 7 : if (poSRS)
1152 2 : poSRS->Reference();
1153 7 : }
1154 :
1155 0 : OGRCoordinateTransformation *Clone() const override
1156 : {
1157 0 : return new GCPCoordTransformation(*this);
1158 : }
1159 :
1160 7 : bool IsValid() const
1161 : {
1162 7 : return hTransformArg != nullptr;
1163 : }
1164 :
1165 14 : virtual ~GCPCoordTransformation()
1166 7 : {
1167 7 : if (hTransformArg != nullptr)
1168 : {
1169 6 : GDALDestroyTransformer(hTransformArg);
1170 : }
1171 7 : if (poSRS)
1172 2 : poSRS->Dereference();
1173 14 : }
1174 :
1175 11 : virtual const OGRSpatialReference *GetSourceCS() const override
1176 : {
1177 11 : return poSRS;
1178 : }
1179 :
1180 18 : virtual const OGRSpatialReference *GetTargetCS() const override
1181 : {
1182 18 : return poSRS;
1183 : }
1184 :
1185 11 : virtual int Transform(size_t nCount, double *x, double *y, double *z,
1186 : double * /* t */, int *pabSuccess) override
1187 : {
1188 11 : CPLAssert(nCount <=
1189 : static_cast<size_t>(std::numeric_limits<int>::max()));
1190 11 : if (bUseTPS)
1191 2 : return GDALTPSTransform(hTransformArg, FALSE,
1192 : static_cast<int>(nCount), x, y, z,
1193 2 : pabSuccess);
1194 : else
1195 9 : return GDALGCPTransform(hTransformArg, FALSE,
1196 : static_cast<int>(nCount), x, y, z,
1197 9 : pabSuccess);
1198 : }
1199 :
1200 0 : virtual OGRCoordinateTransformation *GetInverse() const override
1201 : {
1202 : static std::once_flag flag;
1203 0 : std::call_once(flag,
1204 0 : []()
1205 : {
1206 0 : CPLDebug("OGR2OGR",
1207 : "GCPCoordTransformation::GetInverse() "
1208 : "called, but not implemented");
1209 0 : });
1210 0 : return nullptr;
1211 : }
1212 : };
1213 :
1214 : /************************************************************************/
1215 : /* CompositeCT */
1216 : /************************************************************************/
1217 :
1218 : class CompositeCT : public OGRCoordinateTransformation
1219 : {
1220 : OGRCoordinateTransformation *const poCT1;
1221 : const bool bOwnCT1;
1222 : OGRCoordinateTransformation *const poCT2;
1223 : const bool bOwnCT2;
1224 :
1225 : // Working buffer
1226 : std::vector<int> m_anErrorCode{};
1227 :
1228 15 : CompositeCT(const CompositeCT &other)
1229 15 : : poCT1(other.poCT1 ? other.poCT1->Clone() : nullptr), bOwnCT1(true),
1230 15 : poCT2(other.poCT2 ? other.poCT2->Clone() : nullptr), bOwnCT2(true),
1231 45 : m_anErrorCode({})
1232 : {
1233 15 : }
1234 :
1235 : CompositeCT &operator=(const CompositeCT &) = delete;
1236 :
1237 : public:
1238 40 : CompositeCT(OGRCoordinateTransformation *poCT1In, bool bOwnCT1In,
1239 : OGRCoordinateTransformation *poCT2In, bool bOwnCT2In)
1240 40 : : poCT1(poCT1In), bOwnCT1(bOwnCT1In), poCT2(poCT2In), bOwnCT2(bOwnCT2In)
1241 : {
1242 40 : }
1243 :
1244 110 : virtual ~CompositeCT()
1245 55 : {
1246 55 : if (bOwnCT1)
1247 15 : delete poCT1;
1248 55 : if (bOwnCT2)
1249 50 : delete poCT2;
1250 110 : }
1251 :
1252 15 : OGRCoordinateTransformation *Clone() const override
1253 : {
1254 15 : return new CompositeCT(*this);
1255 : }
1256 :
1257 112 : virtual const OGRSpatialReference *GetSourceCS() const override
1258 : {
1259 213 : return poCT1 ? poCT1->GetSourceCS()
1260 101 : : poCT2 ? poCT2->GetSourceCS()
1261 112 : : nullptr;
1262 : }
1263 :
1264 344 : virtual const OGRSpatialReference *GetTargetCS() const override
1265 : {
1266 362 : return poCT2 ? poCT2->GetTargetCS()
1267 18 : : poCT1 ? poCT1->GetTargetCS()
1268 344 : : nullptr;
1269 : }
1270 :
1271 10 : virtual bool GetEmitErrors() const override
1272 : {
1273 10 : if (poCT1)
1274 0 : return poCT1->GetEmitErrors();
1275 10 : if (poCT2)
1276 10 : return poCT2->GetEmitErrors();
1277 0 : return true;
1278 : }
1279 :
1280 20 : virtual void SetEmitErrors(bool bEmitErrors) override
1281 : {
1282 20 : if (poCT1)
1283 0 : poCT1->SetEmitErrors(bEmitErrors);
1284 20 : if (poCT2)
1285 20 : poCT2->SetEmitErrors(bEmitErrors);
1286 20 : }
1287 :
1288 306 : virtual int Transform(size_t nCount, double *x, double *y, double *z,
1289 : double *t, int *pabSuccess) override
1290 : {
1291 306 : int nResult = TRUE;
1292 306 : if (poCT1)
1293 11 : nResult = poCT1->Transform(nCount, x, y, z, t, pabSuccess);
1294 306 : if (nResult && poCT2)
1295 297 : nResult = poCT2->Transform(nCount, x, y, z, t, pabSuccess);
1296 306 : return nResult;
1297 : }
1298 :
1299 10246 : virtual int TransformWithErrorCodes(size_t nCount, double *x, double *y,
1300 : double *z, double *t,
1301 : int *panErrorCodes) override
1302 : {
1303 10246 : if (poCT1 && poCT2 && panErrorCodes)
1304 : {
1305 0 : m_anErrorCode.resize(nCount);
1306 0 : int nResult = poCT1->TransformWithErrorCodes(nCount, x, y, z, t,
1307 0 : m_anErrorCode.data());
1308 0 : if (nResult)
1309 0 : nResult = poCT2->TransformWithErrorCodes(nCount, x, y, z, t,
1310 0 : panErrorCodes);
1311 0 : for (size_t i = 0; i < nCount; ++i)
1312 : {
1313 0 : if (m_anErrorCode[i])
1314 0 : panErrorCodes[i] = m_anErrorCode[i];
1315 : }
1316 0 : return nResult;
1317 : }
1318 10246 : int nResult = TRUE;
1319 10246 : if (poCT1)
1320 0 : nResult = poCT1->TransformWithErrorCodes(nCount, x, y, z, t,
1321 0 : panErrorCodes);
1322 10246 : if (nResult && poCT2)
1323 10251 : nResult = poCT2->TransformWithErrorCodes(nCount, x, y, z, t,
1324 10247 : panErrorCodes);
1325 10250 : return nResult;
1326 : }
1327 :
1328 5 : virtual OGRCoordinateTransformation *GetInverse() const override
1329 : {
1330 5 : if (!poCT1 && !poCT2)
1331 0 : return nullptr;
1332 5 : if (!poCT2)
1333 0 : return poCT1->GetInverse();
1334 5 : if (!poCT1)
1335 5 : return poCT2->GetInverse();
1336 : auto poInvCT1 =
1337 0 : std::unique_ptr<OGRCoordinateTransformation>(poCT1->GetInverse());
1338 : auto poInvCT2 =
1339 0 : std::unique_ptr<OGRCoordinateTransformation>(poCT2->GetInverse());
1340 0 : if (!poInvCT1 || !poInvCT2)
1341 0 : return nullptr;
1342 0 : return std::make_unique<CompositeCT>(poInvCT2.release(), true,
1343 0 : poInvCT1.release(), true)
1344 0 : .release();
1345 : }
1346 : };
1347 :
1348 : /************************************************************************/
1349 : /* AxisMappingCoordinateTransformation */
1350 : /************************************************************************/
1351 :
1352 : class AxisMappingCoordinateTransformation : public OGRCoordinateTransformation
1353 : {
1354 : bool bSwapXY = false;
1355 :
1356 0 : explicit AxisMappingCoordinateTransformation(bool bSwapXYIn)
1357 0 : : bSwapXY(bSwapXYIn)
1358 : {
1359 0 : }
1360 :
1361 : public:
1362 0 : AxisMappingCoordinateTransformation(const std::vector<int> &mappingIn,
1363 : const std::vector<int> &mappingOut)
1364 0 : {
1365 0 : if (mappingIn.size() >= 2 && mappingIn[0] == 1 && mappingIn[1] == 2 &&
1366 0 : mappingOut.size() >= 2 && mappingOut[0] == 2 && mappingOut[1] == 1)
1367 : {
1368 0 : bSwapXY = true;
1369 : }
1370 0 : else if (mappingIn.size() >= 2 && mappingIn[0] == 2 &&
1371 0 : mappingIn[1] == 1 && mappingOut.size() >= 2 &&
1372 0 : mappingOut[0] == 1 && mappingOut[1] == 2)
1373 : {
1374 0 : bSwapXY = true;
1375 : }
1376 : else
1377 : {
1378 0 : CPLError(CE_Failure, CPLE_NotSupported,
1379 : "Unsupported axis transformation");
1380 : }
1381 0 : }
1382 :
1383 0 : ~AxisMappingCoordinateTransformation() override
1384 0 : {
1385 0 : }
1386 :
1387 0 : virtual OGRCoordinateTransformation *Clone() const override
1388 : {
1389 0 : return new AxisMappingCoordinateTransformation(*this);
1390 : }
1391 :
1392 0 : virtual const OGRSpatialReference *GetSourceCS() const override
1393 : {
1394 0 : return nullptr;
1395 : }
1396 :
1397 0 : virtual const OGRSpatialReference *GetTargetCS() const override
1398 : {
1399 0 : return nullptr;
1400 : }
1401 :
1402 0 : virtual int Transform(size_t nCount, double *x, double *y, double * /*z*/,
1403 : double * /*t*/, int *pabSuccess) override
1404 : {
1405 0 : for (size_t i = 0; i < nCount; i++)
1406 : {
1407 0 : if (pabSuccess)
1408 0 : pabSuccess[i] = true;
1409 0 : if (bSwapXY)
1410 0 : std::swap(x[i], y[i]);
1411 : }
1412 0 : return true;
1413 : }
1414 :
1415 0 : virtual int TransformWithErrorCodes(size_t nCount, double *x, double *y,
1416 : double * /*z*/, double * /*t*/,
1417 : int *panErrorCodes) override
1418 : {
1419 0 : for (size_t i = 0; i < nCount; i++)
1420 : {
1421 0 : if (panErrorCodes)
1422 0 : panErrorCodes[i] = 0;
1423 0 : if (bSwapXY)
1424 0 : std::swap(x[i], y[i]);
1425 : }
1426 0 : return true;
1427 : }
1428 :
1429 0 : virtual OGRCoordinateTransformation *GetInverse() const override
1430 : {
1431 0 : return new AxisMappingCoordinateTransformation(bSwapXY);
1432 : }
1433 : };
1434 :
1435 : /************************************************************************/
1436 : /* ApplySpatialFilter() */
1437 : /************************************************************************/
1438 :
1439 836 : static void ApplySpatialFilter(OGRLayer *poLayer, OGRGeometry *poSpatialFilter,
1440 : const OGRSpatialReference *poSpatSRS,
1441 : const char *pszGeomField,
1442 : const OGRSpatialReference *poSourceSRS)
1443 : {
1444 836 : if (poSpatialFilter == nullptr)
1445 828 : return;
1446 :
1447 8 : OGRGeometry *poSpatialFilterReprojected = nullptr;
1448 8 : if (poSpatSRS)
1449 : {
1450 4 : poSpatialFilterReprojected = poSpatialFilter->clone();
1451 4 : poSpatialFilterReprojected->assignSpatialReference(poSpatSRS);
1452 : const OGRSpatialReference *poSpatialFilterTargetSRS =
1453 4 : poSourceSRS ? poSourceSRS : poLayer->GetSpatialRef();
1454 4 : if (poSpatialFilterTargetSRS)
1455 : {
1456 : // When transforming the spatial filter from its spat_srs to the
1457 : // layer SRS, make sure to densify it sufficiently to avoid issues
1458 4 : constexpr double SEGMENT_DISTANCE_METRE = 10 * 1000;
1459 4 : if (poSpatSRS->IsGeographic())
1460 : {
1461 : const double LENGTH_OF_ONE_DEGREE =
1462 1 : poSpatSRS->GetSemiMajor(nullptr) * M_PI / 180.0;
1463 1 : poSpatialFilterReprojected->segmentize(SEGMENT_DISTANCE_METRE /
1464 1 : LENGTH_OF_ONE_DEGREE);
1465 : }
1466 3 : else if (poSpatSRS->IsProjected())
1467 : {
1468 3 : poSpatialFilterReprojected->segmentize(
1469 : SEGMENT_DISTANCE_METRE /
1470 3 : poSpatSRS->GetLinearUnits(nullptr));
1471 : }
1472 4 : poSpatialFilterReprojected->transformTo(poSpatialFilterTargetSRS);
1473 : }
1474 : else
1475 0 : CPLError(CE_Warning, CPLE_AppDefined,
1476 : "cannot determine layer SRS for %s.",
1477 0 : poLayer->GetDescription());
1478 : }
1479 :
1480 8 : if (pszGeomField != nullptr)
1481 : {
1482 : const int iGeomField =
1483 1 : poLayer->GetLayerDefn()->GetGeomFieldIndex(pszGeomField);
1484 1 : if (iGeomField >= 0)
1485 1 : poLayer->SetSpatialFilter(iGeomField,
1486 : poSpatialFilterReprojected
1487 : ? poSpatialFilterReprojected
1488 1 : : poSpatialFilter);
1489 : else
1490 0 : CPLError(CE_Warning, CPLE_AppDefined,
1491 : "Cannot find geometry field %s.", pszGeomField);
1492 : }
1493 : else
1494 : {
1495 7 : poLayer->SetSpatialFilter(poSpatialFilterReprojected
1496 : ? poSpatialFilterReprojected
1497 7 : : poSpatialFilter);
1498 : }
1499 :
1500 8 : delete poSpatialFilterReprojected;
1501 : }
1502 :
1503 : /************************************************************************/
1504 : /* GetFieldType() */
1505 : /************************************************************************/
1506 :
1507 12 : static int GetFieldType(const char *pszArg, int *pnSubFieldType)
1508 : {
1509 12 : *pnSubFieldType = OFSTNone;
1510 12 : const char *pszOpenParenthesis = strchr(pszArg, '(');
1511 12 : const int nLengthBeforeParenthesis =
1512 12 : pszOpenParenthesis ? static_cast<int>(pszOpenParenthesis - pszArg)
1513 11 : : static_cast<int>(strlen(pszArg));
1514 72 : for (int iType = 0; iType <= static_cast<int>(OFTMaxType); iType++)
1515 : {
1516 : const char *pszFieldTypeName =
1517 72 : OGRFieldDefn::GetFieldTypeName(static_cast<OGRFieldType>(iType));
1518 72 : if (EQUALN(pszArg, pszFieldTypeName, nLengthBeforeParenthesis) &&
1519 12 : pszFieldTypeName[nLengthBeforeParenthesis] == '\0')
1520 : {
1521 12 : if (pszOpenParenthesis != nullptr)
1522 : {
1523 1 : *pnSubFieldType = -1;
1524 2 : CPLString osArgSubType = pszOpenParenthesis + 1;
1525 1 : if (!osArgSubType.empty() && osArgSubType.back() == ')')
1526 1 : osArgSubType.pop_back();
1527 2 : for (int iSubType = 0;
1528 2 : iSubType <= static_cast<int>(OFSTMaxSubType); iSubType++)
1529 : {
1530 : const char *pszFieldSubTypeName =
1531 2 : OGRFieldDefn::GetFieldSubTypeName(
1532 : static_cast<OGRFieldSubType>(iSubType));
1533 2 : if (EQUAL(pszFieldSubTypeName, osArgSubType))
1534 : {
1535 1 : *pnSubFieldType = iSubType;
1536 1 : break;
1537 : }
1538 : }
1539 : }
1540 12 : return iType;
1541 : }
1542 : }
1543 0 : return -1;
1544 : }
1545 :
1546 : /************************************************************************/
1547 : /* IsFieldType() */
1548 : /************************************************************************/
1549 :
1550 8 : static bool IsFieldType(const char *pszArg)
1551 : {
1552 : int iSubType;
1553 8 : return GetFieldType(pszArg, &iSubType) >= 0 && iSubType >= 0;
1554 : }
1555 :
1556 : class GDALVectorTranslateWrappedDataset : public GDALDataset
1557 : {
1558 : std::unique_ptr<GDALDriver> m_poDriverToFree{};
1559 : GDALDataset *m_poBase = nullptr;
1560 : OGRSpatialReference *m_poOutputSRS = nullptr;
1561 : const bool m_bTransform = false;
1562 :
1563 : std::vector<std::unique_ptr<OGRLayer>> m_apoLayers{};
1564 : std::vector<std::unique_ptr<OGRLayer>> m_apoHiddenLayers{};
1565 :
1566 : GDALVectorTranslateWrappedDataset(GDALDataset *poBase,
1567 : OGRSpatialReference *poOutputSRS,
1568 : bool bTransform);
1569 :
1570 : CPL_DISALLOW_COPY_ASSIGN(GDALVectorTranslateWrappedDataset)
1571 :
1572 : public:
1573 3 : virtual int GetLayerCount() override
1574 : {
1575 3 : return static_cast<int>(m_apoLayers.size());
1576 : }
1577 :
1578 : virtual OGRLayer *GetLayer(int nIdx) override;
1579 : virtual OGRLayer *GetLayerByName(const char *pszName) override;
1580 :
1581 : virtual OGRLayer *ExecuteSQL(const char *pszStatement,
1582 : OGRGeometry *poSpatialFilter,
1583 : const char *pszDialect) override;
1584 : virtual void ReleaseResultSet(OGRLayer *poResultsSet) override;
1585 :
1586 : static std::unique_ptr<GDALVectorTranslateWrappedDataset>
1587 : New(GDALDataset *poBase, OGRSpatialReference *poOutputSRS, bool bTransform);
1588 : };
1589 :
1590 : class GDALVectorTranslateWrappedLayer : public OGRLayerDecorator
1591 : {
1592 : std::vector<std::unique_ptr<OGRCoordinateTransformation>> m_apoCT{};
1593 : OGRFeatureDefn *m_poFDefn = nullptr;
1594 :
1595 : GDALVectorTranslateWrappedLayer(OGRLayer *poBaseLayer, bool bOwnBaseLayer);
1596 : std::unique_ptr<OGRFeature>
1597 : TranslateFeature(std::unique_ptr<OGRFeature> poSrcFeat);
1598 :
1599 : CPL_DISALLOW_COPY_ASSIGN(GDALVectorTranslateWrappedLayer)
1600 :
1601 : public:
1602 : virtual ~GDALVectorTranslateWrappedLayer();
1603 :
1604 379 : virtual OGRFeatureDefn *GetLayerDefn() override
1605 : {
1606 379 : return m_poFDefn;
1607 : }
1608 :
1609 : virtual OGRFeature *GetNextFeature() override;
1610 : virtual OGRFeature *GetFeature(GIntBig nFID) override;
1611 :
1612 : static std::unique_ptr<GDALVectorTranslateWrappedLayer>
1613 : New(OGRLayer *poBaseLayer, bool bOwnBaseLayer,
1614 : OGRSpatialReference *poOutputSRS, bool bTransform);
1615 : };
1616 :
1617 89 : GDALVectorTranslateWrappedLayer::GDALVectorTranslateWrappedLayer(
1618 89 : OGRLayer *poBaseLayer, bool bOwnBaseLayer)
1619 : : OGRLayerDecorator(poBaseLayer, bOwnBaseLayer),
1620 89 : m_apoCT(poBaseLayer->GetLayerDefn()->GetGeomFieldCount())
1621 : {
1622 89 : }
1623 :
1624 : std::unique_ptr<GDALVectorTranslateWrappedLayer>
1625 89 : GDALVectorTranslateWrappedLayer::New(OGRLayer *poBaseLayer, bool bOwnBaseLayer,
1626 : OGRSpatialReference *poOutputSRS,
1627 : bool bTransform)
1628 : {
1629 : auto poNew = std::unique_ptr<GDALVectorTranslateWrappedLayer>(
1630 178 : new GDALVectorTranslateWrappedLayer(poBaseLayer, bOwnBaseLayer));
1631 89 : poNew->m_poFDefn = poBaseLayer->GetLayerDefn()->Clone();
1632 89 : poNew->m_poFDefn->Reference();
1633 89 : if (!poOutputSRS)
1634 0 : return poNew;
1635 :
1636 104 : for (int i = 0; i < poNew->m_poFDefn->GetGeomFieldCount(); i++)
1637 : {
1638 15 : if (bTransform)
1639 : {
1640 0 : const OGRSpatialReference *poSourceSRS = poBaseLayer->GetLayerDefn()
1641 0 : ->GetGeomFieldDefn(i)
1642 0 : ->GetSpatialRef();
1643 0 : if (poSourceSRS == nullptr)
1644 : {
1645 0 : CPLError(CE_Failure, CPLE_AppDefined,
1646 : "Layer %s has no source SRS for geometry field %s",
1647 0 : poBaseLayer->GetName(),
1648 0 : poBaseLayer->GetLayerDefn()
1649 0 : ->GetGeomFieldDefn(i)
1650 : ->GetNameRef());
1651 0 : return nullptr;
1652 : }
1653 : else
1654 : {
1655 0 : poNew->m_apoCT[i] =
1656 0 : std::unique_ptr<OGRCoordinateTransformation>(
1657 : OGRCreateCoordinateTransformation(poSourceSRS,
1658 0 : poOutputSRS));
1659 0 : if (poNew->m_apoCT[i] == nullptr)
1660 : {
1661 0 : CPLError(CE_Failure, CPLE_AppDefined,
1662 : "Failed to create coordinate transformation "
1663 : "between the\n"
1664 : "following coordinate systems. This may be "
1665 : "because they\n"
1666 : "are not transformable.");
1667 :
1668 0 : char *pszWKT = nullptr;
1669 0 : poSourceSRS->exportToPrettyWkt(&pszWKT, FALSE);
1670 0 : CPLError(CE_Failure, CPLE_AppDefined, "Source:\n%s",
1671 : pszWKT);
1672 0 : CPLFree(pszWKT);
1673 :
1674 0 : poOutputSRS->exportToPrettyWkt(&pszWKT, FALSE);
1675 0 : CPLError(CE_Failure, CPLE_AppDefined, "Target:\n%s",
1676 : pszWKT);
1677 0 : CPLFree(pszWKT);
1678 :
1679 0 : return nullptr;
1680 : }
1681 : }
1682 : }
1683 15 : poNew->m_poFDefn->GetGeomFieldDefn(i)->SetSpatialRef(poOutputSRS);
1684 : }
1685 :
1686 89 : return poNew;
1687 : }
1688 :
1689 178 : GDALVectorTranslateWrappedLayer::~GDALVectorTranslateWrappedLayer()
1690 : {
1691 89 : if (m_poFDefn)
1692 89 : m_poFDefn->Release();
1693 178 : }
1694 :
1695 661 : OGRFeature *GDALVectorTranslateWrappedLayer::GetNextFeature()
1696 : {
1697 1322 : return TranslateFeature(
1698 1322 : std::unique_ptr<OGRFeature>(OGRLayerDecorator::GetNextFeature()))
1699 1322 : .release();
1700 : }
1701 :
1702 0 : OGRFeature *GDALVectorTranslateWrappedLayer::GetFeature(GIntBig nFID)
1703 : {
1704 0 : return TranslateFeature(
1705 0 : std::unique_ptr<OGRFeature>(OGRLayerDecorator::GetFeature(nFID)))
1706 0 : .release();
1707 : }
1708 :
1709 661 : std::unique_ptr<OGRFeature> GDALVectorTranslateWrappedLayer::TranslateFeature(
1710 : std::unique_ptr<OGRFeature> poSrcFeat)
1711 : {
1712 661 : if (poSrcFeat == nullptr)
1713 103 : return nullptr;
1714 1116 : auto poNewFeat = std::make_unique<OGRFeature>(m_poFDefn);
1715 558 : poNewFeat->SetFrom(poSrcFeat.get());
1716 558 : poNewFeat->SetFID(poSrcFeat->GetFID());
1717 573 : for (int i = 0; i < poNewFeat->GetGeomFieldCount(); i++)
1718 : {
1719 15 : OGRGeometry *poGeom = poNewFeat->GetGeomFieldRef(i);
1720 15 : if (poGeom)
1721 : {
1722 13 : if (m_apoCT[i])
1723 0 : poGeom->transform(m_apoCT[i].get());
1724 13 : poGeom->assignSpatialReference(
1725 13 : m_poFDefn->GetGeomFieldDefn(i)->GetSpatialRef());
1726 : }
1727 : }
1728 558 : return poNewFeat;
1729 : }
1730 :
1731 3 : GDALVectorTranslateWrappedDataset::GDALVectorTranslateWrappedDataset(
1732 3 : GDALDataset *poBase, OGRSpatialReference *poOutputSRS, bool bTransform)
1733 3 : : m_poBase(poBase), m_poOutputSRS(poOutputSRS), m_bTransform(bTransform)
1734 : {
1735 3 : SetDescription(poBase->GetDescription());
1736 3 : if (poBase->GetDriver())
1737 : {
1738 3 : poDriver = new GDALDriver();
1739 3 : poDriver->SetDescription(poBase->GetDriver()->GetDescription());
1740 3 : m_poDriverToFree.reset(poDriver);
1741 : }
1742 3 : }
1743 :
1744 : std::unique_ptr<GDALVectorTranslateWrappedDataset>
1745 3 : GDALVectorTranslateWrappedDataset::New(GDALDataset *poBase,
1746 : OGRSpatialReference *poOutputSRS,
1747 : bool bTransform)
1748 : {
1749 : auto poNew = std::unique_ptr<GDALVectorTranslateWrappedDataset>(
1750 6 : new GDALVectorTranslateWrappedDataset(poBase, poOutputSRS, bTransform));
1751 70 : for (int i = 0; i < poBase->GetLayerCount(); i++)
1752 : {
1753 : auto poLayer = GDALVectorTranslateWrappedLayer::New(
1754 67 : poBase->GetLayer(i), /* bOwnBaseLayer = */ false, poOutputSRS,
1755 67 : bTransform);
1756 67 : if (poLayer == nullptr)
1757 : {
1758 0 : return nullptr;
1759 : }
1760 67 : poNew->m_apoLayers.push_back(std::move(poLayer));
1761 : }
1762 3 : return poNew;
1763 : }
1764 :
1765 0 : OGRLayer *GDALVectorTranslateWrappedDataset::GetLayer(int i)
1766 : {
1767 0 : if (i < 0 || i >= static_cast<int>(m_apoLayers.size()))
1768 0 : return nullptr;
1769 0 : return m_apoLayers[i].get();
1770 : }
1771 :
1772 68 : OGRLayer *GDALVectorTranslateWrappedDataset::GetLayerByName(const char *pszName)
1773 : {
1774 1008 : for (const auto &poLayer : m_apoLayers)
1775 : {
1776 1008 : if (strcmp(poLayer->GetName(), pszName) == 0)
1777 68 : return poLayer.get();
1778 : }
1779 0 : for (const auto &poLayer : m_apoHiddenLayers)
1780 : {
1781 0 : if (strcmp(poLayer->GetName(), pszName) == 0)
1782 0 : return poLayer.get();
1783 : }
1784 0 : for (const auto &poLayer : m_apoLayers)
1785 : {
1786 0 : if (EQUAL(poLayer->GetName(), pszName))
1787 0 : return poLayer.get();
1788 : }
1789 0 : for (const auto &poLayer : m_apoHiddenLayers)
1790 : {
1791 0 : if (EQUAL(poLayer->GetName(), pszName))
1792 0 : return poLayer.get();
1793 : }
1794 :
1795 0 : OGRLayer *poLayer = m_poBase->GetLayerByName(pszName);
1796 0 : if (poLayer == nullptr)
1797 0 : return nullptr;
1798 :
1799 : auto poNewLayer = GDALVectorTranslateWrappedLayer::New(
1800 0 : poLayer, /* bOwnBaseLayer = */ false, m_poOutputSRS, m_bTransform);
1801 0 : if (poNewLayer == nullptr)
1802 0 : return nullptr;
1803 :
1804 : // Replicate source dataset behavior: if the fact of calling
1805 : // GetLayerByName() on a initially hidden layer makes it visible through
1806 : // GetLayerCount()/GetLayer(), do the same. Otherwise we are going to
1807 : // maintain it hidden as well.
1808 0 : for (int i = 0; i < m_poBase->GetLayerCount(); i++)
1809 : {
1810 0 : if (m_poBase->GetLayer(i) == poLayer)
1811 : {
1812 0 : m_apoLayers.push_back(std::move(poNewLayer));
1813 0 : return m_apoLayers.back().get();
1814 : }
1815 : }
1816 0 : m_apoHiddenLayers.push_back(std::move(poNewLayer));
1817 0 : return m_apoHiddenLayers.back().get();
1818 : }
1819 :
1820 : OGRLayer *
1821 22 : GDALVectorTranslateWrappedDataset::ExecuteSQL(const char *pszStatement,
1822 : OGRGeometry *poSpatialFilter,
1823 : const char *pszDialect)
1824 : {
1825 : OGRLayer *poLayer =
1826 22 : m_poBase->ExecuteSQL(pszStatement, poSpatialFilter, pszDialect);
1827 22 : if (poLayer == nullptr)
1828 0 : return nullptr;
1829 22 : return GDALVectorTranslateWrappedLayer::New(
1830 22 : poLayer, /* bOwnBaseLayer = */ true, m_poOutputSRS, m_bTransform)
1831 22 : .release();
1832 : }
1833 :
1834 22 : void GDALVectorTranslateWrappedDataset::ReleaseResultSet(OGRLayer *poResultsSet)
1835 : {
1836 22 : delete poResultsSet;
1837 22 : }
1838 :
1839 : /************************************************************************/
1840 : /* OGR2OGRSpatialReferenceHolder */
1841 : /************************************************************************/
1842 :
1843 : class OGR2OGRSpatialReferenceHolder
1844 : {
1845 : OGRSpatialReference *m_poSRS = nullptr;
1846 :
1847 : CPL_DISALLOW_COPY_ASSIGN(OGR2OGRSpatialReferenceHolder)
1848 :
1849 : public:
1850 : OGR2OGRSpatialReferenceHolder() = default;
1851 :
1852 701 : ~OGR2OGRSpatialReferenceHolder()
1853 701 : {
1854 701 : if (m_poSRS)
1855 145 : m_poSRS->Release();
1856 701 : }
1857 :
1858 145 : void assignNoRefIncrease(OGRSpatialReference *poSRS)
1859 : {
1860 145 : CPLAssert(m_poSRS == nullptr);
1861 145 : m_poSRS = poSRS;
1862 145 : }
1863 :
1864 1800 : OGRSpatialReference *get()
1865 : {
1866 1800 : return m_poSRS;
1867 : }
1868 : };
1869 :
1870 : /************************************************************************/
1871 : /* GDALVectorTranslateCreateCopy() */
1872 : /************************************************************************/
1873 :
1874 : static GDALDataset *
1875 22 : GDALVectorTranslateCreateCopy(GDALDriver *poDriver, const char *pszDest,
1876 : GDALDataset *poDS,
1877 : const GDALVectorTranslateOptions *psOptions)
1878 : {
1879 22 : const char *const szErrorMsg = "%s not supported by this output driver";
1880 :
1881 22 : if (psOptions->bSkipFailures)
1882 : {
1883 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-skipfailures");
1884 0 : return nullptr;
1885 : }
1886 22 : if (psOptions->nLayerTransaction >= 0)
1887 : {
1888 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg,
1889 : "-lyr_transaction or -ds_transaction");
1890 0 : return nullptr;
1891 : }
1892 22 : if (psOptions->nFIDToFetch >= 0)
1893 : {
1894 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-fid");
1895 0 : return nullptr;
1896 : }
1897 22 : if (!psOptions->aosLCO.empty())
1898 : {
1899 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-lco");
1900 0 : return nullptr;
1901 : }
1902 22 : if (psOptions->bAddMissingFields)
1903 : {
1904 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-addfields");
1905 0 : return nullptr;
1906 : }
1907 22 : if (!psOptions->osSourceSRSDef.empty())
1908 : {
1909 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-s_srs");
1910 0 : return nullptr;
1911 : }
1912 22 : if (!psOptions->bExactFieldNameMatch)
1913 : {
1914 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg,
1915 : "-relaxedFieldNameMatch");
1916 0 : return nullptr;
1917 : }
1918 22 : if (!psOptions->osNewLayerName.empty())
1919 : {
1920 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-nln");
1921 0 : return nullptr;
1922 : }
1923 22 : if (psOptions->bSelFieldsSet)
1924 : {
1925 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-select");
1926 0 : return nullptr;
1927 : }
1928 22 : if (!psOptions->osSQLStatement.empty())
1929 : {
1930 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-sql");
1931 0 : return nullptr;
1932 : }
1933 22 : if (!psOptions->osDialect.empty())
1934 : {
1935 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-dialect");
1936 0 : return nullptr;
1937 : }
1938 22 : if (psOptions->eGType != GEOMTYPE_UNCHANGED ||
1939 22 : psOptions->eGeomTypeConversion != GTC_DEFAULT)
1940 : {
1941 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-nlt");
1942 0 : return nullptr;
1943 : }
1944 22 : if (!psOptions->aosFieldTypesToString.empty())
1945 : {
1946 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg,
1947 : "-fieldTypeToString");
1948 0 : return nullptr;
1949 : }
1950 22 : if (!psOptions->aosMapFieldType.empty())
1951 : {
1952 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-mapFieldType");
1953 0 : return nullptr;
1954 : }
1955 22 : if (psOptions->bUnsetFieldWidth)
1956 : {
1957 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-unsetFieldWidth");
1958 0 : return nullptr;
1959 : }
1960 22 : if (psOptions->bWrapDateline)
1961 : {
1962 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-wrapdateline");
1963 0 : return nullptr;
1964 : }
1965 22 : if (psOptions->bClipSrc)
1966 : {
1967 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipsrc");
1968 0 : return nullptr;
1969 : }
1970 22 : if (!psOptions->osClipSrcSQL.empty())
1971 : {
1972 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipsrcsql");
1973 0 : return nullptr;
1974 : }
1975 22 : if (!psOptions->osClipSrcLayer.empty())
1976 : {
1977 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipsrclayer");
1978 0 : return nullptr;
1979 : }
1980 22 : if (!psOptions->osClipSrcWhere.empty())
1981 : {
1982 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipsrcwhere");
1983 0 : return nullptr;
1984 : }
1985 22 : if (!psOptions->osClipDstDS.empty() || psOptions->poClipDst)
1986 : {
1987 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipdst");
1988 0 : return nullptr;
1989 : }
1990 22 : if (!psOptions->osClipDstSQL.empty())
1991 : {
1992 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipdstsql");
1993 0 : return nullptr;
1994 : }
1995 22 : if (!psOptions->osClipDstLayer.empty())
1996 : {
1997 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipdstlayer");
1998 0 : return nullptr;
1999 : }
2000 22 : if (!psOptions->osClipDstWhere.empty())
2001 : {
2002 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-clipdstwhere");
2003 0 : return nullptr;
2004 : }
2005 22 : if (psOptions->bSplitListFields)
2006 : {
2007 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-splitlistfields");
2008 0 : return nullptr;
2009 : }
2010 22 : if (psOptions->nMaxSplitListSubFields >= 0)
2011 : {
2012 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-maxsubfields");
2013 0 : return nullptr;
2014 : }
2015 22 : if (psOptions->bExplodeCollections)
2016 : {
2017 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg,
2018 : "-explodecollections");
2019 0 : return nullptr;
2020 : }
2021 22 : if (!psOptions->osZField.empty())
2022 : {
2023 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-zfield");
2024 0 : return nullptr;
2025 : }
2026 22 : if (psOptions->oGCPs.nGCPCount)
2027 : {
2028 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-gcp");
2029 0 : return nullptr;
2030 : }
2031 22 : if (!psOptions->aosFieldMap.empty())
2032 : {
2033 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-fieldmap");
2034 0 : return nullptr;
2035 : }
2036 22 : if (psOptions->bForceNullable)
2037 : {
2038 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-forceNullable");
2039 0 : return nullptr;
2040 : }
2041 22 : if (psOptions->bResolveDomains)
2042 : {
2043 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-forceNullable");
2044 0 : return nullptr;
2045 : }
2046 22 : if (psOptions->bEmptyStrAsNull)
2047 : {
2048 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-emptyStrAsNull");
2049 0 : return nullptr;
2050 : }
2051 22 : if (psOptions->bUnsetDefault)
2052 : {
2053 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-unsetDefault");
2054 0 : return nullptr;
2055 : }
2056 22 : if (psOptions->bUnsetFid)
2057 : {
2058 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-unsetFid");
2059 0 : return nullptr;
2060 : }
2061 22 : if (!psOptions->bCopyMD)
2062 : {
2063 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-nomd");
2064 0 : return nullptr;
2065 : }
2066 22 : if (!psOptions->bNativeData)
2067 : {
2068 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-noNativeData");
2069 0 : return nullptr;
2070 : }
2071 22 : if (psOptions->nLimit >= 0)
2072 : {
2073 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-limit");
2074 0 : return nullptr;
2075 : }
2076 22 : if (!psOptions->aosMetadataOptions.empty())
2077 : {
2078 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-mo");
2079 0 : return nullptr;
2080 : }
2081 :
2082 22 : GDALDataset *poWrkSrcDS = poDS;
2083 22 : std::unique_ptr<GDALDataset> poWrkSrcDSToFree;
2084 22 : OGR2OGRSpatialReferenceHolder oOutputSRSHolder;
2085 :
2086 22 : if (!psOptions->osOutputSRSDef.empty())
2087 : {
2088 3 : oOutputSRSHolder.assignNoRefIncrease(new OGRSpatialReference());
2089 3 : oOutputSRSHolder.get()->SetAxisMappingStrategy(
2090 : OAMS_TRADITIONAL_GIS_ORDER);
2091 3 : if (oOutputSRSHolder.get()->SetFromUserInput(
2092 3 : psOptions->osOutputSRSDef.c_str()) != OGRERR_NONE)
2093 : {
2094 0 : CPLError(CE_Failure, CPLE_AppDefined,
2095 : "Failed to process SRS definition: %s",
2096 : psOptions->osOutputSRSDef.c_str());
2097 0 : return nullptr;
2098 : }
2099 3 : oOutputSRSHolder.get()->SetCoordinateEpoch(
2100 3 : psOptions->dfOutputCoordinateEpoch);
2101 :
2102 6 : poWrkSrcDSToFree = GDALVectorTranslateWrappedDataset::New(
2103 6 : poDS, oOutputSRSHolder.get(), psOptions->bTransform);
2104 3 : if (poWrkSrcDSToFree == nullptr)
2105 0 : return nullptr;
2106 3 : poWrkSrcDS = poWrkSrcDSToFree.get();
2107 : }
2108 :
2109 22 : if (!psOptions->osWHERE.empty())
2110 : {
2111 : // Hack for GMLAS driver
2112 0 : if (EQUAL(poDriver->GetDescription(), "GMLAS"))
2113 : {
2114 0 : if (psOptions->aosLayers.empty())
2115 : {
2116 0 : CPLError(CE_Failure, CPLE_NotSupported,
2117 : "-where not supported by this output driver "
2118 : "without explicit layer name(s)");
2119 0 : return nullptr;
2120 : }
2121 : else
2122 : {
2123 0 : for (const char *pszLayer : psOptions->aosLayers)
2124 : {
2125 0 : OGRLayer *poSrcLayer = poDS->GetLayerByName(pszLayer);
2126 0 : if (poSrcLayer != nullptr)
2127 : {
2128 0 : poSrcLayer->SetAttributeFilter(
2129 0 : psOptions->osWHERE.c_str());
2130 : }
2131 : }
2132 : }
2133 : }
2134 : else
2135 : {
2136 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-where");
2137 0 : return nullptr;
2138 : }
2139 : }
2140 :
2141 22 : if (psOptions->poSpatialFilter)
2142 : {
2143 0 : for (int i = 0; i < poWrkSrcDS->GetLayerCount(); ++i)
2144 : {
2145 0 : OGRLayer *poSrcLayer = poWrkSrcDS->GetLayer(i);
2146 0 : if (poSrcLayer &&
2147 0 : poSrcLayer->GetLayerDefn()->GetGeomFieldCount() > 0 &&
2148 0 : (psOptions->aosLayers.empty() ||
2149 0 : psOptions->aosLayers.FindString(poSrcLayer->GetName()) >= 0))
2150 : {
2151 0 : if (psOptions->bGeomFieldSet)
2152 : {
2153 : const int iGeomField =
2154 0 : poSrcLayer->GetLayerDefn()->GetGeomFieldIndex(
2155 0 : psOptions->osGeomField.c_str());
2156 0 : if (iGeomField >= 0)
2157 0 : poSrcLayer->SetSpatialFilter(
2158 0 : iGeomField, psOptions->poSpatialFilter.get());
2159 : else
2160 0 : CPLError(CE_Warning, CPLE_AppDefined,
2161 : "Cannot find geometry field %s in layer %s. "
2162 : "Applying to first geometry field",
2163 : psOptions->osGeomField.c_str(),
2164 0 : poSrcLayer->GetName());
2165 : }
2166 : else
2167 : {
2168 0 : poSrcLayer->SetSpatialFilter(
2169 0 : psOptions->poSpatialFilter.get());
2170 : }
2171 : }
2172 : }
2173 : }
2174 :
2175 44 : CPLStringList aosDSCO(psOptions->aosDSCO);
2176 22 : if (!psOptions->aosLayers.empty())
2177 : {
2178 : // Hack for GMLAS driver
2179 0 : if (EQUAL(poDriver->GetDescription(), "GMLAS"))
2180 : {
2181 0 : CPLString osLayers;
2182 0 : for (const char *pszLayer : psOptions->aosLayers)
2183 : {
2184 0 : if (!osLayers.empty())
2185 0 : osLayers += ",";
2186 0 : osLayers += pszLayer;
2187 : }
2188 0 : aosDSCO.SetNameValue("LAYERS", osLayers);
2189 : }
2190 : else
2191 : {
2192 0 : CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg,
2193 : "Specifying layers");
2194 0 : return nullptr;
2195 : }
2196 : }
2197 :
2198 : // Hack for GMLAS driver (this speed up deletion by avoiding the GML
2199 : // driver to try parsing a pre-existing file). Could be potentially
2200 : // removed if the GML driver implemented fast dataset opening (ie
2201 : // without parsing) and GetFileList()
2202 22 : if (EQUAL(poDriver->GetDescription(), "GMLAS"))
2203 : {
2204 22 : GDALDriverH hIdentifyingDriver = GDALIdentifyDriver(pszDest, nullptr);
2205 23 : if (hIdentifyingDriver != nullptr &&
2206 1 : EQUAL(GDALGetDescription(hIdentifyingDriver), "GML"))
2207 : {
2208 0 : VSIUnlink(pszDest);
2209 0 : VSIUnlink(CPLResetExtension(pszDest, "gfs"));
2210 : }
2211 : }
2212 :
2213 : GDALDataset *poOut =
2214 22 : poDriver->CreateCopy(pszDest, poWrkSrcDS, FALSE, aosDSCO.List(),
2215 22 : psOptions->pfnProgress, psOptions->pProgressData);
2216 :
2217 22 : return poOut;
2218 : }
2219 :
2220 : /************************************************************************/
2221 : /* GDALVectorTranslate() */
2222 : /************************************************************************/
2223 : /**
2224 : * Converts vector data between file formats.
2225 : *
2226 : * This is the equivalent of the <a href="/programs/ogr2ogr.html">ogr2ogr</a>
2227 : * utility.
2228 : *
2229 : * GDALVectorTranslateOptions* must be allocated and freed with
2230 : * GDALVectorTranslateOptionsNew() and GDALVectorTranslateOptionsFree()
2231 : * respectively. pszDest and hDstDS cannot be used at the same time.
2232 : *
2233 : * @param pszDest the destination dataset path or NULL.
2234 : * @param hDstDS the destination dataset or NULL.
2235 : * @param nSrcCount the number of input datasets (only 1 supported currently)
2236 : * @param pahSrcDS the list of input datasets.
2237 : * @param psOptionsIn the options struct returned by
2238 : * GDALVectorTranslateOptionsNew() or NULL.
2239 : * @param pbUsageError pointer to a integer output variable to store if any
2240 : * usage error has occurred, or NULL.
2241 : * @return the output dataset (new dataset that must be closed using
2242 : * GDALClose(), or hDstDS is not NULL) or NULL in case of error.
2243 : *
2244 : * @since GDAL 2.1
2245 : */
2246 :
2247 717 : GDALDatasetH GDALVectorTranslate(const char *pszDest, GDALDatasetH hDstDS,
2248 : int nSrcCount, GDALDatasetH *pahSrcDS,
2249 : const GDALVectorTranslateOptions *psOptionsIn,
2250 : int *pbUsageError)
2251 :
2252 : {
2253 717 : if (pszDest == nullptr && hDstDS == nullptr)
2254 : {
2255 0 : CPLError(CE_Failure, CPLE_AppDefined,
2256 : "pszDest == NULL && hDstDS == NULL");
2257 :
2258 0 : if (pbUsageError)
2259 0 : *pbUsageError = TRUE;
2260 0 : return nullptr;
2261 : }
2262 717 : if (nSrcCount != 1)
2263 : {
2264 0 : CPLError(CE_Failure, CPLE_AppDefined, "nSrcCount != 1");
2265 :
2266 0 : if (pbUsageError)
2267 0 : *pbUsageError = TRUE;
2268 0 : return nullptr;
2269 : }
2270 :
2271 717 : GDALDatasetH hSrcDS = pahSrcDS[0];
2272 717 : if (hSrcDS == nullptr)
2273 : {
2274 0 : CPLError(CE_Failure, CPLE_AppDefined, "hSrcDS == NULL");
2275 :
2276 0 : if (pbUsageError)
2277 0 : *pbUsageError = TRUE;
2278 0 : return nullptr;
2279 : }
2280 :
2281 : auto psOptions =
2282 : psOptionsIn ? std::make_unique<GDALVectorTranslateOptions>(*psOptionsIn)
2283 1434 : : std::make_unique<GDALVectorTranslateOptions>();
2284 :
2285 717 : bool bAppend = false;
2286 717 : bool bUpdate = false;
2287 717 : bool bOverwrite = false;
2288 :
2289 717 : if (psOptions->eAccessMode == ACCESS_UPDATE)
2290 : {
2291 5 : bUpdate = true;
2292 : }
2293 712 : else if (psOptions->eAccessMode == ACCESS_APPEND)
2294 : {
2295 33 : bAppend = true;
2296 33 : bUpdate = true;
2297 : }
2298 679 : else if (psOptions->eAccessMode == ACCESS_OVERWRITE)
2299 : {
2300 12 : bOverwrite = true;
2301 12 : bUpdate = true;
2302 : }
2303 667 : else if (hDstDS != nullptr)
2304 : {
2305 5 : bUpdate = true;
2306 : }
2307 :
2308 : const CPLString osDateLineOffset =
2309 1434 : CPLOPrintf("%g", psOptions->dfDateLineOffset);
2310 :
2311 717 : if (psOptions->bPreserveFID && psOptions->bExplodeCollections)
2312 : {
2313 1 : CPLError(CE_Failure, CPLE_IllegalArg,
2314 : "cannot use -preserve_fid and -explodecollections at the same "
2315 : "time.");
2316 1 : if (pbUsageError)
2317 1 : *pbUsageError = TRUE;
2318 1 : return nullptr;
2319 : }
2320 :
2321 716 : if (!psOptions->aosFieldMap.empty() && !bAppend)
2322 : {
2323 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2324 : "if -fieldmap is specified, -append must also be specified");
2325 0 : if (pbUsageError)
2326 0 : *pbUsageError = TRUE;
2327 0 : return nullptr;
2328 : }
2329 :
2330 716 : if (!psOptions->aosFieldMap.empty() && psOptions->bAddMissingFields)
2331 : {
2332 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2333 : "if -addfields is specified, -fieldmap cannot be used.");
2334 0 : if (pbUsageError)
2335 0 : *pbUsageError = TRUE;
2336 0 : return nullptr;
2337 : }
2338 :
2339 716 : if (psOptions->bSelFieldsSet && bAppend && !psOptions->bAddMissingFields)
2340 : {
2341 1 : CPLError(CE_Failure, CPLE_IllegalArg,
2342 : "if -append is specified, -select cannot be used "
2343 : "(use -fieldmap or -sql instead).");
2344 1 : if (pbUsageError)
2345 1 : *pbUsageError = TRUE;
2346 1 : return nullptr;
2347 : }
2348 :
2349 715 : if (!psOptions->aosFieldTypesToString.empty() &&
2350 0 : !psOptions->aosMapFieldType.empty())
2351 : {
2352 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2353 : "-fieldTypeToString and -mapFieldType are exclusive.");
2354 0 : if (pbUsageError)
2355 0 : *pbUsageError = TRUE;
2356 0 : return nullptr;
2357 : }
2358 :
2359 723 : if (!psOptions->osSourceSRSDef.empty() &&
2360 723 : psOptions->osOutputSRSDef.empty() && psOptions->osSpatSRSDef.empty())
2361 : {
2362 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2363 : "if -s_srs is specified, -t_srs and/or -spat_srs must also be "
2364 : "specified.");
2365 0 : if (pbUsageError)
2366 0 : *pbUsageError = TRUE;
2367 0 : return nullptr;
2368 : }
2369 :
2370 : /* -------------------------------------------------------------------- */
2371 : /* Parse spatial filter SRS if needed. */
2372 : /* -------------------------------------------------------------------- */
2373 715 : std::unique_ptr<OGRSpatialReference, OGRSpatialReferenceReleaser> poSpatSRS;
2374 715 : if (psOptions->poSpatialFilter && !psOptions->osSpatSRSDef.empty())
2375 : {
2376 4 : if (!psOptions->osSQLStatement.empty())
2377 : {
2378 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2379 : "-spat_srs not compatible with -sql.");
2380 0 : return nullptr;
2381 : }
2382 4 : OGREnvelope sEnvelope;
2383 4 : psOptions->poSpatialFilter->getEnvelope(&sEnvelope);
2384 4 : poSpatSRS.reset(new OGRSpatialReference());
2385 4 : poSpatSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2386 4 : if (poSpatSRS->SetFromUserInput(psOptions->osSpatSRSDef.c_str()) !=
2387 : OGRERR_NONE)
2388 : {
2389 0 : CPLError(CE_Failure, CPLE_AppDefined,
2390 : "Failed to process SRS definition: %s",
2391 0 : psOptions->osSpatSRSDef.c_str());
2392 0 : return nullptr;
2393 : }
2394 : }
2395 :
2396 715 : if (!psOptions->poClipSrc && !psOptions->osClipSrcDS.empty())
2397 : {
2398 9 : psOptions->poClipSrc =
2399 18 : LoadGeometry(psOptions->osClipSrcDS, psOptions->osClipSrcSQL,
2400 9 : psOptions->osClipSrcLayer, psOptions->osClipSrcWhere,
2401 18 : psOptions->bMakeValid);
2402 9 : if (psOptions->poClipSrc == nullptr)
2403 : {
2404 2 : CPLError(CE_Failure, CPLE_IllegalArg,
2405 : "cannot load source clip geometry");
2406 2 : return nullptr;
2407 : }
2408 : }
2409 707 : else if (psOptions->bClipSrc && !psOptions->poClipSrc &&
2410 1 : psOptions->poSpatialFilter)
2411 : {
2412 1 : psOptions->poClipSrc.reset(psOptions->poSpatialFilter->clone());
2413 1 : if (poSpatSRS)
2414 : {
2415 0 : psOptions->poClipSrc->assignSpatialReference(poSpatSRS.get());
2416 : }
2417 : }
2418 705 : else if (psOptions->bClipSrc && !psOptions->poClipSrc)
2419 : {
2420 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2421 : "-clipsrc must be used with -spat option or a\n"
2422 : "bounding box, WKT string or datasource must be specified");
2423 0 : if (pbUsageError)
2424 0 : *pbUsageError = TRUE;
2425 0 : return nullptr;
2426 : }
2427 713 : if (psOptions->poClipSrc && !psOptions->poClipSrc->IsValid())
2428 : {
2429 2 : if (!psOptions->bMakeValid)
2430 : {
2431 1 : CPLError(CE_Failure, CPLE_IllegalArg,
2432 : "-clipsrc geometry is invalid. You can try to make it "
2433 : "valid with -makevalid, but the results of the operation "
2434 : "should be manually inspected.");
2435 1 : return nullptr;
2436 : }
2437 : auto poValid =
2438 1 : std::unique_ptr<OGRGeometry>(psOptions->poClipSrc->MakeValid());
2439 1 : if (!poValid)
2440 : {
2441 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2442 : "-clipsrc geometry is invalid and cannot be made valid.");
2443 0 : return nullptr;
2444 : }
2445 1 : CPLError(CE_Warning, CPLE_AppDefined,
2446 : "-clipsrc geometry was invalid and has been made valid, "
2447 : "but the results of the operation "
2448 : "should be manually inspected.");
2449 1 : psOptions->poClipSrc = std::move(poValid);
2450 : }
2451 :
2452 712 : if (!psOptions->osClipDstDS.empty())
2453 : {
2454 9 : psOptions->poClipDst =
2455 18 : LoadGeometry(psOptions->osClipDstDS, psOptions->osClipDstSQL,
2456 9 : psOptions->osClipDstLayer, psOptions->osClipDstWhere,
2457 18 : psOptions->bMakeValid);
2458 9 : if (psOptions->poClipDst == nullptr)
2459 : {
2460 3 : CPLError(CE_Failure, CPLE_IllegalArg,
2461 : "cannot load dest clip geometry");
2462 3 : return nullptr;
2463 : }
2464 : }
2465 709 : if (psOptions->poClipDst && !psOptions->poClipDst->IsValid())
2466 : {
2467 2 : if (!psOptions->bMakeValid)
2468 : {
2469 1 : CPLError(CE_Failure, CPLE_IllegalArg,
2470 : "-clipdst geometry is invalid. You can try to make it "
2471 : "valid with -makevalid, but the results of the operation "
2472 : "should be manually inspected.");
2473 1 : return nullptr;
2474 : }
2475 : auto poValid =
2476 1 : std::unique_ptr<OGRGeometry>(psOptions->poClipDst->MakeValid());
2477 1 : if (!poValid)
2478 : {
2479 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2480 : "-clipdst geometry is invalid and cannot be made valid.");
2481 0 : return nullptr;
2482 : }
2483 1 : CPLError(CE_Warning, CPLE_AppDefined,
2484 : "-clipdst geometry was invalid and has been made valid, "
2485 : "but the results of the operation "
2486 : "should be manually inspected.");
2487 1 : psOptions->poClipDst = std::move(poValid);
2488 : }
2489 :
2490 708 : GDALDataset *poDS = GDALDataset::FromHandle(hSrcDS);
2491 708 : GDALDataset *poODS = nullptr;
2492 708 : GDALDriver *poDriver = nullptr;
2493 1416 : CPLString osDestFilename;
2494 :
2495 708 : if (hDstDS)
2496 : {
2497 13 : poODS = GDALDataset::FromHandle(hDstDS);
2498 13 : osDestFilename = poODS->GetDescription();
2499 : }
2500 : else
2501 : {
2502 695 : osDestFilename = pszDest;
2503 : }
2504 :
2505 : /* Various tests to avoid overwriting the source layer(s) */
2506 : /* or to avoid appending a layer to itself */
2507 54 : if (bUpdate && strcmp(osDestFilename, poDS->GetDescription()) == 0 &&
2508 762 : !EQUAL(poDS->GetDriverName(), "Memory") && (bOverwrite || bAppend))
2509 : {
2510 1 : bool bError = false;
2511 1 : if (psOptions->osNewLayerName.empty())
2512 0 : bError = true;
2513 1 : else if (psOptions->aosLayers.size() == 1)
2514 1 : bError = strcmp(psOptions->osNewLayerName.c_str(),
2515 1 : psOptions->aosLayers[0]) == 0;
2516 0 : else if (psOptions->osSQLStatement.empty())
2517 0 : bError = true;
2518 1 : if (bError)
2519 : {
2520 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2521 : "-nln name must be specified combined with "
2522 : "a single source layer name,\nor a -sql statement, and "
2523 : "name must be different from an existing layer.");
2524 0 : return nullptr;
2525 : }
2526 : }
2527 832 : else if (!bUpdate && strcmp(osDestFilename, poDS->GetDescription()) == 0 &&
2528 63 : (psOptions->osFormat.empty() ||
2529 62 : !EQUAL(psOptions->osFormat.c_str(), "Memory")))
2530 : {
2531 1 : CPLError(CE_Failure, CPLE_AppDefined,
2532 : "Source and destination datasets must be different "
2533 : "in non-update mode.");
2534 1 : return nullptr;
2535 : }
2536 :
2537 : /* -------------------------------------------------------------------- */
2538 : /* Try opening the output datasource as an existing, writable */
2539 : /* -------------------------------------------------------------------- */
2540 1414 : std::vector<std::string> aoDrivers;
2541 707 : if (poODS == nullptr && psOptions->osFormat.empty())
2542 : {
2543 288 : aoDrivers = GetOutputDriversFor(pszDest, GDAL_OF_VECTOR);
2544 288 : if (!bUpdate && aoDrivers.size() == 1)
2545 : {
2546 245 : GDALDriverH hDriver = GDALGetDriverByName(aoDrivers[0].c_str());
2547 245 : const char *pszPrefix = GDALGetMetadataItem(
2548 : hDriver, GDAL_DMD_CONNECTION_PREFIX, nullptr);
2549 245 : if (pszPrefix && STARTS_WITH_CI(pszDest, pszPrefix))
2550 : {
2551 4 : bUpdate = true;
2552 : }
2553 : }
2554 : }
2555 :
2556 707 : if (bUpdate && poODS == nullptr)
2557 : {
2558 45 : poODS = GDALDataset::Open(
2559 : osDestFilename, GDAL_OF_UPDATE | GDAL_OF_VECTOR, nullptr,
2560 45 : psOptions->aosDestOpenOptions.List(), nullptr);
2561 :
2562 45 : if (poODS == nullptr)
2563 : {
2564 1 : if (bOverwrite || bAppend)
2565 : {
2566 1 : poODS = GDALDataset::Open(
2567 : osDestFilename, GDAL_OF_VECTOR, nullptr,
2568 1 : psOptions->aosDestOpenOptions.List(), nullptr);
2569 1 : if (poODS == nullptr)
2570 : {
2571 : /* OK the datasource doesn't exist at all */
2572 1 : bUpdate = false;
2573 : }
2574 : else
2575 : {
2576 0 : poDriver = poODS->GetDriver();
2577 0 : GDALClose(poODS);
2578 0 : poODS = nullptr;
2579 : }
2580 : }
2581 :
2582 1 : if (bUpdate)
2583 : {
2584 0 : CPLError(CE_Failure, CPLE_AppDefined,
2585 : "Unable to open existing output datasource `%s'.",
2586 : osDestFilename.c_str());
2587 0 : return nullptr;
2588 : }
2589 : }
2590 44 : else if (psOptions->aosDSCO.size() > 0)
2591 : {
2592 0 : CPLError(CE_Warning, CPLE_AppDefined,
2593 : "Datasource creation options ignored since an existing "
2594 : "datasource\n"
2595 : " being updated.");
2596 : }
2597 : }
2598 :
2599 707 : if (poODS)
2600 57 : poDriver = poODS->GetDriver();
2601 :
2602 : /* -------------------------------------------------------------------- */
2603 : /* Find the output driver. */
2604 : /* -------------------------------------------------------------------- */
2605 707 : bool bNewDataSource = false;
2606 707 : if (!bUpdate)
2607 : {
2608 650 : GDALDriverManager *poDM = GetGDALDriverManager();
2609 :
2610 650 : if (psOptions->osFormat.empty())
2611 : {
2612 254 : if (aoDrivers.empty())
2613 : {
2614 11 : if (EQUAL(CPLGetExtension(pszDest), ""))
2615 : {
2616 10 : psOptions->osFormat = "ESRI Shapefile";
2617 : }
2618 : else
2619 : {
2620 1 : CPLError(CE_Failure, CPLE_AppDefined,
2621 : "Cannot guess driver for %s", pszDest);
2622 28 : return nullptr;
2623 : }
2624 : }
2625 : else
2626 : {
2627 243 : if (aoDrivers.size() > 1)
2628 : {
2629 1 : CPLError(CE_Warning, CPLE_AppDefined,
2630 : "Several drivers matching %s extension. Using %s",
2631 1 : CPLGetExtension(pszDest), aoDrivers[0].c_str());
2632 : }
2633 243 : psOptions->osFormat = aoDrivers[0];
2634 : }
2635 253 : CPLDebug("GDAL", "Using %s driver", psOptions->osFormat.c_str());
2636 : }
2637 :
2638 649 : CPLString osOGRCompatFormat(psOptions->osFormat);
2639 : // Special processing for non-unified drivers that have the same name
2640 : // as GDAL and OGR drivers. GMT should become OGR_GMT.
2641 : // Other candidates could be VRT, SDTS and PDS, but they don't
2642 : // have write capabilities. But do the substitution to get a sensible
2643 : // error message
2644 649 : if (EQUAL(osOGRCompatFormat, "GMT") ||
2645 648 : EQUAL(osOGRCompatFormat, "VRT") ||
2646 1297 : EQUAL(osOGRCompatFormat, "SDTS") || EQUAL(osOGRCompatFormat, "PDS"))
2647 : {
2648 1 : osOGRCompatFormat = "OGR_" + osOGRCompatFormat;
2649 : }
2650 649 : poDriver = poDM->GetDriverByName(osOGRCompatFormat);
2651 649 : if (poDriver == nullptr)
2652 : {
2653 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unable to find driver `%s'.",
2654 0 : psOptions->osFormat.c_str());
2655 0 : return nullptr;
2656 : }
2657 :
2658 649 : char **papszDriverMD = poDriver->GetMetadata();
2659 649 : if (!CPLTestBool(
2660 : CSLFetchNameValueDef(papszDriverMD, GDAL_DCAP_VECTOR, "FALSE")))
2661 : {
2662 0 : CPLError(CE_Failure, CPLE_AppDefined,
2663 : "%s driver has no vector capabilities.",
2664 0 : psOptions->osFormat.c_str());
2665 0 : return nullptr;
2666 : }
2667 :
2668 649 : if (poDriver->CanVectorTranslateFrom(
2669 649 : pszDest, poDS, psOptions->aosArguments.List(), nullptr))
2670 : {
2671 2 : return poDriver->VectorTranslateFrom(
2672 2 : pszDest, poDS, psOptions->aosArguments.List(),
2673 4 : psOptions->pfnProgress, psOptions->pProgressData);
2674 : }
2675 :
2676 647 : if (!CPLTestBool(
2677 : CSLFetchNameValueDef(papszDriverMD, GDAL_DCAP_CREATE, "FALSE")))
2678 : {
2679 22 : if (CPLTestBool(CSLFetchNameValueDef(
2680 : papszDriverMD, GDAL_DCAP_CREATECOPY, "FALSE")))
2681 : {
2682 22 : poODS = GDALVectorTranslateCreateCopy(poDriver, pszDest, poDS,
2683 22 : psOptions.get());
2684 22 : return poODS;
2685 : }
2686 :
2687 0 : CPLError(CE_Failure, CPLE_AppDefined,
2688 : "%s driver does not support data source creation.",
2689 0 : psOptions->osFormat.c_str());
2690 0 : return nullptr;
2691 : }
2692 :
2693 625 : if (!psOptions->aosDestOpenOptions.empty())
2694 : {
2695 0 : CPLError(CE_Warning, CPLE_AppDefined,
2696 : "-doo ignored when creating the output datasource.");
2697 : }
2698 :
2699 : /* --------------------------------------------------------------------
2700 : */
2701 : /* Special case to improve user experience when translating */
2702 : /* a datasource with multiple layers into a shapefile. If the */
2703 : /* user gives a target datasource with .shp and it does not exist,
2704 : */
2705 : /* the shapefile driver will try to create a file, but this is not
2706 : */
2707 : /* appropriate because here we have several layers, so create */
2708 : /* a directory instead. */
2709 : /* --------------------------------------------------------------------
2710 : */
2711 : VSIStatBufL sStat;
2712 696 : if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
2713 71 : psOptions->osSQLStatement.empty() &&
2714 68 : (psOptions->aosLayers.size() > 1 ||
2715 71 : (psOptions->aosLayers.empty() && poDS->GetLayerCount() > 1)) &&
2716 6 : psOptions->osNewLayerName.empty() &&
2717 697 : EQUAL(CPLGetExtension(osDestFilename), "SHP") &&
2718 1 : VSIStatL(osDestFilename, &sStat) != 0)
2719 : {
2720 1 : if (VSIMkdir(osDestFilename, 0755) != 0)
2721 : {
2722 0 : CPLError(CE_Failure, CPLE_AppDefined,
2723 : "Failed to create directory %s\n"
2724 : "for shapefile datastore.",
2725 : osDestFilename.c_str());
2726 0 : return nullptr;
2727 : }
2728 : }
2729 :
2730 625 : CPLStringList aosDSCO(psOptions->aosDSCO);
2731 :
2732 625 : if (!aosDSCO.FetchNameValue("SINGLE_LAYER"))
2733 : {
2734 : // Informs the target driver (e.g. JSONFG) if a single layer
2735 : // will be created
2736 : const char *pszCOList =
2737 625 : poDriver->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
2738 626 : if (pszCOList && strstr(pszCOList, "SINGLE_LAYER") &&
2739 1 : (!psOptions->osSQLStatement.empty() ||
2740 1 : psOptions->aosLayers.size() == 1 ||
2741 1 : (psOptions->aosLayers.empty() && poDS->GetLayerCount() == 1)))
2742 : {
2743 1 : aosDSCO.SetNameValue("SINGLE_LAYER", "YES");
2744 : }
2745 : }
2746 :
2747 : /* --------------------------------------------------------------------
2748 : */
2749 : /* Create the output data source. */
2750 : /* --------------------------------------------------------------------
2751 : */
2752 625 : poODS = poDriver->Create(osDestFilename, 0, 0, 0, GDT_Unknown,
2753 625 : aosDSCO.List());
2754 625 : if (poODS == nullptr)
2755 : {
2756 6 : CPLError(CE_Failure, CPLE_AppDefined,
2757 : "%s driver failed to create %s",
2758 3 : psOptions->osFormat.c_str(), osDestFilename.c_str());
2759 3 : return nullptr;
2760 : }
2761 622 : bNewDataSource = true;
2762 :
2763 622 : if (psOptions->bCopyMD)
2764 : {
2765 1236 : const CPLStringList aosDomains(poDS->GetMetadataDomainList());
2766 648 : for (const char *pszMD : aosDomains)
2767 : {
2768 30 : if (char **papszMD = poDS->GetMetadata(pszMD))
2769 7 : poODS->SetMetadata(papszMD, pszMD);
2770 : }
2771 : }
2772 2 : for (const auto &[pszKey, pszValue] :
2773 624 : cpl::IterateNameValue(psOptions->aosMetadataOptions))
2774 : {
2775 1 : poODS->SetMetadataItem(pszKey, pszValue);
2776 : }
2777 :
2778 : // When writing to GeoJSON and using -nln, set the @NAME layer
2779 : // creation option to avoid the GeoJSON driver to potentially reuse
2780 : // the source feature collection name if the input is also GeoJSON.
2781 633 : if (!psOptions->osNewLayerName.empty() &&
2782 11 : EQUAL(psOptions->osFormat.c_str(), "GeoJSON"))
2783 : {
2784 1 : psOptions->aosLCO.SetNameValue("@NAME",
2785 1 : psOptions->osNewLayerName.c_str());
2786 : }
2787 : }
2788 :
2789 : // Automatically close poODS on error, if it has been created by this
2790 : // method.
2791 1358 : GDALDatasetUniquePtr poODSUniquePtr(hDstDS == nullptr ? poODS : nullptr);
2792 :
2793 : // Some syntaxic sugar to make "ogr2ogr [-f PostgreSQL] PG:dbname=....
2794 : // source [srclayer] -lco OVERWRITE=YES" work like "ogr2ogr -overwrite
2795 : // PG:dbname=.... source [srclayer]" The former syntax used to work at
2796 : // GDAL 1.1.8 time when it was documented in the PG driver, but was broken
2797 : // starting with GDAL 1.3.2
2798 : // (https://github.com/OSGeo/gdal/commit/29c108a6c9f651dfebae6d1313ba0e707a77c1aa)
2799 : // This could probably be generalized to other drivers that support the
2800 : // OVERWRITE layer creation option, but we'd need to make sure that they
2801 : // just do a DeleteLayer() call. The CARTO driver is an exception regarding
2802 : // that.
2803 697 : if (EQUAL(poODS->GetDriver()->GetDescription(), "PostgreSQL") &&
2804 18 : CPLTestBool(psOptions->aosLCO.FetchNameValueDef("OVERWRITE", "NO")))
2805 : {
2806 0 : if (bAppend)
2807 : {
2808 0 : CPLError(CE_Failure, CPLE_AppDefined,
2809 : "-append and -lco OVERWRITE=YES are mutually exclusive");
2810 0 : return nullptr;
2811 : }
2812 0 : bOverwrite = true;
2813 : }
2814 :
2815 : /* -------------------------------------------------------------------- */
2816 : /* For random reading */
2817 : /* -------------------------------------------------------------------- */
2818 : const bool bRandomLayerReading =
2819 679 : CPL_TO_BOOL(poDS->TestCapability(ODsCRandomLayerRead));
2820 17 : if (bRandomLayerReading && !poODS->TestCapability(ODsCRandomLayerWrite) &&
2821 696 : psOptions->aosLayers.size() != 1 && psOptions->osSQLStatement.empty() &&
2822 0 : !psOptions->bQuiet)
2823 : {
2824 0 : CPLError(CE_Warning, CPLE_AppDefined,
2825 : "Input datasource uses random layer reading, but "
2826 : "output datasource does not support random layer writing");
2827 : }
2828 :
2829 679 : if (psOptions->nLayerTransaction < 0)
2830 : {
2831 678 : if (bRandomLayerReading)
2832 17 : psOptions->nLayerTransaction = FALSE;
2833 : else
2834 661 : psOptions->nLayerTransaction =
2835 661 : !poODS->TestCapability(ODsCTransactions);
2836 : }
2837 1 : else if (psOptions->nLayerTransaction && bRandomLayerReading)
2838 : {
2839 0 : psOptions->nLayerTransaction = false;
2840 : }
2841 :
2842 : /* -------------------------------------------------------------------- */
2843 : /* Parse the output SRS definition if possible. */
2844 : /* -------------------------------------------------------------------- */
2845 679 : OGR2OGRSpatialReferenceHolder oOutputSRSHolder;
2846 679 : if (!psOptions->osOutputSRSDef.empty())
2847 : {
2848 142 : oOutputSRSHolder.assignNoRefIncrease(new OGRSpatialReference());
2849 142 : oOutputSRSHolder.get()->SetAxisMappingStrategy(
2850 : OAMS_TRADITIONAL_GIS_ORDER);
2851 284 : if (oOutputSRSHolder.get()->SetFromUserInput(
2852 284 : psOptions->osOutputSRSDef.c_str()) != OGRERR_NONE)
2853 : {
2854 0 : CPLError(CE_Failure, CPLE_AppDefined,
2855 : "Failed to process SRS definition: %s",
2856 0 : psOptions->osOutputSRSDef.c_str());
2857 0 : return nullptr;
2858 : }
2859 284 : oOutputSRSHolder.get()->SetCoordinateEpoch(
2860 142 : psOptions->dfOutputCoordinateEpoch);
2861 : }
2862 :
2863 : /* -------------------------------------------------------------------- */
2864 : /* Parse the source SRS definition if possible. */
2865 : /* -------------------------------------------------------------------- */
2866 1358 : OGRSpatialReference oSourceSRS;
2867 679 : OGRSpatialReference *poSourceSRS = nullptr;
2868 679 : if (!psOptions->osSourceSRSDef.empty())
2869 : {
2870 8 : oSourceSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2871 8 : if (oSourceSRS.SetFromUserInput(psOptions->osSourceSRSDef.c_str()) !=
2872 : OGRERR_NONE)
2873 : {
2874 0 : CPLError(CE_Failure, CPLE_AppDefined,
2875 : "Failed to process SRS definition: %s",
2876 0 : psOptions->osSourceSRSDef.c_str());
2877 0 : return nullptr;
2878 : }
2879 8 : oSourceSRS.SetCoordinateEpoch(psOptions->dfSourceCoordinateEpoch);
2880 8 : poSourceSRS = &oSourceSRS;
2881 : }
2882 :
2883 : /* -------------------------------------------------------------------- */
2884 : /* Create a transformation object from the source to */
2885 : /* destination coordinate system. */
2886 : /* -------------------------------------------------------------------- */
2887 679 : std::unique_ptr<GCPCoordTransformation> poGCPCoordTrans;
2888 679 : if (psOptions->oGCPs.nGCPCount > 0)
2889 : {
2890 7 : poGCPCoordTrans = std::make_unique<GCPCoordTransformation>(
2891 7 : psOptions->oGCPs.nGCPCount, psOptions->oGCPs.pasGCPs,
2892 7 : psOptions->nTransformOrder,
2893 14 : poSourceSRS ? poSourceSRS : oOutputSRSHolder.get());
2894 7 : if (!(poGCPCoordTrans->IsValid()))
2895 : {
2896 1 : return nullptr;
2897 : }
2898 : }
2899 :
2900 : /* -------------------------------------------------------------------- */
2901 : /* Create layer setup and transformer objects. */
2902 : /* -------------------------------------------------------------------- */
2903 678 : SetupTargetLayer oSetup;
2904 678 : oSetup.m_poSrcDS = poDS;
2905 678 : oSetup.m_poDstDS = poODS;
2906 678 : oSetup.m_papszLCO = psOptions->aosLCO.List();
2907 678 : oSetup.m_poOutputSRS = oOutputSRSHolder.get();
2908 678 : oSetup.m_bTransform = psOptions->bTransform;
2909 678 : oSetup.m_bNullifyOutputSRS = psOptions->bNullifyOutputSRS;
2910 678 : oSetup.m_poUserSourceSRS = poSourceSRS;
2911 678 : oSetup.m_bSelFieldsSet = psOptions->bSelFieldsSet;
2912 678 : oSetup.m_papszSelFields = psOptions->aosSelFields.List();
2913 678 : oSetup.m_bAppend = bAppend;
2914 678 : oSetup.m_bAddMissingFields = psOptions->bAddMissingFields;
2915 678 : oSetup.m_eGType = psOptions->eGType;
2916 678 : oSetup.m_eGeomTypeConversion = psOptions->eGeomTypeConversion;
2917 678 : oSetup.m_nCoordDim = psOptions->nCoordDim;
2918 678 : oSetup.m_bOverwrite = bOverwrite;
2919 678 : oSetup.m_papszFieldTypesToString = psOptions->aosFieldTypesToString.List();
2920 678 : oSetup.m_papszMapFieldType = psOptions->aosMapFieldType.List();
2921 678 : oSetup.m_bUnsetFieldWidth = psOptions->bUnsetFieldWidth;
2922 678 : oSetup.m_bExplodeCollections = psOptions->bExplodeCollections;
2923 678 : oSetup.m_pszZField =
2924 678 : psOptions->osZField.empty() ? nullptr : psOptions->osZField.c_str();
2925 678 : oSetup.m_papszFieldMap = psOptions->aosFieldMap.List();
2926 678 : oSetup.m_pszWHERE =
2927 678 : psOptions->osWHERE.empty() ? nullptr : psOptions->osWHERE.c_str();
2928 678 : oSetup.m_bExactFieldNameMatch = psOptions->bExactFieldNameMatch;
2929 678 : oSetup.m_bQuiet = psOptions->bQuiet;
2930 678 : oSetup.m_bForceNullable = psOptions->bForceNullable;
2931 678 : oSetup.m_bResolveDomains = psOptions->bResolveDomains;
2932 678 : oSetup.m_bUnsetDefault = psOptions->bUnsetDefault;
2933 678 : oSetup.m_bUnsetFid = psOptions->bUnsetFid;
2934 678 : oSetup.m_bPreserveFID = psOptions->bPreserveFID;
2935 678 : oSetup.m_bCopyMD = psOptions->bCopyMD;
2936 678 : oSetup.m_bNativeData = psOptions->bNativeData;
2937 678 : oSetup.m_bNewDataSource = bNewDataSource;
2938 678 : oSetup.m_pszCTPipeline = psOptions->osCTPipeline.empty()
2939 678 : ? nullptr
2940 3 : : psOptions->osCTPipeline.c_str();
2941 :
2942 1356 : LayerTranslator oTranslator;
2943 678 : oTranslator.m_poSrcDS = poDS;
2944 678 : oTranslator.m_poODS = poODS;
2945 678 : oTranslator.m_bTransform = psOptions->bTransform;
2946 678 : oTranslator.m_bWrapDateline = psOptions->bWrapDateline;
2947 678 : oTranslator.m_osDateLineOffset = osDateLineOffset;
2948 678 : oTranslator.m_poOutputSRS = oOutputSRSHolder.get();
2949 678 : oTranslator.m_bNullifyOutputSRS = psOptions->bNullifyOutputSRS;
2950 678 : oTranslator.m_poUserSourceSRS = poSourceSRS;
2951 678 : oTranslator.m_poGCPCoordTrans = poGCPCoordTrans.get();
2952 678 : oTranslator.m_eGType = psOptions->eGType;
2953 678 : oTranslator.m_eGeomTypeConversion = psOptions->eGeomTypeConversion;
2954 678 : oTranslator.m_bMakeValid = psOptions->bMakeValid;
2955 678 : oTranslator.m_bSkipInvalidGeom = psOptions->bSkipInvalidGeom;
2956 678 : oTranslator.m_nCoordDim = psOptions->nCoordDim;
2957 678 : oTranslator.m_eGeomOp = psOptions->eGeomOp;
2958 678 : oTranslator.m_dfGeomOpParam = psOptions->dfGeomOpParam;
2959 : // Do not emit warning if the user specified directly the clip source geom
2960 678 : if (psOptions->osClipSrcDS.empty())
2961 671 : oTranslator.m_bWarnedClipSrcSRS = true;
2962 678 : oTranslator.m_poClipSrcOri = psOptions->poClipSrc.get();
2963 : // Do not emit warning if the user specified directly the clip dest geom
2964 678 : if (psOptions->osClipDstDS.empty())
2965 672 : oTranslator.m_bWarnedClipDstSRS = true;
2966 678 : oTranslator.m_poClipDstOri = psOptions->poClipDst.get();
2967 678 : oTranslator.m_bExplodeCollections = psOptions->bExplodeCollections;
2968 678 : oTranslator.m_bNativeData = psOptions->bNativeData;
2969 678 : oTranslator.m_nLimit = psOptions->nLimit;
2970 :
2971 678 : if (psOptions->nGroupTransactions)
2972 : {
2973 677 : if (!psOptions->nLayerTransaction)
2974 109 : poODS->StartTransaction(psOptions->bForceTransaction);
2975 : }
2976 :
2977 678 : GIntBig nTotalEventsDone = 0;
2978 :
2979 : /* -------------------------------------------------------------------- */
2980 : /* Special case for -sql clause. No source layers required. */
2981 : /* -------------------------------------------------------------------- */
2982 678 : int nRetCode = 0;
2983 :
2984 678 : if (!psOptions->osSQLStatement.empty())
2985 : {
2986 : /* Special case: if output=input, then we must likely destroy the */
2987 : /* old table before to avoid transaction issues. */
2988 11 : if (poDS == poODS && !psOptions->osNewLayerName.empty() && bOverwrite)
2989 0 : GetLayerAndOverwriteIfNecessary(
2990 0 : poODS, psOptions->osNewLayerName.c_str(), bOverwrite, nullptr,
2991 : nullptr, nullptr);
2992 :
2993 11 : if (!psOptions->osWHERE.empty())
2994 0 : CPLError(CE_Warning, CPLE_AppDefined,
2995 : "-where clause ignored in combination with -sql.");
2996 11 : if (psOptions->aosLayers.size() > 0)
2997 0 : CPLError(CE_Warning, CPLE_AppDefined,
2998 : "layer names ignored in combination with -sql.");
2999 :
3000 22 : OGRLayer *poResultSet = poDS->ExecuteSQL(
3001 11 : psOptions->osSQLStatement.c_str(),
3002 11 : (!psOptions->bGeomFieldSet) ? psOptions->poSpatialFilter.get()
3003 : : nullptr,
3004 11 : psOptions->osDialect.empty() ? nullptr
3005 12 : : psOptions->osDialect.c_str());
3006 :
3007 11 : if (poResultSet != nullptr)
3008 : {
3009 11 : if (psOptions->poSpatialFilter && psOptions->bGeomFieldSet)
3010 : {
3011 0 : int iGeomField = poResultSet->GetLayerDefn()->GetGeomFieldIndex(
3012 0 : psOptions->osGeomField.c_str());
3013 0 : if (iGeomField >= 0)
3014 0 : poResultSet->SetSpatialFilter(
3015 0 : iGeomField, psOptions->poSpatialFilter.get());
3016 : else
3017 0 : CPLError(CE_Warning, CPLE_AppDefined,
3018 : "Cannot find geometry field %s.",
3019 0 : psOptions->osGeomField.c_str());
3020 : }
3021 :
3022 11 : GIntBig nCountLayerFeatures = 0;
3023 11 : GDALProgressFunc pfnProgress = nullptr;
3024 11 : void *pProgressArg = nullptr;
3025 11 : if (psOptions->bDisplayProgress)
3026 : {
3027 1 : if (bRandomLayerReading)
3028 : {
3029 1 : pfnProgress = psOptions->pfnProgress;
3030 1 : pProgressArg = psOptions->pProgressData;
3031 : }
3032 0 : else if (!poResultSet->TestCapability(OLCFastFeatureCount))
3033 : {
3034 0 : CPLError(CE_Warning, CPLE_AppDefined,
3035 : "Progress turned off as fast feature count is not "
3036 : "available.");
3037 0 : psOptions->bDisplayProgress = false;
3038 : }
3039 : else
3040 : {
3041 0 : nCountLayerFeatures = poResultSet->GetFeatureCount();
3042 0 : pfnProgress = psOptions->pfnProgress;
3043 0 : pProgressArg = psOptions->pProgressData;
3044 : }
3045 : }
3046 :
3047 11 : OGRLayer *poPassedLayer = poResultSet;
3048 11 : if (psOptions->bSplitListFields)
3049 : {
3050 : auto poLayer = new OGRSplitListFieldLayer(
3051 0 : poPassedLayer, psOptions->nMaxSplitListSubFields);
3052 0 : poPassedLayer = poLayer;
3053 0 : int nRet = poLayer->BuildLayerDefn(nullptr, nullptr);
3054 0 : if (!nRet)
3055 : {
3056 0 : delete poPassedLayer;
3057 0 : poPassedLayer = poResultSet;
3058 : }
3059 : }
3060 :
3061 : /* --------------------------------------------------------------------
3062 : */
3063 : /* Special case to improve user experience when translating
3064 : * into */
3065 : /* single file shapefile and source has only one layer, and
3066 : * that */
3067 : /* the layer name isn't specified */
3068 : /* --------------------------------------------------------------------
3069 : */
3070 : VSIStatBufL sStat;
3071 14 : if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
3072 3 : psOptions->osNewLayerName.empty() &&
3073 3 : VSIStatL(osDestFilename, &sStat) == 0 &&
3074 14 : VSI_ISREG(sStat.st_mode) &&
3075 0 : (EQUAL(CPLGetExtension(osDestFilename), "shp") ||
3076 0 : EQUAL(CPLGetExtension(osDestFilename), "shz") ||
3077 0 : EQUAL(CPLGetExtension(osDestFilename), "dbf")))
3078 : {
3079 0 : psOptions->osNewLayerName = CPLGetBasename(osDestFilename);
3080 : }
3081 :
3082 : auto psInfo = oSetup.Setup(poPassedLayer,
3083 11 : psOptions->osNewLayerName.empty()
3084 : ? nullptr
3085 1 : : psOptions->osNewLayerName.c_str(),
3086 34 : psOptions.get(), nTotalEventsDone);
3087 :
3088 11 : poPassedLayer->ResetReading();
3089 :
3090 22 : if (psInfo == nullptr ||
3091 11 : !oTranslator.Translate(nullptr, psInfo.get(),
3092 : nCountLayerFeatures, nullptr,
3093 : nTotalEventsDone, pfnProgress,
3094 11 : pProgressArg, psOptions.get()))
3095 : {
3096 0 : CPLError(CE_Failure, CPLE_AppDefined,
3097 : "Terminating translation prematurely after failed\n"
3098 : "translation from sql statement.");
3099 :
3100 0 : nRetCode = 1;
3101 : }
3102 :
3103 11 : if (poPassedLayer != poResultSet)
3104 0 : delete poPassedLayer;
3105 :
3106 11 : poDS->ReleaseResultSet(poResultSet);
3107 : }
3108 : else
3109 : {
3110 0 : if (CPLGetLastErrorNo() != 0)
3111 0 : nRetCode = 1;
3112 : }
3113 : }
3114 :
3115 : /* -------------------------------------------------------------------- */
3116 : /* Special case for layer interleaving mode. */
3117 : /* -------------------------------------------------------------------- */
3118 667 : else if (bRandomLayerReading)
3119 : {
3120 16 : if (psOptions->bSplitListFields)
3121 : {
3122 0 : CPLError(CE_Failure, CPLE_AppDefined,
3123 : "-splitlistfields not supported in this mode");
3124 0 : return nullptr;
3125 : }
3126 :
3127 : // Make sure to probe all layers in case some are by default invisible
3128 28 : for (const char *pszLayer : psOptions->aosLayers)
3129 : {
3130 12 : OGRLayer *poLayer = poDS->GetLayerByName(pszLayer);
3131 :
3132 12 : if (poLayer == nullptr)
3133 : {
3134 0 : CPLError(CE_Failure, CPLE_AppDefined,
3135 : "Couldn't fetch requested layer %s!", pszLayer);
3136 0 : return nullptr;
3137 : }
3138 : }
3139 :
3140 16 : const int nSrcLayerCount = poDS->GetLayerCount();
3141 16 : std::vector<AssociatedLayers> pasAssocLayers(nSrcLayerCount);
3142 :
3143 : /* --------------------------------------------------------------------
3144 : */
3145 : /* Special case to improve user experience when translating into */
3146 : /* single file shapefile and source has only one layer, and that */
3147 : /* the layer name isn't specified */
3148 : /* --------------------------------------------------------------------
3149 : */
3150 : VSIStatBufL sStat;
3151 16 : if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
3152 5 : (psOptions->aosLayers.size() == 1 || nSrcLayerCount == 1) &&
3153 0 : psOptions->osNewLayerName.empty() &&
3154 21 : VSIStatL(osDestFilename, &sStat) == 0 && VSI_ISREG(sStat.st_mode) &&
3155 0 : (EQUAL(CPLGetExtension(osDestFilename), "shp") ||
3156 0 : EQUAL(CPLGetExtension(osDestFilename), "shz") ||
3157 0 : EQUAL(CPLGetExtension(osDestFilename), "dbf")))
3158 : {
3159 0 : psOptions->osNewLayerName = CPLGetBasename(osDestFilename);
3160 : }
3161 :
3162 16 : GDALProgressFunc pfnProgress = nullptr;
3163 16 : void *pProgressArg = nullptr;
3164 16 : if (!psOptions->bQuiet)
3165 : {
3166 16 : pfnProgress = psOptions->pfnProgress;
3167 16 : pProgressArg = psOptions->pProgressData;
3168 : }
3169 :
3170 : /* --------------------------------------------------------------------
3171 : */
3172 : /* If no target layer specified, use all source layers. */
3173 : /* --------------------------------------------------------------------
3174 : */
3175 16 : if (psOptions->aosLayers.empty())
3176 : {
3177 148 : for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)
3178 : {
3179 135 : OGRLayer *poLayer = poDS->GetLayer(iLayer);
3180 :
3181 135 : if (poLayer == nullptr)
3182 : {
3183 0 : CPLError(CE_Failure, CPLE_AppDefined,
3184 : "Couldn't fetch advertised layer %d!", iLayer);
3185 0 : return nullptr;
3186 : }
3187 :
3188 135 : psOptions->aosLayers.AddString(poLayer->GetName());
3189 : }
3190 : }
3191 : else
3192 : {
3193 3 : const bool bSrcIsOSM = (strcmp(poDS->GetDriverName(), "OSM") == 0);
3194 3 : if (bSrcIsOSM)
3195 : {
3196 6 : CPLString osInterestLayers = "SET interest_layers =";
3197 15 : for (int iLayer = 0; iLayer < psOptions->aosLayers.size();
3198 : iLayer++)
3199 : {
3200 12 : if (iLayer != 0)
3201 9 : osInterestLayers += ",";
3202 12 : osInterestLayers += psOptions->aosLayers[iLayer];
3203 : }
3204 :
3205 3 : poDS->ExecuteSQL(osInterestLayers.c_str(), nullptr, nullptr);
3206 : }
3207 : }
3208 :
3209 : /* --------------------------------------------------------------------
3210 : */
3211 : /* First pass to set filters. */
3212 : /* --------------------------------------------------------------------
3213 : */
3214 16 : std::map<OGRLayer *, int> oMapLayerToIdx;
3215 :
3216 166 : for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)
3217 : {
3218 150 : OGRLayer *poLayer = poDS->GetLayer(iLayer);
3219 150 : if (poLayer == nullptr)
3220 : {
3221 0 : CPLError(CE_Failure, CPLE_AppDefined,
3222 : "Couldn't fetch advertised layer %d!", iLayer);
3223 0 : return nullptr;
3224 : }
3225 :
3226 150 : pasAssocLayers[iLayer].poSrcLayer = poLayer;
3227 :
3228 150 : if (psOptions->aosLayers.FindString(poLayer->GetName()) >= 0)
3229 : {
3230 147 : if (!psOptions->osWHERE.empty())
3231 : {
3232 0 : if (poLayer->SetAttributeFilter(
3233 0 : psOptions->osWHERE.c_str()) != OGRERR_NONE)
3234 : {
3235 0 : CPLError(CE_Failure, CPLE_AppDefined,
3236 : "SetAttributeFilter(%s) on layer '%s' failed.",
3237 0 : psOptions->osWHERE.c_str(),
3238 0 : poLayer->GetName());
3239 0 : if (!psOptions->bSkipFailures)
3240 : {
3241 0 : return nullptr;
3242 : }
3243 : }
3244 : }
3245 :
3246 294 : ApplySpatialFilter(
3247 147 : poLayer, psOptions->poSpatialFilter.get(), poSpatSRS.get(),
3248 147 : psOptions->bGeomFieldSet ? psOptions->osGeomField.c_str()
3249 : : nullptr,
3250 : poSourceSRS);
3251 :
3252 147 : oMapLayerToIdx[poLayer] = iLayer;
3253 : }
3254 : }
3255 :
3256 : /* --------------------------------------------------------------------
3257 : */
3258 : /* Second pass to process features in a interleaved layer mode. */
3259 : /* --------------------------------------------------------------------
3260 : */
3261 16 : bool bTargetLayersHaveBeenCreated = false;
3262 : while (true)
3263 : {
3264 991 : OGRLayer *poFeatureLayer = nullptr;
3265 : auto poFeature = std::unique_ptr<OGRFeature>(poDS->GetNextFeature(
3266 991 : &poFeatureLayer, nullptr, pfnProgress, pProgressArg));
3267 991 : if (poFeature == nullptr)
3268 16 : break;
3269 : std::map<OGRLayer *, int>::const_iterator oIter =
3270 975 : oMapLayerToIdx.find(poFeatureLayer);
3271 975 : if (oIter == oMapLayerToIdx.end())
3272 : {
3273 : // Feature in a layer that is not a layer of interest.
3274 : // nothing to do
3275 : }
3276 : else
3277 : {
3278 975 : if (!bTargetLayersHaveBeenCreated)
3279 : {
3280 : // We defer target layer creation at the first feature
3281 : // retrieved since getting the layer definition can be
3282 : // costly (case of the GMLAS driver) and thus we'd better
3283 : // taking advantage from the progress callback of
3284 : // GetNextFeature.
3285 15 : bTargetLayersHaveBeenCreated = true;
3286 160 : for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)
3287 : {
3288 145 : OGRLayer *poLayer = poDS->GetLayer(iLayer);
3289 290 : if (psOptions->aosLayers.FindString(
3290 290 : poLayer->GetName()) < 0)
3291 3 : continue;
3292 :
3293 : auto psInfo = oSetup.Setup(
3294 : poLayer,
3295 142 : psOptions->osNewLayerName.empty()
3296 : ? nullptr
3297 0 : : psOptions->osNewLayerName.c_str(),
3298 284 : psOptions.get(), nTotalEventsDone);
3299 :
3300 142 : if (psInfo == nullptr && !psOptions->bSkipFailures)
3301 : {
3302 0 : return nullptr;
3303 : }
3304 :
3305 142 : pasAssocLayers[iLayer].psInfo = std::move(psInfo);
3306 : }
3307 15 : if (nRetCode)
3308 0 : break;
3309 : }
3310 :
3311 975 : int iLayer = oIter->second;
3312 975 : TargetLayerInfo *psInfo = pasAssocLayers[iLayer].psInfo.get();
3313 1949 : if ((psInfo == nullptr ||
3314 974 : !oTranslator.Translate(poFeature.release(), psInfo, 0,
3315 : nullptr, nTotalEventsDone, nullptr,
3316 1950 : nullptr, psOptions.get())) &&
3317 1 : !psOptions->bSkipFailures)
3318 : {
3319 0 : CPLError(
3320 : CE_Failure, CPLE_AppDefined,
3321 : "Terminating translation prematurely after failed\n"
3322 : "translation of layer %s (use -skipfailures to skip "
3323 : "errors)",
3324 0 : poFeatureLayer->GetName());
3325 :
3326 0 : nRetCode = 1;
3327 0 : break;
3328 : }
3329 : }
3330 975 : } // while true
3331 :
3332 16 : if (pfnProgress)
3333 : {
3334 0 : pfnProgress(1.0, "", pProgressArg);
3335 : }
3336 :
3337 16 : if (!bTargetLayersHaveBeenCreated)
3338 : {
3339 : // bTargetLayersHaveBeenCreated not used after here.
3340 : // bTargetLayersHaveBeenCreated = true;
3341 6 : for (int iLayer = 0; iLayer < nSrcLayerCount; iLayer++)
3342 : {
3343 5 : OGRLayer *poLayer = poDS->GetLayer(iLayer);
3344 5 : if (psOptions->aosLayers.FindString(poLayer->GetName()) < 0)
3345 0 : continue;
3346 :
3347 : auto psInfo =
3348 : oSetup.Setup(poLayer,
3349 5 : psOptions->osNewLayerName.empty()
3350 : ? nullptr
3351 0 : : psOptions->osNewLayerName.c_str(),
3352 10 : psOptions.get(), nTotalEventsDone);
3353 :
3354 5 : if (psInfo == nullptr && !psOptions->bSkipFailures)
3355 : {
3356 0 : return nullptr;
3357 : }
3358 :
3359 5 : pasAssocLayers[iLayer].psInfo = std::move(psInfo);
3360 : }
3361 : }
3362 : }
3363 :
3364 : else
3365 : {
3366 651 : std::vector<OGRLayer *> apoLayers;
3367 :
3368 : /* --------------------------------------------------------------------
3369 : */
3370 : /* Process each data source layer. */
3371 : /* --------------------------------------------------------------------
3372 : */
3373 651 : if (psOptions->aosLayers.empty())
3374 : {
3375 642 : const int nLayerCount = poDS->GetLayerCount();
3376 :
3377 1316 : for (int iLayer = 0; iLayer < nLayerCount; iLayer++)
3378 : {
3379 674 : OGRLayer *poLayer = poDS->GetLayer(iLayer);
3380 :
3381 674 : if (poLayer == nullptr)
3382 : {
3383 0 : CPLError(CE_Failure, CPLE_AppDefined,
3384 : "Couldn't fetch advertised layer %d!", iLayer);
3385 0 : return nullptr;
3386 : }
3387 674 : if (!poDS->IsLayerPrivate(iLayer))
3388 : {
3389 674 : apoLayers.push_back(poLayer);
3390 : }
3391 : }
3392 : }
3393 : /* --------------------------------------------------------------------
3394 : */
3395 : /* Process specified data source layers. */
3396 : /* --------------------------------------------------------------------
3397 : */
3398 : else
3399 : {
3400 :
3401 24 : for (int iLayer = 0; psOptions->aosLayers[iLayer] != nullptr;
3402 : iLayer++)
3403 : {
3404 : OGRLayer *poLayer =
3405 15 : poDS->GetLayerByName(psOptions->aosLayers[iLayer]);
3406 :
3407 15 : if (poLayer == nullptr)
3408 : {
3409 0 : CPLError(CE_Failure, CPLE_AppDefined,
3410 : "Couldn't fetch requested layer '%s'!",
3411 0 : psOptions->aosLayers[iLayer]);
3412 0 : if (!psOptions->bSkipFailures)
3413 : {
3414 0 : return nullptr;
3415 : }
3416 : }
3417 :
3418 15 : apoLayers.emplace_back(poLayer);
3419 : }
3420 : }
3421 :
3422 : /* --------------------------------------------------------------------
3423 : */
3424 : /* Special case to improve user experience when translating into */
3425 : /* single file shapefile and source has only one layer, and that */
3426 : /* the layer name isn't specified */
3427 : /* --------------------------------------------------------------------
3428 : */
3429 : VSIStatBufL sStat;
3430 651 : const int nLayerCount = static_cast<int>(apoLayers.size());
3431 734 : if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
3432 82 : nLayerCount == 1 && psOptions->osNewLayerName.empty() &&
3433 744 : VSIStatL(osDestFilename, &sStat) == 0 && VSI_ISREG(sStat.st_mode) &&
3434 10 : (EQUAL(CPLGetExtension(osDestFilename), "shp") ||
3435 2 : EQUAL(CPLGetExtension(osDestFilename), "shz") ||
3436 1 : EQUAL(CPLGetExtension(osDestFilename), "dbf")))
3437 : {
3438 9 : psOptions->osNewLayerName = CPLGetBasename(osDestFilename);
3439 : }
3440 :
3441 651 : std::vector<GIntBig> anLayerCountFeatures;
3442 651 : anLayerCountFeatures.resize(nLayerCount);
3443 651 : GIntBig nCountLayersFeatures = 0;
3444 651 : GIntBig nAccCountFeatures = 0;
3445 :
3446 : /* First pass to apply filters and count all features if necessary */
3447 1340 : for (int iLayer = 0; iLayer < nLayerCount; iLayer++)
3448 : {
3449 689 : OGRLayer *poLayer = apoLayers[iLayer];
3450 689 : if (poLayer == nullptr)
3451 0 : continue;
3452 :
3453 689 : if (!psOptions->osWHERE.empty())
3454 : {
3455 8 : if (poLayer->SetAttributeFilter(psOptions->osWHERE.c_str()) !=
3456 : OGRERR_NONE)
3457 : {
3458 0 : CPLError(CE_Failure, CPLE_AppDefined,
3459 : "SetAttributeFilter(%s) on layer '%s' failed.",
3460 0 : psOptions->osWHERE.c_str(), poLayer->GetName());
3461 0 : if (!psOptions->bSkipFailures)
3462 : {
3463 0 : return nullptr;
3464 : }
3465 : }
3466 : }
3467 :
3468 1377 : ApplySpatialFilter(
3469 689 : poLayer, psOptions->poSpatialFilter.get(), poSpatSRS.get(),
3470 689 : psOptions->bGeomFieldSet ? psOptions->osGeomField.c_str()
3471 : : nullptr,
3472 : poSourceSRS);
3473 :
3474 689 : if (psOptions->bDisplayProgress)
3475 : {
3476 3 : if (!poLayer->TestCapability(OLCFastFeatureCount))
3477 : {
3478 0 : CPLError(CE_Warning, CPLE_NotSupported,
3479 : "Progress turned off as fast feature count is not "
3480 : "available.");
3481 0 : psOptions->bDisplayProgress = false;
3482 : }
3483 : else
3484 : {
3485 3 : anLayerCountFeatures[iLayer] = poLayer->GetFeatureCount();
3486 3 : if (psOptions->nLimit >= 0)
3487 0 : anLayerCountFeatures[iLayer] = std::min(
3488 0 : anLayerCountFeatures[iLayer], psOptions->nLimit);
3489 3 : nCountLayersFeatures += anLayerCountFeatures[iLayer];
3490 : }
3491 : }
3492 : }
3493 :
3494 : /* Second pass to do the real job */
3495 1340 : for (int iLayer = 0; iLayer < nLayerCount && nRetCode == 0; iLayer++)
3496 : {
3497 689 : OGRLayer *poLayer = apoLayers[iLayer];
3498 689 : if (poLayer == nullptr)
3499 0 : continue;
3500 :
3501 689 : GDALProgressFunc pfnProgress = nullptr;
3502 689 : void *pProgressArg = nullptr;
3503 :
3504 689 : OGRLayer *poPassedLayer = poLayer;
3505 689 : if (psOptions->bSplitListFields)
3506 : {
3507 : auto poSLFLayer = new OGRSplitListFieldLayer(
3508 1 : poPassedLayer, psOptions->nMaxSplitListSubFields);
3509 1 : poPassedLayer = poSLFLayer;
3510 :
3511 1 : if (psOptions->bDisplayProgress &&
3512 1 : psOptions->nMaxSplitListSubFields != 1 &&
3513 : nCountLayersFeatures != 0)
3514 : {
3515 0 : pfnProgress = GDALScaledProgress;
3516 0 : pProgressArg = GDALCreateScaledProgress(
3517 : nAccCountFeatures * 1.0 / nCountLayersFeatures,
3518 0 : (nAccCountFeatures + anLayerCountFeatures[iLayer] / 2) *
3519 : 1.0 / nCountLayersFeatures,
3520 0 : psOptions->pfnProgress, psOptions->pProgressData);
3521 : }
3522 : else
3523 : {
3524 1 : pfnProgress = nullptr;
3525 1 : pProgressArg = nullptr;
3526 : }
3527 :
3528 : int nRet =
3529 1 : poSLFLayer->BuildLayerDefn(pfnProgress, pProgressArg);
3530 1 : if (!nRet)
3531 : {
3532 0 : delete poPassedLayer;
3533 0 : poPassedLayer = poLayer;
3534 : }
3535 :
3536 1 : if (psOptions->bDisplayProgress)
3537 0 : GDALDestroyScaledProgress(pProgressArg);
3538 1 : pfnProgress = nullptr;
3539 1 : pProgressArg = nullptr;
3540 : }
3541 :
3542 689 : if (psOptions->bDisplayProgress)
3543 : {
3544 3 : if (nCountLayersFeatures != 0)
3545 : {
3546 3 : pfnProgress = GDALScaledProgress;
3547 3 : GIntBig nStart = 0;
3548 3 : if (poPassedLayer != poLayer &&
3549 0 : psOptions->nMaxSplitListSubFields != 1)
3550 0 : nStart = anLayerCountFeatures[iLayer] / 2;
3551 3 : pProgressArg = GDALCreateScaledProgress(
3552 3 : (nAccCountFeatures + nStart) * 1.0 /
3553 : nCountLayersFeatures,
3554 3 : (nAccCountFeatures + anLayerCountFeatures[iLayer]) *
3555 : 1.0 / nCountLayersFeatures,
3556 3 : psOptions->pfnProgress, psOptions->pProgressData);
3557 : }
3558 : }
3559 :
3560 689 : nAccCountFeatures += anLayerCountFeatures[iLayer];
3561 :
3562 : auto psInfo = oSetup.Setup(poPassedLayer,
3563 689 : psOptions->osNewLayerName.empty()
3564 : ? nullptr
3565 30 : : psOptions->osNewLayerName.c_str(),
3566 2097 : psOptions.get(), nTotalEventsDone);
3567 :
3568 689 : poPassedLayer->ResetReading();
3569 :
3570 689 : if ((psInfo == nullptr ||
3571 687 : !oTranslator.Translate(nullptr, psInfo.get(),
3572 687 : anLayerCountFeatures[iLayer], nullptr,
3573 : nTotalEventsDone, pfnProgress,
3574 1378 : pProgressArg, psOptions.get())) &&
3575 8 : !psOptions->bSkipFailures)
3576 : {
3577 7 : CPLError(CE_Failure, CPLE_AppDefined,
3578 : "Terminating translation prematurely after failed\n"
3579 : "translation of layer %s (use -skipfailures to skip "
3580 : "errors)",
3581 7 : poLayer->GetName());
3582 :
3583 7 : nRetCode = 1;
3584 : }
3585 :
3586 689 : if (poPassedLayer != poLayer)
3587 1 : delete poPassedLayer;
3588 :
3589 689 : if (psOptions->bDisplayProgress)
3590 3 : GDALDestroyScaledProgress(pProgressArg);
3591 : }
3592 : }
3593 : /* -------------------------------------------------------------------- */
3594 : /* Process DS style table */
3595 : /* -------------------------------------------------------------------- */
3596 :
3597 678 : poODS->SetStyleTable(poDS->GetStyleTable());
3598 :
3599 678 : if (psOptions->nGroupTransactions)
3600 : {
3601 677 : if (!psOptions->nLayerTransaction)
3602 : {
3603 109 : if (nRetCode != 0 && !psOptions->bSkipFailures)
3604 6 : poODS->RollbackTransaction();
3605 : else
3606 : {
3607 103 : OGRErr eRet = poODS->CommitTransaction();
3608 103 : if (eRet != OGRERR_NONE && eRet != OGRERR_UNSUPPORTED_OPERATION)
3609 : {
3610 1 : nRetCode = 1;
3611 : }
3612 : }
3613 : }
3614 : }
3615 :
3616 : // Note: this guarantees that the file can be opened in a consistent state,
3617 : // without requiring to close poODS, only if the driver declares
3618 : // DCAP_FLUSHCACHE_CONSISTENT_STATE
3619 678 : if (poODS->FlushCache() != CE_None)
3620 0 : nRetCode = 1;
3621 :
3622 678 : if (nRetCode == 0)
3623 : {
3624 670 : if (hDstDS)
3625 13 : return hDstDS;
3626 : else
3627 657 : return GDALDataset::ToHandle(poODSUniquePtr.release());
3628 : }
3629 :
3630 8 : return nullptr;
3631 : }
3632 :
3633 : /************************************************************************/
3634 : /* SetZ() */
3635 : /************************************************************************/
3636 :
3637 : namespace
3638 : {
3639 : class SetZVisitor : public OGRDefaultGeometryVisitor
3640 : {
3641 : double m_dfZ;
3642 :
3643 : public:
3644 30 : explicit SetZVisitor(double dfZ) : m_dfZ(dfZ)
3645 : {
3646 30 : }
3647 :
3648 : using OGRDefaultGeometryVisitor::visit;
3649 :
3650 735 : void visit(OGRPoint *poPoint) override
3651 : {
3652 735 : poPoint->setZ(m_dfZ);
3653 735 : }
3654 : };
3655 : } // namespace
3656 :
3657 30 : static void SetZ(OGRGeometry *poGeom, double dfZ)
3658 : {
3659 30 : if (poGeom == nullptr)
3660 0 : return;
3661 60 : SetZVisitor visitor(dfZ);
3662 30 : poGeom->set3D(true);
3663 30 : poGeom->accept(&visitor);
3664 : }
3665 :
3666 : /************************************************************************/
3667 : /* ForceCoordDimension() */
3668 : /************************************************************************/
3669 :
3670 967 : static int ForceCoordDimension(int eGType, int nCoordDim)
3671 : {
3672 967 : if (nCoordDim == 2 && eGType != wkbNone)
3673 3 : return wkbFlatten(eGType);
3674 964 : else if (nCoordDim == 3 && eGType != wkbNone)
3675 3 : return wkbSetZ(wkbFlatten(eGType));
3676 961 : else if (nCoordDim == COORD_DIM_XYM && eGType != wkbNone)
3677 2 : return wkbSetM(wkbFlatten(eGType));
3678 959 : else if (nCoordDim == 4 && eGType != wkbNone)
3679 2 : return OGR_GT_SetModifier(static_cast<OGRwkbGeometryType>(eGType), TRUE,
3680 2 : TRUE);
3681 : else
3682 957 : return eGType;
3683 : }
3684 :
3685 : /************************************************************************/
3686 : /* GetLayerAndOverwriteIfNecessary() */
3687 : /************************************************************************/
3688 :
3689 847 : static OGRLayer *GetLayerAndOverwriteIfNecessary(GDALDataset *poDstDS,
3690 : const char *pszNewLayerName,
3691 : bool bOverwrite,
3692 : bool *pbErrorOccurred,
3693 : bool *pbOverwriteActuallyDone,
3694 : bool *pbAddOverwriteLCO)
3695 : {
3696 847 : if (pbErrorOccurred)
3697 847 : *pbErrorOccurred = false;
3698 847 : if (pbOverwriteActuallyDone)
3699 847 : *pbOverwriteActuallyDone = false;
3700 847 : if (pbAddOverwriteLCO)
3701 847 : *pbAddOverwriteLCO = false;
3702 :
3703 : /* GetLayerByName() can instantiate layers that would have been */
3704 : /* 'hidden' otherwise, for example, non-spatial tables in a */
3705 : /* PostGIS-enabled database, so this apparently useless command is */
3706 : /* not useless. (#4012) */
3707 847 : CPLPushErrorHandler(CPLQuietErrorHandler);
3708 847 : OGRLayer *poDstLayer = poDstDS->GetLayerByName(pszNewLayerName);
3709 847 : CPLPopErrorHandler();
3710 847 : CPLErrorReset();
3711 :
3712 847 : int iLayer = -1;
3713 847 : if (poDstLayer != nullptr)
3714 : {
3715 53 : const int nLayerCount = poDstDS->GetLayerCount();
3716 367 : for (iLayer = 0; iLayer < nLayerCount; iLayer++)
3717 : {
3718 367 : OGRLayer *poLayer = poDstDS->GetLayer(iLayer);
3719 367 : if (poLayer == poDstLayer)
3720 53 : break;
3721 : }
3722 :
3723 53 : if (iLayer == nLayerCount)
3724 : /* should not happen with an ideal driver */
3725 0 : poDstLayer = nullptr;
3726 : }
3727 :
3728 : /* -------------------------------------------------------------------- */
3729 : /* If the user requested overwrite, and we have the layer in */
3730 : /* question we need to delete it now so it will get recreated */
3731 : /* (overwritten). */
3732 : /* -------------------------------------------------------------------- */
3733 847 : if (poDstLayer != nullptr && bOverwrite)
3734 : {
3735 : /* When using the CARTO driver we don't want to delete the layer if */
3736 : /* it's going to be recreated. Instead we mark it to be overwritten */
3737 : /* when the new creation is requested */
3738 12 : if (poDstDS->GetDriver()->GetMetadataItem(
3739 24 : GDAL_DS_LAYER_CREATIONOPTIONLIST) != nullptr &&
3740 24 : strstr(poDstDS->GetDriver()->GetMetadataItem(
3741 12 : GDAL_DS_LAYER_CREATIONOPTIONLIST),
3742 : "CARTODBFY") != nullptr)
3743 : {
3744 0 : if (pbAddOverwriteLCO)
3745 0 : *pbAddOverwriteLCO = true;
3746 0 : if (pbOverwriteActuallyDone)
3747 0 : *pbOverwriteActuallyDone = true;
3748 : }
3749 12 : else if (poDstDS->DeleteLayer(iLayer) != OGRERR_NONE)
3750 : {
3751 0 : CPLError(CE_Failure, CPLE_AppDefined,
3752 : "DeleteLayer() failed when overwrite requested.");
3753 0 : if (pbErrorOccurred)
3754 0 : *pbErrorOccurred = true;
3755 : }
3756 : else
3757 : {
3758 12 : if (pbOverwriteActuallyDone)
3759 12 : *pbOverwriteActuallyDone = true;
3760 : }
3761 12 : poDstLayer = nullptr;
3762 : }
3763 :
3764 847 : return poDstLayer;
3765 : }
3766 :
3767 : /************************************************************************/
3768 : /* ConvertType() */
3769 : /************************************************************************/
3770 :
3771 962 : static OGRwkbGeometryType ConvertType(GeomTypeConversion eGeomTypeConversion,
3772 : OGRwkbGeometryType eGType)
3773 : {
3774 962 : OGRwkbGeometryType eRetType = eGType;
3775 :
3776 962 : if (eGeomTypeConversion == GTC_CONVERT_TO_LINEAR ||
3777 : eGeomTypeConversion == GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR)
3778 : {
3779 13 : eRetType = OGR_GT_GetLinear(eRetType);
3780 : }
3781 :
3782 962 : if (eGeomTypeConversion == GTC_PROMOTE_TO_MULTI ||
3783 : eGeomTypeConversion == GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR)
3784 : {
3785 12 : if (eRetType == wkbTriangle || eRetType == wkbTIN ||
3786 : eRetType == wkbPolyhedralSurface)
3787 : {
3788 0 : eRetType = wkbMultiPolygon;
3789 : }
3790 12 : else if (!OGR_GT_IsSubClassOf(eRetType, wkbGeometryCollection))
3791 : {
3792 8 : eRetType = OGR_GT_GetCollection(eRetType);
3793 : }
3794 : }
3795 :
3796 962 : if (eGeomTypeConversion == GTC_CONVERT_TO_CURVE)
3797 2 : eRetType = OGR_GT_GetCurve(eRetType);
3798 :
3799 962 : return eRetType;
3800 : }
3801 :
3802 : /************************************************************************/
3803 : /* DoFieldTypeConversion() */
3804 : /************************************************************************/
3805 :
3806 3159 : static void DoFieldTypeConversion(GDALDataset *poDstDS,
3807 : OGRFieldDefn &oFieldDefn,
3808 : CSLConstList papszFieldTypesToString,
3809 : CSLConstList papszMapFieldType,
3810 : bool bUnsetFieldWidth, bool bQuiet,
3811 : bool bForceNullable, bool bUnsetDefault)
3812 : {
3813 3159 : if (papszFieldTypesToString != nullptr)
3814 : {
3815 0 : CPLString osLookupString;
3816 : osLookupString.Printf(
3817 : "%s(%s)", OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
3818 0 : OGRFieldDefn::GetFieldSubTypeName(oFieldDefn.GetSubType()));
3819 :
3820 0 : int iIdx = CSLFindString(papszFieldTypesToString, osLookupString);
3821 0 : if (iIdx < 0)
3822 0 : iIdx = CSLFindString(
3823 : papszFieldTypesToString,
3824 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()));
3825 0 : if (iIdx < 0)
3826 0 : iIdx = CSLFindString(papszFieldTypesToString, "All");
3827 0 : if (iIdx >= 0)
3828 : {
3829 0 : oFieldDefn.SetSubType(OFSTNone);
3830 0 : oFieldDefn.SetType(OFTString);
3831 : }
3832 : }
3833 3159 : else if (papszMapFieldType != nullptr)
3834 : {
3835 28 : CPLString osLookupString;
3836 : osLookupString.Printf(
3837 : "%s(%s)", OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
3838 14 : OGRFieldDefn::GetFieldSubTypeName(oFieldDefn.GetSubType()));
3839 :
3840 : const char *pszType =
3841 14 : CSLFetchNameValue(papszMapFieldType, osLookupString);
3842 14 : if (pszType == nullptr)
3843 13 : pszType = CSLFetchNameValue(
3844 : papszMapFieldType,
3845 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()));
3846 14 : if (pszType == nullptr)
3847 10 : pszType = CSLFetchNameValue(papszMapFieldType, "All");
3848 14 : if (pszType != nullptr)
3849 : {
3850 : int iSubType;
3851 4 : int iType = GetFieldType(pszType, &iSubType);
3852 4 : if (iType >= 0 && iSubType >= 0)
3853 : {
3854 4 : oFieldDefn.SetSubType(OFSTNone);
3855 4 : oFieldDefn.SetType(static_cast<OGRFieldType>(iType));
3856 4 : oFieldDefn.SetSubType(static_cast<OGRFieldSubType>(iSubType));
3857 4 : if (iType == OFTInteger)
3858 1 : oFieldDefn.SetWidth(0);
3859 : }
3860 : }
3861 : }
3862 3159 : if (bUnsetFieldWidth)
3863 : {
3864 6 : oFieldDefn.SetWidth(0);
3865 6 : oFieldDefn.SetPrecision(0);
3866 : }
3867 3159 : if (bForceNullable)
3868 4 : oFieldDefn.SetNullable(TRUE);
3869 3159 : if (bUnsetDefault)
3870 2 : oFieldDefn.SetDefault(nullptr);
3871 :
3872 3159 : const auto poDstDriver = poDstDS->GetDriver();
3873 : const char *pszCreationFieldDataTypes =
3874 : poDstDriver
3875 3159 : ? poDstDriver->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES)
3876 3159 : : nullptr;
3877 : const char *pszCreationFieldDataSubtypes =
3878 : poDstDriver
3879 3159 : ? poDstDriver->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES)
3880 3159 : : nullptr;
3881 6209 : if (pszCreationFieldDataTypes &&
3882 3050 : strstr(pszCreationFieldDataTypes,
3883 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType())) == nullptr)
3884 : {
3885 33 : if (pszCreationFieldDataSubtypes &&
3886 64 : (oFieldDefn.GetType() == OFTIntegerList ||
3887 61 : oFieldDefn.GetType() == OFTInteger64List ||
3888 59 : oFieldDefn.GetType() == OFTRealList ||
3889 98 : oFieldDefn.GetType() == OFTStringList) &&
3890 25 : strstr(pszCreationFieldDataSubtypes, "JSON"))
3891 : {
3892 5 : if (!bQuiet)
3893 : {
3894 5 : CPLError(
3895 : CE_Warning, CPLE_AppDefined,
3896 : "The output driver does not seem to natively support %s "
3897 : "type for field %s. Converting it to String(JSON) instead. "
3898 : "-mapFieldType can be used to control field type "
3899 : "conversion.",
3900 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
3901 : oFieldDefn.GetNameRef());
3902 : }
3903 5 : oFieldDefn.SetSubType(OFSTNone);
3904 5 : oFieldDefn.SetType(OFTString);
3905 5 : oFieldDefn.SetSubType(OFSTJSON);
3906 : }
3907 31 : else if (oFieldDefn.GetType() == OFTInteger64)
3908 : {
3909 6 : if (!bQuiet)
3910 : {
3911 6 : CPLError(
3912 : CE_Warning, CPLE_AppDefined,
3913 : "The output driver does not seem to natively support %s "
3914 : "type for field %s. Converting it to Real instead. "
3915 : "-mapFieldType can be used to control field type "
3916 : "conversion.",
3917 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
3918 : oFieldDefn.GetNameRef());
3919 : }
3920 6 : oFieldDefn.SetType(OFTReal);
3921 : }
3922 25 : else if (!bQuiet)
3923 : {
3924 25 : CPLError(
3925 : CE_Warning, CPLE_AppDefined,
3926 : "The output driver does not natively support %s type for "
3927 : "field %s. Misconversion can happen. "
3928 : "-mapFieldType can be used to control field type conversion.",
3929 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
3930 : oFieldDefn.GetNameRef());
3931 : }
3932 : }
3933 3123 : else if (!pszCreationFieldDataTypes)
3934 : {
3935 : // All drivers supporting OFTInteger64 should advertise it theoretically
3936 109 : if (oFieldDefn.GetType() == OFTInteger64)
3937 : {
3938 1 : if (!bQuiet)
3939 : {
3940 1 : CPLError(CE_Warning, CPLE_AppDefined,
3941 : "The output driver does not seem to natively support "
3942 : "%s type "
3943 : "for field %s. Converting it to Real instead. "
3944 : "-mapFieldType can be used to control field type "
3945 : "conversion.",
3946 : OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
3947 : oFieldDefn.GetNameRef());
3948 : }
3949 1 : oFieldDefn.SetType(OFTReal);
3950 : }
3951 : }
3952 3159 : }
3953 :
3954 : /************************************************************************/
3955 : /* GetArrowGeomFieldIndex() */
3956 : /************************************************************************/
3957 :
3958 22 : static int GetArrowGeomFieldIndex(const struct ArrowSchema *psLayerSchema,
3959 : const char *pszFieldName)
3960 : {
3961 22 : if (strcmp(psLayerSchema->format, "+s") == 0) // struct
3962 : {
3963 80 : for (int i = 0; i < psLayerSchema->n_children; ++i)
3964 : {
3965 80 : const auto psSchema = psLayerSchema->children[i];
3966 80 : if (strcmp(psSchema->format, "z") == 0) // binary
3967 : {
3968 22 : if (strcmp(psSchema->name, pszFieldName) == 0)
3969 : {
3970 22 : return i;
3971 : }
3972 : else
3973 : {
3974 : // Check if ARROW:extension:name = ogc.wkb or geoarrow.wkb
3975 0 : const char *pabyMetadata = psSchema->metadata;
3976 0 : if (pabyMetadata)
3977 : {
3978 : const auto oMetadata =
3979 0 : OGRParseArrowMetadata(pabyMetadata);
3980 0 : auto oIter = oMetadata.find(ARROW_EXTENSION_NAME_KEY);
3981 0 : if (oIter != oMetadata.end() &&
3982 0 : (oIter->second == EXTENSION_NAME_OGC_WKB ||
3983 0 : oIter->second == EXTENSION_NAME_GEOARROW_WKB))
3984 : {
3985 0 : return i;
3986 : }
3987 : }
3988 : }
3989 : }
3990 : }
3991 : }
3992 0 : return -1;
3993 : }
3994 :
3995 : /************************************************************************/
3996 : /* BuildGetArrowStreamOptions() */
3997 : /************************************************************************/
3998 :
3999 : static CPLStringList
4000 142 : BuildGetArrowStreamOptions(const GDALVectorTranslateOptions *psOptions,
4001 : bool bPreserveFID)
4002 : {
4003 142 : CPLStringList aosOptionsGetArrowStream;
4004 142 : aosOptionsGetArrowStream.SetNameValue("SILENCE_GET_SCHEMA_ERROR", "YES");
4005 142 : aosOptionsGetArrowStream.SetNameValue("GEOMETRY_ENCODING", "WKB");
4006 142 : if (!bPreserveFID)
4007 126 : aosOptionsGetArrowStream.SetNameValue("INCLUDE_FID", "NO");
4008 142 : if (psOptions->nLimit >= 0)
4009 : {
4010 : aosOptionsGetArrowStream.SetNameValue(
4011 : "MAX_FEATURES_IN_BATCH",
4012 : CPLSPrintf(CPL_FRMT_GIB,
4013 2 : std::min<GIntBig>(psOptions->nLimit,
4014 2 : (psOptions->nGroupTransactions > 0
4015 4 : ? psOptions->nGroupTransactions
4016 2 : : 65536))));
4017 : }
4018 140 : else if (psOptions->nGroupTransactions > 0)
4019 : {
4020 : aosOptionsGetArrowStream.SetNameValue(
4021 : "MAX_FEATURES_IN_BATCH",
4022 140 : CPLSPrintf("%d", psOptions->nGroupTransactions));
4023 : }
4024 142 : return aosOptionsGetArrowStream;
4025 : }
4026 :
4027 : /************************************************************************/
4028 : /* SetupTargetLayer::CanUseWriteArrowBatch() */
4029 : /************************************************************************/
4030 :
4031 843 : bool SetupTargetLayer::CanUseWriteArrowBatch(
4032 : OGRLayer *poSrcLayer, OGRLayer *poDstLayer, bool bJustCreatedLayer,
4033 : const GDALVectorTranslateOptions *psOptions, bool bPreserveFID,
4034 : bool &bError, OGRArrowArrayStream &streamSrc)
4035 : {
4036 843 : bError = false;
4037 :
4038 : // Check if we can use the Arrow interface to get and write features
4039 : // as it will be faster if the input driver has a fast
4040 : // implementation of GetArrowStream().
4041 : // We also can only do that only if using ogr2ogr without options that
4042 : // alter features.
4043 : // OGR2OGR_USE_ARROW_API config option is mostly for testing purposes
4044 : // or as a safety belt if things turned bad...
4045 843 : bool bUseWriteArrowBatch = false;
4046 843 : if (((poSrcLayer->TestCapability(OLCFastGetArrowStream) &&
4047 : // As we don't control the input array size when the input or output
4048 : // drivers are Arrow/Parquet (as they don't use the generic
4049 : // implementation), we can't guarantee that ROW_GROUP_SIZE/BATCH_SIZE
4050 : // layer creation options will be honored.
4051 150 : !psOptions->aosLCO.FetchNameValue("ROW_GROUP_SIZE") &&
4052 148 : !psOptions->aosLCO.FetchNameValue("BATCH_SIZE") &&
4053 145 : CPLTestBool(CPLGetConfigOption("OGR2OGR_USE_ARROW_API", "YES"))) ||
4054 698 : CPLTestBool(CPLGetConfigOption("OGR2OGR_USE_ARROW_API", "NO"))) &&
4055 150 : !psOptions->bSkipFailures && !psOptions->poClipSrc &&
4056 147 : !psOptions->poClipDst && psOptions->oGCPs.nGCPCount == 0 &&
4057 144 : !psOptions->bWrapDateline && !m_papszSelFields &&
4058 144 : !m_bAddMissingFields && m_eGType == GEOMTYPE_UNCHANGED &&
4059 144 : psOptions->eGeomOp == GEOMOP_NONE &&
4060 144 : m_eGeomTypeConversion == GTC_DEFAULT && m_nCoordDim < 0 &&
4061 144 : !m_papszFieldTypesToString && !m_papszMapFieldType &&
4062 144 : !m_bUnsetFieldWidth && !m_bExplodeCollections && !m_pszZField &&
4063 143 : m_bExactFieldNameMatch && !m_bForceNullable && !m_bResolveDomains &&
4064 143 : !m_bUnsetDefault && psOptions->nFIDToFetch == OGRNullFID &&
4065 143 : psOptions->dfXYRes == OGRGeomCoordinatePrecision::UNKNOWN &&
4066 1686 : !psOptions->bMakeValid && !psOptions->bSkipInvalidGeom)
4067 : {
4068 143 : if (psOptions->bTransform)
4069 : {
4070 : // To simplify implementation for now
4071 24 : if (poSrcLayer->GetLayerDefn()->GetGeomFieldCount() != 1 ||
4072 12 : poDstLayer->GetLayerDefn()->GetGeomFieldCount() != 1)
4073 : {
4074 1 : return false;
4075 : }
4076 12 : auto poSrcSRS = m_poUserSourceSRS ? m_poUserSourceSRS
4077 11 : : poSrcLayer->GetLayerDefn()
4078 11 : ->GetGeomFieldDefn(0)
4079 11 : ->GetSpatialRef();
4080 24 : if (!poSrcSRS ||
4081 12 : !OGRGeometryFactory::isTransformWithOptionsRegularTransform(
4082 : poSrcSRS, m_poOutputSRS, nullptr))
4083 : {
4084 1 : return false;
4085 : }
4086 : }
4087 :
4088 : const CPLStringList aosGetArrowStreamOptions(
4089 142 : BuildGetArrowStreamOptions(psOptions, bPreserveFID));
4090 142 : if (poSrcLayer->GetArrowStream(streamSrc.get(),
4091 142 : aosGetArrowStreamOptions.List()))
4092 : {
4093 : struct ArrowSchema schemaSrc;
4094 142 : if (streamSrc.get_schema(&schemaSrc) == 0)
4095 : {
4096 153 : if (psOptions->bTransform &&
4097 11 : GetArrowGeomFieldIndex(&schemaSrc,
4098 11 : poSrcLayer->GetGeometryColumn()) < 0)
4099 : {
4100 0 : schemaSrc.release(&schemaSrc);
4101 0 : streamSrc.clear();
4102 0 : return false;
4103 : }
4104 :
4105 142 : std::string osErrorMsg;
4106 142 : if (poDstLayer->IsArrowSchemaSupported(&schemaSrc, nullptr,
4107 142 : osErrorMsg))
4108 : {
4109 : const OGRFeatureDefn *poSrcFDefn =
4110 142 : poSrcLayer->GetLayerDefn();
4111 : const OGRFeatureDefn *poDstFDefn =
4112 142 : poDstLayer->GetLayerDefn();
4113 140 : if (bJustCreatedLayer && poDstFDefn &&
4114 422 : poDstFDefn->GetFieldCount() == 0 &&
4115 140 : poDstFDefn->GetGeomFieldCount() ==
4116 140 : poSrcFDefn->GetGeomFieldCount())
4117 : {
4118 : // Create output fields using CreateFieldFromArrowSchema()
4119 1185 : for (int i = 0; i < schemaSrc.n_children; ++i)
4120 : {
4121 1045 : const char *pszFieldName =
4122 1045 : schemaSrc.children[i]->name;
4123 :
4124 : const auto iSrcField =
4125 1045 : poSrcFDefn->GetFieldIndex(pszFieldName);
4126 1045 : if (iSrcField >= 0)
4127 : {
4128 : const auto poSrcFieldDefn =
4129 881 : poSrcFDefn->GetFieldDefn(iSrcField);
4130 : // Create field domain in output dataset if not already existing.
4131 : const std::string osDomainName(
4132 1762 : poSrcFieldDefn->GetDomainName());
4133 881 : if (!osDomainName.empty())
4134 : {
4135 33 : if (m_poDstDS->TestCapability(
4136 22 : ODsCAddFieldDomain) &&
4137 11 : m_poDstDS->GetFieldDomain(
4138 11 : osDomainName) == nullptr)
4139 : {
4140 : const auto poSrcDomain =
4141 22 : m_poSrcDS->GetFieldDomain(
4142 11 : osDomainName);
4143 11 : if (poSrcDomain)
4144 : {
4145 22 : std::string failureReason;
4146 11 : if (!m_poDstDS->AddFieldDomain(
4147 22 : std::unique_ptr<
4148 : OGRFieldDomain>(
4149 11 : poSrcDomain->Clone()),
4150 11 : failureReason))
4151 : {
4152 0 : CPLDebug("OGR2OGR",
4153 : "Cannot create domain "
4154 : "%s: %s",
4155 : osDomainName.c_str(),
4156 : failureReason.c_str());
4157 : }
4158 : }
4159 : else
4160 : {
4161 0 : CPLDebug("OGR2OGR",
4162 : "Cannot find domain %s in "
4163 : "source dataset",
4164 : osDomainName.c_str());
4165 : }
4166 : }
4167 : }
4168 : }
4169 :
4170 3135 : if (!EQUAL(pszFieldName, "OGC_FID") &&
4171 1045 : !EQUAL(pszFieldName, "wkb_geometry") &&
4172 1042 : !EQUAL(pszFieldName,
4173 1026 : poSrcLayer->GetFIDColumn()) &&
4174 1026 : poSrcFDefn->GetGeomFieldIndex(pszFieldName) <
4175 2090 : 0 &&
4176 890 : !poDstLayer->CreateFieldFromArrowSchema(
4177 890 : schemaSrc.children[i], nullptr))
4178 : {
4179 0 : CPLError(CE_Failure, CPLE_AppDefined,
4180 : "Cannot create field %s",
4181 : pszFieldName);
4182 0 : schemaSrc.release(&schemaSrc);
4183 0 : streamSrc.clear();
4184 0 : return false;
4185 : }
4186 : }
4187 140 : bUseWriteArrowBatch = true;
4188 : }
4189 2 : else if (!bJustCreatedLayer)
4190 : {
4191 : // If the layer already exist, get its schema, and
4192 : // check that it looks to be the same as the source
4193 : // one
4194 : struct ArrowArrayStream streamDst;
4195 2 : if (poDstLayer->GetArrowStream(
4196 2 : &streamDst, aosGetArrowStreamOptions.List()))
4197 : {
4198 : struct ArrowSchema schemaDst;
4199 2 : if (streamDst.get_schema(&streamDst, &schemaDst) ==
4200 : 0)
4201 : {
4202 2 : if (schemaDst.n_children ==
4203 2 : schemaSrc.n_children)
4204 : {
4205 2 : bUseWriteArrowBatch = true;
4206 : }
4207 2 : schemaDst.release(&schemaDst);
4208 : }
4209 2 : streamDst.release(&streamDst);
4210 : }
4211 : }
4212 142 : if (bUseWriteArrowBatch)
4213 : {
4214 142 : CPLDebug("OGR2OGR", "Using WriteArrowBatch()");
4215 : }
4216 : }
4217 : else
4218 : {
4219 0 : CPLDebug("OGR2OGR",
4220 : "Cannot use WriteArrowBatch() because "
4221 : "input layer schema is not supported by output "
4222 : "layer: %s",
4223 : osErrorMsg.c_str());
4224 : }
4225 142 : schemaSrc.release(&schemaSrc);
4226 : }
4227 142 : if (!bUseWriteArrowBatch)
4228 0 : streamSrc.clear();
4229 : }
4230 : }
4231 842 : return bUseWriteArrowBatch;
4232 : }
4233 :
4234 : /************************************************************************/
4235 : /* SetupTargetLayer::Setup() */
4236 : /************************************************************************/
4237 :
4238 : std::unique_ptr<TargetLayerInfo>
4239 847 : SetupTargetLayer::Setup(OGRLayer *poSrcLayer, const char *pszNewLayerName,
4240 : GDALVectorTranslateOptions *psOptions,
4241 : GIntBig &nTotalEventsDone)
4242 : {
4243 847 : int eGType = m_eGType;
4244 847 : bool bPreserveFID = m_bPreserveFID;
4245 847 : bool bAppend = m_bAppend;
4246 :
4247 847 : if (pszNewLayerName == nullptr)
4248 816 : pszNewLayerName = poSrcLayer->GetName();
4249 :
4250 : /* -------------------------------------------------------------------- */
4251 : /* Get other info. */
4252 : /* -------------------------------------------------------------------- */
4253 847 : OGRFeatureDefn *poSrcFDefn = poSrcLayer->GetLayerDefn();
4254 :
4255 : /* -------------------------------------------------------------------- */
4256 : /* Find requested geometry fields. */
4257 : /* -------------------------------------------------------------------- */
4258 1694 : std::vector<int> anRequestedGeomFields;
4259 847 : const int nSrcGeomFieldCount = poSrcFDefn->GetGeomFieldCount();
4260 847 : if (m_bSelFieldsSet && !bAppend)
4261 : {
4262 40 : for (int iField = 0; m_papszSelFields && m_papszSelFields[iField];
4263 : iField++)
4264 : {
4265 25 : int iSrcField = poSrcFDefn->GetFieldIndex(m_papszSelFields[iField]);
4266 25 : if (iSrcField >= 0)
4267 : {
4268 : /* do nothing */
4269 : }
4270 : else
4271 : {
4272 3 : iSrcField =
4273 3 : poSrcFDefn->GetGeomFieldIndex(m_papszSelFields[iField]);
4274 3 : if (iSrcField >= 0)
4275 : {
4276 3 : anRequestedGeomFields.push_back(iSrcField);
4277 : }
4278 : else
4279 : {
4280 0 : CPLError(CE_Failure, CPLE_AppDefined,
4281 : "Field '%s' not found in source layer.",
4282 0 : m_papszSelFields[iField]);
4283 0 : if (!psOptions->bSkipFailures)
4284 0 : return nullptr;
4285 : }
4286 : }
4287 : }
4288 :
4289 16 : if (anRequestedGeomFields.size() > 1 &&
4290 1 : !m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
4291 : {
4292 0 : CPLError(CE_Failure, CPLE_AppDefined,
4293 : "Several geometry fields requested, but output "
4294 : "datasource does not support multiple geometry "
4295 : "fields.");
4296 0 : if (!psOptions->bSkipFailures)
4297 0 : return nullptr;
4298 : else
4299 0 : anRequestedGeomFields.resize(0);
4300 : }
4301 : }
4302 :
4303 847 : const OGRSpatialReference *poOutputSRS = m_poOutputSRS;
4304 847 : if (poOutputSRS == nullptr && !m_bNullifyOutputSRS)
4305 : {
4306 701 : if (nSrcGeomFieldCount == 1 || anRequestedGeomFields.empty())
4307 699 : poOutputSRS = poSrcLayer->GetSpatialRef();
4308 2 : else if (anRequestedGeomFields.size() == 1)
4309 : {
4310 1 : int iSrcGeomField = anRequestedGeomFields[0];
4311 : poOutputSRS =
4312 1 : poSrcFDefn->GetGeomFieldDefn(iSrcGeomField)->GetSpatialRef();
4313 : }
4314 : }
4315 :
4316 847 : int iSrcZField = -1;
4317 847 : if (m_pszZField != nullptr)
4318 : {
4319 4 : iSrcZField = poSrcFDefn->GetFieldIndex(m_pszZField);
4320 4 : if (iSrcZField < 0)
4321 : {
4322 1 : CPLError(CE_Warning, CPLE_AppDefined,
4323 : "zfield '%s' does not exist in layer %s", m_pszZField,
4324 1 : poSrcLayer->GetName());
4325 : }
4326 : }
4327 :
4328 : /* -------------------------------------------------------------------- */
4329 : /* Find the layer. */
4330 : /* -------------------------------------------------------------------- */
4331 :
4332 : bool bErrorOccurred;
4333 : bool bOverwriteActuallyDone;
4334 : bool bAddOverwriteLCO;
4335 1694 : OGRLayer *poDstLayer = GetLayerAndOverwriteIfNecessary(
4336 847 : m_poDstDS, pszNewLayerName, m_bOverwrite, &bErrorOccurred,
4337 : &bOverwriteActuallyDone, &bAddOverwriteLCO);
4338 847 : const bool bJustCreatedLayer = (poDstLayer == nullptr);
4339 847 : if (bErrorOccurred)
4340 0 : return nullptr;
4341 :
4342 : /* -------------------------------------------------------------------- */
4343 : /* If the layer does not exist, then create it. */
4344 : /* -------------------------------------------------------------------- */
4345 847 : if (poDstLayer == nullptr)
4346 : {
4347 806 : if (!m_poDstDS->TestCapability(ODsCCreateLayer))
4348 : {
4349 0 : CPLError(
4350 : CE_Failure, CPLE_AppDefined,
4351 : "Layer '%s' does not already exist in the output dataset, and "
4352 : "cannot be created by the output driver.",
4353 : pszNewLayerName);
4354 4 : return nullptr;
4355 : }
4356 :
4357 806 : bool bForceGType = (eGType != GEOMTYPE_UNCHANGED);
4358 806 : if (!bForceGType)
4359 : {
4360 790 : if (anRequestedGeomFields.empty())
4361 : {
4362 788 : eGType = poSrcFDefn->GetGeomType();
4363 : }
4364 2 : else if (anRequestedGeomFields.size() == 1)
4365 : {
4366 1 : int iSrcGeomField = anRequestedGeomFields[0];
4367 1 : eGType = poSrcFDefn->GetGeomFieldDefn(iSrcGeomField)->GetType();
4368 : }
4369 : else
4370 : {
4371 1 : eGType = wkbNone;
4372 : }
4373 :
4374 : bool bHasZ =
4375 790 : CPL_TO_BOOL(wkbHasZ(static_cast<OGRwkbGeometryType>(eGType)));
4376 790 : eGType = ConvertType(m_eGeomTypeConversion,
4377 : static_cast<OGRwkbGeometryType>(eGType));
4378 :
4379 790 : if (m_bExplodeCollections)
4380 : {
4381 12 : const OGRwkbGeometryType eFGType = wkbFlatten(eGType);
4382 12 : if (eFGType == wkbMultiPoint)
4383 : {
4384 1 : eGType = wkbPoint;
4385 : }
4386 11 : else if (eFGType == wkbMultiLineString)
4387 : {
4388 0 : eGType = wkbLineString;
4389 : }
4390 11 : else if (eFGType == wkbMultiPolygon)
4391 : {
4392 0 : eGType = wkbPolygon;
4393 : }
4394 11 : else if (eFGType == wkbGeometryCollection ||
4395 11 : eFGType == wkbMultiCurve || eFGType == wkbMultiSurface)
4396 : {
4397 0 : eGType = wkbUnknown;
4398 : }
4399 : }
4400 :
4401 790 : if (bHasZ || (iSrcZField >= 0 && eGType != wkbNone))
4402 109 : eGType = wkbSetZ(static_cast<OGRwkbGeometryType>(eGType));
4403 : }
4404 :
4405 806 : eGType = ForceCoordDimension(eGType, m_nCoordDim);
4406 :
4407 806 : CPLErrorReset();
4408 :
4409 806 : char **papszLCOTemp = CSLDuplicate(m_papszLCO);
4410 : const char *pszDestCreationOptions =
4411 806 : m_poDstDS->GetDriver()->GetMetadataItem(
4412 806 : GDAL_DS_LAYER_CREATIONOPTIONLIST);
4413 :
4414 806 : int eGCreateLayerType = eGType;
4415 817 : if (anRequestedGeomFields.empty() && nSrcGeomFieldCount > 1 &&
4416 11 : m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
4417 : {
4418 10 : eGCreateLayerType = wkbNone;
4419 : }
4420 : // If the source layer has a single geometry column that is not nullable
4421 : // and that ODsCCreateGeomFieldAfterCreateLayer is available, use it
4422 : // so as to be able to set the not null constraint (if the driver
4423 : // supports it) and that the output driver has no GEOMETRY_NULLABLE
4424 : // layer creation option. Same if the source geometry column has a non
4425 : // empty name that is not overridden, and that the output driver has no
4426 : // GEOMETRY_NAME layer creation option, but no LAUNDER option (if
4427 : // laundering is available, then we might want to launder the geometry
4428 : // column name as well)
4429 640 : else if (eGType != wkbNone && anRequestedGeomFields.empty() &&
4430 638 : nSrcGeomFieldCount == 1 &&
4431 638 : m_poDstDS->TestCapability(
4432 2229 : ODsCCreateGeomFieldAfterCreateLayer) &&
4433 155 : ((!poSrcFDefn->GetGeomFieldDefn(0)->IsNullable() &&
4434 2 : CSLFetchNameValue(m_papszLCO, "GEOMETRY_NULLABLE") ==
4435 2 : nullptr &&
4436 2 : (pszDestCreationOptions == nullptr ||
4437 2 : strstr(pszDestCreationOptions, "GEOMETRY_NULLABLE") !=
4438 0 : nullptr) &&
4439 0 : !m_bForceNullable) ||
4440 155 : (poSrcLayer->GetGeometryColumn() != nullptr &&
4441 155 : CSLFetchNameValue(m_papszLCO, "GEOMETRY_NAME") == nullptr &&
4442 155 : !EQUAL(poSrcLayer->GetGeometryColumn(), "") &&
4443 35 : (pszDestCreationOptions == nullptr ||
4444 35 : strstr(pszDestCreationOptions, "GEOMETRY_NAME") ==
4445 8 : nullptr ||
4446 8 : strstr(pszDestCreationOptions, "LAUNDER") != nullptr) &&
4447 35 : poSrcFDefn->GetFieldIndex(poSrcLayer->GetGeometryColumn()) <
4448 : 0)))
4449 : {
4450 35 : anRequestedGeomFields.push_back(0);
4451 35 : eGCreateLayerType = wkbNone;
4452 : }
4453 762 : else if (anRequestedGeomFields.size() == 1 &&
4454 1 : m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
4455 : {
4456 0 : eGCreateLayerType = wkbNone;
4457 : }
4458 :
4459 806 : OGRGeomCoordinatePrecision oCoordPrec;
4460 806 : std::string osGeomFieldName;
4461 806 : bool bGeomFieldNullable = true;
4462 :
4463 : {
4464 806 : int iSrcGeomField = -1;
4465 972 : if (anRequestedGeomFields.empty() &&
4466 166 : (nSrcGeomFieldCount == 1 ||
4467 166 : (!m_poDstDS->TestCapability(
4468 200 : ODsCCreateGeomFieldAfterCreateLayer) &&
4469 : nSrcGeomFieldCount > 1)))
4470 : {
4471 604 : iSrcGeomField = 0;
4472 : }
4473 202 : else if (anRequestedGeomFields.size() == 1)
4474 : {
4475 36 : iSrcGeomField = anRequestedGeomFields[0];
4476 : }
4477 :
4478 806 : if (iSrcGeomField >= 0)
4479 : {
4480 : const auto poSrcGeomFieldDefn =
4481 640 : poSrcFDefn->GetGeomFieldDefn(iSrcGeomField);
4482 640 : if (!psOptions->bUnsetCoordPrecision)
4483 : {
4484 639 : oCoordPrec = poSrcGeomFieldDefn->GetCoordinatePrecision()
4485 1278 : .ConvertToOtherSRS(
4486 639 : poSrcGeomFieldDefn->GetSpatialRef(),
4487 639 : poOutputSRS);
4488 : }
4489 :
4490 : bGeomFieldNullable =
4491 640 : CPL_TO_BOOL(poSrcGeomFieldDefn->IsNullable());
4492 :
4493 640 : const char *pszGFldName = poSrcGeomFieldDefn->GetNameRef();
4494 837 : if (pszGFldName != nullptr && !EQUAL(pszGFldName, "") &&
4495 197 : poSrcFDefn->GetFieldIndex(pszGFldName) < 0)
4496 : {
4497 196 : osGeomFieldName = pszGFldName;
4498 :
4499 : // Use source geometry field name as much as possible
4500 196 : if (eGType != wkbNone && pszDestCreationOptions &&
4501 196 : strstr(pszDestCreationOptions, "GEOMETRY_NAME") !=
4502 392 : nullptr &&
4503 156 : CSLFetchNameValue(m_papszLCO, "GEOMETRY_NAME") ==
4504 : nullptr)
4505 : {
4506 156 : papszLCOTemp = CSLSetNameValue(
4507 : papszLCOTemp, "GEOMETRY_NAME", pszGFldName);
4508 : }
4509 : }
4510 : }
4511 : }
4512 :
4513 : // If the source feature first geometry column is not nullable
4514 : // and that GEOMETRY_NULLABLE creation option is available, use it
4515 : // so as to be able to set the not null constraint (if the driver
4516 : // supports it)
4517 650 : if (eGType != wkbNone && anRequestedGeomFields.empty() &&
4518 614 : nSrcGeomFieldCount >= 1 &&
4519 614 : !poSrcFDefn->GetGeomFieldDefn(0)->IsNullable() &&
4520 0 : pszDestCreationOptions != nullptr &&
4521 0 : strstr(pszDestCreationOptions, "GEOMETRY_NULLABLE") != nullptr &&
4522 1456 : CSLFetchNameValue(m_papszLCO, "GEOMETRY_NULLABLE") == nullptr &&
4523 0 : !m_bForceNullable)
4524 : {
4525 0 : bGeomFieldNullable = false;
4526 : papszLCOTemp =
4527 0 : CSLSetNameValue(papszLCOTemp, "GEOMETRY_NULLABLE", "NO");
4528 0 : CPLDebug("GDALVectorTranslate", "Using GEOMETRY_NULLABLE=NO");
4529 : }
4530 :
4531 806 : if (psOptions->dfXYRes != OGRGeomCoordinatePrecision::UNKNOWN)
4532 : {
4533 7 : if (m_poDstDS->GetDriver()->GetMetadataItem(
4534 8 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION) == nullptr &&
4535 1 : !OGRGeometryFactory::haveGEOS())
4536 : {
4537 0 : CPLError(CE_Warning, CPLE_AppDefined,
4538 : "-xyRes specified, but driver does not expose the "
4539 : "DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, "
4540 : "and this build has no GEOS support");
4541 : }
4542 :
4543 7 : oCoordPrec.dfXYResolution = psOptions->dfXYRes;
4544 7 : if (!psOptions->osXYResUnit.empty())
4545 : {
4546 5 : if (!poOutputSRS)
4547 : {
4548 1 : CSLDestroy(papszLCOTemp);
4549 1 : CPLError(CE_Failure, CPLE_AppDefined,
4550 : "Unit suffix for -xyRes cannot be used with an "
4551 : "unknown destination SRS");
4552 1 : return nullptr;
4553 : }
4554 :
4555 4 : if (psOptions->osXYResUnit == "mm")
4556 : {
4557 1 : oCoordPrec.dfXYResolution *= 1e-3;
4558 : }
4559 3 : else if (psOptions->osXYResUnit == "deg")
4560 : {
4561 : double dfFactorDegToMeter =
4562 2 : poOutputSRS->GetSemiMajor(nullptr) * M_PI / 180;
4563 2 : oCoordPrec.dfXYResolution *= dfFactorDegToMeter;
4564 : }
4565 : else
4566 : {
4567 : // Checked at argument parsing time
4568 1 : CPLAssert(psOptions->osXYResUnit == "m");
4569 : }
4570 :
4571 4 : OGRGeomCoordinatePrecision tmp;
4572 4 : tmp.SetFromMeter(poOutputSRS, oCoordPrec.dfXYResolution, 0, 0);
4573 4 : oCoordPrec.dfXYResolution = tmp.dfXYResolution;
4574 : }
4575 : }
4576 :
4577 805 : if (psOptions->dfZRes != OGRGeomCoordinatePrecision::UNKNOWN)
4578 : {
4579 4 : if (m_poDstDS->GetDriver()->GetMetadataItem(
4580 4 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION) == nullptr)
4581 : {
4582 0 : CPLError(CE_Warning, CPLE_AppDefined,
4583 : "-zRes specified, but driver does not expose the "
4584 : "DCAP_HONOR_GEOM_COORDINATE_PRECISION capability");
4585 : }
4586 :
4587 4 : oCoordPrec.dfZResolution = psOptions->dfZRes;
4588 4 : if (!psOptions->osZResUnit.empty())
4589 : {
4590 3 : if (!poOutputSRS)
4591 : {
4592 1 : CSLDestroy(papszLCOTemp);
4593 1 : CPLError(CE_Failure, CPLE_AppDefined,
4594 : "Unit suffix for -zRes cannot be used with an "
4595 : "unknown destination SRS");
4596 1 : return nullptr;
4597 : }
4598 :
4599 2 : if (psOptions->osZResUnit == "mm")
4600 : {
4601 1 : oCoordPrec.dfZResolution *= 1e-3;
4602 : }
4603 : else
4604 : {
4605 : // Checked at argument parsing time
4606 1 : CPLAssert(psOptions->osZResUnit == "m");
4607 : }
4608 :
4609 2 : OGRGeomCoordinatePrecision tmp;
4610 2 : tmp.SetFromMeter(poOutputSRS, 0, oCoordPrec.dfZResolution, 0);
4611 2 : oCoordPrec.dfZResolution = tmp.dfZResolution;
4612 : }
4613 : }
4614 :
4615 804 : if (psOptions->dfMRes != OGRGeomCoordinatePrecision::UNKNOWN)
4616 : {
4617 3 : if (m_poDstDS->GetDriver()->GetMetadataItem(
4618 3 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION) == nullptr)
4619 : {
4620 0 : CPLError(CE_Warning, CPLE_AppDefined,
4621 : "-mRes specified, but driver does not expose the "
4622 : "DCAP_HONOR_GEOM_COORDINATE_PRECISION capability");
4623 : }
4624 :
4625 3 : oCoordPrec.dfMResolution = psOptions->dfMRes;
4626 : }
4627 :
4628 : // Force FID column as 64 bit if the source feature has a 64 bit FID,
4629 : // the target driver supports 64 bit FID and the user didn't set it
4630 : // manually.
4631 804 : if (poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
4632 1 : EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES") &&
4633 1 : pszDestCreationOptions &&
4634 805 : strstr(pszDestCreationOptions, "FID64") != nullptr &&
4635 0 : CSLFetchNameValue(m_papszLCO, "FID64") == nullptr)
4636 : {
4637 0 : papszLCOTemp = CSLSetNameValue(papszLCOTemp, "FID64", "YES");
4638 0 : CPLDebug("GDALVectorTranslate", "Using FID64=YES");
4639 : }
4640 :
4641 : // If output driver supports FID layer creation option, set it with
4642 : // the FID column name of the source layer
4643 802 : if (!m_bUnsetFid && !bAppend && poSrcLayer->GetFIDColumn() != nullptr &&
4644 801 : !EQUAL(poSrcLayer->GetFIDColumn(), "") &&
4645 39 : pszDestCreationOptions != nullptr &&
4646 39 : (strstr(pszDestCreationOptions, "='FID'") != nullptr ||
4647 1608 : strstr(pszDestCreationOptions, "=\"FID\"") != nullptr) &&
4648 35 : CSLFetchNameValue(m_papszLCO, "FID") == nullptr)
4649 : {
4650 35 : papszLCOTemp = CSLSetNameValue(papszLCOTemp, "FID",
4651 35 : poSrcLayer->GetFIDColumn());
4652 35 : if (!psOptions->bExplodeCollections)
4653 : {
4654 34 : CPLDebug("GDALVectorTranslate",
4655 : "Using FID=%s and -preserve_fid",
4656 34 : poSrcLayer->GetFIDColumn());
4657 34 : bPreserveFID = true;
4658 : }
4659 : else
4660 : {
4661 1 : CPLDebug("GDALVectorTranslate",
4662 : "Using FID=%s and disable -preserve_fid because not "
4663 : "compatible with -explodecollection",
4664 1 : poSrcLayer->GetFIDColumn());
4665 1 : bPreserveFID = false;
4666 : }
4667 : }
4668 : // Detect scenario of converting from GPX to a format like GPKG
4669 : // Cf https://github.com/OSGeo/gdal/issues/9225
4670 764 : else if (!bPreserveFID && !m_bUnsetFid && !bAppend &&
4671 761 : m_poSrcDS->GetDriver() &&
4672 761 : EQUAL(m_poSrcDS->GetDriver()->GetDescription(), "GPX") &&
4673 5 : pszDestCreationOptions &&
4674 5 : (strstr(pszDestCreationOptions, "='FID'") != nullptr ||
4675 1533 : strstr(pszDestCreationOptions, "=\"FID\"") != nullptr) &&
4676 5 : CSLFetchNameValue(m_papszLCO, "FID") == nullptr)
4677 : {
4678 5 : CPLDebug("GDALVectorTranslate",
4679 : "Forcing -preserve_fid because source is GPX and layers "
4680 : "have FID cross references");
4681 5 : bPreserveFID = true;
4682 : }
4683 : // Detect scenario of converting GML2 with fid attribute to GPKG
4684 807 : else if (EQUAL(m_poDstDS->GetDriver()->GetDescription(), "GPKG") &&
4685 43 : CSLFetchNameValue(m_papszLCO, "FID") == nullptr)
4686 : {
4687 43 : int nFieldIdx = poSrcLayer->GetLayerDefn()->GetFieldIndex("fid");
4688 44 : if (nFieldIdx >= 0 && poSrcLayer->GetLayerDefn()
4689 1 : ->GetFieldDefn(nFieldIdx)
4690 1 : ->GetType() == OFTString)
4691 : {
4692 1 : CPLDebug("GDALVectorTranslate",
4693 : "Source layer has a non-string 'fid' column. Using "
4694 : "FID=gpkg_fid for GeoPackage");
4695 1 : papszLCOTemp = CSLSetNameValue(papszLCOTemp, "FID", "gpkg_fid");
4696 : }
4697 : }
4698 :
4699 : // If bAddOverwriteLCO is ON (set up when overwriting a CARTO layer),
4700 : // set OVERWRITE to YES so the new layer overwrites the old one
4701 804 : if (bAddOverwriteLCO)
4702 : {
4703 0 : papszLCOTemp = CSLSetNameValue(papszLCOTemp, "OVERWRITE", "ON");
4704 0 : CPLDebug("GDALVectorTranslate", "Using OVERWRITE=ON");
4705 : }
4706 :
4707 2411 : if (m_bNativeData &&
4708 803 : poSrcLayer->GetMetadataItem("NATIVE_DATA", "NATIVE_DATA") !=
4709 25 : nullptr &&
4710 25 : poSrcLayer->GetMetadataItem("NATIVE_MEDIA_TYPE", "NATIVE_DATA") !=
4711 25 : nullptr &&
4712 25 : pszDestCreationOptions != nullptr &&
4713 1632 : strstr(pszDestCreationOptions, "NATIVE_DATA") != nullptr &&
4714 25 : strstr(pszDestCreationOptions, "NATIVE_MEDIA_TYPE") != nullptr)
4715 : {
4716 25 : papszLCOTemp = CSLSetNameValue(
4717 : papszLCOTemp, "NATIVE_DATA",
4718 25 : poSrcLayer->GetMetadataItem("NATIVE_DATA", "NATIVE_DATA"));
4719 : papszLCOTemp =
4720 25 : CSLSetNameValue(papszLCOTemp, "NATIVE_MEDIA_TYPE",
4721 : poSrcLayer->GetMetadataItem("NATIVE_MEDIA_TYPE",
4722 25 : "NATIVE_DATA"));
4723 25 : CPLDebug("GDALVectorTranslate", "Transferring layer NATIVE_DATA");
4724 : }
4725 :
4726 : // For FileGeodatabase, automatically set
4727 : // CREATE_SHAPE_AREA_AND_LENGTH_FIELDS=YES creation option if the source
4728 : // layer has a Shape_Area/Shape_Length field
4729 1587 : if (pszDestCreationOptions &&
4730 783 : strstr(pszDestCreationOptions,
4731 1587 : "CREATE_SHAPE_AREA_AND_LENGTH_FIELDS") != nullptr &&
4732 14 : CSLFetchNameValue(m_papszLCO,
4733 : "CREATE_SHAPE_AREA_AND_LENGTH_FIELDS") == nullptr)
4734 : {
4735 14 : const auto poSrcLayerDefn = poSrcLayer->GetLayerDefn();
4736 : const int nIdxShapeArea =
4737 14 : poSrcLayerDefn->GetFieldIndex("Shape_Area");
4738 : const int nIdxShapeLength =
4739 14 : poSrcLayerDefn->GetFieldIndex("Shape_Length");
4740 16 : if ((nIdxShapeArea >= 0 &&
4741 2 : poSrcLayerDefn->GetFieldDefn(nIdxShapeArea)->GetDefault() !=
4742 2 : nullptr &&
4743 2 : EQUAL(
4744 : poSrcLayerDefn->GetFieldDefn(nIdxShapeArea)->GetDefault(),
4745 2 : "FILEGEODATABASE_SHAPE_AREA") &&
4746 2 : (m_papszSelFields == nullptr ||
4747 18 : CSLFindString(m_papszSelFields, "Shape_Area") >= 0)) ||
4748 2 : (nIdxShapeLength >= 0 &&
4749 2 : poSrcLayerDefn->GetFieldDefn(nIdxShapeLength)->GetDefault() !=
4750 2 : nullptr &&
4751 2 : EQUAL(poSrcLayerDefn->GetFieldDefn(nIdxShapeLength)
4752 : ->GetDefault(),
4753 2 : "FILEGEODATABASE_SHAPE_LENGTH") &&
4754 2 : (m_papszSelFields == nullptr ||
4755 0 : CSLFindString(m_papszSelFields, "Shape_Length") >= 0)))
4756 : {
4757 4 : papszLCOTemp = CSLSetNameValue(
4758 : papszLCOTemp, "CREATE_SHAPE_AREA_AND_LENGTH_FIELDS", "YES");
4759 4 : CPLDebug("GDALVectorTranslate",
4760 : "Setting CREATE_SHAPE_AREA_AND_LENGTH_FIELDS=YES");
4761 : }
4762 : }
4763 :
4764 : OGRGeomFieldDefn oGeomFieldDefn(
4765 : osGeomFieldName.c_str(),
4766 804 : static_cast<OGRwkbGeometryType>(eGCreateLayerType));
4767 804 : oGeomFieldDefn.SetSpatialRef(poOutputSRS);
4768 804 : oGeomFieldDefn.SetCoordinatePrecision(oCoordPrec);
4769 804 : oGeomFieldDefn.SetNullable(bGeomFieldNullable);
4770 804 : poDstLayer = m_poDstDS->CreateLayer(
4771 : pszNewLayerName,
4772 : eGCreateLayerType == wkbNone ? nullptr : &oGeomFieldDefn,
4773 : papszLCOTemp);
4774 804 : CSLDestroy(papszLCOTemp);
4775 :
4776 804 : if (poDstLayer == nullptr)
4777 : {
4778 2 : return nullptr;
4779 : }
4780 :
4781 : // Cf https://github.com/OSGeo/gdal/issues/6859
4782 : // warn if the user requests -t_srs but the driver uses a different SRS.
4783 836 : if (m_poOutputSRS != nullptr && m_bTransform && !psOptions->bQuiet &&
4784 : // MapInfo is somewhat lossy regarding SRS, so do not warn
4785 34 : !EQUAL(m_poDstDS->GetDriver()->GetDescription(), "MapInfo File"))
4786 : {
4787 34 : auto poCreatedSRS = poDstLayer->GetSpatialRef();
4788 34 : if (poCreatedSRS != nullptr)
4789 : {
4790 20 : const char *const apszOptions[] = {
4791 : "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES",
4792 : "CRITERION=EQUIVALENT", nullptr};
4793 20 : if (!poCreatedSRS->IsSame(m_poOutputSRS, apszOptions))
4794 : {
4795 1 : const char *pszTargetSRSName = m_poOutputSRS->GetName();
4796 1 : const char *pszCreatedSRSName = poCreatedSRS->GetName();
4797 1 : CPLError(CE_Warning, CPLE_AppDefined,
4798 : "Target SRS %s not taken into account as target "
4799 : "driver likely implements on-the-fly reprojection "
4800 : "to %s",
4801 : pszTargetSRSName ? pszTargetSRSName : "",
4802 : pszCreatedSRSName ? pszCreatedSRSName : "");
4803 : }
4804 : }
4805 : }
4806 :
4807 802 : if (m_bCopyMD)
4808 : {
4809 1596 : const CPLStringList aosDomains(poSrcLayer->GetMetadataDomainList());
4810 1150 : for (const char *pszMD : aosDomains)
4811 : {
4812 352 : if (!EQUAL(pszMD, "IMAGE_STRUCTURE") &&
4813 352 : !EQUAL(pszMD, "SUBDATASETS"))
4814 : {
4815 352 : if (char **papszMD = poSrcLayer->GetMetadata(pszMD))
4816 338 : poDstLayer->SetMetadata(papszMD, pszMD);
4817 : }
4818 : }
4819 : }
4820 :
4821 813 : if (anRequestedGeomFields.empty() && nSrcGeomFieldCount > 1 &&
4822 11 : m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
4823 : {
4824 135 : for (int i = 0; i < nSrcGeomFieldCount; i++)
4825 : {
4826 125 : anRequestedGeomFields.push_back(i);
4827 : }
4828 : }
4829 :
4830 1629 : if (anRequestedGeomFields.size() > 1 ||
4831 791 : (anRequestedGeomFields.size() == 1 &&
4832 36 : m_poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer)))
4833 : {
4834 208 : for (int i = 0; i < static_cast<int>(anRequestedGeomFields.size());
4835 : i++)
4836 : {
4837 162 : const int iSrcGeomField = anRequestedGeomFields[i];
4838 : OGRGeomFieldDefn oGFldDefn(
4839 324 : poSrcFDefn->GetGeomFieldDefn(iSrcGeomField));
4840 162 : if (m_poOutputSRS != nullptr)
4841 : {
4842 13 : auto poOutputSRSClone = m_poOutputSRS->Clone();
4843 13 : oGFldDefn.SetSpatialRef(poOutputSRSClone);
4844 13 : poOutputSRSClone->Release();
4845 : }
4846 162 : if (bForceGType)
4847 : {
4848 1 : oGFldDefn.SetType(static_cast<OGRwkbGeometryType>(eGType));
4849 : }
4850 : else
4851 : {
4852 161 : eGType = oGFldDefn.GetType();
4853 161 : eGType =
4854 161 : ConvertType(m_eGeomTypeConversion,
4855 : static_cast<OGRwkbGeometryType>(eGType));
4856 161 : eGType = ForceCoordDimension(eGType, m_nCoordDim);
4857 161 : oGFldDefn.SetType(static_cast<OGRwkbGeometryType>(eGType));
4858 : }
4859 162 : if (m_bForceNullable)
4860 2 : oGFldDefn.SetNullable(TRUE);
4861 162 : poDstLayer->CreateGeomField(&oGFldDefn);
4862 : }
4863 : }
4864 :
4865 802 : bAppend = false;
4866 : }
4867 :
4868 : /* -------------------------------------------------------------------- */
4869 : /* Otherwise we will append to it, if append was requested. */
4870 : /* -------------------------------------------------------------------- */
4871 41 : else if (!bAppend && !m_bNewDataSource)
4872 : {
4873 0 : CPLError(CE_Failure, CPLE_AppDefined,
4874 : "Layer %s already exists, and -append not specified.\n"
4875 : " Consider using -append, or -overwrite.",
4876 : pszNewLayerName);
4877 0 : return nullptr;
4878 : }
4879 : else
4880 : {
4881 41 : if (CSLCount(m_papszLCO) > 0)
4882 : {
4883 0 : CPLError(
4884 : CE_Warning, CPLE_AppDefined,
4885 : "Layer creation options ignored since an existing layer is\n"
4886 : " being appended to.");
4887 : }
4888 : }
4889 :
4890 : /* -------------------------------------------------------------------- */
4891 : /* Process Layer style table */
4892 : /* -------------------------------------------------------------------- */
4893 :
4894 843 : poDstLayer->SetStyleTable(poSrcLayer->GetStyleTable());
4895 : /* -------------------------------------------------------------------- */
4896 : /* Add fields. Default to copy all field. */
4897 : /* If only a subset of all fields requested, then output only */
4898 : /* the selected fields, and in the order that they were */
4899 : /* selected. */
4900 : /* -------------------------------------------------------------------- */
4901 843 : const int nSrcFieldCount = poSrcFDefn->GetFieldCount();
4902 843 : int iSrcFIDField = -1;
4903 :
4904 : // Initialize the index-to-index map to -1's
4905 1686 : std::vector<int> anMap(nSrcFieldCount, -1);
4906 :
4907 1686 : std::map<int, TargetLayerInfo::ResolvedInfo> oMapResolved;
4908 :
4909 : /* Determine if NUMERIC field width narrowing is allowed */
4910 843 : auto poSrcDriver = m_poSrcDS->GetDriver();
4911 : const char *pszSrcWidthIncludesDecimalSeparator{
4912 1686 : poSrcDriver ? poSrcDriver->GetMetadataItem(
4913 843 : "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_DECIMAL_SEPARATOR")
4914 843 : : nullptr};
4915 843 : const bool bSrcWidthIncludesDecimalSeparator{
4916 1071 : pszSrcWidthIncludesDecimalSeparator &&
4917 228 : EQUAL(pszSrcWidthIncludesDecimalSeparator, "YES")};
4918 : const char *pszDstWidthIncludesDecimalSeparator{
4919 843 : m_poDstDS->GetDriver()->GetMetadataItem(
4920 843 : "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_DECIMAL_SEPARATOR")};
4921 843 : const bool bDstWidthIncludesDecimalSeparator{
4922 988 : pszDstWidthIncludesDecimalSeparator &&
4923 145 : EQUAL(pszDstWidthIncludesDecimalSeparator, "YES")};
4924 : const char *pszSrcWidthIncludesMinusSign{
4925 1686 : poSrcDriver ? poSrcDriver->GetMetadataItem(
4926 843 : "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_SIGN")
4927 843 : : nullptr};
4928 843 : const bool bSrcWidthIncludesMinusSign{
4929 1071 : pszSrcWidthIncludesMinusSign &&
4930 228 : EQUAL(pszSrcWidthIncludesMinusSign, "YES")};
4931 : const char *pszDstWidthIncludesMinusSign{
4932 843 : m_poDstDS->GetDriver()->GetMetadataItem(
4933 843 : "DMD_NUMERIC_FIELD_WIDTH_INCLUDES_SIGN")};
4934 843 : const bool bDstWidthIncludesMinusSign{
4935 988 : pszDstWidthIncludesMinusSign &&
4936 145 : EQUAL(pszDstWidthIncludesMinusSign, "YES")};
4937 :
4938 : // Calculate width delta
4939 843 : int iChangeWidthBy{0};
4940 :
4941 843 : if (bSrcWidthIncludesDecimalSeparator && !bDstWidthIncludesDecimalSeparator)
4942 : {
4943 132 : iChangeWidthBy--;
4944 : }
4945 711 : else if (!bSrcWidthIncludesDecimalSeparator &&
4946 : bDstWidthIncludesDecimalSeparator)
4947 : {
4948 49 : iChangeWidthBy++;
4949 : }
4950 :
4951 : // We cannot assume there is no minus sign, we can only inflate here
4952 843 : if (!bSrcWidthIncludesMinusSign && bDstWidthIncludesMinusSign)
4953 : {
4954 49 : iChangeWidthBy++;
4955 : }
4956 :
4957 843 : bool bError = false;
4958 1686 : OGRArrowArrayStream streamSrc;
4959 : const bool bUseWriteArrowBatch =
4960 843 : CanUseWriteArrowBatch(poSrcLayer, poDstLayer, bJustCreatedLayer,
4961 : psOptions, bPreserveFID, bError, streamSrc);
4962 843 : if (bError)
4963 0 : return nullptr;
4964 :
4965 : /* Caution : at the time of writing, the MapInfo driver */
4966 : /* returns NULL until a field has been added */
4967 843 : OGRFeatureDefn *poDstFDefn = poDstLayer->GetLayerDefn();
4968 :
4969 843 : if (bUseWriteArrowBatch)
4970 : {
4971 : // Fields created above
4972 : }
4973 701 : else if (m_papszFieldMap && bAppend)
4974 : {
4975 2 : bool bIdentity = false;
4976 :
4977 2 : if (EQUAL(m_papszFieldMap[0], "identity"))
4978 1 : bIdentity = true;
4979 1 : else if (CSLCount(m_papszFieldMap) != nSrcFieldCount)
4980 : {
4981 0 : CPLError(
4982 : CE_Failure, CPLE_AppDefined,
4983 : "Field map should contain the value 'identity' or "
4984 : "the same number of integer values as the source field count.");
4985 0 : return nullptr;
4986 : }
4987 :
4988 32 : for (int iField = 0; iField < nSrcFieldCount; iField++)
4989 : {
4990 30 : anMap[iField] = bIdentity ? iField : atoi(m_papszFieldMap[iField]);
4991 30 : if (anMap[iField] >= poDstFDefn->GetFieldCount())
4992 : {
4993 0 : CPLError(CE_Failure, CPLE_AppDefined,
4994 0 : "Invalid destination field index %d.", anMap[iField]);
4995 0 : return nullptr;
4996 : }
4997 2 : }
4998 : }
4999 699 : else if (m_bSelFieldsSet && !bAppend)
5000 : {
5001 15 : int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
5002 40 : for (int iField = 0; m_papszSelFields && m_papszSelFields[iField];
5003 : iField++)
5004 : {
5005 : const int iSrcField =
5006 25 : poSrcFDefn->GetFieldIndex(m_papszSelFields[iField]);
5007 25 : if (iSrcField >= 0)
5008 : {
5009 : OGRFieldDefn *poSrcFieldDefn =
5010 22 : poSrcFDefn->GetFieldDefn(iSrcField);
5011 44 : OGRFieldDefn oFieldDefn(poSrcFieldDefn);
5012 :
5013 22 : DoFieldTypeConversion(
5014 : m_poDstDS, oFieldDefn, m_papszFieldTypesToString,
5015 22 : m_papszMapFieldType, m_bUnsetFieldWidth, psOptions->bQuiet,
5016 22 : m_bForceNullable, m_bUnsetDefault);
5017 :
5018 22 : if (iChangeWidthBy != 0 && oFieldDefn.GetType() == OFTReal &&
5019 0 : oFieldDefn.GetWidth() != 0)
5020 : {
5021 0 : oFieldDefn.SetWidth(oFieldDefn.GetWidth() + iChangeWidthBy);
5022 : }
5023 :
5024 : /* The field may have been already created at layer creation */
5025 : const int iDstField =
5026 : poDstFDefn
5027 22 : ? poDstFDefn->GetFieldIndex(oFieldDefn.GetNameRef())
5028 22 : : -1;
5029 22 : if (iDstField >= 0)
5030 : {
5031 0 : anMap[iSrcField] = iDstField;
5032 : }
5033 22 : else if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
5034 : {
5035 : /* now that we've created a field, GetLayerDefn() won't
5036 : * return NULL */
5037 22 : if (poDstFDefn == nullptr)
5038 0 : poDstFDefn = poDstLayer->GetLayerDefn();
5039 :
5040 : /* Sanity check : if it fails, the driver is buggy */
5041 44 : if (poDstFDefn != nullptr &&
5042 22 : poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
5043 : {
5044 0 : CPLError(CE_Warning, CPLE_AppDefined,
5045 : "The output driver has claimed to have added "
5046 : "the %s field, but it did not!",
5047 : oFieldDefn.GetNameRef());
5048 : }
5049 : else
5050 : {
5051 22 : anMap[iSrcField] = nDstFieldCount;
5052 22 : nDstFieldCount++;
5053 : }
5054 : }
5055 : }
5056 : }
5057 :
5058 : /* --------------------------------------------------------------------
5059 : */
5060 : /* Use SetIgnoredFields() on source layer if available */
5061 : /* --------------------------------------------------------------------
5062 : */
5063 15 : if (poSrcLayer->TestCapability(OLCIgnoreFields))
5064 : {
5065 10 : bool bUseIgnoredFields = true;
5066 10 : char **papszWHEREUsedFields = nullptr;
5067 :
5068 10 : if (m_pszWHERE)
5069 : {
5070 : /* We must not ignore fields used in the -where expression
5071 : * (#4015) */
5072 4 : OGRFeatureQuery oFeatureQuery;
5073 2 : if (oFeatureQuery.Compile(poSrcLayer->GetLayerDefn(),
5074 : m_pszWHERE, FALSE,
5075 2 : nullptr) == OGRERR_NONE)
5076 : {
5077 0 : papszWHEREUsedFields = oFeatureQuery.GetUsedFields();
5078 : }
5079 : else
5080 : {
5081 2 : bUseIgnoredFields = false;
5082 : }
5083 : }
5084 :
5085 10 : char **papszIgnoredFields = nullptr;
5086 :
5087 32 : for (int iSrcField = 0;
5088 32 : bUseIgnoredFields && iSrcField < poSrcFDefn->GetFieldCount();
5089 : iSrcField++)
5090 : {
5091 : const char *pszFieldName =
5092 22 : poSrcFDefn->GetFieldDefn(iSrcField)->GetNameRef();
5093 22 : bool bFieldRequested = false;
5094 44 : for (int iField = 0;
5095 44 : m_papszSelFields && m_papszSelFields[iField]; iField++)
5096 : {
5097 33 : if (EQUAL(pszFieldName, m_papszSelFields[iField]))
5098 : {
5099 11 : bFieldRequested = true;
5100 11 : break;
5101 : }
5102 : }
5103 22 : bFieldRequested |=
5104 22 : CSLFindString(papszWHEREUsedFields, pszFieldName) >= 0;
5105 22 : bFieldRequested |= (m_pszZField != nullptr &&
5106 0 : EQUAL(pszFieldName, m_pszZField));
5107 :
5108 : /* If source field not requested, add it to ignored files list
5109 : */
5110 22 : if (!bFieldRequested)
5111 : papszIgnoredFields =
5112 11 : CSLAddString(papszIgnoredFields, pszFieldName);
5113 : }
5114 10 : if (bUseIgnoredFields)
5115 8 : poSrcLayer->SetIgnoredFields(
5116 8 : const_cast<const char **>(papszIgnoredFields));
5117 10 : CSLDestroy(papszIgnoredFields);
5118 10 : CSLDestroy(papszWHEREUsedFields);
5119 15 : }
5120 : }
5121 684 : else if (!bAppend || m_bAddMissingFields)
5122 : {
5123 655 : int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
5124 :
5125 : const bool caseInsensitive =
5126 655 : !EQUAL(m_poDstDS->GetDriver()->GetDescription(), "GeoJSON");
5127 12447 : const auto formatName = [caseInsensitive](const char *name)
5128 : {
5129 12447 : if (caseInsensitive)
5130 : {
5131 24230 : return CPLString(name).toupper();
5132 : }
5133 : else
5134 : {
5135 332 : return CPLString(name);
5136 : }
5137 655 : };
5138 :
5139 : /* Save the map of existing fields, before creating new ones */
5140 : /* This helps when converting a source layer that has duplicated field
5141 : * names */
5142 : /* which is a bad idea */
5143 1310 : std::map<CPLString, int> oMapPreExistingFields;
5144 1310 : std::unordered_set<std::string> oSetDstFieldNames;
5145 800 : for (int iField = 0; iField < nDstFieldCount; iField++)
5146 : {
5147 : const char *pszFieldName =
5148 145 : poDstFDefn->GetFieldDefn(iField)->GetNameRef();
5149 290 : CPLString osUpperFieldName(formatName(pszFieldName));
5150 145 : oSetDstFieldNames.insert(osUpperFieldName);
5151 145 : if (oMapPreExistingFields.find(osUpperFieldName) ==
5152 290 : oMapPreExistingFields.end())
5153 145 : oMapPreExistingFields[osUpperFieldName] = iField;
5154 : /*else
5155 : CPLError(CE_Warning, CPLE_AppDefined,
5156 : "The target layer has already a duplicated field name
5157 : '%s' before " "adding the fields of the source layer",
5158 : pszFieldName); */
5159 : }
5160 :
5161 655 : const char *pszFIDColumn = poDstLayer->GetFIDColumn();
5162 :
5163 1310 : std::vector<int> anSrcFieldIndices;
5164 655 : if (m_bSelFieldsSet)
5165 : {
5166 2 : for (int iField = 0; m_papszSelFields && m_papszSelFields[iField];
5167 : iField++)
5168 : {
5169 : const int iSrcField =
5170 1 : poSrcFDefn->GetFieldIndex(m_papszSelFields[iField]);
5171 1 : if (iSrcField >= 0)
5172 : {
5173 1 : anSrcFieldIndices.push_back(iSrcField);
5174 : }
5175 : }
5176 : }
5177 : else
5178 : {
5179 3791 : for (int iField = 0; iField < nSrcFieldCount; iField++)
5180 : {
5181 3137 : anSrcFieldIndices.push_back(iField);
5182 : }
5183 : }
5184 :
5185 1310 : std::unordered_set<std::string> oSetSrcFieldNames;
5186 3794 : for (int i = 0; i < poSrcFDefn->GetFieldCount(); i++)
5187 : {
5188 : oSetSrcFieldNames.insert(
5189 3139 : formatName(poSrcFDefn->GetFieldDefn(i)->GetNameRef()));
5190 : }
5191 :
5192 : // For each source field name, memorize the last number suffix to have
5193 : // unique field names in the target. Let's imagine we have a source
5194 : // layer with the field name foo repeated twice After dealing the first
5195 : // field, oMapFieldNameToLastSuffix["foo"] will be 1, so when starting a
5196 : // unique name for the second field, we'll be able to start at 2. This
5197 : // avoids quadratic complexity if a big number of source field names are
5198 : // identical. Like in
5199 : // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=37768
5200 1310 : std::map<std::string, int> oMapFieldNameToLastSuffix;
5201 :
5202 3793 : for (size_t i = 0; i < anSrcFieldIndices.size(); i++)
5203 : {
5204 3138 : const int iField = anSrcFieldIndices[i];
5205 : const OGRFieldDefn *poSrcFieldDefn =
5206 3138 : poSrcFDefn->GetFieldDefn(iField);
5207 3138 : OGRFieldDefn oFieldDefn(poSrcFieldDefn);
5208 :
5209 : // Avoid creating a field with the same name as the FID column
5210 6277 : if (pszFIDColumn != nullptr &&
5211 3139 : EQUAL(pszFIDColumn, oFieldDefn.GetNameRef()) &&
5212 1 : (oFieldDefn.GetType() == OFTInteger ||
5213 0 : oFieldDefn.GetType() == OFTInteger64))
5214 : {
5215 1 : iSrcFIDField = iField;
5216 1 : continue;
5217 : }
5218 :
5219 3137 : DoFieldTypeConversion(
5220 : m_poDstDS, oFieldDefn, m_papszFieldTypesToString,
5221 3137 : m_papszMapFieldType, m_bUnsetFieldWidth, psOptions->bQuiet,
5222 3137 : m_bForceNullable, m_bUnsetDefault);
5223 :
5224 3278 : if (iChangeWidthBy != 0 && oFieldDefn.GetType() == OFTReal &&
5225 141 : oFieldDefn.GetWidth() != 0)
5226 : {
5227 101 : oFieldDefn.SetWidth(oFieldDefn.GetWidth() + iChangeWidthBy);
5228 : }
5229 :
5230 : /* The field may have been already created at layer creation */
5231 : {
5232 : const auto oIter = oMapPreExistingFields.find(
5233 3137 : formatName(oFieldDefn.GetNameRef()));
5234 3137 : if (oIter != oMapPreExistingFields.end())
5235 : {
5236 115 : anMap[iField] = oIter->second;
5237 115 : continue;
5238 : }
5239 : }
5240 :
5241 3022 : bool bHasRenamed = false;
5242 : /* In case the field name already exists in the target layer, */
5243 : /* build a unique field name */
5244 3022 : if (oSetDstFieldNames.find(formatName(oFieldDefn.GetNameRef())) !=
5245 6044 : oSetDstFieldNames.end())
5246 : {
5247 : const CPLString osTmpNameRaddixUC(
5248 4 : formatName(oFieldDefn.GetNameRef()));
5249 2 : int nTry = 1;
5250 : const auto oIter =
5251 2 : oMapFieldNameToLastSuffix.find(osTmpNameRaddixUC);
5252 2 : if (oIter != oMapFieldNameToLastSuffix.end())
5253 1 : nTry = oIter->second;
5254 2 : CPLString osTmpNameUC = osTmpNameRaddixUC;
5255 2 : osTmpNameUC.reserve(osTmpNameUC.size() + 10);
5256 : while (true)
5257 : {
5258 3 : ++nTry;
5259 : char szTry[32];
5260 3 : snprintf(szTry, sizeof(szTry), "%d", nTry);
5261 : osTmpNameUC.replace(osTmpNameRaddixUC.size(),
5262 3 : std::string::npos, szTry);
5263 :
5264 : /* Check that the proposed name doesn't exist either in the
5265 : * already */
5266 : /* created fields or in the source fields */
5267 3 : if (oSetDstFieldNames.find(osTmpNameUC) ==
5268 9 : oSetDstFieldNames.end() &&
5269 3 : oSetSrcFieldNames.find(osTmpNameUC) ==
5270 6 : oSetSrcFieldNames.end())
5271 : {
5272 2 : bHasRenamed = true;
5273 2 : oFieldDefn.SetName(
5274 4 : (CPLString(oFieldDefn.GetNameRef()) + szTry)
5275 : .c_str());
5276 2 : oMapFieldNameToLastSuffix[osTmpNameRaddixUC] = nTry;
5277 2 : break;
5278 : }
5279 1 : }
5280 : }
5281 :
5282 : // Create field domain in output dataset if not already existing.
5283 6044 : const std::string osDomainName(oFieldDefn.GetDomainName());
5284 3022 : if (!osDomainName.empty())
5285 : {
5286 32 : if (m_poDstDS->TestCapability(ODsCAddFieldDomain) &&
5287 16 : m_poDstDS->GetFieldDomain(osDomainName) == nullptr)
5288 : {
5289 : const auto poSrcDomain =
5290 16 : m_poSrcDS->GetFieldDomain(osDomainName);
5291 16 : if (poSrcDomain)
5292 : {
5293 28 : std::string failureReason;
5294 14 : if (!m_poDstDS->AddFieldDomain(
5295 28 : std::unique_ptr<OGRFieldDomain>(
5296 14 : poSrcDomain->Clone()),
5297 14 : failureReason))
5298 : {
5299 0 : oFieldDefn.SetDomainName(std::string());
5300 0 : CPLDebug("OGR2OGR", "Cannot create domain %s: %s",
5301 : osDomainName.c_str(),
5302 : failureReason.c_str());
5303 : }
5304 : }
5305 : else
5306 : {
5307 2 : CPLDebug("OGR2OGR",
5308 : "Cannot find domain %s in source dataset",
5309 : osDomainName.c_str());
5310 : }
5311 : }
5312 16 : if (m_poDstDS->GetFieldDomain(osDomainName) == nullptr)
5313 : {
5314 2 : oFieldDefn.SetDomainName(std::string());
5315 : }
5316 : }
5317 :
5318 3022 : if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
5319 : {
5320 : /* now that we've created a field, GetLayerDefn() won't return
5321 : * NULL */
5322 3002 : if (poDstFDefn == nullptr)
5323 0 : poDstFDefn = poDstLayer->GetLayerDefn();
5324 :
5325 : /* Sanity check : if it fails, the driver is buggy */
5326 6004 : if (poDstFDefn != nullptr &&
5327 3002 : poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
5328 : {
5329 0 : CPLError(CE_Warning, CPLE_AppDefined,
5330 : "The output driver has claimed to have added the "
5331 : "%s field, but it did not!",
5332 : oFieldDefn.GetNameRef());
5333 : }
5334 : else
5335 : {
5336 3002 : if (poDstFDefn != nullptr)
5337 : {
5338 : const char *pszNewFieldName =
5339 3002 : poDstFDefn->GetFieldDefn(nDstFieldCount)
5340 3002 : ->GetNameRef();
5341 3002 : if (bHasRenamed)
5342 : {
5343 2 : CPLError(CE_Warning, CPLE_AppDefined,
5344 : "Field '%s' already exists. Renaming it "
5345 : "as '%s'",
5346 : poSrcFieldDefn->GetNameRef(),
5347 : pszNewFieldName);
5348 : }
5349 3002 : oSetDstFieldNames.insert(formatName(pszNewFieldName));
5350 : }
5351 :
5352 3002 : anMap[iField] = nDstFieldCount;
5353 3002 : nDstFieldCount++;
5354 : }
5355 : }
5356 :
5357 3022 : if (m_bResolveDomains && !osDomainName.empty())
5358 : {
5359 : const auto poSrcDomain =
5360 3 : m_poSrcDS->GetFieldDomain(osDomainName);
5361 3 : if (poSrcDomain && poSrcDomain->GetDomainType() == OFDT_CODED)
5362 : {
5363 : OGRFieldDefn oResolvedField(
5364 : CPLSPrintf("%s_resolved", oFieldDefn.GetNameRef()),
5365 2 : OFTString);
5366 1 : if (poDstLayer->CreateField(&oResolvedField) == OGRERR_NONE)
5367 : {
5368 : TargetLayerInfo::ResolvedInfo resolvedInfo;
5369 1 : resolvedInfo.nSrcField = iField;
5370 1 : resolvedInfo.poDomain = poSrcDomain;
5371 1 : oMapResolved[nDstFieldCount] = resolvedInfo;
5372 1 : nDstFieldCount++;
5373 : }
5374 : }
5375 : }
5376 655 : }
5377 : }
5378 : else
5379 : {
5380 : /* For an existing layer, build the map by fetching the index in the
5381 : * destination */
5382 : /* layer for each source field */
5383 29 : if (poDstFDefn == nullptr)
5384 : {
5385 0 : CPLError(CE_Failure, CPLE_AppDefined, "poDstFDefn == NULL.");
5386 0 : return nullptr;
5387 : }
5388 :
5389 95 : for (int iField = 0; iField < nSrcFieldCount; iField++)
5390 : {
5391 66 : OGRFieldDefn *poSrcFieldDefn = poSrcFDefn->GetFieldDefn(iField);
5392 66 : const int iDstField = poDstLayer->FindFieldIndex(
5393 66 : poSrcFieldDefn->GetNameRef(), m_bExactFieldNameMatch);
5394 66 : if (iDstField >= 0)
5395 62 : anMap[iField] = iDstField;
5396 : else
5397 : {
5398 4 : if (m_bExactFieldNameMatch)
5399 : {
5400 4 : const int iDstFieldCandidate = poDstLayer->FindFieldIndex(
5401 4 : poSrcFieldDefn->GetNameRef(), false);
5402 4 : if (iDstFieldCandidate >= 0)
5403 : {
5404 1 : CPLError(CE_Warning, CPLE_AppDefined,
5405 : "Source field '%s' could have been identified "
5406 : "with existing field '%s' of destination "
5407 : "layer '%s' if the -relaxedFieldNameMatch "
5408 : "option had been specified.",
5409 : poSrcFieldDefn->GetNameRef(),
5410 1 : poDstLayer->GetLayerDefn()
5411 1 : ->GetFieldDefn(iDstFieldCandidate)
5412 : ->GetNameRef(),
5413 1 : poDstLayer->GetName());
5414 : }
5415 : }
5416 :
5417 4 : CPLDebug(
5418 : "GDALVectorTranslate",
5419 : "Skipping field '%s' not found in destination layer '%s'.",
5420 4 : poSrcFieldDefn->GetNameRef(), poDstLayer->GetName());
5421 : }
5422 : }
5423 : }
5424 :
5425 12 : if (bOverwriteActuallyDone && !bAddOverwriteLCO &&
5426 12 : EQUAL(m_poDstDS->GetDriver()->GetDescription(), "PostgreSQL") &&
5427 861 : !psOptions->nLayerTransaction && psOptions->nGroupTransactions > 0 &&
5428 6 : CPLTestBool(CPLGetConfigOption("PG_COMMIT_WHEN_OVERWRITING", "YES")))
5429 : {
5430 6 : CPLDebug("GDALVectorTranslate",
5431 : "Forcing transaction commit as table overwriting occurred");
5432 : // Commit when overwriting as this consumes a lot of PG resources
5433 : // and could result in """out of shared memory.
5434 : // You might need to increase max_locks_per_transaction."""" errors
5435 12 : if (m_poDstDS->CommitTransaction() == OGRERR_FAILURE ||
5436 6 : m_poDstDS->StartTransaction(psOptions->bForceTransaction) ==
5437 : OGRERR_FAILURE)
5438 : {
5439 0 : return nullptr;
5440 : }
5441 6 : nTotalEventsDone = 0;
5442 : }
5443 :
5444 1686 : auto psInfo = std::make_unique<TargetLayerInfo>();
5445 843 : psInfo->m_bUseWriteArrowBatch = bUseWriteArrowBatch;
5446 843 : psInfo->m_nFeaturesRead = 0;
5447 843 : psInfo->m_bPerFeatureCT = false;
5448 843 : psInfo->m_poSrcLayer = poSrcLayer;
5449 843 : psInfo->m_poDstLayer = poDstLayer;
5450 843 : psInfo->m_aoReprojectionInfo.resize(
5451 843 : poDstLayer->GetLayerDefn()->GetGeomFieldCount());
5452 843 : psInfo->m_anMap = std::move(anMap);
5453 843 : psInfo->m_iSrcZField = iSrcZField;
5454 843 : psInfo->m_iSrcFIDField = iSrcFIDField;
5455 843 : if (anRequestedGeomFields.size() == 1)
5456 36 : psInfo->m_iRequestedSrcGeomField = anRequestedGeomFields[0];
5457 : else
5458 807 : psInfo->m_iRequestedSrcGeomField = -1;
5459 843 : psInfo->m_bPreserveFID = bPreserveFID;
5460 843 : psInfo->m_pszCTPipeline = m_pszCTPipeline;
5461 843 : psInfo->m_oMapResolved = std::move(oMapResolved);
5462 844 : for (const auto &kv : psInfo->m_oMapResolved)
5463 : {
5464 1 : const auto poDomain = kv.second.poDomain;
5465 : const auto poCodedDomain =
5466 1 : cpl::down_cast<const OGRCodedFieldDomain *>(poDomain);
5467 1 : const auto enumeration = poCodedDomain->GetEnumeration();
5468 2 : std::map<std::string, std::string> oMapCodeValue;
5469 4 : for (int i = 0; enumeration[i].pszCode != nullptr; ++i)
5470 : {
5471 6 : oMapCodeValue[enumeration[i].pszCode] =
5472 6 : enumeration[i].pszValue ? enumeration[i].pszValue : "";
5473 : }
5474 1 : psInfo->m_oMapDomainToKV[poDomain] = std::move(oMapCodeValue);
5475 : }
5476 :
5477 : // Detect if we can directly pass the source feature to the CreateFeature()
5478 : // method of the target layer, without doing any copying of field content.
5479 843 : psInfo->m_bCanAvoidSetFrom = false;
5480 843 : if (!m_bExplodeCollections && iSrcZField == -1 && poDstFDefn != nullptr)
5481 : {
5482 828 : psInfo->m_bCanAvoidSetFrom = true;
5483 828 : const int nDstGeomFieldCount = poDstFDefn->GetGeomFieldCount();
5484 828 : if (nSrcFieldCount != poDstFDefn->GetFieldCount() ||
5485 : nSrcGeomFieldCount != nDstGeomFieldCount)
5486 : {
5487 157 : psInfo->m_bCanAvoidSetFrom = false;
5488 : }
5489 : else
5490 : {
5491 3436 : for (int i = 0; i < nSrcFieldCount; ++i)
5492 : {
5493 2797 : auto poSrcFieldDefn = poSrcFDefn->GetFieldDefn(i);
5494 2797 : auto poDstFieldDefn = poDstFDefn->GetFieldDefn(i);
5495 5580 : if (poSrcFieldDefn->GetType() != poDstFieldDefn->GetType() ||
5496 2783 : psInfo->m_anMap[i] != i)
5497 : {
5498 32 : psInfo->m_bCanAvoidSetFrom = false;
5499 32 : break;
5500 : }
5501 : }
5502 671 : if (!psInfo->m_bCanAvoidSetFrom && nSrcGeomFieldCount > 1)
5503 : {
5504 4 : for (int i = 0; i < nSrcGeomFieldCount; ++i)
5505 : {
5506 3 : auto poSrcGeomFieldDefn = poSrcFDefn->GetGeomFieldDefn(i);
5507 3 : auto poDstGeomFieldDefn = poDstFDefn->GetGeomFieldDefn(i);
5508 3 : if (!EQUAL(poSrcGeomFieldDefn->GetNameRef(),
5509 : poDstGeomFieldDefn->GetNameRef()))
5510 : {
5511 1 : psInfo->m_bCanAvoidSetFrom = false;
5512 1 : break;
5513 : }
5514 : }
5515 : }
5516 : }
5517 : }
5518 :
5519 1686 : psInfo->m_pszSpatSRSDef = psOptions->osSpatSRSDef.empty()
5520 843 : ? nullptr
5521 4 : : psOptions->osSpatSRSDef.c_str();
5522 843 : psInfo->m_hSpatialFilter =
5523 843 : OGRGeometry::ToHandle(psOptions->poSpatialFilter.get());
5524 843 : psInfo->m_pszGeomField =
5525 843 : psOptions->bGeomFieldSet ? psOptions->osGeomField.c_str() : nullptr;
5526 :
5527 843 : if (psOptions->nTZOffsetInSec != TZ_OFFSET_INVALID && poDstFDefn)
5528 : {
5529 15 : for (int i = 0; i < poDstFDefn->GetFieldCount(); ++i)
5530 : {
5531 10 : if (poDstFDefn->GetFieldDefn(i)->GetType() == OFTDateTime)
5532 : {
5533 5 : psInfo->m_anDateTimeFieldIdx.push_back(i);
5534 : }
5535 : }
5536 : }
5537 :
5538 843 : psInfo->m_bSupportCurves =
5539 843 : CPL_TO_BOOL(poDstLayer->TestCapability(OLCCurveGeometries));
5540 :
5541 843 : psInfo->m_sArrowArrayStream = std::move(streamSrc);
5542 :
5543 843 : return psInfo;
5544 : }
5545 :
5546 : /************************************************************************/
5547 : /* SetupCT() */
5548 : /************************************************************************/
5549 :
5550 : static bool
5551 677 : SetupCT(TargetLayerInfo *psInfo, OGRLayer *poSrcLayer, bool bTransform,
5552 : bool bWrapDateline, const CPLString &osDateLineOffset,
5553 : const OGRSpatialReference *poUserSourceSRS, OGRFeature *poFeature,
5554 : const OGRSpatialReference *poOutputSRS,
5555 : OGRCoordinateTransformation *poGCPCoordTrans, bool bVerboseError)
5556 : {
5557 677 : OGRLayer *poDstLayer = psInfo->m_poDstLayer;
5558 : const int nDstGeomFieldCount =
5559 677 : poDstLayer->GetLayerDefn()->GetGeomFieldCount();
5560 1310 : for (int iGeom = 0; iGeom < nDstGeomFieldCount; iGeom++)
5561 : {
5562 : /* --------------------------------------------------------------------
5563 : */
5564 : /* Setup coordinate transformation if we need it. */
5565 : /* --------------------------------------------------------------------
5566 : */
5567 634 : const OGRSpatialReference *poSourceSRS = nullptr;
5568 634 : OGRCoordinateTransformation *poCT = nullptr;
5569 634 : char **papszTransformOptions = nullptr;
5570 :
5571 : int iSrcGeomField;
5572 : auto poDstGeomFieldDefn =
5573 634 : poDstLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom);
5574 634 : if (psInfo->m_iRequestedSrcGeomField >= 0)
5575 : {
5576 34 : iSrcGeomField = psInfo->m_iRequestedSrcGeomField;
5577 : }
5578 : else
5579 : {
5580 1200 : iSrcGeomField = poSrcLayer->GetLayerDefn()->GetGeomFieldIndex(
5581 600 : poDstGeomFieldDefn->GetNameRef());
5582 600 : if (iSrcGeomField < 0)
5583 : {
5584 238 : if (nDstGeomFieldCount == 1 &&
5585 119 : poSrcLayer->GetLayerDefn()->GetGeomFieldCount() > 0)
5586 : {
5587 113 : iSrcGeomField = 0;
5588 : }
5589 : else
5590 : {
5591 6 : continue;
5592 : }
5593 : }
5594 : }
5595 :
5596 628 : if (psInfo->m_nFeaturesRead == 0)
5597 : {
5598 627 : poSourceSRS = poUserSourceSRS;
5599 627 : if (poSourceSRS == nullptr)
5600 : {
5601 619 : if (iSrcGeomField > 0)
5602 118 : poSourceSRS = poSrcLayer->GetLayerDefn()
5603 118 : ->GetGeomFieldDefn(iSrcGeomField)
5604 118 : ->GetSpatialRef();
5605 : else
5606 501 : poSourceSRS = poSrcLayer->GetSpatialRef();
5607 : }
5608 : }
5609 628 : if (poSourceSRS == nullptr)
5610 : {
5611 262 : if (poFeature == nullptr)
5612 : {
5613 1 : if (bVerboseError)
5614 : {
5615 0 : CPLError(CE_Failure, CPLE_AppDefined,
5616 : "Non-null feature expected to set transformation");
5617 : }
5618 1 : return false;
5619 : }
5620 : OGRGeometry *poSrcGeometry =
5621 261 : poFeature->GetGeomFieldRef(iSrcGeomField);
5622 261 : if (poSrcGeometry)
5623 217 : poSourceSRS = poSrcGeometry->getSpatialReference();
5624 261 : psInfo->m_bPerFeatureCT = (bTransform || bWrapDateline);
5625 : }
5626 :
5627 627 : if (bTransform)
5628 : {
5629 36 : if (poSourceSRS == nullptr && psInfo->m_pszCTPipeline == nullptr)
5630 : {
5631 0 : CPLError(CE_Failure, CPLE_AppDefined,
5632 : "Can't transform coordinates, source layer has no\n"
5633 : "coordinate system. Use -s_srs to set one.");
5634 :
5635 0 : return false;
5636 : }
5637 :
5638 36 : if (psInfo->m_pszCTPipeline == nullptr)
5639 : {
5640 33 : CPLAssert(nullptr != poSourceSRS);
5641 33 : CPLAssert(nullptr != poOutputSRS);
5642 : }
5643 :
5644 36 : if (psInfo->m_nFeaturesRead == 0 && !psInfo->m_bPerFeatureCT)
5645 : {
5646 : const auto &supportedSRSList =
5647 34 : poSrcLayer->GetSupportedSRSList(iGeom);
5648 34 : if (!supportedSRSList.empty())
5649 : {
5650 1 : const char *const apszOptions[] = {
5651 : "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES", nullptr};
5652 1 : for (const auto &poSRS : supportedSRSList)
5653 : {
5654 1 : if (poSRS->IsSame(poOutputSRS, apszOptions))
5655 : {
5656 2 : OGRSpatialReference oSourceSRSBackup;
5657 1 : if (poSourceSRS)
5658 1 : oSourceSRSBackup = *poSourceSRS;
5659 1 : if (poSrcLayer->SetActiveSRS(iGeom, poSRS.get()) ==
5660 : OGRERR_NONE)
5661 : {
5662 1 : CPLDebug("ogr2ogr",
5663 : "Switching layer active SRS to %s",
5664 : poSRS->GetName());
5665 :
5666 1 : if (psInfo->m_hSpatialFilter != nullptr &&
5667 0 : ((psInfo->m_iRequestedSrcGeomField < 0 &&
5668 0 : iGeom == 0) ||
5669 : (iGeom ==
5670 0 : psInfo->m_iRequestedSrcGeomField)))
5671 : {
5672 0 : OGRSpatialReference oSpatSRS;
5673 0 : oSpatSRS.SetAxisMappingStrategy(
5674 : OAMS_TRADITIONAL_GIS_ORDER);
5675 0 : if (psInfo->m_pszSpatSRSDef)
5676 0 : oSpatSRS.SetFromUserInput(
5677 : psInfo->m_pszSpatSRSDef);
5678 0 : ApplySpatialFilter(
5679 : poSrcLayer,
5680 : OGRGeometry::FromHandle(
5681 : psInfo->m_hSpatialFilter),
5682 0 : !oSpatSRS.IsEmpty() ? &oSpatSRS
5683 0 : : !oSourceSRSBackup.IsEmpty()
5684 : ? &oSourceSRSBackup
5685 : : nullptr,
5686 : psInfo->m_pszGeomField, poOutputSRS);
5687 : }
5688 :
5689 1 : bTransform = false;
5690 : }
5691 1 : break;
5692 : }
5693 : }
5694 : }
5695 : }
5696 :
5697 36 : if (!bTransform)
5698 : {
5699 : // do nothing
5700 : }
5701 36 : else if (psInfo->m_aoReprojectionInfo[iGeom].m_poCT != nullptr &&
5702 1 : psInfo->m_aoReprojectionInfo[iGeom]
5703 1 : .m_poCT->GetSourceCS() == poSourceSRS)
5704 : {
5705 0 : poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
5706 : }
5707 : else
5708 : {
5709 35 : OGRCoordinateTransformationOptions options;
5710 35 : if (psInfo->m_pszCTPipeline)
5711 : {
5712 3 : options.SetCoordinateOperation(psInfo->m_pszCTPipeline,
5713 : false);
5714 : }
5715 35 : poCT = OGRCreateCoordinateTransformation(poSourceSRS,
5716 : poOutputSRS, options);
5717 35 : if (poCT == nullptr)
5718 : {
5719 0 : char *pszWKT = nullptr;
5720 :
5721 0 : CPLError(CE_Failure, CPLE_AppDefined,
5722 : "Failed to create coordinate transformation "
5723 : "between the\n"
5724 : "following coordinate systems. This may be "
5725 : "because they\n"
5726 : "are not transformable.");
5727 :
5728 0 : if (poSourceSRS)
5729 : {
5730 0 : poSourceSRS->exportToPrettyWkt(&pszWKT, FALSE);
5731 0 : CPLError(CE_Failure, CPLE_AppDefined, "Source:\n%s",
5732 : pszWKT);
5733 0 : CPLFree(pszWKT);
5734 : }
5735 :
5736 0 : if (poOutputSRS)
5737 : {
5738 0 : poOutputSRS->exportToPrettyWkt(&pszWKT, FALSE);
5739 0 : CPLError(CE_Failure, CPLE_AppDefined, "Target:\n%s",
5740 : pszWKT);
5741 0 : CPLFree(pszWKT);
5742 : }
5743 :
5744 0 : return false;
5745 : }
5746 35 : poCT = new CompositeCT(poGCPCoordTrans, false, poCT, true);
5747 35 : psInfo->m_aoReprojectionInfo[iGeom].m_poCT.reset(poCT);
5748 35 : psInfo->m_aoReprojectionInfo[iGeom].m_bCanInvalidateValidity =
5749 69 : !(poGCPCoordTrans == nullptr && poSourceSRS &&
5750 34 : poSourceSRS->IsGeographic() && poOutputSRS &&
5751 3 : poOutputSRS->IsGeographic());
5752 : }
5753 : }
5754 : else
5755 : {
5756 591 : const char *const apszOptions[] = {
5757 : "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES",
5758 : "CRITERION=EQUIVALENT", nullptr};
5759 : auto poDstGeomFieldDefnSpatialRef =
5760 591 : poDstGeomFieldDefn->GetSpatialRef();
5761 332 : if (poSourceSRS && poDstGeomFieldDefnSpatialRef &&
5762 251 : poSourceSRS->GetDataAxisToSRSAxisMapping() !=
5763 : poDstGeomFieldDefnSpatialRef
5764 923 : ->GetDataAxisToSRSAxisMapping() &&
5765 2 : poSourceSRS->IsSame(poDstGeomFieldDefnSpatialRef, apszOptions))
5766 : {
5767 0 : psInfo->m_aoReprojectionInfo[iGeom].m_poCT.reset(
5768 : new CompositeCT(
5769 0 : new AxisMappingCoordinateTransformation(
5770 0 : poSourceSRS->GetDataAxisToSRSAxisMapping(),
5771 : poDstGeomFieldDefnSpatialRef
5772 0 : ->GetDataAxisToSRSAxisMapping()),
5773 0 : true, poGCPCoordTrans, false));
5774 0 : poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
5775 : }
5776 591 : else if (poGCPCoordTrans)
5777 : {
5778 10 : psInfo->m_aoReprojectionInfo[iGeom].m_poCT.reset(
5779 5 : new CompositeCT(poGCPCoordTrans, false, nullptr, false));
5780 5 : poCT = psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
5781 : }
5782 : }
5783 :
5784 627 : if (bWrapDateline)
5785 : {
5786 5 : if (bTransform && poCT != nullptr && poOutputSRS != nullptr &&
5787 1 : poOutputSRS->IsGeographic())
5788 : {
5789 : papszTransformOptions =
5790 1 : CSLAddString(papszTransformOptions, "WRAPDATELINE=YES");
5791 1 : if (!osDateLineOffset.empty())
5792 : {
5793 1 : CPLString soOffset("DATELINEOFFSET=");
5794 1 : soOffset += osDateLineOffset;
5795 : papszTransformOptions =
5796 1 : CSLAddString(papszTransformOptions, soOffset);
5797 : }
5798 : }
5799 3 : else if (poSourceSRS != nullptr && poSourceSRS->IsGeographic())
5800 : {
5801 : papszTransformOptions =
5802 3 : CSLAddString(papszTransformOptions, "WRAPDATELINE=YES");
5803 3 : if (!osDateLineOffset.empty())
5804 : {
5805 3 : CPLString soOffset("DATELINEOFFSET=");
5806 3 : soOffset += osDateLineOffset;
5807 : papszTransformOptions =
5808 3 : CSLAddString(papszTransformOptions, soOffset);
5809 : }
5810 : }
5811 : else
5812 : {
5813 : static bool bHasWarned = false;
5814 0 : if (!bHasWarned)
5815 0 : CPLError(CE_Failure, CPLE_IllegalArg,
5816 : "-wrapdateline option only works when "
5817 : "reprojecting to a geographic SRS");
5818 0 : bHasWarned = true;
5819 : }
5820 :
5821 4 : psInfo->m_aoReprojectionInfo[iGeom].m_aosTransformOptions.Assign(
5822 4 : papszTransformOptions);
5823 : }
5824 : }
5825 676 : return true;
5826 : }
5827 :
5828 : /************************************************************************/
5829 : /* LayerTranslator::TranslateArrow() */
5830 : /************************************************************************/
5831 :
5832 142 : bool LayerTranslator::TranslateArrow(
5833 : TargetLayerInfo *psInfo, GIntBig nCountLayerFeatures,
5834 : GIntBig *pnReadFeatureCount, GDALProgressFunc pfnProgress,
5835 : void *pProgressArg, const GDALVectorTranslateOptions *psOptions)
5836 : {
5837 : struct ArrowSchema schema;
5838 284 : CPLStringList aosOptionsWriteArrowBatch;
5839 142 : if (psInfo->m_bPreserveFID)
5840 : {
5841 : aosOptionsWriteArrowBatch.SetNameValue(
5842 16 : "FID", psInfo->m_poSrcLayer->GetFIDColumn());
5843 : aosOptionsWriteArrowBatch.SetNameValue("IF_FID_NOT_PRESERVED",
5844 16 : "WARNING");
5845 : }
5846 :
5847 142 : if (psInfo->m_sArrowArrayStream.get_schema(&schema) != 0)
5848 : {
5849 0 : CPLError(CE_Failure, CPLE_AppDefined, "stream.get_schema() failed");
5850 0 : return false;
5851 : }
5852 :
5853 142 : int iArrowGeomFieldIndex = -1;
5854 142 : if (m_bTransform)
5855 : {
5856 11 : iArrowGeomFieldIndex = GetArrowGeomFieldIndex(
5857 11 : &schema, psInfo->m_poSrcLayer->GetGeometryColumn());
5858 11 : if (!SetupCT(psInfo, psInfo->m_poSrcLayer, m_bTransform,
5859 11 : m_bWrapDateline, m_osDateLineOffset, m_poUserSourceSRS,
5860 : nullptr, m_poOutputSRS, m_poGCPCoordTrans, false))
5861 : {
5862 0 : return false;
5863 : }
5864 : }
5865 :
5866 142 : bool bRet = true;
5867 :
5868 142 : GIntBig nCount = 0;
5869 142 : bool bGoOn = true;
5870 142 : std::vector<GByte> abyModifiedWKB;
5871 142 : const int nNumReprojectionThreads = []()
5872 : {
5873 142 : const int nNumCPUs = CPLGetNumCPUs();
5874 142 : if (nNumCPUs <= 1)
5875 : {
5876 0 : return 1;
5877 : }
5878 : else
5879 : {
5880 : const char *pszNumThreads =
5881 142 : CPLGetConfigOption("GDAL_NUM_THREADS", nullptr);
5882 142 : if (pszNumThreads)
5883 : {
5884 0 : if (EQUAL(pszNumThreads, "ALL_CPUS"))
5885 0 : return CPLGetNumCPUs();
5886 0 : return std::min(atoi(pszNumThreads), 1024);
5887 : }
5888 : else
5889 : {
5890 142 : return std::max(2, nNumCPUs / 2);
5891 : }
5892 : }
5893 142 : }();
5894 :
5895 : // Somewhat arbitrary threshold (config option only/mostly for autotest purposes)
5896 142 : const int MIN_FEATURES_FOR_THREADED_REPROJ = atoi(CPLGetConfigOption(
5897 : "OGR2OGR_MIN_FEATURES_FOR_THREADED_REPROJ", "10000"));
5898 :
5899 285 : while (bGoOn)
5900 : {
5901 : struct ArrowArray array;
5902 : // Acquire source batch
5903 283 : if (psInfo->m_sArrowArrayStream.get_next(&array) != 0)
5904 : {
5905 0 : CPLError(CE_Failure, CPLE_AppDefined, "stream.get_next() failed");
5906 0 : bRet = false;
5907 140 : break;
5908 : }
5909 :
5910 283 : if (array.release == nullptr)
5911 : {
5912 : // End of stream
5913 140 : break;
5914 : }
5915 :
5916 : // Limit number of features in batch if needed
5917 143 : if (psOptions->nLimit >= 0 &&
5918 2 : nCount + array.length >= psOptions->nLimit)
5919 : {
5920 2 : const auto nAdjustedLength = psOptions->nLimit - nCount;
5921 14 : for (int i = 0; i < array.n_children; ++i)
5922 : {
5923 12 : if (array.children[i]->length == array.length)
5924 12 : array.children[i]->length = nAdjustedLength;
5925 : }
5926 2 : array.length = nAdjustedLength;
5927 2 : nCount = psOptions->nLimit;
5928 2 : bGoOn = false;
5929 : }
5930 : else
5931 : {
5932 141 : nCount += array.length;
5933 : }
5934 :
5935 143 : const auto nArrayLength = array.length;
5936 :
5937 : // Coordinate reprojection
5938 143 : if (m_bTransform)
5939 : {
5940 : struct GeomArrayReleaser
5941 : {
5942 : const void *origin_buffers_2 = nullptr;
5943 : void (*origin_release)(struct ArrowArray *) = nullptr;
5944 : void *origin_private_data = nullptr;
5945 :
5946 10 : static void init(struct ArrowArray *psGeomArray)
5947 : {
5948 10 : GeomArrayReleaser *releaser = new GeomArrayReleaser();
5949 10 : CPLAssert(psGeomArray->n_buffers >= 3);
5950 10 : releaser->origin_buffers_2 = psGeomArray->buffers[2];
5951 10 : releaser->origin_private_data = psGeomArray->private_data;
5952 10 : releaser->origin_release = psGeomArray->release;
5953 10 : psGeomArray->release = GeomArrayReleaser::release;
5954 10 : psGeomArray->private_data = releaser;
5955 10 : }
5956 :
5957 10 : static void release(struct ArrowArray *psGeomArray)
5958 : {
5959 10 : GeomArrayReleaser *releaser =
5960 : static_cast<GeomArrayReleaser *>(
5961 : psGeomArray->private_data);
5962 10 : psGeomArray->buffers[2] = releaser->origin_buffers_2;
5963 10 : psGeomArray->private_data = releaser->origin_private_data;
5964 10 : psGeomArray->release = releaser->origin_release;
5965 10 : if (psGeomArray->release)
5966 10 : psGeomArray->release(psGeomArray);
5967 10 : delete releaser;
5968 10 : }
5969 : };
5970 :
5971 10 : auto *psGeomArray = array.children[iArrowGeomFieldIndex];
5972 10 : GeomArrayReleaser::init(psGeomArray);
5973 :
5974 10 : GByte *pabyWKB = static_cast<GByte *>(
5975 10 : const_cast<void *>(psGeomArray->buffers[2]));
5976 10 : const uint32_t *panOffsets =
5977 10 : static_cast<const uint32_t *>(psGeomArray->buffers[1]);
5978 10 : auto poCT = psInfo->m_aoReprojectionInfo[0].m_poCT.get();
5979 :
5980 : try
5981 : {
5982 10 : abyModifiedWKB.resize(panOffsets[nArrayLength]);
5983 : }
5984 0 : catch (const std::exception &)
5985 : {
5986 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
5987 0 : bRet = false;
5988 0 : if (array.release)
5989 0 : array.release(&array);
5990 0 : break;
5991 : }
5992 10 : memcpy(abyModifiedWKB.data(), pabyWKB, panOffsets[nArrayLength]);
5993 10 : psGeomArray->buffers[2] = abyModifiedWKB.data();
5994 :
5995 10 : std::atomic<bool> atomicRet{true};
5996 : const auto oReprojectionLambda =
5997 15 : [psGeomArray, nArrayLength, panOffsets, &atomicRet,
5998 40061 : &abyModifiedWKB, &poCT](int iThread, int nThreads)
5999 : {
6000 : OGRWKBTransformCache oCache;
6001 15 : OGREnvelope3D sEnv3D;
6002 : auto poThisCT =
6003 15 : std::unique_ptr<OGRCoordinateTransformation>(poCT->Clone());
6004 15 : if (!poThisCT)
6005 : {
6006 0 : CPLError(CE_Failure, CPLE_AppDefined,
6007 : "Cannot clone OGRCoordinateTransformation");
6008 0 : atomicRet = false;
6009 0 : return;
6010 : }
6011 :
6012 15 : const GByte *pabyValidity =
6013 15 : static_cast<const GByte *>(psGeomArray->buffers[0]);
6014 15 : const size_t iStart =
6015 15 : static_cast<size_t>(iThread * nArrayLength / nThreads);
6016 15 : const size_t iMax = static_cast<size_t>(
6017 15 : (iThread + 1) * nArrayLength / nThreads);
6018 10023 : for (size_t i = iStart; i < iMax; ++i)
6019 : {
6020 10009 : const size_t iShifted =
6021 10009 : static_cast<size_t>(i + psGeomArray->offset);
6022 10009 : if (!pabyValidity || (pabyValidity[iShifted >> 8] &
6023 24 : (1 << (iShifted % 8))) != 0)
6024 : {
6025 10002 : const auto nWKBSize =
6026 10002 : panOffsets[iShifted + 1] - panOffsets[iShifted];
6027 20003 : if (!OGRWKBTransform(
6028 10007 : abyModifiedWKB.data() + panOffsets[iShifted],
6029 : nWKBSize, poThisCT.get(), oCache, sEnv3D))
6030 : {
6031 0 : CPLError(CE_Failure, CPLE_AppDefined,
6032 : "Reprojection failed");
6033 0 : atomicRet = false;
6034 0 : break;
6035 : }
6036 : }
6037 : }
6038 10 : };
6039 :
6040 10 : if (nArrayLength >= MIN_FEATURES_FOR_THREADED_REPROJ &&
6041 5 : nNumReprojectionThreads >= 2)
6042 : {
6043 10 : std::vector<std::future<void>> oTasks;
6044 15 : for (int iThread = 0; iThread < nNumReprojectionThreads;
6045 : ++iThread)
6046 : {
6047 20 : oTasks.emplace_back(std::async(std::launch::async,
6048 : oReprojectionLambda, iThread,
6049 10 : nNumReprojectionThreads));
6050 : }
6051 15 : for (auto &oTask : oTasks)
6052 : {
6053 10 : oTask.get();
6054 5 : }
6055 : }
6056 : else
6057 : {
6058 5 : oReprojectionLambda(0, 1);
6059 : }
6060 :
6061 10 : bRet = atomicRet;
6062 10 : if (!bRet)
6063 : {
6064 0 : if (array.release)
6065 0 : array.release(&array);
6066 0 : break;
6067 : }
6068 : }
6069 :
6070 : // Write batch to target layer
6071 143 : const bool bWriteOK = psInfo->m_poDstLayer->WriteArrowBatch(
6072 143 : &schema, &array, aosOptionsWriteArrowBatch.List());
6073 :
6074 143 : if (array.release)
6075 26 : array.release(&array);
6076 :
6077 143 : if (!bWriteOK)
6078 : {
6079 0 : CPLError(CE_Failure, CPLE_AppDefined, "WriteArrowBatch() failed");
6080 0 : bRet = false;
6081 0 : break;
6082 : }
6083 :
6084 : /* Report progress */
6085 143 : if (pfnProgress)
6086 : {
6087 0 : if (!pfnProgress(nCountLayerFeatures
6088 0 : ? nCount * 1.0 / nCountLayerFeatures
6089 : : 1.0,
6090 : "", pProgressArg))
6091 : {
6092 0 : bGoOn = false;
6093 0 : bRet = false;
6094 : }
6095 : }
6096 :
6097 143 : if (pnReadFeatureCount)
6098 0 : *pnReadFeatureCount = nCount;
6099 : }
6100 :
6101 142 : schema.release(&schema);
6102 :
6103 142 : return bRet;
6104 : }
6105 :
6106 : /************************************************************************/
6107 : /* LayerTranslator::Translate() */
6108 : /************************************************************************/
6109 :
6110 1672 : bool LayerTranslator::Translate(
6111 : OGRFeature *poFeatureIn, TargetLayerInfo *psInfo,
6112 : GIntBig nCountLayerFeatures, GIntBig *pnReadFeatureCount,
6113 : GIntBig &nTotalEventsDone, GDALProgressFunc pfnProgress, void *pProgressArg,
6114 : const GDALVectorTranslateOptions *psOptions)
6115 : {
6116 1672 : if (psInfo->m_bUseWriteArrowBatch)
6117 : {
6118 142 : return TranslateArrow(psInfo, nCountLayerFeatures, pnReadFeatureCount,
6119 142 : pfnProgress, pProgressArg, psOptions);
6120 : }
6121 :
6122 1530 : const int eGType = m_eGType;
6123 1530 : const OGRSpatialReference *poOutputSRS = m_poOutputSRS;
6124 :
6125 1530 : OGRLayer *poSrcLayer = psInfo->m_poSrcLayer;
6126 1530 : OGRLayer *poDstLayer = psInfo->m_poDstLayer;
6127 1530 : const int *const panMap = psInfo->m_anMap.data();
6128 1530 : const int iSrcZField = psInfo->m_iSrcZField;
6129 1530 : const bool bPreserveFID = psInfo->m_bPreserveFID;
6130 1530 : const auto poSrcFDefn = poSrcLayer->GetLayerDefn();
6131 1530 : const auto poDstFDefn = poDstLayer->GetLayerDefn();
6132 1530 : const int nSrcGeomFieldCount = poSrcFDefn->GetGeomFieldCount();
6133 1530 : const int nDstGeomFieldCount = poDstFDefn->GetGeomFieldCount();
6134 1530 : const bool bExplodeCollections =
6135 1530 : m_bExplodeCollections && nDstGeomFieldCount <= 1;
6136 1530 : const int iRequestedSrcGeomField = psInfo->m_iRequestedSrcGeomField;
6137 :
6138 1530 : if (poOutputSRS == nullptr && !m_bNullifyOutputSRS)
6139 : {
6140 1499 : if (nSrcGeomFieldCount == 1)
6141 : {
6142 499 : poOutputSRS = poSrcLayer->GetSpatialRef();
6143 : }
6144 1000 : else if (iRequestedSrcGeomField > 0)
6145 : {
6146 1 : poOutputSRS = poSrcLayer->GetLayerDefn()
6147 1 : ->GetGeomFieldDefn(iRequestedSrcGeomField)
6148 1 : ->GetSpatialRef();
6149 : }
6150 : }
6151 :
6152 : /* -------------------------------------------------------------------- */
6153 : /* Transfer features. */
6154 : /* -------------------------------------------------------------------- */
6155 1530 : if (psOptions->nGroupTransactions)
6156 : {
6157 1529 : if (psOptions->nLayerTransaction)
6158 : {
6159 463 : if (poDstLayer->StartTransaction() == OGRERR_FAILURE)
6160 : {
6161 0 : delete poFeatureIn;
6162 0 : return false;
6163 : }
6164 : }
6165 : }
6166 :
6167 1530 : std::unique_ptr<OGRFeature> poFeature;
6168 3060 : std::unique_ptr<OGRFeature> poDstFeature(new OGRFeature(poDstFDefn));
6169 1530 : int nFeaturesInTransaction = 0;
6170 1530 : GIntBig nCount = 0; /* written + failed */
6171 1530 : GIntBig nFeaturesWritten = 0;
6172 1530 : bool bRunSetPrecisionEvaluated = false;
6173 1530 : bool bRunSetPrecision = false;
6174 :
6175 1530 : bool bRet = true;
6176 1530 : CPLErrorReset();
6177 :
6178 1530 : bool bSetupCTOK = false;
6179 1530 : if (m_bTransform && psInfo->m_nFeaturesRead == 0 &&
6180 24 : !psInfo->m_bPerFeatureCT)
6181 : {
6182 24 : bSetupCTOK = SetupCT(psInfo, poSrcLayer, m_bTransform, m_bWrapDateline,
6183 24 : m_osDateLineOffset, m_poUserSourceSRS, nullptr,
6184 : poOutputSRS, m_poGCPCoordTrans, false);
6185 : }
6186 :
6187 : while (true)
6188 : {
6189 5196 : if (m_nLimit >= 0 && psInfo->m_nFeaturesRead >= m_nLimit)
6190 : {
6191 9 : break;
6192 : }
6193 :
6194 5187 : if (poFeatureIn != nullptr)
6195 974 : poFeature.reset(poFeatureIn);
6196 4213 : else if (psOptions->nFIDToFetch != OGRNullFID)
6197 5 : poFeature.reset(poSrcLayer->GetFeature(psOptions->nFIDToFetch));
6198 : else
6199 4208 : poFeature.reset(poSrcLayer->GetNextFeature());
6200 :
6201 5187 : if (poFeature == nullptr)
6202 : {
6203 537 : if (CPLGetLastErrorType() == CE_Failure)
6204 : {
6205 1 : bRet = false;
6206 : }
6207 537 : break;
6208 : }
6209 :
6210 4650 : if (!bSetupCTOK &&
6211 4550 : (psInfo->m_nFeaturesRead == 0 || psInfo->m_bPerFeatureCT))
6212 : {
6213 1284 : if (!SetupCT(psInfo, poSrcLayer, m_bTransform, m_bWrapDateline,
6214 642 : m_osDateLineOffset, m_poUserSourceSRS, poFeature.get(),
6215 : poOutputSRS, m_poGCPCoordTrans, true))
6216 : {
6217 4 : return false;
6218 : }
6219 : }
6220 :
6221 4650 : psInfo->m_nFeaturesRead++;
6222 :
6223 4650 : int nIters = 1;
6224 0 : std::unique_ptr<OGRGeometryCollection> poCollToExplode;
6225 4650 : int iGeomCollToExplode = -1;
6226 4650 : OGRGeometry *poSrcGeometry = nullptr;
6227 4650 : if (bExplodeCollections)
6228 : {
6229 13 : if (iRequestedSrcGeomField >= 0)
6230 : poSrcGeometry =
6231 0 : poFeature->GetGeomFieldRef(iRequestedSrcGeomField);
6232 : else
6233 13 : poSrcGeometry = poFeature->GetGeometryRef();
6234 26 : if (poSrcGeometry &&
6235 13 : OGR_GT_IsSubClassOf(poSrcGeometry->getGeometryType(),
6236 : wkbGeometryCollection))
6237 : {
6238 : const int nParts =
6239 12 : poSrcGeometry->toGeometryCollection()->getNumGeometries();
6240 21 : if (nParts > 0 ||
6241 9 : wkbFlatten(poSrcGeometry->getGeometryType()) !=
6242 : wkbGeometryCollection)
6243 : {
6244 11 : iGeomCollToExplode = iRequestedSrcGeomField >= 0
6245 : ? iRequestedSrcGeomField
6246 : : 0;
6247 11 : poCollToExplode.reset(
6248 : poFeature->StealGeometry(iGeomCollToExplode)
6249 : ->toGeometryCollection());
6250 11 : nIters = std::max(1, nParts);
6251 : }
6252 : }
6253 : }
6254 :
6255 4650 : const GIntBig nSrcFID = poFeature->GetFID();
6256 4650 : GIntBig nDesiredFID = OGRNullFID;
6257 4650 : if (bPreserveFID)
6258 1160 : nDesiredFID = nSrcFID;
6259 3491 : else if (psInfo->m_iSrcFIDField >= 0 &&
6260 1 : poFeature->IsFieldSetAndNotNull(psInfo->m_iSrcFIDField))
6261 : nDesiredFID =
6262 1 : poFeature->GetFieldAsInteger64(psInfo->m_iSrcFIDField);
6263 :
6264 9299 : for (int iPart = 0; iPart < nIters; iPart++)
6265 : {
6266 7944 : if (psOptions->nLayerTransaction &&
6267 3291 : ++nFeaturesInTransaction == psOptions->nGroupTransactions)
6268 : {
6269 0 : if (poDstLayer->CommitTransaction() == OGRERR_FAILURE ||
6270 0 : poDstLayer->StartTransaction() == OGRERR_FAILURE)
6271 : {
6272 0 : return false;
6273 : }
6274 0 : nFeaturesInTransaction = 0;
6275 : }
6276 10668 : else if (!psOptions->nLayerTransaction &&
6277 5995 : psOptions->nGroupTransactions > 0 &&
6278 1342 : ++nTotalEventsDone >= psOptions->nGroupTransactions)
6279 : {
6280 40 : if (m_poODS->CommitTransaction() == OGRERR_FAILURE ||
6281 20 : m_poODS->StartTransaction(psOptions->bForceTransaction) ==
6282 : OGRERR_FAILURE)
6283 : {
6284 0 : return false;
6285 : }
6286 20 : nTotalEventsDone = 0;
6287 : }
6288 :
6289 4653 : CPLErrorReset();
6290 4653 : if (psInfo->m_bCanAvoidSetFrom)
6291 : {
6292 4366 : poDstFeature = std::move(poFeature);
6293 : // From now on, poFeature is null !
6294 4366 : poDstFeature->SetFDefnUnsafe(poDstFDefn);
6295 4366 : poDstFeature->SetFID(nDesiredFID);
6296 : }
6297 : else
6298 : {
6299 : /* Optimization to avoid duplicating the source geometry in the
6300 : */
6301 : /* target feature : we steal it from the source feature for
6302 : * now... */
6303 0 : std::unique_ptr<OGRGeometry> poStolenGeometry;
6304 287 : if (!bExplodeCollections && nSrcGeomFieldCount == 1 &&
6305 64 : (nDstGeomFieldCount == 1 ||
6306 64 : (nDstGeomFieldCount == 0 && m_poClipSrcOri)))
6307 : {
6308 183 : poStolenGeometry.reset(poFeature->StealGeometry());
6309 : }
6310 104 : else if (!bExplodeCollections && iRequestedSrcGeomField >= 0)
6311 : {
6312 0 : poStolenGeometry.reset(
6313 : poFeature->StealGeometry(iRequestedSrcGeomField));
6314 : }
6315 :
6316 287 : if (nDstGeomFieldCount == 0 && poStolenGeometry &&
6317 0 : m_poClipSrcOri)
6318 : {
6319 0 : if (poStolenGeometry->IsEmpty())
6320 0 : goto end_loop;
6321 :
6322 0 : const auto [poClipGeom, poClipGeomEnvelope] =
6323 0 : GetSrcClipGeom(poStolenGeometry->getSpatialReference());
6324 :
6325 0 : if (poClipGeom && poClipGeomEnvelope)
6326 : {
6327 0 : OGREnvelope oEnv;
6328 0 : poStolenGeometry->getEnvelope(&oEnv);
6329 0 : if (!poClipGeomEnvelope->Contains(oEnv) &&
6330 0 : !(poClipGeomEnvelope->Intersects(oEnv) &&
6331 0 : poClipGeom->Intersects(poStolenGeometry.get())))
6332 : {
6333 0 : goto end_loop;
6334 : }
6335 : }
6336 : }
6337 :
6338 287 : poDstFeature->Reset();
6339 287 : if (poDstFeature->SetFrom(poFeature.get(), panMap, TRUE) !=
6340 : OGRERR_NONE)
6341 : {
6342 0 : if (psOptions->nGroupTransactions)
6343 : {
6344 0 : if (psOptions->nLayerTransaction)
6345 : {
6346 0 : if (poDstLayer->CommitTransaction() != OGRERR_NONE)
6347 : {
6348 0 : return false;
6349 : }
6350 : }
6351 : }
6352 :
6353 0 : CPLError(CE_Failure, CPLE_AppDefined,
6354 : "Unable to translate feature " CPL_FRMT_GIB
6355 : " from layer %s.",
6356 0 : nSrcFID, poSrcLayer->GetName());
6357 :
6358 0 : return false;
6359 : }
6360 :
6361 : /* ... and now we can attach the stolen geometry */
6362 287 : if (poStolenGeometry)
6363 : {
6364 176 : poDstFeature->SetGeometryDirectly(
6365 : poStolenGeometry.release());
6366 : }
6367 :
6368 287 : if (!psInfo->m_oMapResolved.empty())
6369 : {
6370 4 : for (const auto &kv : psInfo->m_oMapResolved)
6371 : {
6372 2 : const int nDstField = kv.first;
6373 2 : const int nSrcField = kv.second.nSrcField;
6374 2 : if (poFeature->IsFieldSetAndNotNull(nSrcField))
6375 : {
6376 2 : const auto poDomain = kv.second.poDomain;
6377 : const auto &oMapKV =
6378 2 : psInfo->m_oMapDomainToKV[poDomain];
6379 : const auto iter = oMapKV.find(
6380 2 : poFeature->GetFieldAsString(nSrcField));
6381 2 : if (iter != oMapKV.end())
6382 : {
6383 2 : poDstFeature->SetField(nDstField,
6384 1 : iter->second.c_str());
6385 : }
6386 : }
6387 : }
6388 : }
6389 :
6390 287 : if (nDesiredFID != OGRNullFID)
6391 2 : poDstFeature->SetFID(nDesiredFID);
6392 : }
6393 :
6394 4653 : if (psOptions->bEmptyStrAsNull)
6395 : {
6396 2 : for (int i = 0; i < poDstFeature->GetFieldCount(); i++)
6397 : {
6398 1 : if (!poDstFeature->IsFieldSetAndNotNull(i))
6399 0 : continue;
6400 1 : auto fieldDef = poDstFeature->GetFieldDefnRef(i);
6401 1 : if (fieldDef->GetType() != OGRFieldType::OFTString)
6402 0 : continue;
6403 1 : auto str = poDstFeature->GetFieldAsString(i);
6404 1 : if (strcmp(str, "") == 0)
6405 1 : poDstFeature->SetFieldNull(i);
6406 : }
6407 : }
6408 :
6409 4653 : if (!psInfo->m_anDateTimeFieldIdx.empty())
6410 : {
6411 40 : for (int i : psInfo->m_anDateTimeFieldIdx)
6412 : {
6413 20 : if (!poDstFeature->IsFieldSetAndNotNull(i))
6414 11 : continue;
6415 15 : auto psField = poDstFeature->GetRawFieldRef(i);
6416 15 : if (psField->Date.TZFlag == 0 || psField->Date.TZFlag == 1)
6417 5 : continue;
6418 :
6419 10 : const int nTZOffsetInSec =
6420 10 : (psField->Date.TZFlag - 100) * 15 * 60;
6421 10 : if (nTZOffsetInSec == psOptions->nTZOffsetInSec)
6422 1 : continue;
6423 :
6424 : struct tm brokendowntime;
6425 9 : memset(&brokendowntime, 0, sizeof(brokendowntime));
6426 9 : brokendowntime.tm_year = psField->Date.Year - 1900;
6427 9 : brokendowntime.tm_mon = psField->Date.Month - 1;
6428 9 : brokendowntime.tm_mday = psField->Date.Day;
6429 9 : GIntBig nUnixTime = CPLYMDHMSToUnixTime(&brokendowntime);
6430 9 : int nSec = psField->Date.Hour * 3600 +
6431 9 : psField->Date.Minute * 60 +
6432 9 : static_cast<int>(psField->Date.Second);
6433 9 : nSec += psOptions->nTZOffsetInSec - nTZOffsetInSec;
6434 9 : nUnixTime += nSec;
6435 9 : CPLUnixTimeToYMDHMS(nUnixTime, &brokendowntime);
6436 :
6437 9 : psField->Date.Year =
6438 9 : static_cast<GInt16>(brokendowntime.tm_year + 1900);
6439 9 : psField->Date.Month =
6440 9 : static_cast<GByte>(brokendowntime.tm_mon + 1);
6441 9 : psField->Date.Day =
6442 9 : static_cast<GByte>(brokendowntime.tm_mday);
6443 9 : psField->Date.Hour =
6444 9 : static_cast<GByte>(brokendowntime.tm_hour);
6445 9 : psField->Date.Minute =
6446 9 : static_cast<GByte>(brokendowntime.tm_min);
6447 9 : psField->Date.Second = static_cast<float>(
6448 9 : brokendowntime.tm_sec + fmod(psField->Date.Second, 1));
6449 9 : psField->Date.TZFlag = static_cast<GByte>(
6450 9 : 100 + psOptions->nTZOffsetInSec / (15 * 60));
6451 : }
6452 : }
6453 :
6454 : /* Erase native data if asked explicitly */
6455 4653 : if (!m_bNativeData)
6456 : {
6457 1 : poDstFeature->SetNativeData(nullptr);
6458 1 : poDstFeature->SetNativeMediaType(nullptr);
6459 : }
6460 :
6461 8243 : for (int iGeom = 0; iGeom < nDstGeomFieldCount; iGeom++)
6462 : {
6463 0 : std::unique_ptr<OGRGeometry> poDstGeometry;
6464 :
6465 3635 : if (poCollToExplode && iGeom == iGeomCollToExplode)
6466 : {
6467 14 : if (poSrcGeometry && poCollToExplode->IsEmpty())
6468 : {
6469 : const OGRwkbGeometryType eSrcType =
6470 8 : poSrcGeometry->getGeometryType();
6471 : const OGRwkbGeometryType eSrcFlattenType =
6472 8 : wkbFlatten(eSrcType);
6473 8 : OGRwkbGeometryType eDstType = eSrcType;
6474 8 : switch (eSrcFlattenType)
6475 : {
6476 4 : case wkbMultiPoint:
6477 4 : eDstType = wkbPoint;
6478 4 : break;
6479 1 : case wkbMultiLineString:
6480 1 : eDstType = wkbLineString;
6481 1 : break;
6482 1 : case wkbMultiPolygon:
6483 1 : eDstType = wkbPolygon;
6484 1 : break;
6485 1 : case wkbMultiCurve:
6486 1 : eDstType = wkbCompoundCurve;
6487 1 : break;
6488 1 : case wkbMultiSurface:
6489 1 : eDstType = wkbCurvePolygon;
6490 1 : break;
6491 0 : default:
6492 0 : break;
6493 : }
6494 : eDstType =
6495 8 : OGR_GT_SetModifier(eDstType, OGR_GT_HasZ(eSrcType),
6496 : OGR_GT_HasM(eSrcType));
6497 8 : poDstGeometry.reset(
6498 : OGRGeometryFactory::createGeometry(eDstType));
6499 : }
6500 : else
6501 : {
6502 : OGRGeometry *poPart =
6503 6 : poCollToExplode->getGeometryRef(0);
6504 6 : poCollToExplode->removeGeometry(0, FALSE);
6505 6 : poDstGeometry.reset(poPart);
6506 : }
6507 : }
6508 : else
6509 : {
6510 3621 : poDstGeometry.reset(poDstFeature->StealGeometry(iGeom));
6511 : }
6512 3635 : if (poDstGeometry == nullptr)
6513 612 : continue;
6514 :
6515 : // poFeature hasn't been moved if iSrcZField != -1
6516 : // cppcheck-suppress accessMoved
6517 3023 : if (iSrcZField != -1 && poFeature != nullptr)
6518 : {
6519 30 : SetZ(poDstGeometry.get(),
6520 : poFeature->GetFieldAsDouble(iSrcZField));
6521 : /* This will correct the coordinate dimension to 3 */
6522 30 : poDstGeometry.reset(poDstGeometry->clone());
6523 : }
6524 :
6525 3023 : if (m_nCoordDim == 2 || m_nCoordDim == 3)
6526 : {
6527 24 : poDstGeometry->setCoordinateDimension(m_nCoordDim);
6528 : }
6529 2999 : else if (m_nCoordDim == 4)
6530 : {
6531 2 : poDstGeometry->set3D(TRUE);
6532 2 : poDstGeometry->setMeasured(TRUE);
6533 : }
6534 2997 : else if (m_nCoordDim == COORD_DIM_XYM)
6535 : {
6536 2 : poDstGeometry->set3D(FALSE);
6537 2 : poDstGeometry->setMeasured(TRUE);
6538 : }
6539 2995 : else if (m_nCoordDim == COORD_DIM_LAYER_DIM)
6540 : {
6541 : const OGRwkbGeometryType eDstLayerGeomType =
6542 2 : poDstLayer->GetLayerDefn()
6543 2 : ->GetGeomFieldDefn(iGeom)
6544 2 : ->GetType();
6545 2 : poDstGeometry->set3D(wkbHasZ(eDstLayerGeomType));
6546 2 : poDstGeometry->setMeasured(wkbHasM(eDstLayerGeomType));
6547 : }
6548 :
6549 3023 : if (m_eGeomOp == GEOMOP_SEGMENTIZE)
6550 : {
6551 20 : if (m_dfGeomOpParam > 0)
6552 20 : poDstGeometry->segmentize(m_dfGeomOpParam);
6553 : }
6554 3003 : else if (m_eGeomOp == GEOMOP_SIMPLIFY_PRESERVE_TOPOLOGY)
6555 : {
6556 1 : if (m_dfGeomOpParam > 0)
6557 : {
6558 : auto poNewGeom = std::unique_ptr<OGRGeometry>(
6559 : poDstGeometry->SimplifyPreserveTopology(
6560 2 : m_dfGeomOpParam));
6561 1 : if (poNewGeom)
6562 : {
6563 1 : poDstGeometry = std::move(poNewGeom);
6564 : }
6565 : }
6566 : }
6567 :
6568 3023 : if (m_poClipSrcOri)
6569 : {
6570 45 : if (poDstGeometry->IsEmpty())
6571 25 : goto end_loop;
6572 :
6573 45 : const auto [poClipGeom, poClipGeomEnvelope] =
6574 45 : GetSrcClipGeom(poDstGeometry->getSpatialReference());
6575 :
6576 45 : if (!(poClipGeom && poClipGeomEnvelope))
6577 0 : goto end_loop;
6578 :
6579 45 : OGREnvelope oDstEnv;
6580 45 : poDstGeometry->getEnvelope(&oDstEnv);
6581 :
6582 45 : if (!poClipGeomEnvelope->Contains(oDstEnv))
6583 : {
6584 0 : std::unique_ptr<OGRGeometry> poClipped;
6585 38 : if (poClipGeomEnvelope->Intersects(oDstEnv))
6586 : {
6587 18 : poClipped.reset(
6588 18 : poClipGeom->Intersection(poDstGeometry.get()));
6589 : }
6590 38 : if (poClipped == nullptr || poClipped->IsEmpty())
6591 : {
6592 24 : goto end_loop;
6593 : }
6594 :
6595 14 : const int nDim = poDstGeometry->getDimension();
6596 15 : if (poClipped->getDimension() < nDim &&
6597 1 : wkbFlatten(poDstFDefn->GetGeomFieldDefn(iGeom)
6598 : ->GetType()) != wkbUnknown)
6599 : {
6600 3 : CPLDebug(
6601 : "OGR2OGR",
6602 : "Discarding feature " CPL_FRMT_GIB
6603 : " of layer %s, "
6604 : "as its intersection with -clipsrc is a %s "
6605 : "whereas the input is a %s",
6606 1 : nSrcFID, poSrcLayer->GetName(),
6607 1 : OGRToOGCGeomType(poClipped->getGeometryType()),
6608 : OGRToOGCGeomType(
6609 1 : poDstGeometry->getGeometryType()));
6610 1 : goto end_loop;
6611 : }
6612 :
6613 13 : poDstGeometry = std::move(poClipped);
6614 : }
6615 : }
6616 :
6617 : OGRCoordinateTransformation *const poCT =
6618 2998 : psInfo->m_aoReprojectionInfo[iGeom].m_poCT.get();
6619 : char **const papszTransformOptions =
6620 2998 : psInfo->m_aoReprojectionInfo[iGeom]
6621 2998 : .m_aosTransformOptions.List();
6622 : const bool bReprojCanInvalidateValidity =
6623 2998 : psInfo->m_aoReprojectionInfo[iGeom]
6624 2998 : .m_bCanInvalidateValidity;
6625 :
6626 2998 : if (poCT != nullptr || papszTransformOptions != nullptr)
6627 : {
6628 : // If we need to change the geometry type to linear, and
6629 : // we have a geometry with curves, then convert it to
6630 : // linear first, to avoid invalidities due to the fact
6631 : // that validity of arc portions isn't always kept while
6632 : // reprojecting and then discretizing.
6633 113 : if (bReprojCanInvalidateValidity &&
6634 111 : (!psInfo->m_bSupportCurves ||
6635 50 : m_eGeomTypeConversion == GTC_CONVERT_TO_LINEAR ||
6636 48 : m_eGeomTypeConversion ==
6637 : GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR))
6638 : {
6639 63 : if (poDstGeometry->hasCurveGeometry(TRUE))
6640 : {
6641 4 : OGRwkbGeometryType eTargetType = OGR_GT_GetLinear(
6642 4 : poDstGeometry->getGeometryType());
6643 4 : poDstGeometry.reset(OGRGeometryFactory::forceTo(
6644 : poDstGeometry.release(), eTargetType));
6645 63 : }
6646 : }
6647 48 : else if (bReprojCanInvalidateValidity &&
6648 2 : eGType != GEOMTYPE_UNCHANGED &&
6649 2 : !OGR_GT_IsNonLinear(
6650 98 : static_cast<OGRwkbGeometryType>(eGType)) &&
6651 2 : poDstGeometry->hasCurveGeometry(TRUE))
6652 : {
6653 2 : poDstGeometry.reset(OGRGeometryFactory::forceTo(
6654 : poDstGeometry.release(),
6655 : static_cast<OGRwkbGeometryType>(eGType)));
6656 : }
6657 :
6658 114 : for (int iIter = 0; iIter < 2; ++iIter)
6659 : {
6660 : auto poReprojectedGeom = std::unique_ptr<OGRGeometry>(
6661 : OGRGeometryFactory::transformWithOptions(
6662 114 : poDstGeometry.get(), poCT,
6663 : papszTransformOptions,
6664 114 : m_transformWithOptionsCache));
6665 114 : if (poReprojectedGeom == nullptr)
6666 : {
6667 0 : if (psOptions->nGroupTransactions)
6668 : {
6669 0 : if (psOptions->nLayerTransaction)
6670 : {
6671 0 : if (poDstLayer->CommitTransaction() !=
6672 0 : OGRERR_NONE &&
6673 0 : !psOptions->bSkipFailures)
6674 : {
6675 0 : return false;
6676 : }
6677 : }
6678 : }
6679 :
6680 0 : CPLError(CE_Failure, CPLE_AppDefined,
6681 : "Failed to reproject feature " CPL_FRMT_GIB
6682 : " (geometry probably out of source or "
6683 : "destination SRS).",
6684 : nSrcFID);
6685 0 : if (!psOptions->bSkipFailures)
6686 : {
6687 0 : return false;
6688 : }
6689 : }
6690 :
6691 : // Check if a curve geometry is no longer valid after
6692 : // reprojection
6693 114 : const auto eType = poDstGeometry->getGeometryType();
6694 114 : const auto eFlatType = wkbFlatten(eType);
6695 :
6696 4 : const auto IsValid = [](const OGRGeometry *poGeom)
6697 : {
6698 : CPLErrorHandlerPusher oErrorHandler(
6699 8 : CPLQuietErrorHandler);
6700 8 : return poGeom->IsValid();
6701 : };
6702 :
6703 113 : if (iIter == 0 && bReprojCanInvalidateValidity &&
6704 111 : OGRGeometryFactory::haveGEOS() &&
6705 109 : (eFlatType == wkbCurvePolygon ||
6706 109 : eFlatType == wkbCompoundCurve ||
6707 109 : eFlatType == wkbMultiCurve ||
6708 2 : eFlatType == wkbMultiSurface) &&
6709 229 : poDstGeometry->hasCurveGeometry(TRUE) &&
6710 2 : IsValid(poDstGeometry.get()))
6711 : {
6712 2 : OGRwkbGeometryType eTargetType = OGR_GT_GetLinear(
6713 2 : poDstGeometry->getGeometryType());
6714 : auto poDstGeometryTmp =
6715 : std::unique_ptr<OGRGeometry>(
6716 : OGRGeometryFactory::forceTo(
6717 2 : poReprojectedGeom->clone(),
6718 2 : eTargetType));
6719 2 : if (!IsValid(poDstGeometryTmp.get()))
6720 : {
6721 1 : CPLDebug("OGR2OGR",
6722 : "Curve geometry no longer valid after "
6723 : "reprojection: transforming it into "
6724 : "linear one before reprojecting");
6725 1 : poDstGeometry.reset(OGRGeometryFactory::forceTo(
6726 : poDstGeometry.release(), eTargetType));
6727 1 : poDstGeometry.reset(OGRGeometryFactory::forceTo(
6728 : poDstGeometry.release(), eType));
6729 : }
6730 : else
6731 : {
6732 1 : poDstGeometry = std::move(poReprojectedGeom);
6733 1 : break;
6734 : }
6735 : }
6736 : else
6737 : {
6738 112 : poDstGeometry = std::move(poReprojectedGeom);
6739 112 : break;
6740 : }
6741 113 : }
6742 : }
6743 2885 : else if (poOutputSRS != nullptr)
6744 : {
6745 1843 : poDstGeometry->assignSpatialReference(poOutputSRS);
6746 : }
6747 :
6748 2998 : if (poDstGeometry != nullptr)
6749 : {
6750 2998 : if (m_poClipDstOri)
6751 : {
6752 39 : if (poDstGeometry->IsEmpty())
6753 19 : goto end_loop;
6754 :
6755 39 : auto [poClipGeom, poClipGeomEnvelope] = GetDstClipGeom(
6756 39 : poDstGeometry->getSpatialReference());
6757 39 : if (!poClipGeom || !poClipGeomEnvelope)
6758 : {
6759 0 : goto end_loop;
6760 : }
6761 :
6762 39 : OGREnvelope oDstEnv;
6763 39 : poDstGeometry->getEnvelope(&oDstEnv);
6764 :
6765 39 : if (!poClipGeomEnvelope->Contains(oDstEnv))
6766 : {
6767 0 : std::unique_ptr<OGRGeometry> poClipped;
6768 31 : if (poClipGeomEnvelope->Intersects(oDstEnv))
6769 : {
6770 16 : poClipped.reset(poClipGeom->Intersection(
6771 16 : poDstGeometry.get()));
6772 : }
6773 :
6774 31 : if (poClipped == nullptr || poClipped->IsEmpty())
6775 : {
6776 18 : goto end_loop;
6777 : }
6778 :
6779 13 : const int nDim = poDstGeometry->getDimension();
6780 14 : if (poClipped->getDimension() < nDim &&
6781 1 : wkbFlatten(poDstFDefn->GetGeomFieldDefn(iGeom)
6782 : ->GetType()) != wkbUnknown)
6783 : {
6784 3 : CPLDebug(
6785 : "OGR2OGR",
6786 : "Discarding feature " CPL_FRMT_GIB
6787 : " of layer %s, "
6788 : "as its intersection with -clipdst is a %s "
6789 : "whereas the input is a %s",
6790 1 : nSrcFID, poSrcLayer->GetName(),
6791 : OGRToOGCGeomType(
6792 1 : poClipped->getGeometryType()),
6793 : OGRToOGCGeomType(
6794 1 : poDstGeometry->getGeometryType()));
6795 1 : goto end_loop;
6796 : }
6797 :
6798 12 : poDstGeometry = std::move(poClipped);
6799 : }
6800 : }
6801 :
6802 5958 : if (psOptions->dfXYRes !=
6803 1 : OGRGeomCoordinatePrecision::UNKNOWN &&
6804 2980 : OGRGeometryFactory::haveGEOS() &&
6805 1 : !poDstGeometry->hasCurveGeometry())
6806 : {
6807 : // OGR_APPLY_GEOM_SET_PRECISION default value for
6808 : // OGRLayer::CreateFeature() purposes, but here in the
6809 : // ogr2ogr -xyRes context, we force calling SetPrecision(),
6810 : // unless the user explicitly asks not to do it by
6811 : // setting the config option to NO.
6812 1 : if (!bRunSetPrecisionEvaluated)
6813 : {
6814 1 : bRunSetPrecisionEvaluated = true;
6815 1 : bRunSetPrecision = CPLTestBool(CPLGetConfigOption(
6816 : "OGR_APPLY_GEOM_SET_PRECISION", "YES"));
6817 : }
6818 1 : if (bRunSetPrecision)
6819 : {
6820 : auto poNewGeom = std::unique_ptr<OGRGeometry>(
6821 1 : poDstGeometry->SetPrecision(psOptions->dfXYRes,
6822 1 : /* nFlags = */ 0));
6823 1 : if (!poNewGeom)
6824 0 : goto end_loop;
6825 1 : poDstGeometry = std::move(poNewGeom);
6826 : }
6827 : }
6828 :
6829 2979 : if (m_bMakeValid)
6830 : {
6831 : const bool bIsGeomCollection =
6832 7 : wkbFlatten(poDstGeometry->getGeometryType()) ==
6833 7 : wkbGeometryCollection;
6834 : auto poNewGeom = std::unique_ptr<OGRGeometry>(
6835 7 : poDstGeometry->MakeValid());
6836 7 : if (!poNewGeom)
6837 0 : goto end_loop;
6838 7 : poDstGeometry = std::move(poNewGeom);
6839 7 : if (!bIsGeomCollection)
6840 : {
6841 6 : poDstGeometry.reset(
6842 : OGRGeometryFactory::
6843 : removeLowerDimensionSubGeoms(
6844 6 : poDstGeometry.get()));
6845 : }
6846 : }
6847 :
6848 2979 : if (m_bSkipInvalidGeom && !poDstGeometry->IsValid())
6849 1 : goto end_loop;
6850 :
6851 2978 : if (m_eGeomTypeConversion != GTC_DEFAULT)
6852 : {
6853 : OGRwkbGeometryType eTargetType =
6854 11 : poDstGeometry->getGeometryType();
6855 : eTargetType =
6856 11 : ConvertType(m_eGeomTypeConversion, eTargetType);
6857 11 : poDstGeometry.reset(OGRGeometryFactory::forceTo(
6858 : poDstGeometry.release(), eTargetType));
6859 : }
6860 2967 : else if (eGType != GEOMTYPE_UNCHANGED)
6861 : {
6862 59 : poDstGeometry.reset(OGRGeometryFactory::forceTo(
6863 : poDstGeometry.release(),
6864 : static_cast<OGRwkbGeometryType>(eGType)));
6865 : }
6866 : }
6867 :
6868 2978 : poDstFeature->SetGeomFieldDirectly(iGeom,
6869 : poDstGeometry.release());
6870 : }
6871 :
6872 4608 : CPLErrorReset();
6873 9216 : if ((psOptions->bUpsert
6874 4608 : ? poDstLayer->UpsertFeature(poDstFeature.get())
6875 4608 : : poDstLayer->CreateFeature(poDstFeature.get())) ==
6876 : OGRERR_NONE)
6877 : {
6878 4603 : nFeaturesWritten++;
6879 5758 : if (nDesiredFID != OGRNullFID &&
6880 1155 : poDstFeature->GetFID() != nDesiredFID)
6881 : {
6882 0 : CPLError(CE_Warning, CPLE_AppDefined,
6883 : "Feature id " CPL_FRMT_GIB " not preserved",
6884 : nDesiredFID);
6885 : }
6886 : }
6887 5 : else if (!psOptions->bSkipFailures)
6888 : {
6889 4 : if (psOptions->nGroupTransactions)
6890 : {
6891 4 : if (psOptions->nLayerTransaction)
6892 0 : poDstLayer->RollbackTransaction();
6893 : }
6894 :
6895 4 : CPLError(CE_Failure, CPLE_AppDefined,
6896 : "Unable to write feature " CPL_FRMT_GIB
6897 : " from layer %s.",
6898 4 : nSrcFID, poSrcLayer->GetName());
6899 :
6900 4 : return false;
6901 : }
6902 : else
6903 : {
6904 1 : CPLDebug("GDALVectorTranslate",
6905 : "Unable to write feature " CPL_FRMT_GIB
6906 : " into layer %s.",
6907 1 : nSrcFID, poSrcLayer->GetName());
6908 1 : if (psOptions->nGroupTransactions)
6909 : {
6910 1 : if (psOptions->nLayerTransaction)
6911 : {
6912 0 : poDstLayer->RollbackTransaction();
6913 0 : CPL_IGNORE_RET_VAL(poDstLayer->StartTransaction());
6914 : }
6915 : else
6916 : {
6917 1 : m_poODS->RollbackTransaction();
6918 1 : m_poODS->StartTransaction(psOptions->bForceTransaction);
6919 : }
6920 : }
6921 : }
6922 :
6923 4649 : end_loop:; // nothing
6924 : }
6925 :
6926 : /* Report progress */
6927 4646 : nCount++;
6928 4646 : bool bGoOn = true;
6929 4646 : if (pfnProgress)
6930 : {
6931 55 : bGoOn = pfnProgress(nCountLayerFeatures
6932 26 : ? nCount * 1.0 / nCountLayerFeatures
6933 : : 1.0,
6934 : "", pProgressArg) != FALSE;
6935 : }
6936 4646 : if (!bGoOn)
6937 : {
6938 1 : bRet = false;
6939 1 : break;
6940 : }
6941 :
6942 4645 : if (pnReadFeatureCount)
6943 0 : *pnReadFeatureCount = nCount;
6944 :
6945 4645 : if (psOptions->nFIDToFetch != OGRNullFID)
6946 5 : break;
6947 4640 : if (poFeatureIn != nullptr)
6948 974 : break;
6949 3666 : }
6950 :
6951 1526 : if (psOptions->nGroupTransactions)
6952 : {
6953 1525 : if (psOptions->nLayerTransaction)
6954 : {
6955 463 : if (poDstLayer->CommitTransaction() != OGRERR_NONE)
6956 0 : bRet = false;
6957 : }
6958 : }
6959 :
6960 1526 : if (poFeatureIn == nullptr)
6961 : {
6962 552 : CPLDebug("GDALVectorTranslate",
6963 : CPL_FRMT_GIB " features written in layer '%s'",
6964 552 : nFeaturesWritten, poDstLayer->GetName());
6965 : }
6966 :
6967 1526 : return bRet;
6968 : }
6969 :
6970 : /************************************************************************/
6971 : /* LayerTranslator::GetDstClipGeom() */
6972 : /************************************************************************/
6973 :
6974 : /** Returns the destination clip geometry and its envelope
6975 : *
6976 : * @param poGeomSRS The SRS into which the destination clip geometry should be
6977 : * expressed.
6978 : * @return the destination clip geometry and its envelope, or (nullptr, nullptr)
6979 : */
6980 : std::pair<const OGRGeometry *, const OGREnvelope *>
6981 39 : LayerTranslator::GetDstClipGeom(const OGRSpatialReference *poGeomSRS)
6982 : {
6983 39 : if (m_poClipDstReprojectedToDstSRS_SRS != poGeomSRS)
6984 : {
6985 36 : auto poClipDstSRS = m_poClipDstOri->getSpatialReference();
6986 36 : if (poClipDstSRS && poGeomSRS && !poClipDstSRS->IsSame(poGeomSRS))
6987 : {
6988 : // Transform clip geom to geometry SRS
6989 1 : m_poClipDstReprojectedToDstSRS.reset(m_poClipDstOri->clone());
6990 1 : if (m_poClipDstReprojectedToDstSRS->transformTo(poGeomSRS) !=
6991 : OGRERR_NONE)
6992 : {
6993 0 : return std::make_pair(nullptr, nullptr);
6994 : }
6995 1 : m_poClipDstReprojectedToDstSRS_SRS = poGeomSRS;
6996 : }
6997 35 : else if (!poClipDstSRS && poGeomSRS)
6998 : {
6999 35 : if (!m_bWarnedClipDstSRS)
7000 : {
7001 2 : m_bWarnedClipDstSRS = true;
7002 2 : CPLError(CE_Warning, CPLE_AppDefined,
7003 : "Clip destination geometry has no "
7004 : "attached SRS, but the feature's "
7005 : "geometry has one. Assuming clip "
7006 : "destination geometry SRS is the "
7007 : "same as the feature's geometry");
7008 : }
7009 : }
7010 36 : m_oClipDstEnv = OGREnvelope();
7011 : }
7012 :
7013 : const auto poGeom = m_poClipDstReprojectedToDstSRS
7014 39 : ? m_poClipDstReprojectedToDstSRS.get()
7015 39 : : m_poClipDstOri;
7016 39 : if (poGeom && !m_oClipDstEnv.IsInit())
7017 : {
7018 39 : poGeom->getEnvelope(&m_oClipDstEnv);
7019 : }
7020 39 : return std::make_pair(poGeom, poGeom ? &m_oClipDstEnv : nullptr);
7021 : }
7022 :
7023 : /************************************************************************/
7024 : /* LayerTranslator::GetSrcClipGeom() */
7025 : /************************************************************************/
7026 :
7027 : /** Returns the source clip geometry and its envelope
7028 : *
7029 : * @param poGeomSRS The SRS into which the source clip geometry should be
7030 : * expressed.
7031 : * @return the source clip geometry and its envelope, or (nullptr, nullptr)
7032 : */
7033 : std::pair<const OGRGeometry *, const OGREnvelope *>
7034 45 : LayerTranslator::GetSrcClipGeom(const OGRSpatialReference *poGeomSRS)
7035 : {
7036 45 : if (m_poClipSrcReprojectedToSrcSRS_SRS != poGeomSRS)
7037 : {
7038 42 : auto poClipSrcSRS = m_poClipSrcOri->getSpatialReference();
7039 42 : if (poClipSrcSRS && poGeomSRS && !poClipSrcSRS->IsSame(poGeomSRS))
7040 : {
7041 : // Transform clip geom to geometry SRS
7042 1 : m_poClipSrcReprojectedToSrcSRS.reset(m_poClipSrcOri->clone());
7043 1 : if (m_poClipSrcReprojectedToSrcSRS->transformTo(poGeomSRS) !=
7044 : OGRERR_NONE)
7045 : {
7046 0 : return std::make_pair(nullptr, nullptr);
7047 : }
7048 1 : m_poClipSrcReprojectedToSrcSRS_SRS = poGeomSRS;
7049 : }
7050 41 : else if (!poClipSrcSRS && poGeomSRS)
7051 : {
7052 41 : if (!m_bWarnedClipSrcSRS)
7053 : {
7054 3 : m_bWarnedClipSrcSRS = true;
7055 3 : CPLError(CE_Warning, CPLE_AppDefined,
7056 : "Clip source geometry has no attached SRS, "
7057 : "but the feature's geometry has one. "
7058 : "Assuming clip source geometry SRS is the "
7059 : "same as the feature's geometry");
7060 : }
7061 : }
7062 42 : m_oClipSrcEnv = OGREnvelope();
7063 : }
7064 :
7065 : const auto poGeom = m_poClipSrcReprojectedToSrcSRS
7066 45 : ? m_poClipSrcReprojectedToSrcSRS.get()
7067 45 : : m_poClipSrcOri;
7068 45 : if (poGeom && !m_oClipSrcEnv.IsInit())
7069 : {
7070 45 : poGeom->getEnvelope(&m_oClipSrcEnv);
7071 : }
7072 45 : return std::make_pair(poGeom, poGeom ? &m_oClipSrcEnv : nullptr);
7073 : }
7074 :
7075 : /************************************************************************/
7076 : /* GDALVectorTranslateOptionsGetParser() */
7077 : /************************************************************************/
7078 :
7079 758 : static std::unique_ptr<GDALArgumentParser> GDALVectorTranslateOptionsGetParser(
7080 : GDALVectorTranslateOptions *psOptions,
7081 : GDALVectorTranslateOptionsForBinary *psOptionsForBinary, int nCountClipSrc,
7082 : int nCountClipDst)
7083 : {
7084 : auto argParser = std::make_unique<GDALArgumentParser>(
7085 758 : "ogr2ogr", /* bForBinary=*/psOptionsForBinary != nullptr);
7086 :
7087 758 : argParser->add_description(
7088 758 : _("Converts simple features data between file formats."));
7089 :
7090 758 : argParser->add_epilog(
7091 758 : _("For more details, consult https://gdal.org/programs/ogr2ogr.html"));
7092 :
7093 758 : argParser->add_output_format_argument(psOptions->osFormat);
7094 :
7095 758 : argParser->add_dataset_creation_options_argument(psOptions->aosDSCO);
7096 :
7097 758 : argParser->add_layer_creation_options_argument(psOptions->aosLCO);
7098 :
7099 758 : argParser->add_usage_newline();
7100 :
7101 : {
7102 758 : auto &group = argParser->add_mutually_exclusive_group();
7103 758 : group.add_argument("-append")
7104 758 : .flag()
7105 31 : .action([psOptions](const std::string &)
7106 758 : { psOptions->eAccessMode = ACCESS_APPEND; })
7107 758 : .help(_("Append to existing layer instead of creating new."));
7108 :
7109 758 : group.add_argument("-upsert")
7110 758 : .flag()
7111 : .action(
7112 1 : [psOptions](const std::string &)
7113 : {
7114 1 : psOptions->eAccessMode = ACCESS_APPEND;
7115 1 : psOptions->bUpsert = true;
7116 758 : })
7117 : .help(_("Variant of -append where the UpsertFeature() operation is "
7118 758 : "used to insert or update features."));
7119 :
7120 758 : group.add_argument("-overwrite")
7121 758 : .flag()
7122 12 : .action([psOptions](const std::string &)
7123 758 : { psOptions->eAccessMode = ACCESS_OVERWRITE; })
7124 758 : .help(_("Delete the output layer and recreate it empty."));
7125 : }
7126 :
7127 758 : argParser->add_argument("-update")
7128 758 : .flag()
7129 : .action(
7130 22 : [psOptions](const std::string &)
7131 : {
7132 : /* Don't reset -append or -overwrite */
7133 8 : if (psOptions->eAccessMode != ACCESS_APPEND &&
7134 7 : psOptions->eAccessMode != ACCESS_OVERWRITE)
7135 7 : psOptions->eAccessMode = ACCESS_UPDATE;
7136 758 : })
7137 : .help(_("Open existing output datasource in update mode rather than "
7138 758 : "trying to create a new one."));
7139 :
7140 758 : argParser->add_argument("-sql")
7141 1516 : .metavar("<statement>|@<filename>")
7142 : .action(
7143 22 : [psOptions](const std::string &s)
7144 : {
7145 11 : GByte *pabyRet = nullptr;
7146 14 : if (!s.empty() && s.front() == '@' &&
7147 3 : VSIIngestFile(nullptr, s.c_str() + 1, &pabyRet, nullptr,
7148 : 1024 * 1024))
7149 : {
7150 3 : GDALRemoveBOM(pabyRet);
7151 3 : char *pszSQLStatement = reinterpret_cast<char *>(pabyRet);
7152 : psOptions->osSQLStatement =
7153 3 : GDALRemoveSQLComments(pszSQLStatement);
7154 3 : VSIFree(pszSQLStatement);
7155 : }
7156 : else
7157 : {
7158 8 : psOptions->osSQLStatement = s;
7159 : }
7160 769 : })
7161 758 : .help(_("SQL statement to execute."));
7162 :
7163 758 : argParser->add_argument("-dialect")
7164 1516 : .metavar("<dialect>")
7165 758 : .store_into(psOptions->osDialect)
7166 758 : .help(_("SQL dialect."));
7167 :
7168 758 : argParser->add_argument("-spat")
7169 1516 : .metavar("<xmin> <ymin> <xmax> <ymax>")
7170 758 : .nargs(4)
7171 758 : .scan<'g', double>()
7172 : .help(_("Spatial query extents, in the SRS of the source layer(s) (or "
7173 758 : "the one specified with -spat_srs."));
7174 :
7175 758 : argParser->add_argument("-where")
7176 1516 : .metavar("<restricted_where>|@<filename>")
7177 : .action(
7178 16 : [psOptions](const std::string &s)
7179 : {
7180 8 : GByte *pabyRet = nullptr;
7181 9 : if (!s.empty() && s.front() == '@' &&
7182 1 : VSIIngestFile(nullptr, s.c_str() + 1, &pabyRet, nullptr,
7183 : 1024 * 1024))
7184 : {
7185 1 : GDALRemoveBOM(pabyRet);
7186 1 : char *pszWHERE = reinterpret_cast<char *>(pabyRet);
7187 1 : psOptions->osWHERE = pszWHERE;
7188 1 : VSIFree(pszWHERE);
7189 : }
7190 : else
7191 : {
7192 7 : psOptions->osWHERE = s;
7193 : }
7194 766 : })
7195 758 : .help(_("Attribute query (like SQL WHERE)."));
7196 :
7197 758 : argParser->add_argument("-select")
7198 1516 : .metavar("<field_list>")
7199 : .action(
7200 34 : [psOptions](const std::string &s)
7201 : {
7202 17 : psOptions->bSelFieldsSet = true;
7203 : psOptions->aosSelFields =
7204 17 : CSLTokenizeStringComplex(s.c_str(), ",", TRUE, FALSE);
7205 758 : })
7206 : .help(_("Comma-delimited list of fields from input layer to copy to "
7207 758 : "the new layer."));
7208 :
7209 758 : argParser->add_argument("-nln")
7210 1516 : .metavar("<name>")
7211 758 : .store_into(psOptions->osNewLayerName)
7212 758 : .help(_("Assign an alternate name to the new layer."));
7213 :
7214 758 : argParser->add_argument("-nlt")
7215 1516 : .metavar("<type>")
7216 758 : .append()
7217 : .action(
7218 223 : [psOptions](const std::string &osGeomNameIn)
7219 : {
7220 49 : bool bIs3D = false;
7221 98 : std::string osGeomName(osGeomNameIn);
7222 98 : if (osGeomName.size() > 3 &&
7223 49 : STARTS_WITH_CI(osGeomName.c_str() + osGeomName.size() - 3,
7224 : "25D"))
7225 : {
7226 1 : bIs3D = true;
7227 1 : osGeomName.resize(osGeomName.size() - 3);
7228 : }
7229 96 : else if (osGeomName.size() > 1 &&
7230 48 : STARTS_WITH_CI(
7231 : osGeomName.c_str() + osGeomName.size() - 1, "Z"))
7232 : {
7233 0 : bIs3D = true;
7234 0 : osGeomName.pop_back();
7235 : }
7236 49 : if (EQUAL(osGeomName.c_str(), "NONE"))
7237 : {
7238 1 : if (psOptions->eGType != GEOMTYPE_UNCHANGED)
7239 : {
7240 : throw std::invalid_argument(
7241 0 : "Unsupported combination of -nlt arguments.");
7242 : }
7243 1 : psOptions->eGType = wkbNone;
7244 : }
7245 48 : else if (EQUAL(osGeomName.c_str(), "GEOMETRY"))
7246 : {
7247 4 : if (psOptions->eGType != GEOMTYPE_UNCHANGED)
7248 : {
7249 : throw std::invalid_argument(
7250 0 : "Unsupported combination of -nlt arguments.");
7251 : }
7252 4 : psOptions->eGType = wkbUnknown;
7253 : }
7254 44 : else if (EQUAL(osGeomName.c_str(), "PROMOTE_TO_MULTI"))
7255 : {
7256 8 : if (psOptions->eGeomTypeConversion == GTC_CONVERT_TO_LINEAR)
7257 2 : psOptions->eGeomTypeConversion =
7258 : GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR;
7259 6 : else if (psOptions->eGeomTypeConversion == GTC_DEFAULT)
7260 5 : psOptions->eGeomTypeConversion = GTC_PROMOTE_TO_MULTI;
7261 : else
7262 : {
7263 : throw std::invalid_argument(
7264 1 : "Unsupported combination of -nlt arguments.");
7265 : }
7266 : }
7267 36 : else if (EQUAL(osGeomName.c_str(), "CONVERT_TO_LINEAR"))
7268 : {
7269 12 : if (psOptions->eGeomTypeConversion == GTC_PROMOTE_TO_MULTI)
7270 2 : psOptions->eGeomTypeConversion =
7271 : GTC_PROMOTE_TO_MULTI_AND_CONVERT_TO_LINEAR;
7272 10 : else if (psOptions->eGeomTypeConversion == GTC_DEFAULT)
7273 9 : psOptions->eGeomTypeConversion = GTC_CONVERT_TO_LINEAR;
7274 : else
7275 : {
7276 : throw std::invalid_argument(
7277 1 : "Unsupported combination of -nlt arguments.");
7278 : }
7279 : }
7280 24 : else if (EQUAL(osGeomName.c_str(), "CONVERT_TO_CURVE"))
7281 : {
7282 7 : if (psOptions->eGeomTypeConversion == GTC_DEFAULT)
7283 5 : psOptions->eGeomTypeConversion = GTC_CONVERT_TO_CURVE;
7284 : else
7285 : {
7286 : throw std::invalid_argument(
7287 2 : "Unsupported combination of -nlt arguments.");
7288 : }
7289 : }
7290 : else
7291 : {
7292 17 : if (psOptions->eGType != GEOMTYPE_UNCHANGED)
7293 : {
7294 : throw std::invalid_argument(
7295 3 : "Unsupported combination of -nlt arguments.");
7296 : }
7297 14 : psOptions->eGType = OGRFromOGCGeomType(osGeomName.c_str());
7298 14 : if (psOptions->eGType == wkbUnknown)
7299 : {
7300 : throw std::invalid_argument(
7301 : CPLSPrintf("-nlt %s: type not recognised.",
7302 0 : osGeomName.c_str()));
7303 : }
7304 : }
7305 42 : if (psOptions->eGType != GEOMTYPE_UNCHANGED &&
7306 23 : psOptions->eGType != wkbNone && bIs3D)
7307 1 : psOptions->eGType = wkbSetZ(
7308 : static_cast<OGRwkbGeometryType>(psOptions->eGType));
7309 800 : })
7310 758 : .help(_("Define the geometry type for the created layer."));
7311 :
7312 758 : argParser->add_argument("-s_srs")
7313 1516 : .metavar("<srs_def>")
7314 758 : .store_into(psOptions->osSourceSRSDef)
7315 758 : .help(_("Set/override source SRS."));
7316 :
7317 : {
7318 758 : auto &group = argParser->add_mutually_exclusive_group();
7319 758 : group.add_argument("-a_srs")
7320 1516 : .metavar("<srs_def>")
7321 : .action(
7322 353 : [psOptions](const std::string &osOutputSRSDef)
7323 : {
7324 115 : psOptions->osOutputSRSDef = osOutputSRSDef;
7325 230 : if (EQUAL(psOptions->osOutputSRSDef.c_str(), "NULL") ||
7326 115 : EQUAL(psOptions->osOutputSRSDef.c_str(), "NONE"))
7327 : {
7328 4 : psOptions->osOutputSRSDef.clear();
7329 4 : psOptions->bNullifyOutputSRS = true;
7330 : }
7331 758 : })
7332 758 : .help(_("Assign an output SRS, but without reprojecting."));
7333 :
7334 758 : group.add_argument("-t_srs")
7335 1516 : .metavar("<srs_def>")
7336 : .action(
7337 68 : [psOptions](const std::string &osOutputSRSDef)
7338 : {
7339 34 : psOptions->osOutputSRSDef = osOutputSRSDef;
7340 34 : psOptions->bTransform = true;
7341 758 : })
7342 : .help(_("Reproject/transform to this SRS on output, and assign it "
7343 758 : "as output SRS."));
7344 : }
7345 :
7346 : ///////////////////////////////////////////////////////////////////////
7347 758 : argParser->add_group("Field related options");
7348 :
7349 758 : argParser->add_argument("-addfields")
7350 758 : .flag()
7351 : .action(
7352 2 : [psOptions](const std::string &)
7353 : {
7354 2 : psOptions->bAddMissingFields = true;
7355 2 : psOptions->eAccessMode = ACCESS_APPEND;
7356 758 : })
7357 758 : .help(_("Same as append, but add also any new fields."));
7358 :
7359 758 : argParser->add_argument("-relaxedFieldNameMatch")
7360 758 : .flag()
7361 1 : .action([psOptions](const std::string &)
7362 758 : { psOptions->bExactFieldNameMatch = false; })
7363 : .help(_("Do field name matching between source and existing target "
7364 758 : "layer in a more relaxed way."));
7365 :
7366 758 : argParser->add_argument("-fieldTypeToString")
7367 1516 : .metavar("All|<type1>[,<type2>]...")
7368 : .action(
7369 0 : [psOptions](const std::string &s)
7370 : {
7371 : psOptions->aosFieldTypesToString =
7372 0 : CSLTokenizeStringComplex(s.c_str(), " ,", FALSE, FALSE);
7373 0 : CSLConstList iter = psOptions->aosFieldTypesToString.List();
7374 0 : while (*iter)
7375 : {
7376 0 : if (IsFieldType(*iter))
7377 : {
7378 : /* Do nothing */
7379 : }
7380 0 : else if (EQUAL(*iter, "All"))
7381 : {
7382 0 : psOptions->aosFieldTypesToString.Clear();
7383 0 : psOptions->aosFieldTypesToString.AddString("All");
7384 0 : break;
7385 : }
7386 : else
7387 : {
7388 : throw std::invalid_argument(CPLSPrintf(
7389 : "Unhandled type for fieldTypeToString option : %s",
7390 0 : *iter));
7391 : }
7392 0 : iter++;
7393 : }
7394 758 : })
7395 : .help(_("Converts any field of the specified type to a field of type "
7396 758 : "string in the destination layer."));
7397 :
7398 758 : argParser->add_argument("-mapFieldType")
7399 1516 : .metavar("<srctype>|All=<dsttype>[,<srctype2>=<dsttype2>]...")
7400 : .action(
7401 12 : [psOptions](const std::string &s)
7402 : {
7403 : psOptions->aosMapFieldType =
7404 4 : CSLTokenizeStringComplex(s.c_str(), " ,", FALSE, FALSE);
7405 4 : CSLConstList iter = psOptions->aosMapFieldType.List();
7406 8 : while (*iter)
7407 : {
7408 4 : char *pszKey = nullptr;
7409 4 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
7410 4 : if (pszKey && pszValue)
7411 : {
7412 8 : if (!((IsFieldType(pszKey) || EQUAL(pszKey, "All")) &&
7413 4 : IsFieldType(pszValue)))
7414 : {
7415 0 : CPLFree(pszKey);
7416 : throw std::invalid_argument(CPLSPrintf(
7417 0 : "Invalid value for -mapFieldType : %s", *iter));
7418 : }
7419 : }
7420 4 : CPLFree(pszKey);
7421 4 : iter++;
7422 : }
7423 762 : })
7424 758 : .help(_("Converts any field of the specified type to another type."));
7425 :
7426 758 : argParser->add_argument("-fieldmap")
7427 1516 : .metavar("<field_1>[,<field_2>]...")
7428 : .action(
7429 4 : [psOptions](const std::string &s)
7430 : {
7431 : psOptions->aosFieldMap =
7432 2 : CSLTokenizeStringComplex(s.c_str(), ",", FALSE, FALSE);
7433 758 : })
7434 : .help(_("Specifies the list of field indexes to be copied from the "
7435 758 : "source to the destination."));
7436 :
7437 758 : argParser->add_argument("-splitlistfields")
7438 758 : .store_into(psOptions->bSplitListFields)
7439 : .help(_("Split fields of type list type into as many fields of scalar "
7440 758 : "type as necessary."));
7441 :
7442 758 : argParser->add_argument("-maxsubfields")
7443 1516 : .metavar("<n>")
7444 758 : .scan<'i', int>()
7445 : .action(
7446 0 : [psOptions](const std::string &s)
7447 : {
7448 0 : const int nVal = atoi(s.c_str());
7449 0 : if (nVal > 0)
7450 : {
7451 0 : psOptions->nMaxSplitListSubFields = nVal;
7452 : }
7453 758 : })
7454 : .help(_("To be combined with -splitlistfields to limit the number of "
7455 758 : "subfields created for each split field."));
7456 :
7457 758 : argParser->add_argument("-emptyStrAsNull")
7458 758 : .store_into(psOptions->bEmptyStrAsNull)
7459 758 : .help(_("Treat empty string values as null."));
7460 :
7461 758 : argParser->add_argument("-forceNullable")
7462 758 : .store_into(psOptions->bForceNullable)
7463 : .help(_("Do not propagate not-nullable constraints to target layer if "
7464 758 : "they exist in source layer."));
7465 :
7466 758 : argParser->add_argument("-unsetFieldWidth")
7467 758 : .store_into(psOptions->bUnsetFieldWidth)
7468 758 : .help(_("Set field width and precision to 0."));
7469 :
7470 758 : argParser->add_argument("-unsetDefault")
7471 758 : .store_into(psOptions->bUnsetDefault)
7472 : .help(_("Do not propagate default field values to target layer if they "
7473 758 : "exist in source layer."));
7474 :
7475 758 : argParser->add_argument("-resolveDomains")
7476 758 : .store_into(psOptions->bResolveDomains)
7477 : .help(_("Cause any selected field that is linked to a coded field "
7478 758 : "domain will be accompanied by an additional field."));
7479 :
7480 758 : argParser->add_argument("-dateTimeTo")
7481 1516 : .metavar("UTC|UTC(+|-)<HH>|UTC(+|-)<HH>:<MM>")
7482 : .action(
7483 33 : [psOptions](const std::string &s)
7484 : {
7485 13 : const char *pszFormat = s.c_str();
7486 13 : if (EQUAL(pszFormat, "UTC"))
7487 : {
7488 1 : psOptions->nTZOffsetInSec = 0;
7489 : }
7490 12 : else if (STARTS_WITH_CI(pszFormat, "UTC") &&
7491 11 : (strlen(pszFormat) == strlen("UTC+HH") ||
7492 9 : strlen(pszFormat) == strlen("UTC+HH:MM")) &&
7493 7 : (pszFormat[3] == '+' || pszFormat[3] == '-'))
7494 : {
7495 6 : const int nHour = atoi(pszFormat + strlen("UTC+"));
7496 6 : if (nHour < 0 || nHour > 14)
7497 : {
7498 1 : throw std::invalid_argument("Invalid UTC hour offset.");
7499 : }
7500 5 : else if (strlen(pszFormat) == strlen("UTC+HH"))
7501 : {
7502 0 : psOptions->nTZOffsetInSec = nHour * 3600;
7503 0 : if (pszFormat[3] == '-')
7504 0 : psOptions->nTZOffsetInSec =
7505 0 : -psOptions->nTZOffsetInSec;
7506 : }
7507 : else // if( strlen(pszFormat) == strlen("UTC+HH:MM") )
7508 : {
7509 5 : const int nMin = atoi(pszFormat + strlen("UTC+HH:"));
7510 5 : if (nMin == 0 || nMin == 15 || nMin == 30 || nMin == 45)
7511 : {
7512 4 : psOptions->nTZOffsetInSec =
7513 4 : nHour * 3600 + nMin * 60;
7514 4 : if (pszFormat[3] == '-')
7515 3 : psOptions->nTZOffsetInSec =
7516 3 : -psOptions->nTZOffsetInSec;
7517 : }
7518 : }
7519 : }
7520 12 : if (psOptions->nTZOffsetInSec == TZ_OFFSET_INVALID)
7521 : {
7522 : throw std::invalid_argument(
7523 : "Value of -dateTimeTo should be UTC, UTC(+|-)HH or "
7524 7 : "UTC(+|-)HH:MM with HH in [0,14] and MM=00,15,30,45");
7525 : }
7526 763 : })
7527 : .help(_("Converts date time values from the timezone specified in the "
7528 758 : "source value to the target timezone."));
7529 :
7530 758 : argParser->add_argument("-noNativeData")
7531 758 : .flag()
7532 1 : .action([psOptions](const std::string &)
7533 758 : { psOptions->bNativeData = false; })
7534 758 : .help(_("Disable copying of native data."));
7535 :
7536 : ///////////////////////////////////////////////////////////////////////
7537 758 : argParser->add_group("Advanced geometry and SRS related options");
7538 :
7539 758 : argParser->add_argument("-dim")
7540 1516 : .metavar("layer_dim|2|XY|3|XYZ|XYM|XYZM")
7541 : .action(
7542 24 : [psOptions](const std::string &osDim)
7543 : {
7544 12 : if (EQUAL(osDim.c_str(), "layer_dim"))
7545 2 : psOptions->nCoordDim = COORD_DIM_LAYER_DIM;
7546 18 : else if (EQUAL(osDim.c_str(), "XY") ||
7547 8 : EQUAL(osDim.c_str(), "2"))
7548 3 : psOptions->nCoordDim = 2;
7549 12 : else if (EQUAL(osDim.c_str(), "XYZ") ||
7550 5 : EQUAL(osDim.c_str(), "3"))
7551 3 : psOptions->nCoordDim = 3;
7552 4 : else if (EQUAL(osDim.c_str(), "XYM"))
7553 2 : psOptions->nCoordDim = COORD_DIM_XYM;
7554 2 : else if (EQUAL(osDim.c_str(), "XYZM"))
7555 2 : psOptions->nCoordDim = 4;
7556 : else
7557 : {
7558 : throw std::invalid_argument(CPLSPrintf(
7559 0 : "-dim %s: value not handled.", osDim.c_str()));
7560 : }
7561 770 : })
7562 758 : .help(_("Force the coordinate dimension."));
7563 :
7564 758 : argParser->add_argument("-s_coord_epoch")
7565 1516 : .metavar("<epoch>")
7566 758 : .store_into(psOptions->dfSourceCoordinateEpoch)
7567 758 : .help(_("Assign a coordinate epoch, linked with the source SRS."));
7568 :
7569 758 : argParser->add_argument("-a_coord_epoch")
7570 1516 : .metavar("<epoch>")
7571 758 : .store_into(psOptions->dfOutputCoordinateEpoch)
7572 : .help(_("Assign a coordinate epoch, linked with the output SRS when "
7573 758 : "-a_srs is used."));
7574 :
7575 758 : argParser->add_argument("-t_coord_epoch")
7576 1516 : .metavar("<epoch>")
7577 758 : .store_into(psOptions->dfOutputCoordinateEpoch)
7578 : .help(_("Assign a coordinate epoch, linked with the output SRS when "
7579 758 : "-t_srs is used."));
7580 :
7581 758 : argParser->add_argument("-ct")
7582 1516 : .metavar("<pipeline_def>")
7583 : .action(
7584 6 : [psOptions](const std::string &s)
7585 : {
7586 3 : psOptions->osCTPipeline = s;
7587 3 : psOptions->bTransform = true;
7588 758 : })
7589 : .help(_("Override the default transformation from the source to the "
7590 758 : "target CRS."));
7591 :
7592 758 : argParser->add_argument("-spat_srs")
7593 1516 : .metavar("<srs_def>")
7594 758 : .store_into(psOptions->osSpatSRSDef)
7595 758 : .help(_("Override spatial filter SRS."));
7596 :
7597 758 : argParser->add_argument("-geomfield")
7598 1516 : .metavar("<name>")
7599 : .action(
7600 2 : [psOptions](const std::string &s)
7601 : {
7602 1 : psOptions->osGeomField = s;
7603 1 : psOptions->bGeomFieldSet = true;
7604 758 : })
7605 : .help(_("Name of the geometry field on which the spatial filter "
7606 758 : "operates on."));
7607 :
7608 758 : argParser->add_argument("-segmentize")
7609 1516 : .metavar("<max_dist>")
7610 758 : .store_into(psOptions->dfGeomOpParam)
7611 2 : .action([psOptions](const std::string &)
7612 758 : { psOptions->eGeomOp = GEOMOP_SEGMENTIZE; })
7613 758 : .help(_("Maximum distance between 2 nodes."));
7614 :
7615 758 : argParser->add_argument("-simplify")
7616 1516 : .metavar("<tolerance>")
7617 758 : .store_into(psOptions->dfGeomOpParam)
7618 1 : .action([psOptions](const std::string &)
7619 758 : { psOptions->eGeomOp = GEOMOP_SIMPLIFY_PRESERVE_TOPOLOGY; })
7620 758 : .help(_("Distance tolerance for simplification."));
7621 :
7622 758 : argParser->add_argument("-makevalid")
7623 758 : .flag()
7624 : .action(
7625 10 : [psOptions](const std::string &)
7626 : {
7627 5 : if (!OGRGeometryFactory::haveGEOS())
7628 : {
7629 : throw std::invalid_argument(
7630 0 : "-makevalid only supported for builds against GEOS");
7631 : }
7632 5 : psOptions->bMakeValid = true;
7633 763 : })
7634 : .help(_("Fix geometries to be valid regarding the rules of the Simple "
7635 758 : "Features specification."));
7636 :
7637 758 : argParser->add_argument("-skipinvalid")
7638 758 : .flag()
7639 : .action(
7640 2 : [psOptions](const std::string &)
7641 : {
7642 1 : if (!OGRGeometryFactory::haveGEOS())
7643 : {
7644 : throw std::invalid_argument(
7645 0 : "-skipinvalid only supported for builds against GEOS");
7646 : }
7647 1 : psOptions->bSkipInvalidGeom = true;
7648 759 : })
7649 : .help(_("Whether to skip features with invalid geometries regarding the"
7650 758 : "rules of the Simple Features specification."));
7651 :
7652 758 : argParser->add_argument("-wrapdateline")
7653 758 : .store_into(psOptions->bWrapDateline)
7654 758 : .help(_("Split geometries crossing the dateline meridian."));
7655 :
7656 758 : argParser->add_argument("-datelineoffset")
7657 1516 : .metavar("<val_in_degree>")
7658 758 : .default_value(psOptions->dfDateLineOffset)
7659 758 : .store_into(psOptions->dfDateLineOffset)
7660 758 : .help(_("Offset from dateline in degrees."));
7661 :
7662 758 : argParser->add_argument("-clipsrc")
7663 758 : .nargs(nCountClipSrc)
7664 1516 : .metavar("[<xmin> <ymin> <xmax> <ymax>]|<WKT>|<datasource>|spat_extent")
7665 758 : .help(_("Clip geometries (in source SRS)."));
7666 :
7667 758 : argParser->add_argument("-clipsrcsql")
7668 1516 : .metavar("<sql_statement>")
7669 758 : .store_into(psOptions->osClipSrcSQL)
7670 : .help(_("Select desired geometries from the source clip datasource "
7671 758 : "using an SQL query."));
7672 :
7673 758 : argParser->add_argument("-clipsrclayer")
7674 1516 : .metavar("<layername>")
7675 758 : .store_into(psOptions->osClipSrcLayer)
7676 758 : .help(_("Select the named layer from the source clip datasource."));
7677 :
7678 758 : argParser->add_argument("-clipsrcwhere")
7679 1516 : .metavar("<expression>")
7680 758 : .store_into(psOptions->osClipSrcWhere)
7681 : .help(_("Restrict desired geometries from the source clip layer based "
7682 758 : "on an attribute query."));
7683 :
7684 758 : argParser->add_argument("-clipdst")
7685 758 : .nargs(nCountClipDst)
7686 1516 : .metavar("[<xmin> <ymin> <xmax> <ymax>]|<WKT>|<datasource>")
7687 758 : .help(_("Clip geometries (in target SRS)."));
7688 :
7689 758 : argParser->add_argument("-clipdstsql")
7690 1516 : .metavar("<sql_statement>")
7691 758 : .store_into(psOptions->osClipDstSQL)
7692 : .help(_("Select desired geometries from the destination clip "
7693 758 : "datasource using an SQL query."));
7694 :
7695 758 : argParser->add_argument("-clipdstlayer")
7696 1516 : .metavar("<layername>")
7697 758 : .store_into(psOptions->osClipDstLayer)
7698 : .help(
7699 758 : _("Select the named layer from the destination clip datasource."));
7700 :
7701 758 : argParser->add_argument("-clipdstwhere")
7702 1516 : .metavar("<expression>")
7703 758 : .store_into(psOptions->osClipDstWhere)
7704 : .help(_("Restrict desired geometries from the destination clip layer "
7705 758 : "based on an attribute query."));
7706 :
7707 758 : argParser->add_argument("-explodecollections")
7708 758 : .store_into(psOptions->bExplodeCollections)
7709 : .help(_("Produce one feature for each geometry in any kind of geometry "
7710 758 : "collection in the source file."));
7711 :
7712 758 : argParser->add_argument("-zfield")
7713 1516 : .metavar("<name>")
7714 758 : .store_into(psOptions->osZField)
7715 : .help(_("Uses the specified field to fill the Z coordinate of "
7716 758 : "geometries."));
7717 :
7718 758 : argParser->add_argument("-gcp")
7719 : .metavar(
7720 1516 : "<ungeoref_x> <ungeoref_y> <georef_x> <georef_y> [<elevation>]")
7721 758 : .nargs(4, 5)
7722 758 : .append()
7723 758 : .scan<'g', double>()
7724 758 : .help(_("Add the indicated ground control point."));
7725 :
7726 758 : argParser->add_argument("-tps")
7727 758 : .flag()
7728 1 : .action([psOptions](const std::string &)
7729 758 : { psOptions->nTransformOrder = -1; })
7730 : .help(_("Force use of thin plate spline transformer based on available "
7731 758 : "GCPs."));
7732 :
7733 758 : argParser->add_argument("-order")
7734 1516 : .metavar("1|2|3")
7735 758 : .store_into(psOptions->nTransformOrder)
7736 758 : .help(_("Order of polynomial used for warping."));
7737 :
7738 758 : argParser->add_argument("-xyRes")
7739 1516 : .metavar("<val>[ m|mm|deg]")
7740 : .action(
7741 25 : [psOptions](const std::string &s)
7742 : {
7743 9 : const char *pszVal = s.c_str();
7744 :
7745 9 : char *endptr = nullptr;
7746 9 : psOptions->dfXYRes = CPLStrtodM(pszVal, &endptr);
7747 9 : if (!endptr)
7748 : {
7749 : throw std::invalid_argument(
7750 : "Invalid value for -xyRes. Must be of the form "
7751 0 : "{numeric_value}[ ]?[m|mm|deg]?");
7752 : }
7753 9 : if (*endptr == ' ')
7754 6 : ++endptr;
7755 9 : if (*endptr != 0 && strcmp(endptr, "m") != 0 &&
7756 5 : strcmp(endptr, "mm") != 0 && strcmp(endptr, "deg") != 0)
7757 : {
7758 : throw std::invalid_argument(
7759 : "Invalid value for -xyRes. Must be of the form "
7760 2 : "{numeric_value}[ ]?[m|mm|deg]?");
7761 : }
7762 7 : psOptions->osXYResUnit = endptr;
7763 765 : })
7764 758 : .help(_("Set/override the geometry X/Y coordinate resolution."));
7765 :
7766 758 : argParser->add_argument("-zRes")
7767 1516 : .metavar("<val>[ m|mm]")
7768 : .action(
7769 16 : [psOptions](const std::string &s)
7770 : {
7771 6 : const char *pszVal = s.c_str();
7772 :
7773 6 : char *endptr = nullptr;
7774 6 : psOptions->dfZRes = CPLStrtodM(pszVal, &endptr);
7775 6 : if (!endptr)
7776 : {
7777 : throw std::invalid_argument(
7778 : "Invalid value for -zRes. Must be of the form "
7779 0 : "{numeric_value}[ ]?[m|mm]?");
7780 : }
7781 6 : if (*endptr == ' ')
7782 4 : ++endptr;
7783 6 : if (*endptr != 0 && strcmp(endptr, "m") != 0 &&
7784 3 : strcmp(endptr, "mm") != 0 && strcmp(endptr, "deg") != 0)
7785 : {
7786 : throw std::invalid_argument(
7787 : "Invalid value for -zRes. Must be of the form "
7788 2 : "{numeric_value}[ ]?[m|mm]?");
7789 : }
7790 4 : psOptions->osZResUnit = endptr;
7791 762 : })
7792 758 : .help(_("Set/override the geometry Z coordinate resolution."));
7793 :
7794 758 : argParser->add_argument("-mRes")
7795 1516 : .metavar("<val>")
7796 758 : .store_into(psOptions->dfMRes)
7797 758 : .help(_("Set/override the geometry M coordinate resolution."));
7798 :
7799 758 : argParser->add_argument("-unsetCoordPrecision")
7800 758 : .store_into(psOptions->bUnsetCoordPrecision)
7801 : .help(_("Prevent the geometry coordinate resolution from being set on "
7802 758 : "target layer(s)."));
7803 :
7804 : ///////////////////////////////////////////////////////////////////////
7805 758 : argParser->add_group("Other options");
7806 :
7807 758 : argParser->add_quiet_argument(&psOptions->bQuiet);
7808 :
7809 758 : argParser->add_argument("-progress")
7810 758 : .store_into(psOptions->bDisplayProgress)
7811 : .help(_("Display progress on terminal. Only works if input layers have "
7812 758 : "the 'fast feature count' capability."));
7813 :
7814 : argParser->add_input_format_argument(
7815 : psOptionsForBinary ? &psOptionsForBinary->aosAllowInputDrivers
7816 758 : : nullptr);
7817 :
7818 : argParser->add_open_options_argument(
7819 758 : psOptionsForBinary ? &(psOptionsForBinary->aosOpenOptions) : nullptr);
7820 :
7821 758 : argParser->add_argument("-doo")
7822 1516 : .metavar("<NAME>=<VALUE>")
7823 758 : .append()
7824 0 : .action([psOptions](const std::string &s)
7825 758 : { psOptions->aosDestOpenOptions.AddString(s.c_str()); })
7826 758 : .help(_("Open option(s) for output dataset."));
7827 :
7828 758 : argParser->add_usage_newline();
7829 :
7830 758 : argParser->add_argument("-fid")
7831 1516 : .metavar("<FID>")
7832 758 : .store_into(psOptions->nFIDToFetch)
7833 : .help(_("If provided, only the feature with the specified feature id "
7834 758 : "will be processed."));
7835 :
7836 758 : argParser->add_argument("-preserve_fid")
7837 758 : .store_into(psOptions->bPreserveFID)
7838 : .help(_("Use the FID of the source features instead of letting the "
7839 758 : "output driver automatically assign a new one."));
7840 :
7841 758 : argParser->add_argument("-unsetFid")
7842 758 : .store_into(psOptions->bUnsetFid)
7843 : .help(_("Prevent the name of the source FID column and source feature "
7844 758 : "IDs from being re-used."));
7845 :
7846 : {
7847 758 : auto &group = argParser->add_mutually_exclusive_group();
7848 758 : group.add_argument("-skip", "-skipfailures")
7849 758 : .flag()
7850 : .action(
7851 4 : [psOptions](const std::string &)
7852 : {
7853 4 : psOptions->bSkipFailures = true;
7854 4 : psOptions->nGroupTransactions = 1; /* #2409 */
7855 758 : })
7856 758 : .help(_("Continue after a failure, skipping the failed feature."));
7857 :
7858 758 : auto &arg = group.add_argument("-gt")
7859 1516 : .metavar("<n>|unlimited")
7860 : .action(
7861 8 : [psOptions](const std::string &s)
7862 : {
7863 : /* If skipfailures is already set we should not
7864 : modify nGroupTransactions = 1 #2409 */
7865 4 : if (!psOptions->bSkipFailures)
7866 : {
7867 4 : if (EQUAL(s.c_str(), "unlimited"))
7868 1 : psOptions->nGroupTransactions = -1;
7869 : else
7870 3 : psOptions->nGroupTransactions =
7871 3 : atoi(s.c_str());
7872 : }
7873 758 : })
7874 758 : .help(_("Group <n> features per transaction "));
7875 :
7876 758 : argParser->add_hidden_alias_for(arg, "tg");
7877 : }
7878 :
7879 758 : argParser->add_argument("-limit")
7880 1516 : .metavar("<nb_features>")
7881 758 : .store_into(psOptions->nLimit)
7882 758 : .help(_("Limit the number of features per layer."));
7883 :
7884 758 : argParser->add_argument("-ds_transaction")
7885 758 : .flag()
7886 : .action(
7887 1 : [psOptions](const std::string &)
7888 : {
7889 1 : psOptions->nLayerTransaction = FALSE;
7890 1 : psOptions->bForceTransaction = true;
7891 758 : })
7892 758 : .help(_("Force the use of a dataset level transaction."));
7893 :
7894 : /* Undocumented. Just a provision. Default behavior should be OK */
7895 758 : argParser->add_argument("-lyr_transaction")
7896 758 : .flag()
7897 758 : .hidden()
7898 0 : .action([psOptions](const std::string &)
7899 758 : { psOptions->nLayerTransaction = TRUE; })
7900 758 : .help(_("Force the use of a layer level transaction."));
7901 :
7902 : argParser->add_metadata_item_options_argument(
7903 758 : psOptions->aosMetadataOptions);
7904 :
7905 758 : argParser->add_argument("-nomd")
7906 758 : .flag()
7907 4 : .action([psOptions](const std::string &)
7908 758 : { psOptions->bCopyMD = false; })
7909 : .help(_("Disable copying of metadata from source dataset and layers "
7910 758 : "into target dataset and layers."));
7911 :
7912 758 : if (psOptionsForBinary)
7913 : {
7914 135 : argParser->add_argument("dst_dataset_name")
7915 270 : .metavar("<dst_dataset_name>")
7916 135 : .store_into(psOptionsForBinary->osDestDataSource)
7917 135 : .help(_("Output dataset."));
7918 :
7919 135 : argParser->add_argument("src_dataset_name")
7920 270 : .metavar("<src_dataset_name>")
7921 135 : .store_into(psOptionsForBinary->osDataSource)
7922 135 : .help(_("Input dataset."));
7923 : }
7924 :
7925 758 : argParser->add_argument("layer")
7926 758 : .remaining()
7927 1516 : .metavar("<layer_name>")
7928 758 : .help(_("Layer name"));
7929 758 : return argParser;
7930 : }
7931 :
7932 : /************************************************************************/
7933 : /* GDALVectorTranslateGetParserUsage() */
7934 : /************************************************************************/
7935 :
7936 1 : std::string GDALVectorTranslateGetParserUsage()
7937 : {
7938 : try
7939 : {
7940 2 : GDALVectorTranslateOptions sOptions;
7941 2 : GDALVectorTranslateOptionsForBinary sOptionsForBinary;
7942 : auto argParser = GDALVectorTranslateOptionsGetParser(
7943 2 : &sOptions, &sOptionsForBinary, 1, 1);
7944 1 : return argParser->usage();
7945 : }
7946 0 : catch (const std::exception &err)
7947 : {
7948 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unexpected exception: %s",
7949 0 : err.what());
7950 0 : return std::string();
7951 : }
7952 : }
7953 :
7954 : /************************************************************************/
7955 : /* CHECK_HAS_ENOUGH_ADDITIONAL_ARGS() */
7956 : /************************************************************************/
7957 :
7958 : #ifndef CheckHasEnoughAdditionalArgs_defined
7959 : #define CheckHasEnoughAdditionalArgs_defined
7960 :
7961 51 : static bool CheckHasEnoughAdditionalArgs(CSLConstList papszArgv, int i,
7962 : int nExtraArg, int nArgc)
7963 : {
7964 51 : if (i + nExtraArg >= nArgc)
7965 : {
7966 2 : CPLError(CE_Failure, CPLE_IllegalArg,
7967 2 : "%s option requires %d argument%s", papszArgv[i], nExtraArg,
7968 : nExtraArg == 1 ? "" : "s");
7969 2 : return false;
7970 : }
7971 49 : return true;
7972 : }
7973 : #endif
7974 :
7975 : #define CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(nExtraArg) \
7976 : if (!CheckHasEnoughAdditionalArgs(papszArgv, i, nExtraArg, nArgc)) \
7977 : { \
7978 : return nullptr; \
7979 : }
7980 :
7981 : /************************************************************************/
7982 : /* GDALVectorTranslateOptionsNew() */
7983 : /************************************************************************/
7984 :
7985 : /**
7986 : * allocates a GDALVectorTranslateOptions struct.
7987 : *
7988 : * @param papszArgv NULL terminated list of options (potentially including
7989 : * filename and open options too), or NULL. The accepted options are the ones of
7990 : * the <a href="/programs/ogr2ogr.html">ogr2ogr</a> utility.
7991 : * @param psOptionsForBinary (output) may be NULL (and should generally be
7992 : * NULL), otherwise (gdal_translate_bin.cpp use case) must be allocated with
7993 : * GDALVectorTranslateOptionsForBinaryNew() prior to
7994 : * this function. Will be filled with potentially present filename, open
7995 : * options,...
7996 : * @return pointer to the allocated GDALVectorTranslateOptions struct. Must be
7997 : * freed with GDALVectorTranslateOptionsFree().
7998 : *
7999 : * @since GDAL 2.1
8000 : */
8001 761 : GDALVectorTranslateOptions *GDALVectorTranslateOptionsNew(
8002 : char **papszArgv, GDALVectorTranslateOptionsForBinary *psOptionsForBinary)
8003 : {
8004 1519 : auto psOptions = std::make_unique<GDALVectorTranslateOptions>();
8005 :
8006 : /* -------------------------------------------------------------------- */
8007 : /* Pre-processing for custom syntax that ArgumentParser does not */
8008 : /* support. */
8009 : /* -------------------------------------------------------------------- */
8010 :
8011 1519 : CPLStringList aosArgv;
8012 761 : const int nArgc = CSLCount(papszArgv);
8013 761 : int nCountClipSrc = 0;
8014 761 : int nCountClipDst = 0;
8015 3605 : for (int i = 0;
8016 3605 : i < nArgc && papszArgv != nullptr && papszArgv[i] != nullptr; i++)
8017 : {
8018 2848 : if (EQUAL(papszArgv[i], "-gcp"))
8019 : {
8020 : // repeated argument of varying size: not handled by argparse.
8021 :
8022 18 : CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(4);
8023 18 : char *endptr = nullptr;
8024 : /* -gcp pixel line easting northing [elev] */
8025 :
8026 18 : psOptions->oGCPs.nGCPCount++;
8027 36 : psOptions->oGCPs.pasGCPs = static_cast<GDAL_GCP *>(
8028 18 : CPLRealloc(psOptions->oGCPs.pasGCPs,
8029 18 : sizeof(GDAL_GCP) * psOptions->oGCPs.nGCPCount));
8030 18 : GDALInitGCPs(1, psOptions->oGCPs.pasGCPs +
8031 18 : psOptions->oGCPs.nGCPCount - 1);
8032 :
8033 18 : psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1]
8034 18 : .dfGCPPixel = CPLAtof(papszArgv[++i]);
8035 18 : psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1].dfGCPLine =
8036 18 : CPLAtof(papszArgv[++i]);
8037 18 : psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1].dfGCPX =
8038 18 : CPLAtof(papszArgv[++i]);
8039 18 : psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1].dfGCPY =
8040 18 : CPLAtof(papszArgv[++i]);
8041 33 : if (papszArgv[i + 1] != nullptr &&
8042 15 : (CPLStrtod(papszArgv[i + 1], &endptr) != 0.0 ||
8043 15 : papszArgv[i + 1][0] == '0'))
8044 : {
8045 : /* Check that last argument is really a number and not a
8046 : * filename */
8047 : /* looking like a number (see ticket #863) */
8048 0 : if (endptr && *endptr == 0)
8049 0 : psOptions->oGCPs.pasGCPs[psOptions->oGCPs.nGCPCount - 1]
8050 0 : .dfGCPZ = CPLAtof(papszArgv[++i]);
8051 : }
8052 :
8053 : /* should set id and info? */
8054 : }
8055 :
8056 2830 : else if (EQUAL(papszArgv[i], "-clipsrc"))
8057 : {
8058 18 : if (nCountClipSrc)
8059 : {
8060 1 : CPLError(CE_Failure, CPLE_AppDefined, "Duplicate argument %s",
8061 1 : papszArgv[i]);
8062 1 : return nullptr;
8063 : }
8064 : // argparse doesn't handle well variable number of values
8065 : // just before the positional arguments, so we have to detect
8066 : // it manually and set the correct number.
8067 17 : nCountClipSrc = 1;
8068 17 : CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
8069 19 : if (CPLGetValueType(papszArgv[i + 1]) != CPL_VALUE_STRING &&
8070 3 : i + 4 < nArgc)
8071 : {
8072 2 : nCountClipSrc = 4;
8073 : }
8074 :
8075 54 : for (int j = 0; j < 1 + nCountClipSrc; ++j)
8076 : {
8077 38 : aosArgv.AddString(papszArgv[i]);
8078 38 : ++i;
8079 : }
8080 16 : --i;
8081 : }
8082 :
8083 2812 : else if (EQUAL(papszArgv[i], "-clipdst"))
8084 : {
8085 17 : if (nCountClipDst)
8086 : {
8087 1 : CPLError(CE_Failure, CPLE_AppDefined, "Duplicate argument %s",
8088 1 : papszArgv[i]);
8089 1 : return nullptr;
8090 : }
8091 : // argparse doesn't handle well variable number of values
8092 : // just before the positional arguments, so we have to detect
8093 : // it manually and set the correct number.
8094 16 : nCountClipDst = 1;
8095 16 : CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
8096 19 : if (CPLGetValueType(papszArgv[i + 1]) != CPL_VALUE_STRING &&
8097 4 : i + 4 < nArgc)
8098 : {
8099 3 : nCountClipDst = 4;
8100 : }
8101 :
8102 54 : for (int j = 0; j < 1 + nCountClipDst; ++j)
8103 : {
8104 39 : aosArgv.AddString(papszArgv[i]);
8105 39 : ++i;
8106 : }
8107 15 : --i;
8108 : }
8109 :
8110 : else
8111 : {
8112 2795 : aosArgv.AddString(papszArgv[i]);
8113 : }
8114 : }
8115 :
8116 : try
8117 : {
8118 : auto argParser = GDALVectorTranslateOptionsGetParser(
8119 1511 : psOptions.get(), psOptionsForBinary, nCountClipSrc, nCountClipDst);
8120 :
8121 : // Collect non-positional arguments for VectorTranslateFrom() case
8122 756 : psOptions->aosArguments =
8123 1513 : argParser->get_non_positional_arguments(aosArgv);
8124 :
8125 756 : argParser->parse_args_without_binary_name(aosArgv.List());
8126 :
8127 730 : if (psOptionsForBinary)
8128 130 : psOptionsForBinary->bQuiet = psOptions->bQuiet;
8129 :
8130 738 : if (auto oSpat = argParser->present<std::vector<double>>("-spat"))
8131 : {
8132 16 : OGRLinearRing oRing;
8133 8 : const double dfMinX = (*oSpat)[0];
8134 8 : const double dfMinY = (*oSpat)[1];
8135 8 : const double dfMaxX = (*oSpat)[2];
8136 8 : const double dfMaxY = (*oSpat)[3];
8137 :
8138 8 : oRing.addPoint(dfMinX, dfMinY);
8139 8 : oRing.addPoint(dfMinX, dfMaxY);
8140 8 : oRing.addPoint(dfMaxX, dfMaxY);
8141 8 : oRing.addPoint(dfMaxX, dfMinY);
8142 8 : oRing.addPoint(dfMinX, dfMinY);
8143 :
8144 16 : auto poSpatialFilter = std::make_shared<OGRPolygon>();
8145 8 : poSpatialFilter->addRing(&oRing);
8146 8 : psOptions->poSpatialFilter = poSpatialFilter;
8147 : }
8148 :
8149 730 : if (auto oClipSrc =
8150 730 : argParser->present<std::vector<std::string>>("-clipsrc"))
8151 : {
8152 15 : const std::string &osVal = (*oClipSrc)[0];
8153 :
8154 15 : psOptions->poClipSrc.reset();
8155 15 : psOptions->osClipSrcDS.clear();
8156 :
8157 : VSIStatBufL sStat;
8158 15 : psOptions->bClipSrc = true;
8159 15 : if (oClipSrc->size() == 4)
8160 : {
8161 1 : const double dfMinX = CPLAtofM((*oClipSrc)[0].c_str());
8162 1 : const double dfMinY = CPLAtofM((*oClipSrc)[1].c_str());
8163 1 : const double dfMaxX = CPLAtofM((*oClipSrc)[2].c_str());
8164 1 : const double dfMaxY = CPLAtofM((*oClipSrc)[3].c_str());
8165 :
8166 2 : OGRLinearRing oRing;
8167 :
8168 1 : oRing.addPoint(dfMinX, dfMinY);
8169 1 : oRing.addPoint(dfMinX, dfMaxY);
8170 1 : oRing.addPoint(dfMaxX, dfMaxY);
8171 1 : oRing.addPoint(dfMaxX, dfMinY);
8172 1 : oRing.addPoint(dfMinX, dfMinY);
8173 :
8174 2 : auto poPoly = std::make_shared<OGRPolygon>();
8175 1 : psOptions->poClipSrc = poPoly;
8176 1 : poPoly->addRing(&oRing);
8177 : }
8178 14 : else if ((STARTS_WITH_CI(osVal.c_str(), "POLYGON") ||
8179 18 : STARTS_WITH_CI(osVal.c_str(), "MULTIPOLYGON")) &&
8180 4 : VSIStatL(osVal.c_str(), &sStat) != 0)
8181 : {
8182 4 : OGRGeometry *poGeom = nullptr;
8183 4 : OGRGeometryFactory::createFromWkt(osVal.c_str(), nullptr,
8184 : &poGeom);
8185 4 : psOptions->poClipSrc.reset(poGeom);
8186 4 : if (psOptions->poClipSrc == nullptr)
8187 : {
8188 0 : CPLError(
8189 : CE_Failure, CPLE_IllegalArg,
8190 : "Invalid -clipsrc geometry. Must be a valid POLYGON or "
8191 : "MULTIPOLYGON WKT");
8192 0 : return nullptr;
8193 : }
8194 : }
8195 10 : else if (EQUAL(osVal.c_str(), "spat_extent"))
8196 : {
8197 : // Nothing to do
8198 : }
8199 : else
8200 : {
8201 9 : psOptions->osClipSrcDS = osVal;
8202 : }
8203 : }
8204 :
8205 730 : if (auto oClipDst =
8206 730 : argParser->present<std::vector<std::string>>("-clipdst"))
8207 : {
8208 14 : const std::string &osVal = (*oClipDst)[0];
8209 :
8210 14 : psOptions->poClipDst.reset();
8211 14 : psOptions->osClipDstDS.clear();
8212 :
8213 : VSIStatBufL sStat;
8214 14 : if (oClipDst->size() == 4)
8215 : {
8216 2 : const double dfMinX = CPLAtofM((*oClipDst)[0].c_str());
8217 2 : const double dfMinY = CPLAtofM((*oClipDst)[1].c_str());
8218 2 : const double dfMaxX = CPLAtofM((*oClipDst)[2].c_str());
8219 2 : const double dfMaxY = CPLAtofM((*oClipDst)[3].c_str());
8220 :
8221 4 : OGRLinearRing oRing;
8222 :
8223 2 : oRing.addPoint(dfMinX, dfMinY);
8224 2 : oRing.addPoint(dfMinX, dfMaxY);
8225 2 : oRing.addPoint(dfMaxX, dfMaxY);
8226 2 : oRing.addPoint(dfMaxX, dfMinY);
8227 2 : oRing.addPoint(dfMinX, dfMinY);
8228 :
8229 4 : auto poPoly = std::make_shared<OGRPolygon>();
8230 2 : psOptions->poClipDst = poPoly;
8231 2 : poPoly->addRing(&oRing);
8232 : }
8233 12 : else if ((STARTS_WITH_CI(osVal.c_str(), "POLYGON") ||
8234 15 : STARTS_WITH_CI(osVal.c_str(), "MULTIPOLYGON")) &&
8235 3 : VSIStatL(osVal.c_str(), &sStat) != 0)
8236 : {
8237 3 : OGRGeometry *poGeom = nullptr;
8238 3 : OGRGeometryFactory::createFromWkt(osVal.c_str(), nullptr,
8239 : &poGeom);
8240 3 : psOptions->poClipDst.reset(poGeom);
8241 3 : if (psOptions->poClipDst == nullptr)
8242 : {
8243 0 : CPLError(
8244 : CE_Failure, CPLE_IllegalArg,
8245 : "Invalid -clipdst geometry. Must be a valid POLYGON or "
8246 : "MULTIPOLYGON WKT");
8247 0 : return nullptr;
8248 : }
8249 : }
8250 : else
8251 : {
8252 9 : psOptions->osClipDstDS = osVal;
8253 : }
8254 : }
8255 :
8256 1460 : auto layers = argParser->present<std::vector<std::string>>("layer");
8257 730 : if (layers)
8258 : {
8259 49 : for (const auto &layer : *layers)
8260 : {
8261 34 : psOptions->aosLayers.AddString(layer.c_str());
8262 : }
8263 : }
8264 730 : if (psOptionsForBinary)
8265 : {
8266 130 : psOptionsForBinary->eAccessMode = psOptions->eAccessMode;
8267 130 : psOptionsForBinary->osFormat = psOptions->osFormat;
8268 :
8269 130 : if (!(CPLTestBool(
8270 : psOptionsForBinary->aosOpenOptions.FetchNameValueDef(
8271 : "NATIVE_DATA",
8272 : psOptionsForBinary->aosOpenOptions.FetchNameValueDef(
8273 : "@NATIVE_DATA", "TRUE")))))
8274 : {
8275 0 : psOptions->bNativeData = false;
8276 : }
8277 :
8278 130 : if (psOptions->bNativeData &&
8279 129 : psOptionsForBinary->aosOpenOptions.FetchNameValue(
8280 259 : "NATIVE_DATA") == nullptr &&
8281 129 : psOptionsForBinary->aosOpenOptions.FetchNameValue(
8282 : "@NATIVE_DATA") == nullptr)
8283 : {
8284 : psOptionsForBinary->aosOpenOptions.AddString(
8285 129 : "@NATIVE_DATA=YES");
8286 : }
8287 : }
8288 :
8289 730 : return psOptions.release();
8290 : }
8291 24 : catch (const std::exception &err)
8292 : {
8293 24 : CPLError(CE_Failure, CPLE_AppDefined, "%s", err.what());
8294 24 : if (psOptionsForBinary)
8295 1 : psOptionsForBinary->bShowUsageIfError = true;
8296 24 : return nullptr;
8297 : }
8298 : }
8299 :
8300 : /************************************************************************/
8301 : /* GDALVectorTranslateOptionsFree() */
8302 : /************************************************************************/
8303 :
8304 : /**
8305 : * Frees the GDALVectorTranslateOptions struct.
8306 : *
8307 : * @param psOptions the options struct for GDALVectorTranslate().
8308 : * @since GDAL 2.1
8309 : */
8310 :
8311 730 : void GDALVectorTranslateOptionsFree(GDALVectorTranslateOptions *psOptions)
8312 : {
8313 730 : delete psOptions;
8314 730 : }
8315 :
8316 : /************************************************************************/
8317 : /* GDALVectorTranslateOptionsSetProgress() */
8318 : /************************************************************************/
8319 :
8320 : /**
8321 : * Set a progress function.
8322 : *
8323 : * @param psOptions the options struct for GDALVectorTranslate().
8324 : * @param pfnProgress the progress callback.
8325 : * @param pProgressData the user data for the progress callback.
8326 : *
8327 : * @since GDAL 2.1
8328 : */
8329 :
8330 131 : void GDALVectorTranslateOptionsSetProgress(
8331 : GDALVectorTranslateOptions *psOptions, GDALProgressFunc pfnProgress,
8332 : void *pProgressData)
8333 : {
8334 131 : psOptions->pfnProgress = pfnProgress ? pfnProgress : GDALDummyProgress;
8335 131 : psOptions->pProgressData = pProgressData;
8336 131 : if (pfnProgress == GDALTermProgress)
8337 129 : psOptions->bQuiet = false;
8338 131 : }
8339 :
8340 : #undef CHECK_HAS_ENOUGH_ADDITIONAL_ARGS
|