LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/gmlas - ogr_gmlas.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 325 325 100.0 %
Date: 2025-05-31 00:00:17 Functions: 136 137 99.3 %

          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             : #ifndef OGR_GMLAS_INCLUDED
      16             : #define OGR_GMLAS_INCLUDED
      17             : 
      18             : #include "xercesc_headers.h"
      19             : #include "ogr_xerces.h"
      20             : 
      21             : #include "cpl_vsi_virtual.h"
      22             : #include "gdal_priv.h"
      23             : #include "ogrsf_frmts.h"
      24             : 
      25             : #include "ogr_gmlas_consts.h"
      26             : 
      27             : #include <list>
      28             : #include <set>
      29             : #include <map>
      30             : #include <vector>
      31             : 
      32             : typedef std::pair<CPLString, CPLString> PairURIFilename;
      33             : 
      34             : typedef enum
      35             : {
      36             :     GMLAS_SWAP_AUTO,
      37             :     GMLAS_SWAP_YES,
      38             :     GMLAS_SWAP_NO,
      39             : } GMLASSwapCoordinatesEnum;
      40             : 
      41             : GDALDataset *OGRGMLASDriverCreateCopy(const char *pszFilename,
      42             :                                       GDALDataset *poSrcDS, int /*bStrict*/,
      43             :                                       char **papszOptions,
      44             :                                       GDALProgressFunc pfnProgress,
      45             :                                       void *pProgressData);
      46             : 
      47             : /************************************************************************/
      48             : /*                          IGMLASInputSourceClosing                    */
      49             : /************************************************************************/
      50             : 
      51             : class IGMLASInputSourceClosing
      52             : {
      53             :   public:
      54         240 :     virtual ~IGMLASInputSourceClosing()
      55         240 :     {
      56         240 :     }
      57             : 
      58             :     virtual void notifyClosing(const CPLString &osFilename) = 0;
      59             : };
      60             : 
      61             : /************************************************************************/
      62             : /*                         GMLASResourceCache                           */
      63             : /************************************************************************/
      64             : 
      65             : class GMLASResourceCache
      66             : {
      67             :   protected:
      68             :     bool m_bHasCheckedCacheDirectory = false;
      69             :     std::string m_osCacheDirectory{};
      70             :     bool m_bRefresh = false;
      71             :     bool m_bAllowDownload = false;
      72             :     std::set<std::string> m_aoSetRefreshedFiles{};
      73             : 
      74             :     static bool
      75             :     RecursivelyCreateDirectoryIfNeeded(const std::string &osDirname);
      76             :     bool RecursivelyCreateDirectoryIfNeeded();
      77             : 
      78             :     std::string GetCachedFilename(const std::string &osResource);
      79             : 
      80             :   public:
      81             :     void SetCacheDirectory(const std::string &osCacheDirectory);
      82             : 
      83         371 :     void SetRefreshMode(bool bRefresh)
      84             :     {
      85         371 :         m_bRefresh = bRefresh;
      86         371 :     }
      87             : 
      88         193 :     void SetAllowDownload(bool bVal)
      89             :     {
      90         193 :         m_bAllowDownload = bVal;
      91         193 :     }
      92             : };
      93             : 
      94             : /************************************************************************/
      95             : /*                          GMLASXSDCache                               */
      96             : /************************************************************************/
      97             : 
      98             : class GMLASXSDCache final : public GMLASResourceCache
      99             : {
     100             :     bool CacheAllGML321();
     101             :     bool CacheAllISO20070417();
     102             : 
     103             :   public:
     104             :     VSILFILE *Open(const std::string &osResource, const std::string &osBasePath,
     105             :                    std::string &osOutFilename);
     106             : };
     107             : 
     108             : /************************************************************************/
     109             : /*                     GMLASBaseEntityResolver                          */
     110             : /************************************************************************/
     111             : 
     112             : class GMLASBaseEntityResolver : public EntityResolver,
     113             :                                 public IGMLASInputSourceClosing
     114             : {
     115             :   protected:
     116             :     std::vector<CPLString> m_aosPathStack{};
     117             :     GMLASXSDCache &m_oCache;
     118             :     CPLString m_osGMLVersionFound{};
     119             :     std::set<CPLString> m_oSetSchemaURLs{};
     120             :     bool m_bFoundNonOfficialGMLSchemaLocation = false;
     121             :     bool m_bSubstituteWithOGCSchemaLocation = false;
     122             : 
     123             :   public:
     124             :     GMLASBaseEntityResolver(const CPLString &osBasePath, GMLASXSDCache &oCache);
     125             :     virtual ~GMLASBaseEntityResolver();
     126             : 
     127             :     void SetBasePath(const CPLString &osBasePath);
     128             : 
     129         179 :     const CPLString &GetGMLVersionFound() const
     130             :     {
     131         179 :         return m_osGMLVersionFound;
     132             :     }
     133             : 
     134         179 :     const std::set<CPLString> &GetSchemaURLS() const
     135             :     {
     136         179 :         return m_oSetSchemaURLs;
     137             :     }
     138             : 
     139           2 :     void SetSubstituteWithOGCSchemaLocation(bool b)
     140             :     {
     141           2 :         m_bSubstituteWithOGCSchemaLocation = b;
     142           2 :     }
     143             : 
     144           2 :     bool GetFoundNonOfficialGMLSchemaLocation() const
     145             :     {
     146           2 :         return m_bFoundNonOfficialGMLSchemaLocation;
     147             :     }
     148             : 
     149             :     virtual void notifyClosing(const CPLString &osFilename) override;
     150             :     virtual InputSource *resolveEntity(const XMLCh *const publicId,
     151             :                                        const XMLCh *const systemId) override;
     152             : 
     153             :     virtual void
     154             :     DoExtraSchemaProcessing(const CPLString &osFilename,
     155             :                             const std::shared_ptr<VSIVirtualHandle> &fp);
     156             : };
     157             : 
     158             : /************************************************************************/
     159             : /*                          GMLASInputSource                            */
     160             : /************************************************************************/
     161             : 
     162             : class GMLASInputSource final : public InputSource
     163             : {
     164             :     std::shared_ptr<VSIVirtualHandle> m_fp{};
     165             :     int m_nCounter = 0;
     166             :     int *m_pnCounter = nullptr;
     167             :     CPLString m_osFilename{};
     168             :     IGMLASInputSourceClosing *m_cbk = nullptr;
     169             : 
     170             :     CPL_DISALLOW_COPY_ASSIGN(GMLASInputSource)
     171             : 
     172             :   public:
     173             :     GMLASInputSource(
     174             :         const char *pszFilename, const std::shared_ptr<VSIVirtualHandle> &fp,
     175             :         MemoryManager *const manager = XMLPlatformUtils::fgMemoryManager);
     176             :     virtual ~GMLASInputSource();
     177             : 
     178             :     virtual BinInputStream *makeStream() const override;
     179             : 
     180             :     void SetClosingCallback(IGMLASInputSourceClosing *cbk);
     181             : };
     182             : 
     183             : /************************************************************************/
     184             : /*                            GMLASErrorHandler                         */
     185             : /************************************************************************/
     186             : 
     187             : class GMLASErrorHandler : public ErrorHandler
     188             : {
     189             :   public:
     190        2963 :     GMLASErrorHandler() = default;
     191             : 
     192        1673 :     void SetSchemaFullCheckingEnabled(bool b)
     193             :     {
     194        1673 :         m_bSchemaFullChecking = b;
     195        1673 :     }
     196             : 
     197        1673 :     void SetHandleMultipleImportsEnabled(bool b)
     198             :     {
     199        1673 :         m_bHandleMultipleImports = b;
     200        1673 :     }
     201             : 
     202         279 :     void SetHideGMLTypeNotFound(bool b)
     203             :     {
     204         279 :         m_bHideGMLTypeNotFound = b;
     205         279 :     }
     206             : 
     207           6 :     const std::string &GetGMLTypeNotFoundError() const
     208             :     {
     209           6 :         return m_osGMLTypeNotFoundError;
     210             :     }
     211             : 
     212         278 :     bool hasFailed() const
     213             :     {
     214         278 :         return m_bFailed;
     215             :     }
     216             : 
     217             :     virtual void warning(const SAXParseException &e) override;
     218             :     virtual void error(const SAXParseException &e) override;
     219             :     virtual void fatalError(const SAXParseException &e) override;
     220             : 
     221        2529 :     virtual void resetErrors() override
     222             :     {
     223        2529 :         m_bFailed = false;
     224        2529 :     }
     225             : 
     226             :   private:
     227             :     bool m_bFailed = false;
     228             :     bool m_bSchemaFullChecking = false;
     229             :     bool m_bHandleMultipleImports = false;
     230             :     bool m_bHideGMLTypeNotFound = false;
     231             :     std::string m_osGMLTypeNotFoundError{};
     232             : 
     233             :     void handle(const SAXParseException &e, CPLErr eErr);
     234             : };
     235             : 
     236             : /************************************************************************/
     237             : /*                        GMLASXLinkResolutionConf                      */
     238             : /************************************************************************/
     239             : 
     240             : class GMLASXLinkResolutionConf
     241             : {
     242             :   public:
     243             :     /* See data/gmlasconf.xsd for docomentation of the fields */
     244             : 
     245             :     typedef enum
     246             :     {
     247             :         RawContent,
     248             :         FieldsFromXPath
     249             :     } ResolutionMode;
     250             : 
     251             :     int m_nTimeOut = 0;
     252             : 
     253             :     int m_nMaxFileSize = MAX_FILE_SIZE_DEFAULT;
     254             : 
     255             :     int m_nMaxGlobalResolutionTime = 0;
     256             : 
     257             :     CPLString m_osProxyServerPort{};
     258             : 
     259             :     CPLString m_osProxyUserPassword{};
     260             : 
     261             :     CPLString m_osProxyAuth{};
     262             : 
     263             :     CPLString m_osCacheDirectory{};
     264             : 
     265             :     bool m_bDefaultResolutionEnabled = DEFAULT_RESOLUTION_ENABLED_DEFAULT;
     266             : 
     267             :     bool m_bDefaultAllowRemoteDownload = ALLOW_REMOTE_DOWNLOAD_DEFAULT;
     268             : 
     269             :     ResolutionMode m_eDefaultResolutionMode = RawContent;
     270             : 
     271             :     int m_nDefaultResolutionDepth = 1;
     272             : 
     273             :     bool m_bDefaultCacheResults = CACHE_RESULTS_DEFAULT;
     274             : 
     275             :     bool m_bResolveInternalXLinks = INTERNAL_XLINK_RESOLUTION_DEFAULT;
     276             : 
     277             :     struct URLSpecificResolution
     278             :     {
     279             :         CPLString m_osURLPrefix{};
     280             : 
     281             :         std::vector<std::pair<CPLString, CPLString>>
     282             :             m_aosNameValueHTTPHeaders{};
     283             : 
     284             :         bool m_bAllowRemoteDownload = false;
     285             : 
     286             :         ResolutionMode m_eResolutionMode = RawContent;
     287             : 
     288             :         int m_nResolutionDepth = 1;
     289             : 
     290             :         bool m_bCacheResults = false;
     291             : 
     292             :         struct XPathDerivedField
     293             :         {
     294             :             CPLString m_osName{};
     295             : 
     296             :             CPLString m_osType{};
     297             : 
     298             :             CPLString m_osXPath{};
     299             :         };
     300             : 
     301             :         std::vector<XPathDerivedField> m_aoFields{};
     302             :     };
     303             : 
     304             :     std::vector<URLSpecificResolution> m_aoURLSpecificRules{};
     305             : 
     306             :     GMLASXLinkResolutionConf() = default;
     307             : 
     308             :     bool LoadFromXML(CPLXMLNode *psRoot);
     309             : };
     310             : 
     311             : /************************************************************************/
     312             : /*                          GMLASConfiguration                          */
     313             : /************************************************************************/
     314             : 
     315             : class GMLASConfiguration
     316             : {
     317             :   public:
     318             :     /** Whether remote schemas are allowed to be download. */
     319             :     bool m_bAllowRemoteSchemaDownload = ALLOW_REMOTE_SCHEMA_DOWNLOAD_DEFAULT;
     320             : 
     321             :     /** Whether a ogr_pkid attribute should always be generated. */
     322             :     bool m_bAlwaysGenerateOGRId = ALWAYS_GENERATE_OGR_ID_DEFAULT;
     323             : 
     324             :     /** Whether to remove layers found to be unused in initial scan pass */
     325             :     bool m_bRemoveUnusedLayers = REMOVE_UNUSED_LAYERS_DEFAULT;
     326             : 
     327             :     /** Whether to remove fields found to be unused in initial scan pass */
     328             :     bool m_bRemoveUnusedFields = REMOVE_UNUSED_FIELDS_DEFAULT;
     329             : 
     330             :     /** Whether repeated strings, integers, reals should be in corresponding
     331             :         OGR array types. */
     332             :     bool m_bUseArrays = USE_ARRAYS_DEFAULT;
     333             : 
     334             :     /** Whether OGR field null state should be used. */
     335             :     bool m_bUseNullState = USE_NULL_STATE_DEFAULT;
     336             : 
     337             :     /** Whether geometries should be stored as XML in a OGR string field. */
     338             :     bool m_bIncludeGeometryXML = INCLUDE_GEOMETRY_XML_DEFAULT;
     339             : 
     340             :     /** Whether, when dealing with schemas that import the
     341             :         GML namespace, and that at least one of them has
     342             :         elements that derive from gml:_Feature or
     343             :         gml:AbstractFeatureonly, only such elements should be
     344             :         instantiated as OGR layers, during the first pass that
     345             :         iterates over top level elements of the imported
     346             :         schemas. */
     347             :     bool m_bInstantiateGMLFeaturesOnly = INSTANTIATE_GML_FEATURES_ONLY_DEFAULT;
     348             : 
     349             :     /** Maximum length of layer and field identifiers*/
     350             :     int m_nIdentifierMaxLength = 0;
     351             : 
     352             :     /** Whether case insensitive comparison should be used for identifier
     353             :      * equality testing */
     354             :     bool m_bCaseInsensitiveIdentifier = CASE_INSENSITIVE_IDENTIFIER_DEFAULT;
     355             : 
     356             :     /** Whether to launder identifiers like postgresql does */
     357             :     bool m_bPGIdentifierLaundering = PG_IDENTIFIER_LAUNDERING_DEFAULT;
     358             : 
     359             :     /* Maximum number of fields in an element considered for flattening. */
     360             :     int m_nMaximumFieldsForFlattening = MAXIMUM_FIELDS_FLATTENING_DEFAULT;
     361             : 
     362             :     /** Whether remote XSD schemas should be locally cached. */
     363             :     bool m_bAllowXSDCache = ALLOW_XSD_CACHE_DEFAULT;
     364             : 
     365             :     /** Cache directory for cached XSD schemas. */
     366             :     CPLString m_osXSDCacheDirectory{};
     367             : 
     368             :     /** Whether to enable schema full checking. */
     369             :     bool m_bSchemaFullChecking = SCHEMA_FULL_CHECKING_DEFAULT;
     370             : 
     371             :     /** Whether to allow multiple imports of the same namespace. */
     372             :     bool m_bHandleMultipleImports = HANDLE_MULTIPLE_IMPORTS_DEFAULT;
     373             : 
     374             :     /** Whether validation of document against schema should be done.  */
     375             :     bool m_bValidate = VALIDATE_DEFAULT;
     376             : 
     377             :     /** Whether a validation error should prevent dataset opening.  */
     378             :     bool m_bFailIfValidationError = FAIL_IF_VALIDATION_ERROR_DEFAULT;
     379             : 
     380             :     /** Whether technical layers should be exposed.  */
     381             :     bool m_bExposeMetadataLayers = WARN_IF_EXCLUDED_XPATH_FOUND_DEFAULT;
     382             : 
     383             :     /** For flatening rules, map prefix namespace to its URI */
     384             :     std::map<CPLString, CPLString> m_oMapPrefixToURIFlatteningRules{};
     385             : 
     386             :     std::vector<CPLString> m_osForcedFlattenedXPath{};
     387             : 
     388             :     std::vector<CPLString> m_osDisabledFlattenedXPath{};
     389             : 
     390             :     enum SWEActivationMode
     391             :     {
     392             :         SWE_ACTIVATE_IF_NAMESPACE_FOUND,
     393             :         SWE_ACTIVATE_TRUE,
     394             :         SWE_ACTIVATE_FALSE
     395             :     };
     396             : 
     397             :     /** If and when activate SWE special processings */
     398             :     SWEActivationMode m_eSWEActivationMode = SWE_ACTIVATE_IF_NAMESPACE_FOUND;
     399             : 
     400             :     /** If enabling swe:DataRecord parsing */
     401             :     bool m_bSWEProcessDataRecord = SWE_PROCESS_DATA_RECORD_DEFAULT;
     402             : 
     403             :     /** If enabling swe:DataArray parsing */
     404             :     bool m_bSWEProcessDataArray = SWE_PROCESS_DATA_ARRAY_DEFAULT;
     405             : 
     406             :     /** For ignored xpaths, map prefix namespace to its URI */
     407             :     std::map<CPLString, CPLString> m_oMapPrefixToURIIgnoredXPaths{};
     408             : 
     409             :     /** Ignored xpaths */
     410             :     std::vector<CPLString> m_aosIgnoredXPaths{};
     411             : 
     412             :     /** For type constraints, map prefix namespace to its URI */
     413             :     std::map<CPLString, CPLString> m_oMapPrefixToURITypeConstraints{};
     414             : 
     415             :     /** Map an XPath to a list of potential types for its children */
     416             :     std::map<CPLString, std::vector<CPLString>>
     417             :         m_oMapChildrenElementsConstraints{};
     418             : 
     419             :     /* Beginning of Writer config */
     420             : 
     421             :     /** Number of spaces for indentation */
     422             :     int m_nIndentSize = INDENT_SIZE_DEFAULT;
     423             : 
     424             :     CPLString m_osComment{};
     425             : 
     426             :     /** End of line format: "CRLF" or "LR" */
     427             :     CPLString m_osLineFormat{};
     428             : 
     429             :     /** "SHORT", "OGC_URN" or "OGC_URL" */
     430             :     CPLString m_osSRSNameFormat = szSRSNAME_DEFAULT;
     431             : 
     432             :     /** "WFS2_FEATURECOLLECTION" or "GMLAS_FEATURECOLLECTION" */
     433             :     CPLString m_osWrapping = szWFS2_FEATURECOLLECTION;
     434             : 
     435             :     /** XML datetime or empty for current time */
     436             :     CPLString m_osTimestamp{};
     437             : 
     438             :     /** Path or URL to OGC WFS 2.0 schema. */
     439             :     CPLString m_osWFS20SchemaLocation = szWFS20_SCHEMALOCATION;
     440             : 
     441             :     /* End of Writer config */
     442             : 
     443             :     /** Whether a warning should be emitted when an element or attribute is
     444             :         found in the document parsed, but ignored because of the ignored
     445             :         XPath defined.  */
     446             :     std::map<CPLString, bool> m_oMapIgnoredXPathToWarn{};
     447             : 
     448             :     GMLASXLinkResolutionConf m_oXLinkResolution{};
     449             : 
     450             :     GMLASConfiguration() = default;
     451             : 
     452             :     bool Load(const char *pszFilename);
     453             :     void Finalize();
     454             : 
     455             :     static std::string GetDefaultConfFile(bool &bUnlinkAfterUse);
     456             : };
     457             : 
     458             : /************************************************************************/
     459             : /*                          GMLASXLinkResolver                          */
     460             : /************************************************************************/
     461             : 
     462             : class GMLASXLinkResolver final : public GMLASResourceCache
     463             : {
     464             :     GMLASXLinkResolutionConf m_oConf{};
     465             :     int m_nGlobalResolutionTime = 0;
     466             : 
     467             :     std::map<CPLString, CPLString> m_oMapURLToContent{};
     468             :     std::map<size_t, std::vector<CPLString>> m_oMapFileSizeToURLs{};
     469             :     size_t m_nMaxRAMCacheSize = 0;
     470             :     size_t m_nCurrentRAMCacheSize = 0;
     471             : 
     472             :     CPLString FetchRawContent(const CPLString &osURL, const char *pszHeaders);
     473             : 
     474             :     CPLString GetRawContent(const CPLString &osURL, const char *pszHeaders,
     475             :                             bool bAllowRemoteDownload, bool bCacheResults);
     476             : 
     477             :   public:
     478             :     GMLASXLinkResolver();
     479             : 
     480             :     void SetConf(const GMLASXLinkResolutionConf &oConf);
     481             : 
     482       19559 :     const GMLASXLinkResolutionConf &GetConf() const
     483             :     {
     484       19559 :         return m_oConf;
     485             :     }
     486             : 
     487             :     bool IsRawContentResolutionEnabled() const;
     488             :     int GetMatchingResolutionRule(const CPLString &osURL) const;
     489             :     CPLString GetRawContent(const CPLString &osURL);
     490             :     CPLString GetRawContentForRule(const CPLString &osURL, int nIdxRule);
     491             : };
     492             : 
     493             : /************************************************************************/
     494             : /*                           GMLASXPathMatcher                          */
     495             : /************************************************************************/
     496             : 
     497             : /** Object to compares a user provided XPath against a set of test XPaths */
     498             : class GMLASXPathMatcher
     499             : {
     500             :     struct XPathComponent
     501             :     {
     502             :         CPLString m_osValue{};
     503             :         bool m_bDirectChild = false;
     504             :     };
     505             : 
     506             :     /** For reference xpaths, map prefix namespace to its URI */
     507             :     std::map<CPLString, CPLString> m_oMapPrefixToURIReferenceXPaths{};
     508             : 
     509             :     /** Reference xpaths */
     510             :     std::vector<CPLString> m_aosReferenceXPathsUncompiled{};
     511             : 
     512             :     /** Reference xpaths "compiled" */
     513             :     std::vector<std::vector<XPathComponent>> m_aosReferenceXPaths{};
     514             : 
     515             :     static bool MatchesRefXPath(const CPLString &osXPath,
     516             :                                 const std::vector<XPathComponent> &oRefXPath);
     517             : 
     518             :   public:
     519             :     void SetRefXPaths(
     520             :         const std::map<CPLString, CPLString> &oMapPrefixToURIReferenceXPaths,
     521             :         const std::vector<CPLString> &aosReferenceXPaths);
     522             : 
     523             :     void SetDocumentMapURIToPrefix(
     524             :         const std::map<CPLString, CPLString> &oMapURIToPrefix);
     525             : 
     526             :     /** Return true if osXPath matches one of the XPath of
     527             :         m_aosReferenceXPaths */
     528             :     bool MatchesRefXPath(const CPLString &osXPath,
     529             :                          CPLString &osOutMatchedXPath) const;
     530             : 
     531           6 :     const std::map<CPLString, CPLString> &GetMapPrefixToURI() const
     532             :     {
     533           6 :         return m_oMapPrefixToURIReferenceXPaths;
     534             :     }
     535             : };
     536             : 
     537             : /************************************************************************/
     538             : /*                            GMLASFieldType                            */
     539             : /************************************************************************/
     540             : 
     541             : /** Enumeration for XML primitive types */
     542             : typedef enum
     543             : {
     544             :     GMLAS_FT_STRING,
     545             :     GMLAS_FT_ID,
     546             :     GMLAS_FT_BOOLEAN,
     547             :     GMLAS_FT_SHORT,
     548             :     GMLAS_FT_INT32,
     549             :     GMLAS_FT_INT64,
     550             :     GMLAS_FT_FLOAT,
     551             :     GMLAS_FT_DOUBLE,
     552             :     GMLAS_FT_DECIMAL,
     553             :     GMLAS_FT_DATE,
     554             :     GMLAS_FT_GYEAR,
     555             :     GMLAS_FT_GYEAR_MONTH,
     556             :     GMLAS_FT_TIME,
     557             :     GMLAS_FT_DATETIME,
     558             :     GMLAS_FT_BASE64BINARY,
     559             :     GMLAS_FT_HEXBINARY,
     560             :     GMLAS_FT_ANYURI,
     561             :     GMLAS_FT_ANYTYPE,
     562             :     GMLAS_FT_ANYSIMPLETYPE,
     563             :     GMLAS_FT_GEOMETRY,  // this one isn't a XML primitive type.
     564             : } GMLASFieldType;
     565             : 
     566             : /************************************************************************/
     567             : /*                              GMLASField                              */
     568             : /************************************************************************/
     569             : 
     570             : class GMLASField
     571             : {
     572             :   public:
     573             :     typedef enum
     574             :     {
     575             :         /** Field that is going to be instantiated as a OGR field */
     576             :         REGULAR,
     577             : 
     578             :         /** Non-instanciable field. The corresponding element to the XPath
     579             :             is stored in a child layer that will reference back to the
     580             :             main layer. */
     581             :         PATH_TO_CHILD_ELEMENT_NO_LINK,
     582             : 
     583             :         /** Field that will store the PKID of a child element */
     584             :         PATH_TO_CHILD_ELEMENT_WITH_LINK,
     585             : 
     586             :         /** Non-instanciable field. The corresponding element to the XPath
     587             :             is stored in a child layer. And the link between both will be
     588             :             done through a junction table. */
     589             :         PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE,
     590             : 
     591             :         /** Non-instanciable field. Corresponds to a group of an element. */
     592             :         GROUP
     593             :     } Category;
     594             : 
     595             :   private:
     596             :     CPLString m_osName{};                     /**< Field name */
     597             :     GMLASFieldType m_eType = GMLAS_FT_STRING; /**< Field type */
     598             :     OGRwkbGeometryType m_eGeomType = wkbNone; /**< Field geometry type */
     599             :     CPLString m_osTypeName{};                 /**< Original XSD type */
     600             :     int m_nWidth = 0;                         /**< Field width */
     601             :     bool m_bNotNullable = false; /**< If the field is not nullable */
     602             : 
     603             :     /** If the field is an array (from OGR types point of view) */
     604             :     bool m_bArray = false;
     605             :     bool m_bList = false; /**< If the field is a list (a xs:list) */
     606             : 
     607             :     /** Category of the field. */
     608             :     Category m_eCategory = REGULAR;
     609             : 
     610             :     /** XPath of the field. */
     611             :     CPLString m_osXPath{};
     612             : 
     613             :     /** Set of XPath that are linked to this field.
     614             :         This is used for cases where a gml:AbstractGeometry element is
     615             :         referenced. In which case all possible realizations of this
     616             :         element are listed. Will be used with eType == GMLAS_FT_ANYTYPE
     617             :         to store XML blob on parsing. */
     618             :     std::vector<CPLString> m_aosXPath{};
     619             : 
     620             :     CPLString m_osFixedValue{};   /**< Value of fixed='' attribute */
     621             :     CPLString m_osDefaultValue{}; /**< Value of default='' attribute */
     622             : 
     623             :     /** Minimum number of occurrences. Might be -1 if unset */
     624             :     int m_nMinOccurs = -1;
     625             : 
     626             :     /** Maximum number of occurrences, or MAXOCCURS_UNLIMITED. Might be
     627             :         -1 if unset. */
     628             :     int m_nMaxOccurs = -1;
     629             : 
     630             :     /** For a PATH_TO_CHILD_ELEMENT_NO_LINK, whether maxOccurs>1 is on the
     631             :         sequence rather than on the element */
     632             :     bool m_bRepetitionOnSequence = false;
     633             : 
     634             :     /** In case of m_eType == GMLAS_FT_ANYTYPE whether the current element
     635             :         must be stored in the XML blob (if false, only its children) */
     636             :     bool m_bIncludeThisEltInBlob = false;
     637             : 
     638             :     /** Only used for PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE. The XPath
     639             :         of the abstract element (the concrete XPath is in m_osXPath).
     640             :         e.g myns:mainElt/myns:subEltAbstract whereas the concrete XPath
     641             :         is myns:mainElt/myns:subEltRealization */
     642             :     CPLString m_osAbstractElementXPath{};
     643             : 
     644             :     /** Only used for PATH_TO_CHILD_ELEMENT_WITH_LINK and
     645             :         PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE (and also for
     646             :         PATH_TO_CHILD_ELEMENT_NO_LINK and GROUP but for metadata layers only).
     647             :         The XPath of the child element. */
     648             :     CPLString m_osRelatedClassXPath{};
     649             : 
     650             :     /** Only use for PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE. Name of
     651             :         the junction layer to consult for this field. Only used by
     652             :         writer code. */
     653             :     CPLString m_osJunctionLayer{};
     654             : 
     655             :     /** Dirty hack to register attributes with fixed values, despite being
     656             :         in the XPath ignored list. Needed to avoid warning when doing validation
     657             :      */
     658             :     bool m_bIgnored = false;
     659             : 
     660             :     /** Documentation from schema */
     661             :     CPLString m_osDoc{};
     662             : 
     663             :     /** For elements within xs:choice */
     664             :     bool m_bMayAppearOutOfOrder = false;
     665             : 
     666             :   public:
     667      231519 :     GMLASField() = default;
     668             : 
     669      819392 :     void SetName(const CPLString &osName)
     670             :     {
     671      819392 :         m_osName = osName;
     672      819392 :     }
     673             : 
     674             :     void SetType(GMLASFieldType eType, const char *pszTypeName);
     675             : 
     676         739 :     void SetGeomType(OGRwkbGeometryType eGeomType)
     677             :     {
     678         739 :         m_eGeomType = eGeomType;
     679         739 :     }
     680             : 
     681      200972 :     void SetWidth(int nWidth)
     682             :     {
     683      200972 :         m_nWidth = nWidth;
     684      200972 :     }
     685             : 
     686      174697 :     void SetNotNullable(bool bNotNullable)
     687             :     {
     688      174697 :         m_bNotNullable = bNotNullable;
     689      174697 :     }
     690             : 
     691        4250 :     void SetArray(bool bArray)
     692             :     {
     693        4250 :         m_bArray = bArray;
     694        4250 :     }
     695             : 
     696        2504 :     void SetList(bool bList)
     697             :     {
     698        2504 :         m_bList = bList;
     699        2504 :     }
     700             : 
     701      230717 :     void SetXPath(const CPLString &osXPath)
     702             :     {
     703      230717 :         m_osXPath = osXPath;
     704      230717 :     }
     705             : 
     706        1780 :     void AddAlternateXPath(const CPLString &osXPath)
     707             :     {
     708        1780 :         m_aosXPath.push_back(osXPath);
     709        1780 :     }
     710             : 
     711        1105 :     void SetFixedValue(const CPLString &osFixedValue)
     712             :     {
     713        1105 :         m_osFixedValue = osFixedValue;
     714        1105 :     }
     715             : 
     716         922 :     void SetDefaultValue(const CPLString &osDefaultValue)
     717             :     {
     718         922 :         m_osDefaultValue = osDefaultValue;
     719         922 :     }
     720             : 
     721       29712 :     void SetCategory(Category eCategory)
     722             :     {
     723       29712 :         m_eCategory = eCategory;
     724       29712 :     }
     725             : 
     726      336809 :     void SetMinOccurs(int nMinOccurs)
     727             :     {
     728      336809 :         m_nMinOccurs = nMinOccurs;
     729      336809 :     }
     730             : 
     731      230593 :     void SetMaxOccurs(int nMaxOccurs)
     732             :     {
     733      230593 :         m_nMaxOccurs = nMaxOccurs;
     734      230593 :     }
     735             : 
     736         818 :     void SetRepetitionOnSequence(bool b)
     737             :     {
     738         818 :         m_bRepetitionOnSequence = b;
     739         818 :     }
     740             : 
     741         321 :     void SetIncludeThisEltInBlob(bool b)
     742             :     {
     743         321 :         m_bIncludeThisEltInBlob = b;
     744         321 :     }
     745             : 
     746        9857 :     void SetAbstractElementXPath(const CPLString &osName)
     747             :     {
     748        9857 :         m_osAbstractElementXPath = osName;
     749        9857 :     }
     750             : 
     751       29144 :     void SetRelatedClassXPath(const CPLString &osName)
     752             :     {
     753       29144 :         m_osRelatedClassXPath = osName;
     754       29144 :     }
     755             : 
     756          16 :     void SetJunctionLayer(const CPLString &osName)
     757             :     {
     758          16 :         m_osJunctionLayer = osName;
     759          16 :     }
     760             : 
     761         451 :     void SetIgnored()
     762             :     {
     763         451 :         m_bIgnored = true;
     764         451 :     }
     765             : 
     766      200833 :     void SetDocumentation(const CPLString &osDoc)
     767             :     {
     768      200833 :         m_osDoc = osDoc;
     769      200833 :     }
     770             : 
     771      149490 :     void SetMayAppearOutOfOrder(bool b)
     772             :     {
     773      149490 :         m_bMayAppearOutOfOrder = b;
     774      149490 :     }
     775             : 
     776             :     static CPLString
     777          22 :     MakePKIDFieldXPathFromXLinkHrefXPath(const CPLString &osBaseXPath)
     778             :     {
     779          44 :         return "{" + osBaseXPath + "}_pkid";
     780             :     }
     781             : 
     782          25 :     static CPLString MakeXLinkRawContentFieldXPathFromXLinkHrefXPath(
     783             :         const CPLString &osBaseXPath)
     784             :     {
     785          50 :         return "{" + osBaseXPath + "}_rawcontent";
     786             :     }
     787             : 
     788             :     static CPLString
     789          40 :     MakeXLinkDerivedFieldXPathFromXLinkHrefXPath(const CPLString &osBaseXPath,
     790             :                                                  const CPLString &osName)
     791             :     {
     792          80 :         return "{" + osBaseXPath + "}_derived_" + osName;
     793             :     }
     794             : 
     795     1767320 :     const CPLString &GetName() const
     796             :     {
     797     1767320 :         return m_osName;
     798             :     }
     799             : 
     800     6560560 :     const CPLString &GetXPath() const
     801             :     {
     802     6560560 :         return m_osXPath;
     803             :     }
     804             : 
     805      200459 :     const std::vector<CPLString> &GetAlternateXPaths() const
     806             :     {
     807      200459 :         return m_aosXPath;
     808             :     }
     809             : 
     810      694478 :     GMLASFieldType GetType() const
     811             :     {
     812      694478 :         return m_eType;
     813             :     }
     814             : 
     815         737 :     OGRwkbGeometryType GetGeomType() const
     816             :     {
     817         737 :         return m_eGeomType;
     818             :     }
     819             : 
     820      386333 :     const CPLString &GetTypeName() const
     821             :     {
     822      386333 :         return m_osTypeName;
     823             :     }
     824             : 
     825      183842 :     int GetWidth() const
     826             :     {
     827      183842 :         return m_nWidth;
     828             :     }
     829             : 
     830      235352 :     bool IsNotNullable() const
     831             :     {
     832      235352 :         return m_bNotNullable;
     833             :     }
     834             : 
     835      351012 :     bool IsArray() const
     836             :     {
     837      351012 :         return m_bArray;
     838             :     }
     839             : 
     840      235266 :     bool IsList() const
     841             :     {
     842      235266 :         return m_bList;
     843             :     }
     844             : 
     845     2013780 :     const CPLString &GetFixedValue() const
     846             :     {
     847     2013780 :         return m_osFixedValue;
     848             :     }
     849             : 
     850     1869310 :     const CPLString &GetDefaultValue() const
     851             :     {
     852     1869310 :         return m_osDefaultValue;
     853             :     }
     854             : 
     855     2400050 :     Category GetCategory() const
     856             :     {
     857     2400050 :         return m_eCategory;
     858             :     }
     859             : 
     860      400830 :     int GetMinOccurs() const
     861             :     {
     862      400830 :         return m_nMinOccurs;
     863             :     }
     864             : 
     865      955178 :     int GetMaxOccurs() const
     866             :     {
     867      955178 :         return m_nMaxOccurs;
     868             :     }
     869             : 
     870       15895 :     bool GetRepetitionOnSequence() const
     871             :     {
     872       15895 :         return m_bRepetitionOnSequence;
     873             :     }
     874             : 
     875        5788 :     bool GetIncludeThisEltInBlob() const
     876             :     {
     877        5788 :         return m_bIncludeThisEltInBlob;
     878             :     }
     879             : 
     880       14423 :     const CPLString &GetAbstractElementXPath() const
     881             :     {
     882       14423 :         return m_osAbstractElementXPath;
     883             :     }
     884             : 
     885          24 :     const CPLString &GetJunctionLayer() const
     886             :     {
     887          24 :         return m_osJunctionLayer;
     888             :     }
     889             : 
     890      250502 :     const CPLString &GetRelatedClassXPath() const
     891             :     {
     892      250502 :         return m_osRelatedClassXPath;
     893             :     }
     894             : 
     895      199977 :     bool IsIgnored() const
     896             :     {
     897      199977 :         return m_bIgnored;
     898             :     }
     899             : 
     900      342899 :     const CPLString &GetDocumentation() const
     901             :     {
     902      342899 :         return m_osDoc;
     903             :     }
     904             : 
     905           4 :     bool MayAppearOutOfOrder() const
     906             :     {
     907           4 :         return m_bMayAppearOutOfOrder;
     908             :     }
     909             : 
     910             :     static GMLASFieldType GetTypeFromString(const CPLString &osType);
     911             : };
     912             : 
     913             : /************************************************************************/
     914             : /*                            GMLASFeatureClass                         */
     915             : /************************************************************************/
     916             : 
     917             : class GMLASFeatureClass
     918             : {
     919             :     /** User facing name */
     920             :     CPLString m_osName{};
     921             : 
     922             :     /** XPath to the main element of the feature class */
     923             :     CPLString m_osXPath{};
     924             : 
     925             :     /** List of fields */
     926             :     std::vector<GMLASField> m_aoFields{};
     927             : 
     928             :     /** Child nested classes */
     929             :     std::vector<GMLASFeatureClass> m_aoNestedClasses{};
     930             : 
     931             :     /** Whether this layer corresponds to a (multiple instantiated) xs:group
     932             :         or a repeated sequence */
     933             :     bool m_bIsRepeatedSequence = false;
     934             : 
     935             :     /** Whether this is a repeated group. Should be set together with
     936             :      * m_bIsRepeatedSequence */
     937             :     bool m_bIsGroup = false;
     938             : 
     939             :     /** Only used for junction tables. The XPath to the parent table */
     940             :     CPLString m_osParentXPath{};
     941             : 
     942             :     /** Only used for junction tables. The XPath to the child table */
     943             :     CPLString m_osChildXPath{};
     944             : 
     945             :     /** Whether this corresponds to a top-level XSD element in the schema */
     946             :     bool m_bIsTopLevelElt = false;
     947             : 
     948             :     /** Documentation from schema */
     949             :     CPLString m_osDoc{};
     950             : 
     951             :   public:
     952       44357 :     GMLASFeatureClass() = default;
     953             : 
     954             :     void SetName(const CPLString &osName);
     955             :     void SetXPath(const CPLString &osXPath);
     956             :     void AddField(const GMLASField &oField);
     957             :     void PrependFields(const std::vector<GMLASField> &aoFields);
     958             :     void AppendFields(const std::vector<GMLASField> &aoFields);
     959             :     void AddNestedClass(const GMLASFeatureClass &oNestedClass);
     960             : 
     961        4292 :     void SetIsRepeatedSequence(bool bIsRepeatedSequence)
     962             :     {
     963        4292 :         m_bIsRepeatedSequence = bIsRepeatedSequence;
     964        4292 :     }
     965             : 
     966         215 :     void SetIsGroup(bool bIsGroup)
     967             :     {
     968         215 :         m_bIsGroup = bIsGroup;
     969         215 :     }
     970             : 
     971        9857 :     void SetParentXPath(const CPLString &osXPath)
     972             :     {
     973        9857 :         m_osParentXPath = osXPath;
     974        9857 :     }
     975             : 
     976        9857 :     void SetChildXPath(const CPLString &osXPath)
     977             :     {
     978        9857 :         m_osChildXPath = osXPath;
     979        9857 :     }
     980             : 
     981        3322 :     void SetIsTopLevelElt(bool bIsTopLevelElt)
     982             :     {
     983        3322 :         m_bIsTopLevelElt = bIsTopLevelElt;
     984        3322 :     }
     985             : 
     986       31356 :     void SetDocumentation(const CPLString &osDoc)
     987             :     {
     988       31356 :         m_osDoc = osDoc;
     989       31356 :     }
     990             : 
     991       94154 :     const CPLString &GetName() const
     992             :     {
     993       94154 :         return m_osName;
     994             :     }
     995             : 
     996     7903870 :     const CPLString &GetXPath() const
     997             :     {
     998     7903870 :         return m_osXPath;
     999             :     }
    1000             : 
    1001      327878 :     const std::vector<GMLASField> &GetFields() const
    1002             :     {
    1003      327878 :         return m_aoFields;
    1004             :     }
    1005             : 
    1006       66385 :     std::vector<GMLASField> &GetFields()
    1007             :     {
    1008       66385 :         return m_aoFields;
    1009             :     }
    1010             : 
    1011       16958 :     const std::vector<GMLASFeatureClass> &GetNestedClasses() const
    1012             :     {
    1013       16958 :         return m_aoNestedClasses;
    1014             :     }
    1015             : 
    1016       50727 :     std::vector<GMLASFeatureClass> &GetNestedClasses()
    1017             :     {
    1018       50727 :         return m_aoNestedClasses;
    1019             :     }
    1020             : 
    1021      189133 :     bool IsRepeatedSequence() const
    1022             :     {
    1023      189133 :         return m_bIsRepeatedSequence;
    1024             :     }
    1025             : 
    1026       64261 :     bool IsGroup() const
    1027             :     {
    1028       64261 :         return m_bIsGroup;
    1029             :     }
    1030             : 
    1031       77230 :     const CPLString &GetParentXPath() const
    1032             :     {
    1033       77230 :         return m_osParentXPath;
    1034             :     }
    1035             : 
    1036             :     const CPLString &GetChildXPath() const
    1037             :     {
    1038             :         return m_osChildXPath;
    1039             :     }
    1040             : 
    1041        7101 :     bool IsTopLevelElt() const
    1042             :     {
    1043        7101 :         return m_bIsTopLevelElt;
    1044             :     }
    1045             : 
    1046       12844 :     const CPLString &GetDocumentation() const
    1047             :     {
    1048       12844 :         return m_osDoc;
    1049             :     }
    1050             : };
    1051             : 
    1052             : /************************************************************************/
    1053             : /*                         GMLASSchemaAnalyzer                          */
    1054             : /************************************************************************/
    1055             : 
    1056             : class GMLASSchemaAnalyzer
    1057             : {
    1058             :     GMLASXPathMatcher &m_oIgnoredXPathMatcher;
    1059             : 
    1060             :     GMLASXPathMatcher &m_oChildrenElementsConstraintsXPathMatcher;
    1061             : 
    1062             :     GMLASXPathMatcher &m_oForcedFlattenedXPathMatcher;
    1063             : 
    1064             :     GMLASXPathMatcher &m_oDisabledFlattenedXPathMatcher;
    1065             : 
    1066             :     std::map<CPLString, std::vector<CPLString>>
    1067             :         m_oMapChildrenElementsConstraints{};
    1068             : 
    1069             :     /** Whether repeated strings, integers, reals should be in corresponding
    1070             :         OGR array types. */
    1071             :     bool m_bUseArrays = true;
    1072             : 
    1073             :     /** Whether OGR field null state should be used. */
    1074             :     bool m_bUseNullState = false;
    1075             : 
    1076             :     /** Whether, when dealing with schemas that import the
    1077             :         GML namespace, and that at least one of them has
    1078             :         elements that derive from gml:_Feature or
    1079             :         gml:AbstractFeatureonly, only such elements should be
    1080             :         instantiated as OGR layers, during the first pass that
    1081             :         iterates over top level elements of the imported
    1082             :         schemas. */
    1083             :     bool m_bInstantiateGMLFeaturesOnly = true;
    1084             : 
    1085             :     /** Vector of feature classes */
    1086             :     std::vector<GMLASFeatureClass> m_aoClasses{};
    1087             : 
    1088             :     /** Map from a namespace URI to the corresponding prefix */
    1089             :     std::map<CPLString, CPLString> m_oMapURIToPrefix{};
    1090             : 
    1091             :     /** Map element XPath to its XSElementDeclaration* */
    1092             :     std::map<CPLString, XSElementDeclaration *> m_oMapXPathToEltDecl{};
    1093             : 
    1094             :     typedef std::map<XSElementDeclaration *,
    1095             :                      std::vector<XSElementDeclaration *>>
    1096             :         tMapParentEltToChildElt;
    1097             :     /** Map from a base/parent element to a vector of derived/children
    1098             :         elements that are substitutionGroup of it. The map only
    1099             :         addresses the direct derived types, and not the 2nd level or more
    1100             :         derived ones. For that recursion in the map must be used.*/
    1101             :     tMapParentEltToChildElt m_oMapParentEltToChildElt{};
    1102             : 
    1103             :     /** Map from a XSModelGroup* object to the name of its group definition. */
    1104             :     std::map<XSModelGroup *, XSModelGroupDefinition *> m_oMapModelGroupToMGD{};
    1105             : 
    1106             :     /** Map from (non namespace prefixed) element names to the number of
    1107             :         elements that share the same namespace (in different namespaces) */
    1108             :     std::map<CPLString, int> m_oMapEltNamesToInstanceCount{};
    1109             : 
    1110             :     /** Set of elements that match a OGR layer */
    1111             :     std::set<XSElementDeclaration *> m_oSetEltsForTopClass{};
    1112             : 
    1113             :     /** Set of elements that are simple enough to be inlined whenever they
    1114             :         are referenced with cardinality 1. The use case if base:identifier
    1115             :         used by Inspire schemas. */
    1116             :     std::set<XSElementDeclaration *> m_oSetSimpleEnoughElts{};
    1117             : 
    1118             :     /** Maximum length of layer and field identifiers*/
    1119             :     int m_nIdentifierMaxLength = 0;
    1120             : 
    1121             :     /** Whether case insensitive comparison should be used for identifier
    1122             :      * equality testing */
    1123             :     bool m_bCaseInsensitiveIdentifier = CASE_INSENSITIVE_IDENTIFIER_DEFAULT;
    1124             : 
    1125             :     /** Whether to launder identifiers like postgresql does */
    1126             :     bool m_bPGIdentifierLaundering = PG_IDENTIFIER_LAUNDERING_DEFAULT;
    1127             : 
    1128             :     /* Maximum number of fields in an element considered for flattening. */
    1129             :     int m_nMaximumFieldsForFlattening = MAXIMUM_FIELDS_FLATTENING_DEFAULT;
    1130             : 
    1131             :     /** GML version found: 2.1.1, 3.1.1 or 3.2.1 or empty*/
    1132             :     CPLString m_osGMLVersionFound{};
    1133             : 
    1134             :     /** Set of schemas opened */
    1135             :     std::set<CPLString> m_oSetSchemaURLs{};
    1136             : 
    1137             :     /** Map from namespace URI to namespace prefix coming from the
    1138             :      * examination of xmlns:foo=bar attributes of the top element of the
    1139             :      * GML document */
    1140             :     std::map<CPLString, CPLString> m_oMapDocNSURIToPrefix{};
    1141             : 
    1142             :     bool m_bAlwaysGenerateOGRId = ALWAYS_GENERATE_OGR_ID_DEFAULT;
    1143             : 
    1144             :     static bool IsSame(const XSModelGroup *poModelGroup1,
    1145             :                        const XSModelGroup *poModelGroup2);
    1146             :     XSModelGroupDefinition *
    1147             :     GetGroupDefinition(const XSModelGroup *poModelGroup);
    1148             :     bool SetFieldFromAttribute(GMLASField &oField, XSAttributeUse *poAttr,
    1149             :                                const CPLString &osXPathPrefix,
    1150             :                                const CPLString &osNamePrefix = CPLString());
    1151             :     void GetConcreteImplementationTypes(
    1152             :         XSElementDeclaration *poParentElt,
    1153             :         std::vector<XSElementDeclaration *> &apoImplEltList);
    1154             :     std::vector<XSElementDeclaration *>
    1155             :     GetConstraintChildrenElements(const CPLString &osFullXPath);
    1156             :     bool FindElementsWithMustBeToLevel(
    1157             :         const CPLString &osParentXPath, XSModelGroup *poModelGroup,
    1158             :         int nRecursionCounter,
    1159             :         std::set<XSElementDeclaration *> &oSetVisitedEltDecl,
    1160             :         std::set<XSModelGroup *> &oSetVisitedModelGroups,
    1161             :         std::vector<XSElementDeclaration *> &oVectorEltsForTopClass,
    1162             :         std::set<CPLString> &aoSetXPathEltsForTopClass, XSModel *poModel,
    1163             :         bool &bSimpleEnoughOut, int &nCountSubEltsOut);
    1164             :     static void BuildMapCountOccurrencesOfSameName(
    1165             :         XSModelGroup *poModelGroup,
    1166             :         std::map<CPLString, int> &oMapCountOccurrencesOfSameName);
    1167             :     bool ExploreModelGroup(
    1168             :         XSModelGroup *psMainModelGroup, XSAttributeUseList *poMainAttrList,
    1169             :         GMLASFeatureClass &oClass, int nRecursionCounter,
    1170             :         std::set<XSModelGroup *> &oSetVisitedModelGroups, XSModel *poModel,
    1171             :         const std::map<CPLString, int> &oMapCountOccurrencesOfSameName);
    1172             :     void SetFieldTypeAndWidthFromDefinition(XSSimpleTypeDefinition *poST,
    1173             :                                             GMLASField &oField);
    1174             :     CPLString GetPrefix(const CPLString &osNamespaceURI);
    1175             :     CPLString MakeXPath(const CPLString &osNamespace, const CPLString &osName);
    1176             :     bool LaunderFieldNames(GMLASFeatureClass &oClass);
    1177             :     void LaunderClassNames();
    1178             : 
    1179             :     XSElementDeclaration *
    1180             :     GetTopElementDeclarationFromXPath(const CPLString &osXPath,
    1181             :                                       XSModel *poModel);
    1182             : 
    1183             :     bool InstantiateClassFromEltDeclaration(XSElementDeclaration *poEltDecl,
    1184             :                                             XSModel *poModel, bool &bError);
    1185             :     void CreateNonNestedRelationship(
    1186             :         XSElementDeclaration *poElt,
    1187             :         std::vector<XSElementDeclaration *> &apoSubEltList,
    1188             :         GMLASFeatureClass &oClass, int nMaxOccurs, bool bEltNameWillNeedPrefix,
    1189             :         bool bForceJunctionTable, bool bCaseOfConstraintChildren);
    1190             : 
    1191             :     bool IsGMLNamespace(const CPLString &osURI);
    1192             : 
    1193             :     bool DerivesFromGMLFeature(XSElementDeclaration *poEltDecl);
    1194             : 
    1195             :     bool IsIgnoredXPath(const CPLString &osXPath);
    1196             : 
    1197             :     static void
    1198             :     CollectClassesReferences(GMLASFeatureClass &oClass,
    1199             :                              std::vector<GMLASFeatureClass *> &aoClasses);
    1200             : 
    1201             :     CPL_DISALLOW_COPY_ASSIGN(GMLASSchemaAnalyzer)
    1202             : 
    1203             :   public:
    1204             :     GMLASSchemaAnalyzer(
    1205             :         GMLASXPathMatcher &oIgnoredXPathMatcher,
    1206             :         GMLASXPathMatcher &oChildrenElementsConstraintsXPathMatcher,
    1207             :         const std::map<CPLString, std::vector<CPLString>>
    1208             :             &oMapChildrenElementsConstraints,
    1209             :         GMLASXPathMatcher &oForcedFlattenedXPathMatcher,
    1210             :         GMLASXPathMatcher &oDisabledFlattenedXPathMatcher);
    1211             : 
    1212         193 :     void SetUseArrays(bool b)
    1213             :     {
    1214         193 :         m_bUseArrays = b;
    1215         193 :     }
    1216             : 
    1217         193 :     void SetUseNullState(bool b)
    1218             :     {
    1219         193 :         m_bUseNullState = b;
    1220         193 :     }
    1221             : 
    1222         193 :     void SetInstantiateGMLFeaturesOnly(bool b)
    1223             :     {
    1224         193 :         m_bInstantiateGMLFeaturesOnly = b;
    1225         193 :     }
    1226             : 
    1227         193 :     void SetIdentifierMaxLength(int nLength)
    1228             :     {
    1229         193 :         m_nIdentifierMaxLength = nLength;
    1230         193 :     }
    1231             : 
    1232         193 :     void SetCaseInsensitiveIdentifier(bool b)
    1233             :     {
    1234         193 :         m_bCaseInsensitiveIdentifier = b;
    1235         193 :     }
    1236             : 
    1237         193 :     void SetPGIdentifierLaundering(bool b)
    1238             :     {
    1239         193 :         m_bPGIdentifierLaundering = b;
    1240         193 :     }
    1241             : 
    1242         193 :     void SetMaximumFieldsForFlattening(int n)
    1243             :     {
    1244         193 :         m_nMaximumFieldsForFlattening = n;
    1245         193 :     }
    1246             : 
    1247         158 :     void SetMapDocNSURIToPrefix(const std::map<CPLString, CPLString> &oMap)
    1248             :     {
    1249         158 :         m_oMapDocNSURIToPrefix = oMap;
    1250         158 :     }
    1251             : 
    1252         193 :     void SetAlwaysGenerateOGRId(bool b)
    1253             :     {
    1254         193 :         m_bAlwaysGenerateOGRId = b;
    1255         193 :     }
    1256             : 
    1257             :     bool Analyze(GMLASXSDCache &oCache, const CPLString &osBaseDirname,
    1258             :                  std::vector<PairURIFilename> &aoXSDs, bool bSchemaFullChecking,
    1259             :                  bool bHandleMultipleImports);
    1260             : 
    1261         178 :     const std::vector<GMLASFeatureClass> &GetClasses() const
    1262             :     {
    1263         178 :         return m_aoClasses;
    1264             :     }
    1265             : 
    1266         178 :     const std::map<CPLString, CPLString> &GetMapURIToPrefix() const
    1267             :     {
    1268         178 :         return m_oMapURIToPrefix;
    1269             :     }
    1270             : 
    1271         178 :     const CPLString &GetGMLVersionFound() const
    1272             :     {
    1273         178 :         return m_osGMLVersionFound;
    1274             :     }
    1275             : 
    1276         178 :     const std::set<CPLString> &GetSchemaURLS() const
    1277             :     {
    1278         178 :         return m_oSetSchemaURLs;
    1279             :     }
    1280             : 
    1281       14453 :     static CPLString BuildJunctionTableXPath(const CPLString &osEltXPath,
    1282             :                                              const CPLString &osSubEltXPath)
    1283             :     {
    1284       28906 :         return osEltXPath + "|" + osSubEltXPath;
    1285             :     }
    1286             : };
    1287             : 
    1288             : /************************************************************************/
    1289             : /*                           OGRGMLASDataSource                         */
    1290             : /************************************************************************/
    1291             : 
    1292             : class OGRGMLASLayer;
    1293             : class GMLASReader;
    1294             : 
    1295             : class OGRGMLASDataSource final : public GDALDataset
    1296             : {
    1297             :     struct XercesInitializer
    1298             :     {
    1299             :         XercesInitializer();
    1300             :         ~XercesInitializer();
    1301             :     };
    1302             : 
    1303             :     // MUST be first member, to get destroyed last after we have cleaned up
    1304             :     // all other Xerces dependent objects.
    1305             :     XercesInitializer m_oXercesInitializer{};
    1306             : 
    1307             :     std::vector<std::unique_ptr<OGRGMLASLayer>> m_apoLayers{};
    1308             :     std::map<CPLString, CPLString> m_oMapURIToPrefix{};
    1309             :     CPLString m_osGMLFilename{};
    1310             :     std::unique_ptr<OGRLayer> m_poFieldsMetadataLayer{};
    1311             :     std::unique_ptr<OGRLayer> m_poLayersMetadataLayer{};
    1312             :     std::unique_ptr<OGRLayer> m_poRelationshipsLayer{};
    1313             :     std::unique_ptr<OGRLayer> m_poOtherMetadataLayer{};
    1314             :     std::vector<OGRLayer *> m_apoRequestedMetadataLayers{};
    1315             :     std::shared_ptr<VSIVirtualHandle> m_fpGML{};
    1316             :     std::shared_ptr<VSIVirtualHandle> m_fpGMLParser{};
    1317             :     bool m_bLayerInitFinished = false;
    1318             :     bool m_bSchemaFullChecking = false;
    1319             :     bool m_bHandleMultipleImports = false;
    1320             :     bool m_bValidate = false;
    1321             :     bool m_bRemoveUnusedLayers = false;
    1322             :     bool m_bRemoveUnusedFields = false;
    1323             :     bool m_bFirstPassDone = false;
    1324             :     /** Map from a SRS name to a boolean indicating if its coordinate
    1325             :         order is inverted. */
    1326             :     std::map<CPLString, bool> m_oMapSRSNameToInvertedAxis{};
    1327             : 
    1328             :     /** Map from geometry field definition to its expected SRSName */
    1329             :     std::map<OGRGeomFieldDefn *, CPLString> m_oMapGeomFieldDefnToSRSName{};
    1330             : 
    1331             :     /* map the ID attribute to its belonging layer, e.g foo.1 -> layer Foo */
    1332             :     std::map<CPLString, OGRGMLASLayer *> m_oMapElementIdToLayer{};
    1333             : 
    1334             :     /* map the ID attribute to the feature PKID (when different from itself) */
    1335             :     std::map<CPLString, CPLString> m_oMapElementIdToPKID{};
    1336             : 
    1337             :     std::vector<PairURIFilename> m_aoXSDsManuallyPassed{};
    1338             : 
    1339             :     /** Default value for srsDimension attribute. */
    1340             :     int m_nDefaultSrsDimension = 0;
    1341             : 
    1342             :     GMLASConfiguration m_oConf{};
    1343             : 
    1344             :     /** Schema cache */
    1345             :     GMLASXSDCache m_oCache{};
    1346             : 
    1347             :     GMLASXPathMatcher m_oIgnoredXPathMatcher{};
    1348             : 
    1349             :     GMLASXPathMatcher m_oChildrenElementsConstraintsXPathMatcher{};
    1350             : 
    1351             :     GMLASXPathMatcher m_oForcedFlattenedXPathMatcher{};
    1352             : 
    1353             :     GMLASXPathMatcher m_oDisabledFlattenedXPathMatcher{};
    1354             : 
    1355             :     GMLASSwapCoordinatesEnum m_eSwapCoordinates = GMLAS_SWAP_AUTO;
    1356             : 
    1357             :     /** Base unique identifier */
    1358             :     CPLString m_osHash{};
    1359             : 
    1360             :     vsi_l_offset m_nFileSize = 0;
    1361             : 
    1362             :     std::unique_ptr<GMLASReader> m_poReader{};
    1363             : 
    1364             :     bool m_bEndOfReaderLayers = false;
    1365             : 
    1366             :     int m_nCurMetadataLayerIdx = -1;
    1367             : 
    1368             :     GMLASXLinkResolver m_oXLinkResolver{};
    1369             : 
    1370             :     CPLString m_osGMLVersionFound{};
    1371             : 
    1372             :     bool m_bFoundSWE = false;
    1373             : 
    1374             :     // Pointers are also included in m_apoLayers
    1375             :     std::vector<OGRGMLASLayer *> m_apoSWEDataArrayLayersRef{};
    1376             : 
    1377             :     // Path to gmlasconf.xml. It is a /vsimem temporary file if
    1378             :     // m_bUnlinkConfigFileAfterUse is set.
    1379             :     std::string m_osConfigFile{};
    1380             : 
    1381             :     // Whether m_osConfigFile should be removed at closing.
    1382             :     bool m_bUnlinkConfigFileAfterUse = false;
    1383             : 
    1384             :     void TranslateClasses(OGRGMLASLayer *poParentLayer,
    1385             :                           const GMLASFeatureClass &oFC);
    1386             : 
    1387             :     bool RunFirstPassIfNeeded(GMLASReader *poReader,
    1388             :                               GDALProgressFunc pfnProgress,
    1389             :                               void *pProgressData);
    1390             : 
    1391             :     void FillOtherMetadataLayer(GDALOpenInfo *poOpenInfo,
    1392             :                                 const CPLString &osConfigFile,
    1393             :                                 const std::vector<PairURIFilename> &aoXSDs,
    1394             :                                 const std::set<CPLString> &oSetSchemaURLs);
    1395             : 
    1396             :     static std::vector<PairURIFilename>
    1397             :     BuildXSDVector(const CPLString &osXSDFilenames);
    1398             : 
    1399             :     void InitReaderWithFirstPassElements(GMLASReader *poReader);
    1400             : 
    1401             :   public:
    1402             :     OGRGMLASDataSource();
    1403             : 
    1404             :     ~OGRGMLASDataSource();
    1405             : 
    1406             :     virtual int GetLayerCount() override;
    1407             :     virtual OGRLayer *GetLayer(int) override;
    1408             :     virtual OGRLayer *GetLayerByName(const char *pszName) override;
    1409             : 
    1410             :     virtual void ResetReading() override;
    1411             :     virtual OGRFeature *GetNextFeature(OGRLayer **ppoBelongingLayer,
    1412             :                                        double *pdfProgressPct,
    1413             :                                        GDALProgressFunc pfnProgress,
    1414             :                                        void *pProgressData) override;
    1415             :     virtual int TestCapability(const char *) override;
    1416             : 
    1417             :     bool Open(GDALOpenInfo *poOpenInfo);
    1418             : 
    1419        1392 :     std::vector<std::unique_ptr<OGRGMLASLayer>> &GetLayers()
    1420             :     {
    1421        1392 :         return m_apoLayers;
    1422             :     }
    1423             : 
    1424        1392 :     const std::map<CPLString, CPLString> &GetMapURIToPrefix() const
    1425             :     {
    1426        1392 :         return m_oMapURIToPrefix;
    1427             :     }
    1428             : 
    1429        1475 :     const CPLString &GetGMLFilename() const
    1430             :     {
    1431        1475 :         return m_osGMLFilename;
    1432             :     }
    1433             : 
    1434             :     const CPLString &GetGMLVersionFound() const
    1435             :     {
    1436             :         return m_osGMLVersionFound;
    1437             :     }
    1438             : 
    1439       16987 :     OGRLayer *GetFieldsMetadataLayer()
    1440             :     {
    1441       16987 :         return m_poFieldsMetadataLayer.get();
    1442             :     }
    1443             : 
    1444       16958 :     OGRLayer *GetLayersMetadataLayer()
    1445             :     {
    1446       16958 :         return m_poLayersMetadataLayer.get();
    1447             :     }
    1448             : 
    1449       16961 :     OGRLayer *GetRelationshipsLayer()
    1450             :     {
    1451       16961 :         return m_poRelationshipsLayer.get();
    1452             :     }
    1453             : 
    1454             :     OGRGMLASLayer *GetLayerByXPath(const CPLString &osXPath);
    1455             : 
    1456             :     GMLASReader *CreateReader(std::shared_ptr<VSIVirtualHandle> &fpGML,
    1457             :                               GDALProgressFunc pfnProgress = nullptr,
    1458             :                               void *pProgressData = nullptr);
    1459             : 
    1460        1280 :     GMLASXSDCache &GetCache()
    1461             :     {
    1462        1280 :         return m_oCache;
    1463             :     }
    1464             : 
    1465             :     void PushUnusedGMLFilePointer(std::shared_ptr<VSIVirtualHandle> &fpGML);
    1466             :     std::shared_ptr<VSIVirtualHandle> PopUnusedGMLFilePointer();
    1467             : 
    1468       61587 :     bool IsLayerInitFinished() const
    1469             :     {
    1470       61587 :         return m_bLayerInitFinished;
    1471             :     }
    1472             : 
    1473        1280 :     GMLASSwapCoordinatesEnum GetSwapCoordinates() const
    1474             :     {
    1475        1280 :         return m_eSwapCoordinates;
    1476             :     }
    1477             : 
    1478        1280 :     const std::map<CPLString, bool> &GetMapIgnoredXPathToWarn() const
    1479             :     {
    1480        1280 :         return m_oConf.m_oMapIgnoredXPathToWarn;
    1481             :     }
    1482             : 
    1483        1280 :     const GMLASXPathMatcher &GetIgnoredXPathMatcher() const
    1484             :     {
    1485        1280 :         return m_oIgnoredXPathMatcher;
    1486             :     }
    1487             : 
    1488         982 :     const GMLASConfiguration &GetConf() const
    1489             :     {
    1490         982 :         return m_oConf;
    1491             :     }
    1492             : 
    1493             :     const std::vector<PairURIFilename> &GetXSDsManuallyPassed() const
    1494             :     {
    1495             :         return m_aoXSDsManuallyPassed;
    1496             :     }
    1497             : };
    1498             : 
    1499             : /************************************************************************/
    1500             : /*                             OGRGMLASLayer                            */
    1501             : /************************************************************************/
    1502             : 
    1503             : class OGRGMLASLayer final : public OGRLayer
    1504             : {
    1505             :     friend class OGRGMLASDataSource;
    1506             : 
    1507             :     OGRGMLASDataSource *m_poDS = nullptr;
    1508             :     GMLASFeatureClass m_oFC{};
    1509             :     bool m_bLayerDefnFinalized = false;
    1510             :     int m_nMaxFieldIndex = 0;
    1511             :     OGRFeatureDefn *m_poFeatureDefn = nullptr;
    1512             : 
    1513             :     /** Map from XPath to corresponding field index in OGR layer
    1514             :         definition */
    1515             :     std::map<CPLString, int> m_oMapFieldXPathToOGRFieldIdx{};
    1516             : 
    1517             :     /** Map from XPath to corresponding geometry field index in OGR layer
    1518             :         definition */
    1519             :     std::map<CPLString, int> m_oMapFieldXPathToOGRGeomFieldIdx{};
    1520             : 
    1521             :     /** Map from a OGR field index to the corresponding field index in
    1522             :         m_oFC.GetFields() */
    1523             :     std::map<int, int> m_oMapOGRFieldIdxtoFCFieldIdx{};
    1524             :     std::map<int, int> m_oMapOGRGeomFieldIdxtoFCFieldIdx{};
    1525             : 
    1526             :     /** Map from XPath to corresponding field index in m_oFC.GetFields() */
    1527             :     std::map<CPLString, int> m_oMapFieldXPathToFCFieldIdx{};
    1528             : 
    1529             :     bool m_bEOF = false;
    1530             :     std::unique_ptr<GMLASReader> m_poReader{};
    1531             :     std::shared_ptr<VSIVirtualHandle> m_fpGML{};
    1532             :     /** OGR field index of the ID field */
    1533             :     int m_nIDFieldIdx = -1;
    1534             :     /** Whether the ID field is generated, or comes from the XML content */
    1535             :     bool m_bIDFieldIsGenerated = false;
    1536             :     /** Pointer to parent layer */
    1537             :     OGRGMLASLayer *m_poParentLayer = nullptr;
    1538             :     /** OGR field index of the field that points to the parent ID */
    1539             :     int m_nParentIDFieldIdx = -1;
    1540             : 
    1541             :     std::map<CPLString, CPLString> m_oMapSWEFieldToOGRFieldName{};
    1542             : 
    1543             :     OGRFeature *GetNextRawFeature();
    1544             : 
    1545             :     bool InitReader();
    1546             : 
    1547       14212 :     void SetLayerDefnFinalized(bool bVal)
    1548             :     {
    1549       14212 :         m_bLayerDefnFinalized = bVal;
    1550       14212 :     }
    1551             : 
    1552             :     CPLString LaunderFieldName(const CPLString &osFieldName);
    1553             : 
    1554             :     CPLString GetXPathFromOGRFieldIndex(int nIdx) const;
    1555             : 
    1556             :     CPL_DISALLOW_COPY_ASSIGN(OGRGMLASLayer)
    1557             : 
    1558             :   public:
    1559             :     OGRGMLASLayer(OGRGMLASDataSource *poDS, const GMLASFeatureClass &oFC,
    1560             :                   OGRGMLASLayer *poParentLayer, bool bAlwaysGenerateOGRPKId);
    1561             :     explicit OGRGMLASLayer(const char *pszLayerName);
    1562             :     virtual ~OGRGMLASLayer();
    1563             : 
    1564      352967 :     virtual const char *GetName() override
    1565             :     {
    1566      352967 :         return GetDescription();
    1567             :     }
    1568             : 
    1569             :     virtual OGRFeatureDefn *GetLayerDefn() override;
    1570             :     virtual void ResetReading() override;
    1571             :     virtual OGRFeature *GetNextFeature() override;
    1572             : 
    1573         919 :     virtual int TestCapability(const char *) override
    1574             :     {
    1575         919 :         return FALSE;
    1576             :     }
    1577             : 
    1578           3 :     void SetDataSource(OGRGMLASDataSource *poDS)
    1579             :     {
    1580           3 :         m_poDS = poDS;
    1581           3 :     }
    1582             : 
    1583             :     void PostInit(bool bIncludeGeometryXML);
    1584             :     void
    1585             :     ProcessDataRecordCreateFields(CPLXMLNode *psDataRecord,
    1586             :                                   const std::vector<OGRFeature *> &apoFeatures,
    1587             :                                   OGRLayer *poFieldsMetadataLayer);
    1588             :     void ProcessDataRecordFillFeature(CPLXMLNode *psDataRecord,
    1589             :                                       OGRFeature *poFeature);
    1590             :     void
    1591             :     ProcessDataRecordOfDataArrayCreateFields(OGRGMLASLayer *poParentLayer,
    1592             :                                              CPLXMLNode *psDataRecord,
    1593             :                                              OGRLayer *poFieldsMetadataLayer);
    1594             :     void CreateCompoundFoldedMappings();
    1595             : 
    1596     8154920 :     const GMLASFeatureClass &GetFeatureClass() const
    1597             :     {
    1598     8154920 :         return m_oFC;
    1599             :     }
    1600             : 
    1601             :     int GetOGRFieldIndexFromXPath(const CPLString &osXPath) const;
    1602             :     int GetOGRGeomFieldIndexFromXPath(const CPLString &osXPath) const;
    1603             : 
    1604      207980 :     int GetIDFieldIdx() const
    1605             :     {
    1606      207980 :         return m_nIDFieldIdx;
    1607             :     }
    1608             : 
    1609       52467 :     bool IsGeneratedIDField() const
    1610             :     {
    1611       52467 :         return m_bIDFieldIsGenerated;
    1612             :     }
    1613             : 
    1614      109449 :     OGRGMLASLayer *GetParent()
    1615             :     {
    1616      109449 :         return m_poParentLayer;
    1617             :     }
    1618             : 
    1619       90567 :     int GetParentIDFieldIdx() const
    1620             :     {
    1621       90567 :         return m_nParentIDFieldIdx;
    1622             :     }
    1623             : 
    1624             :     int GetFCFieldIndexFromOGRFieldIdx(int iOGRFieldIdx) const;
    1625             :     int GetFCFieldIndexFromOGRGeomFieldIdx(int iOGRGeomFieldIdx) const;
    1626             :     int GetFCFieldIndexFromXPath(const CPLString &osXPath) const;
    1627             : 
    1628             :     bool EvaluateFilter(OGRFeature *poFeature);
    1629             : 
    1630             :     bool RemoveField(int nIdx);
    1631             :     void InsertNewField(int nInsertPos, const OGRFieldDefn &oFieldDefn,
    1632             :                         const CPLString &osXPath);
    1633             : 
    1634             :     CPLString
    1635             :     GetXPathOfFieldLinkForAttrToOtherLayer(const CPLString &osFieldName,
    1636             :                                            const CPLString &osTargetLayerXPath);
    1637             :     CPLString
    1638             :     CreateLinkForAttrToOtherLayer(const CPLString &osFieldName,
    1639             :                                   const CPLString &osTargetLayerXPath);
    1640             : 
    1641        2237 :     const std::map<CPLString, int> &GetMapFieldXPathToOGRFieldIdx() const
    1642             :     {
    1643        2237 :         return m_oMapFieldXPathToOGRFieldIdx;
    1644             :     }
    1645             : };
    1646             : 
    1647             : /************************************************************************/
    1648             : /*                              GMLASReader                             */
    1649             : /************************************************************************/
    1650             : 
    1651             : class GMLASReader final : public DefaultHandler
    1652             : {
    1653             :     /** Schema cache */
    1654             :     GMLASXSDCache &m_oCache;
    1655             : 
    1656             :     /** Object to tell if a XPath must be ignored */
    1657             :     const GMLASXPathMatcher &m_oIgnoredXPathMatcher;
    1658             : 
    1659             :     /** XLink resolver */
    1660             :     GMLASXLinkResolver &m_oXLinkResolver;
    1661             : 
    1662             :     /** Whether we should stop parsing */
    1663             :     bool m_bParsingError = false;
    1664             : 
    1665             :     /** Xerces reader object */
    1666             :     std::unique_ptr<SAX2XMLReader> m_poSAXReader{};
    1667             : 
    1668             :     /** Token for Xerces */
    1669             :     XMLPScanToken m_oToFill{};
    1670             : 
    1671             :     /** File descriptor */
    1672             :     std::shared_ptr<VSIVirtualHandle> m_fp{};
    1673             : 
    1674             :     /** Input source */
    1675             :     std::unique_ptr<GMLASInputSource> m_GMLInputSource{};
    1676             : 
    1677             :     /** Whether we are at the first iteration */
    1678             :     bool m_bFirstIteration = true;
    1679             : 
    1680             :     /** Whether we have reached end of file (or an error) */
    1681             :     bool m_bEOF = false;
    1682             : 
    1683             :     /** Whether GetNextFeature() has been user interrupted (progress cbk) */
    1684             :     bool m_bInterrupted = false;
    1685             : 
    1686             :     /** Error handler (for Xerces reader) */
    1687             :     GMLASErrorHandler m_oErrorHandler{};
    1688             : 
    1689             :     /** Map URI namespaces to their prefix */
    1690             :     std::map<CPLString, CPLString> m_oMapURIToPrefix{};
    1691             : 
    1692             :     /** List of OGR layers */
    1693             :     std::vector<std::unique_ptr<OGRGMLASLayer>> *m_apoLayers = nullptr;
    1694             : 
    1695             :     /** Vector of features ready for consumption */
    1696             :     std::list<std::pair<std::unique_ptr<OGRFeature>, OGRGMLASLayer *>>
    1697             :         m_aoFeaturesReady{};
    1698             : 
    1699             :     /** OGR field index of the current field */
    1700             :     int m_nCurFieldIdx = -1;
    1701             : 
    1702             :     /** OGR geometry field index of the current field */
    1703             :     int m_nCurGeomFieldIdx = -1;
    1704             : 
    1705             :     /** XML nested level of current field */
    1706             :     int m_nCurFieldLevel = 0;
    1707             : 
    1708             :     /** Whether we should store all content of the current field as XML */
    1709             :     bool m_bIsXMLBlob = false;
    1710             :     bool m_bIsXMLBlobIncludeUpper = false;
    1711             : 
    1712             :     /** Content of the current field */
    1713             :     CPLString m_osTextContent{};
    1714             : 
    1715             :     /** For list field types, list of content */
    1716             :     CPLStringList m_osTextContentList{};
    1717             :     /** Estimated memory footprint of m_osTextContentList */
    1718             :     size_t m_nTextContentListEstimatedSize = 0;
    1719             : 
    1720             :     /** Which layer is of interest for the reader, or NULL for all */
    1721             :     OGRGMLASLayer *m_poLayerOfInterest = nullptr;
    1722             : 
    1723             :     /** Stack of length of split XPath components */
    1724             :     std::vector<size_t> m_anStackXPathLength{};
    1725             : 
    1726             :     /** Current absolute XPath */
    1727             :     CPLString m_osCurXPath{};
    1728             : 
    1729             :     /** Current XPath, relative to top-level feature */
    1730             :     CPLString m_osCurSubXPath{};
    1731             : 
    1732             :     /** Current XML nesting level */
    1733             :     int m_nLevel = 0;
    1734             : 
    1735             :     /** Whether we are in a gml:boundedBy element at level 1 */
    1736             :     bool m_bInGMLBoundedByLevel1 = false;
    1737             : 
    1738             :     /** Default value for srsDimension attribute. */
    1739             :     int m_nDefaultSrsDimension = 0;
    1740             : 
    1741             :     /** Map layer to global FID */
    1742             :     std::map<OGRLayer *, int> m_oMapGlobalCounter{};
    1743             : 
    1744             :     /** Parsing context */
    1745             :     struct Context
    1746             :     {
    1747             :         /** XML nesting level */
    1748             :         int m_nLevel = 0;
    1749             : 
    1750             :         /** Current feature */
    1751             :         OGRFeature *m_poFeature = nullptr;
    1752             : 
    1753             :         /** Layer of m_poFeature */
    1754             :         OGRGMLASLayer *m_poLayer = nullptr;
    1755             : 
    1756             :         /** Current layer in a repeated group */
    1757             :         OGRGMLASLayer *m_poGroupLayer = nullptr;
    1758             : 
    1759             :         /** Nesting level of m_poCurGroupLayer */
    1760             :         int m_nGroupLayerLevel = -1;
    1761             : 
    1762             :         /** Index of the last processed OGR field in m_poCurGroupLayer */
    1763             :         int m_nLastFieldIdxGroupLayer = -1;
    1764             : 
    1765             :         /** Map layer to local FID */
    1766             :         std::map<OGRLayer *, int> m_oMapCounter{};
    1767             : 
    1768             :         /** Current XPath, relative to (current) top-level feature */
    1769             :         CPLString m_osCurSubXPath{};
    1770             : 
    1771             :         void Dump() const;
    1772             :     };
    1773             : 
    1774             :     /** Current context */
    1775             :     Context m_oCurCtxt{};
    1776             : 
    1777             :     /** Stack of saved contexts */
    1778             :     std::vector<Context> m_aoStackContext{};
    1779             : 
    1780             :     /** Context used in m_apsXMLNodeStack */
    1781             :     struct NodeLastChild
    1782             :     {
    1783             :         /** Current node */
    1784             :         CPLXMLNode *psNode = nullptr;
    1785             : 
    1786             :         /** Last child of psNode (for fast append operations) */
    1787             :         CPLXMLNode *psLastChild = nullptr;
    1788             :     };
    1789             : 
    1790             :     /** Stack of contexts to build XML tree of GML Geometry */
    1791             :     std::vector<NodeLastChild> m_apsXMLNodeStack{};
    1792             : 
    1793             :     /** Counter used to prevent XML billion laugh attacks */
    1794             :     int m_nEntityCounter = 0;
    1795             : 
    1796             :     /** Maximum allowed number of XML nesting level */
    1797             :     int m_nMaxLevel = 100;
    1798             : 
    1799             :     /** Maximum allowed size of XML content in byte */
    1800             :     size_t m_nMaxContentSize = 512000000;
    1801             : 
    1802             :     /** Map from a SRS name to a boolean indicating if its coordinate
    1803             :         order is inverted. */
    1804             :     std::map<CPLString, bool> m_oMapSRSNameToInvertedAxis{};
    1805             : 
    1806             :     /** Set of geometry fields with unknown SRS */
    1807             :     std::set<OGRGeomFieldDefn *> m_oSetGeomFieldsWithUnknownSRS{};
    1808             : 
    1809             :     /** Map from geometry field definition to its expected SRSName.
    1810             :         This is used to know if reprojection must be done */
    1811             :     std::map<OGRGeomFieldDefn *, CPLString> m_oMapGeomFieldDefnToSRSName{};
    1812             : 
    1813             :     /** Whether this parsing involves schema validation */
    1814             :     bool m_bValidate = false;
    1815             : 
    1816             :     /** Entity resolver used during schema validation */
    1817             :     std::unique_ptr<GMLASBaseEntityResolver> m_poEntityResolver{};
    1818             : 
    1819             :     /** First level from which warnings about ignored XPath should be
    1820             :         silent. */
    1821             :     int m_nLevelSilentIgnoredXPath = -1;
    1822             : 
    1823             :     /** Whether a warning should be emitted when an element or attribute is
    1824             :         found in the document parsed, but ignored because of the ignored
    1825             :         XPath defined.  */
    1826             :     std::map<CPLString, bool> m_oMapIgnoredXPathToWarn{};
    1827             : 
    1828             :     /** Policy to decide when to invert coordinates */
    1829             :     GMLASSwapCoordinatesEnum m_eSwapCoordinates = GMLAS_SWAP_AUTO;
    1830             : 
    1831             :     /** Initial pass to guess SRS, etc... */
    1832             :     bool m_bInitialPass = false;
    1833             : 
    1834             :     /** Whether to process swe:DataArray in a special way */
    1835             :     bool m_bProcessSWEDataArray = false;
    1836             : 
    1837             :     /** Whether to process swe:DataArray in a special way */
    1838             :     bool m_bProcessSWEDataRecord = false;
    1839             : 
    1840             :     /** Depth level of the swe:DataArray element */
    1841             :     int m_nSWEDataArrayLevel = -1;
    1842             : 
    1843             :     /** Field name to which the DataArray belongs to */
    1844             :     CPLString m_osSWEDataArrayParentField{};
    1845             : 
    1846             :     /** Depth level of the swe:DataRecord element */
    1847             :     int m_nSWEDataRecordLevel = -1;
    1848             : 
    1849             :     OGRLayer *m_poFieldsMetadataLayer = nullptr;
    1850             :     OGRLayer *m_poLayersMetadataLayer = nullptr;
    1851             :     OGRLayer *m_poRelationshipsLayer = nullptr;
    1852             : 
    1853             :     /** Base unique identifier */
    1854             :     CPLString m_osHash{};
    1855             : 
    1856             :     vsi_l_offset m_nFileSize = 0;
    1857             : 
    1858             :     bool m_bWarnUnexpected = false;
    1859             : 
    1860             :     /** Map from layer to a map of field XPath to a set of matching
    1861             :         URL specific resolution rule index */
    1862             :     std::map<OGRGMLASLayer *, std::map<CPLString, std::set<int>>>
    1863             :         m_oMapXLinkFields{};
    1864             : 
    1865             :     /** Variables that could be local but more efficient to have same
    1866             :         persistent, so as to save many memory allocations/deallocations */
    1867             :     CPLString m_osLocalname{};
    1868             :     CPLString m_osNSUri{};
    1869             :     CPLString m_osNSPrefix{};
    1870             :     CPLString m_osXPath{};
    1871             :     CPLString m_osLayerXPath{};
    1872             :     CPLString m_osAttrNSUri{};
    1873             :     CPLString m_osAttrNSPrefix{};
    1874             :     CPLString m_osAttrLocalName{};
    1875             :     CPLString m_osAttrXPath{};
    1876             :     CPLString m_osAttrValue{};
    1877             :     CPLString m_osText{};
    1878             : 
    1879             :     std::vector<OGRGMLASLayer *> m_apoSWEDataArrayLayersRef{};
    1880             :     std::vector<std::unique_ptr<OGRGMLASLayer>> m_apoSWEDataArrayLayersOwned{};
    1881             : 
    1882             :     int m_nSWEDataArrayLayerIdx = 0;
    1883             : 
    1884             :     /* Set of 3 maps used for xlink:href="#xxxx" internal links resolution */
    1885             :     /* 1) map the ID attribute to its belonging layer, e.g foo.1 -> layer Foo */
    1886             :     std::map<CPLString, OGRGMLASLayer *> m_oMapElementIdToLayer{};
    1887             :     /* 2) map the ID attribute to the feature PKID (when different from itself)
    1888             :      */
    1889             :     std::map<CPLString, CPLString> m_oMapElementIdToPKID{};
    1890             :     /* 3) map each (layer, field_xpath) to the list of ID it refers to */
    1891             :     /*    e.g  (layer Bar, field_xpath) -> [foo.1, foo.2] */
    1892             :     std::map<std::pair<OGRGMLASLayer *, CPLString>, std::vector<CPLString>>
    1893             :         m_oMapFieldXPathToLinkValue{};
    1894             : 
    1895             :     /* Map layer's XPath to layer (for layers that are not group) */
    1896             :     std::map<CPLString, OGRGMLASLayer *> m_oMapXPathToLayer{};
    1897             : 
    1898             :     /* Map OGR field XPath to layer (for layers that are group) */
    1899             :     std::map<CPLString, OGRGMLASLayer *> m_oMapFieldXPathToGroupLayer{};
    1900             : 
    1901             :     /* Map layer's XPath to layer (for layers that are repeated sequences) */
    1902             :     std::map<CPLString, std::vector<OGRGMLASLayer *>>
    1903             :         m_oMapXPathToLayerRepeadedSequence{};
    1904             : 
    1905             :     void SetField(OGRFeature *poFeature, OGRGMLASLayer *poLayer, int nAttrIdx,
    1906             :                   const CPLString &osAttrValue);
    1907             : 
    1908             :     void CreateNewFeature(const CPLString &osLocalname);
    1909             : 
    1910             :     void PushFeatureReady(std::unique_ptr<OGRFeature> &&,
    1911             :                           OGRGMLASLayer *poLayer);
    1912             : 
    1913             :     void PushContext(const Context &oContext);
    1914             :     void PopContext();
    1915             : 
    1916             :     void BuildXMLBlobStartElement(const CPLString &osXPath,
    1917             :                                   const Attributes &attrs);
    1918             : 
    1919             :     OGRGMLASLayer *GetLayerByXPath(const CPLString &osXPath);
    1920             : 
    1921             :     void AttachAsLastChild(CPLXMLNode *psNode);
    1922             : 
    1923             :     void ProcessSWEDataArray(CPLXMLNode *psRoot);
    1924             :     void ProcessSWEDataRecord(CPLXMLNode *psRoot);
    1925             :     void ProcessGeometry(CPLXMLNode *psRoot);
    1926             : 
    1927             :     void ProcessAttributes(const Attributes &attrs);
    1928             :     void ProcessXLinkHref(int nAttrIdx, const CPLString &osAttrXPath,
    1929             :                           const CPLString &osAttrValue);
    1930             :     void
    1931             :     ExploreXMLDoc(const CPLString &osAttrXPath,
    1932             :                   const GMLASXLinkResolutionConf::URLSpecificResolution &oRule,
    1933             :                   CPLXMLNode *psNode, const CPLString &osParentXPath,
    1934             :                   const GMLASXPathMatcher &oMatcher,
    1935             :                   const std::map<CPLString, size_t> &oMapFieldXPathToIdx);
    1936             : 
    1937             :     void CreateFieldsForURLSpecificRules();
    1938             :     void CreateFieldsForURLSpecificRule(
    1939             :         OGRGMLASLayer *poLayer, int nFieldIdx, const CPLString &osFieldXPath,
    1940             :         int &nInsertFieldIdx,
    1941             :         const GMLASXLinkResolutionConf::URLSpecificResolution &oRule);
    1942             : 
    1943      321265 :     bool FillTextContent() const
    1944             :     {
    1945      321265 :         return !m_bInitialPass && m_nCurFieldIdx >= 0;
    1946             :     }
    1947             : 
    1948             :     void ProcessInternalXLinkFirstPass(
    1949             :         bool bRemoveUnusedFields,
    1950             :         std::map<OGRGMLASLayer *, std::set<CPLString>> &oMapUnusedFields);
    1951             : 
    1952             :     CPL_DISALLOW_COPY_ASSIGN(GMLASReader)
    1953             : 
    1954             :   public:
    1955             :     GMLASReader(GMLASXSDCache &oCache,
    1956             :                 const GMLASXPathMatcher &oIgnoredXPathMatcher,
    1957             :                 GMLASXLinkResolver &oXLinkResolver);
    1958             :     ~GMLASReader();
    1959             : 
    1960             :     bool Init(const char *pszFilename,
    1961             :               const std::shared_ptr<VSIVirtualHandle> &fp,
    1962             :               const std::map<CPLString, CPLString> &oMapURIToPrefix,
    1963             :               std::vector<std::unique_ptr<OGRGMLASLayer>> &apoLayers,
    1964             :               bool bValidate, const std::vector<PairURIFilename> &aoXSDs,
    1965             :               bool bSchemaFullChecking, bool bHandleMultipleImports);
    1966             : 
    1967             :     void SetLayerOfInterest(OGRGMLASLayer *poLayer);
    1968             : 
    1969        1392 :     void SetMapIgnoredXPathToWarn(const std::map<CPLString, bool> &oMap)
    1970             :     {
    1971        1392 :         m_oMapIgnoredXPathToWarn = oMap;
    1972        1392 :     }
    1973             : 
    1974        1280 :     void SetSwapCoordinates(GMLASSwapCoordinatesEnum eVal)
    1975             :     {
    1976        1280 :         m_eSwapCoordinates = eVal;
    1977        1280 :     }
    1978             : 
    1979          43 :     const std::shared_ptr<VSIVirtualHandle> &GetFP() const
    1980             :     {
    1981          43 :         return m_fp;
    1982             :     }
    1983             : 
    1984         112 :     const std::map<CPLString, bool> &GetMapSRSNameToInvertedAxis() const
    1985             :     {
    1986         112 :         return m_oMapSRSNameToInvertedAxis;
    1987             :     }
    1988             : 
    1989        1267 :     void SetMapSRSNameToInvertedAxis(const std::map<CPLString, bool> &oMap)
    1990             :     {
    1991        1267 :         m_oMapSRSNameToInvertedAxis = oMap;
    1992        1267 :     }
    1993             : 
    1994             :     const std::map<OGRGeomFieldDefn *, CPLString> &
    1995         112 :     GetMapGeomFieldDefnToSRSName() const
    1996             :     {
    1997         112 :         return m_oMapGeomFieldDefnToSRSName;
    1998             :     }
    1999             : 
    2000        1267 :     void SetMapGeomFieldDefnToSRSName(
    2001             :         const std::map<OGRGeomFieldDefn *, CPLString> &oMap)
    2002             :     {
    2003        1267 :         m_oMapGeomFieldDefnToSRSName = oMap;
    2004        1267 :     }
    2005             : 
    2006         112 :     const std::map<CPLString, OGRGMLASLayer *> &GetMapElementIdToLayer() const
    2007             :     {
    2008         112 :         return m_oMapElementIdToLayer;
    2009             :     }
    2010             : 
    2011             :     void
    2012        1267 :     SetMapElementIdToLayer(const std::map<CPLString, OGRGMLASLayer *> &oMap)
    2013             :     {
    2014        1267 :         m_oMapElementIdToLayer = oMap;
    2015        1267 :     }
    2016             : 
    2017         112 :     const std::map<CPLString, CPLString> &GetMapElementIdToPKID() const
    2018             :     {
    2019         112 :         return m_oMapElementIdToPKID;
    2020             :     }
    2021             : 
    2022        1267 :     void SetMapElementIdToPKID(const std::map<CPLString, CPLString> &oMap)
    2023             :     {
    2024        1267 :         m_oMapElementIdToPKID = oMap;
    2025        1267 :     }
    2026             : 
    2027         112 :     int GetDefaultSrsDimension() const
    2028             :     {
    2029         112 :         return m_nDefaultSrsDimension;
    2030             :     }
    2031             : 
    2032        1267 :     void SetDefaultSrsDimension(int nDim)
    2033             :     {
    2034        1267 :         m_nDefaultSrsDimension = nDim;
    2035        1267 :     }
    2036             : 
    2037        1392 :     void SetHash(const CPLString &osHash)
    2038             :     {
    2039        1392 :         m_osHash = osHash;
    2040        1392 :     }
    2041             : 
    2042        1392 :     void SetFileSize(vsi_l_offset nFileSize)
    2043             :     {
    2044        1392 :         m_nFileSize = nFileSize;
    2045        1392 :     }
    2046             : 
    2047             :     OGRFeature *GetNextFeature(OGRGMLASLayer **ppoBelongingLayer = nullptr,
    2048             :                                GDALProgressFunc pfnProgress = nullptr,
    2049             :                                void *pProgressData = nullptr);
    2050             : 
    2051             :     virtual void startElement(const XMLCh *const uri,
    2052             :                               const XMLCh *const localname,
    2053             :                               const XMLCh *const qname,
    2054             :                               const Attributes &attrs) override;
    2055             :     virtual void endElement(const XMLCh *const uri,
    2056             :                             const XMLCh *const localname,
    2057             :                             const XMLCh *const qname) override;
    2058             : 
    2059             :     virtual void characters(const XMLCh *const chars,
    2060             :                             const XMLSize_t length) override;
    2061             : 
    2062             :     void startEntity(const XMLCh *const name) override;
    2063             : 
    2064             :     bool RunFirstPass(GDALProgressFunc pfnProgress, void *pProgressData,
    2065             :                       bool bRemoveUnusedLayers, bool bRemoveUnusedFields,
    2066             :                       bool bProcessSWEDataArray,
    2067             :                       OGRLayer *poFieldsMetadataLayer,
    2068             :                       OGRLayer *poLayersMetadataLayer,
    2069             :                       OGRLayer *poRelationshipsLayer,
    2070             :                       std::set<CPLString> &aoSetRemovedLayerNames);
    2071             : 
    2072             :     static bool LoadXSDInParser(SAX2XMLReader *poParser, GMLASXSDCache &oCache,
    2073             :                                 GMLASBaseEntityResolver &oXSDEntityResolver,
    2074             :                                 const CPLString &osBaseDirname,
    2075             :                                 const CPLString &osXSDFilename,
    2076             :                                 Grammar **ppoGrammar, bool bSchemaFullChecking,
    2077             :                                 bool bHandleMultipleImports);
    2078             : 
    2079             :     void SetSWEDataArrayLayersRef(const std::vector<OGRGMLASLayer *> &ar);
    2080             : 
    2081        1379 :     void SetProcessDataRecord(bool b)
    2082             :     {
    2083        1379 :         m_bProcessSWEDataRecord = b;
    2084        1379 :     }
    2085             : 
    2086         112 :     std::vector<std::unique_ptr<OGRGMLASLayer>> StealSWEDataArrayLayersOwned()
    2087             :     {
    2088         112 :         return std::move(m_apoSWEDataArrayLayersOwned);
    2089             :     }
    2090             : };
    2091             : 
    2092             : CPLString OGRGMLASTruncateIdentifier(const CPLString &osName,
    2093             :                                      int nIdentMaxLength);
    2094             : 
    2095             : CPLString OGRGMLASAddSerialNumber(const CPLString &osNameIn, int iOccurrence,
    2096             :                                   size_t nOccurrences, int nIdentMaxLength);
    2097             : 
    2098             : #endif  // OGR_GMLAS_INCLUDED

Generated by: LCOV version 1.14