Coverage Report

Created: 2026-11-12 08:28

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