Line data Source code
1 : /******************************************************************************
2 : * Project: OGR
3 : * Purpose: OGRGMLASDriver implementation
4 : * Author: Even Rouault, <even dot rouault at spatialys dot com>
5 : *
6 : * Initial development funded by the European Earth observation programme
7 : * Copernicus
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2016, Even Rouault, <even dot rouault at spatialys dot com>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "ogr_gmlas.h"
32 :
33 : #include "ogr_mem.h"
34 : #include "cpl_sha256.h"
35 :
36 : #include <algorithm>
37 :
38 : /************************************************************************/
39 : /* XercesInitializer::XercesInitializer() */
40 : /************************************************************************/
41 :
42 187 : OGRGMLASDataSource::XercesInitializer::XercesInitializer()
43 : {
44 187 : OGRInitializeXerces();
45 187 : }
46 :
47 : /************************************************************************/
48 : /* XercesInitializer::~XercesInitializer() */
49 : /************************************************************************/
50 :
51 187 : OGRGMLASDataSource::XercesInitializer::~XercesInitializer()
52 : {
53 187 : OGRDeinitializeXerces();
54 187 : }
55 :
56 : /************************************************************************/
57 : /* OGRGMLASDataSource() */
58 : /************************************************************************/
59 :
60 187 : OGRGMLASDataSource::OGRGMLASDataSource()
61 187 : : m_poFieldsMetadataLayer(std::make_unique<OGRMemLayer>(
62 0 : szOGR_FIELDS_METADATA, nullptr, wkbNone)),
63 187 : m_poLayersMetadataLayer(std::make_unique<OGRMemLayer>(
64 0 : szOGR_LAYERS_METADATA, nullptr, wkbNone)),
65 187 : m_poRelationshipsLayer(std::make_unique<OGRMemLayer>(
66 0 : szOGR_LAYER_RELATIONSHIPS, nullptr, wkbNone)),
67 : m_poOtherMetadataLayer(
68 748 : std::make_unique<OGRMemLayer>(szOGR_OTHER_METADATA, nullptr, wkbNone))
69 : {
70 : // Initialize m_poFieldsMetadataLayer
71 : {
72 374 : OGRFieldDefn oFieldDefn(szLAYER_NAME, OFTString);
73 187 : m_poFieldsMetadataLayer->CreateField(&oFieldDefn);
74 : }
75 : {
76 374 : OGRFieldDefn oFieldDefn(szFIELD_INDEX, OFTInteger);
77 187 : m_poFieldsMetadataLayer->CreateField(&oFieldDefn);
78 : }
79 : {
80 374 : OGRFieldDefn oFieldDefn(szFIELD_NAME, OFTString);
81 187 : m_poFieldsMetadataLayer->CreateField(&oFieldDefn);
82 : }
83 : {
84 374 : OGRFieldDefn oFieldDefn(szFIELD_XPATH, OFTString);
85 187 : m_poFieldsMetadataLayer->CreateField(&oFieldDefn);
86 : }
87 : {
88 374 : OGRFieldDefn oFieldDefn(szFIELD_TYPE, OFTString);
89 187 : m_poFieldsMetadataLayer->CreateField(&oFieldDefn);
90 : }
91 : {
92 374 : OGRFieldDefn oFieldDefn(szFIELD_IS_LIST, OFTInteger);
93 187 : oFieldDefn.SetSubType(OFSTBoolean);
94 187 : m_poFieldsMetadataLayer->CreateField(&oFieldDefn);
95 : }
96 : {
97 374 : OGRFieldDefn oFieldDefn(szFIELD_MIN_OCCURS, OFTInteger);
98 187 : m_poFieldsMetadataLayer->CreateField(&oFieldDefn);
99 : }
100 : {
101 374 : OGRFieldDefn oFieldDefn(szFIELD_MAX_OCCURS, OFTInteger);
102 187 : m_poFieldsMetadataLayer->CreateField(&oFieldDefn);
103 : }
104 : {
105 374 : OGRFieldDefn oFieldDefn(szFIELD_REPETITION_ON_SEQUENCE, OFTInteger);
106 187 : oFieldDefn.SetSubType(OFSTBoolean);
107 187 : m_poFieldsMetadataLayer->CreateField(&oFieldDefn);
108 : }
109 : {
110 374 : OGRFieldDefn oFieldDefn(szFIELD_DEFAULT_VALUE, OFTString);
111 187 : m_poFieldsMetadataLayer->CreateField(&oFieldDefn);
112 : }
113 : {
114 374 : OGRFieldDefn oFieldDefn(szFIELD_FIXED_VALUE, OFTString);
115 187 : m_poFieldsMetadataLayer->CreateField(&oFieldDefn);
116 : }
117 : {
118 374 : OGRFieldDefn oFieldDefn(szFIELD_CATEGORY, OFTString);
119 187 : m_poFieldsMetadataLayer->CreateField(&oFieldDefn);
120 : }
121 : {
122 374 : OGRFieldDefn oFieldDefn(szFIELD_RELATED_LAYER, OFTString);
123 187 : m_poFieldsMetadataLayer->CreateField(&oFieldDefn);
124 : }
125 : {
126 374 : OGRFieldDefn oFieldDefn(szFIELD_JUNCTION_LAYER, OFTString);
127 187 : m_poFieldsMetadataLayer->CreateField(&oFieldDefn);
128 : }
129 : {
130 374 : OGRFieldDefn oFieldDefn(szFIELD_DOCUMENTATION, OFTString);
131 187 : m_poFieldsMetadataLayer->CreateField(&oFieldDefn);
132 : }
133 :
134 : // Initialize m_poLayersMetadataLayer
135 : {
136 374 : OGRFieldDefn oFieldDefn(szLAYER_NAME, OFTString);
137 187 : m_poLayersMetadataLayer->CreateField(&oFieldDefn);
138 : }
139 : {
140 374 : OGRFieldDefn oFieldDefn(szLAYER_XPATH, OFTString);
141 187 : m_poLayersMetadataLayer->CreateField(&oFieldDefn);
142 : }
143 : {
144 374 : OGRFieldDefn oFieldDefn(szLAYER_CATEGORY, OFTString);
145 187 : m_poLayersMetadataLayer->CreateField(&oFieldDefn);
146 : }
147 : {
148 374 : OGRFieldDefn oFieldDefn(szLAYER_PKID_NAME, OFTString);
149 187 : m_poLayersMetadataLayer->CreateField(&oFieldDefn);
150 : }
151 : {
152 374 : OGRFieldDefn oFieldDefn(szLAYER_PARENT_PKID_NAME, OFTString);
153 187 : m_poLayersMetadataLayer->CreateField(&oFieldDefn);
154 : }
155 : {
156 374 : OGRFieldDefn oFieldDefn(szLAYER_DOCUMENTATION, OFTString);
157 187 : m_poLayersMetadataLayer->CreateField(&oFieldDefn);
158 : }
159 :
160 : // Initialize m_poRelationshipsLayer
161 : {
162 374 : OGRFieldDefn oFieldDefn(szPARENT_LAYER, OFTString);
163 187 : m_poRelationshipsLayer->CreateField(&oFieldDefn);
164 : }
165 : {
166 374 : OGRFieldDefn oFieldDefn(szPARENT_PKID, OFTString);
167 187 : m_poRelationshipsLayer->CreateField(&oFieldDefn);
168 : }
169 : {
170 374 : OGRFieldDefn oFieldDefn(szPARENT_ELEMENT_NAME, OFTString);
171 187 : m_poRelationshipsLayer->CreateField(&oFieldDefn);
172 : }
173 : {
174 374 : OGRFieldDefn oFieldDefn(szCHILD_LAYER, OFTString);
175 187 : m_poRelationshipsLayer->CreateField(&oFieldDefn);
176 : }
177 : {
178 374 : OGRFieldDefn oFieldDefn(szCHILD_PKID, OFTString);
179 187 : m_poRelationshipsLayer->CreateField(&oFieldDefn);
180 : }
181 :
182 : // Initialize m_poOtherMetadataLayer
183 : {
184 374 : OGRFieldDefn oFieldDefn(szKEY, OFTString);
185 187 : m_poOtherMetadataLayer->CreateField(&oFieldDefn);
186 : }
187 : {
188 374 : OGRFieldDefn oFieldDefn(szVALUE, OFTString);
189 187 : m_poOtherMetadataLayer->CreateField(&oFieldDefn);
190 : }
191 187 : }
192 :
193 : /************************************************************************/
194 : /* GetLayerCount() */
195 : /************************************************************************/
196 :
197 8510 : int OGRGMLASDataSource::GetLayerCount()
198 : {
199 8510 : return static_cast<int>(m_apoLayers.size() +
200 8510 : m_apoRequestedMetadataLayers.size());
201 : }
202 :
203 : /************************************************************************/
204 : /* GetLayer() */
205 : /************************************************************************/
206 :
207 8901 : OGRLayer *OGRGMLASDataSource::GetLayer(int i)
208 : {
209 8901 : const int nBaseLayers = static_cast<int>(m_apoLayers.size());
210 8901 : if (i >= nBaseLayers)
211 : {
212 153 : RunFirstPassIfNeeded(nullptr, nullptr, nullptr);
213 153 : if (i - nBaseLayers <
214 153 : static_cast<int>(m_apoRequestedMetadataLayers.size()))
215 152 : return m_apoRequestedMetadataLayers[i - nBaseLayers];
216 : }
217 :
218 8749 : if (i < 0 || i >= nBaseLayers)
219 2 : return nullptr;
220 8747 : return m_apoLayers[i].get();
221 : }
222 :
223 : /************************************************************************/
224 : /* GetLayerByName() */
225 : /************************************************************************/
226 :
227 600 : OGRLayer *OGRGMLASDataSource::GetLayerByName(const char *pszName)
228 : {
229 600 : if (OGRLayer *poLayer = GDALDataset::GetLayerByName(pszName))
230 576 : return poLayer;
231 :
232 : OGRLayer *apoLayers[] = {
233 24 : m_poFieldsMetadataLayer.get(), m_poLayersMetadataLayer.get(),
234 24 : m_poRelationshipsLayer.get(), m_poOtherMetadataLayer.get()};
235 52 : for (auto *poLayer : apoLayers)
236 : {
237 51 : if (EQUAL(pszName, poLayer->GetName()))
238 : {
239 23 : if (std::find(m_apoRequestedMetadataLayers.begin(),
240 : m_apoRequestedMetadataLayers.end(),
241 23 : poLayer) == m_apoRequestedMetadataLayers.end())
242 : {
243 23 : m_apoRequestedMetadataLayers.push_back(poLayer);
244 : }
245 23 : RunFirstPassIfNeeded(nullptr, nullptr, nullptr);
246 23 : return poLayer;
247 : }
248 : }
249 :
250 1 : return nullptr;
251 : }
252 :
253 : /************************************************************************/
254 : /* TranslateClasses() */
255 : /************************************************************************/
256 :
257 15386 : void OGRGMLASDataSource::TranslateClasses(OGRGMLASLayer *poParentLayer,
258 : const GMLASFeatureClass &oFC)
259 : {
260 15386 : const std::vector<GMLASFeatureClass> &aoClasses = oFC.GetNestedClasses();
261 :
262 : // CPLDebug("GMLAS", "TranslateClasses(%s,%s)",
263 : // oFC.GetName().c_str(), oFC.GetXPath().c_str());
264 :
265 15386 : m_apoLayers.emplace_back(std::make_unique<OGRGMLASLayer>(
266 15386 : this, oFC, poParentLayer, m_oConf.m_bAlwaysGenerateOGRId));
267 15386 : auto poLayer = m_apoLayers.back().get();
268 :
269 18708 : for (size_t i = 0; i < aoClasses.size(); ++i)
270 : {
271 3322 : TranslateClasses(poLayer, aoClasses[i]);
272 : }
273 15386 : }
274 :
275 : /************************************************************************/
276 : /* GMLASTopElementParser */
277 : /************************************************************************/
278 :
279 : class GMLASTopElementParser : public DefaultHandler
280 : {
281 : std::vector<PairURIFilename> m_aoFilenames{};
282 : int m_nStartElementCounter = 0;
283 : bool m_bFinish = false;
284 : bool m_bFoundSWE = false;
285 : std::map<CPLString, CPLString> m_oMapDocNSURIToPrefix{};
286 :
287 : public:
288 182 : GMLASTopElementParser() = default;
289 :
290 : void Parse(const CPLString &osFilename,
291 : const std::shared_ptr<VSIVirtualHandle> &fp);
292 :
293 148 : const std::vector<PairURIFilename> &GetXSDs() const
294 : {
295 148 : return m_aoFilenames;
296 : }
297 :
298 151 : bool GetSWE() const
299 : {
300 151 : return m_bFoundSWE;
301 : }
302 :
303 151 : const std::map<CPLString, CPLString> &GetMapDocNSURIToPrefix() const
304 : {
305 151 : return m_oMapDocNSURIToPrefix;
306 : }
307 :
308 : virtual void startElement(const XMLCh *const uri,
309 : const XMLCh *const localname,
310 : const XMLCh *const qname,
311 : const Attributes &attrs) override;
312 : };
313 :
314 : /************************************************************************/
315 : /* Parse() */
316 : /************************************************************************/
317 :
318 151 : void GMLASTopElementParser::Parse(const CPLString &osFilename,
319 : const std::shared_ptr<VSIVirtualHandle> &fp)
320 : {
321 : auto poSAXReader =
322 302 : std::unique_ptr<SAX2XMLReader>(XMLReaderFactory::createXMLReader());
323 :
324 151 : poSAXReader->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);
325 151 : poSAXReader->setFeature(XMLUni::fgSAX2CoreNameSpacePrefixes, true);
326 :
327 151 : poSAXReader->setContentHandler(this);
328 151 : poSAXReader->setLexicalHandler(this);
329 151 : poSAXReader->setDTDHandler(this);
330 :
331 151 : poSAXReader->setFeature(XMLUni::fgXercesLoadSchema, false);
332 :
333 302 : GMLASErrorHandler oErrorHandler;
334 151 : poSAXReader->setErrorHandler(&oErrorHandler);
335 :
336 302 : GMLASInputSource oIS(osFilename, fp);
337 :
338 : try
339 : {
340 302 : XMLPScanToken oToFill;
341 151 : if (poSAXReader->parseFirst(oIS, oToFill))
342 : {
343 302 : while (!m_bFinish && poSAXReader->parseNext(oToFill))
344 : {
345 : // do nothing
346 : }
347 : }
348 : }
349 0 : catch (const XMLException &toCatch)
350 : {
351 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s",
352 0 : transcode(toCatch.getMessage()).c_str());
353 : }
354 0 : catch (const SAXException &toCatch)
355 : {
356 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s",
357 0 : transcode(toCatch.getMessage()).c_str());
358 : }
359 151 : }
360 :
361 : /************************************************************************/
362 : /* startElement() */
363 : /************************************************************************/
364 :
365 151 : void GMLASTopElementParser::startElement(const XMLCh *const /*uri*/,
366 : const XMLCh *const /*localname*/,
367 : const XMLCh *const /*qname*/,
368 : const Attributes &attrs)
369 : {
370 151 : m_nStartElementCounter++;
371 :
372 929 : for (unsigned int i = 0; i < attrs.getLength(); i++)
373 : {
374 1556 : const std::string osAttrURIPrefix(transcode(attrs.getURI(i)));
375 1556 : const std::string osAttrLocalname(transcode(attrs.getLocalName(i)));
376 1556 : const std::string osAttrValue(transcode(attrs.getValue(i)));
377 :
378 928 : if (osAttrURIPrefix == szXSI_URI &&
379 150 : osAttrLocalname == szSCHEMA_LOCATION)
380 : {
381 124 : CPLDebug("GMLAS", "%s=%s", szSCHEMA_LOCATION, osAttrValue.c_str());
382 :
383 : const CPLStringList aosTokens(
384 248 : CSLTokenizeString2(osAttrValue.c_str(), " ", 0));
385 124 : const int nTokens = aosTokens.size();
386 124 : if ((nTokens % 2) == 0)
387 : {
388 331 : for (int j = 0; j < nTokens; j += 2)
389 : {
390 410 : if (!STARTS_WITH(aosTokens[j], szWFS_URI) &&
391 203 : !(EQUAL(aosTokens[j], szGML_URI) ||
392 410 : STARTS_WITH(aosTokens[j],
393 : (CPLString(szGML_URI) + "/").c_str())))
394 : {
395 203 : CPLDebug("GMLAS", "Schema to analyze: %s -> %s",
396 : aosTokens[j], aosTokens[j + 1]);
397 203 : m_aoFilenames.push_back(
398 406 : PairURIFilename(aosTokens[j], aosTokens[j + 1]));
399 : }
400 : }
401 : }
402 : }
403 680 : else if (osAttrURIPrefix == szXSI_URI &&
404 26 : osAttrLocalname == szNO_NAMESPACE_SCHEMA_LOCATION)
405 : {
406 26 : CPLDebug("GMLAS", "%s=%s", szNO_NAMESPACE_SCHEMA_LOCATION,
407 : osAttrValue.c_str());
408 26 : m_aoFilenames.push_back(PairURIFilename("", osAttrValue));
409 : }
410 628 : else if (osAttrURIPrefix == szXMLNS_URI && osAttrValue == szSWE_URI)
411 : {
412 3 : CPLDebug("GMLAS", "SWE namespace found");
413 3 : m_bFoundSWE = true;
414 : }
415 1053 : else if (osAttrURIPrefix == szXMLNS_URI && !osAttrValue.empty() &&
416 428 : !osAttrLocalname.empty())
417 : {
418 : #ifdef DEBUG_VERBOSE
419 : CPLDebug("GMLAS", "Namespace %s = %s", osAttrLocalname.c_str(),
420 : osAttrValue.c_str());
421 : #endif
422 428 : m_oMapDocNSURIToPrefix[osAttrValue] = osAttrLocalname;
423 : }
424 : }
425 :
426 151 : if (m_nStartElementCounter == 1)
427 151 : m_bFinish = true;
428 151 : }
429 :
430 : /************************************************************************/
431 : /* FillOtherMetadataLayer() */
432 : /************************************************************************/
433 :
434 171 : void OGRGMLASDataSource::FillOtherMetadataLayer(
435 : GDALOpenInfo *poOpenInfo, const CPLString &osConfigFile,
436 : const std::vector<PairURIFilename> &aoXSDs,
437 : const std::set<CPLString> &oSetSchemaURLs)
438 : {
439 : // 2 "secret" options just used for tests
440 171 : const bool bKeepRelativePathsForMetadata = CPLTestBool(
441 171 : CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
442 : szKEEP_RELATIVE_PATHS_FOR_METADATA_OPTION, "NO"));
443 :
444 171 : const bool bExposeConfiguration = CPLTestBool(
445 171 : CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
446 : szEXPOSE_CONFIGURATION_IN_METADATA_OPTION, "YES"));
447 :
448 171 : const bool bExposeSchemaNames = CPLTestBool(
449 171 : CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
450 : szEXPOSE_SCHEMAS_NAME_IN_METADATA_OPTION, "YES"));
451 :
452 171 : OGRFeatureDefn *poFDefn = m_poOtherMetadataLayer->GetLayerDefn();
453 :
454 171 : if (!osConfigFile.empty() && bExposeConfiguration)
455 : {
456 169 : if (STARTS_WITH(osConfigFile, "<Configuration"))
457 : {
458 85 : OGRFeature oFeature(poFDefn);
459 85 : oFeature.SetField(szKEY, szCONFIGURATION_INLINED);
460 85 : oFeature.SetField(szVALUE, osConfigFile.c_str());
461 85 : CPL_IGNORE_RET_VAL(
462 85 : m_poOtherMetadataLayer->CreateFeature(&oFeature));
463 : }
464 : else
465 : {
466 : {
467 84 : OGRFeature oFeature(poFDefn);
468 84 : oFeature.SetField(szKEY, szCONFIGURATION_FILENAME);
469 84 : char *pszCurDir = CPLGetCurrentDir();
470 252 : if (!bKeepRelativePathsForMetadata &&
471 84 : CPLIsFilenameRelative(osConfigFile) && pszCurDir != nullptr)
472 : {
473 0 : oFeature.SetField(
474 : szVALUE,
475 : CPLFormFilename(pszCurDir, osConfigFile, nullptr));
476 : }
477 : else
478 : {
479 84 : oFeature.SetField(szVALUE, osConfigFile.c_str());
480 : }
481 84 : CPLFree(pszCurDir);
482 84 : CPL_IGNORE_RET_VAL(
483 84 : m_poOtherMetadataLayer->CreateFeature(&oFeature));
484 : }
485 :
486 84 : GByte *pabyRet = nullptr;
487 84 : if (VSIIngestFile(nullptr, osConfigFile, &pabyRet, nullptr, -1))
488 : {
489 84 : OGRFeature oFeature(poFDefn);
490 84 : oFeature.SetField(szKEY, szCONFIGURATION_INLINED);
491 84 : oFeature.SetField(szVALUE, reinterpret_cast<char *>(pabyRet));
492 84 : CPL_IGNORE_RET_VAL(
493 84 : m_poOtherMetadataLayer->CreateFeature(&oFeature));
494 : }
495 84 : VSIFree(pabyRet);
496 : }
497 : }
498 :
499 171 : const char *const apszMeaningfulOptionsToStoreInMD[] = {
500 : szSWAP_COORDINATES_OPTION, szREMOVE_UNUSED_LAYERS_OPTION,
501 : szREMOVE_UNUSED_FIELDS_OPTION};
502 684 : for (size_t i = 0; i < CPL_ARRAYSIZE(apszMeaningfulOptionsToStoreInMD); ++i)
503 : {
504 513 : const char *pszKey = apszMeaningfulOptionsToStoreInMD[i];
505 : const char *pszVal =
506 513 : CSLFetchNameValue(poOpenInfo->papszOpenOptions, pszKey);
507 513 : if (pszVal)
508 : {
509 4 : OGRFeature oFeature(poFDefn);
510 4 : oFeature.SetField(szKEY, pszKey);
511 4 : oFeature.SetField(szVALUE, pszVal);
512 4 : CPL_IGNORE_RET_VAL(
513 4 : m_poOtherMetadataLayer->CreateFeature(&oFeature));
514 : }
515 : }
516 :
517 342 : CPLString osAbsoluteGMLFilename;
518 171 : if (!m_osGMLFilename.empty())
519 : {
520 143 : OGRFeature oFeature(poFDefn);
521 143 : oFeature.SetField(szKEY, szDOCUMENT_FILENAME);
522 143 : char *pszCurDir = CPLGetCurrentDir();
523 427 : if (!bKeepRelativePathsForMetadata &&
524 143 : CPLIsFilenameRelative(m_osGMLFilename) && pszCurDir != nullptr)
525 : {
526 : osAbsoluteGMLFilename =
527 72 : CPLFormFilename(pszCurDir, m_osGMLFilename, nullptr);
528 : }
529 : else
530 71 : osAbsoluteGMLFilename = m_osGMLFilename;
531 143 : oFeature.SetField(szVALUE, osAbsoluteGMLFilename.c_str());
532 143 : CPLFree(pszCurDir);
533 143 : CPL_IGNORE_RET_VAL(m_poOtherMetadataLayer->CreateFeature(&oFeature));
534 : }
535 :
536 171 : int nNSIdx = 1;
537 342 : std::set<CPLString> oSetVisitedURI;
538 421 : for (int i = 0; i < static_cast<int>(aoXSDs.size()); i++)
539 : {
540 250 : const CPLString osURI(aoXSDs[i].first);
541 250 : const CPLString osXSDFilename(aoXSDs[i].second);
542 :
543 250 : oSetVisitedURI.insert(osURI);
544 :
545 250 : if (osURI == szOGRGMLAS_URI)
546 9 : continue;
547 :
548 : {
549 241 : OGRFeature oFeature(poFDefn);
550 241 : oFeature.SetField(szKEY, CPLSPrintf(szNAMESPACE_URI_FMT, nNSIdx));
551 241 : oFeature.SetField(szVALUE, osURI.c_str());
552 241 : CPL_IGNORE_RET_VAL(
553 241 : m_poOtherMetadataLayer->CreateFeature(&oFeature));
554 : }
555 :
556 : {
557 482 : OGRFeature oFeature(poFDefn);
558 241 : oFeature.SetField(szKEY,
559 : CPLSPrintf(szNAMESPACE_LOCATION_FMT, nNSIdx));
560 :
561 : const CPLString osAbsoluteXSDFilename(
562 470 : (osXSDFilename.find("http://") != 0 &&
563 229 : osXSDFilename.find("https://") != 0 &&
564 126 : CPLIsFilenameRelative(osXSDFilename))
565 241 : ? CPLString(
566 : CPLFormFilename(CPLGetDirname(osAbsoluteGMLFilename),
567 : osXSDFilename, nullptr))
568 241 : : osXSDFilename);
569 241 : oFeature.SetField(szVALUE, osAbsoluteXSDFilename.c_str());
570 241 : CPL_IGNORE_RET_VAL(
571 241 : m_poOtherMetadataLayer->CreateFeature(&oFeature));
572 : }
573 :
574 241 : if (m_oMapURIToPrefix.find(osURI) != m_oMapURIToPrefix.end())
575 : {
576 213 : OGRFeature oFeature(poFDefn);
577 213 : oFeature.SetField(szKEY,
578 : CPLSPrintf(szNAMESPACE_PREFIX_FMT, nNSIdx));
579 213 : oFeature.SetField(szVALUE, m_oMapURIToPrefix[osURI].c_str());
580 213 : CPL_IGNORE_RET_VAL(
581 213 : m_poOtherMetadataLayer->CreateFeature(&oFeature));
582 : }
583 :
584 241 : nNSIdx++;
585 : }
586 :
587 1049 : for (const auto &oIter : m_oMapURIToPrefix)
588 : {
589 878 : const CPLString &osURI(oIter.first);
590 878 : const CPLString &osPrefix(oIter.second);
591 :
592 1534 : if (oSetVisitedURI.find(osURI) == oSetVisitedURI.end() &&
593 1627 : osURI != szXML_URI && osURI != szXS_URI && osURI != szXSI_URI &&
594 1849 : osURI != szXMLNS_URI && osURI != szOGRGMLAS_URI)
595 : {
596 : {
597 144 : OGRFeature oFeature(poFDefn);
598 144 : oFeature.SetField(szKEY,
599 : CPLSPrintf(szNAMESPACE_URI_FMT, nNSIdx));
600 144 : oFeature.SetField(szVALUE, osURI.c_str());
601 144 : CPL_IGNORE_RET_VAL(
602 144 : m_poOtherMetadataLayer->CreateFeature(&oFeature));
603 : }
604 :
605 : {
606 144 : OGRFeature oFeature(poFDefn);
607 144 : oFeature.SetField(szKEY,
608 : CPLSPrintf(szNAMESPACE_PREFIX_FMT, nNSIdx));
609 144 : oFeature.SetField(szVALUE, osPrefix.c_str());
610 144 : CPL_IGNORE_RET_VAL(
611 144 : m_poOtherMetadataLayer->CreateFeature(&oFeature));
612 : }
613 :
614 144 : nNSIdx++;
615 : }
616 : }
617 :
618 171 : if (!m_osGMLVersionFound.empty())
619 : {
620 3 : OGRFeature oFeature(poFDefn);
621 3 : oFeature.SetField(szKEY, szGML_VERSION);
622 3 : oFeature.SetField(szVALUE, m_osGMLVersionFound);
623 3 : CPL_IGNORE_RET_VAL(m_poOtherMetadataLayer->CreateFeature(&oFeature));
624 : }
625 :
626 171 : int nSchemaIdx = 1;
627 171 : if (bExposeSchemaNames)
628 : {
629 442 : for (const auto &osSchemaURL : oSetSchemaURLs)
630 : {
631 273 : OGRFeature oFeature(poFDefn);
632 273 : oFeature.SetField(szKEY, CPLSPrintf(szSCHEMA_NAME_FMT, nSchemaIdx));
633 273 : oFeature.SetField(szVALUE, osSchemaURL.c_str());
634 273 : CPL_IGNORE_RET_VAL(
635 273 : m_poOtherMetadataLayer->CreateFeature(&oFeature));
636 :
637 273 : nSchemaIdx++;
638 : }
639 : }
640 171 : }
641 :
642 : /************************************************************************/
643 : /* BuildXSDVector() */
644 : /************************************************************************/
645 :
646 : std::vector<PairURIFilename>
647 34 : OGRGMLASDataSource::BuildXSDVector(const CPLString &osXSDFilenames)
648 : {
649 34 : std::vector<PairURIFilename> aoXSDs;
650 34 : char **papszTokens = CSLTokenizeString2(osXSDFilenames, ",", 0);
651 34 : char *pszCurDir = CPLGetCurrentDir();
652 68 : for (int i = 0; papszTokens != nullptr && papszTokens[i] != nullptr; i++)
653 : {
654 101 : if (!STARTS_WITH(papszTokens[i], "http://") &&
655 33 : !STARTS_WITH(papszTokens[i], "https://") &&
656 67 : CPLIsFilenameRelative(papszTokens[i]) && pszCurDir != nullptr)
657 : {
658 28 : aoXSDs.push_back(PairURIFilename(
659 56 : "", CPLFormFilename(pszCurDir, papszTokens[i], nullptr)));
660 : }
661 : else
662 : {
663 6 : aoXSDs.push_back(PairURIFilename("", papszTokens[i]));
664 : }
665 : }
666 34 : CPLFree(pszCurDir);
667 34 : CSLDestroy(papszTokens);
668 34 : return aoXSDs;
669 : }
670 :
671 : /************************************************************************/
672 : /* Open() */
673 : /************************************************************************/
674 :
675 187 : bool OGRGMLASDataSource::Open(GDALOpenInfo *poOpenInfo)
676 : {
677 187 : CPLString osConfigFile = CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
678 374 : szCONFIG_FILE_OPTION, "");
679 187 : if (osConfigFile.empty())
680 : {
681 : const char *pszConfigFile =
682 96 : CPLFindFile("gdal", szDEFAULT_CONF_FILENAME);
683 96 : if (pszConfigFile)
684 96 : osConfigFile = pszConfigFile;
685 : }
686 187 : if (osConfigFile.empty())
687 : {
688 0 : CPLError(CE_Warning, CPLE_AppDefined,
689 : "No configuration file found. Using hard-coded defaults");
690 0 : m_oConf.Finalize();
691 : }
692 : else
693 : {
694 187 : if (!m_oConf.Load(osConfigFile))
695 : {
696 2 : CPLError(CE_Failure, CPLE_AppDefined,
697 : "Loading of configuration failed");
698 2 : return false;
699 : }
700 : }
701 :
702 185 : m_oCache.SetCacheDirectory(m_oConf.m_osXSDCacheDirectory);
703 185 : const bool bRefreshCache(CPLTestBool(CSLFetchNameValueDef(
704 185 : poOpenInfo->papszOpenOptions, szREFRESH_CACHE_OPTION, "NO")));
705 185 : m_oCache.SetRefreshMode(bRefreshCache);
706 185 : m_oCache.SetAllowDownload(m_oConf.m_bAllowRemoteSchemaDownload);
707 :
708 185 : m_oIgnoredXPathMatcher.SetRefXPaths(m_oConf.m_oMapPrefixToURIIgnoredXPaths,
709 185 : m_oConf.m_aosIgnoredXPaths);
710 :
711 : {
712 370 : std::vector<CPLString> oVector;
713 284 : for (const auto &oIter : m_oConf.m_oMapChildrenElementsConstraints)
714 99 : oVector.push_back(oIter.first);
715 185 : m_oChildrenElementsConstraintsXPathMatcher.SetRefXPaths(
716 185 : m_oConf.m_oMapPrefixToURITypeConstraints, oVector);
717 : }
718 :
719 185 : m_oForcedFlattenedXPathMatcher.SetRefXPaths(
720 185 : m_oConf.m_oMapPrefixToURIFlatteningRules,
721 185 : m_oConf.m_osForcedFlattenedXPath);
722 :
723 185 : m_oDisabledFlattenedXPathMatcher.SetRefXPaths(
724 185 : m_oConf.m_oMapPrefixToURIFlatteningRules,
725 185 : m_oConf.m_osDisabledFlattenedXPath);
726 :
727 : GMLASSchemaAnalyzer oAnalyzer(
728 185 : m_oIgnoredXPathMatcher, m_oChildrenElementsConstraintsXPathMatcher,
729 185 : m_oConf.m_oMapChildrenElementsConstraints,
730 370 : m_oForcedFlattenedXPathMatcher, m_oDisabledFlattenedXPathMatcher);
731 185 : oAnalyzer.SetUseArrays(m_oConf.m_bUseArrays);
732 185 : oAnalyzer.SetUseNullState(m_oConf.m_bUseNullState);
733 185 : oAnalyzer.SetInstantiateGMLFeaturesOnly(
734 185 : m_oConf.m_bInstantiateGMLFeaturesOnly);
735 185 : oAnalyzer.SetIdentifierMaxLength(m_oConf.m_nIdentifierMaxLength);
736 185 : oAnalyzer.SetCaseInsensitiveIdentifier(
737 185 : m_oConf.m_bCaseInsensitiveIdentifier);
738 185 : oAnalyzer.SetPGIdentifierLaundering(m_oConf.m_bPGIdentifierLaundering);
739 185 : oAnalyzer.SetMaximumFieldsForFlattening(
740 : m_oConf.m_nMaximumFieldsForFlattening);
741 185 : oAnalyzer.SetAlwaysGenerateOGRId(m_oConf.m_bAlwaysGenerateOGRId);
742 :
743 : m_osGMLFilename =
744 185 : STARTS_WITH_CI(poOpenInfo->pszFilename, szGMLAS_PREFIX)
745 185 : ? CPLExpandTilde(poOpenInfo->pszFilename + strlen(szGMLAS_PREFIX))
746 370 : : poOpenInfo->pszFilename;
747 :
748 : CPLString osXSDFilenames =
749 370 : CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, szXSD_OPTION, "");
750 :
751 185 : std::shared_ptr<VSIVirtualHandle> fpGML;
752 185 : if (!m_osGMLFilename.empty())
753 : {
754 153 : fpGML.reset(VSIFOpenL(m_osGMLFilename, "rb"), VSIVirtualHandleCloser{});
755 153 : if (fpGML == nullptr)
756 : {
757 2 : CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s",
758 : m_osGMLFilename.c_str());
759 2 : return false;
760 : }
761 : }
762 32 : else if (osXSDFilenames.empty())
763 : {
764 1 : CPLError(CE_Failure, CPLE_AppDefined,
765 : "%s open option must be provided when no "
766 : "XML data file is passed",
767 : szXSD_OPTION);
768 1 : return false;
769 : }
770 :
771 364 : GMLASTopElementParser topElementParser;
772 182 : if (!m_osGMLFilename.empty())
773 : {
774 151 : topElementParser.Parse(m_osGMLFilename, fpGML);
775 151 : if (m_oConf.m_eSWEActivationMode ==
776 : GMLASConfiguration::SWE_ACTIVATE_IF_NAMESPACE_FOUND)
777 : {
778 151 : m_bFoundSWE = topElementParser.GetSWE();
779 : }
780 0 : else if (m_oConf.m_eSWEActivationMode ==
781 : GMLASConfiguration::SWE_ACTIVATE_TRUE)
782 : {
783 0 : m_bFoundSWE = true;
784 : }
785 151 : oAnalyzer.SetMapDocNSURIToPrefix(
786 : topElementParser.GetMapDocNSURIToPrefix());
787 : }
788 364 : std::vector<PairURIFilename> aoXSDs;
789 182 : if (osXSDFilenames.empty())
790 : {
791 148 : aoXSDs = topElementParser.GetXSDs();
792 : }
793 : else
794 : {
795 34 : aoXSDs = BuildXSDVector(osXSDFilenames);
796 : }
797 182 : if (fpGML)
798 : {
799 : m_osHash =
800 151 : CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "HASH", "");
801 151 : if (m_osHash.empty())
802 : {
803 145 : fpGML->Seek(0, SEEK_SET);
804 290 : std::string osBuffer;
805 145 : osBuffer.resize(8192);
806 145 : size_t nRead = fpGML->Read(&osBuffer[0], 1, 8192);
807 145 : osBuffer.resize(nRead);
808 145 : size_t nPos = osBuffer.find("timeStamp=\"");
809 145 : if (nPos != std::string::npos)
810 : {
811 : size_t nPos2 =
812 6 : osBuffer.find('"', nPos + strlen("timeStamp=\""));
813 6 : if (nPos2 != std::string::npos)
814 6 : osBuffer.replace(nPos, nPos2 - nPos + 1, nPos2 - nPos + 1,
815 6 : ' ');
816 : }
817 : CPL_SHA256Context ctxt;
818 145 : CPL_SHA256Init(&ctxt);
819 145 : CPL_SHA256Update(&ctxt, osBuffer.data(), osBuffer.size());
820 :
821 : VSIStatBufL sStat;
822 145 : if (VSIStatL(m_osGMLFilename, &sStat) == 0)
823 : {
824 145 : m_nFileSize = sStat.st_size;
825 145 : GUInt64 nFileSizeLittleEndian =
826 145 : static_cast<GUInt64>(sStat.st_size);
827 145 : CPL_LSBPTR64(&nFileSizeLittleEndian);
828 145 : CPL_SHA256Update(&ctxt, &nFileSizeLittleEndian,
829 : sizeof(nFileSizeLittleEndian));
830 : }
831 :
832 : GByte abyHash[CPL_SHA256_HASH_SIZE];
833 145 : CPL_SHA256Final(&ctxt, abyHash);
834 : // Half of the hash should be enough for our purpose
835 145 : char *pszHash = CPLBinaryToHex(CPL_SHA256_HASH_SIZE / 2, abyHash);
836 145 : m_osHash = pszHash;
837 145 : CPLFree(pszHash);
838 : }
839 :
840 151 : fpGML->Seek(0, SEEK_SET);
841 151 : PushUnusedGMLFilePointer(fpGML);
842 : }
843 :
844 182 : if (aoXSDs.empty())
845 : {
846 1 : if (osXSDFilenames.empty())
847 : {
848 1 : CPLError(CE_Failure, CPLE_AppDefined,
849 : "No schema locations found when analyzing data file: "
850 : "%s open option must be provided",
851 : szXSD_OPTION);
852 : }
853 : else
854 : {
855 0 : CPLError(CE_Failure, CPLE_AppDefined, "No schema locations found");
856 : }
857 1 : return false;
858 : }
859 :
860 362 : m_bSchemaFullChecking = CPLFetchBool(poOpenInfo->papszOpenOptions,
861 : szSCHEMA_FULL_CHECKING_OPTION,
862 181 : m_oConf.m_bSchemaFullChecking);
863 :
864 362 : m_bHandleMultipleImports = CPLFetchBool(poOpenInfo->papszOpenOptions,
865 : szHANDLE_MULTIPLE_IMPORTS_OPTION,
866 181 : m_oConf.m_bHandleMultipleImports);
867 :
868 : bool bRet =
869 181 : oAnalyzer.Analyze(m_oCache, CPLGetDirname(m_osGMLFilename), aoXSDs,
870 181 : m_bSchemaFullChecking, m_bHandleMultipleImports);
871 181 : if (!bRet)
872 : {
873 10 : return false;
874 : }
875 :
876 171 : if (!osXSDFilenames.empty())
877 31 : m_aoXSDsManuallyPassed = aoXSDs;
878 :
879 171 : m_oMapURIToPrefix = oAnalyzer.GetMapURIToPrefix();
880 :
881 171 : m_osGMLVersionFound = oAnalyzer.GetGMLVersionFound();
882 :
883 171 : const std::set<CPLString> &oSetSchemaURLs = oAnalyzer.GetSchemaURLS();
884 :
885 171 : FillOtherMetadataLayer(poOpenInfo, osConfigFile, aoXSDs, oSetSchemaURLs);
886 :
887 171 : if (CPLFetchBool(poOpenInfo->papszOpenOptions,
888 : szEXPOSE_METADATA_LAYERS_OPTION,
889 171 : m_oConf.m_bExposeMetadataLayers))
890 : {
891 15 : m_apoRequestedMetadataLayers.push_back(m_poFieldsMetadataLayer.get());
892 15 : m_apoRequestedMetadataLayers.push_back(m_poLayersMetadataLayer.get());
893 15 : m_apoRequestedMetadataLayers.push_back(m_poRelationshipsLayer.get());
894 15 : m_apoRequestedMetadataLayers.push_back(m_poOtherMetadataLayer.get());
895 : }
896 :
897 342 : const char *pszSwapCoordinates = CSLFetchNameValueDef(
898 171 : poOpenInfo->papszOpenOptions, szSWAP_COORDINATES_OPTION, "AUTO");
899 171 : if (EQUAL(pszSwapCoordinates, "AUTO"))
900 : {
901 169 : m_eSwapCoordinates = GMLAS_SWAP_AUTO;
902 : }
903 2 : else if (CPLTestBool(pszSwapCoordinates))
904 : {
905 1 : m_eSwapCoordinates = GMLAS_SWAP_YES;
906 : }
907 : else
908 : {
909 1 : m_eSwapCoordinates = GMLAS_SWAP_NO;
910 : }
911 :
912 171 : const std::vector<GMLASFeatureClass> &aoClasses = oAnalyzer.GetClasses();
913 :
914 : // First "standard" tables
915 12235 : for (auto &oClass : aoClasses)
916 : {
917 12064 : if (oClass.GetParentXPath().empty())
918 3129 : TranslateClasses(nullptr, oClass);
919 : }
920 : // Then junction tables
921 12235 : for (auto &oClass : aoClasses)
922 : {
923 12064 : if (!oClass.GetParentXPath().empty())
924 8935 : TranslateClasses(nullptr, oClass);
925 : }
926 :
927 : // And now do initialization since we need to have instantiated everything
928 : // to be able to do cross-layer links
929 15557 : for (auto &poLayer : m_apoLayers)
930 : {
931 15386 : poLayer->PostInit(m_oConf.m_bIncludeGeometryXML);
932 : }
933 171 : m_bLayerInitFinished = true;
934 :
935 : // Do optional validation
936 342 : m_bValidate = CPLFetchBool(poOpenInfo->papszOpenOptions, szVALIDATE_OPTION,
937 171 : m_oConf.m_bValidate);
938 :
939 342 : m_bRemoveUnusedLayers = CPLFetchBool(poOpenInfo->papszOpenOptions,
940 : szREMOVE_UNUSED_LAYERS_OPTION,
941 171 : m_oConf.m_bRemoveUnusedLayers);
942 :
943 342 : m_bRemoveUnusedFields = CPLFetchBool(poOpenInfo->papszOpenOptions,
944 : szREMOVE_UNUSED_FIELDS_OPTION,
945 171 : m_oConf.m_bRemoveUnusedFields);
946 :
947 171 : m_oXLinkResolver.SetConf(m_oConf.m_oXLinkResolution);
948 171 : m_oXLinkResolver.SetRefreshMode(bRefreshCache);
949 :
950 171 : if (m_bValidate || m_bRemoveUnusedLayers ||
951 119 : (m_bFoundSWE &&
952 2 : (m_oConf.m_bSWEProcessDataRecord || m_oConf.m_bSWEProcessDataArray)))
953 : {
954 54 : CPLErrorReset();
955 54 : RunFirstPassIfNeeded(nullptr, nullptr, nullptr);
956 162 : if (CPLFetchBool(poOpenInfo->papszOpenOptions,
957 : szFAIL_IF_VALIDATION_ERROR_OPTION,
958 96 : m_oConf.m_bFailIfValidationError) &&
959 42 : CPLGetLastErrorType() != CE_None)
960 : {
961 2 : CPLError(CE_Failure, CPLE_AppDefined,
962 : "Validation errors encountered");
963 2 : return false;
964 : }
965 : }
966 169 : if (CPLGetLastErrorType() == CE_Failure)
967 1 : CPLErrorReset();
968 :
969 169 : return true;
970 : }
971 :
972 : /************************************************************************/
973 : /* TestCapability() */
974 : /************************************************************************/
975 :
976 96 : int OGRGMLASDataSource::TestCapability(const char *pszCap)
977 : {
978 96 : return EQUAL(pszCap, ODsCRandomLayerRead);
979 : }
980 :
981 : /************************************************************************/
982 : /* CreateReader() */
983 : /************************************************************************/
984 :
985 : GMLASReader *
986 1274 : OGRGMLASDataSource::CreateReader(std::shared_ptr<VSIVirtualHandle> &fpGML,
987 : GDALProgressFunc pfnProgress,
988 : void *pProgressData)
989 : {
990 1274 : if (fpGML == nullptr)
991 : {
992 : // Try recycling an already opened and unused file pointer
993 1009 : fpGML = PopUnusedGMLFilePointer();
994 1009 : if (fpGML == nullptr)
995 6 : fpGML.reset(VSIFOpenL(GetGMLFilename(), "rb"),
996 : VSIVirtualHandleCloser{});
997 1009 : if (fpGML == nullptr)
998 2 : return nullptr;
999 : }
1000 :
1001 : auto poReader = std::make_unique<GMLASReader>(
1002 2544 : GetCache(), GetIgnoredXPathMatcher(), m_oXLinkResolver);
1003 2544 : poReader->Init(GetGMLFilename(), fpGML, GetMapURIToPrefix(), GetLayers(),
1004 1272 : false, std::vector<PairURIFilename>(), m_bSchemaFullChecking,
1005 1272 : m_bHandleMultipleImports);
1006 :
1007 1272 : poReader->SetSwapCoordinates(GetSwapCoordinates());
1008 :
1009 1272 : poReader->SetFileSize(m_nFileSize);
1010 :
1011 1272 : if (!RunFirstPassIfNeeded(poReader.get(), pfnProgress, pProgressData))
1012 : {
1013 0 : return nullptr;
1014 : }
1015 :
1016 1272 : poReader->SetMapIgnoredXPathToWarn(GetMapIgnoredXPathToWarn());
1017 :
1018 1272 : poReader->SetHash(m_osHash);
1019 :
1020 1272 : return poReader.release();
1021 : }
1022 :
1023 : /************************************************************************/
1024 : /* ResetReading() */
1025 : /************************************************************************/
1026 :
1027 2 : void OGRGMLASDataSource::ResetReading()
1028 : {
1029 2 : m_poReader.reset();
1030 6 : for (auto *poLayer : m_apoRequestedMetadataLayers)
1031 4 : poLayer->ResetReading();
1032 2 : m_bEndOfReaderLayers = false;
1033 2 : m_nCurMetadataLayerIdx = -1;
1034 2 : }
1035 :
1036 : /************************************************************************/
1037 : /* GetNextFeature() */
1038 : /************************************************************************/
1039 :
1040 2774 : OGRFeature *OGRGMLASDataSource::GetNextFeature(OGRLayer **ppoBelongingLayer,
1041 : double *pdfProgressPct,
1042 : GDALProgressFunc pfnProgress,
1043 : void *pProgressData)
1044 : {
1045 2774 : if (m_bEndOfReaderLayers)
1046 : {
1047 3934 : if (m_nCurMetadataLayerIdx >= 0 &&
1048 1963 : m_nCurMetadataLayerIdx <
1049 1963 : static_cast<int>(m_apoRequestedMetadataLayers.size()))
1050 : {
1051 : while (true)
1052 : {
1053 : OGRLayer *poLayer =
1054 2002 : m_apoRequestedMetadataLayers[m_nCurMetadataLayerIdx];
1055 2002 : OGRFeature *poFeature = poLayer->GetNextFeature();
1056 2002 : if (poFeature != nullptr)
1057 : {
1058 1945 : if (pdfProgressPct != nullptr)
1059 0 : *pdfProgressPct = 1.0;
1060 1945 : if (ppoBelongingLayer != nullptr)
1061 1945 : *ppoBelongingLayer = poLayer;
1062 1945 : return poFeature;
1063 : }
1064 57 : if (m_nCurMetadataLayerIdx + 1 <
1065 57 : static_cast<int>(m_apoRequestedMetadataLayers.size()))
1066 : {
1067 39 : m_nCurMetadataLayerIdx++;
1068 : }
1069 : else
1070 : {
1071 18 : m_nCurMetadataLayerIdx = -1;
1072 18 : break;
1073 : }
1074 39 : }
1075 : }
1076 :
1077 26 : if (pdfProgressPct != nullptr)
1078 0 : *pdfProgressPct = 1.0;
1079 26 : if (ppoBelongingLayer != nullptr)
1080 26 : *ppoBelongingLayer = nullptr;
1081 26 : return nullptr;
1082 : }
1083 :
1084 803 : const double dfInitialScanRatio = 0.1;
1085 803 : if (m_poReader == nullptr)
1086 : {
1087 23 : void *pScaledProgress = GDALCreateScaledProgress(
1088 : 0.0, dfInitialScanRatio, pfnProgress, pProgressData);
1089 :
1090 46 : m_poReader.reset(CreateReader(
1091 23 : m_fpGMLParser, pScaledProgress ? GDALScaledProgress : nullptr,
1092 : pScaledProgress));
1093 :
1094 23 : GDALDestroyScaledProgress(pScaledProgress);
1095 :
1096 23 : if (m_poReader == nullptr)
1097 : {
1098 1 : if (pdfProgressPct != nullptr)
1099 0 : *pdfProgressPct = 1.0;
1100 1 : if (ppoBelongingLayer != nullptr)
1101 1 : *ppoBelongingLayer = nullptr;
1102 1 : m_bEndOfReaderLayers = true;
1103 1 : if (!m_apoRequestedMetadataLayers.empty())
1104 : {
1105 1 : m_nCurMetadataLayerIdx = 0;
1106 1 : return GetNextFeature(ppoBelongingLayer, pdfProgressPct,
1107 1 : pfnProgress, pProgressData);
1108 : }
1109 : else
1110 : {
1111 0 : return nullptr;
1112 : }
1113 : }
1114 : }
1115 :
1116 802 : void *pScaledProgress = GDALCreateScaledProgress(
1117 : dfInitialScanRatio, 1.0, pfnProgress, pProgressData);
1118 :
1119 : while (true)
1120 : {
1121 802 : OGRGMLASLayer *poBelongingLayer = nullptr;
1122 : auto poFeature = std::unique_ptr<OGRFeature>(m_poReader->GetNextFeature(
1123 : &poBelongingLayer, pScaledProgress ? GDALScaledProgress : nullptr,
1124 802 : pScaledProgress));
1125 1582 : if (poFeature == nullptr ||
1126 780 : poBelongingLayer->EvaluateFilter(poFeature.get()))
1127 : {
1128 802 : if (ppoBelongingLayer != nullptr)
1129 802 : *ppoBelongingLayer = poBelongingLayer;
1130 802 : if (pdfProgressPct != nullptr)
1131 : {
1132 60 : const vsi_l_offset nOffset = m_fpGMLParser->Tell();
1133 60 : if (nOffset == m_nFileSize)
1134 60 : *pdfProgressPct = 1.0;
1135 : else
1136 0 : *pdfProgressPct =
1137 0 : dfInitialScanRatio +
1138 0 : (1.0 - dfInitialScanRatio) * nOffset / m_nFileSize;
1139 : }
1140 802 : GDALDestroyScaledProgress(pScaledProgress);
1141 802 : if (poFeature == nullptr)
1142 : {
1143 22 : m_bEndOfReaderLayers = true;
1144 22 : if (!m_apoRequestedMetadataLayers.empty())
1145 : {
1146 17 : m_nCurMetadataLayerIdx = 0;
1147 17 : return GetNextFeature(ppoBelongingLayer, pdfProgressPct,
1148 17 : pfnProgress, pProgressData);
1149 : }
1150 : else
1151 : {
1152 5 : return nullptr;
1153 : }
1154 : }
1155 : else
1156 780 : return poFeature.release();
1157 : }
1158 0 : }
1159 : }
1160 :
1161 : /************************************************************************/
1162 : /* GetLayerByXPath() */
1163 : /************************************************************************/
1164 :
1165 28542 : OGRGMLASLayer *OGRGMLASDataSource::GetLayerByXPath(const CPLString &osXPath)
1166 : {
1167 3713120 : for (auto &poLayer : m_apoLayers)
1168 : {
1169 3711960 : if (poLayer->GetFeatureClass().GetXPath() == osXPath)
1170 : {
1171 27379 : return poLayer.get();
1172 : }
1173 : }
1174 1163 : return nullptr;
1175 : }
1176 :
1177 : /************************************************************************/
1178 : /* PushUnusedGMLFilePointer() */
1179 : /************************************************************************/
1180 :
1181 1168 : void OGRGMLASDataSource::PushUnusedGMLFilePointer(
1182 : std::shared_ptr<VSIVirtualHandle> &fpGML)
1183 : {
1184 1168 : if (m_fpGML == nullptr)
1185 : {
1186 1098 : std::swap(m_fpGML, fpGML);
1187 : }
1188 : else
1189 : {
1190 70 : fpGML.reset();
1191 : }
1192 1168 : }
1193 :
1194 : /************************************************************************/
1195 : /* PopUnusedGMLFilePointer() */
1196 : /************************************************************************/
1197 :
1198 1009 : std::shared_ptr<VSIVirtualHandle> OGRGMLASDataSource::PopUnusedGMLFilePointer()
1199 : {
1200 1009 : std::shared_ptr<VSIVirtualHandle> fpGML;
1201 1009 : std::swap(fpGML, m_fpGML);
1202 1009 : return fpGML;
1203 : }
1204 :
1205 : /************************************************************************/
1206 : /* InitReaderWithFirstPassElements() */
1207 : /************************************************************************/
1208 :
1209 1482 : void OGRGMLASDataSource::InitReaderWithFirstPassElements(GMLASReader *poReader)
1210 : {
1211 1482 : if (poReader != nullptr)
1212 : {
1213 1259 : poReader->SetMapSRSNameToInvertedAxis(m_oMapSRSNameToInvertedAxis);
1214 1259 : poReader->SetMapGeomFieldDefnToSRSName(m_oMapGeomFieldDefnToSRSName);
1215 1263 : poReader->SetProcessDataRecord(m_bFoundSWE &&
1216 4 : m_oConf.m_bSWEProcessDataRecord);
1217 1259 : poReader->SetSWEDataArrayLayersRef(m_apoSWEDataArrayLayersRef);
1218 1259 : poReader->SetMapElementIdToLayer(m_oMapElementIdToLayer);
1219 1259 : poReader->SetMapElementIdToPKID(m_oMapElementIdToPKID);
1220 1259 : poReader->SetDefaultSrsDimension(m_nDefaultSrsDimension);
1221 : }
1222 1482 : }
1223 :
1224 : /************************************************************************/
1225 : /* RunFirstPassIfNeeded() */
1226 : /************************************************************************/
1227 :
1228 1502 : bool OGRGMLASDataSource::RunFirstPassIfNeeded(GMLASReader *poReader,
1229 : GDALProgressFunc pfnProgress,
1230 : void *pProgressData)
1231 : {
1232 1502 : if (m_bFirstPassDone)
1233 : {
1234 1375 : InitReaderWithFirstPassElements(poReader);
1235 1375 : return true;
1236 : }
1237 :
1238 127 : m_bFirstPassDone = true;
1239 :
1240 : // Determine if we have geometry fields in any layer
1241 : // If so, do an initial pass to determine the SRS of those geometry fields.
1242 127 : bool bHasGeomFields = false;
1243 14314 : for (auto &poLayer : m_apoLayers)
1244 : {
1245 14207 : poLayer->SetLayerDefnFinalized(true);
1246 14207 : if (poLayer->GetLayerDefn()->GetGeomFieldCount() > 0)
1247 : {
1248 20 : bHasGeomFields = true;
1249 20 : break;
1250 : }
1251 : }
1252 :
1253 127 : bool bSuccess = true;
1254 : const bool bHasURLSpecificRules =
1255 127 : !m_oXLinkResolver.GetConf().m_aoURLSpecificRules.empty();
1256 107 : if (bHasGeomFields || m_bValidate || m_bRemoveUnusedLayers ||
1257 57 : m_bRemoveUnusedFields || bHasURLSpecificRules ||
1258 247 : m_oXLinkResolver.GetConf().m_bResolveInternalXLinks ||
1259 13 : (m_bFoundSWE &&
1260 0 : (m_oConf.m_bSWEProcessDataRecord || m_oConf.m_bSWEProcessDataArray)))
1261 : {
1262 114 : bool bJustOpenedFiled = false;
1263 0 : std::shared_ptr<VSIVirtualHandle> fp;
1264 114 : if (poReader)
1265 38 : fp = poReader->GetFP();
1266 : else
1267 : {
1268 76 : fp.reset(VSIFOpenL(GetGMLFilename(), "rb"),
1269 : VSIVirtualHandleCloser{});
1270 76 : if (fp == nullptr)
1271 : {
1272 7 : return false;
1273 : }
1274 69 : bJustOpenedFiled = true;
1275 : }
1276 :
1277 : auto poReaderFirstPass = std::make_unique<GMLASReader>(
1278 214 : m_oCache, m_oIgnoredXPathMatcher, m_oXLinkResolver);
1279 214 : poReaderFirstPass->Init(GetGMLFilename(), fp, GetMapURIToPrefix(),
1280 107 : GetLayers(), m_bValidate,
1281 107 : m_aoXSDsManuallyPassed, m_bSchemaFullChecking,
1282 107 : m_bHandleMultipleImports);
1283 :
1284 214 : poReaderFirstPass->SetProcessDataRecord(
1285 107 : m_bFoundSWE && m_oConf.m_bSWEProcessDataRecord);
1286 :
1287 107 : poReaderFirstPass->SetFileSize(m_nFileSize);
1288 :
1289 107 : poReaderFirstPass->SetMapIgnoredXPathToWarn(
1290 107 : m_oConf.m_oMapIgnoredXPathToWarn);
1291 :
1292 107 : poReaderFirstPass->SetHash(m_osHash);
1293 :
1294 : // No need to warn afterwards
1295 107 : m_oConf.m_oMapIgnoredXPathToWarn.clear();
1296 :
1297 214 : std::set<CPLString> aoSetRemovedLayerNames;
1298 107 : bSuccess = poReaderFirstPass->RunFirstPass(
1299 107 : pfnProgress, pProgressData, m_bRemoveUnusedLayers,
1300 107 : m_bRemoveUnusedFields,
1301 107 : m_bFoundSWE && m_oConf.m_bSWEProcessDataArray,
1302 : m_poFieldsMetadataLayer.get(), m_poLayersMetadataLayer.get(),
1303 : m_poRelationshipsLayer.get(), aoSetRemovedLayerNames);
1304 :
1305 : std::vector<std::unique_ptr<OGRGMLASLayer>> apoSWEDataArrayLayers =
1306 214 : poReaderFirstPass->StealSWEDataArrayLayersOwned();
1307 110 : for (auto &poLayer : apoSWEDataArrayLayers)
1308 : {
1309 3 : poLayer->SetDataSource(this);
1310 3 : m_apoSWEDataArrayLayersRef.push_back(poLayer.get());
1311 3 : m_apoLayers.emplace_back(std::move(poLayer));
1312 : }
1313 :
1314 : // If we have removed layers, we also need to cleanup our special
1315 : // metadata layers
1316 107 : if (!aoSetRemovedLayerNames.empty())
1317 : {
1318 : // Removing features while iterating works here given the layers
1319 : // are MEM layers
1320 1 : m_poLayersMetadataLayer->ResetReading();
1321 5 : for (auto &poFeature : *m_poLayersMetadataLayer)
1322 : {
1323 : const char *pszLayerName =
1324 4 : poFeature->GetFieldAsString(szLAYER_NAME);
1325 4 : if (aoSetRemovedLayerNames.find(pszLayerName) !=
1326 8 : aoSetRemovedLayerNames.end())
1327 : {
1328 6 : CPL_IGNORE_RET_VAL(m_poLayersMetadataLayer->DeleteFeature(
1329 3 : poFeature->GetFID()));
1330 : }
1331 : }
1332 1 : m_poLayersMetadataLayer->ResetReading();
1333 :
1334 1 : m_poFieldsMetadataLayer->ResetReading();
1335 14 : for (auto &poFeature : *m_poFieldsMetadataLayer)
1336 : {
1337 : const char *pszLayerName =
1338 13 : poFeature->GetFieldAsString(szLAYER_NAME);
1339 : const char *pszRelatedLayerName =
1340 13 : poFeature->GetFieldAsString(szFIELD_RELATED_LAYER);
1341 26 : if (aoSetRemovedLayerNames.find(pszLayerName) !=
1342 47 : aoSetRemovedLayerNames.end() ||
1343 21 : aoSetRemovedLayerNames.find(pszRelatedLayerName) !=
1344 21 : aoSetRemovedLayerNames.end())
1345 : {
1346 12 : CPL_IGNORE_RET_VAL(m_poFieldsMetadataLayer->DeleteFeature(
1347 6 : poFeature->GetFID()));
1348 : }
1349 : }
1350 1 : m_poFieldsMetadataLayer->ResetReading();
1351 :
1352 1 : m_poRelationshipsLayer->ResetReading();
1353 2 : for (auto &poFeature : *m_poRelationshipsLayer)
1354 : {
1355 : const char *pszParentLayerName =
1356 1 : poFeature->GetFieldAsString(szPARENT_LAYER);
1357 : const char *pszChildLayerName =
1358 1 : poFeature->GetFieldAsString(szCHILD_LAYER);
1359 2 : if (aoSetRemovedLayerNames.find(pszParentLayerName) !=
1360 4 : aoSetRemovedLayerNames.end() ||
1361 2 : aoSetRemovedLayerNames.find(pszChildLayerName) !=
1362 2 : aoSetRemovedLayerNames.end())
1363 : {
1364 2 : CPL_IGNORE_RET_VAL(m_poRelationshipsLayer->DeleteFeature(
1365 1 : poFeature->GetFID()));
1366 : }
1367 : }
1368 1 : m_poRelationshipsLayer->ResetReading();
1369 : }
1370 :
1371 : // Store maps to reinject them in real readers
1372 : m_oMapSRSNameToInvertedAxis =
1373 107 : poReaderFirstPass->GetMapSRSNameToInvertedAxis();
1374 : m_oMapGeomFieldDefnToSRSName =
1375 107 : poReaderFirstPass->GetMapGeomFieldDefnToSRSName();
1376 :
1377 107 : m_oMapElementIdToLayer = poReaderFirstPass->GetMapElementIdToLayer();
1378 107 : m_oMapElementIdToPKID = poReaderFirstPass->GetMapElementIdToPKID();
1379 107 : m_nDefaultSrsDimension = poReaderFirstPass->GetDefaultSrsDimension();
1380 :
1381 107 : poReaderFirstPass.reset();
1382 :
1383 107 : fp->Seek(0, SEEK_SET);
1384 107 : if (bJustOpenedFiled)
1385 69 : PushUnusedGMLFilePointer(fp);
1386 :
1387 107 : InitReaderWithFirstPassElements(poReader);
1388 : }
1389 :
1390 120 : return bSuccess;
1391 : }
|