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

Generated by: LCOV version 1.14