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

Generated by: LCOV version 1.14