Coverage Report

Created: 2025-08-11 09:23

/src/gdal/ogr/ogrsf_frmts/nas/ogrnaslayer.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  OGR
4
 * Purpose:  Implements OGRNASLayer class.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
9
 * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_conv.h"
15
#include "cpl_port.h"
16
#include "cpl_string.h"
17
#include "ogr_nas.h"
18
19
/************************************************************************/
20
/*                           OGRNASLayer()                              */
21
/************************************************************************/
22
23
OGRNASLayer::OGRNASLayer(const char *pszName, OGRNASDataSource *poDSIn)
24
0
    : poFeatureDefn(new OGRFeatureDefn(
25
0
          pszName + (STARTS_WITH_CI(pszName, "ogr:") ? 4 : 0))),
26
0
      iNextNASId(0), poDS(poDSIn),
27
      // Readers should get the corresponding GMLFeatureClass and cache it.
28
0
      poFClass(poDS->GetReader()->GetClass(pszName))
29
0
{
30
0
    SetDescription(poFeatureDefn->GetName());
31
0
    poFeatureDefn->Reference();
32
0
    poFeatureDefn->SetGeomType(wkbNone);
33
0
}
34
35
/************************************************************************/
36
/*                           ~OGRNASLayer()                           */
37
/************************************************************************/
38
39
OGRNASLayer::~OGRNASLayer()
40
41
0
{
42
0
    if (poFeatureDefn)
43
0
        poFeatureDefn->Release();
44
0
}
45
46
/************************************************************************/
47
/*                            ResetReading()                            */
48
/************************************************************************/
49
50
void OGRNASLayer::ResetReading()
51
52
0
{
53
0
    iNextNASId = 0;
54
0
    poDS->GetReader()->ResetReading();
55
0
    if (poFClass)
56
0
        poDS->GetReader()->SetFilteredClassName(poFClass->GetElementName());
57
0
}
58
59
/************************************************************************/
60
/*                           GetNextFeature()                           */
61
/************************************************************************/
62
63
OGRFeature *OGRNASLayer::GetNextFeature()
64
65
0
{
66
0
    GMLFeature *poNASFeature = nullptr;
67
68
0
    if (iNextNASId == 0)
69
0
        ResetReading();
70
71
    /* ==================================================================== */
72
    /*      Loop till we find and translate a feature meeting all our       */
73
    /*      requirements.                                                   */
74
    /* ==================================================================== */
75
0
    while (true)
76
0
    {
77
        /* --------------------------------------------------------------------
78
         */
79
        /*      Cleanup last feature, and get a new raw nas feature. */
80
        /* --------------------------------------------------------------------
81
         */
82
0
        delete poNASFeature;
83
0
        poNASFeature = poDS->GetReader()->NextFeature();
84
0
        if (poNASFeature == nullptr)
85
0
            return nullptr;
86
87
        /* --------------------------------------------------------------------
88
         */
89
        /*      Is it of the proper feature class? */
90
        /* --------------------------------------------------------------------
91
         */
92
93
        // We count reading low level NAS features as a feature read for
94
        // work checking purposes, though at least we didn't necessary
95
        // have to turn it into an OGRFeature.
96
0
        m_nFeaturesRead++;
97
98
0
        if (poNASFeature->GetClass() != poFClass)
99
0
            continue;
100
101
0
        iNextNASId++;
102
103
        /* --------------------------------------------------------------------
104
         */
105
        /*      Does it satisfy the spatial query, if there is one? */
106
        /* --------------------------------------------------------------------
107
         */
108
0
        const CPLXMLNode *const *papsGeometry = poNASFeature->GetGeometryList();
109
110
0
        std::vector<OGRGeometry *> poGeom(poNASFeature->GetGeometryCount());
111
112
0
        bool bErrored = false, bFiltered = false;
113
0
        CPLString osLastErrorMsg;
114
0
        for (int iGeom = 0; iGeom < poNASFeature->GetGeometryCount(); ++iGeom)
115
0
        {
116
0
            if (papsGeometry[iGeom] == nullptr)
117
0
            {
118
0
                poGeom[iGeom] = nullptr;
119
0
            }
120
0
            else
121
0
            {
122
0
                CPLPushErrorHandler(CPLQuietErrorHandler);
123
124
0
                poGeom[iGeom] =
125
0
                    (OGRGeometry *)OGR_G_CreateFromGMLTree(papsGeometry[iGeom]);
126
0
                CPLPopErrorHandler();
127
0
                if (poGeom[iGeom] == nullptr)
128
0
                    osLastErrorMsg = CPLGetLastErrorMsg();
129
0
                poGeom[iGeom] = NASReader::ConvertGeometry(poGeom[iGeom]);
130
0
                poGeom[iGeom] =
131
0
                    OGRGeometryFactory::forceTo(poGeom[iGeom], GetGeomType());
132
                // poGeom->dumpReadable( 0, "NAS: " );
133
134
0
                if (poGeom[iGeom] == nullptr)
135
0
                    bErrored = true;
136
0
            }
137
138
0
            bFiltered =
139
0
                m_poFilterGeom != nullptr && !FilterGeometry(poGeom[iGeom]);
140
0
            if (bErrored || bFiltered)
141
0
            {
142
0
                while (iGeom > 0)
143
0
                    delete poGeom[--iGeom];
144
0
                poGeom.clear();
145
146
0
                break;
147
0
            }
148
0
        }
149
150
0
        if (bErrored)
151
0
        {
152
153
0
            CPLString osGMLId;
154
0
            if (poFClass->GetPropertyIndex("gml_id") == 0)
155
0
            {
156
0
                const GMLProperty *psGMLProperty = poNASFeature->GetProperty(0);
157
0
                if (psGMLProperty && psGMLProperty->nSubProperties == 1)
158
0
                {
159
0
                    osGMLId.Printf("(gml_id=%s) ",
160
0
                                   psGMLProperty->papszSubProperties[0]);
161
0
                }
162
0
            }
163
164
0
            delete poNASFeature;
165
0
            poNASFeature = nullptr;
166
167
0
            const bool bGoOn = CPLTestBool(
168
0
                CPLGetConfigOption("NAS_SKIP_CORRUPTED_FEATURES", "NO"));
169
0
            CPLError(bGoOn ? CE_Warning : CE_Failure, CPLE_AppDefined,
170
0
                     "Geometry of feature %d %scannot be parsed: %s%s",
171
0
                     iNextNASId, osGMLId.c_str(), osLastErrorMsg.c_str(),
172
0
                     bGoOn ? ". Skipping to next feature."
173
0
                           : ". You may set the NAS_SKIP_CORRUPTED_FEATURES "
174
0
                             "configuration option to YES to skip to the next "
175
0
                             "feature");
176
0
            if (bGoOn)
177
0
                continue;
178
179
0
            return nullptr;
180
0
        }
181
182
0
        if (bFiltered)
183
0
            continue;
184
185
        /* --------------------------------------------------------------------
186
         */
187
        /*      Convert the whole feature into an OGRFeature. */
188
        /* --------------------------------------------------------------------
189
         */
190
0
        OGRFeature *poOGRFeature = new OGRFeature(GetLayerDefn());
191
192
0
        poOGRFeature->SetFID(iNextNASId);
193
194
0
        for (int iField = 0; iField < poFClass->GetPropertyCount(); iField++)
195
0
        {
196
0
            const GMLProperty *psGMLProperty =
197
0
                poNASFeature->GetProperty(iField);
198
0
            if (psGMLProperty == nullptr || psGMLProperty->nSubProperties == 0)
199
0
                continue;
200
201
0
            switch (poFClass->GetProperty(iField)->GetType())
202
0
            {
203
0
                case GMLPT_Real:
204
0
                {
205
0
                    poOGRFeature->SetField(
206
0
                        iField, CPLAtof(psGMLProperty->papszSubProperties[0]));
207
0
                }
208
0
                break;
209
210
0
                case GMLPT_IntegerList:
211
0
                {
212
0
                    int nCount = psGMLProperty->nSubProperties;
213
0
                    int *panIntList =
214
0
                        static_cast<int *>(CPLMalloc(sizeof(int) * nCount));
215
216
0
                    for (int i = 0; i < nCount; i++)
217
0
                        panIntList[i] =
218
0
                            atoi(psGMLProperty->papszSubProperties[i]);
219
220
0
                    poOGRFeature->SetField(iField, nCount, panIntList);
221
0
                    CPLFree(panIntList);
222
0
                }
223
0
                break;
224
225
0
                case GMLPT_RealList:
226
0
                {
227
0
                    int nCount = psGMLProperty->nSubProperties;
228
0
                    double *padfList = static_cast<double *>(
229
0
                        CPLMalloc(sizeof(double) * nCount));
230
231
0
                    for (int i = 0; i < nCount; i++)
232
0
                        padfList[i] =
233
0
                            CPLAtof(psGMLProperty->papszSubProperties[i]);
234
235
0
                    poOGRFeature->SetField(iField, nCount, padfList);
236
0
                    CPLFree(padfList);
237
0
                }
238
0
                break;
239
240
0
                case GMLPT_StringList:
241
0
                {
242
0
                    poOGRFeature->SetField(iField,
243
0
                                           psGMLProperty->papszSubProperties);
244
0
                }
245
0
                break;
246
247
0
                default:
248
0
                    poOGRFeature->SetField(
249
0
                        iField, psGMLProperty->papszSubProperties[0]);
250
0
                    break;
251
0
            }
252
0
        }
253
254
0
        for (int iGeom = 0; iGeom < poNASFeature->GetGeometryCount(); ++iGeom)
255
0
        {
256
0
            poOGRFeature->SetGeomFieldDirectly(iGeom, poGeom[iGeom]);
257
0
            poGeom[iGeom] = nullptr;
258
0
        }
259
0
        poGeom.clear();
260
261
        /* --------------------------------------------------------------------
262
         */
263
        /*      Test against the attribute query. */
264
        /* --------------------------------------------------------------------
265
         */
266
0
        if (m_poAttrQuery != nullptr && !m_poAttrQuery->Evaluate(poOGRFeature))
267
0
        {
268
0
            delete poOGRFeature;
269
0
            continue;
270
0
        }
271
272
        /* --------------------------------------------------------------------
273
         */
274
        /*      Wow, we got our desired feature. Return it. */
275
        /* --------------------------------------------------------------------
276
         */
277
0
        delete poNASFeature;
278
279
0
        return poOGRFeature;
280
0
    }
281
282
0
    return nullptr;
283
0
}
284
285
/************************************************************************/
286
/*                          GetFeatureCount()                           */
287
/************************************************************************/
288
289
GIntBig OGRNASLayer::GetFeatureCount(int bForce)
290
291
0
{
292
0
    if (poFClass == nullptr)
293
0
        return 0;
294
295
0
    if (m_poFilterGeom != nullptr || m_poAttrQuery != nullptr)
296
0
        return OGRLayer::GetFeatureCount(bForce);
297
298
0
    return poFClass->GetFeatureCount();
299
0
}
300
301
/************************************************************************/
302
/*                            IGetExtent()                              */
303
/************************************************************************/
304
305
OGRErr OGRNASLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
306
                               bool bForce)
307
308
0
{
309
0
    double dfXMin = 0.0;
310
0
    double dfXMax = 0.0;
311
0
    double dfYMin = 0.0;
312
0
    double dfYMax = 0.0;
313
314
0
    if (poFClass != nullptr &&
315
0
        poFClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax))
316
0
    {
317
0
        psExtent->MinX = dfXMin;
318
0
        psExtent->MaxX = dfXMax;
319
0
        psExtent->MinY = dfYMin;
320
0
        psExtent->MaxY = dfYMax;
321
322
0
        return OGRERR_NONE;
323
0
    }
324
325
0
    return OGRLayer::IGetExtent(iGeomField, psExtent, bForce);
326
0
}
327
328
/************************************************************************/
329
/*                           TestCapability()                           */
330
/************************************************************************/
331
332
int OGRNASLayer::TestCapability(const char *pszCap)
333
334
0
{
335
0
    if (EQUAL(pszCap, OLCFastGetExtent))
336
0
    {
337
0
        if (poFClass == nullptr)
338
0
            return FALSE;
339
340
0
        double dfXMin = 0.0;
341
0
        double dfXMax = 0.0;
342
0
        double dfYMin = 0.0;
343
0
        double dfYMax = 0.0;
344
345
0
        return poFClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax);
346
0
    }
347
348
0
    if (EQUAL(pszCap, OLCFastFeatureCount))
349
0
    {
350
0
        if (poFClass == nullptr || m_poFilterGeom != nullptr ||
351
0
            m_poAttrQuery != nullptr)
352
0
            return FALSE;
353
354
0
        return poFClass->GetFeatureCount() != -1;
355
0
    }
356
357
0
    if (EQUAL(pszCap, OLCStringsAsUTF8))
358
0
        return TRUE;
359
360
0
    return FALSE;
361
0
}