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