LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/ili - ili1reader.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 273 367 74.4 %
Date: 2025-02-18 14:19:29 Functions: 17 18 94.4 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Interlis 1 Reader
       4             :  * Purpose:  Implementation of ILI1Reader class.
       5             :  * Author:   Pirmin Kalberer, Sourcepole AG
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2004, Pirmin Kalberer, Sourcepole AG
       9             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_conv.h"
      15             : #include "cpl_string.h"
      16             : #include "ogr_api.h"
      17             : #include "ogr_ili1.h"
      18             : #include "ogr_geos.h"
      19             : 
      20             : #include "ili1reader.h"
      21             : #include "ili1readerp.h"
      22             : 
      23             : #include <vector>
      24             : 
      25             : #ifdef HAVE_GEOS
      26             : #define POLYGONIZE_AREAS
      27             : #endif
      28             : 
      29             : #ifndef POLYGONIZE_AREAS
      30             : #if defined(__GNUC_PREREQ)
      31             : // #    warning Interlis 1 Area polygonizing disabled. Needs GEOS >= 3.1.0
      32             : #endif
      33             : #endif
      34             : 
      35             : //
      36             : // ILI1Reader
      37             : //
      38          13 : IILI1Reader::~IILI1Reader()
      39             : {
      40          13 : }
      41             : 
      42          13 : ILI1Reader::ILI1Reader()
      43             :     : fpItf(nullptr), nLayers(0), papoLayers(nullptr), curLayer(nullptr),
      44          13 :       codeBlank('_'), codeUndefined('@'), codeContinue('\\')
      45             : {
      46          13 : }
      47             : 
      48          26 : ILI1Reader::~ILI1Reader()
      49             : {
      50          13 :     if (fpItf)
      51          13 :         VSIFCloseL(fpItf);
      52             : 
      53          59 :     for (int i = 0; i < nLayers; i++)
      54          46 :         delete papoLayers[i];
      55          13 :     CPLFree(papoLayers);
      56          26 : }
      57             : 
      58             : /* -------------------------------------------------------------------- */
      59             : /*      Open the source file.                                           */
      60             : /* -------------------------------------------------------------------- */
      61          13 : int ILI1Reader::OpenFile(const char *pszFilename)
      62             : {
      63          13 :     fpItf = VSIFOpenL(pszFilename, "r");
      64          13 :     if (fpItf == nullptr)
      65             :     {
      66           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open ILI file `%s'.",
      67             :                  pszFilename);
      68             : 
      69           0 :         return FALSE;
      70             :     }
      71          13 :     return TRUE;
      72             : }
      73             : 
      74          39 : const char *ILI1Reader::GetLayerNameString(const char *topicname,
      75             :                                            const char *tablename)
      76             : {
      77             : 
      78          39 :     return CPLSPrintf("%s__%s", topicname, tablename);
      79             : }
      80             : 
      81          13 : int ILI1Reader::ReadModel(ImdReader *poImdReader, const char *pszModelFilename,
      82             :                           OGRILI1DataSource *poDS)
      83             : {
      84             : 
      85          13 :     poImdReader->ReadModel(pszModelFilename);
      86          32 :     for (FeatureDefnInfos::const_iterator it =
      87          13 :              poImdReader->featureDefnInfos.begin();
      88          77 :          it != poImdReader->featureDefnInfos.end(); ++it)
      89             :     {
      90             : #if DEBUG_VERBOSE
      91             :         CPLDebug("OGR_ILI", "Adding OGRILI1Layer with table '%s'",
      92             :                  it->GetTableDefnRef()->GetName());
      93             : #endif
      94             :         OGRILI1Layer *layer =
      95          32 :             new OGRILI1Layer(it->GetTableDefnRef(), it->poGeomFieldInfos, poDS);
      96          32 :         AddLayer(layer);
      97             :         // Create additional layers for surface and area geometries.
      98          52 :         for (GeomFieldInfos::const_iterator it2 = it->poGeomFieldInfos.begin();
      99          72 :              it2 != it->poGeomFieldInfos.end(); ++it2)
     100             :         {
     101          20 :             if (it2->second.GetGeomTableDefnRef())
     102             :             {
     103             :                 OGRFeatureDefn *poGeomTableDefn =
     104          14 :                     it2->second.GetGeomTableDefnRef();
     105             :                 OGRGeomFieldDefn *poOGRGeomFieldDefn =
     106          14 :                     poGeomTableDefn->GetGeomFieldDefn(0);
     107          28 :                 GeomFieldInfos oGeomFieldInfos;
     108             :                 // We add iliGeomType to recognize Ili1 geom tables
     109          28 :                 oGeomFieldInfos[poOGRGeomFieldDefn->GetNameRef()].iliGeomType =
     110          28 :                     it2->second.iliGeomType;
     111             : #if DEBUG_VERBOSE
     112             :                 CPLDebug("OGR_ILI",
     113             :                          "Adding OGRILI1Layer with geometry table '%s'",
     114             :                          poGeomTableDefn->GetName());
     115             : #endif
     116             :                 OGRILI1Layer *geomlayer =
     117          14 :                     new OGRILI1Layer(poGeomTableDefn, oGeomFieldInfos, poDS);
     118          14 :                 AddLayer(geomlayer);
     119             :             }
     120             :         }
     121             :     }
     122             : 
     123          13 :     codeBlank = poImdReader->codeBlank;
     124          13 :     CPLDebug("OGR_ILI", "Ili1Format blankCode '%c'", poImdReader->codeBlank);
     125          13 :     codeUndefined = poImdReader->codeUndefined;
     126          13 :     CPLDebug("OGR_ILI", "Ili1Format undefinedCode '%c'",
     127          13 :              poImdReader->codeUndefined);
     128          13 :     codeContinue = poImdReader->codeContinue;
     129          13 :     CPLDebug("OGR_ILI", "Ili1Format continueCode '%c'",
     130          13 :              poImdReader->codeContinue);
     131          13 :     return 0;
     132             : }
     133             : 
     134          13 : int ILI1Reader::ReadFeatures()
     135             : {
     136          13 :     char **tokens = nullptr;
     137          13 :     const char *pszLine = nullptr;
     138          13 :     char *topic = CPLStrdup("(null)");
     139          13 :     int ret = TRUE;
     140             : 
     141         130 :     while (ret && (tokens = ReadParseLine()) != nullptr)
     142             :     {
     143         130 :         const char *firsttok = tokens[0];
     144         130 :         if (EQUAL(firsttok, "SCNT"))
     145             :         {
     146             :             // read description
     147          10 :             do
     148             :             {
     149          23 :                 pszLine = CPLReadLineL(fpItf);
     150          23 :             } while (pszLine && !STARTS_WITH_CI(pszLine, "////"));
     151          13 :             ret = (pszLine != nullptr);
     152             :         }
     153         117 :         else if (EQUAL(firsttok, "MOTR"))
     154             :         {
     155             :             // read model
     156           0 :             do
     157             :             {
     158           0 :                 pszLine = CPLReadLineL(fpItf);
     159           0 :             } while (pszLine && !STARTS_WITH_CI(pszLine, "////"));
     160           0 :             ret = (pszLine != nullptr);
     161             :         }
     162         117 :         else if (EQUAL(firsttok, "MTID"))
     163             :         {
     164             :         }
     165         104 :         else if (EQUAL(firsttok, "MODL"))
     166             :         {
     167             :         }
     168          91 :         else if (EQUAL(firsttok, "TOPI") && CSLCount(tokens) >= 2)
     169             :         {
     170          13 :             CPLFree(topic);
     171          13 :             topic = CPLStrdup(CSLGetField(tokens, 1));
     172             :         }
     173          78 :         else if (EQUAL(firsttok, "TABL") && CSLCount(tokens) >= 2)
     174             :         {
     175             :             const char *layername =
     176          39 :                 GetLayerNameString(topic, CSLGetField(tokens, 1));
     177          39 :             CPLDebug("OGR_ILI", "Reading table '%s'", layername);
     178          39 :             curLayer = GetLayerByName(layername);
     179             : 
     180          39 :             if (curLayer == nullptr)
     181             :             {  // create one
     182           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
     183             :                          "No model definition for table '%s' found, "
     184             :                          "using default field names.",
     185             :                          layername);
     186             :                 OGRFeatureDefn *poFeatureDefn = new OGRFeatureDefn(
     187           0 :                     GetLayerNameString(topic, CSLGetField(tokens, 1)));
     188           0 :                 poFeatureDefn->SetGeomType(wkbUnknown);
     189           0 :                 GeomFieldInfos oGeomFieldInfos;
     190           0 :                 curLayer =
     191           0 :                     new OGRILI1Layer(poFeatureDefn, oGeomFieldInfos, nullptr);
     192           0 :                 AddLayer(curLayer);
     193             :             }
     194          39 :             if (curLayer != nullptr)
     195             :             {
     196         173 :                 for (int i = 0; i < curLayer->GetLayerDefn()->GetFieldCount();
     197             :                      i++)
     198             :                 {
     199         134 :                     CPLDebug("OGR_ILI", "Field %d: %s", i,
     200         134 :                              curLayer->GetLayerDefn()
     201         134 :                                  ->GetFieldDefn(i)
     202             :                                  ->GetNameRef());
     203             :                 }
     204             :             }
     205          39 :             ret = ReadTable(layername);
     206             :         }
     207          39 :         else if (EQUAL(firsttok, "ETOP"))
     208             :         {
     209             :         }
     210          26 :         else if (EQUAL(firsttok, "EMOD"))
     211             :         {
     212             :         }
     213          13 :         else if (EQUAL(firsttok, "ENDE"))
     214             :         {
     215          13 :             CSLDestroy(tokens);
     216          13 :             CPLFree(topic);
     217          13 :             return TRUE;
     218             :         }
     219             :         else
     220             :         {
     221           0 :             CPLError(CE_Warning, CPLE_AppDefined, "Unexpected token: %s",
     222             :                      firsttok);
     223             :         }
     224             : 
     225         117 :         CSLDestroy(tokens);
     226         117 :         tokens = nullptr;
     227             :     }
     228             : 
     229           0 :     CSLDestroy(tokens);
     230           0 :     CPLFree(topic);
     231             : 
     232           0 :     return ret;
     233             : }
     234             : 
     235          39 : int ILI1Reader::ReadTable(CPL_UNUSED const char *layername)
     236             : {
     237          39 :     char **tokens = nullptr;
     238          39 :     int warned = FALSE;
     239          39 :     int geomIdx = -1;
     240             : 
     241          39 :     OGRFeatureDefn *featureDef = curLayer->GetLayerDefn();
     242          39 :     OGRFeature *feature = nullptr;
     243          39 :     bool bFeatureAdded = false;
     244             : 
     245         195 :     while ((tokens = ReadParseLine()) != nullptr)
     246             :     {
     247         195 :         const char *firsttok = CSLGetField(tokens, 0);
     248         195 :         if (EQUAL(firsttok, "OBJE"))
     249             :         {
     250         100 :             if (featureDef->GetFieldCount() == 0 &&
     251           0 :                 curLayer->GetFeatureCount() == 0)
     252             :             {
     253           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
     254             :                          "No field definition found for table: %s",
     255           0 :                          featureDef->GetName());
     256             :                 // Model not read - use heuristics.
     257           0 :                 for (int fIndex = 1; tokens[fIndex] != nullptr; fIndex++)
     258             :                 {
     259             :                     char szFieldName[32];
     260           0 :                     snprintf(szFieldName, sizeof(szFieldName), "Field%02d",
     261             :                              fIndex);
     262           0 :                     OGRFieldDefn oFieldDefn(szFieldName, OFTString);
     263           0 :                     featureDef->AddFieldDefn(&oFieldDefn);
     264             :                 }
     265             :             }
     266             :             // start new feature
     267         100 :             if (!bFeatureAdded)
     268          39 :                 delete feature;
     269         100 :             feature = new OGRFeature(featureDef);
     270             : 
     271         421 :             for (int fIndex = 1, fieldno = 0;
     272         748 :                  tokens[fIndex] != nullptr &&
     273         327 :                  fieldno < featureDef->GetFieldCount();
     274             :                  fIndex++, fieldno++)
     275             :             {
     276         321 :                 if (!(tokens[fIndex][0] == codeUndefined &&
     277           3 :                       tokens[fIndex][1] == '\0'))
     278             :                 {
     279             : #ifdef DEBUG_VERBOSE
     280             :                     CPLDebug("READ TABLE OGR_ILI",
     281             :                              "Setting Field %d (Type %d): %s", fieldno,
     282             :                              featureDef->GetFieldDefn(fieldno)->GetType(),
     283             :                              tokens[fIndex]);
     284             : #endif
     285         318 :                     if (featureDef->GetFieldDefn(fieldno)->GetType() ==
     286             :                         OFTString)
     287             :                     {
     288             :                         // Interlis 1 encoding is ISO 8859-1 (Latin1) -> Recode
     289             :                         // to UTF-8
     290         308 :                         char *pszRecoded = CPLRecode(
     291         154 :                             tokens[fIndex], CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
     292             :                         // Replace space marks
     293         807 :                         for (char *pszString = pszRecoded; *pszString != '\0';
     294             :                              pszString++)
     295             :                         {
     296         653 :                             if (*pszString == codeBlank)
     297          25 :                                 *pszString = ' ';
     298             :                         }
     299         154 :                         feature->SetField(fieldno, pszRecoded);
     300         154 :                         CPLFree(pszRecoded);
     301             :                     }
     302             :                     else
     303             :                     {
     304         164 :                         feature->SetField(fieldno, tokens[fIndex]);
     305             :                     }
     306         318 :                     if (featureDef->GetFieldDefn(fieldno)->GetType() ==
     307         149 :                             OFTReal &&
     308         467 :                         fieldno > 0 &&
     309         149 :                         featureDef->GetFieldDefn(fieldno - 1)->GetType() ==
     310             :                             OFTReal)
     311             :                     {
     312             :                         // Check for Point geometry (Coord type).
     313             :                         // If there is no ili model read,
     314             :                         // we have no chance to detect the
     315             :                         // geometry column.
     316             :                         CPLString geomfldname =
     317         206 :                             featureDef->GetFieldDefn(fieldno)->GetNameRef();
     318             :                         // Check if name ends with _1.
     319         206 :                         if (geomfldname.size() >= 2 &&
     320         103 :                             geomfldname[geomfldname.size() - 2] == '_')
     321             :                         {
     322             :                             geomfldname =
     323          26 :                                 geomfldname.substr(0, geomfldname.size() - 2);
     324          26 :                             geomIdx = featureDef->GetGeomFieldIndex(
     325          26 :                                 geomfldname.c_str());
     326          26 :                             if (geomIdx == -1)
     327             :                             {
     328           0 :                                 CPLError(
     329             :                                     CE_Warning, CPLE_AppDefined,
     330             :                                     "No matching definition for field '%s' of "
     331             :                                     "table %s found",
     332           0 :                                     geomfldname.c_str(), featureDef->GetName());
     333             :                             }
     334             :                         }
     335             :                         else
     336             :                         {
     337          77 :                             geomIdx = -1;
     338             :                         }
     339         103 :                         if (geomIdx >= 0)
     340             :                         {
     341          52 :                             if (featureDef->GetGeomFieldDefn(geomIdx)
     342          26 :                                     ->GetType() == wkbPoint)
     343             :                             {
     344             :                                 // Add Point geometry.
     345             :                                 OGRPoint *ogrPoint =
     346          23 :                                     new OGRPoint(CPLAtof(tokens[fIndex - 1]),
     347          23 :                                                  CPLAtof(tokens[fIndex]));
     348          23 :                                 feature->SetGeomFieldDirectly(geomIdx,
     349             :                                                               ogrPoint);
     350             :                             }
     351           6 :                             else if (featureDef->GetGeomFieldDefn(geomIdx)
     352           6 :                                              ->GetType() == wkbPoint25D &&
     353           6 :                                      fieldno > 1 &&
     354           3 :                                      featureDef->GetFieldDefn(fieldno - 2)
     355           3 :                                              ->GetType() == OFTReal)
     356             :                             {
     357             :                                 // Add 3D Point geometry.
     358             :                                 OGRPoint *ogrPoint =
     359           3 :                                     new OGRPoint(CPLAtof(tokens[fIndex - 2]),
     360           3 :                                                  CPLAtof(tokens[fIndex - 1]),
     361           3 :                                                  CPLAtof(tokens[fIndex]));
     362           3 :                                 feature->SetGeomFieldDirectly(geomIdx,
     363             :                                                               ogrPoint);
     364             :                             }
     365             :                         }
     366             :                     }
     367             :                 }
     368             :             }
     369         100 :             if (!warned && featureDef->GetFieldCount() != CSLCount(tokens) - 1)
     370             :             {
     371           2 :                 CPLError(CE_Warning, CPLE_AppDefined,
     372             :                          "Field count of table %s doesn't match. %d declared, "
     373             :                          "%d found (e.g. ignored LINEATTR)",
     374           2 :                          featureDef->GetName(), featureDef->GetFieldCount(),
     375           2 :                          CSLCount(tokens) - 1);
     376           2 :                 warned = TRUE;
     377             :             }
     378         100 :             if (feature->GetFieldCount() > 0)
     379             :             {
     380             :                 // USE _TID as FID. TODO: respect IDENT field from model.
     381         100 :                 feature->SetFID(feature->GetFieldAsInteger64(0));
     382             :             }
     383         100 :             curLayer->AddFeature(feature);
     384         100 :             bFeatureAdded = true;
     385         100 :             geomIdx = -1;  // Reset
     386             :         }
     387          95 :         else if (EQUAL(firsttok, "STPT") && feature != nullptr)
     388             :         {
     389             :             // Find next non-Point geometry
     390          55 :             if (geomIdx < 0)
     391          55 :                 geomIdx = 0;
     392         110 :             while (geomIdx < featureDef->GetGeomFieldCount() &&
     393          55 :                    featureDef->GetGeomFieldDefn(geomIdx)->GetType() == wkbPoint)
     394             :             {
     395           0 :                 geomIdx++;
     396             :             }
     397             :             OGRwkbGeometryType geomType =
     398          55 :                 (geomIdx < featureDef->GetGeomFieldCount())
     399          55 :                     ? featureDef->GetGeomFieldDefn(geomIdx)->GetType()
     400          55 :                     : wkbNone;
     401          55 :             if (CSLCount(tokens) >= 3)
     402          55 :                 ReadGeom(tokens, geomIdx, geomType, feature);
     403             :         }
     404          40 :         else if (EQUAL(firsttok, "ELIN"))
     405             :         {
     406             :             // Empty geom.
     407             :         }
     408          39 :         else if (EQUAL(firsttok, "EDGE") && feature != nullptr)
     409             :         {
     410           0 :             CSLDestroy(tokens);
     411           0 :             tokens = ReadParseLine();  // STPT
     412             :             // Find next non-Point geometry
     413           0 :             do
     414             :             {
     415           0 :                 geomIdx++;
     416           0 :             } while (geomIdx < featureDef->GetGeomFieldCount() &&
     417           0 :                      featureDef->GetGeomFieldDefn(geomIdx)->GetType() ==
     418             :                          wkbPoint);
     419           0 :             if (CSLCount(tokens) >= 3)
     420           0 :                 ReadGeom(tokens, geomIdx, wkbMultiLineString, feature);
     421             :         }
     422          39 :         else if (EQUAL(firsttok, "PERI"))
     423             :         {
     424             :         }
     425          39 :         else if (EQUAL(firsttok, "ETAB"))
     426             :         {
     427          39 :             CPLDebug("OGR_ILI", "Total features: " CPL_FRMT_GIB,
     428          39 :                      curLayer->GetFeatureCount());
     429          39 :             CSLDestroy(tokens);
     430          39 :             if (!bFeatureAdded)
     431           0 :                 delete feature;
     432          39 :             return TRUE;
     433             :         }
     434             :         else
     435             :         {
     436           0 :             CPLError(CE_Warning, CPLE_AppDefined, "Unexpected token: %s",
     437             :                      firsttok);
     438             :         }
     439             : 
     440         156 :         CSLDestroy(tokens);
     441             :     }
     442             : 
     443           0 :     if (!bFeatureAdded)
     444           0 :         delete feature;
     445             : 
     446           0 :     return TRUE;
     447             : }
     448             : 
     449          55 : void ILI1Reader::ReadGeom(char **stgeom, int geomIdx, OGRwkbGeometryType eType,
     450             :                           OGRFeature *feature)
     451             : {
     452             : #ifdef DEBUG_VERBOSE
     453             :     CPLDebug("OGR_ILI", "ILI1Reader::ReadGeom geomIdx: %d OGRGeometryType: %s",
     454             :              geomIdx, OGRGeometryTypeToName(eType));
     455             : #endif
     456          55 :     if (eType == wkbNone)
     457             :     {
     458           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     459             :                  "Calling ILI1Reader::ReadGeom with wkbNone");
     460             :     }
     461             : 
     462             :     // Initialize geometry.
     463             : 
     464          55 :     OGRCompoundCurve *ogrCurve = new OGRCompoundCurve();
     465          55 :     OGRCurvePolygon *ogrPoly = nullptr;     // current polygon
     466          55 :     OGRMultiCurve *ogrMultiLine = nullptr;  // current multi line
     467             : 
     468          55 :     if (eType == wkbMultiCurve || eType == wkbMultiLineString)
     469             :     {
     470          55 :         ogrMultiLine = new OGRMultiCurve();
     471             :     }
     472           0 :     else if (eType == wkbPolygon || eType == wkbCurvePolygon)
     473             :     {
     474           0 :         ogrPoly = new OGRCurvePolygon();
     475             :     }
     476             : 
     477         110 :     OGRPoint ogrPoint;  // Current point.
     478          55 :     ogrPoint.setX(CPLAtof(stgeom[1]));
     479          55 :     ogrPoint.setY(CPLAtof(stgeom[2]));
     480             : 
     481          55 :     OGRLineString *ogrLine = new OGRLineString();
     482          55 :     ogrLine->addPoint(&ogrPoint);
     483             : 
     484             :     // Parse geometry.
     485             : 
     486          55 :     char **tokens = nullptr;
     487          55 :     bool end = false;
     488          55 :     OGRCircularString *arc = nullptr;  // current arc
     489             : 
     490         422 :     while (!end && (tokens = ReadParseLine()) != nullptr)
     491             :     {
     492         367 :         const char *firsttok = CSLGetField(tokens, 0);
     493         367 :         if (firsttok == nullptr)
     494             :         {
     495             :             // do nothing
     496             :         }
     497         367 :         else if (EQUAL(firsttok, "LIPT") && CSLCount(tokens) >= 3)
     498             :         {
     499         292 :             ogrPoint.setX(CPLAtof(tokens[1]));
     500         292 :             ogrPoint.setY(CPLAtof(tokens[2]));
     501         292 :             if (arc)
     502             :             {
     503          20 :                 arc->addPoint(&ogrPoint);
     504          20 :                 OGRErr error = ogrCurve->addCurveDirectly(arc);
     505          20 :                 if (error != OGRERR_NONE)
     506             :                 {
     507           0 :                     char *pszJSon = arc->exportToJson();
     508           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     509             :                              "Could not add geometry: %s",
     510             :                              pszJSon ? pszJSon : "(null)");
     511           0 :                     CPLFree(pszJSon);
     512           0 :                     delete arc;
     513             :                 }
     514          20 :                 arc = nullptr;
     515             :             }
     516         292 :             ogrLine->addPoint(&ogrPoint);
     517             :         }
     518          75 :         else if (EQUAL(firsttok, "ARCP") && CSLCount(tokens) >= 3)
     519             :         {
     520             :             // Finish line and start arc
     521          20 :             if (ogrLine->getNumPoints() > 1)
     522             :             {
     523           9 :                 OGRErr error = ogrCurve->addCurveDirectly(ogrLine);
     524           9 :                 if (error != OGRERR_NONE)
     525             :                 {
     526           0 :                     char *pszJSon = ogrLine->exportToJson();
     527           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     528             :                              "Could not add geometry: %s",
     529             :                              pszJSon ? pszJSon : "(null)");
     530           0 :                     CPLFree(pszJSon);
     531           0 :                     delete ogrLine;
     532             :                 }
     533           9 :                 ogrLine = new OGRLineString();
     534             :             }
     535             :             else
     536             :             {
     537          11 :                 ogrLine->empty();
     538             :             }
     539          20 :             delete arc;
     540          20 :             arc = new OGRCircularString();
     541          20 :             arc->addPoint(&ogrPoint);
     542          20 :             ogrPoint.setX(CPLAtof(tokens[1]));
     543          20 :             ogrPoint.setY(CPLAtof(tokens[2]));
     544          20 :             arc->addPoint(&ogrPoint);
     545             :         }
     546          55 :         else if (EQUAL(firsttok, "ELIN"))
     547             :         {
     548          55 :             if (ogrLine->getNumPoints() > 1)
     549             :             {  // Ignore single LIPT after ARCP
     550          55 :                 OGRErr error = ogrCurve->addCurveDirectly(ogrLine);
     551          55 :                 if (error != OGRERR_NONE)
     552             :                 {
     553           0 :                     char *pszJSon = ogrLine->exportToJson();
     554           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     555             :                              "Could not add geometry: %s",
     556             :                              pszJSon ? pszJSon : "(null)");
     557           0 :                     CPLFree(pszJSon);
     558           0 :                     delete ogrLine;
     559             :                 }
     560          55 :                 ogrLine = nullptr;
     561             :             }
     562          55 :             if (!ogrCurve->IsEmpty())
     563             :             {
     564          55 :                 if (ogrMultiLine)
     565             :                 {
     566          55 :                     OGRErr error = ogrMultiLine->addGeometryDirectly(ogrCurve);
     567          55 :                     if (error != OGRERR_NONE)
     568             :                     {
     569           0 :                         char *pszJSon = ogrCurve->exportToJson();
     570           0 :                         CPLError(CE_Warning, CPLE_AppDefined,
     571             :                                  "Could not add geometry: %s",
     572             :                                  pszJSon ? pszJSon : "(null)");
     573           0 :                         CPLFree(pszJSon);
     574           0 :                         delete ogrCurve;
     575             :                     }
     576          55 :                     ogrCurve = nullptr;
     577             :                 }
     578          55 :                 if (ogrPoly)
     579             :                 {
     580           0 :                     OGRErr error = ogrPoly->addRingDirectly(ogrCurve);
     581           0 :                     if (error != OGRERR_NONE)
     582             :                     {
     583           0 :                         char *pszJSon = ogrCurve->exportToJson();
     584           0 :                         CPLError(CE_Warning, CPLE_AppDefined,
     585             :                                  "Could not add geometry: %s",
     586             :                                  pszJSon ? pszJSon : "(null)");
     587           0 :                         CPLFree(pszJSon);
     588           0 :                         delete ogrCurve;
     589             :                     }
     590           0 :                     ogrCurve = nullptr;
     591             :                 }
     592             :             }
     593          55 :             end = true;
     594             :         }
     595           0 :         else if (EQUAL(firsttok, "EEDG"))
     596             :         {
     597           0 :             end = true;
     598             :         }
     599           0 :         else if (EQUAL(firsttok, "LATT"))
     600             :         {
     601             :             // Line Attributes (ignored)
     602             :         }
     603           0 :         else if (EQUAL(firsttok, "EFLA"))
     604             :         {
     605           0 :             end = true;
     606             :         }
     607           0 :         else if (EQUAL(firsttok, "ETAB"))
     608             :         {
     609           0 :             end = true;
     610             :         }
     611             :         else
     612             :         {
     613           0 :             CPLError(CE_Warning, CPLE_AppDefined, "Unexpected token: %s",
     614             :                      firsttok);
     615             :         }
     616             : 
     617         367 :         CSLDestroy(tokens);
     618             :     }
     619          55 :     delete arc;
     620             : 
     621          55 :     delete ogrLine;
     622             : 
     623             :     // Set feature geometry
     624          55 :     if (eType == wkbMultiCurve)
     625             :     {
     626          37 :         feature->SetGeomFieldDirectly(geomIdx, ogrMultiLine);
     627          37 :         delete ogrCurve;
     628             :     }
     629          18 :     else if (eType == wkbMultiLineString)
     630             :     {
     631          18 :         feature->SetGeomFieldDirectly(geomIdx,
     632          18 :                                       ogrMultiLine->getLinearGeometry());
     633          18 :         delete ogrMultiLine;
     634          18 :         delete ogrCurve;
     635             :     }
     636           0 :     else if (eType == wkbCurvePolygon)
     637             :     {
     638           0 :         feature->SetGeomFieldDirectly(geomIdx, ogrPoly);
     639           0 :         delete ogrCurve;
     640             :     }
     641           0 :     else if (eType == wkbPolygon)
     642             :     {
     643           0 :         feature->SetGeomFieldDirectly(geomIdx, ogrPoly->getLinearGeometry());
     644           0 :         delete ogrPoly;
     645           0 :         delete ogrCurve;
     646             :     }
     647             :     else
     648             :     {
     649           0 :         feature->SetGeomFieldDirectly(geomIdx, ogrCurve);
     650             :     }
     651          55 : }
     652             : 
     653             : /************************************************************************/
     654             : /*                              AddLayer()                              */
     655             : /************************************************************************/
     656             : 
     657          46 : void ILI1Reader::AddLayer(OGRILI1Layer *poNewLayer)
     658             : 
     659             : {
     660          46 :     nLayers++;
     661             : 
     662          46 :     papoLayers = static_cast<OGRILI1Layer **>(
     663          46 :         CPLRealloc(papoLayers, sizeof(void *) * nLayers));
     664             : 
     665          46 :     papoLayers[nLayers - 1] = poNewLayer;
     666          46 : }
     667             : 
     668             : /************************************************************************/
     669             : /*                              GetLayer()                              */
     670             : /************************************************************************/
     671             : 
     672          23 : OGRILI1Layer *ILI1Reader::GetLayer(int iLayer)
     673             : 
     674             : {
     675          23 :     if (iLayer < 0 || iLayer >= nLayers)
     676           0 :         return nullptr;
     677             : 
     678          23 :     return papoLayers[iLayer];
     679             : }
     680             : 
     681          65 : OGRILI1Layer *ILI1Reader::GetLayerByName(const char *pszLayerName)
     682             : 
     683             : {
     684         196 :     for (int iLayer = 0; iLayer < nLayers; iLayer++)
     685             :     {
     686         196 :         if (EQUAL(pszLayerName, papoLayers[iLayer]->GetLayerDefn()->GetName()))
     687          65 :             return papoLayers[iLayer];
     688             :     }
     689           0 :     return nullptr;
     690             : }
     691             : 
     692             : /************************************************************************/
     693             : /*                           GetLayerCount()                            */
     694             : /************************************************************************/
     695             : 
     696          29 : int ILI1Reader::GetLayerCount()
     697             : 
     698             : {
     699          29 :     return nLayers;
     700             : }
     701             : 
     702             : /************************************************************************/
     703             : /*     Read one logical line, and return split into fields.  The return */
     704             : /*     result is a stringlist, in the sense of the CSL functions.       */
     705             : /************************************************************************/
     706             : 
     707         692 : char **ILI1Reader::ReadParseLine()
     708             : {
     709         692 :     CPLAssert(fpItf != nullptr);
     710         692 :     if (fpItf == nullptr)
     711           0 :         return nullptr;
     712             : 
     713         692 :     const char *pszLine = CPLReadLineL(fpItf);
     714         692 :     if (pszLine == nullptr)
     715           0 :         return nullptr;
     716             : 
     717         692 :     if (strlen(pszLine) == 0)
     718           0 :         return nullptr;
     719             : 
     720         692 :     char **tokens = CSLTokenizeString2(pszLine, " ", CSLT_PRESERVEESCAPES);
     721         692 :     int nCount = CSLCount(tokens);
     722         692 :     if (nCount == 0)
     723             :     {
     724           0 :         CSLDestroy(tokens);
     725           0 :         return nullptr;
     726             :     }
     727         692 :     const char *token = tokens[nCount - 1];
     728             : 
     729             :     // Append CONT lines
     730         694 :     while (strlen(pszLine) && token[0] == codeContinue && token[1] == '\0')
     731             :     {
     732             :         // remove last token
     733           2 :         CPLFree(tokens[CSLCount(tokens) - 1]);
     734           2 :         tokens[CSLCount(tokens) - 1] = nullptr;
     735             : 
     736           2 :         pszLine = CPLReadLineL(fpItf);
     737           2 :         if (pszLine == nullptr)
     738             :         {
     739           0 :             break;
     740             :         }
     741           2 :         char **conttok = CSLTokenizeString2(pszLine, " ", CSLT_PRESERVEESCAPES);
     742           2 :         if (!conttok || conttok[0] == nullptr || !EQUAL(conttok[0], "CONT") ||
     743           2 :             conttok[1] == nullptr)
     744             :         {
     745           0 :             CSLDestroy(conttok);
     746           0 :             break;
     747             :         }
     748             : 
     749             :         // append
     750           2 :         tokens = CSLInsertStrings(tokens, -1, &conttok[1]);
     751           2 :         token = tokens[CSLCount(tokens) - 1];
     752             : 
     753           2 :         CSLDestroy(conttok);
     754             :     }
     755         692 :     if (tokens[0] == nullptr)
     756             :     {
     757           0 :         CSLDestroy(tokens);
     758           0 :         tokens = nullptr;
     759             :     }
     760         692 :     return tokens;
     761             : }
     762             : 
     763          13 : IILI1Reader *CreateILI1Reader()
     764             : {
     765          13 :     return new ILI1Reader();
     766             : }
     767             : 
     768          67 : void DestroyILI1Reader(IILI1Reader *reader)
     769             : {
     770          67 :     if (reader)
     771          13 :         delete reader;
     772          67 : }

Generated by: LCOV version 1.14