LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/gmlas - ogrgmlasconf.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 214 230 93.0 %
Date: 2025-05-31 00:00:17 Functions: 7 8 87.5 %

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

Generated by: LCOV version 1.14