1 /******************************************************************************
2 * Project: OGR
3 * Purpose: OGRGMLASDriver implementation
4 * Author: Even Rouault, <even dot rouault at spatialys dot com>
5 *
6 * Initial development funded by the European Earth observation programme
7 * Copernicus
8 *
9 ******************************************************************************
10 * Copyright (c) 2016, Even Rouault, <even dot rouault at spatialys dot com>
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 * DEALINGS IN THE SOFTWARE.
29 ****************************************************************************/
30
31 // Must be first for DEBUG_BOOL case
32 #include "ogr_gmlas.h"
33
34 #define CONSTANT_DEFINITION
35 #undef OGR_GMLAS_CONSTS_INCLUDED_REDEFINABLE
36 #include "ogr_gmlas_consts.h"
37
38 #include "cpl_minixml.h"
39
40 #include <algorithm>
41
42 CPL_CVSID("$Id: ogrgmlasconf.cpp 8ca42e1b9c2e54b75d35e49885df9789a2643aa4 2020-05-17 21:43:40 +0200 Even Rouault $")
43
44 /************************************************************************/
45 /* GMLASConfiguration() */
46 /************************************************************************/
47
GMLASConfiguration()48 GMLASConfiguration::GMLASConfiguration()
49 : m_bAllowRemoteSchemaDownload(ALLOW_REMOTE_SCHEMA_DOWNLOAD_DEFAULT)
50 , m_bAlwaysGenerateOGRId(ALWAYS_GENERATE_OGR_ID_DEFAULT)
51 , m_bRemoveUnusedLayers(REMOVE_UNUSED_LAYERS_DEFAULT)
52 , m_bRemoveUnusedFields(REMOVE_UNUSED_FIELDS_DEFAULT)
53 , m_bUseArrays(USE_ARRAYS_DEFAULT)
54 , m_bUseNullState(USE_NULL_STATE_DEFAULT)
55 , m_bIncludeGeometryXML(INCLUDE_GEOMETRY_XML_DEFAULT)
56 , m_bInstantiateGMLFeaturesOnly(INSTANTIATE_GML_FEATURES_ONLY_DEFAULT)
57 , m_nIdentifierMaxLength(0)
58 , m_bCaseInsensitiveIdentifier(CASE_INSENSITIVE_IDENTIFIER_DEFAULT)
59 , m_bPGIdentifierLaundering(PG_IDENTIFIER_LAUNDERING_DEFAULT)
60 , m_nMaximumFieldsForFlattening(MAXIMUM_FIELDS_FLATTENING_DEFAULT)
61 , m_bAllowXSDCache(ALLOW_XSD_CACHE_DEFAULT)
62 , m_bSchemaFullChecking(SCHEMA_FULL_CHECKING_DEFAULT)
63 , m_bHandleMultipleImports(HANDLE_MULTIPLE_IMPORTS_DEFAULT)
64 , m_bValidate(VALIDATE_DEFAULT)
65 , m_bFailIfValidationError(FAIL_IF_VALIDATION_ERROR_DEFAULT)
66 , m_bExposeMetadataLayers(WARN_IF_EXCLUDED_XPATH_FOUND_DEFAULT)
67 , m_eSWEActivationMode(SWE_ACTIVATE_IF_NAMESPACE_FOUND)
68 , m_bSWEProcessDataRecord(SWE_PROCESS_DATA_RECORD_DEFAULT)
69 , m_bSWEProcessDataArray(SWE_PROCESS_DATA_ARRAY_DEFAULT)
70 , m_nIndentSize(INDENT_SIZE_DEFAULT)
71 , m_osSRSNameFormat(szSRSNAME_DEFAULT)
72 , m_osWrapping(szWFS2_FEATURECOLLECTION)
73 , m_osWFS20SchemaLocation(szWFS20_SCHEMALOCATION)
74 {
75 }
76
77 /************************************************************************/
78 /* ~GMLASConfiguration() */
79 /************************************************************************/
80
~GMLASConfiguration()81 GMLASConfiguration::~GMLASConfiguration()
82 {
83 }
84
85 /************************************************************************/
86 /* GetBaseCacheDirectory() */
87 /************************************************************************/
88
GetBaseCacheDirectory()89 CPLString GMLASConfiguration::GetBaseCacheDirectory()
90 {
91 #ifdef WIN32
92 const char* pszHome = CPLGetConfigOption("USERPROFILE", nullptr);
93 #else
94 const char* pszHome = CPLGetConfigOption("HOME", nullptr);
95 #endif
96 if( pszHome != nullptr )
97 {
98 return CPLFormFilename( pszHome, ".gdal", nullptr) ;
99 }
100 else
101 {
102 const char *pszDir = CPLGetConfigOption( "CPL_TMPDIR", nullptr );
103
104 if( pszDir == nullptr )
105 pszDir = CPLGetConfigOption( "TMPDIR", nullptr );
106
107 if( pszDir == nullptr )
108 pszDir = CPLGetConfigOption( "TEMP", nullptr );
109
110 const char* pszUsername = CPLGetConfigOption("USERNAME", nullptr);
111 if( pszUsername == nullptr )
112 pszUsername = CPLGetConfigOption("USER", nullptr);
113
114 if( pszDir != nullptr && pszUsername != nullptr )
115 {
116 return CPLFormFilename( pszDir,
117 CPLSPrintf(".gdal_%s", pszUsername), nullptr) ;
118 }
119 }
120 return CPLString();
121 }
122
123 /************************************************************************/
124 /* Finalize() */
125 /************************************************************************/
126
Finalize()127 void GMLASConfiguration::Finalize()
128 {
129 if( m_bAllowXSDCache && m_osXSDCacheDirectory.empty() )
130 {
131 m_osXSDCacheDirectory = GetBaseCacheDirectory();
132 if( m_osXSDCacheDirectory.empty() )
133 {
134 CPLError(CE_Warning, CPLE_AppDefined,
135 "Could not determine a directory for GMLAS XSD cache");
136 }
137 else
138 {
139 m_osXSDCacheDirectory = CPLFormFilename( m_osXSDCacheDirectory,
140 "gmlas_xsd_cache", nullptr) ;
141 CPLDebug("GMLAS", "XSD cache directory: %s",
142 m_osXSDCacheDirectory.c_str());
143 }
144 }
145 }
146
147 /************************************************************************/
148 /* CPLGetXMLBoolValue() */
149 /************************************************************************/
150
CPLGetXMLBoolValue(CPLXMLNode * psNode,const char * pszKey,bool bDefault)151 static bool CPLGetXMLBoolValue(CPLXMLNode* psNode,
152 const char* pszKey,
153 bool bDefault)
154 {
155 const char* pszVal = CPLGetXMLValue(psNode, pszKey, nullptr);
156 if( pszVal )
157 return CPLTestBool(pszVal);
158 else
159 return bDefault;
160 }
161
162 /************************************************************************/
163 /* IsValidXPath() */
164 /************************************************************************/
165
IsValidXPath(const CPLString & osXPath)166 static bool IsValidXPath(const CPLString& osXPath )
167 {
168 // Check that the XPath syntax belongs to the subset we
169 // understand
170 bool bOK = !osXPath.empty();
171 for(size_t i = 0; i < osXPath.size(); ++i )
172 {
173 const char chCur = osXPath[i];
174 if( chCur == '/' )
175 {
176 // OK
177 }
178 else if( chCur == '@' &&
179 (i == 0 || osXPath[i-1] == '/') &&
180 i < osXPath.size()-1 &&
181 isalpha( static_cast<int>(osXPath[i+1]) ) )
182 {
183 // OK
184 }
185 else if( chCur == '_' ||
186 isalpha( static_cast<int>(chCur) ) )
187 {
188 // OK
189 }
190 else if( isdigit( static_cast<int>(chCur) ) &&
191 i > 0 &&
192 (isalnum( static_cast<int>(osXPath[i-1]) ) ||
193 osXPath[i-1] == '_') )
194 {
195 // OK
196 }
197 else if( chCur == ':' &&
198 i > 0 &&
199 (isalnum( static_cast<int>(osXPath[i-1]) ) ||
200 osXPath[i-1] == '_') &&
201 i < osXPath.size()-1 &&
202 isalpha( static_cast<int>(osXPath[i+1]) ) )
203 {
204 // OK
205 }
206 else
207 {
208 bOK = false;
209 break;
210 }
211 }
212 return bOK;
213 }
214
215 /************************************************************************/
216 /* GMLASConfigurationErrorHandler() */
217 /************************************************************************/
218
GMLASConfigurationErrorHandler(CPLErr,CPLErrorNum,const char * pszMsg)219 static void CPL_STDCALL GMLASConfigurationErrorHandler(CPLErr /*eErr*/,
220 CPLErrorNum /*nType*/,
221 const char* pszMsg)
222 {
223 std::vector<CPLString>* paosErrors =
224 (std::vector<CPLString>* )CPLGetErrorHandlerUserData();
225 paosErrors->push_back(pszMsg);
226 }
227
228 /************************************************************************/
229 /* ParseNamespaces() */
230 /************************************************************************/
231
ParseNamespaces(CPLXMLNode * psContainerNode,std::map<CPLString,CPLString> & oMap)232 static void ParseNamespaces(CPLXMLNode* psContainerNode,
233 std::map<CPLString, CPLString>& oMap)
234 {
235 CPLXMLNode* psNamespaces = CPLGetXMLNode(psContainerNode, "Namespaces");
236 if( psNamespaces != nullptr )
237 {
238 for( CPLXMLNode* psIter = psNamespaces->psChild;
239 psIter != nullptr;
240 psIter = psIter->psNext )
241 {
242 if( psIter->eType == CXT_Element &&
243 EQUAL(psIter->pszValue, "Namespace") )
244 {
245 CPLString osPrefix = CPLGetXMLValue(psIter, "prefix", "");
246 CPLString osURI = CPLGetXMLValue(psIter, "uri", "");
247 if( !osPrefix.empty() && !osURI.empty() )
248 {
249 if( oMap.find(osPrefix) ==
250 oMap.end() )
251 {
252 oMap[osPrefix] = osURI;
253 }
254 else
255 {
256 CPLError(CE_Warning, CPLE_AppDefined,
257 "Prefix %s was already mapped to %s. "
258 "Attempt to map it to %s ignored",
259 osPrefix.c_str(),
260 oMap[osPrefix].
261 c_str(),
262 osURI.c_str());
263 }
264 }
265 }
266 }
267 }
268 }
269
270 /************************************************************************/
271 /* Load() */
272 /************************************************************************/
273
Load(const char * pszFilename)274 bool GMLASConfiguration::Load(const char* pszFilename)
275 {
276 // Allow configuration to be inlined
277 CPLXMLNode* psRoot = STARTS_WITH(pszFilename, "<Configuration") ?
278 CPLParseXMLString(pszFilename) :
279 CPLParseXMLFile(pszFilename);
280 if( psRoot == nullptr )
281 {
282 Finalize();
283 return false;
284 }
285 CPLXMLTreeCloser oCloser(psRoot);
286 CPL_IGNORE_RET_VAL(oCloser);
287
288 // Validate the configuration file
289 if( CPLTestBool(CPLGetConfigOption("GDAL_XML_VALIDATION", "YES")) )
290 {
291 const char* pszXSD = CPLFindFile( "gdal", "gmlasconf.xsd" );
292 if( pszXSD != nullptr )
293 {
294 std::vector<CPLString> aosErrors;
295 const CPLErr eErrClass = CPLGetLastErrorType();
296 const CPLErrorNum nErrNum = CPLGetLastErrorNo();
297 const CPLString osErrMsg = CPLGetLastErrorMsg();
298 CPLPushErrorHandlerEx(GMLASConfigurationErrorHandler, &aosErrors);
299 int bRet = CPLValidateXML(pszFilename, pszXSD, nullptr);
300 CPLPopErrorHandler();
301 if( !bRet && !aosErrors.empty() &&
302 strstr(aosErrors[0].c_str(), "missing libxml2 support") == nullptr )
303 {
304 for(size_t i = 0; i < aosErrors.size(); i++)
305 {
306 CPLError(CE_Warning, CPLE_AppDefined,
307 "%s", aosErrors[i].c_str());
308 }
309 }
310 else
311 {
312 CPLErrorSetState(eErrClass, nErrNum, osErrMsg);
313 }
314 }
315 }
316
317 m_bAllowRemoteSchemaDownload = CPLGetXMLBoolValue(psRoot,
318 "=Configuration.AllowRemoteSchemaDownload",
319 ALLOW_REMOTE_SCHEMA_DOWNLOAD_DEFAULT );
320
321 m_bAllowXSDCache = CPLGetXMLBoolValue( psRoot,
322 "=Configuration.SchemaCache.enabled",
323 ALLOW_XSD_CACHE_DEFAULT );
324 if( m_bAllowXSDCache )
325 {
326 m_osXSDCacheDirectory =
327 CPLGetXMLValue(psRoot, "=Configuration.SchemaCache.Directory",
328 "");
329 }
330
331 m_bSchemaFullChecking = CPLGetXMLBoolValue( psRoot,
332 "=Configuration.SchemaAnalysisOptions.SchemaFullChecking",
333 SCHEMA_FULL_CHECKING_DEFAULT);
334
335 m_bHandleMultipleImports = CPLGetXMLBoolValue( psRoot,
336 "=Configuration.SchemaAnalysisOptions.HandleMultipleImports",
337 HANDLE_MULTIPLE_IMPORTS_DEFAULT);
338
339 m_bValidate = CPLGetXMLBoolValue( psRoot,
340 "=Configuration.Validation.enabled",
341 VALIDATE_DEFAULT );
342
343 if( m_bValidate )
344 {
345 m_bFailIfValidationError = CPLGetXMLBoolValue(psRoot,
346 "=Configuration.Validation.FailIfError",
347 FAIL_IF_VALIDATION_ERROR_DEFAULT );
348 }
349
350 m_bExposeMetadataLayers = CPLGetXMLBoolValue( psRoot,
351 "=Configuration.ExposeMetadataLayers",
352 EXPOSE_METADATA_LAYERS_DEFAULT );
353
354 m_bAlwaysGenerateOGRId = CPLGetXMLBoolValue( psRoot,
355 "=Configuration.LayerBuildingRules.AlwaysGenerateOGRId",
356 ALWAYS_GENERATE_OGR_ID_DEFAULT );
357
358 m_bRemoveUnusedLayers = CPLGetXMLBoolValue( psRoot,
359 "=Configuration.LayerBuildingRules.RemoveUnusedLayers",
360 REMOVE_UNUSED_LAYERS_DEFAULT );
361
362 m_bRemoveUnusedFields = CPLGetXMLBoolValue( psRoot,
363 "=Configuration.LayerBuildingRules.RemoveUnusedFields",
364 REMOVE_UNUSED_FIELDS_DEFAULT );
365
366 m_bUseArrays = CPLGetXMLBoolValue( psRoot,
367 "=Configuration.LayerBuildingRules.UseArrays",
368 USE_ARRAYS_DEFAULT );
369 m_bUseNullState = CPLGetXMLBoolValue( psRoot,
370 "=Configuration.LayerBuildingRules.UseNullState",
371 USE_NULL_STATE_DEFAULT );
372 m_bIncludeGeometryXML = CPLGetXMLBoolValue( psRoot,
373 "=Configuration.LayerBuildingRules.GML.IncludeGeometryXML",
374 INCLUDE_GEOMETRY_XML_DEFAULT );
375 m_bInstantiateGMLFeaturesOnly = CPLGetXMLBoolValue( psRoot,
376 "=Configuration.LayerBuildingRules.GML.InstantiateGMLFeaturesOnly",
377 INSTANTIATE_GML_FEATURES_ONLY_DEFAULT );
378 m_nIdentifierMaxLength = atoi( CPLGetXMLValue( psRoot,
379 "=Configuration.LayerBuildingRules.IdentifierMaxLength",
380 "0" ) );
381 m_bCaseInsensitiveIdentifier = CPLGetXMLBoolValue( psRoot,
382 "=Configuration.LayerBuildingRules.CaseInsensitiveIdentifier",
383 CASE_INSENSITIVE_IDENTIFIER_DEFAULT );
384 m_bPGIdentifierLaundering = CPLGetXMLBoolValue( psRoot,
385 "=Configuration.LayerBuildingRules.PostgreSQLIdentifierLaundering",
386 PG_IDENTIFIER_LAUNDERING_DEFAULT );
387
388 CPLXMLNode* psFlatteningRules = CPLGetXMLNode(psRoot,
389 "=Configuration.LayerBuildingRules.FlatteningRules");
390 if( psFlatteningRules )
391 {
392 m_nMaximumFieldsForFlattening = atoi( CPLGetXMLValue( psFlatteningRules,
393 "MaximumNumberOfFields",
394 CPLSPrintf("%d", MAXIMUM_FIELDS_FLATTENING_DEFAULT) ) );
395
396 ParseNamespaces(psFlatteningRules, m_oMapPrefixToURIFlatteningRules);
397
398 for( CPLXMLNode* psIter = psFlatteningRules->psChild;
399 psIter != nullptr;
400 psIter = psIter->psNext )
401 {
402 if( psIter->eType == CXT_Element &&
403 EQUAL(psIter->pszValue, "ForceFlatteningXPath") )
404 {
405 m_osForcedFlattenedXPath.push_back(
406 CPLGetXMLValue(psIter, "", "") );
407 }
408 else if( psIter->eType == CXT_Element &&
409 EQUAL(psIter->pszValue, "DisableFlatteningXPath") )
410 {
411 m_osDisabledFlattenedXPath.push_back(
412 CPLGetXMLValue(psIter, "", "") );
413 }
414 }
415 }
416
417 const char* pszSWEProcessingActivation = CPLGetXMLValue( psRoot,
418 "=Configuration.LayerBuildingRules.SWEProcessing.Activation",
419 "ifSWENamespaceFoundInTopElement" );
420 if( EQUAL(pszSWEProcessingActivation, "ifSWENamespaceFoundInTopElement") )
421 m_eSWEActivationMode = SWE_ACTIVATE_IF_NAMESPACE_FOUND;
422 else if( CPLTestBool(pszSWEProcessingActivation) )
423 m_eSWEActivationMode = SWE_ACTIVATE_TRUE;
424 else
425 m_eSWEActivationMode = SWE_ACTIVATE_FALSE;
426 m_bSWEProcessDataRecord = CPLTestBool(CPLGetXMLValue( psRoot,
427 "=Configuration.LayerBuildingRules.SWEProcessing.ProcessDataRecord",
428 "true" ));
429 m_bSWEProcessDataArray = CPLTestBool(CPLGetXMLValue( psRoot,
430 "=Configuration.LayerBuildingRules.SWEProcessing.ProcessDataArray",
431 "true" ));
432
433 CPLXMLNode* psTypingConstraints = CPLGetXMLNode(psRoot,
434 "=Configuration.TypingConstraints");
435 if( psTypingConstraints )
436 {
437 ParseNamespaces(psTypingConstraints, m_oMapPrefixToURITypeConstraints);
438
439 for( CPLXMLNode* psIter = psTypingConstraints->psChild;
440 psIter != nullptr;
441 psIter = psIter->psNext )
442 {
443 if( psIter->eType == CXT_Element &&
444 EQUAL(psIter->pszValue, "ChildConstraint") )
445 {
446 const CPLString& osXPath( CPLGetXMLValue(psIter, "ContainerXPath", "") );
447 CPLXMLNode* psChildrenTypes = CPLGetXMLNode(psIter, "ChildrenElements");
448 if( IsValidXPath(osXPath) )
449 {
450 for( CPLXMLNode* psIter2 =
451 psChildrenTypes ? psChildrenTypes->psChild : nullptr;
452 psIter2 != nullptr;
453 psIter2 = psIter2->psNext )
454 {
455 if( psIter2->eType == CXT_Element &&
456 EQUAL(psIter2->pszValue, "Element") )
457 {
458 m_oMapChildrenElementsConstraints[osXPath].push_back(
459 CPLGetXMLValue(psIter2, "", "") );
460 }
461 }
462 }
463 else
464 {
465 CPLError(CE_Warning, CPLE_AppDefined,
466 "XPath syntax %s not supported",
467 osXPath.c_str());
468 }
469 }
470 }
471 }
472
473 CPLXMLNode* psIgnoredXPaths = CPLGetXMLNode(psRoot,
474 "=Configuration.IgnoredXPaths");
475 if( psIgnoredXPaths )
476 {
477 const bool bGlobalWarnIfIgnoredXPathFound = CPLGetXMLBoolValue(
478 psIgnoredXPaths,
479 "WarnIfIgnoredXPathFoundInDocInstance",
480 WARN_IF_EXCLUDED_XPATH_FOUND_DEFAULT );
481
482 ParseNamespaces(psIgnoredXPaths, m_oMapPrefixToURIIgnoredXPaths);
483
484 for( CPLXMLNode* psIter = psIgnoredXPaths->psChild;
485 psIter != nullptr;
486 psIter = psIter->psNext )
487 {
488 if( psIter->eType == CXT_Element &&
489 EQUAL(psIter->pszValue, "XPath") )
490 {
491 const CPLString& osXPath( CPLGetXMLValue(psIter, "", "") );
492 if( IsValidXPath(osXPath) )
493 {
494 m_aosIgnoredXPaths.push_back( osXPath );
495
496 const bool bWarnIfIgnoredXPathFound = CPLGetXMLBoolValue(
497 psIter,
498 "warnIfIgnoredXPathFoundInDocInstance",
499 bGlobalWarnIfIgnoredXPathFound );
500 m_oMapIgnoredXPathToWarn[ osXPath ] = bWarnIfIgnoredXPathFound;
501 }
502 else
503 {
504 CPLError(CE_Warning, CPLE_AppDefined,
505 "XPath syntax %s not supported",
506 osXPath.c_str());
507 }
508 }
509 }
510 }
511
512 CPLXMLNode* psXLinkResolutionNode = CPLGetXMLNode( psRoot,
513 "=Configuration.XLinkResolution");
514 if( psXLinkResolutionNode != nullptr )
515 m_oXLinkResolution.LoadFromXML( psXLinkResolutionNode );
516
517 // Parse WriterConfig
518 CPLXMLNode* psWriterConfig = CPLGetXMLNode( psRoot,
519 "=Configuration.WriterConfig");
520 if( psWriterConfig != nullptr )
521 {
522 m_nIndentSize = atoi( CPLGetXMLValue( psWriterConfig,
523 "IndentationSize",
524 CPLSPrintf("%d", INDENT_SIZE_DEFAULT ) ) );
525 m_nIndentSize = std::min( INDENT_SIZE_MAX,
526 std::max( INDENT_SIZE_MIN, m_nIndentSize ) );
527
528 m_osComment = CPLGetXMLValue( psWriterConfig, "Comment", "" );
529
530 m_osLineFormat = CPLGetXMLValue( psWriterConfig, "LineFormat", "" );
531
532 m_osSRSNameFormat = CPLGetXMLValue( psWriterConfig, "SRSNameFormat", "" );
533
534 m_osWrapping = CPLGetXMLValue( psWriterConfig, "Wrapping",
535 szWFS2_FEATURECOLLECTION );
536
537 m_osTimestamp = CPLGetXMLValue( psWriterConfig, "Timestamp", "" );
538
539 m_osWFS20SchemaLocation = CPLGetXMLValue( psWriterConfig,
540 "WFS20SchemaLocation",
541 szWFS20_SCHEMALOCATION );
542 }
543
544 Finalize();
545
546 return true;
547 }
548
549 /************************************************************************/
550 /* GMLASXLinkResolutionConf() */
551 /************************************************************************/
552
GMLASXLinkResolutionConf()553 GMLASXLinkResolutionConf::GMLASXLinkResolutionConf() :
554 m_nTimeOut(0),
555 m_nMaxFileSize(MAX_FILE_SIZE_DEFAULT),
556 m_nMaxGlobalResolutionTime(0),
557 m_bDefaultResolutionEnabled(DEFAULT_RESOLUTION_ENABLED_DEFAULT),
558 m_bDefaultAllowRemoteDownload(ALLOW_REMOTE_DOWNLOAD_DEFAULT),
559 m_eDefaultResolutionMode(RawContent),
560 m_nDefaultResolutionDepth(1),
561 m_bDefaultCacheResults(CACHE_RESULTS_DEFAULT),
562 m_bResolveInternalXLinks(INTERNAL_XLINK_RESOLUTION_DEFAULT)
563 {
564 }
565
566 /************************************************************************/
567 /* LoadFromXML() */
568 /************************************************************************/
569
LoadFromXML(CPLXMLNode * psRoot)570 bool GMLASXLinkResolutionConf::LoadFromXML(CPLXMLNode* psRoot)
571 {
572 m_nTimeOut = atoi( CPLGetXMLValue( psRoot, "Timeout", "0" ) );
573
574 m_nMaxFileSize = atoi( CPLGetXMLValue( psRoot, "MaxFileSize",
575 CPLSPrintf("%d", MAX_FILE_SIZE_DEFAULT)) );
576
577 m_nMaxGlobalResolutionTime = atoi(
578 CPLGetXMLValue( psRoot, "MaxGlobalResolutionTime", "0" ) );
579
580 m_osProxyServerPort = CPLGetXMLValue( psRoot, "ProxyServerPort", "" );
581 m_osProxyUserPassword = CPLGetXMLValue( psRoot, "ProxyUserPassword", "" );
582 m_osProxyAuth = CPLGetXMLValue( psRoot, "ProxyAuth", "" );
583
584 m_osCacheDirectory = CPLGetXMLValue( psRoot, "CacheDirectory", "" );
585 if( m_osCacheDirectory.empty() )
586 {
587 m_osCacheDirectory = GMLASConfiguration::GetBaseCacheDirectory();
588 if( !m_osCacheDirectory.empty() )
589 {
590 m_osCacheDirectory = CPLFormFilename( m_osCacheDirectory,
591 "xlink_resolved_cache",
592 nullptr );
593 }
594 }
595
596 m_bDefaultResolutionEnabled = CPLGetXMLBoolValue( psRoot,
597 "DefaultResolution.enabled",
598 DEFAULT_RESOLUTION_ENABLED_DEFAULT);
599
600 m_bDefaultAllowRemoteDownload = CPLGetXMLBoolValue( psRoot,
601 "DefaultResolution.AllowRemoteDownload",
602 ALLOW_REMOTE_DOWNLOAD_DEFAULT);
603
604 // TODO when we support other modes
605 // m_eDefaultResolutionMode =
606
607 m_nDefaultResolutionDepth = atoi( CPLGetXMLValue( psRoot,
608 "DefaultResolution.ResolutionDepth", "1") );
609
610 m_bDefaultCacheResults = CPLGetXMLBoolValue( psRoot,
611 "DefaultResolution.CacheResults",
612 CACHE_RESULTS_DEFAULT);
613
614 CPLXMLNode* psIterURL = psRoot->psChild;
615 for( ; psIterURL != nullptr; psIterURL = psIterURL->psNext )
616 {
617 if( psIterURL->eType == CXT_Element &&
618 strcmp(psIterURL->pszValue, "URLSpecificResolution") == 0 )
619 {
620 GMLASXLinkResolutionConf::URLSpecificResolution oItem;
621 oItem.m_osURLPrefix = CPLGetXMLValue(psIterURL, "URLPrefix", "");
622
623 oItem.m_bAllowRemoteDownload = CPLGetXMLBoolValue( psIterURL,
624 "AllowRemoteDownload",
625 ALLOW_REMOTE_DOWNLOAD_DEFAULT);
626
627 const char* pszResolutionModel = CPLGetXMLValue(psIterURL,
628 "ResolutionMode", "RawContent");
629 if( EQUAL(pszResolutionModel, "RawContent") )
630 oItem.m_eResolutionMode = RawContent;
631 else
632 oItem.m_eResolutionMode = FieldsFromXPath;
633
634 oItem.m_nResolutionDepth = atoi( CPLGetXMLValue( psIterURL,
635 "ResolutionDepth", "1") );
636
637 oItem.m_bCacheResults = CPLGetXMLBoolValue( psIterURL,
638 "CacheResults",
639 CACHE_RESULTS_DEFAULT);
640
641 CPLXMLNode* psIter = psIterURL->psChild;
642 for( ; psIter != nullptr; psIter = psIter->psNext )
643 {
644 if( psIter->eType == CXT_Element &&
645 strcmp(psIter->pszValue, "HTTPHeader") == 0 )
646 {
647 CPLString osName( CPLGetXMLValue(psIter, "Name", "") );
648 CPLString osValue( CPLGetXMLValue(psIter, "Value", "") );
649 oItem.m_aosNameValueHTTPHeaders.push_back(
650 std::pair<CPLString, CPLString>(osName, osValue));
651 }
652 else if( psIter->eType == CXT_Element &&
653 strcmp(psIter->pszValue, "Field") == 0 )
654 {
655 URLSpecificResolution::XPathDerivedField oField;
656 oField.m_osName = CPLGetXMLValue(psIter, "Name", "");
657 oField.m_osType = CPLGetXMLValue(psIter, "Type", "");
658 oField.m_osXPath = CPLGetXMLValue(psIter, "XPath", "");
659 oItem.m_aoFields.push_back( oField );
660 }
661 }
662
663 m_aoURLSpecificRules.push_back( oItem );
664 }
665 }
666
667 m_bResolveInternalXLinks = CPLGetXMLBoolValue( psRoot,
668 "ResolveInternalXLinks",
669 INTERNAL_XLINK_RESOLUTION_DEFAULT);
670
671 return true;
672 }
673
674 /************************************************************************/
675 /* URLSpecificResolution() */
676 /************************************************************************/
677
URLSpecificResolution()678 GMLASXLinkResolutionConf::URLSpecificResolution::URLSpecificResolution() :
679 m_bAllowRemoteDownload(false),
680 m_eResolutionMode(RawContent),
681 m_nResolutionDepth(1),
682 m_bCacheResults(false)
683 {
684 }
685