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 "cpl_minixml.h"
18 :
19 : #include <algorithm>
20 :
21 : #ifdef EMBED_RESOURCE_FILES
22 : #include "embedded_resources.h"
23 : #endif
24 :
25 : /************************************************************************/
26 : /* GetBaseCacheDirectory() */
27 : /************************************************************************/
28 :
29 277 : CPLString GMLASConfiguration::GetBaseCacheDirectory()
30 : {
31 : #ifdef _WIN32
32 : const char *pszHome = CPLGetConfigOption("USERPROFILE", nullptr);
33 : #else
34 277 : const char *pszHome = CPLGetConfigOption("HOME", nullptr);
35 : #endif
36 277 : if (pszHome != nullptr)
37 : {
38 277 : return CPLFormFilename(pszHome, ".gdal", nullptr);
39 : }
40 : else
41 : {
42 0 : const char *pszDir = CPLGetConfigOption("CPL_TMPDIR", nullptr);
43 :
44 0 : if (pszDir == nullptr)
45 0 : pszDir = CPLGetConfigOption("TMPDIR", nullptr);
46 :
47 0 : if (pszDir == nullptr)
48 0 : pszDir = CPLGetConfigOption("TEMP", nullptr);
49 :
50 0 : const char *pszUsername = CPLGetConfigOption("USERNAME", nullptr);
51 0 : if (pszUsername == nullptr)
52 0 : pszUsername = CPLGetConfigOption("USER", nullptr);
53 :
54 0 : if (pszDir != nullptr && pszUsername != nullptr)
55 : {
56 : return CPLFormFilename(pszDir, CPLSPrintf(".gdal_%s", pszUsername),
57 0 : nullptr);
58 : }
59 : }
60 0 : return CPLString();
61 : }
62 :
63 : /************************************************************************/
64 : /* Finalize() */
65 : /************************************************************************/
66 :
67 209 : void GMLASConfiguration::Finalize()
68 : {
69 209 : if (m_bAllowXSDCache && m_osXSDCacheDirectory.empty())
70 : {
71 160 : m_osXSDCacheDirectory = GetBaseCacheDirectory();
72 160 : if (m_osXSDCacheDirectory.empty())
73 : {
74 0 : CPLError(CE_Warning, CPLE_AppDefined,
75 : "Could not determine a directory for GMLAS XSD cache");
76 : }
77 : else
78 : {
79 : m_osXSDCacheDirectory = CPLFormFilename(m_osXSDCacheDirectory,
80 160 : "gmlas_xsd_cache", nullptr);
81 160 : CPLDebug("GMLAS", "XSD cache directory: %s",
82 : m_osXSDCacheDirectory.c_str());
83 : }
84 : }
85 209 : }
86 :
87 : /************************************************************************/
88 : /* CPLGetXMLBoolValue() */
89 : /************************************************************************/
90 :
91 6441 : static bool CPLGetXMLBoolValue(CPLXMLNode *psNode, const char *pszKey,
92 : bool bDefault)
93 : {
94 6441 : const char *pszVal = CPLGetXMLValue(psNode, pszKey, nullptr);
95 6441 : if (pszVal)
96 2668 : return CPLTestBool(pszVal);
97 : else
98 3773 : return bDefault;
99 : }
100 :
101 : /************************************************************************/
102 : /* IsValidXPath() */
103 : /************************************************************************/
104 :
105 2834 : static bool IsValidXPath(const CPLString &osXPath)
106 : {
107 : // Check that the XPath syntax belongs to the subset we
108 : // understand
109 2834 : bool bOK = !osXPath.empty();
110 60554 : for (size_t i = 0; i < osXPath.size(); ++i)
111 : {
112 57730 : const char chCur = osXPath[i];
113 57730 : if (chCur == '/')
114 : {
115 : // OK
116 : }
117 1528 : else if (chCur == '@' && (i == 0 || osXPath[i - 1] == '/') &&
118 59250 : i < osXPath.size() - 1 &&
119 1527 : isalpha(static_cast<unsigned char>(osXPath[i + 1])))
120 : {
121 : // OK
122 : }
123 54669 : else if (chCur == '_' || isalpha(static_cast<unsigned char>(chCur)))
124 : {
125 : // OK
126 : }
127 5762 : else if (isdigit(static_cast<unsigned char>(chCur)) && i > 0 &&
128 1053 : (isalnum(static_cast<unsigned char>(osXPath[i - 1])) ||
129 0 : osXPath[i - 1] == '_'))
130 : {
131 : // OK
132 : }
133 3650 : else if (chCur == ':' && i > 0 &&
134 3649 : (isalnum(static_cast<unsigned char>(osXPath[i - 1])) ||
135 1 : osXPath[i - 1] == '_') &&
136 10953 : i < osXPath.size() - 1 &&
137 3647 : isalpha(static_cast<unsigned char>(osXPath[i + 1])))
138 : {
139 : // OK
140 : }
141 : else
142 : {
143 10 : bOK = false;
144 10 : break;
145 : }
146 : }
147 2834 : return bOK;
148 : }
149 :
150 : /************************************************************************/
151 : /* GMLASConfigurationErrorHandler() */
152 : /************************************************************************/
153 :
154 0 : static void CPL_STDCALL GMLASConfigurationErrorHandler(CPLErr /*eErr*/,
155 : CPLErrorNum /*nType*/,
156 : const char *pszMsg)
157 : {
158 : std::vector<CPLString> *paosErrors =
159 0 : static_cast<std::vector<CPLString> *>(CPLGetErrorHandlerUserData());
160 0 : paosErrors->push_back(pszMsg);
161 0 : }
162 :
163 : /************************************************************************/
164 : /* ParseNamespaces() */
165 : /************************************************************************/
166 :
167 370 : static void ParseNamespaces(CPLXMLNode *psContainerNode,
168 : std::map<CPLString, CPLString> &oMap)
169 : {
170 370 : CPLXMLNode *psNamespaces = CPLGetXMLNode(psContainerNode, "Namespaces");
171 370 : if (psNamespaces != nullptr)
172 : {
173 1064 : for (CPLXMLNode *psIter = psNamespaces->psChild; psIter != nullptr;
174 708 : psIter = psIter->psNext)
175 : {
176 708 : if (psIter->eType == CXT_Element &&
177 708 : EQUAL(psIter->pszValue, "Namespace"))
178 : {
179 : const std::string osPrefix =
180 1416 : CPLGetXMLValue(psIter, "prefix", "");
181 1416 : const std::string osURI = CPLGetXMLValue(psIter, "uri", "");
182 708 : if (!osPrefix.empty() && !osURI.empty())
183 : {
184 708 : if (oMap.find(osPrefix) == oMap.end())
185 : {
186 707 : oMap[osPrefix] = osURI;
187 : }
188 : else
189 : {
190 2 : CPLError(CE_Warning, CPLE_AppDefined,
191 : "Prefix %s was already mapped to %s. "
192 : "Attempt to map it to %s ignored",
193 2 : osPrefix.c_str(), oMap[osPrefix].c_str(),
194 : osURI.c_str());
195 : }
196 : }
197 : }
198 : }
199 : }
200 370 : }
201 :
202 : /************************************************************************/
203 : /* GetDefaultConfFile() */
204 : /************************************************************************/
205 :
206 : /* static */
207 117 : std::string GMLASConfiguration::GetDefaultConfFile(bool &bUnlinkAfterUse)
208 : {
209 117 : bUnlinkAfterUse = false;
210 : #if !defined(USE_ONLY_EMBEDDED_RESOURCE_FILES)
211 117 : const char *pszConfigFile = CPLFindFile("gdal", szDEFAULT_CONF_FILENAME);
212 117 : if (pszConfigFile)
213 117 : return pszConfigFile;
214 : #endif
215 : #ifdef EMBED_RESOURCE_FILES
216 : static const bool bOnce [[maybe_unused]] = []()
217 : {
218 : CPLDebug("GMLAS", "Using embedded %s", szDEFAULT_CONF_FILENAME);
219 : return true;
220 : }();
221 : bUnlinkAfterUse = true;
222 : const std::string osTmpFilename =
223 : VSIMemGenerateHiddenFilename(szDEFAULT_CONF_FILENAME);
224 : VSIFCloseL(VSIFileFromMemBuffer(
225 : osTmpFilename.c_str(),
226 : const_cast<GByte *>(
227 : reinterpret_cast<const GByte *>(GMLASConfXMLGetFileContent())),
228 : static_cast<int>(strlen(GMLASConfXMLGetFileContent())),
229 : /* bTakeOwnership = */ false));
230 : return osTmpFilename;
231 : #else
232 0 : return std::string();
233 : #endif
234 : }
235 :
236 : /************************************************************************/
237 : /* Load() */
238 : /************************************************************************/
239 :
240 209 : bool GMLASConfiguration::Load(const char *pszFilename)
241 : {
242 : // Allow configuration to be inlined
243 209 : CPLXMLNode *psRoot = STARTS_WITH(pszFilename, "<Configuration")
244 209 : ? CPLParseXMLString(pszFilename)
245 121 : : CPLParseXMLFile(pszFilename);
246 209 : if (psRoot == nullptr)
247 : {
248 3 : Finalize();
249 3 : return false;
250 : }
251 206 : CPLXMLTreeCloser oCloser(psRoot);
252 206 : CPL_IGNORE_RET_VAL(oCloser);
253 :
254 : // Validate the configuration file
255 206 : if (CPLTestBool(CPLGetConfigOption("GDAL_XML_VALIDATION", "YES")))
256 : {
257 : #ifdef EMBED_RESOURCE_FILES
258 : std::string osTmpFilename;
259 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
260 : #endif
261 : #ifdef USE_ONLY_EMBEDDED_RESOURCE_FILES
262 : const char *pszXSD = nullptr;
263 : #else
264 44 : const char *pszXSD = CPLFindFile("gdal", "gmlasconf.xsd");
265 : #endif
266 : #ifdef EMBED_RESOURCE_FILES
267 : if (!pszXSD)
268 : {
269 : static const bool bOnce [[maybe_unused]] = []()
270 : {
271 : CPLDebug("GMLAS", "Using embedded gmlasconf.xsd");
272 : return true;
273 : }();
274 : osTmpFilename = VSIMemGenerateHiddenFilename("gmlasconf.xsd");
275 : pszXSD = osTmpFilename.c_str();
276 : VSIFCloseL(VSIFileFromMemBuffer(
277 : osTmpFilename.c_str(),
278 : const_cast<GByte *>(reinterpret_cast<const GByte *>(
279 : GMLASConfXSDGetFileContent())),
280 : static_cast<int>(strlen(GMLASConfXSDGetFileContent())),
281 : /* bTakeOwnership = */ false));
282 : }
283 : #else
284 44 : if (pszXSD)
285 : #endif
286 : {
287 88 : std::vector<CPLString> aosErrors;
288 44 : const CPLErr eErrClass = CPLGetLastErrorType();
289 44 : const CPLErrorNum nErrNum = CPLGetLastErrorNo();
290 88 : const CPLString osErrMsg = CPLGetLastErrorMsg();
291 44 : CPLPushErrorHandlerEx(GMLASConfigurationErrorHandler, &aosErrors);
292 44 : int bRet = CPLValidateXML(pszFilename, pszXSD, nullptr);
293 44 : CPLPopErrorHandler();
294 44 : if (!bRet && !aosErrors.empty() &&
295 0 : strstr(aosErrors[0].c_str(), "missing libxml2 support") ==
296 : nullptr)
297 : {
298 0 : for (size_t i = 0; i < aosErrors.size(); i++)
299 : {
300 0 : CPLError(CE_Warning, CPLE_AppDefined, "%s",
301 0 : aosErrors[i].c_str());
302 : }
303 : }
304 : else
305 : {
306 44 : CPLErrorSetState(eErrClass, nErrNum, osErrMsg);
307 : }
308 : }
309 :
310 : #ifdef EMBED_RESOURCE_FILES
311 : if (!osTmpFilename.empty())
312 : VSIUnlink(osTmpFilename.c_str());
313 : #endif
314 : }
315 :
316 206 : m_bAllowRemoteSchemaDownload =
317 206 : CPLGetXMLBoolValue(psRoot, "=Configuration.AllowRemoteSchemaDownload",
318 : ALLOW_REMOTE_SCHEMA_DOWNLOAD_DEFAULT);
319 :
320 206 : m_bAllowXSDCache = CPLGetXMLBoolValue(
321 : psRoot, "=Configuration.SchemaCache.enabled", ALLOW_XSD_CACHE_DEFAULT);
322 206 : if (m_bAllowXSDCache)
323 : {
324 : m_osXSDCacheDirectory =
325 206 : CPLGetXMLValue(psRoot, "=Configuration.SchemaCache.Directory", "");
326 : }
327 :
328 206 : m_bSchemaFullChecking = CPLGetXMLBoolValue(
329 : psRoot, "=Configuration.SchemaAnalysisOptions.SchemaFullChecking",
330 : SCHEMA_FULL_CHECKING_DEFAULT);
331 :
332 206 : m_bHandleMultipleImports = CPLGetXMLBoolValue(
333 : psRoot, "=Configuration.SchemaAnalysisOptions.HandleMultipleImports",
334 : HANDLE_MULTIPLE_IMPORTS_DEFAULT);
335 :
336 206 : m_bValidate = CPLGetXMLBoolValue(
337 : psRoot, "=Configuration.Validation.enabled", VALIDATE_DEFAULT);
338 :
339 206 : if (m_bValidate)
340 : {
341 1 : m_bFailIfValidationError =
342 1 : CPLGetXMLBoolValue(psRoot, "=Configuration.Validation.FailIfError",
343 : FAIL_IF_VALIDATION_ERROR_DEFAULT);
344 : }
345 :
346 206 : m_bExposeMetadataLayers =
347 206 : CPLGetXMLBoolValue(psRoot, "=Configuration.ExposeMetadataLayers",
348 : EXPOSE_METADATA_LAYERS_DEFAULT);
349 :
350 206 : m_bAlwaysGenerateOGRId = CPLGetXMLBoolValue(
351 : psRoot, "=Configuration.LayerBuildingRules.AlwaysGenerateOGRId",
352 : ALWAYS_GENERATE_OGR_ID_DEFAULT);
353 :
354 206 : m_bRemoveUnusedLayers = CPLGetXMLBoolValue(
355 : psRoot, "=Configuration.LayerBuildingRules.RemoveUnusedLayers",
356 : REMOVE_UNUSED_LAYERS_DEFAULT);
357 :
358 206 : m_bRemoveUnusedFields = CPLGetXMLBoolValue(
359 : psRoot, "=Configuration.LayerBuildingRules.RemoveUnusedFields",
360 : REMOVE_UNUSED_FIELDS_DEFAULT);
361 :
362 206 : m_bUseArrays = CPLGetXMLBoolValue(
363 : psRoot, "=Configuration.LayerBuildingRules.UseArrays",
364 : USE_ARRAYS_DEFAULT);
365 206 : m_bUseNullState = CPLGetXMLBoolValue(
366 : psRoot, "=Configuration.LayerBuildingRules.UseNullState",
367 : USE_NULL_STATE_DEFAULT);
368 206 : m_bIncludeGeometryXML = CPLGetXMLBoolValue(
369 : psRoot, "=Configuration.LayerBuildingRules.GML.IncludeGeometryXML",
370 : INCLUDE_GEOMETRY_XML_DEFAULT);
371 206 : m_bInstantiateGMLFeaturesOnly = CPLGetXMLBoolValue(
372 : psRoot,
373 : "=Configuration.LayerBuildingRules.GML.InstantiateGMLFeaturesOnly",
374 : INSTANTIATE_GML_FEATURES_ONLY_DEFAULT);
375 206 : m_nIdentifierMaxLength = atoi(CPLGetXMLValue(
376 : psRoot, "=Configuration.LayerBuildingRules.IdentifierMaxLength", "0"));
377 206 : m_bCaseInsensitiveIdentifier = CPLGetXMLBoolValue(
378 : psRoot, "=Configuration.LayerBuildingRules.CaseInsensitiveIdentifier",
379 : CASE_INSENSITIVE_IDENTIFIER_DEFAULT);
380 206 : m_bPGIdentifierLaundering = CPLGetXMLBoolValue(
381 : psRoot,
382 : "=Configuration.LayerBuildingRules.PostgreSQLIdentifierLaundering",
383 : PG_IDENTIFIER_LAUNDERING_DEFAULT);
384 :
385 206 : CPLXMLNode *psFlatteningRules = CPLGetXMLNode(
386 : psRoot, "=Configuration.LayerBuildingRules.FlatteningRules");
387 206 : if (psFlatteningRules)
388 : {
389 117 : m_nMaximumFieldsForFlattening = atoi(CPLGetXMLValue(
390 : psFlatteningRules, "MaximumNumberOfFields",
391 : CPLSPrintf("%d", MAXIMUM_FIELDS_FLATTENING_DEFAULT)));
392 :
393 117 : ParseNamespaces(psFlatteningRules, m_oMapPrefixToURIFlatteningRules);
394 :
395 936 : for (CPLXMLNode *psIter = psFlatteningRules->psChild; psIter != nullptr;
396 819 : psIter = psIter->psNext)
397 : {
398 819 : if (psIter->eType == CXT_Element &&
399 351 : EQUAL(psIter->pszValue, "ForceFlatteningXPath"))
400 : {
401 117 : m_osForcedFlattenedXPath.push_back(
402 : CPLGetXMLValue(psIter, "", ""));
403 : }
404 702 : else if (psIter->eType == CXT_Element &&
405 234 : EQUAL(psIter->pszValue, "DisableFlatteningXPath"))
406 : {
407 0 : m_osDisabledFlattenedXPath.push_back(
408 : CPLGetXMLValue(psIter, "", ""));
409 : }
410 : }
411 : }
412 :
413 206 : const char *pszSWEProcessingActivation = CPLGetXMLValue(
414 : psRoot, "=Configuration.LayerBuildingRules.SWEProcessing.Activation",
415 : "ifSWENamespaceFoundInTopElement");
416 206 : if (EQUAL(pszSWEProcessingActivation, "ifSWENamespaceFoundInTopElement"))
417 206 : m_eSWEActivationMode = SWE_ACTIVATE_IF_NAMESPACE_FOUND;
418 0 : else if (CPLTestBool(pszSWEProcessingActivation))
419 0 : m_eSWEActivationMode = SWE_ACTIVATE_TRUE;
420 : else
421 0 : m_eSWEActivationMode = SWE_ACTIVATE_FALSE;
422 206 : m_bSWEProcessDataRecord = CPLTestBool(CPLGetXMLValue(
423 : psRoot,
424 : "=Configuration.LayerBuildingRules.SWEProcessing.ProcessDataRecord",
425 : "true"));
426 206 : m_bSWEProcessDataArray = CPLTestBool(CPLGetXMLValue(
427 : psRoot,
428 : "=Configuration.LayerBuildingRules.SWEProcessing.ProcessDataArray",
429 : "true"));
430 :
431 : CPLXMLNode *psTypingConstraints =
432 206 : CPLGetXMLNode(psRoot, "=Configuration.TypingConstraints");
433 206 : if (psTypingConstraints)
434 : {
435 120 : ParseNamespaces(psTypingConstraints, m_oMapPrefixToURITypeConstraints);
436 :
437 120 : for (CPLXMLNode *psIter = psTypingConstraints->psChild;
438 360 : psIter != nullptr; psIter = psIter->psNext)
439 : {
440 240 : if (psIter->eType == CXT_Element &&
441 240 : EQUAL(psIter->pszValue, "ChildConstraint"))
442 : {
443 : const CPLString &osXPath(
444 240 : CPLGetXMLValue(psIter, "ContainerXPath", ""));
445 : CPLXMLNode *psChildrenTypes =
446 120 : CPLGetXMLNode(psIter, "ChildrenElements");
447 120 : if (IsValidXPath(osXPath))
448 : {
449 120 : for (CPLXMLNode *psIter2 = psChildrenTypes
450 120 : ? psChildrenTypes->psChild
451 : : nullptr;
452 241 : psIter2 != nullptr; psIter2 = psIter2->psNext)
453 : {
454 121 : if (psIter2->eType == CXT_Element &&
455 121 : EQUAL(psIter2->pszValue, "Element"))
456 : {
457 121 : m_oMapChildrenElementsConstraints[osXPath]
458 121 : .push_back(CPLGetXMLValue(psIter2, "", ""));
459 : }
460 : }
461 : }
462 : else
463 : {
464 0 : CPLError(CE_Warning, CPLE_AppDefined,
465 : "XPath syntax %s not supported", osXPath.c_str());
466 : }
467 : }
468 : }
469 : }
470 :
471 : CPLXMLNode *psIgnoredXPaths =
472 206 : CPLGetXMLNode(psRoot, "=Configuration.IgnoredXPaths");
473 206 : if (psIgnoredXPaths)
474 : {
475 133 : const bool bGlobalWarnIfIgnoredXPathFound = CPLGetXMLBoolValue(
476 : psIgnoredXPaths, "WarnIfIgnoredXPathFoundInDocInstance",
477 : WARN_IF_EXCLUDED_XPATH_FOUND_DEFAULT);
478 :
479 133 : ParseNamespaces(psIgnoredXPaths, m_oMapPrefixToURIIgnoredXPaths);
480 :
481 3217 : for (CPLXMLNode *psIter = psIgnoredXPaths->psChild; psIter != nullptr;
482 3084 : psIter = psIter->psNext)
483 : {
484 3084 : if (psIter->eType == CXT_Element &&
485 2963 : EQUAL(psIter->pszValue, "XPath"))
486 : {
487 5428 : const CPLString &osXPath(CPLGetXMLValue(psIter, "", ""));
488 2714 : if (IsValidXPath(osXPath))
489 : {
490 2703 : m_aosIgnoredXPaths.push_back(osXPath);
491 :
492 2703 : const bool bWarnIfIgnoredXPathFound = CPLGetXMLBoolValue(
493 : psIter, "warnIfIgnoredXPathFoundInDocInstance",
494 : bGlobalWarnIfIgnoredXPathFound);
495 2703 : m_oMapIgnoredXPathToWarn[osXPath] =
496 : bWarnIfIgnoredXPathFound;
497 : }
498 : else
499 : {
500 11 : CPLError(CE_Warning, CPLE_AppDefined,
501 : "XPath syntax %s not supported", osXPath.c_str());
502 : }
503 : }
504 : }
505 : }
506 :
507 : CPLXMLNode *psXLinkResolutionNode =
508 206 : CPLGetXMLNode(psRoot, "=Configuration.XLinkResolution");
509 206 : if (psXLinkResolutionNode != nullptr)
510 126 : m_oXLinkResolution.LoadFromXML(psXLinkResolutionNode);
511 :
512 : // Parse WriterConfig
513 : CPLXMLNode *psWriterConfig =
514 206 : CPLGetXMLNode(psRoot, "=Configuration.WriterConfig");
515 206 : if (psWriterConfig != nullptr)
516 : {
517 117 : m_nIndentSize =
518 117 : atoi(CPLGetXMLValue(psWriterConfig, "IndentationSize",
519 : CPLSPrintf("%d", INDENT_SIZE_DEFAULT)));
520 117 : m_nIndentSize =
521 117 : std::min(INDENT_SIZE_MAX, std::max(INDENT_SIZE_MIN, m_nIndentSize));
522 :
523 117 : m_osComment = CPLGetXMLValue(psWriterConfig, "Comment", "");
524 :
525 117 : m_osLineFormat = CPLGetXMLValue(psWriterConfig, "LineFormat", "");
526 :
527 117 : m_osSRSNameFormat = CPLGetXMLValue(psWriterConfig, "SRSNameFormat", "");
528 :
529 : m_osWrapping = CPLGetXMLValue(psWriterConfig, "Wrapping",
530 117 : szWFS2_FEATURECOLLECTION);
531 :
532 117 : m_osTimestamp = CPLGetXMLValue(psWriterConfig, "Timestamp", "");
533 :
534 : m_osWFS20SchemaLocation = CPLGetXMLValue(
535 117 : psWriterConfig, "WFS20SchemaLocation", szWFS20_SCHEMALOCATION);
536 : }
537 :
538 206 : Finalize();
539 :
540 206 : return true;
541 : }
542 :
543 : /************************************************************************/
544 : /* LoadFromXML() */
545 : /************************************************************************/
546 :
547 126 : bool GMLASXLinkResolutionConf::LoadFromXML(CPLXMLNode *psRoot)
548 : {
549 126 : m_nTimeOut = atoi(CPLGetXMLValue(psRoot, "Timeout", "0"));
550 :
551 126 : m_nMaxFileSize = atoi(CPLGetXMLValue(
552 : psRoot, "MaxFileSize", CPLSPrintf("%d", MAX_FILE_SIZE_DEFAULT)));
553 :
554 126 : m_nMaxGlobalResolutionTime =
555 126 : atoi(CPLGetXMLValue(psRoot, "MaxGlobalResolutionTime", "0"));
556 :
557 126 : m_osProxyServerPort = CPLGetXMLValue(psRoot, "ProxyServerPort", "");
558 126 : m_osProxyUserPassword = CPLGetXMLValue(psRoot, "ProxyUserPassword", "");
559 126 : m_osProxyAuth = CPLGetXMLValue(psRoot, "ProxyAuth", "");
560 :
561 126 : m_osCacheDirectory = CPLGetXMLValue(psRoot, "CacheDirectory", "");
562 126 : if (m_osCacheDirectory.empty())
563 : {
564 117 : m_osCacheDirectory = GMLASConfiguration::GetBaseCacheDirectory();
565 117 : if (!m_osCacheDirectory.empty())
566 : {
567 : m_osCacheDirectory = CPLFormFilename(
568 117 : m_osCacheDirectory, "xlink_resolved_cache", nullptr);
569 : }
570 : }
571 :
572 126 : m_bDefaultResolutionEnabled =
573 126 : CPLGetXMLBoolValue(psRoot, "DefaultResolution.enabled",
574 : DEFAULT_RESOLUTION_ENABLED_DEFAULT);
575 :
576 126 : m_bDefaultAllowRemoteDownload =
577 126 : CPLGetXMLBoolValue(psRoot, "DefaultResolution.AllowRemoteDownload",
578 : ALLOW_REMOTE_DOWNLOAD_DEFAULT);
579 :
580 : // TODO when we support other modes
581 : // m_eDefaultResolutionMode =
582 :
583 126 : m_nDefaultResolutionDepth =
584 126 : atoi(CPLGetXMLValue(psRoot, "DefaultResolution.ResolutionDepth", "1"));
585 :
586 126 : m_bDefaultCacheResults = CPLGetXMLBoolValue(
587 : psRoot, "DefaultResolution.CacheResults", CACHE_RESULTS_DEFAULT);
588 :
589 126 : CPLXMLNode *psIterURL = psRoot->psChild;
590 1317 : for (; psIterURL != nullptr; psIterURL = psIterURL->psNext)
591 : {
592 1191 : if (psIterURL->eType == CXT_Element &&
593 606 : strcmp(psIterURL->pszValue, "URLSpecificResolution") == 0)
594 : {
595 10 : GMLASXLinkResolutionConf::URLSpecificResolution oItem;
596 5 : oItem.m_osURLPrefix = CPLGetXMLValue(psIterURL, "URLPrefix", "");
597 :
598 5 : oItem.m_bAllowRemoteDownload =
599 5 : CPLGetXMLBoolValue(psIterURL, "AllowRemoteDownload",
600 : ALLOW_REMOTE_DOWNLOAD_DEFAULT);
601 :
602 : const char *pszResolutionModel =
603 5 : CPLGetXMLValue(psIterURL, "ResolutionMode", "RawContent");
604 5 : if (EQUAL(pszResolutionModel, "RawContent"))
605 1 : oItem.m_eResolutionMode = RawContent;
606 : else
607 4 : oItem.m_eResolutionMode = FieldsFromXPath;
608 :
609 5 : oItem.m_nResolutionDepth =
610 5 : atoi(CPLGetXMLValue(psIterURL, "ResolutionDepth", "1"));
611 :
612 5 : oItem.m_bCacheResults = CPLGetXMLBoolValue(
613 : psIterURL, "CacheResults", CACHE_RESULTS_DEFAULT);
614 :
615 5 : CPLXMLNode *psIter = psIterURL->psChild;
616 45 : for (; psIter != nullptr; psIter = psIter->psNext)
617 : {
618 40 : if (psIter->eType == CXT_Element &&
619 40 : strcmp(psIter->pszValue, "HTTPHeader") == 0)
620 : {
621 8 : CPLString osName(CPLGetXMLValue(psIter, "Name", ""));
622 4 : CPLString osValue(CPLGetXMLValue(psIter, "Value", ""));
623 4 : oItem.m_aosNameValueHTTPHeaders.push_back(
624 12 : std::pair<CPLString, CPLString>(osName, osValue));
625 : }
626 36 : else if (psIter->eType == CXT_Element &&
627 36 : strcmp(psIter->pszValue, "Field") == 0)
628 : {
629 32 : URLSpecificResolution::XPathDerivedField oField;
630 16 : oField.m_osName = CPLGetXMLValue(psIter, "Name", "");
631 16 : oField.m_osType = CPLGetXMLValue(psIter, "Type", "");
632 16 : oField.m_osXPath = CPLGetXMLValue(psIter, "XPath", "");
633 16 : oItem.m_aoFields.push_back(oField);
634 : }
635 : }
636 :
637 5 : m_aoURLSpecificRules.push_back(oItem);
638 : }
639 : }
640 :
641 126 : m_bResolveInternalXLinks = CPLGetXMLBoolValue(
642 : psRoot, "ResolveInternalXLinks", INTERNAL_XLINK_RESOLUTION_DEFAULT);
643 :
644 126 : return true;
645 : }
|