LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/jml - ogrjmllayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 384 422 91.0 %
Date: 2026-10-23 13:59:38 Functions: 20 20 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  JML Translator
       4             :  * Purpose:  Implements OGRJMLLayer class.
       5             :  *
       6             :  ******************************************************************************
       7             :  * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
       8             :  *
       9             :  * SPDX-License-Identifier: MIT
      10             :  ****************************************************************************/
      11             : 
      12             : #include "cpl_conv.h"
      13             : #include "ogr_jml.h"
      14             : #include "ogr_p.h"
      15             : 
      16             : #ifdef HAVE_EXPAT
      17             : 
      18             : constexpr int PARSER_BUF_SIZE = 8192;
      19             : 
      20             : /************************************************************************/
      21             : /*                            OGRJMLLayer()                             */
      22             : /************************************************************************/
      23             : 
      24          42 : OGRJMLLayer::OGRJMLLayer(const char *pszLayerName, OGRJMLDataset *poDSIn,
      25          42 :                          VSILFILE *fpIn)
      26          42 :     : m_poDS(poDSIn), poFeatureDefn(new OGRFeatureDefn(pszLayerName)),
      27             :       nNextFID(0), fp(fpIn), bHasReadSchema(false), currentDepth(0),
      28             :       bStopParsing(false), nWithoutEventCounter(0), nDataHandlerCounter(0),
      29             :       bAccumulateElementValue(false),
      30          84 :       pszElementValue(static_cast<char *>(CPLCalloc(1024, 1))),
      31             :       nElementValueLen(0), nElementValueAlloc(1024), poFeature(nullptr),
      32             :       ppoFeatureTab(nullptr), nFeatureTabLength(0), nFeatureTabIndex(0),
      33             :       bSchemaFinished(false), nJCSGMLInputTemplateDepth(0),
      34             :       nCollectionElementDepth(0), nFeatureCollectionDepth(0),
      35             :       nFeatureElementDepth(0), nGeometryElementDepth(0), nColumnDepth(0),
      36             :       nNameDepth(0), nTypeDepth(0), nAttributeElementDepth(0), iAttr(-1),
      37          84 :       iRGBField(-1)
      38             : {
      39          42 :     SetDescription(poFeatureDefn->GetName());
      40          42 :     poFeatureDefn->Reference();
      41          42 : }
      42             : 
      43             : /************************************************************************/
      44             : /*                            ~OGRJMLLayer()                            */
      45             : /************************************************************************/
      46             : 
      47          84 : OGRJMLLayer::~OGRJMLLayer()
      48             : 
      49             : {
      50          42 :     poFeatureDefn->Release();
      51             : 
      52          42 :     CPLFree(pszElementValue);
      53             : 
      54          42 :     for (int i = nFeatureTabIndex; i < nFeatureTabLength; i++)
      55           0 :         delete ppoFeatureTab[i];
      56          42 :     CPLFree(ppoFeatureTab);
      57             : 
      58          42 :     if (poFeature)
      59           0 :         delete poFeature;
      60          84 : }
      61             : 
      62             : /************************************************************************/
      63             : /*                            GetLayerDefn()                            */
      64             : /************************************************************************/
      65             : 
      66         346 : const OGRFeatureDefn *OGRJMLLayer::GetLayerDefn() const
      67             : {
      68         346 :     if (!bHasReadSchema)
      69           8 :         const_cast<OGRJMLLayer *>(this)->LoadSchema();
      70             : 
      71         346 :     return poFeatureDefn;
      72             : }
      73             : 
      74        5518 : static void XMLCALL startElementCbk(void *pUserData, const char *pszName,
      75             :                                     const char **ppszAttr)
      76             : {
      77        5518 :     static_cast<OGRJMLLayer *>(pUserData)->startElementCbk(pszName, ppszAttr);
      78        5518 : }
      79             : 
      80        5518 : static void XMLCALL endElementCbk(void *pUserData, const char *pszName)
      81             : {
      82        5518 :     static_cast<OGRJMLLayer *>(pUserData)->endElementCbk(pszName);
      83        5518 : }
      84             : 
      85       16885 : static void XMLCALL dataHandlerCbk(void *pUserData, const char *data, int nLen)
      86             : {
      87       16885 :     static_cast<OGRJMLLayer *>(pUserData)->dataHandlerCbk(data, nLen);
      88       16885 : }
      89             : 
      90             : /************************************************************************/
      91             : /*                            ResetReading()                            */
      92             : /************************************************************************/
      93             : 
      94         124 : void OGRJMLLayer::ResetReading()
      95             : 
      96             : {
      97         124 :     nNextFID = 0;
      98             : 
      99         124 :     VSIFSeekL(fp, 0, SEEK_SET);
     100         124 :     VSIFClearErrL(fp);
     101             : 
     102         124 :     poParser.reset(OGRCreateExpatXMLParser());
     103         124 :     XML_SetElementHandler(poParser.get(), ::startElementCbk, ::endElementCbk);
     104         124 :     XML_SetCharacterDataHandler(poParser.get(), ::dataHandlerCbk);
     105         124 :     XML_SetUserData(poParser.get(), this);
     106             : 
     107         148 :     for (int i = nFeatureTabIndex; i < nFeatureTabLength; i++)
     108          24 :         delete ppoFeatureTab[i];
     109         124 :     nFeatureTabIndex = 0;
     110         124 :     nFeatureTabLength = 0;
     111         124 :     delete poFeature;
     112         124 :     poFeature = nullptr;
     113             : 
     114         124 :     currentDepth = 0;
     115             : 
     116         124 :     nCollectionElementDepth = 0;
     117         124 :     nFeatureElementDepth = 0;
     118         124 :     nGeometryElementDepth = 0;
     119         124 :     nAttributeElementDepth = 0;
     120         124 :     iAttr = -1;
     121             : 
     122         124 :     bAccumulateElementValue = false;
     123         124 :     nElementValueLen = 0;
     124         124 :     pszElementValue[0] = '\0';
     125         124 : }
     126             : 
     127             : /************************************************************************/
     128             : /*                          startElementCbk()                           */
     129             : /************************************************************************/
     130             : 
     131        5518 : void OGRJMLLayer::startElementCbk(const char *pszName, const char **ppszAttr)
     132             : {
     133        5518 :     if (bStopParsing)
     134           0 :         return;
     135             : 
     136        5518 :     nWithoutEventCounter = 0;
     137             : 
     138        1408 :     if (nFeatureElementDepth > 0 && nAttributeElementDepth == 0 &&
     139        6926 :         nGeometryElementDepth == 0 && osGeometryElement.compare(pszName) == 0)
     140             :     {
     141         163 :         nGeometryElementDepth = currentDepth;
     142         163 :         bAccumulateElementValue = true;
     143             :     }
     144        5355 :     else if (nFeatureElementDepth > 0 && nAttributeElementDepth == 0 &&
     145        1245 :              nGeometryElementDepth == 0)
     146             :     {
     147             :         /* We assume that attributes are present in the order they are */
     148             :         /* declared, so as a first guess, we can try the aoColumns[iAttr + 1] */
     149         919 :         int i = (iAttr + 1 < poFeatureDefn->GetFieldCount()) ? -1 : 0;
     150        4807 :         for (; i < static_cast<int>(aoColumns.size()); i++)
     151             :         {
     152             :             const OGRJMLColumn &oColumn =
     153        4590 :                 (i < 0) ? aoColumns[iAttr + 1] : aoColumns[i];
     154        4590 :             if (oColumn.osElementName != pszName)
     155        3456 :                 continue;
     156             : 
     157        1134 :             if (oColumn.bIsBody)
     158             :             {
     159        2106 :                 if (!oColumn.osAttributeName.empty() && ppszAttr != nullptr &&
     160        2052 :                     ppszAttr[0] != nullptr && ppszAttr[1] != nullptr &&
     161        3132 :                     oColumn.osAttributeName.compare(ppszAttr[0]) == 0 &&
     162        1026 :                     oColumn.osAttributeValue.compare(ppszAttr[1]) == 0)
     163             :                 {
     164             :                     /* <osElementName
     165             :                      * osAttributeName="osAttributeValue">value</osElementName>
     166             :                      */
     167             : 
     168         594 :                     bAccumulateElementValue = true;
     169         594 :                     nAttributeElementDepth = currentDepth;
     170         594 :                     iAttr = (i < 0) ? iAttr + 1 : i;
     171         594 :                     break;
     172             :                 }
     173         486 :                 else if (oColumn.osAttributeName.empty())
     174             :                 {
     175             :                     /* <osElementName>value</osElementName> */
     176             : 
     177          54 :                     bAccumulateElementValue = true;
     178          54 :                     nAttributeElementDepth = currentDepth;
     179          54 :                     iAttr = (i < 0) ? iAttr + 1 : i;
     180          54 :                     break;
     181             :                 }
     182             :             }
     183         108 :             else if (!oColumn.osAttributeName.empty() && ppszAttr != nullptr &&
     184         162 :                      ppszAttr[0] != nullptr && ppszAttr[1] != nullptr &&
     185          54 :                      oColumn.osAttributeName.compare(ppszAttr[0]) == 0)
     186             :             {
     187             :                 /* <osElementName osAttributeName="value"></osElementName> */
     188             : 
     189          54 :                 AddStringToElementValue(ppszAttr[1], (int)strlen(ppszAttr[1]));
     190             : 
     191          54 :                 nAttributeElementDepth = currentDepth;
     192          54 :                 iAttr = (i < 0) ? iAttr + 1 : i;
     193          54 :                 break;
     194             :             }
     195         919 :         }
     196             :     }
     197        4436 :     else if (nGeometryElementDepth > 0)
     198             :     {
     199         326 :         AddStringToElementValue("<", 1);
     200         326 :         AddStringToElementValue(pszName, (int)strlen(pszName));
     201             : 
     202         326 :         const char **papszIter = ppszAttr;
     203         380 :         while (papszIter && *papszIter != nullptr)
     204             :         {
     205          54 :             AddStringToElementValue(" ", 1);
     206          54 :             AddStringToElementValue(papszIter[0], (int)strlen(papszIter[0]));
     207          54 :             AddStringToElementValue("=\"", 2);
     208          54 :             AddStringToElementValue(papszIter[1], (int)strlen(papszIter[1]));
     209          54 :             AddStringToElementValue("\"", 1);
     210          54 :             papszIter += 2;
     211             :         }
     212             : 
     213         326 :         AddStringToElementValue(">", 1);
     214             :     }
     215        4439 :     else if (nFeatureCollectionDepth > 0 && nFeatureElementDepth == 0 &&
     216         329 :              osFeatureElement.compare(pszName) == 0)
     217             :     {
     218         164 :         nFeatureElementDepth = currentDepth;
     219         164 :         poFeature = new OGRFeature(poFeatureDefn);
     220             :     }
     221        7727 :     else if (nFeatureCollectionDepth == 0 &&
     222        3781 :              osCollectionElement.compare(pszName) == 0)
     223             :     {
     224          56 :         nFeatureCollectionDepth = currentDepth;
     225             :     }
     226             : 
     227        5518 :     currentDepth++;
     228             : }
     229             : 
     230             : /************************************************************************/
     231             : /*                           StopAccumulate()                           */
     232             : /************************************************************************/
     233             : 
     234        1004 : void OGRJMLLayer::StopAccumulate()
     235             : {
     236        1004 :     bAccumulateElementValue = false;
     237        1004 :     nElementValueLen = 0;
     238        1004 :     pszElementValue[0] = '\0';
     239        1004 : }
     240             : 
     241             : /************************************************************************/
     242             : /*                           endElementCbk()                            */
     243             : /************************************************************************/
     244             : 
     245        5518 : void OGRJMLLayer::endElementCbk(const char *pszName)
     246             : {
     247        5518 :     if (bStopParsing)
     248           0 :         return;
     249             : 
     250        5518 :     nWithoutEventCounter = 0;
     251             : 
     252        5518 :     currentDepth--;
     253             : 
     254        5518 :     if (nAttributeElementDepth == currentDepth)
     255             :     {
     256         758 :         if (nElementValueLen)
     257         648 :             poFeature->SetField(iAttr, pszElementValue);
     258         110 :         else if (iAttr >= 0)
     259          54 :             poFeature->SetFieldNull(iAttr);
     260         758 :         nAttributeElementDepth = 0;
     261         758 :         StopAccumulate();
     262             :     }
     263        4760 :     else if (nGeometryElementDepth > 0 && currentDepth > nGeometryElementDepth)
     264             :     {
     265         326 :         AddStringToElementValue("</", 2);
     266         326 :         AddStringToElementValue(pszName, static_cast<int>(strlen(pszName)));
     267         326 :         AddStringToElementValue(">", 1);
     268             :     }
     269        4434 :     else if (nGeometryElementDepth == currentDepth)
     270             :     {
     271         163 :         if (nElementValueLen)
     272             :         {
     273             :             OGRGeometry *poGeom =
     274         109 :                 OGRGeometry::FromHandle(OGR_G_CreateFromGML(pszElementValue));
     275         218 :             if (poGeom != nullptr &&
     276         109 :                 poGeom->getGeometryType() == wkbGeometryCollection &&
     277           0 :                 poGeom->IsEmpty())
     278             :             {
     279           0 :                 delete poGeom;
     280             :             }
     281             :             else
     282         109 :                 poFeature->SetGeometryDirectly(poGeom);
     283             :         }
     284             : 
     285         163 :         nGeometryElementDepth = 0;
     286         163 :         StopAccumulate();
     287             :     }
     288        4271 :     else if (nFeatureElementDepth == currentDepth)
     289             :     {
     290             :         /* Builds a style string from R_G_B if we don't already have a */
     291             :         /* style string */
     292         164 :         OGRGeometry *poGeom = poFeature->GetGeometryRef();
     293         164 :         unsigned int R = 0;
     294         164 :         unsigned int G = 0;
     295         164 :         unsigned int B = 0;
     296         162 :         if (iRGBField >= 0 && poFeature->IsFieldSetAndNotNull(iRGBField) &&
     297         434 :             poFeature->GetStyleString() == nullptr && poGeom != nullptr &&
     298         108 :             sscanf(poFeature->GetFieldAsString(iRGBField), "%02X%02X%02X", &R,
     299             :                    &G, &B) == 3)
     300             :         {
     301             :             const OGRwkbGeometryType eGeomType =
     302         108 :                 wkbFlatten(poGeom->getGeometryType());
     303         108 :             if (eGeomType == wkbPoint || eGeomType == wkbMultiPoint ||
     304          54 :                 eGeomType == wkbLineString || eGeomType == wkbMultiLineString)
     305             :             {
     306          54 :                 poFeature->SetStyleString(
     307          54 :                     CPLSPrintf("PEN(c:#%02X%02X%02X)", R, G, B));
     308             :             }
     309          54 :             else if (eGeomType == wkbPolygon || eGeomType == wkbMultiPolygon)
     310             :             {
     311          54 :                 poFeature->SetStyleString(
     312          54 :                     CPLSPrintf("BRUSH(fc:#%02X%02X%02X)", R, G, B));
     313             :             }
     314             :         }
     315             : 
     316         164 :         poFeature->SetFID(nNextFID++);
     317             : 
     318         310 :         if ((m_poFilterGeom == nullptr || FilterGeometry(poGeom)) &&
     319         146 :             (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
     320             :         {
     321         238 :             ppoFeatureTab = static_cast<OGRFeature **>(CPLRealloc(
     322         119 :                 ppoFeatureTab, sizeof(OGRFeature *) * (nFeatureTabLength + 1)));
     323         119 :             ppoFeatureTab[nFeatureTabLength] = poFeature;
     324         119 :             nFeatureTabLength++;
     325             :         }
     326             :         else
     327             :         {
     328          45 :             delete poFeature;
     329             :         }
     330         164 :         poFeature = nullptr;
     331         164 :         iAttr = -1;
     332             : 
     333         164 :         nFeatureElementDepth = 0;
     334             :     }
     335        4107 :     else if (nFeatureCollectionDepth == currentDepth)
     336             :     {
     337          56 :         nFeatureCollectionDepth = 0;
     338             :     }
     339             : }
     340             : 
     341             : /************************************************************************/
     342             : /*                      AddStringToElementValue()                       */
     343             : /************************************************************************/
     344             : 
     345        3995 : void OGRJMLLayer::AddStringToElementValue(const char *data, int nLen)
     346             : {
     347        3995 :     if (nLen > INT_MAX - nElementValueLen - 1 - 1000)
     348             :     {
     349           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
     350             :                  "Too much data in a single element");
     351           0 :         XML_StopParser(poParser.get(), XML_FALSE);
     352           0 :         bStopParsing = true;
     353           0 :         return;
     354             :     }
     355        3995 :     if (nElementValueLen + nLen + 1 > nElementValueAlloc)
     356             :     {
     357           0 :         char *pszNewElementValue = static_cast<char *>(VSI_REALLOC_VERBOSE(
     358             :             pszElementValue, nElementValueLen + nLen + 1 + 1000));
     359           0 :         if (pszNewElementValue == nullptr)
     360             :         {
     361           0 :             XML_StopParser(poParser.get(), XML_FALSE);
     362           0 :             bStopParsing = true;
     363           0 :             return;
     364             :         }
     365           0 :         nElementValueAlloc = nElementValueLen + nLen + 1 + 1000;
     366           0 :         pszElementValue = pszNewElementValue;
     367             :     }
     368        3995 :     memcpy(pszElementValue + nElementValueLen, data, nLen);
     369        3995 :     nElementValueLen += nLen;
     370        3995 :     pszElementValue[nElementValueLen] = '\0';
     371             : }
     372             : 
     373             : /************************************************************************/
     374             : /*                           dataHandlerCbk()                           */
     375             : /************************************************************************/
     376             : 
     377       16885 : void OGRJMLLayer::dataHandlerCbk(const char *data, int nLen)
     378             : {
     379       16885 :     if (bStopParsing)
     380           0 :         return;
     381             : 
     382       16885 :     nDataHandlerCounter++;
     383       16885 :     if (nDataHandlerCounter >= PARSER_BUF_SIZE)
     384             :     {
     385           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     386             :                  "File probably corrupted (million laugh pattern)");
     387           0 :         XML_StopParser(poParser.get(), XML_FALSE);
     388           0 :         bStopParsing = true;
     389           0 :         return;
     390             :     }
     391             : 
     392       16885 :     nWithoutEventCounter = 0;
     393             : 
     394       16885 :     if (bAccumulateElementValue)
     395             :     {
     396        1715 :         AddStringToElementValue(data, nLen);
     397             :     }
     398             : }
     399             : 
     400             : /************************************************************************/
     401             : /*                           GetNextFeature()                           */
     402             : /************************************************************************/
     403             : 
     404         138 : OGRFeature *OGRJMLLayer::GetNextFeature()
     405             : {
     406         138 :     if (!bHasReadSchema)
     407           0 :         LoadSchema();
     408             : 
     409         138 :     if (bStopParsing)
     410           0 :         return nullptr;
     411             : 
     412         138 :     if (nFeatureTabIndex < nFeatureTabLength)
     413             :     {
     414          50 :         return ppoFeatureTab[nFeatureTabIndex++];
     415             :     }
     416             : 
     417          88 :     if (VSIFEofL(fp) || VSIFErrorL(fp))
     418          32 :         return nullptr;
     419             : 
     420          56 :     std::vector<char> aBuf(PARSER_BUF_SIZE);
     421             : 
     422          56 :     this->nFeatureTabLength = 0;
     423          56 :     nFeatureTabIndex = 0;
     424             : 
     425          56 :     nWithoutEventCounter = 0;
     426             : 
     427          56 :     int nDone = 0;
     428           0 :     do
     429             :     {
     430          56 :         nDataHandlerCounter = 0;
     431             :         unsigned int nLen =
     432          56 :             (unsigned int)VSIFReadL(aBuf.data(), 1, aBuf.size(), fp);
     433          56 :         nDone = (nLen < aBuf.size());
     434          56 :         if (XML_Parse(poParser.get(), aBuf.data(), nLen, nDone) ==
     435             :             XML_STATUS_ERROR)
     436             :         {
     437           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     438             :                      "XML parsing of JML file failed: %s",
     439           0 :                      OGRExpatGetParseError(poParser.get()));
     440           0 :             bStopParsing = true;
     441             :         }
     442          56 :         nWithoutEventCounter++;
     443          56 :     } while (!nDone && !bStopParsing && this->nFeatureTabLength == 0 &&
     444           0 :              nWithoutEventCounter < 10);
     445             : 
     446          56 :     if (nWithoutEventCounter == 10)
     447             :     {
     448           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     449             :                  "Too much data inside one element. File probably corrupted");
     450           0 :         bStopParsing = true;
     451             :     }
     452             : 
     453          56 :     return (this->nFeatureTabLength) ? ppoFeatureTab[nFeatureTabIndex++]
     454          56 :                                      : nullptr;
     455             : }
     456             : 
     457         304 : static void XMLCALL startElementLoadSchemaCbk(void *pUserData,
     458             :                                               const char *pszName,
     459             :                                               const char **ppszAttr)
     460             : {
     461         304 :     static_cast<OGRJMLLayer *>(pUserData)->startElementLoadSchemaCbk(pszName,
     462             :                                                                      ppszAttr);
     463         304 : }
     464             : 
     465         296 : static void XMLCALL endElementLoadSchemaCbk(void *pUserData,
     466             :                                             const char *pszName)
     467             : {
     468         296 :     static_cast<OGRJMLLayer *>(pUserData)->endElementLoadSchemaCbk(pszName);
     469         296 : }
     470             : 
     471             : /************************************************************************/
     472             : /*                             LoadSchema()                             */
     473             : /************************************************************************/
     474             : 
     475             : /** This function parses the beginning of the file to detect the fields */
     476           8 : void OGRJMLLayer::LoadSchema()
     477             : {
     478           8 :     if (bHasReadSchema)
     479           0 :         return;
     480             : 
     481           8 :     bHasReadSchema = true;
     482             : 
     483           8 :     poParser.reset(OGRCreateExpatXMLParser());
     484           8 :     XML_SetElementHandler(poParser.get(), ::startElementLoadSchemaCbk,
     485             :                           ::endElementLoadSchemaCbk);
     486           8 :     XML_SetCharacterDataHandler(poParser.get(), ::dataHandlerCbk);
     487           8 :     XML_SetUserData(poParser.get(), this);
     488             : 
     489           8 :     VSIFSeekL(fp, 0, SEEK_SET);
     490             : 
     491          16 :     std::vector<char> aBuf(PARSER_BUF_SIZE);
     492           8 :     int nDone = 0;
     493           0 :     do
     494             :     {
     495           8 :         nDataHandlerCounter = 0;
     496             :         const unsigned int nLen = static_cast<unsigned int>(
     497           8 :             VSIFReadL(aBuf.data(), 1, aBuf.size(), fp));
     498           8 :         nDone = (nLen < aBuf.size());
     499           8 :         if (XML_Parse(poParser.get(), aBuf.data(), nLen, nDone) ==
     500             :             XML_STATUS_ERROR)
     501             :         {
     502           3 :             CPLError(CE_Failure, CPLE_AppDefined,
     503             :                      "XML parsing of JML file failed: %s",
     504           3 :                      OGRExpatGetParseError(poParser.get()));
     505           3 :             bStopParsing = true;
     506             :         }
     507           8 :         nWithoutEventCounter++;
     508           8 :     } while (!nDone && !bStopParsing && !bSchemaFinished &&
     509           0 :              nWithoutEventCounter < 10);
     510             : 
     511           8 :     poParser.reset();
     512             : 
     513           8 :     if (nWithoutEventCounter == 10)
     514             :     {
     515           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     516             :                  "Too much data inside one element. File probably corrupted");
     517           0 :         bStopParsing = true;
     518             :     }
     519             : 
     520          15 :     if (osCollectionElement.empty() || osFeatureElement.empty() ||
     521           7 :         osGeometryElement.empty())
     522             :     {
     523           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     524             :                  "Missing CollectionElement, FeatureElement or "
     525             :                  "GeometryElement");
     526           1 :         bStopParsing = true;
     527             :     }
     528             : 
     529           8 :     if (!osSRSName.empty())
     530             :     {
     531           1 :         if (osSRSName.find("http://www.opengis.net/gml/srs/epsg.xml#") == 0)
     532             :         {
     533           1 :             OGRSpatialReference *poSRS = new OGRSpatialReference();
     534           1 :             poSRS->importFromEPSG(atoi(
     535             :                 osSRSName
     536           2 :                     .substr(strlen("http://www.opengis.net/gml/srs/epsg.xml#"))
     537             :                     .c_str()));
     538           1 :             poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     539           1 :             poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
     540           1 :             poSRS->Release();
     541             :         }
     542             :     }
     543             : 
     544           8 :     nJCSGMLInputTemplateDepth = 0;
     545           8 :     nCollectionElementDepth = 0;
     546           8 :     nFeatureCollectionDepth = 0;
     547           8 :     nFeatureElementDepth = 0;
     548           8 :     nGeometryElementDepth = 0;
     549           8 :     nColumnDepth = 0;
     550           8 :     nNameDepth = 0;
     551           8 :     nTypeDepth = 0;
     552           8 :     nAttributeElementDepth = 0;
     553             : 
     554           8 :     ResetReading();
     555             : }
     556             : 
     557             : /************************************************************************/
     558             : /*                     startElementLoadSchemaCbk()                      */
     559             : /************************************************************************/
     560             : 
     561         304 : void OGRJMLLayer::startElementLoadSchemaCbk(const char *pszName,
     562             :                                             const char **ppszAttr)
     563             : {
     564         304 :     if (bStopParsing)
     565           0 :         return;
     566             : 
     567         304 :     nWithoutEventCounter = 0;
     568             : 
     569         304 :     if (nJCSGMLInputTemplateDepth == 0 &&
     570         111 :         strcmp(pszName, "JCSGMLInputTemplate") == 0)
     571           8 :         nJCSGMLInputTemplateDepth = currentDepth;
     572         296 :     else if (nJCSGMLInputTemplateDepth > 0)
     573             :     {
     574         193 :         if (nCollectionElementDepth == 0 &&
     575         193 :             strcmp(pszName, "CollectionElement") == 0)
     576             :         {
     577           7 :             nCollectionElementDepth = currentDepth;
     578           7 :             bAccumulateElementValue = true;
     579             :         }
     580         186 :         else if (nFeatureElementDepth == 0 &&
     581         186 :                  strcmp(pszName, "FeatureElement") == 0)
     582             :         {
     583           7 :             nFeatureElementDepth = currentDepth;
     584           7 :             bAccumulateElementValue = true;
     585             :         }
     586         179 :         else if (nGeometryElementDepth == 0 &&
     587         179 :                  strcmp(pszName, "GeometryElement") == 0)
     588             :         {
     589           7 :             nGeometryElementDepth = currentDepth;
     590           7 :             bAccumulateElementValue = true;
     591             :         }
     592         172 :         else if (nColumnDepth == 0 && strcmp(pszName, "column") == 0)
     593             :         {
     594          32 :             nColumnDepth = currentDepth;
     595          32 :             oCurColumn.osName = "";
     596          32 :             oCurColumn.osType = "";
     597          32 :             oCurColumn.osElementName = "";
     598          32 :             oCurColumn.osAttributeName = "";
     599          32 :             oCurColumn.osAttributeValue = "";
     600          32 :             oCurColumn.bIsBody = false;
     601             :         }
     602         140 :         else if (nColumnDepth > 0)
     603             :         {
     604         128 :             if (nNameDepth == 0 && strcmp(pszName, "name") == 0)
     605             :             {
     606          31 :                 nNameDepth = currentDepth;
     607          31 :                 bAccumulateElementValue = true;
     608             :             }
     609          97 :             else if (nTypeDepth == 0 && strcmp(pszName, "type") == 0)
     610             :             {
     611          31 :                 nTypeDepth = currentDepth;
     612          31 :                 bAccumulateElementValue = true;
     613             :             }
     614          66 :             else if (strcmp(pszName, "valueElement") == 0)
     615             :             {
     616          31 :                 const char **papszIter = ppszAttr;
     617         115 :                 while (papszIter && *papszIter != nullptr)
     618             :                 {
     619          84 :                     if (strcmp(*papszIter, "elementName") == 0)
     620          30 :                         oCurColumn.osElementName = papszIter[1];
     621          54 :                     else if (strcmp(*papszIter, "attributeName") == 0)
     622          25 :                         oCurColumn.osAttributeName = papszIter[1];
     623          29 :                     else if (strcmp(*papszIter, "attributeValue") == 0)
     624          25 :                         oCurColumn.osAttributeValue = papszIter[1];
     625          84 :                     papszIter += 2;
     626             :                 }
     627             :             }
     628          35 :             else if (strcmp(pszName, "valueLocation") == 0)
     629             :             {
     630          31 :                 const char **papszIter = ppszAttr;
     631          64 :                 while (papszIter && *papszIter != nullptr)
     632             :                 {
     633          33 :                     if (strcmp(*papszIter, "position") == 0)
     634          31 :                         oCurColumn.bIsBody = strcmp(papszIter[1], "body") == 0;
     635           2 :                     else if (strcmp(*papszIter, "attributeName") == 0)
     636           2 :                         oCurColumn.osAttributeName = papszIter[1];
     637          33 :                     papszIter += 2;
     638             :                 }
     639             :             }
     640             :         }
     641             :     }
     642         132 :     else if (nFeatureCollectionDepth == 0 &&
     643          29 :              osCollectionElement.compare(pszName) == 0)
     644             :     {
     645           6 :         nFeatureCollectionDepth = currentDepth;
     646             :     }
     647          97 :     else if (nFeatureCollectionDepth > 0 &&
     648          74 :              currentDepth == nFeatureCollectionDepth + 2 &&
     649          15 :              strcmp(pszName, "gml:Box") == 0)
     650             :     {
     651           1 :         const char **papszIter = ppszAttr;
     652           2 :         while (papszIter && *papszIter != nullptr)
     653             :         {
     654           1 :             if (strcmp(*papszIter, "srsName") == 0)
     655           1 :                 osSRSName = papszIter[1];
     656           1 :             papszIter += 2;
     657             :         }
     658           1 :         bSchemaFinished = true;
     659             :     }
     660         288 :     else if (nFeatureCollectionDepth >= 0 &&
     661         184 :              currentDepth >= nFeatureCollectionDepth + 1 &&
     662          88 :              osFeatureElement.compare(pszName) == 0)
     663             :     {
     664          11 :         bSchemaFinished = true;
     665             :     }
     666             : 
     667         304 :     currentDepth++;
     668             : }
     669             : 
     670             : /************************************************************************/
     671             : /*                      endElementLoadSchemaCbk()                       */
     672             : /************************************************************************/
     673             : 
     674         296 : void OGRJMLLayer::endElementLoadSchemaCbk(const char * /* pszName */)
     675             : {
     676         296 :     if (bStopParsing)
     677           0 :         return;
     678             : 
     679         296 :     nWithoutEventCounter = 0;
     680             : 
     681         296 :     currentDepth--;
     682             : 
     683         296 :     if (nJCSGMLInputTemplateDepth == currentDepth)
     684             :     {
     685          12 :         nJCSGMLInputTemplateDepth = 0;
     686             :     }
     687         284 :     else if (nCollectionElementDepth == currentDepth)
     688             :     {
     689           7 :         nCollectionElementDepth = 0;
     690           7 :         osCollectionElement = pszElementValue;
     691             : #ifdef DEBUG_VERBOSE
     692             :         CPLDebug("JML", "osCollectionElement = %s",
     693             :                  osCollectionElement.c_str());
     694             : #endif
     695           7 :         StopAccumulate();
     696             :     }
     697         277 :     else if (nFeatureElementDepth == currentDepth)
     698             :     {
     699           7 :         nFeatureElementDepth = 0;
     700           7 :         osFeatureElement = pszElementValue;
     701             : #ifdef DEBUG_VERBOSE
     702             :         CPLDebug("JML", "osFeatureElement = %s", osFeatureElement.c_str());
     703             : #endif
     704           7 :         StopAccumulate();
     705             :     }
     706         270 :     else if (nGeometryElementDepth == currentDepth)
     707             :     {
     708           7 :         nGeometryElementDepth = 0;
     709           7 :         osGeometryElement = pszElementValue;
     710             : #ifdef DEBUG_VERBOSE
     711             :         CPLDebug("JML", "osGeometryElement = %s", osGeometryElement.c_str());
     712             : #endif
     713           7 :         StopAccumulate();
     714             :     }
     715         263 :     else if (nColumnDepth == currentDepth)
     716             :     {
     717          32 :         bool bIsOK = true;
     718          32 :         if (oCurColumn.osName.empty())
     719           1 :             bIsOK = false;
     720          32 :         if (oCurColumn.osType.empty())
     721           1 :             bIsOK = false;
     722          32 :         if (oCurColumn.osElementName.empty())
     723           2 :             bIsOK = false;
     724          32 :         if (oCurColumn.bIsBody)
     725             :         {
     726          32 :             if (oCurColumn.osAttributeName.empty() &&
     727           4 :                 !oCurColumn.osAttributeValue.empty())
     728           1 :                 bIsOK = false;
     729          52 :             if (!oCurColumn.osAttributeName.empty() &&
     730          24 :                 oCurColumn.osAttributeValue.empty())
     731           1 :                 bIsOK = false;
     732             :             /* Only 2 valid possibilities : */
     733             :             /* <osElementName
     734             :              * osAttributeName="osAttributeValue">value</osElementName> */
     735             :             /* <osElementName>value</osElementName> */
     736             :         }
     737             :         else
     738             :         {
     739             :             /* <osElementName osAttributeName="value"></osElementName> */
     740           4 :             if (oCurColumn.osAttributeName.empty())
     741           1 :                 bIsOK = false;
     742           4 :             if (!oCurColumn.osAttributeValue.empty())
     743           1 :                 bIsOK = false;
     744             :         }
     745             : 
     746          32 :         if (bIsOK)
     747             :         {
     748          24 :             OGRFieldType eType = OFTString;
     749          24 :             if (EQUAL(oCurColumn.osType, "INTEGER"))
     750           2 :                 eType = OFTInteger;
     751          22 :             else if (EQUAL(oCurColumn.osType, "DOUBLE"))
     752           2 :                 eType = OFTReal;
     753          20 :             else if (EQUAL(oCurColumn.osType, "DATE"))
     754           4 :                 eType = OFTDateTime;
     755          48 :             OGRFieldDefn oField(oCurColumn.osName, eType);
     756             : 
     757          24 :             if (oCurColumn.osName == "R_G_B" && eType == OFTString)
     758           2 :                 iRGBField = poFeatureDefn->GetFieldCount();
     759             : 
     760          24 :             poFeatureDefn->AddFieldDefn(&oField);
     761          24 :             aoColumns.push_back(oCurColumn);
     762             :         }
     763             :         else
     764             :         {
     765           8 :             CPLDebug("JML",
     766             :                      "Invalid column definition: name = %s, type = %s, "
     767             :                      "elementName = %s, attributeName = %s, "
     768             :                      "attributeValue = %s, bIsBody = %d",
     769             :                      oCurColumn.osName.c_str(), oCurColumn.osType.c_str(),
     770             :                      oCurColumn.osElementName.c_str(),
     771             :                      oCurColumn.osAttributeName.c_str(),
     772             :                      oCurColumn.osAttributeValue.c_str(),
     773           8 :                      static_cast<int>(oCurColumn.bIsBody));
     774             :         }
     775             : 
     776          32 :         nColumnDepth = 0;
     777             :     }
     778         231 :     else if (nNameDepth == currentDepth)
     779             :     {
     780          31 :         nNameDepth = 0;
     781          31 :         oCurColumn.osName = pszElementValue;
     782             : #ifdef DEBUG_VERBOSE
     783             :         CPLDebug("JML", "oCurColumn.osName = %s", oCurColumn.osName.c_str());
     784             : #endif
     785          31 :         StopAccumulate();
     786             :     }
     787         200 :     else if (nTypeDepth == currentDepth)
     788             :     {
     789          31 :         nTypeDepth = 0;
     790          31 :         oCurColumn.osType = pszElementValue;
     791             : #ifdef DEBUG_VERBOSE
     792             :         CPLDebug("JML", "oCurColumn.osType = %s", oCurColumn.osType.c_str());
     793             : #endif
     794          31 :         StopAccumulate();
     795             :     }
     796             : }
     797             : 
     798             : /************************************************************************/
     799             : /*                           TestCapability()                           */
     800             : /************************************************************************/
     801             : 
     802          37 : bool OGRJMLLayer::TestCapability(const char *pszCap) const
     803             : 
     804             : {
     805          37 :     if (EQUAL(pszCap, OLCStringsAsUTF8))
     806          13 :         return true;
     807          24 :     else if (EQUAL(pszCap, OLCZGeometries))
     808           3 :         return true;
     809             : 
     810          21 :     return false;
     811             : }
     812             : 
     813             : #endif /* HAVE_EXPAT */

Generated by: LCOV version 1.14