Coverage Report

Created: 2025-11-15 08:43

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