Coverage Report

Created: 2026-06-30 08:33

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.27k
{
40
9.27k
}
41
42
ILI1Reader::ILI1Reader()
43
9.27k
    : fpItf(nullptr), nLayers(0), papoLayers(nullptr), curLayer(nullptr),
44
9.27k
      codeBlank('_'), codeUndefined('@'), codeContinue('\\')
45
9.27k
{
46
9.27k
}
47
48
ILI1Reader::~ILI1Reader()
49
9.27k
{
50
9.27k
    if (fpItf)
51
9.27k
        VSIFCloseL(fpItf);
52
53
22.3k
    for (int i = 0; i < nLayers; i++)
54
13.0k
        delete papoLayers[i];
55
9.27k
    CPLFree(papoLayers);
56
9.27k
}
57
58
/* -------------------------------------------------------------------- */
59
/*      Open the source file.                                           */
60
/* -------------------------------------------------------------------- */
61
int ILI1Reader::OpenFile(const char *pszFilename)
62
9.27k
{
63
9.27k
    fpItf = VSIFOpenL(pszFilename, "r");
64
9.27k
    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.27k
    return TRUE;
72
9.27k
}
73
74
const char *ILI1Reader::GetLayerNameString(const char *topicname,
75
                                           const char *tablename)
76
83.5k
{
77
78
83.5k
    return CPLSPrintf("%s__%s", topicname, tablename);
79
83.5k
}
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.27k
{
136
9.27k
    char **tokens = nullptr;
137
9.27k
    const char *pszLine = nullptr;
138
9.27k
    char *topic = CPLStrdup("(null)");
139
9.27k
    int ret = TRUE;
140
141
625k
    while (ret && (tokens = ReadParseLine()) != nullptr)
142
616k
    {
143
616k
        const char *firsttok = tokens[0];
144
616k
        if (EQUAL(firsttok, "SCNT"))
145
2.28k
        {
146
            // read description
147
2.28k
            do
148
897k
            {
149
897k
                pszLine = CPLReadLineL(fpItf);
150
897k
            } while (pszLine && !STARTS_WITH_CI(pszLine, "////"));
151
2.28k
            ret = (pszLine != nullptr);
152
2.28k
        }
153
614k
        else if (EQUAL(firsttok, "MOTR"))
154
307
        {
155
            // read model
156
307
            do
157
177k
            {
158
177k
                pszLine = CPLReadLineL(fpItf);
159
177k
            } while (pszLine && !STARTS_WITH_CI(pszLine, "////"));
160
307
            ret = (pszLine != nullptr);
161
307
        }
162
613k
        else if (EQUAL(firsttok, "MTID"))
163
2.21k
        {
164
2.21k
        }
165
611k
        else if (EQUAL(firsttok, "MODL"))
166
1.85k
        {
167
1.85k
        }
168
609k
        else if (EQUAL(firsttok, "TOPI") && CSLCount(tokens) >= 2)
169
5.06k
        {
170
5.06k
            CPLFree(topic);
171
5.06k
            topic = CPLStrdup(CSLGetField(tokens, 1));
172
5.06k
        }
173
604k
        else if (EQUAL(firsttok, "TABL") && CSLCount(tokens) >= 2)
174
70.4k
        {
175
70.4k
            const char *layername =
176
70.4k
                GetLayerNameString(topic, CSLGetField(tokens, 1));
177
70.4k
            CPLDebug("OGR_ILI", "Reading table '%s'", layername);
178
70.4k
            curLayer = GetLayerByName(layername);
179
180
70.4k
            if (curLayer == nullptr)
181
13.0k
            {  // create one
182
13.0k
                CPLError(CE_Warning, CPLE_AppDefined,
183
13.0k
                         "No model definition for table '%s' found, "
184
13.0k
                         "using default field names.",
185
13.0k
                         layername);
186
13.0k
                OGRFeatureDefn *poFeatureDefn = new OGRFeatureDefn(
187
13.0k
                    GetLayerNameString(topic, CSLGetField(tokens, 1)));
188
13.0k
                poFeatureDefn->SetGeomType(wkbUnknown);
189
13.0k
                GeomFieldInfos oGeomFieldInfos;
190
13.0k
                curLayer =
191
13.0k
                    new OGRILI1Layer(poFeatureDefn, oGeomFieldInfos, nullptr);
192
13.0k
                AddLayer(curLayer);
193
13.0k
            }
194
70.4k
            if (curLayer != nullptr)
195
70.4k
            {
196
139k
                for (int i = 0; i < curLayer->GetLayerDefn()->GetFieldCount();
197
70.4k
                     i++)
198
68.5k
                {
199
68.5k
                    CPLDebug("OGR_ILI", "Field %d: %s", i,
200
68.5k
                             curLayer->GetLayerDefn()
201
68.5k
                                 ->GetFieldDefn(i)
202
68.5k
                                 ->GetNameRef());
203
68.5k
                }
204
70.4k
            }
205
70.4k
            ret = ReadTable(layername);
206
70.4k
        }
207
534k
        else if (EQUAL(firsttok, "ETOP"))
208
4.24k
        {
209
4.24k
        }
210
529k
        else if (EQUAL(firsttok, "EMOD"))
211
2.38k
        {
212
2.38k
        }
213
527k
        else if (EQUAL(firsttok, "ENDE"))
214
8
        {
215
8
            CSLDestroy(tokens);
216
8
            CPLFree(topic);
217
8
            return TRUE;
218
8
        }
219
527k
        else
220
527k
        {
221
527k
            CPLError(CE_Warning, CPLE_AppDefined, "Unexpected token: %s",
222
527k
                     firsttok);
223
527k
        }
224
225
616k
        CSLDestroy(tokens);
226
616k
        tokens = nullptr;
227
616k
    }
228
229
9.26k
    CSLDestroy(tokens);
230
9.26k
    CPLFree(topic);
231
232
9.26k
    return ret;
233
9.27k
}
234
235
int ILI1Reader::ReadTable(CPL_UNUSED const char *layername)
236
70.4k
{
237
70.4k
    char **tokens = nullptr;
238
70.4k
    int warned = FALSE;
239
70.4k
    int geomIdx = -1;
240
241
70.4k
    OGRFeatureDefn *featureDef = curLayer->GetLayerDefn();
242
70.4k
    OGRFeature *feature = nullptr;
243
70.4k
    bool bFeatureAdded = false;
244
245
1.09M
    while ((tokens = ReadParseLine()) != nullptr)
246
1.06M
    {
247
1.06M
        const char *firsttok = CSLGetField(tokens, 0);
248
1.06M
        if (EQUAL(firsttok, "OBJE"))
249
107k
        {
250
107k
            if (featureDef->GetFieldCount() == 0 &&
251
40.0k
                curLayer->GetFeatureCount() == 0)
252
9.05k
            {
253
9.05k
                CPLError(CE_Warning, CPLE_AppDefined,
254
9.05k
                         "No field definition found for table: %s",
255
9.05k
                         featureDef->GetName());
256
                // Model not read - use heuristics.
257
20.8k
                for (int fIndex = 1; tokens[fIndex] != nullptr; fIndex++)
258
11.8k
                {
259
11.8k
                    char szFieldName[32];
260
11.8k
                    snprintf(szFieldName, sizeof(szFieldName), "Field%02d",
261
11.8k
                             fIndex);
262
11.8k
                    OGRFieldDefn oFieldDefn(szFieldName, OFTString);
263
11.8k
                    featureDef->AddFieldDefn(&oFieldDefn);
264
11.8k
                }
265
9.05k
            }
266
            // start new feature
267
107k
            if (!bFeatureAdded)
268
43.5k
                delete feature;
269
107k
            feature = new OGRFeature(featureDef);
270
271
107k
            for (int fIndex = 1, fieldno = 0;
272
233k
                 tokens[fIndex] != nullptr &&
273
142k
                 fieldno < featureDef->GetFieldCount();
274
125k
                 fIndex++, fieldno++)
275
125k
            {
276
125k
                if (!(tokens[fIndex][0] == codeUndefined &&
277
6.09k
                      tokens[fIndex][1] == '\0'))
278
124k
                {
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
124k
                    if (featureDef->GetFieldDefn(fieldno)->GetType() ==
286
124k
                        OFTString)
287
124k
                    {
288
                        // Interlis 1 encoding is ISO 8859-1 (Latin1) -> Recode
289
                        // to UTF-8
290
124k
                        char *pszRecoded = CPLRecode(
291
124k
                            tokens[fIndex], CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
292
                        // Replace space marks
293
1.56M
                        for (char *pszString = pszRecoded; *pszString != '\0';
294
1.44M
                             pszString++)
295
1.44M
                        {
296
1.44M
                            if (*pszString == codeBlank)
297
16.4k
                                *pszString = ' ';
298
1.44M
                        }
299
124k
                        feature->SetField(fieldno, pszRecoded);
300
124k
                        CPLFree(pszRecoded);
301
124k
                    }
302
0
                    else
303
0
                    {
304
0
                        feature->SetField(fieldno, tokens[fIndex]);
305
0
                    }
306
124k
                    if (featureDef->GetFieldDefn(fieldno)->GetType() ==
307
124k
                            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
124k
                }
368
125k
            }
369
107k
            if (!warned && featureDef->GetFieldCount() != CSLCount(tokens) - 1)
370
15.0k
            {
371
15.0k
                CPLError(CE_Warning, CPLE_AppDefined,
372
15.0k
                         "Field count of table %s doesn't match. %d declared, "
373
15.0k
                         "%d found (e.g. ignored LINEATTR)",
374
15.0k
                         featureDef->GetName(), featureDef->GetFieldCount(),
375
15.0k
                         CSLCount(tokens) - 1);
376
15.0k
                warned = TRUE;
377
15.0k
            }
378
107k
            if (feature->GetFieldCount() > 0)
379
73.6k
            {
380
                // USE _TID as FID. TODO: respect IDENT field from model.
381
73.6k
                feature->SetFID(feature->GetFieldAsInteger64(0));
382
73.6k
            }
383
107k
            curLayer->AddFeature(feature);
384
107k
            bFeatureAdded = true;
385
107k
            geomIdx = -1;  // Reset
386
107k
        }
387
955k
        else if (EQUAL(firsttok, "STPT") && feature != nullptr)
388
39.7k
        {
389
            // Find next non-Point geometry
390
39.7k
            if (geomIdx < 0)
391
12.1k
                geomIdx = 0;
392
39.7k
            while (geomIdx < featureDef->GetGeomFieldCount() &&
393
30.5k
                   featureDef->GetGeomFieldDefn(geomIdx)->GetType() == wkbPoint)
394
0
            {
395
0
                geomIdx++;
396
0
            }
397
39.7k
            OGRwkbGeometryType geomType =
398
39.7k
                (geomIdx < featureDef->GetGeomFieldCount())
399
39.7k
                    ? featureDef->GetGeomFieldDefn(geomIdx)->GetType()
400
39.7k
                    : wkbNone;
401
39.7k
            if (CSLCount(tokens) >= 3)
402
24.2k
                ReadGeom(tokens, geomIdx, geomType, feature);
403
39.7k
        }
404
915k
        else if (EQUAL(firsttok, "ELIN"))
405
35.4k
        {
406
            // Empty geom.
407
35.4k
        }
408
880k
        else if (EQUAL(firsttok, "EDGE") && feature != nullptr)
409
68.9k
        {
410
68.9k
            CSLDestroy(tokens);
411
68.9k
            tokens = ReadParseLine();  // STPT
412
            // Find next non-Point geometry
413
68.9k
            do
414
68.9k
            {
415
68.9k
                geomIdx++;
416
68.9k
            } while (geomIdx < featureDef->GetGeomFieldCount() &&
417
37.3k
                     featureDef->GetGeomFieldDefn(geomIdx)->GetType() ==
418
37.3k
                         wkbPoint);
419
68.9k
            if (CSLCount(tokens) >= 3)
420
48.8k
                ReadGeom(tokens, geomIdx, wkbMultiLineString, feature);
421
68.9k
        }
422
811k
        else if (EQUAL(firsttok, "PERI"))
423
790
        {
424
790
        }
425
810k
        else if (EQUAL(firsttok, "ETAB"))
426
36.8k
        {
427
36.8k
            CPLDebug("OGR_ILI", "Total features: " CPL_FRMT_GIB,
428
36.8k
                     curLayer->GetFeatureCount());
429
36.8k
            CSLDestroy(tokens);
430
36.8k
            if (!bFeatureAdded)
431
12.4k
                delete feature;
432
36.8k
            return TRUE;
433
36.8k
        }
434
773k
        else
435
773k
        {
436
773k
            CPLError(CE_Warning, CPLE_AppDefined, "Unexpected token: %s",
437
773k
                     firsttok);
438
773k
        }
439
440
1.02M
        CSLDestroy(tokens);
441
1.02M
    }
442
443
33.6k
    if (!bFeatureAdded)
444
14.5k
        delete feature;
445
446
33.6k
    return TRUE;
447
70.4k
}
448
449
void ILI1Reader::ReadGeom(char **stgeom, int geomIdx, OGRwkbGeometryType eType,
450
                          OGRFeature *feature)
451
73.0k
{
452
#ifdef DEBUG_VERBOSE
453
    CPLDebug("OGR_ILI", "ILI1Reader::ReadGeom geomIdx: %d OGRGeometryType: %s",
454
             geomIdx, OGRGeometryTypeToName(eType));
455
#endif
456
73.0k
    if (eType == wkbNone)
457
4.99k
    {
458
4.99k
        CPLError(CE_Warning, CPLE_AppDefined,
459
4.99k
                 "Calling ILI1Reader::ReadGeom with wkbNone");
460
4.99k
    }
461
462
    // Initialize geometry.
463
464
73.0k
    OGRCompoundCurve *ogrCurve = new OGRCompoundCurve();
465
73.0k
    OGRCurvePolygon *ogrPoly = nullptr;     // current polygon
466
73.0k
    OGRMultiCurve *ogrMultiLine = nullptr;  // current multi line
467
468
73.0k
    if (eType == wkbMultiCurve || eType == wkbMultiLineString)
469
48.8k
    {
470
48.8k
        ogrMultiLine = new OGRMultiCurve();
471
48.8k
    }
472
24.2k
    else if (eType == wkbPolygon || eType == wkbCurvePolygon)
473
0
    {
474
0
        ogrPoly = new OGRCurvePolygon();
475
0
    }
476
477
73.0k
    OGRPoint ogrPoint;  // Current point.
478
73.0k
    ogrPoint.setX(CPLAtof(stgeom[1]));
479
73.0k
    ogrPoint.setY(CPLAtof(stgeom[2]));
480
481
73.0k
    OGRLineString *ogrLine = new OGRLineString();
482
73.0k
    ogrLine->addPoint(&ogrPoint);
483
484
    // Parse geometry.
485
486
73.0k
    char **tokens = nullptr;
487
73.0k
    bool end = false;
488
73.0k
    OGRCircularString *arc = nullptr;  // current arc
489
490
2.62M
    while (!end && (tokens = ReadParseLine()) != nullptr)
491
2.55M
    {
492
2.55M
        const char *firsttok = CSLGetField(tokens, 0);
493
2.55M
        if (firsttok == nullptr)
494
0
        {
495
            // do nothing
496
0
        }
497
2.55M
        else if (EQUAL(firsttok, "LIPT") && CSLCount(tokens) >= 3)
498
513k
        {
499
513k
            ogrPoint.setX(CPLAtof(tokens[1]));
500
513k
            ogrPoint.setY(CPLAtof(tokens[2]));
501
513k
            if (arc)
502
230k
            {
503
230k
                arc->addPoint(&ogrPoint);
504
230k
                OGRErr error = ogrCurve->addCurveDirectly(arc);
505
230k
                if (error != OGRERR_NONE)
506
107k
                {
507
107k
                    char *pszJSon = arc->exportToJson();
508
107k
                    CPLError(CE_Warning, CPLE_AppDefined,
509
107k
                             "Could not add geometry: %s",
510
107k
                             pszJSon ? pszJSon : "(null)");
511
107k
                    CPLFree(pszJSon);
512
107k
                    delete arc;
513
107k
                }
514
230k
                arc = nullptr;
515
230k
            }
516
513k
            ogrLine->addPoint(&ogrPoint);
517
513k
        }
518
2.04M
        else if (EQUAL(firsttok, "ARCP") && CSLCount(tokens) >= 3)
519
311k
        {
520
            // Finish line and start arc
521
311k
            if (ogrLine->getNumPoints() > 1)
522
111k
            {
523
111k
                OGRErr error = ogrCurve->addCurveDirectly(ogrLine);
524
111k
                if (error != OGRERR_NONE)
525
52.5k
                {
526
52.5k
                    char *pszJSon = ogrLine->exportToJson();
527
52.5k
                    CPLError(CE_Warning, CPLE_AppDefined,
528
52.5k
                             "Could not add geometry: %s",
529
52.5k
                             pszJSon ? pszJSon : "(null)");
530
52.5k
                    CPLFree(pszJSon);
531
52.5k
                    delete ogrLine;
532
52.5k
                }
533
111k
                ogrLine = new OGRLineString();
534
111k
            }
535
200k
            else
536
200k
            {
537
200k
                ogrLine->empty();
538
200k
            }
539
311k
            delete arc;
540
311k
            arc = new OGRCircularString();
541
311k
            arc->addPoint(&ogrPoint);
542
311k
            ogrPoint.setX(CPLAtof(tokens[1]));
543
311k
            ogrPoint.setY(CPLAtof(tokens[2]));
544
311k
            arc->addPoint(&ogrPoint);
545
311k
        }
546
1.73M
        else if (EQUAL(firsttok, "ELIN"))
547
52.8k
        {
548
52.8k
            if (ogrLine->getNumPoints() > 1)
549
18.3k
            {  // Ignore single LIPT after ARCP
550
18.3k
                OGRErr error = ogrCurve->addCurveDirectly(ogrLine);
551
18.3k
                if (error != OGRERR_NONE)
552
6.58k
                {
553
6.58k
                    char *pszJSon = ogrLine->exportToJson();
554
6.58k
                    CPLError(CE_Warning, CPLE_AppDefined,
555
6.58k
                             "Could not add geometry: %s",
556
6.58k
                             pszJSon ? pszJSon : "(null)");
557
6.58k
                    CPLFree(pszJSon);
558
6.58k
                    delete ogrLine;
559
6.58k
                }
560
18.3k
                ogrLine = nullptr;
561
18.3k
            }
562
52.8k
            if (!ogrCurve->IsEmpty())
563
36.2k
            {
564
36.2k
                if (ogrMultiLine)
565
29.5k
                {
566
29.5k
                    OGRErr error = ogrMultiLine->addGeometryDirectly(ogrCurve);
567
29.5k
                    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
29.5k
                    ogrCurve = nullptr;
577
29.5k
                }
578
36.2k
                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
36.2k
            }
593
52.8k
            end = true;
594
52.8k
        }
595
1.67M
        else if (EQUAL(firsttok, "EEDG"))
596
1.74k
        {
597
1.74k
            end = true;
598
1.74k
        }
599
1.67M
        else if (EQUAL(firsttok, "LATT"))
600
3.06k
        {
601
            // Line Attributes (ignored)
602
3.06k
        }
603
1.67M
        else if (EQUAL(firsttok, "EFLA"))
604
553
        {
605
553
            end = true;
606
553
        }
607
1.67M
        else if (EQUAL(firsttok, "ETAB"))
608
6.44k
        {
609
6.44k
            end = true;
610
6.44k
        }
611
1.66M
        else
612
1.66M
        {
613
1.66M
            CPLError(CE_Warning, CPLE_AppDefined, "Unexpected token: %s",
614
1.66M
                     firsttok);
615
1.66M
        }
616
617
2.55M
        CSLDestroy(tokens);
618
2.55M
    }
619
73.0k
    delete arc;
620
621
73.0k
    delete ogrLine;
622
623
    // Set feature geometry
624
73.0k
    if (eType == wkbMultiCurve)
625
0
    {
626
0
        feature->SetGeomFieldDirectly(geomIdx, ogrMultiLine);
627
0
        delete ogrCurve;
628
0
    }
629
73.0k
    else if (eType == wkbMultiLineString)
630
48.8k
    {
631
48.8k
        feature->SetGeomFieldDirectly(geomIdx,
632
48.8k
                                      ogrMultiLine->getLinearGeometry());
633
48.8k
        delete ogrMultiLine;
634
48.8k
        delete ogrCurve;
635
48.8k
    }
636
24.2k
    else if (eType == wkbCurvePolygon)
637
0
    {
638
0
        feature->SetGeomFieldDirectly(geomIdx, ogrPoly);
639
0
        delete ogrCurve;
640
0
    }
641
24.2k
    else if (eType == wkbPolygon)
642
0
    {
643
0
        feature->SetGeomFieldDirectly(geomIdx, ogrPoly->getLinearGeometry());
644
0
        delete ogrPoly;
645
0
        delete ogrCurve;
646
0
    }
647
24.2k
    else
648
24.2k
    {
649
24.2k
        feature->SetGeomFieldDirectly(geomIdx, ogrCurve);
650
24.2k
    }
651
73.0k
}
652
653
/************************************************************************/
654
/*                              AddLayer()                              */
655
/************************************************************************/
656
657
void ILI1Reader::AddLayer(OGRILI1Layer *poNewLayer)
658
659
13.0k
{
660
13.0k
    nLayers++;
661
662
13.0k
    papoLayers = static_cast<OGRILI1Layer **>(
663
13.0k
        CPLRealloc(papoLayers, sizeof(void *) * nLayers));
664
665
13.0k
    papoLayers[nLayers - 1] = poNewLayer;
666
13.0k
}
667
668
/************************************************************************/
669
/*                              GetLayer()                              */
670
/************************************************************************/
671
672
OGRILI1Layer *ILI1Reader::GetLayer(int iLayer) const
673
674
5.40k
{
675
5.40k
    if (iLayer < 0 || iLayer >= nLayers)
676
0
        return nullptr;
677
678
5.40k
    return papoLayers[iLayer];
679
5.40k
}
680
681
OGRILI1Layer *ILI1Reader::GetLayerByName(const char *pszLayerName)
682
683
71.6k
{
684
402k
    for (int iLayer = 0; iLayer < nLayers; iLayer++)
685
388k
    {
686
388k
        if (EQUAL(pszLayerName, papoLayers[iLayer]->GetLayerDefn()->GetName()))
687
57.4k
            return papoLayers[iLayer];
688
388k
    }
689
14.1k
    return nullptr;
690
71.6k
}
691
692
/************************************************************************/
693
/*                           GetLayerCount()                            */
694
/************************************************************************/
695
696
int ILI1Reader::GetLayerCount() const
697
698
13.3k
{
699
13.3k
    return nLayers;
700
13.3k
}
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.2k
        return nullptr;
716
717
4.34M
    if (strlen(pszLine) == 0)
718
14.2k
        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.32M
    while (strlen(pszLine) && token[0] == codeContinue && token[1] == '\0')
731
27.0k
    {
732
        // remove last token
733
27.0k
        CPLFree(tokens[CSLCount(tokens) - 1]);
734
27.0k
        tokens[CSLCount(tokens) - 1] = nullptr;
735
736
27.0k
        pszLine = CPLReadLineL(fpItf);
737
27.0k
        if (pszLine == nullptr)
738
10
        {
739
10
            break;
740
10
        }
741
27.0k
        char **conttok = CSLTokenizeString2(pszLine, " ", CSLT_PRESERVEESCAPES);
742
27.0k
        if (!conttok || conttok[0] == nullptr || !EQUAL(conttok[0], "CONT") ||
743
5.61k
            conttok[1] == nullptr)
744
21.6k
        {
745
21.6k
            CSLDestroy(conttok);
746
21.6k
            break;
747
21.6k
        }
748
749
        // append
750
5.36k
        tokens = CSLInsertStrings(tokens, -1, &conttok[1]);
751
5.36k
        token = tokens[CSLCount(tokens) - 1];
752
753
5.36k
        CSLDestroy(conttok);
754
5.36k
    }
755
4.31M
    if (tokens[0] == nullptr)
756
15.7k
    {
757
15.7k
        CSLDestroy(tokens);
758
15.7k
        tokens = nullptr;
759
15.7k
    }
760
4.31M
    return tokens;
761
4.32M
}
762
763
IILI1Reader *CreateILI1Reader()
764
9.27k
{
765
9.27k
    return new ILI1Reader();
766
9.27k
}
767
768
void DestroyILI1Reader(IILI1Reader *reader)
769
21.9k
{
770
21.9k
    if (reader)
771
9.27k
        delete reader;
772
21.9k
}