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