Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: Implements OGRVRTDataSource class.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
9 : * Copyright (c) 2009-2014, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 : #include "ogr_vrt.h"
16 :
17 : #include <stdlib.h>
18 : #include <string.h>
19 : #include <algorithm>
20 : #include <set>
21 : #include <string>
22 :
23 : #include "cpl_conv.h"
24 : #include "cpl_error.h"
25 : #include "cpl_minixml.h"
26 : #include "cpl_string.h"
27 : #include "gdal_priv.h"
28 : #include "ogr_core.h"
29 : #include "ogr_feature.h"
30 : #include "ogr_spatialref.h"
31 : #include "ogrlayerpool.h"
32 : #include "ogrunionlayer.h"
33 : #include "ogrwarpedlayer.h"
34 : #include "ogrsf_frmts.h"
35 : #include "ogrvrtgeometrytypes.h"
36 :
37 : /************************************************************************/
38 : /* OGRVRTDataSource() */
39 : /************************************************************************/
40 :
41 402 : OGRVRTDataSource::OGRVRTDataSource(GDALDriver *poDriverIn)
42 : : papoLayers(nullptr), paeLayerType(nullptr), nLayers(0), psTree(nullptr),
43 : nCallLevel(0), poLayerPool(nullptr), poParentDS(nullptr),
44 402 : bRecursionDetected(false)
45 : {
46 402 : poDriver = poDriverIn;
47 402 : }
48 :
49 : /************************************************************************/
50 : /* ~OGRVRTDataSource() */
51 : /************************************************************************/
52 :
53 804 : OGRVRTDataSource::~OGRVRTDataSource()
54 :
55 : {
56 402 : OGRVRTDataSource::CloseDependentDatasets();
57 :
58 402 : CPLFree(paeLayerType);
59 :
60 402 : if (psTree != nullptr)
61 402 : CPLDestroyXMLNode(psTree);
62 :
63 402 : delete poLayerPool;
64 804 : }
65 :
66 : /************************************************************************/
67 : /* CloseDependentDatasets() */
68 : /************************************************************************/
69 :
70 402 : int OGRVRTDataSource::CloseDependentDatasets()
71 : {
72 402 : const int bHasClosedDependentDatasets = nLayers > 0;
73 1111 : for (int i = 0; i < nLayers; i++)
74 : {
75 709 : delete papoLayers[i];
76 : }
77 402 : CPLFree(papoLayers);
78 402 : nLayers = 0;
79 402 : papoLayers = nullptr;
80 402 : return bHasClosedDependentDatasets;
81 : }
82 :
83 : /************************************************************************/
84 : /* InstantiateWarpedLayer() */
85 : /************************************************************************/
86 :
87 21 : OGRLayer *OGRVRTDataSource::InstantiateWarpedLayer(CPLXMLNode *psLTree,
88 : const char *pszVRTDirectory,
89 : int bUpdate, int nRecLevel)
90 : {
91 21 : if (!EQUAL(psLTree->pszValue, "OGRVRTWarpedLayer"))
92 0 : return nullptr;
93 :
94 21 : OGRLayer *poSrcLayer = nullptr;
95 :
96 21 : for (CPLXMLNode *psSubNode = psLTree->psChild; psSubNode != nullptr;
97 0 : psSubNode = psSubNode->psNext)
98 : {
99 21 : if (psSubNode->eType != CXT_Element)
100 0 : continue;
101 :
102 21 : poSrcLayer = InstantiateLayer(psSubNode, pszVRTDirectory, bUpdate,
103 : nRecLevel + 1);
104 21 : if (poSrcLayer != nullptr)
105 21 : break;
106 : }
107 :
108 21 : if (poSrcLayer == nullptr)
109 : {
110 0 : CPLError(CE_Failure, CPLE_AppDefined,
111 : "Cannot instantiate source layer");
112 0 : return nullptr;
113 : }
114 :
115 21 : const char *pszTargetSRS = CPLGetXMLValue(psLTree, "TargetSRS", nullptr);
116 21 : if (pszTargetSRS == nullptr)
117 : {
118 1 : CPLError(CE_Failure, CPLE_AppDefined,
119 : "Missing TargetSRS element within OGRVRTWarpedLayer");
120 1 : delete poSrcLayer;
121 1 : return nullptr;
122 : }
123 :
124 : const char *pszGeomFieldName =
125 20 : CPLGetXMLValue(psLTree, "WarpedGeomFieldName", nullptr);
126 20 : int iGeomField = 0;
127 20 : if (pszGeomFieldName != nullptr)
128 : {
129 : iGeomField =
130 3 : poSrcLayer->GetLayerDefn()->GetGeomFieldIndex(pszGeomFieldName);
131 3 : if (iGeomField < 0)
132 : {
133 1 : CPLError(CE_Failure, CPLE_AppDefined,
134 : "Cannot find source geometry field '%s'",
135 : pszGeomFieldName);
136 1 : delete poSrcLayer;
137 1 : return nullptr;
138 : }
139 : }
140 :
141 19 : const OGRSpatialReference *poSrcSRS = nullptr;
142 19 : const char *pszSourceSRS = CPLGetXMLValue(psLTree, "SrcSRS", nullptr);
143 :
144 19 : if (pszSourceSRS == nullptr)
145 : {
146 16 : if (iGeomField < poSrcLayer->GetLayerDefn()->GetGeomFieldCount())
147 : {
148 13 : poSrcSRS = poSrcLayer->GetLayerDefn()
149 13 : ->GetGeomFieldDefn(iGeomField)
150 13 : ->GetSpatialRef();
151 13 : if (poSrcSRS != nullptr)
152 13 : poSrcSRS = poSrcSRS->Clone();
153 : }
154 : }
155 : else
156 : {
157 3 : auto poSrcSRSNonConst = new OGRSpatialReference();
158 3 : poSrcSRSNonConst->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
159 3 : if (poSrcSRSNonConst->SetFromUserInput(
160 : pszSourceSRS,
161 3 : OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get()) !=
162 : OGRERR_NONE)
163 : {
164 1 : delete poSrcSRSNonConst;
165 : }
166 : else
167 : {
168 2 : poSrcSRS = poSrcSRSNonConst;
169 : }
170 : }
171 :
172 19 : if (poSrcSRS == nullptr)
173 : {
174 4 : CPLError(CE_Failure, CPLE_AppDefined, "Failed to import source SRS");
175 4 : delete poSrcLayer;
176 4 : return nullptr;
177 : }
178 :
179 15 : OGRSpatialReference *poTargetSRS = new OGRSpatialReference();
180 15 : poTargetSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
181 15 : if (poTargetSRS->SetFromUserInput(
182 : pszTargetSRS,
183 15 : OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get()) !=
184 : OGRERR_NONE)
185 : {
186 1 : delete poTargetSRS;
187 1 : poTargetSRS = nullptr;
188 : }
189 :
190 15 : if (poTargetSRS == nullptr)
191 : {
192 1 : CPLError(CE_Failure, CPLE_AppDefined, "Failed to import target SRS");
193 1 : delete poSrcSRS;
194 1 : delete poSrcLayer;
195 1 : return nullptr;
196 : }
197 :
198 14 : if (pszSourceSRS == nullptr && poSrcSRS->IsSame(poTargetSRS))
199 : {
200 1 : delete poSrcSRS;
201 1 : delete poTargetSRS;
202 1 : return poSrcLayer;
203 : }
204 :
205 : OGRCoordinateTransformation *poCT =
206 13 : OGRCreateCoordinateTransformation(poSrcSRS, poTargetSRS);
207 : OGRCoordinateTransformation *poReversedCT =
208 : poCT != nullptr
209 13 : ? OGRCreateCoordinateTransformation(poTargetSRS, poSrcSRS)
210 13 : : nullptr;
211 :
212 13 : delete poSrcSRS;
213 13 : delete poTargetSRS;
214 :
215 13 : if (poCT == nullptr)
216 : {
217 0 : delete poSrcLayer;
218 0 : return nullptr;
219 : }
220 :
221 : // Build the OGRWarpedLayer.
222 : OGRWarpedLayer *poLayer =
223 13 : new OGRWarpedLayer(poSrcLayer, iGeomField, TRUE, poCT, poReversedCT);
224 :
225 : // Set Extent if provided.
226 13 : const char *pszExtentXMin = CPLGetXMLValue(psLTree, "ExtentXMin", nullptr);
227 13 : const char *pszExtentYMin = CPLGetXMLValue(psLTree, "ExtentYMin", nullptr);
228 13 : const char *pszExtentXMax = CPLGetXMLValue(psLTree, "ExtentXMax", nullptr);
229 13 : const char *pszExtentYMax = CPLGetXMLValue(psLTree, "ExtentYMax", nullptr);
230 13 : if (pszExtentXMin != nullptr && pszExtentYMin != nullptr &&
231 1 : pszExtentXMax != nullptr && pszExtentYMax != nullptr)
232 : {
233 1 : poLayer->SetExtent(CPLAtof(pszExtentXMin), CPLAtof(pszExtentYMin),
234 : CPLAtof(pszExtentXMax), CPLAtof(pszExtentYMax));
235 : }
236 :
237 13 : return poLayer;
238 : }
239 :
240 : /************************************************************************/
241 : /* InstantiateUnionLayer() */
242 : /************************************************************************/
243 :
244 84 : OGRLayer *OGRVRTDataSource::InstantiateUnionLayer(CPLXMLNode *psLTree,
245 : const char *pszVRTDirectory,
246 : int bUpdate, int nRecLevel)
247 : {
248 84 : if (!EQUAL(psLTree->pszValue, "OGRVRTUnionLayer"))
249 0 : return nullptr;
250 :
251 : // Get layer name.
252 84 : const char *pszLayerName = CPLGetXMLValue(psLTree, "name", nullptr);
253 :
254 84 : if (pszLayerName == nullptr)
255 : {
256 0 : CPLError(CE_Failure, CPLE_AppDefined,
257 : "Missing name attribute on OGRVRTUnionLayer");
258 0 : return nullptr;
259 : }
260 :
261 : // Do we have a fixed geometry type? If not derive from the
262 : // source layer.
263 84 : const char *pszGType = CPLGetXMLValue(psLTree, "GeometryType", nullptr);
264 84 : bool bGlobalGeomTypeSet = false;
265 84 : OGRwkbGeometryType eGlobalGeomType = wkbUnknown;
266 84 : if (pszGType != nullptr)
267 : {
268 12 : bGlobalGeomTypeSet = true;
269 12 : int bError = FALSE;
270 12 : eGlobalGeomType = OGRVRTGetGeometryType(pszGType, &bError);
271 12 : if (bError)
272 : {
273 0 : CPLError(CE_Failure, CPLE_AppDefined,
274 : "GeometryType %s not recognised.", pszGType);
275 0 : return nullptr;
276 : }
277 : }
278 :
279 : // Apply a spatial reference system if provided.
280 84 : const char *pszLayerSRS = CPLGetXMLValue(psLTree, "LayerSRS", nullptr);
281 84 : OGRSpatialReference *poGlobalSRS = nullptr;
282 84 : bool bGlobalSRSSet = false;
283 84 : if (pszLayerSRS != nullptr)
284 : {
285 9 : bGlobalSRSSet = true;
286 9 : if (!EQUAL(pszLayerSRS, "NULL"))
287 : {
288 9 : OGRSpatialReference oSRS;
289 9 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
290 :
291 9 : if (oSRS.SetFromUserInput(
292 : pszLayerSRS,
293 : OGRSpatialReference::
294 9 : SET_FROM_USER_INPUT_LIMITATIONS_get()) != OGRERR_NONE)
295 : {
296 0 : CPLError(CE_Failure, CPLE_AppDefined,
297 : "Failed to import LayerSRS `%s'.", pszLayerSRS);
298 0 : return nullptr;
299 : }
300 9 : poGlobalSRS = oSRS.Clone();
301 : }
302 : }
303 :
304 : // Find field declarations.
305 84 : OGRFieldDefn **papoFields = nullptr;
306 84 : int nFields = 0;
307 84 : OGRUnionLayerGeomFieldDefn **papoGeomFields = nullptr;
308 84 : int nGeomFields = 0;
309 :
310 441 : for (CPLXMLNode *psSubNode = psLTree->psChild; psSubNode != nullptr;
311 357 : psSubNode = psSubNode->psNext)
312 : {
313 357 : if (psSubNode->eType != CXT_Element)
314 84 : continue;
315 :
316 273 : if (EQUAL(psSubNode->pszValue, "Field"))
317 : {
318 : // Field name.
319 0 : const char *l_pszName = CPLGetXMLValue(psSubNode, "name", nullptr);
320 0 : if (l_pszName == nullptr)
321 : {
322 0 : CPLError(CE_Failure, CPLE_AppDefined,
323 : "Unable to identify Field name.");
324 0 : break;
325 : }
326 :
327 0 : OGRFieldDefn oFieldDefn(l_pszName, OFTString);
328 :
329 : // Type.
330 0 : const char *pszArg = CPLGetXMLValue(psSubNode, "type", nullptr);
331 :
332 0 : if (pszArg != nullptr)
333 : {
334 0 : int iType = 0; // Used after for.
335 :
336 0 : for (; iType <= static_cast<int>(OFTMaxType); iType++)
337 : {
338 0 : if (EQUAL(pszArg, OGRFieldDefn::GetFieldTypeName(
339 : static_cast<OGRFieldType>(iType))))
340 : {
341 0 : oFieldDefn.SetType(static_cast<OGRFieldType>(iType));
342 0 : break;
343 : }
344 : }
345 :
346 0 : if (iType > static_cast<int>(OFTMaxType))
347 : {
348 0 : CPLError(CE_Failure, CPLE_AppDefined,
349 : "Unable to identify Field type '%s'.", pszArg);
350 0 : break;
351 : }
352 : }
353 :
354 : // Width and precision.
355 0 : const int nWidth = atoi(CPLGetXMLValue(psSubNode, "width", "0"));
356 0 : if (nWidth < 0)
357 : {
358 0 : CPLError(CE_Failure, CPLE_IllegalArg,
359 : "Invalid width for field %s.", l_pszName);
360 0 : break;
361 : }
362 0 : oFieldDefn.SetWidth(nWidth);
363 :
364 : const int nPrecision =
365 0 : atoi(CPLGetXMLValue(psSubNode, "precision", "0"));
366 0 : if (nPrecision < 0 || nPrecision > 1024)
367 : {
368 0 : CPLError(CE_Failure, CPLE_IllegalArg,
369 : "Invalid precision for field %s.", l_pszName);
370 0 : break;
371 : }
372 0 : oFieldDefn.SetPrecision(nPrecision);
373 :
374 : papoFields = static_cast<OGRFieldDefn **>(
375 0 : CPLRealloc(papoFields, sizeof(OGRFieldDefn *) * (nFields + 1)));
376 0 : papoFields[nFields] = new OGRFieldDefn(&oFieldDefn);
377 0 : nFields++;
378 : }
379 273 : else if (EQUAL(psSubNode->pszValue, "GeometryField"))
380 : {
381 12 : const char *l_pszName = CPLGetXMLValue(psSubNode, "name", nullptr);
382 12 : if (l_pszName == nullptr)
383 : {
384 0 : CPLError(CE_Failure, CPLE_AppDefined,
385 : "Unable to identify GeometryField name.");
386 0 : break;
387 : }
388 :
389 12 : pszGType = CPLGetXMLValue(psSubNode, "GeometryType", nullptr);
390 12 : if (pszGType == nullptr && nGeomFields == 0)
391 3 : pszGType = CPLGetXMLValue(psLTree, "GeometryType", nullptr);
392 12 : OGRwkbGeometryType eGeomType = wkbUnknown;
393 12 : bool bGeomTypeSet = false;
394 12 : if (pszGType != nullptr)
395 : {
396 3 : int bError = FALSE;
397 3 : eGeomType = OGRVRTGetGeometryType(pszGType, &bError);
398 3 : bGeomTypeSet = true;
399 3 : if (bError || eGeomType == wkbNone)
400 : {
401 0 : CPLError(CE_Failure, CPLE_AppDefined,
402 : "GeometryType %s not recognised.", pszGType);
403 0 : break;
404 : }
405 : }
406 :
407 12 : const char *pszSRS = CPLGetXMLValue(psSubNode, "SRS", nullptr);
408 12 : if (pszSRS == nullptr && nGeomFields == 0)
409 6 : pszSRS = CPLGetXMLValue(psLTree, "LayerSRS", nullptr);
410 12 : OGRSpatialReference *poSRS = nullptr;
411 12 : bool bSRSSet = false;
412 12 : if (pszSRS != nullptr)
413 : {
414 3 : bSRSSet = true;
415 3 : if (!EQUAL(pszSRS, "NULL"))
416 : {
417 3 : OGRSpatialReference oSRS;
418 3 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
419 :
420 3 : if (oSRS.SetFromUserInput(
421 : pszSRS,
422 : OGRSpatialReference::
423 3 : SET_FROM_USER_INPUT_LIMITATIONS_get()) !=
424 : OGRERR_NONE)
425 : {
426 0 : CPLError(CE_Failure, CPLE_AppDefined,
427 : "Failed to import SRS `%s'.", pszSRS);
428 0 : break;
429 : }
430 3 : poSRS = oSRS.Clone();
431 : }
432 : }
433 :
434 : OGRUnionLayerGeomFieldDefn *poFieldDefn =
435 12 : new OGRUnionLayerGeomFieldDefn(l_pszName, eGeomType);
436 12 : if (poSRS != nullptr)
437 : {
438 3 : poFieldDefn->SetSpatialRef(poSRS);
439 3 : poSRS->Dereference();
440 : }
441 12 : poFieldDefn->bGeomTypeSet = bGeomTypeSet;
442 12 : poFieldDefn->bSRSSet = bSRSSet;
443 :
444 : const char *pszExtentXMin =
445 12 : CPLGetXMLValue(psSubNode, "ExtentXMin", nullptr);
446 : const char *pszExtentYMin =
447 12 : CPLGetXMLValue(psSubNode, "ExtentYMin", nullptr);
448 : const char *pszExtentXMax =
449 12 : CPLGetXMLValue(psSubNode, "ExtentXMax", nullptr);
450 : const char *pszExtentYMax =
451 12 : CPLGetXMLValue(psSubNode, "ExtentYMax", nullptr);
452 12 : if (pszExtentXMin != nullptr && pszExtentYMin != nullptr &&
453 3 : pszExtentXMax != nullptr && pszExtentYMax != nullptr)
454 : {
455 3 : poFieldDefn->sStaticEnvelope.MinX = CPLAtof(pszExtentXMin);
456 3 : poFieldDefn->sStaticEnvelope.MinY = CPLAtof(pszExtentYMin);
457 3 : poFieldDefn->sStaticEnvelope.MaxX = CPLAtof(pszExtentXMax);
458 3 : poFieldDefn->sStaticEnvelope.MaxY = CPLAtof(pszExtentYMax);
459 : }
460 :
461 : papoGeomFields =
462 24 : static_cast<OGRUnionLayerGeomFieldDefn **>(CPLRealloc(
463 : papoGeomFields,
464 12 : sizeof(OGRUnionLayerGeomFieldDefn *) * (nGeomFields + 1)));
465 12 : papoGeomFields[nGeomFields] = poFieldDefn;
466 12 : nGeomFields++;
467 : }
468 : }
469 :
470 : // Set Extent if provided.
471 84 : const char *pszExtentXMin = CPLGetXMLValue(psLTree, "ExtentXMin", nullptr);
472 84 : const char *pszExtentYMin = CPLGetXMLValue(psLTree, "ExtentYMin", nullptr);
473 84 : const char *pszExtentXMax = CPLGetXMLValue(psLTree, "ExtentXMax", nullptr);
474 84 : const char *pszExtentYMax = CPLGetXMLValue(psLTree, "ExtentYMax", nullptr);
475 :
476 84 : if (eGlobalGeomType != wkbNone && nGeomFields == 0 &&
477 66 : (bGlobalGeomTypeSet || bGlobalSRSSet ||
478 0 : (pszExtentXMin != nullptr && pszExtentYMin != nullptr &&
479 0 : pszExtentXMax != nullptr && pszExtentYMax != nullptr)))
480 : {
481 : OGRUnionLayerGeomFieldDefn *poFieldDefn =
482 9 : new OGRUnionLayerGeomFieldDefn("", eGlobalGeomType);
483 9 : if (poGlobalSRS != nullptr)
484 : {
485 9 : poFieldDefn->SetSpatialRef(poGlobalSRS);
486 9 : poGlobalSRS->Dereference();
487 9 : poGlobalSRS = nullptr;
488 : }
489 9 : poFieldDefn->bGeomTypeSet = bGlobalGeomTypeSet;
490 9 : poFieldDefn->bSRSSet = bGlobalSRSSet;
491 9 : if (pszExtentXMin != nullptr && pszExtentYMin != nullptr &&
492 9 : pszExtentXMax != nullptr && pszExtentYMax != nullptr)
493 : {
494 9 : poFieldDefn->sStaticEnvelope.MinX = CPLAtof(pszExtentXMin);
495 9 : poFieldDefn->sStaticEnvelope.MinY = CPLAtof(pszExtentYMin);
496 9 : poFieldDefn->sStaticEnvelope.MaxX = CPLAtof(pszExtentXMax);
497 9 : poFieldDefn->sStaticEnvelope.MaxY = CPLAtof(pszExtentYMax);
498 : }
499 :
500 : papoGeomFields = static_cast<OGRUnionLayerGeomFieldDefn **>(
501 18 : CPLRealloc(papoGeomFields, sizeof(OGRUnionLayerGeomFieldDefn *) *
502 9 : (nGeomFields + 1)));
503 9 : papoGeomFields[nGeomFields] = poFieldDefn;
504 9 : nGeomFields++;
505 : }
506 : else
507 : {
508 75 : delete poGlobalSRS;
509 75 : poGlobalSRS = nullptr;
510 : }
511 :
512 : // Find source layers.
513 84 : int nSrcLayers = 0;
514 84 : OGRLayer **papoSrcLayers = nullptr;
515 :
516 441 : for (CPLXMLNode *psSubNode = psLTree->psChild; psSubNode != nullptr;
517 357 : psSubNode = psSubNode->psNext)
518 : {
519 357 : if (psSubNode->eType != CXT_Element)
520 84 : continue;
521 :
522 273 : OGRLayer *poSrcLayer = InstantiateLayer(psSubNode, pszVRTDirectory,
523 : bUpdate, nRecLevel + 1);
524 273 : if (poSrcLayer != nullptr)
525 : {
526 322 : papoSrcLayers = static_cast<OGRLayer **>(CPLRealloc(
527 161 : papoSrcLayers, sizeof(OGRLayer *) * (nSrcLayers + 1)));
528 161 : papoSrcLayers[nSrcLayers] = poSrcLayer;
529 161 : nSrcLayers++;
530 : }
531 : }
532 :
533 84 : if (nSrcLayers == 0)
534 : {
535 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find source layers");
536 0 : for (int iField = 0; iField < nFields; iField++)
537 0 : delete papoFields[iField];
538 0 : CPLFree(papoFields);
539 0 : for (int iField = 0; iField < nGeomFields; iField++)
540 0 : delete papoGeomFields[iField];
541 0 : CPLFree(papoGeomFields);
542 0 : return nullptr;
543 : }
544 :
545 : // Build the OGRUnionLayer.
546 : OGRUnionLayer *poLayer =
547 84 : new OGRUnionLayer(pszLayerName, nSrcLayers, papoSrcLayers, TRUE);
548 :
549 : // Set the source layer field name attribute.
550 : const char *pszSourceLayerFieldName =
551 84 : CPLGetXMLValue(psLTree, "SourceLayerFieldName", nullptr);
552 84 : poLayer->SetSourceLayerFieldName(pszSourceLayerFieldName);
553 :
554 : // Set the PreserveSrcFID attribute.
555 84 : bool bPreserveSrcFID = false;
556 : const char *pszPreserveFID =
557 84 : CPLGetXMLValue(psLTree, "PreserveSrcFID", nullptr);
558 84 : if (pszPreserveFID != nullptr)
559 9 : bPreserveSrcFID = CPLTestBool(pszPreserveFID);
560 84 : poLayer->SetPreserveSrcFID(bPreserveSrcFID);
561 :
562 : // Set fields.
563 84 : FieldUnionStrategy eFieldStrategy = FIELD_UNION_ALL_LAYERS;
564 : const char *pszFieldStrategy =
565 84 : CPLGetXMLValue(psLTree, "FieldStrategy", nullptr);
566 84 : if (pszFieldStrategy != nullptr)
567 : {
568 15 : if (EQUAL(pszFieldStrategy, "FirstLayer"))
569 3 : eFieldStrategy = FIELD_FROM_FIRST_LAYER;
570 12 : else if (EQUAL(pszFieldStrategy, "Union"))
571 0 : eFieldStrategy = FIELD_UNION_ALL_LAYERS;
572 12 : else if (EQUAL(pszFieldStrategy, "Intersection"))
573 12 : eFieldStrategy = FIELD_INTERSECTION_ALL_LAYERS;
574 : else
575 : {
576 0 : CPLError(CE_Warning, CPLE_AppDefined,
577 : "Unhandled value for FieldStrategy `%s'.",
578 : pszFieldStrategy);
579 : }
580 : }
581 84 : if (nFields != 0 || nGeomFields > 1)
582 : {
583 6 : if (pszFieldStrategy != nullptr)
584 0 : CPLError(CE_Warning, CPLE_AppDefined,
585 : "Ignoring FieldStrategy value, "
586 : "because explicit Field or GeometryField is provided");
587 6 : eFieldStrategy = FIELD_SPECIFIED;
588 : }
589 :
590 153 : poLayer->SetFields(
591 : eFieldStrategy, nFields, papoFields,
592 69 : (nGeomFields == 0 && eGlobalGeomType == wkbNone) ? -1 : nGeomFields,
593 : papoGeomFields);
594 :
595 84 : for (int iField = 0; iField < nFields; iField++)
596 0 : delete papoFields[iField];
597 84 : CPLFree(papoFields);
598 105 : for (int iField = 0; iField < nGeomFields; iField++)
599 21 : delete papoGeomFields[iField];
600 84 : CPLFree(papoGeomFields);
601 :
602 : // Set FeatureCount if provided.
603 : const char *pszFeatureCount =
604 84 : CPLGetXMLValue(psLTree, "FeatureCount", nullptr);
605 84 : if (pszFeatureCount != nullptr)
606 : {
607 9 : poLayer->SetFeatureCount(atoi(pszFeatureCount));
608 : }
609 :
610 84 : return poLayer;
611 : }
612 :
613 : /************************************************************************/
614 : /* InstantiateLayerInternal() */
615 : /************************************************************************/
616 :
617 : OGRLayer *
618 1128 : OGRVRTDataSource::InstantiateLayerInternal(CPLXMLNode *psLTree,
619 : const char *pszVRTDirectory,
620 : int bUpdate, int nRecLevel)
621 : {
622 : // Create the layer object.
623 1128 : if (EQUAL(psLTree->pszValue, "OGRVRTLayer"))
624 : {
625 905 : OGRVRTLayer *poVRTLayer = new OGRVRTLayer(this);
626 :
627 905 : if (!poVRTLayer->FastInitialize(psLTree, pszVRTDirectory, bUpdate))
628 : {
629 3 : delete poVRTLayer;
630 3 : return nullptr;
631 : }
632 :
633 902 : return poVRTLayer;
634 : }
635 223 : else if (EQUAL(psLTree->pszValue, "OGRVRTWarpedLayer") && nRecLevel < 30)
636 : {
637 21 : return InstantiateWarpedLayer(psLTree, pszVRTDirectory, bUpdate,
638 21 : nRecLevel + 1);
639 : }
640 202 : else if (EQUAL(psLTree->pszValue, "OGRVRTUnionLayer") && nRecLevel < 30)
641 : {
642 84 : return InstantiateUnionLayer(psLTree, pszVRTDirectory, bUpdate,
643 84 : nRecLevel + 1);
644 : }
645 :
646 118 : return nullptr;
647 : }
648 :
649 : /************************************************************************/
650 : /* OGRVRTOpenProxiedLayer() */
651 : /************************************************************************/
652 :
653 : typedef struct
654 : {
655 : OGRVRTDataSource *poDS;
656 : CPLXMLNode *psNode;
657 : char *pszVRTDirectory;
658 : bool bUpdate;
659 : } PooledInitData;
660 :
661 113 : static OGRLayer *OGRVRTOpenProxiedLayer(void *pUserData)
662 : {
663 113 : PooledInitData *pData = static_cast<PooledInitData *>(pUserData);
664 226 : return pData->poDS->InstantiateLayerInternal(
665 113 : pData->psNode, pData->pszVRTDirectory, pData->bUpdate, 0);
666 : }
667 :
668 : /************************************************************************/
669 : /* OGRVRTFreeProxiedLayerUserData() */
670 : /************************************************************************/
671 :
672 4 : static void OGRVRTFreeProxiedLayerUserData(void *pUserData)
673 : {
674 4 : PooledInitData *pData = static_cast<PooledInitData *>(pUserData);
675 4 : CPLFree(pData->pszVRTDirectory);
676 4 : CPLFree(pData);
677 4 : }
678 :
679 : /************************************************************************/
680 : /* InstantiateLayer() */
681 : /************************************************************************/
682 :
683 1019 : OGRLayer *OGRVRTDataSource::InstantiateLayer(CPLXMLNode *psLTree,
684 : const char *pszVRTDirectory,
685 : int bUpdate, int nRecLevel)
686 : {
687 1019 : if (poLayerPool != nullptr && EQUAL(psLTree->pszValue, "OGRVRTLayer"))
688 : {
689 : PooledInitData *pData =
690 4 : (PooledInitData *)CPLMalloc(sizeof(PooledInitData));
691 4 : pData->poDS = this;
692 4 : pData->psNode = psLTree;
693 4 : pData->pszVRTDirectory = CPLStrdup(pszVRTDirectory);
694 4 : pData->bUpdate = CPL_TO_BOOL(bUpdate);
695 : return new OGRProxiedLayer(poLayerPool, OGRVRTOpenProxiedLayer,
696 4 : OGRVRTFreeProxiedLayerUserData, pData);
697 : }
698 :
699 1015 : return InstantiateLayerInternal(psLTree, pszVRTDirectory, bUpdate,
700 1015 : nRecLevel);
701 : }
702 :
703 : /************************************************************************/
704 : /* CountOGRVRTLayers() */
705 : /************************************************************************/
706 :
707 9246 : static int CountOGRVRTLayers(CPLXMLNode *psTree)
708 : {
709 9246 : if (psTree->eType != CXT_Element)
710 5097 : return 0;
711 :
712 4149 : int nCount = 0;
713 4149 : if (EQUAL(psTree->pszValue, "OGRVRTLayer"))
714 796 : ++nCount;
715 :
716 12994 : for (CPLXMLNode *psNode = psTree->psChild; psNode != nullptr;
717 8845 : psNode = psNode->psNext)
718 : {
719 8845 : nCount += CountOGRVRTLayers(psNode);
720 : }
721 :
722 4149 : return nCount;
723 : }
724 :
725 : /************************************************************************/
726 : /* Initialize() */
727 : /************************************************************************/
728 :
729 402 : bool OGRVRTDataSource::Initialize(CPLXMLNode *psTreeIn, const char *pszNewName,
730 : int bUpdate)
731 :
732 : {
733 402 : CPLAssert(nLayers == 0);
734 :
735 402 : AddForbiddenNames(pszNewName);
736 :
737 402 : psTree = psTreeIn;
738 :
739 : // Set name, and capture the directory path so we can use it
740 : // for relative datasources.
741 804 : CPLString osVRTDirectory = CPLGetPath(pszNewName);
742 :
743 : // Look for the OGRVRTDataSource node, it might be after an <xml> node.
744 402 : CPLXMLNode *psVRTDSXML = CPLGetXMLNode(psTree, "=OGRVRTDataSource");
745 402 : if (psVRTDSXML == nullptr)
746 : {
747 1 : CPLError(CE_Failure, CPLE_AppDefined,
748 : "Did not find the <OGRVRTDataSource> node in the root of the "
749 : "document, this is not really an OGR VRT.");
750 1 : return false;
751 : }
752 :
753 : // Determine if we must proxy layers.
754 401 : const int nOGRVRTLayerCount = CountOGRVRTLayers(psVRTDSXML);
755 :
756 : const int nMaxSimultaneouslyOpened =
757 401 : std::max(atoi(CPLGetConfigOption("OGR_VRT_MAX_OPENED", "100")), 1);
758 401 : if (nOGRVRTLayerCount > nMaxSimultaneouslyOpened)
759 2 : poLayerPool = new OGRLayerPool(nMaxSimultaneouslyOpened);
760 :
761 : // Apply any dataset level metadata.
762 401 : oMDMD.XMLInit(psVRTDSXML, TRUE);
763 :
764 : // Look for layers.
765 1127 : for (CPLXMLNode *psLTree = psVRTDSXML->psChild; psLTree != nullptr;
766 726 : psLTree = psLTree->psNext)
767 : {
768 726 : if (psLTree->eType != CXT_Element)
769 1 : continue;
770 :
771 : // Create the layer object.
772 725 : OGRLayer *poLayer = InstantiateLayer(psLTree, osVRTDirectory, bUpdate);
773 725 : if (poLayer == nullptr)
774 16 : continue;
775 :
776 : // Add layer to data source layer list.
777 709 : nLayers++;
778 709 : papoLayers = static_cast<OGRLayer **>(
779 709 : CPLRealloc(papoLayers, sizeof(OGRLayer *) * nLayers));
780 709 : papoLayers[nLayers - 1] = poLayer;
781 :
782 709 : paeLayerType = static_cast<OGRLayerType *>(
783 709 : CPLRealloc(paeLayerType, sizeof(int) * nLayers));
784 709 : if (poLayerPool != nullptr && EQUAL(psLTree->pszValue, "OGRVRTLayer"))
785 : {
786 0 : paeLayerType[nLayers - 1] = OGR_VRT_PROXIED_LAYER;
787 : }
788 709 : else if (EQUAL(psLTree->pszValue, "OGRVRTLayer"))
789 : {
790 612 : paeLayerType[nLayers - 1] = OGR_VRT_LAYER;
791 : }
792 : else
793 : {
794 97 : paeLayerType[nLayers - 1] = OGR_VRT_OTHER_LAYER;
795 : }
796 : }
797 :
798 401 : return true;
799 : }
800 :
801 : /************************************************************************/
802 : /* TestCapability() */
803 : /************************************************************************/
804 :
805 139 : int OGRVRTDataSource::TestCapability(const char *pszCap)
806 : {
807 139 : if (EQUAL(pszCap, ODsCCurveGeometries))
808 29 : return true;
809 110 : else if (EQUAL(pszCap, ODsCZGeometries))
810 24 : return true;
811 86 : else if (EQUAL(pszCap, ODsCMeasuredGeometries))
812 24 : return true;
813 :
814 62 : return false;
815 : }
816 :
817 : /************************************************************************/
818 : /* GetLayer() */
819 : /************************************************************************/
820 :
821 897 : OGRLayer *OGRVRTDataSource::GetLayer(int iLayer)
822 :
823 : {
824 897 : if (iLayer < 0 || iLayer >= nLayers)
825 32 : return nullptr;
826 :
827 865 : return papoLayers[iLayer];
828 : }
829 :
830 : /************************************************************************/
831 : /* AddForbiddenNames() */
832 : /************************************************************************/
833 :
834 405 : void OGRVRTDataSource::AddForbiddenNames(const char *pszOtherDSName)
835 : {
836 405 : aosOtherDSNameSet.insert(pszOtherDSName);
837 405 : }
838 :
839 : /************************************************************************/
840 : /* IsInForbiddenNames() */
841 : /************************************************************************/
842 :
843 79 : bool OGRVRTDataSource::IsInForbiddenNames(const char *pszOtherDSName) const
844 : {
845 79 : return aosOtherDSNameSet.find(pszOtherDSName) != aosOtherDSNameSet.end();
846 : }
847 :
848 : /************************************************************************/
849 : /* GetFileList() */
850 : /************************************************************************/
851 :
852 16 : char **OGRVRTDataSource::GetFileList()
853 : {
854 32 : CPLStringList oList;
855 16 : oList.AddString(GetDescription());
856 32 : for (int i = 0; i < nLayers; i++)
857 : {
858 16 : OGRLayer *poLayer = papoLayers[i];
859 16 : OGRVRTLayer *poVRTLayer = nullptr;
860 16 : switch (paeLayerType[nLayers - 1])
861 : {
862 0 : case OGR_VRT_PROXIED_LAYER:
863 : poVRTLayer = (OGRVRTLayer *)((OGRProxiedLayer *)poLayer)
864 0 : ->GetUnderlyingLayer();
865 0 : break;
866 7 : case OGR_VRT_LAYER:
867 7 : poVRTLayer = (OGRVRTLayer *)poLayer;
868 7 : break;
869 9 : default:
870 9 : break;
871 : }
872 16 : if (poVRTLayer != nullptr)
873 : {
874 7 : GDALDataset *poSrcDS = poVRTLayer->GetSrcDataset();
875 7 : if (poSrcDS != nullptr)
876 : {
877 7 : char **papszFileList = poSrcDS->GetFileList();
878 7 : char **papszIter = papszFileList;
879 35 : for (; papszIter != nullptr && *papszIter != nullptr;
880 : papszIter++)
881 : {
882 28 : if (oList.FindString(*papszIter) < 0)
883 28 : oList.AddString(*papszIter);
884 : }
885 7 : CSLDestroy(papszFileList);
886 : }
887 : }
888 : }
889 32 : return oList.StealList();
890 : }
|