Coverage Report

Created: 2026-03-30 09:00

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