LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/openfilegdb - filegdb_fielddomain.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 179 238 75.2 %
Date: 2024-05-02 22:57:13 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements Open FileGDB OGR driver.
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2021, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #ifndef FILEGDB_FIELDDOMAIN_H
      30             : #define FILEGDB_FIELDDOMAIN_H
      31             : 
      32             : #include "cpl_minixml.h"
      33             : #include "filegdb_gdbtoogrfieldtype.h"
      34             : #include "ogr_p.h"
      35             : 
      36             : /************************************************************************/
      37             : /*                      ParseXMLFieldDomainDef()                        */
      38             : /************************************************************************/
      39             : 
      40             : inline std::unique_ptr<OGRFieldDomain>
      41        1094 : ParseXMLFieldDomainDef(const std::string &domainDef)
      42             : {
      43        2188 :     CPLXMLTreeCloser oTree(CPLParseXMLString(domainDef.c_str()));
      44        1094 :     if (!oTree.get())
      45             :     {
      46           0 :         return nullptr;
      47             :     }
      48        1094 :     const CPLXMLNode *psDomain = CPLGetXMLNode(oTree.get(), "=esri:Domain");
      49        1094 :     if (psDomain == nullptr)
      50             :     {
      51             :         // esri: namespace prefix omitted when called from the FileGDB driver
      52        1094 :         psDomain = CPLGetXMLNode(oTree.get(), "=Domain");
      53             :     }
      54        1094 :     bool bIsCodedValueDomain = false;
      55        1094 :     if (psDomain == nullptr)
      56             :     {
      57             :         // Also sometimes found...
      58        1092 :         psDomain = CPLGetXMLNode(oTree.get(), "=esri:CodedValueDomain");
      59        1092 :         if (psDomain)
      60           1 :             bIsCodedValueDomain = true;
      61             :     }
      62        1094 :     if (psDomain == nullptr)
      63             :     {
      64             :         // Also sometimes found...
      65        1091 :         psDomain = CPLGetXMLNode(oTree.get(), "=typens:GPCodedValueDomain2");
      66        1091 :         if (psDomain)
      67          19 :             bIsCodedValueDomain = true;
      68             :     }
      69        1094 :     if (psDomain == nullptr)
      70             :     {
      71             :         // Also sometimes found...
      72        1072 :         psDomain = CPLGetXMLNode(oTree.get(), "=GPCodedValueDomain2");
      73        1072 :         if (psDomain)
      74        1051 :             bIsCodedValueDomain = true;
      75             :     }
      76        1094 :     bool bIsRangeDomain = false;
      77        1094 :     if (psDomain == nullptr)
      78             :     {
      79             :         // Also sometimes found...
      80          21 :         psDomain = CPLGetXMLNode(oTree.get(), "=esri:RangeDomain");
      81          21 :         if (psDomain)
      82           3 :             bIsRangeDomain = true;
      83             :     }
      84        1094 :     if (psDomain == nullptr)
      85             :     {
      86             :         // Also sometimes found...
      87          18 :         psDomain = CPLGetXMLNode(oTree.get(), "=typens:GPRangeDomain2");
      88          18 :         if (psDomain)
      89          18 :             bIsRangeDomain = true;
      90             :     }
      91        1094 :     if (psDomain == nullptr)
      92             :     {
      93             :         // Also sometimes found...
      94           0 :         psDomain = CPLGetXMLNode(oTree.get(), "=GPRangeDomain2");
      95           0 :         if (psDomain)
      96           0 :             bIsRangeDomain = true;
      97             :     }
      98        1094 :     if (psDomain == nullptr)
      99             :     {
     100           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find root 'Domain' node");
     101           0 :         return nullptr;
     102             :     }
     103        1094 :     const char *pszType = CPLGetXMLValue(psDomain, "xsi:type", "");
     104        1094 :     const char *pszName = CPLGetXMLValue(psDomain, "DomainName", "");
     105        1094 :     const char *pszDescription = CPLGetXMLValue(psDomain, "Description", "");
     106        1094 :     const char *pszFieldType = CPLGetXMLValue(psDomain, "FieldType", "");
     107        1094 :     OGRFieldType eFieldType = OFTString;
     108        1094 :     OGRFieldSubType eSubType = OFSTNone;
     109        1094 :     if (!GDBToOGRFieldType(pszFieldType, &eFieldType, &eSubType))
     110             :     {
     111           0 :         return nullptr;
     112             :     }
     113             : 
     114        1094 :     std::unique_ptr<OGRFieldDomain> domain;
     115        1094 :     if (bIsCodedValueDomain || strcmp(pszType, "esri:CodedValueDomain") == 0)
     116             :     {
     117             :         const CPLXMLNode *psCodedValues =
     118        1073 :             CPLGetXMLNode(psDomain, "CodedValues");
     119        1073 :         if (psCodedValues == nullptr)
     120             :         {
     121           0 :             return nullptr;
     122             :         }
     123        1073 :         std::vector<OGRCodedValue> asValues;
     124       19155 :         for (const CPLXMLNode *psIter = psCodedValues->psChild; psIter;
     125       18082 :              psIter = psIter->psNext)
     126             :         {
     127       18082 :             if (psIter->eType == CXT_Element &&
     128       17009 :                 strcmp(psIter->pszValue, "CodedValue") == 0)
     129             :             {
     130             :                 OGRCodedValue cv;
     131       17009 :                 cv.pszCode = CPLStrdup(CPLGetXMLValue(psIter, "Code", ""));
     132       17009 :                 cv.pszValue = CPLStrdup(CPLGetXMLValue(psIter, "Name", ""));
     133       17009 :                 asValues.emplace_back(cv);
     134             :             }
     135             :         }
     136        2146 :         domain.reset(new OGRCodedFieldDomain(pszName, pszDescription,
     137             :                                              eFieldType, eSubType,
     138        2146 :                                              std::move(asValues)));
     139             :     }
     140          21 :     else if (bIsRangeDomain || strcmp(pszType, "esri:RangeDomain") == 0)
     141             :     {
     142          21 :         if (eFieldType != OFTInteger && eFieldType != OFTInteger64 &&
     143           9 :             eFieldType != OFTReal && eFieldType != OFTDateTime)
     144             :         {
     145           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     146             :                      "Unsupported field type for range domain: %s",
     147             :                      pszFieldType);
     148           0 :             return nullptr;
     149             :         }
     150          21 :         const char *pszMinValue = CPLGetXMLValue(psDomain, "MinValue", "");
     151          21 :         const char *pszMaxValue = CPLGetXMLValue(psDomain, "MaxValue", "");
     152             :         OGRField sMin;
     153             :         OGRField sMax;
     154          21 :         OGR_RawField_SetUnset(&sMin);
     155          21 :         OGR_RawField_SetUnset(&sMax);
     156          21 :         if (eFieldType == OFTInteger)
     157             :         {
     158          12 :             sMin.Integer = atoi(pszMinValue);
     159          12 :             sMax.Integer = atoi(pszMaxValue);
     160             :         }
     161           9 :         else if (eFieldType == OFTInteger64)
     162             :         {
     163           0 :             sMin.Integer64 = CPLAtoGIntBig(pszMinValue);
     164           0 :             sMax.Integer64 = CPLAtoGIntBig(pszMaxValue);
     165             :         }
     166           9 :         else if (eFieldType == OFTReal)
     167             :         {
     168           0 :             sMin.Real = CPLAtof(pszMinValue);
     169           0 :             sMax.Real = CPLAtof(pszMaxValue);
     170             :         }
     171           9 :         else if (eFieldType == OFTDateTime)
     172             :         {
     173           9 :             if (!OGRParseXMLDateTime(pszMinValue, &sMin))
     174             :             {
     175           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Invalid MinValue: %s",
     176             :                          pszMinValue);
     177           0 :                 return nullptr;
     178             :             }
     179           9 :             if (!OGRParseXMLDateTime(pszMaxValue, &sMax))
     180             :             {
     181           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Invalid MaxValue: %s",
     182             :                          pszMaxValue);
     183           0 :                 return nullptr;
     184             :             }
     185             :         }
     186          42 :         domain.reset(new OGRRangeFieldDomain(pszName, pszDescription,
     187             :                                              eFieldType, eSubType, sMin, true,
     188          42 :                                              sMax, true));
     189             :     }
     190             :     else
     191             :     {
     192           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     193             :                  "Unsupported type of File Geodatabase domain: %s", pszType);
     194           0 :         return nullptr;
     195             :     }
     196             : 
     197             :     const char *pszMergePolicy =
     198        1094 :         CPLGetXMLValue(psDomain, "MergePolicy", "esriMPTDefaultValue");
     199        1094 :     if (EQUAL(pszMergePolicy, "esriMPTDefaultValue"))
     200             :     {
     201        1094 :         domain->SetMergePolicy(OFDMP_DEFAULT_VALUE);
     202             :     }
     203           0 :     else if (EQUAL(pszMergePolicy, "esriMPTSumValues"))
     204             :     {
     205           0 :         domain->SetMergePolicy(OFDMP_SUM);
     206             :     }
     207           0 :     else if (EQUAL(pszMergePolicy, "esriMPTAreaWeighted"))
     208             :     {
     209           0 :         domain->SetMergePolicy(OFDMP_GEOMETRY_WEIGHTED);
     210             :     }
     211             : 
     212             :     const char *pszSplitPolicy =
     213        1094 :         CPLGetXMLValue(psDomain, "SplitPolicy", "esriSPTDefaultValue");
     214        1094 :     if (EQUAL(pszSplitPolicy, "esriSPTDefaultValue"))
     215             :     {
     216        1086 :         domain->SetSplitPolicy(OFDSP_DEFAULT_VALUE);
     217             :     }
     218           8 :     else if (EQUAL(pszSplitPolicy, "esriSPTDuplicate"))
     219             :     {
     220           8 :         domain->SetSplitPolicy(OFDSP_DUPLICATE);
     221             :     }
     222           0 :     else if (EQUAL(pszSplitPolicy, "esriSPTGeometryRatio"))
     223             :     {
     224           0 :         domain->SetSplitPolicy(OFDSP_GEOMETRY_RATIO);
     225             :     }
     226             : 
     227        1094 :     return domain;
     228             : }
     229             : 
     230             : /************************************************************************/
     231             : /*                      BuildXMLFieldDomainDef()                        */
     232             : /************************************************************************/
     233             : 
     234          15 : inline std::string BuildXMLFieldDomainDef(const OGRFieldDomain *poDomain,
     235             :                                           bool bForFileGDBSDK,
     236             :                                           std::string &failureReason)
     237             : {
     238          30 :     std::string osNS = "esri";
     239          15 :     const char *pszRootElt = "esri:Domain";
     240          15 :     if (!bForFileGDBSDK)
     241             :     {
     242           7 :         switch (poDomain->GetDomainType())
     243             :         {
     244           4 :             case OFDT_CODED:
     245             :             {
     246           4 :                 pszRootElt = "typens:GPCodedValueDomain2";
     247           4 :                 break;
     248             :             }
     249             : 
     250           3 :             case OFDT_RANGE:
     251             :             {
     252           3 :                 pszRootElt = "typens:GPRangeDomain2";
     253           3 :                 break;
     254             :             }
     255             : 
     256           0 :             case OFDT_GLOB:
     257             :             {
     258             :                 failureReason =
     259           0 :                     "Glob field domain not handled for FileGeoDatabase";
     260           0 :                 return std::string();
     261             :             }
     262             :         }
     263           7 :         osNS = "typens";
     264             :     }
     265             : 
     266          30 :     CPLXMLTreeCloser oTree(CPLCreateXMLNode(nullptr, CXT_Element, pszRootElt));
     267          15 :     CPLXMLNode *psRoot = oTree.get();
     268             : 
     269          15 :     switch (poDomain->GetDomainType())
     270             :     {
     271           9 :         case OFDT_CODED:
     272             :         {
     273           9 :             CPLAddXMLAttributeAndValue(psRoot, "xsi:type",
     274             :                                        bForFileGDBSDK
     275             :                                            ? "esri:CodedValueDomain"
     276             :                                            : "typens:GPCodedValueDomain2");
     277           9 :             break;
     278             :         }
     279             : 
     280           6 :         case OFDT_RANGE:
     281             :         {
     282           6 :             CPLAddXMLAttributeAndValue(
     283             :                 psRoot, "xsi:type",
     284             :                 bForFileGDBSDK ? "esri:RangeDomain" : "typens:GPRangeDomain2");
     285           6 :             break;
     286             :         }
     287             : 
     288           0 :         case OFDT_GLOB:
     289             :         {
     290           0 :             failureReason = "Glob field domain not handled for FileGeoDatabase";
     291           0 :             return std::string();
     292             :         }
     293             :     }
     294             : 
     295          15 :     CPLAddXMLAttributeAndValue(psRoot, "xmlns:xsi",
     296             :                                "http://www.w3.org/2001/XMLSchema-instance");
     297          15 :     CPLAddXMLAttributeAndValue(psRoot, "xmlns:xs",
     298             :                                "http://www.w3.org/2001/XMLSchema");
     299          15 :     CPLAddXMLAttributeAndValue(psRoot, ("xmlns:" + osNS).c_str(),
     300             :                                "http://www.esri.com/schemas/ArcGIS/10.1");
     301             : 
     302          15 :     CPLCreateXMLElementAndValue(psRoot, "DomainName",
     303          15 :                                 poDomain->GetName().c_str());
     304          15 :     if (poDomain->GetFieldType() == OFTInteger)
     305             :     {
     306          14 :         if (poDomain->GetFieldSubType() == OFSTInt16)
     307           6 :             CPLCreateXMLElementAndValue(psRoot, "FieldType",
     308             :                                         "esriFieldTypeSmallInteger");
     309             :         else
     310           8 :             CPLCreateXMLElementAndValue(psRoot, "FieldType",
     311             :                                         "esriFieldTypeInteger");
     312             :     }
     313           1 :     else if (poDomain->GetFieldType() == OFTReal)
     314             :     {
     315           0 :         if (poDomain->GetFieldSubType() == OFSTFloat32)
     316           0 :             CPLCreateXMLElementAndValue(psRoot, "FieldType",
     317             :                                         "esriFieldTypeSingle");
     318             :         else
     319           0 :             CPLCreateXMLElementAndValue(psRoot, "FieldType",
     320             :                                         "esriFieldTypeDouble");
     321             :     }
     322           1 :     else if (poDomain->GetFieldType() == OFTString)
     323             :     {
     324           0 :         CPLCreateXMLElementAndValue(psRoot, "FieldType", "esriFieldTypeString");
     325             :     }
     326           1 :     else if (poDomain->GetFieldType() == OFTDateTime)
     327             :     {
     328           1 :         CPLCreateXMLElementAndValue(psRoot, "FieldType", "esriFieldTypeDate");
     329             :     }
     330             :     else
     331             :     {
     332           0 :         failureReason = "Unsupported field type for FileGeoDatabase domain";
     333           0 :         return std::string();
     334             :     }
     335             : 
     336          15 :     switch (poDomain->GetMergePolicy())
     337             :     {
     338          15 :         case OFDMP_DEFAULT_VALUE:
     339          15 :             CPLCreateXMLElementAndValue(psRoot, "MergePolicy",
     340             :                                         "esriMPTDefaultValue");
     341          15 :             break;
     342           0 :         case OFDMP_SUM:
     343           0 :             CPLCreateXMLElementAndValue(psRoot, "MergePolicy",
     344             :                                         "esriMPTSumValues");
     345           0 :             break;
     346           0 :         case OFDMP_GEOMETRY_WEIGHTED:
     347           0 :             CPLCreateXMLElementAndValue(psRoot, "MergePolicy",
     348             :                                         "esriMPTAreaWeighted");
     349           0 :             break;
     350             :     }
     351             : 
     352          15 :     switch (poDomain->GetSplitPolicy())
     353             :     {
     354          15 :         case OFDSP_DEFAULT_VALUE:
     355          15 :             CPLCreateXMLElementAndValue(psRoot, "SplitPolicy",
     356             :                                         "esriSPTDefaultValue");
     357          15 :             break;
     358           0 :         case OFDSP_DUPLICATE:
     359           0 :             CPLCreateXMLElementAndValue(psRoot, "SplitPolicy",
     360             :                                         "esriSPTDuplicate");
     361           0 :             break;
     362           0 :         case OFDSP_GEOMETRY_RATIO:
     363           0 :             CPLCreateXMLElementAndValue(psRoot, "SplitPolicy",
     364             :                                         "esriSPTGeometryRatio");
     365           0 :             break;
     366             :     }
     367             : 
     368          15 :     CPLCreateXMLElementAndValue(psRoot, "Description",
     369          15 :                                 poDomain->GetDescription().c_str());
     370          15 :     CPLCreateXMLElementAndValue(psRoot, "Owner", "");
     371             : 
     372          76 :     const auto AddFieldTypeAsXSIType = [&poDomain](CPLXMLNode *psParent)
     373             :     {
     374          36 :         if (poDomain->GetFieldType() == OFTInteger)
     375             :         {
     376          34 :             if (poDomain->GetFieldSubType() == OFSTInt16)
     377          12 :                 CPLAddXMLAttributeAndValue(psParent, "xsi:type", "xs:short");
     378             :             else
     379          22 :                 CPLAddXMLAttributeAndValue(psParent, "xsi:type", "xs:int");
     380             :         }
     381           2 :         else if (poDomain->GetFieldType() == OFTReal)
     382             :         {
     383           0 :             if (poDomain->GetFieldSubType() == OFSTFloat32)
     384           0 :                 CPLAddXMLAttributeAndValue(psParent, "xsi:type", "xs:float");
     385             :             else
     386           0 :                 CPLAddXMLAttributeAndValue(psParent, "xsi:type", "xs:double");
     387             :         }
     388           2 :         else if (poDomain->GetFieldType() == OFTString)
     389             :         {
     390           0 :             CPLAddXMLAttributeAndValue(psParent, "xsi:type", "xs:string");
     391             :         }
     392           2 :         else if (poDomain->GetFieldType() == OFTDateTime)
     393             :         {
     394           2 :             CPLAddXMLAttributeAndValue(psParent, "xsi:type", "xs:dateTime");
     395             :         }
     396          51 :     };
     397             : 
     398          15 :     switch (poDomain->GetDomainType())
     399             :     {
     400           9 :         case OFDT_CODED:
     401             :         {
     402             :             auto psCodedValues =
     403           9 :                 CPLCreateXMLNode(psRoot, CXT_Element, "CodedValues");
     404           9 :             CPLAddXMLAttributeAndValue(psCodedValues, "xsi:type",
     405          18 :                                        (osNS + ":ArrayOfCodedValue").c_str());
     406             : 
     407             :             auto poCodedDomain =
     408           9 :                 cpl::down_cast<const OGRCodedFieldDomain *>(poDomain);
     409             :             const OGRCodedValue *psEnumeration =
     410           9 :                 poCodedDomain->GetEnumeration();
     411          33 :             for (; psEnumeration->pszCode != nullptr; ++psEnumeration)
     412             :             {
     413             :                 auto psCodedValue =
     414          24 :                     CPLCreateXMLNode(psCodedValues, CXT_Element, "CodedValue");
     415          24 :                 CPLAddXMLAttributeAndValue(psCodedValue, "xsi:type",
     416          48 :                                            (osNS + ":CodedValue").c_str());
     417          24 :                 CPLCreateXMLElementAndValue(
     418             :                     psCodedValue, "Name",
     419          24 :                     psEnumeration->pszValue ? psEnumeration->pszValue : "");
     420             : 
     421             :                 auto psCode =
     422          24 :                     CPLCreateXMLNode(psCodedValue, CXT_Element, "Code");
     423          24 :                 AddFieldTypeAsXSIType(psCode);
     424          24 :                 CPLCreateXMLNode(psCode, CXT_Text, psEnumeration->pszCode);
     425             :             }
     426           9 :             break;
     427             :         }
     428             : 
     429           6 :         case OFDT_RANGE:
     430             :         {
     431             :             auto poRangeDomain =
     432           6 :                 cpl::down_cast<const OGRRangeFieldDomain *>(poDomain);
     433             : 
     434             :             const auto SerializeMinOrMax =
     435          12 :                 [&AddFieldTypeAsXSIType, &poDomain,
     436          42 :                  psRoot](const char *pszElementName, const OGRField &oValue)
     437             :             {
     438          12 :                 if (!OGR_RawField_IsUnset(&oValue))
     439             :                 {
     440             :                     auto psValue =
     441          12 :                         CPLCreateXMLNode(psRoot, CXT_Element, pszElementName);
     442          12 :                     AddFieldTypeAsXSIType(psValue);
     443          12 :                     if (poDomain->GetFieldType() == OFTInteger)
     444             :                     {
     445          10 :                         CPLCreateXMLNode(psValue, CXT_Text,
     446          10 :                                          CPLSPrintf("%d", oValue.Integer));
     447             :                     }
     448           2 :                     else if (poDomain->GetFieldType() == OFTReal)
     449             :                     {
     450           0 :                         CPLCreateXMLNode(psValue, CXT_Text,
     451           0 :                                          CPLSPrintf("%.18g", oValue.Real));
     452             :                     }
     453           2 :                     else if (poDomain->GetFieldType() == OFTString)
     454             :                     {
     455           0 :                         CPLCreateXMLNode(psValue, CXT_Text, oValue.String);
     456             :                     }
     457           2 :                     else if (poDomain->GetFieldType() == OFTDateTime)
     458             :                     {
     459           2 :                         CPLCreateXMLNode(
     460             :                             psValue, CXT_Text,
     461             :                             CPLSPrintf(
     462             :                                 "%04d-%02d-%02dT%02d:%02d:%02d",
     463           2 :                                 oValue.Date.Year, oValue.Date.Month,
     464           2 :                                 oValue.Date.Day, oValue.Date.Hour,
     465           2 :                                 oValue.Date.Minute,
     466           2 :                                 static_cast<int>(oValue.Date.Second + 0.5)));
     467             :                     }
     468             :                 }
     469          18 :             };
     470             : 
     471           6 :             bool bIsInclusiveOut = false;
     472           6 :             const OGRField &oMax = poRangeDomain->GetMax(bIsInclusiveOut);
     473           6 :             SerializeMinOrMax("MaxValue", oMax);
     474             : 
     475           6 :             bIsInclusiveOut = false;
     476           6 :             const OGRField &oMin = poRangeDomain->GetMin(bIsInclusiveOut);
     477           6 :             SerializeMinOrMax("MinValue", oMin);
     478             : 
     479           6 :             break;
     480             :         }
     481             : 
     482           0 :         case OFDT_GLOB:
     483             :         {
     484           0 :             CPLAssert(false);
     485             :             break;
     486             :         }
     487             :     }
     488             : 
     489          15 :     char *pszXML = CPLSerializeXMLTree(oTree.get());
     490          30 :     const std::string osXML(pszXML);
     491          15 :     CPLFree(pszXML);
     492          15 :     return osXML;
     493             : }
     494             : 
     495             : #endif  // FILEGDB_FIELDDOMAIN_H

Generated by: LCOV version 1.14