Coverage Report

Created: 2025-12-03 08:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/nas/nashandler.cpp
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * Project:  NAS Reader
4
 * Purpose:  Implementation of NASHandler class.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 **********************************************************************
8
 * Copyright (c) 2002, Frank Warmerdam
9
 * Copyright (c) 2010-2012, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include <ctype.h>
15
#include "nasreaderp.h"
16
#include "cpl_conv.h"
17
#include "cpl_string.h"
18
#include "ogr_xerces.h"
19
20
#define NASDebug(fmt, ...)                                                     \
21
0
    CPLDebugOnly("NAS", "%s:%d %s " fmt, __FILE__, __LINE__, __FUNCTION__,     \
22
0
                 __VA_ARGS__)
23
24
/*
25
  Update modes:
26
27
GID<7
28
    <wfs:Transaction version="1.0.0" service="WFS">
29
        <wfs:Delete typeName="AX_BesondereFlurstuecksgrenze">
30
            <ogc:Filter>
31
                <ogc:FeatureId fid="DENW18AL0000nANA20120117T130819Z" />
32
            </ogc:Filter>
33
        </wfs:Delete>
34
        <wfsext:Replace vendorId="AdV" safeToIgnore="false">
35
            <AP_PTO gml:id="DENW18AL0000pewY20131011T071138Z">
36
                [...]
37
            </AP_PTO>
38
            <ogc:Filter>
39
                <ogc:FeatureId fid="DENW18AL0000pewY20120117T143330Z" />
40
            </ogc:Filter>
41
        </wfsext:Replace>
42
        <wfs:Update typeName="AX_KommunalesGebiet">
43
            <wfs:Property>
44
                <wfs:Name>adv:lebenszeitintervall/adv:AA_Lebenszeitintervall/adv:endet</wfs:Name>
45
                <wfs:Value>2012-08-14T12:32:30Z</wfs:Value>
46
            </wfs:Property>
47
            <wfs:Property>
48
                <wfs:Name>adv:anlass</wfs:Name>
49
                <wfs:Value>000000</wfs:Value>
50
            </wfs:Property>
51
            <wfs:Property>
52
                <wfs:Name>adv:anlass</wfs:Name>
53
                <wfs:Value>010102</wfs:Value>
54
            </wfs:Property>
55
            <ogc:Filter>
56
                <ogc:FeatureId fid="DENW11AL000062WD20111016T122010Z" />
57
            </ogc:Filter>
58
        </wfs:Update>
59
    </wfs:Transaction>
60
61
GID>=7
62
    <wfs:Transaction>
63
        <wfs:Insert>
64
            <AX_Flurstueck gml:id="DEBY0000F0000001">
65
66
            </AX_Flurstueck>
67
            <AX_Gebaeude gml:id="DEBY0000G0000001">
68
69
            </AX_Gebaeude>
70
        </wfs:Insert>
71
        <wfs:Replace>
72
            <AX_Flurstueck gml:id="DEBY0000F0000002">
73
74
            </AX_Flurstueck>
75
            <fes:Filter>
76
                <fes:ResourceId rid="DEBY0000F000000220010101T000000Z"/>
77
            </fes:Filter>
78
        </wfs:Replace>
79
        <wfs:Delete typeNames=“AX_Buchungsstelle”>
80
            <fes:Filter>
81
                <fes:ResourceId rid="DEBY0000B000000320010101T000000Z"/>
82
                <fes:ResourceId rid="DEBY0000B000000420010101T000000Z"/>
83
84
            </fes:Filter>
85
        </wfs:Delete>
86
        <wfs:Update typeNames="adv:AX_Flurstueck">
87
            <wfs:Property>
88
                <wfs:ValueReference>adv:lebenszeitintervall/adv:AA_Lebenszeitintervall/adv:endet</wfs:ValueReference>
89
                    <wfs:Value>2007-11-13T12:00:00Z</wfs:Value>
90
                </wfs:Property>
91
            <wfs:Property>
92
            <wfs:ValueReference>adv:anlass</wfs:ValueReference>
93
                 <wfs:Value>000000</wfs:Value>
94
            </wfs:Property>
95
            <wfs:Property>
96
                 <wfs:ValueReference>adv:anlass</wfs:ValueReference>
97
                 <wfs:Value>010102</wfs:Value>
98
            </wfs:Property>
99
            <wfs:Filter>
100
                 <fes:ResourceId rid="DEBY123412345678"/>
101
            </wfs:Filter>
102
        </wfs:Update>
103
    </wfs:Transaction>
104
*/
105
106
/************************************************************************/
107
/*                             NASHandler()                             */
108
/************************************************************************/
109
110
NASHandler::NASHandler(NASReader *poReader)
111
0
    : m_poReader(poReader), m_pszCurField(nullptr), m_pszGeometry(nullptr),
112
0
      m_nGeomAlloc(0), m_nGeomLen(0), m_nGeometryDepth(0),
113
0
      m_nGeometryPropertyIndex(-1), m_nDepth(0), m_nDepthFeature(0),
114
0
      m_bIgnoreFeature(false), m_Locator(nullptr)
115
0
{
116
0
}
117
118
/************************************************************************/
119
/*                            ~NASHandler()                             */
120
/************************************************************************/
121
122
NASHandler::~NASHandler()
123
124
0
{
125
0
    CPLFree(m_pszCurField);
126
0
    CPLFree(m_pszGeometry);
127
0
}
128
129
/************************************************************************/
130
/*                        GetAttributes()                               */
131
/************************************************************************/
132
133
CPLString NASHandler::GetAttributes(const Attributes *attrs)
134
0
{
135
0
    CPLString osRes;
136
137
0
    for (unsigned int i = 0; i < attrs->getLength(); i++)
138
0
    {
139
0
        osRes += " ";
140
0
        osRes += transcode(attrs->getQName(i));
141
0
        osRes += "=\"";
142
0
        osRes += transcode(attrs->getValue(i));
143
0
        osRes += "\"";
144
0
    }
145
0
    return osRes;
146
0
}
147
148
/************************************************************************/
149
/*                   setDocumentLocator()                               */
150
/************************************************************************/
151
152
void NASHandler::setDocumentLocator(const Locator *locator)
153
0
{
154
0
    m_Locator = locator;
155
0
    return DefaultHandler::setDocumentLocator(locator);
156
0
}
157
158
/************************************************************************/
159
/*                            startElement()                            */
160
/************************************************************************/
161
162
void NASHandler::startElement(const XMLCh *const /* uri */,
163
                              const XMLCh *const localname,
164
                              const XMLCh *const /* qname */,
165
                              const Attributes &attrs)
166
167
0
{
168
0
    m_nEntityCounter = 0;
169
170
0
    GMLReadState *poState = m_poReader->GetState();
171
172
0
    transcode(localname, m_osElementName);
173
174
0
    NASDebug("element=%s poState=%s m_nDepth=%d m_nDepthFeature=%d context=%s",
175
0
             m_osElementName.c_str(), poState ? "(state)" : "(no state)",
176
0
             m_nDepth, m_nDepthFeature, m_osDeleteContext.c_str());
177
178
0
    m_nDepth++;
179
0
    if (m_bIgnoreFeature && m_nDepth > m_nDepthFeature)
180
0
        return;
181
182
0
    if (m_nDepthFeature == 0)
183
0
    {
184
0
        if (m_osElementName == "Replace")
185
0
        {
186
0
            const XMLCh achSafeToIgnore[] = {'s', 'a', 'f', 'e', 'T', 'o', 'I',
187
0
                                             'g', 'n', 'o', 'r', 'e', 0};
188
0
            int nIndex = attrs.getIndex(achSafeToIgnore);
189
0
            if (nIndex != -1)
190
0
                transcode(attrs.getValue(nIndex), m_osSafeToIgnore);
191
0
            else
192
0
                m_osSafeToIgnore = "true";
193
0
            m_osReplacingFID = "";
194
195
0
            CPLAssert(m_osDeleteContext == "");
196
0
            m_osDeleteContext = m_osElementName;
197
0
        }
198
0
        else if (m_osElementName == "Update" || m_osElementName == "Delete")
199
0
        {
200
0
            const XMLCh achTypeNames[] = {'t', 'y', 'p', 'e', 'N',
201
0
                                          'a', 'm', 'e', 's', 0};
202
0
            const XMLCh achTypeName[] = {'t', 'y', 'p', 'e', 'N',
203
0
                                         'a', 'm', 'e', 0};
204
0
            int nIndex = attrs.getIndex(achTypeNames);
205
0
            if (nIndex == -1)
206
0
                nIndex = attrs.getIndex(achTypeName);
207
208
0
            if (nIndex == -1)
209
0
            {
210
0
                CPLError(CE_Failure, CPLE_AssertionFailed,
211
0
                         "NAS: expected type name missing at %s:%d:%d",
212
0
                         m_poReader->GetSourceFileName(),
213
0
                         static_cast<int>(m_Locator->getLineNumber()),
214
0
                         static_cast<int>(m_Locator->getColumnNumber()));
215
0
                return;
216
0
            }
217
218
0
            transcode(attrs.getValue(nIndex), m_osTypeName);
219
220
0
            const char *pszTypeName = strchr(m_osTypeName.c_str(), ':');
221
0
            pszTypeName = pszTypeName ? pszTypeName + 1 : m_osTypeName.c_str();
222
0
            m_osTypeName = pszTypeName;
223
224
0
            CPLAssert(m_osDeleteContext == "");
225
0
            m_osDeleteContext = m_osElementName;
226
0
        }
227
0
        else if (m_osDeleteContext == "Update" &&
228
0
                 (m_osElementName == "Name" ||
229
0
                  m_osElementName == "ValueReference" ||
230
0
                  m_osElementName == "Value"))
231
0
        {
232
            // fetch value
233
0
            CPLFree(m_pszCurField);
234
0
            m_pszCurField = CPLStrdup("");
235
0
        }
236
0
        else if (m_osDeleteContext != "" && (m_osElementName == "ResourceId" ||
237
0
                                             m_osElementName == "FeatureId"))
238
0
        {
239
0
            const char *pszFilteredClassName =
240
0
                m_poReader->GetFilteredClassName();
241
0
            if (!pszFilteredClassName || EQUAL(pszFilteredClassName, "Delete"))
242
0
            {
243
0
                const XMLCh achRid[] = {'r', 'i', 'd', 0};
244
0
                const XMLCh achFid[] = {'f', 'i', 'd', 0};
245
0
                if (m_osTypeName == "")
246
0
                {
247
0
                    CPLError(CE_Failure, CPLE_AssertionFailed,
248
0
                             "NAS: type name(s) missing at %s:%d:%d",
249
0
                             m_poReader->GetSourceFileName(),
250
0
                             static_cast<int>(m_Locator->getLineNumber()),
251
0
                             static_cast<int>(m_Locator->getColumnNumber()));
252
0
                    return;
253
0
                }
254
255
0
                int nIndex = attrs.getIndex(
256
0
                    m_osElementName == "ResourceId" ? achRid : achFid);
257
0
                if (nIndex == -1)
258
0
                {
259
0
                    CPLError(CE_Failure, CPLE_AssertionFailed,
260
0
                             "NAS: expected feature id missing at %s,%d:%d",
261
0
                             m_poReader->GetSourceFileName(),
262
0
                             static_cast<int>(m_Locator->getLineNumber()),
263
0
                             static_cast<int>(m_Locator->getColumnNumber()));
264
0
                    return;
265
0
                }
266
267
0
                CPLString osFeatureId;
268
0
                transcode(attrs.getValue(nIndex), osFeatureId);
269
270
0
                m_poReader->PushFeature("Delete", attrs);
271
0
                m_poReader->SetFeaturePropertyDirectly("typeName",
272
0
                                                       CPLStrdup(m_osTypeName));
273
0
                m_poReader->SetFeaturePropertyDirectly(
274
0
                    "context", CPLStrdup(m_osDeleteContext));
275
0
                m_poReader->SetFeaturePropertyDirectly("FeatureId",
276
0
                                                       CPLStrdup(osFeatureId));
277
278
0
                if (m_osDeleteContext == "Replace")
279
0
                {
280
0
                    if (m_osReplacingFID == "")
281
0
                    {
282
0
                        CPLError(
283
0
                            CE_Failure, CPLE_AssertionFailed,
284
0
                            "NAS: replacing feature id not set at %s:%d:%d",
285
0
                            m_poReader->GetSourceFileName(),
286
0
                            static_cast<int>(m_Locator->getLineNumber()),
287
0
                            static_cast<int>(m_Locator->getColumnNumber()));
288
0
                        return;
289
0
                    }
290
291
0
                    m_poReader->SetFeaturePropertyDirectly(
292
0
                        "replacedBy", CPLStrdup(m_osReplacingFID));
293
0
                    m_poReader->SetFeaturePropertyDirectly(
294
0
                        "safeToIgnore", CPLStrdup(m_osSafeToIgnore));
295
0
                    m_osReplacingFID = "";
296
0
                    m_osSafeToIgnore = "";
297
0
                }
298
0
                else if (m_osDeleteContext == "Update")
299
0
                {
300
0
                    m_poReader->SetFeaturePropertyDirectly(
301
0
                        "endet", CPLStrdup(m_osUpdateEnds));
302
0
                    for (std::list<CPLString>::iterator it =
303
0
                             m_UpdateOccasions.begin();
304
0
                         it != m_UpdateOccasions.end(); ++it)
305
0
                    {
306
0
                        m_poReader->SetFeaturePropertyDirectly("anlass",
307
0
                                                               CPLStrdup(*it));
308
0
                    }
309
310
0
                    m_osUpdateEnds = "";
311
0
                    m_UpdateOccasions.clear();
312
0
                }
313
314
0
                return;
315
0
            }
316
0
            else
317
0
            {
318
                // we don't issue Delete features
319
0
                m_osDeleteContext = "";
320
0
            }
321
0
        }
322
0
        else if (m_poReader->IsFeatureElement(m_osElementName))
323
0
        {
324
0
            m_nDepthFeature = m_nDepth - 1;
325
326
            // record id of replacing feature
327
0
            if (m_osDeleteContext == "Replace")
328
0
            {
329
0
                const XMLCh achGmlId[] = {'g', 'm', 'l', ':', 'i', 'd', 0};
330
0
                int nIndex = attrs.getIndex(achGmlId);
331
0
                if (nIndex == -1)
332
0
                {
333
0
                    CPLError(CE_Failure, CPLE_AssertionFailed,
334
0
                             "NAS: id of replacing feature not set at %s:%d:%d",
335
0
                             m_poReader->GetSourceFileName(),
336
0
                             static_cast<int>(m_Locator->getLineNumber()),
337
0
                             static_cast<int>(m_Locator->getColumnNumber()));
338
0
                    m_bIgnoreFeature = true;
339
0
                    return;
340
0
                }
341
342
0
                CPLAssert(m_osReplacingFID == "");
343
0
                transcode(attrs.getValue(nIndex), m_osReplacingFID);
344
0
            }
345
346
0
            m_osTypeName = m_osElementName;
347
348
0
            const char *pszFilteredClassName =
349
0
                m_poReader->GetFilteredClassName();
350
0
            m_bIgnoreFeature = pszFilteredClassName &&
351
0
                               !EQUAL(m_osElementName, pszFilteredClassName);
352
353
0
            if (!m_bIgnoreFeature)
354
0
                m_poReader->PushFeature(m_osElementName, attrs);
355
356
0
            return;
357
0
        }
358
0
    }
359
0
    else if (m_pszGeometry != nullptr || IsGeometryElement(m_osElementName))
360
0
    {
361
0
        if (m_nGeometryPropertyIndex == -1 && poState->m_poFeature &&
362
0
            poState->m_poFeature->GetClass())
363
0
        {
364
0
            GMLFeatureClass *poClass = poState->m_poFeature->GetClass();
365
0
            m_nGeometryPropertyIndex =
366
0
                poClass->GetGeometryPropertyIndexBySrcElement(
367
0
                    poState->osPath.c_str());
368
0
        }
369
370
0
        const int nLNLen = static_cast<int>(m_osElementName.size());
371
0
        CPLString osAttributes = GetAttributes(&attrs);
372
373
        /* should save attributes too! */
374
375
0
        if (m_pszGeometry == nullptr)
376
0
            m_nGeometryDepth = poState->m_nPathLength;
377
378
0
        if (m_pszGeometry == nullptr ||
379
0
            m_nGeomLen + nLNLen + 4 + (int)osAttributes.size() > m_nGeomAlloc)
380
0
        {
381
0
            m_nGeomAlloc =
382
0
                (int)(m_nGeomAlloc * 1.3 + nLNLen + osAttributes.size() + 1000);
383
0
            m_pszGeometry = (char *)CPLRealloc(m_pszGeometry, m_nGeomAlloc);
384
0
        }
385
386
0
        strcpy(m_pszGeometry + m_nGeomLen, "<");
387
0
        strcpy(m_pszGeometry + m_nGeomLen + 1, m_osElementName);
388
389
0
        if (!osAttributes.empty())
390
0
        {
391
0
            strcat(m_pszGeometry + m_nGeomLen, " ");
392
0
            strcat(m_pszGeometry + m_nGeomLen, osAttributes);
393
0
        }
394
395
0
        strcat(m_pszGeometry + m_nGeomLen, ">");
396
0
        m_nGeomLen += static_cast<int>(strlen(m_pszGeometry + m_nGeomLen));
397
0
    }
398
0
    else if (m_poReader->IsAttributeElement(m_osElementName, attrs))
399
0
    {
400
0
        m_poReader->DealWithAttributes(
401
0
            m_osElementName, static_cast<int>(m_osElementName.length()), attrs);
402
0
        CPLFree(m_pszCurField);
403
0
        m_pszCurField = CPLStrdup("");
404
0
    }
405
406
0
    poState->PushPath(m_osElementName);
407
408
0
    if (poState->osPath.size() > 512)
409
0
    {
410
0
        CPLError(CE_Failure, CPLE_AssertionFailed,
411
0
                 "NAS: Too long path. Stop parsing at %s:%d:%d",
412
0
                 m_poReader->GetSourceFileName(),
413
0
                 static_cast<int>(m_Locator->getLineNumber()),
414
0
                 static_cast<int>(m_Locator->getColumnNumber()));
415
0
        m_poReader->StopParsing();
416
0
    }
417
0
}
418
419
/************************************************************************/
420
/*                             endElement()                             */
421
/************************************************************************/
422
void NASHandler::endElement(const XMLCh *const /* uri */,
423
                            const XMLCh *const localname,
424
                            const XMLCh *const /* qname */)
425
426
0
{
427
0
    m_nEntityCounter = 0;
428
429
0
    GMLReadState *poState = m_poReader->GetState();
430
431
0
    transcode(localname, m_osElementName);
432
433
0
    NASDebug("element=%s poState=%s m_nDepth=%d m_nDepthFeature=%d context=%s",
434
0
             m_osElementName.c_str(), poState ? "(state)" : "(no state)",
435
0
             m_nDepth, m_nDepthFeature, m_osDeleteContext.c_str());
436
437
0
    m_nDepth--;
438
0
    if (m_bIgnoreFeature && m_nDepth >= m_nDepthFeature)
439
0
    {
440
0
        if (m_nDepth == m_nDepthFeature)
441
0
        {
442
0
            m_bIgnoreFeature = false;
443
0
            m_nDepthFeature = 0;
444
0
        }
445
0
        return;
446
0
    }
447
448
0
    if (m_osDeleteContext == "Update")
449
0
    {
450
0
        if (m_osElementName == "Name" || m_osElementName == "ValueReference")
451
0
        {
452
0
            const char *pszName;
453
0
            pszName = strrchr(m_pszCurField, '/');
454
0
            pszName = pszName ? pszName + 1 : m_pszCurField;
455
0
            pszName = strrchr(pszName, ':');
456
0
            pszName = pszName ? pszName + 1 : m_pszCurField;
457
458
0
            CPLAssert(m_osUpdatePropertyName == "");
459
0
            m_osUpdatePropertyName = pszName;
460
0
            CPLFree(m_pszCurField);
461
0
            m_pszCurField = nullptr;
462
463
0
            if (m_osUpdatePropertyName != "endet" &&
464
0
                m_osUpdatePropertyName != "anlass")
465
0
            {
466
0
                CPLError(CE_Failure, CPLE_AppDefined,
467
0
                         "NAS: Unexpected property name %s at %s:%d:%d",
468
0
                         m_osUpdatePropertyName.c_str(),
469
0
                         m_poReader->GetSourceFileName(),
470
0
                         static_cast<int>(m_Locator->getLineNumber()),
471
0
                         static_cast<int>(m_Locator->getColumnNumber()));
472
0
                m_osUpdatePropertyName = "";
473
0
            }
474
0
        }
475
0
        else if (m_osElementName == "Value")
476
0
        {
477
0
            CPLAssert(m_osUpdatePropertyName != "");
478
0
            if (m_osUpdatePropertyName == "endet")
479
0
                m_osUpdateEnds = m_pszCurField;
480
0
            else if (m_osUpdatePropertyName == "anlass")
481
0
                m_UpdateOccasions.push_back(m_pszCurField);
482
0
            m_osUpdatePropertyName = "";
483
0
            CPLFree(m_pszCurField);
484
0
            m_pszCurField = nullptr;
485
0
        }
486
0
    }
487
0
    else if (m_pszCurField != nullptr && poState->m_poFeature != nullptr)
488
0
    {
489
0
        m_poReader->SetFeaturePropertyDirectly(poState->osPath.c_str(),
490
0
                                               m_pszCurField);
491
0
        m_pszCurField = nullptr;
492
0
    }
493
494
    /* -------------------------------------------------------------------- */
495
    /*      If we are collecting Geometry than store it, and consider if    */
496
    /*      this is the end of the geometry.                                */
497
    /* -------------------------------------------------------------------- */
498
0
    if (m_pszGeometry != nullptr)
499
0
    {
500
0
        int nLNLen = static_cast<int>(m_osElementName.size());
501
502
        /* should save attributes too! */
503
504
0
        if (m_nGeomLen + nLNLen + 4 > m_nGeomAlloc)
505
0
        {
506
0
            m_nGeomAlloc = (int)(m_nGeomAlloc * 1.3 + nLNLen + 1000);
507
0
            m_pszGeometry = (char *)CPLRealloc(m_pszGeometry, m_nGeomAlloc);
508
0
        }
509
510
0
        strcat(m_pszGeometry + m_nGeomLen, "</");
511
0
        strcpy(m_pszGeometry + m_nGeomLen + 2, m_osElementName);
512
0
        strcat(m_pszGeometry + m_nGeomLen + nLNLen + 2, ">");
513
0
        m_nGeomLen += static_cast<int>(strlen(m_pszGeometry + m_nGeomLen));
514
515
0
        if (poState->m_nPathLength == m_nGeometryDepth + 1)
516
0
        {
517
0
            if (poState->m_poFeature != nullptr)
518
0
            {
519
0
                CPLXMLNode *psNode = CPLParseXMLString(m_pszGeometry);
520
0
                if (psNode)
521
0
                {
522
                    /* workaround for common malformed gml:pos with just a
523
                     * elevation value instead of a full 3D coordinate:
524
                     *
525
                     * <gml:Point gml:id="BII2H">
526
                     *    <gml:pos
527
                     * srsName="urn:adv:crs:ETRS89_h">41.394</gml:pos>
528
                     * </gml:Point>
529
                     *
530
                     */
531
0
                    const char *pszPos =
532
0
                        CPLGetXMLValue(psNode, "=Point.pos", nullptr);
533
0
                    if (pszPos != nullptr && strstr(pszPos, " ") == nullptr)
534
0
                    {
535
0
                        CPLSetXMLValue(psNode, "pos",
536
0
                                       CPLSPrintf("0 0 %s", pszPos));
537
0
                    }
538
539
0
                    if (m_nGeometryPropertyIndex >= 0 &&
540
0
                        m_nGeometryPropertyIndex <
541
0
                            poState->m_poFeature->GetGeometryCount() &&
542
0
                        poState->m_poFeature
543
0
                            ->GetGeometryList()[m_nGeometryPropertyIndex])
544
0
                    {
545
0
                        int iId =
546
0
                            poState->m_poFeature->GetClass()->GetPropertyIndex(
547
0
                                "gml_id");
548
0
                        const GMLProperty *poIdProp =
549
0
                            poState->m_poFeature->GetProperty(iId);
550
#ifdef DEBUG_VERBOSE
551
                        char *pszOldGeom = CPLSerializeXMLTree(
552
                            poState->m_poFeature
553
                                ->GetGeometryList()[m_nGeometryPropertyIndex]);
554
555
                        NASDebug(
556
                            "Overwriting other geometry (%s; replace:%s; "
557
                            "with:%s) at %s:%d:%d",
558
                            poIdProp && poIdProp->nSubProperties > 0 &&
559
                                    poIdProp->papszSubProperties[0]
560
                                ? poIdProp->papszSubProperties[0]
561
                                : "(null)",
562
                            m_pszGeometry, pszOldGeom,
563
                            m_poReader->GetSourceFileName(),
564
                            static_cast<int>(m_Locator->getLineNumber()),
565
                            static_cast<int>(m_Locator->getColumnNumber()));
566
567
                        CPLFree(pszOldGeom);
568
#else
569
0
                        CPLError(
570
0
                            CE_Warning, CPLE_AppDefined,
571
0
                            "NAS: Overwriting other geometry (%s) at %s:%d:%d",
572
0
                            poIdProp && poIdProp->nSubProperties > 0 &&
573
0
                                    poIdProp->papszSubProperties[0]
574
0
                                ? poIdProp->papszSubProperties[0]
575
0
                                : "(null)",
576
0
                            m_poReader->GetSourceFileName(),
577
0
                            static_cast<int>(m_Locator->getLineNumber()),
578
0
                            static_cast<int>(m_Locator->getColumnNumber()));
579
0
#endif
580
0
                    }
581
582
0
                    if (m_nGeometryPropertyIndex >= 0)
583
0
                        poState->m_poFeature->SetGeometryDirectly(
584
0
                            m_nGeometryPropertyIndex, psNode);
585
586
                    // no geometry property or property without element path
587
0
                    else if (poState->m_poFeature->GetClass()
588
0
                                     ->GetGeometryPropertyCount() == 0 ||
589
0
                             (poState->m_poFeature->GetClass()
590
0
                                      ->GetGeometryPropertyCount() == 1 &&
591
0
                              poState->m_poFeature->GetClass()
592
0
                                  ->GetGeometryProperty(0)
593
0
                                  ->GetSrcElement() &&
594
0
                              *poState->m_poFeature->GetClass()
595
0
                                      ->GetGeometryProperty(0)
596
0
                                      ->GetSrcElement() == 0))
597
0
                        poState->m_poFeature->SetGeometryDirectly(psNode);
598
599
0
                    else
600
0
                    {
601
0
                        CPLError(
602
0
                            CE_Warning, CPLE_AssertionFailed,
603
0
                            "NAS: Unexpected geometry skipped (class:%s "
604
0
                            "path:%s geom:%s) at %s:%d:%d",
605
0
                            poState->m_poFeature->GetClass()->GetName(),
606
0
                            poState->osPath.c_str(), m_pszGeometry,
607
0
                            m_poReader->GetSourceFileName(),
608
0
                            static_cast<int>(m_Locator->getLineNumber()),
609
0
                            static_cast<int>(m_Locator->getColumnNumber()));
610
0
                        CPLDestroyXMLNode(psNode);
611
0
                    }
612
0
                }
613
0
                else
614
0
                    CPLError(CE_Warning, CPLE_AppDefined,
615
0
                             "NAS: Invalid geometry skipped at %s:%d:%d",
616
0
                             m_poReader->GetSourceFileName(),
617
0
                             static_cast<int>(m_Locator->getLineNumber()),
618
0
                             static_cast<int>(m_Locator->getColumnNumber()));
619
0
            }
620
0
            else
621
0
                CPLError(CE_Warning, CPLE_AppDefined,
622
0
                         "NAS: Skipping geometry without feature at %s:%d:%d",
623
0
                         m_poReader->GetSourceFileName(),
624
0
                         static_cast<int>(m_Locator->getLineNumber()),
625
0
                         static_cast<int>(m_Locator->getColumnNumber()));
626
627
0
            CPLFree(m_pszGeometry);
628
0
            m_pszGeometry = nullptr;
629
0
            m_nGeomAlloc = m_nGeomLen = 0;
630
0
            m_nGeometryPropertyIndex = -1;
631
0
        }
632
0
    }
633
634
    // Finished actual feature or ResourceId/FeatureId of Delete/Replace/Update operation
635
0
    if ((m_nDepth == m_nDepthFeature && poState->m_poFeature != nullptr &&
636
0
         EQUAL(m_osElementName,
637
0
               poState->m_poFeature->GetClass()->GetElementName())) ||
638
0
        (m_osDeleteContext != "" &&
639
0
         (m_osElementName == "ResourceId" || m_osElementName == "FeatureId")))
640
0
    {
641
0
        m_nDepthFeature = 0;
642
0
        m_poReader->PopState();
643
0
    }
644
0
    else
645
0
        poState->PopPath();
646
647
0
    if (m_osDeleteContext == m_osElementName)
648
0
    {
649
0
        m_osDeleteContext = "";
650
0
    }
651
0
}
652
653
/************************************************************************/
654
/*                             startEntity()                            */
655
/************************************************************************/
656
657
void NASHandler::startEntity(const XMLCh *const /* name */)
658
0
{
659
0
    m_nEntityCounter++;
660
0
    if (m_nEntityCounter > 1000 && !m_poReader->HasStoppedParsing())
661
0
    {
662
0
        throw SAXNotSupportedException(
663
0
            "File probably corrupted (million laugh pattern)");
664
0
    }
665
0
}
666
667
/************************************************************************/
668
/*                             characters()                             */
669
/************************************************************************/
670
671
void NASHandler::characters(const XMLCh *const chars, const XMLSize_t length)
672
0
{
673
0
    if (m_pszCurField != nullptr)
674
0
    {
675
0
        const int nCurFieldLength = static_cast<int>(strlen(m_pszCurField));
676
677
0
        int nSkipped = 0;
678
0
        if (nCurFieldLength == 0)
679
0
        {
680
            // Ignore white space
681
0
            while (chars[nSkipped] == ' ' || chars[nSkipped] == 10 ||
682
0
                   chars[nSkipped] == 13 || chars[nSkipped] == '\t')
683
0
                nSkipped++;
684
0
        }
685
686
0
        transcode(chars + nSkipped, m_osCharacters,
687
0
                  static_cast<int>(length) - nSkipped);
688
689
0
        m_pszCurField = static_cast<char *>(CPLRealloc(
690
0
            m_pszCurField, nCurFieldLength + m_osCharacters.size() + 1));
691
0
        memcpy(m_pszCurField + nCurFieldLength, m_osCharacters.c_str(),
692
0
               m_osCharacters.size() + 1);
693
0
    }
694
695
0
    if (m_pszGeometry != nullptr)
696
0
    {
697
0
        int nSkipped = 0;
698
0
        if (m_nGeomLen == 0)
699
0
        {
700
            // Ignore white space
701
0
            while (chars[nSkipped] == ' ' || chars[nSkipped] == 10 ||
702
0
                   chars[nSkipped] == 13 || chars[nSkipped] == '\t')
703
0
                nSkipped++;
704
0
        }
705
706
0
        transcode(chars + nSkipped, m_osCharacters,
707
0
                  static_cast<int>(length) - nSkipped);
708
709
0
        const int nCharsLen = static_cast<int>(m_osCharacters.size());
710
711
0
        if (m_nGeomLen + nCharsLen * 4 + 4 > m_nGeomAlloc)
712
0
        {
713
0
            m_nGeomAlloc = (int)(m_nGeomAlloc * 1.3 + nCharsLen * 4 + 1000);
714
0
            m_pszGeometry = (char *)CPLRealloc(m_pszGeometry, m_nGeomAlloc);
715
0
        }
716
717
0
        memcpy(m_pszGeometry + m_nGeomLen, m_osCharacters.c_str(),
718
0
               m_osCharacters.size() + 1);
719
0
        m_nGeomLen += static_cast<int>(strlen(m_pszGeometry + m_nGeomLen));
720
0
    }
721
0
}
722
723
/************************************************************************/
724
/*                             fatalError()                             */
725
/************************************************************************/
726
727
void NASHandler::fatalError(const SAXParseException &exception)
728
729
0
{
730
0
    CPLString osErrMsg;
731
0
    transcode(exception.getMessage(), osErrMsg);
732
0
    CPLError(CE_Failure, CPLE_AppDefined,
733
0
             "NAS: XML Parsing Error: %s at line %d, column %d\n",
734
0
             osErrMsg.c_str(), static_cast<int>(exception.getLineNumber()),
735
0
             static_cast<int>(exception.getColumnNumber()));
736
0
}
737
738
/************************************************************************/
739
/*                         IsGeometryElement()                          */
740
/************************************************************************/
741
742
bool NASHandler::IsGeometryElement(const char *pszElement)
743
744
0
{
745
0
    return strcmp(pszElement, "Polygon") == 0 ||
746
0
           strcmp(pszElement, "MultiPolygon") == 0 ||
747
0
           strcmp(pszElement, "MultiPoint") == 0 ||
748
0
           strcmp(pszElement, "MultiLineString") == 0 ||
749
0
           strcmp(pszElement, "MultiSurface") == 0 ||
750
0
           strcmp(pszElement, "GeometryCollection") == 0 ||
751
0
           strcmp(pszElement, "Point") == 0 ||
752
0
           strcmp(pszElement, "Curve") == 0 ||
753
0
           strcmp(pszElement, "MultiCurve") == 0 ||
754
0
           strcmp(pszElement, "CompositeCurve") == 0 ||
755
0
           strcmp(pszElement, "Surface") == 0 ||
756
0
           strcmp(pszElement, "PolygonPatch") == 0 ||
757
0
           strcmp(pszElement, "LineString") == 0;
758
0
}
759
760
// vim: set sw=4 expandtab ai :