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