Coverage Report

Created: 2026-06-30 08:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/osm/ogrosmlayer.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  Implements OGROSMLayer class
5
 * Author:   Even Rouault, <even dot rouault at spatialys.com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2012-2014, Even Rouault <even dot rouault at spatialys.com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#include "cpl_port.h"
14
15
#include <cinttypes>
16
#include <cstddef>
17
#include <cstdio>
18
#include <cstdlib>
19
#include <cstring>
20
#include <time.h>
21
#include <map>
22
#include <memory>
23
#include <set>
24
#include <string>
25
#include <utility>
26
#include <vector>
27
28
#include "cpl_conv.h"
29
#include "cpl_error.h"
30
#include "cpl_progress.h"
31
#include "cpl_string.h"
32
#include "cpl_time.h"
33
#include "cpl_vsi.h"
34
#include "ogr_core.h"
35
#include "ogr_feature.h"
36
#include "ogr_geometry.h"
37
#include "ogr_p.h"
38
#include "ogr_spatialref.h"
39
#include "ogrsf_frmts.h"
40
#include "ogr_osm.h"
41
#include "osm_parser.h"
42
#include "sqlite3.h"
43
44
#undef SQLITE_TRANSIENT
45
0
#define SQLITE_TRANSIENT reinterpret_cast<sqlite3_destructor_type>(-1)
46
47
constexpr size_t SWITCH_THRESHOLD = 10000;
48
constexpr size_t MAX_THRESHOLD = 100000;
49
50
/************************************************************************/
51
/*                            OGROSMLayer()                             */
52
/************************************************************************/
53
54
OGROSMLayer::OGROSMLayer(OGROSMDataSource *poDSIn, int nIdxLayerIn,
55
                         const char *pszName)
56
4.38k
    : m_poDS(poDSIn), m_nIdxLayer(nIdxLayerIn),
57
4.38k
      m_poFeatureDefn(new OGRFeatureDefn(pszName)),
58
4.38k
      m_poSRS(new OGRSpatialReference())
59
4.38k
{
60
4.38k
    SetDescription(m_poFeatureDefn->GetName());
61
4.38k
    m_poFeatureDefn->Reference();
62
63
4.38k
    m_poSRS->SetWellKnownGeogCS("WGS84");
64
4.38k
    m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
65
66
4.38k
    if (m_poFeatureDefn->GetGeomFieldCount() != 0)
67
4.38k
        m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(m_poSRS);
68
4.38k
}
69
70
/************************************************************************/
71
/*                            ~OGROSMLayer()                            */
72
/************************************************************************/
73
74
OGROSMLayer::~OGROSMLayer()
75
4.38k
{
76
4.38k
    m_poFeatureDefn->Release();
77
78
4.38k
    if (m_poSRS)
79
4.38k
        m_poSRS->Release();
80
81
49.9k
    for (int i = 0; i < static_cast<int>(m_apszNames.size()); i++)
82
45.6k
        CPLFree(m_apszNames[i]);
83
84
9.64k
    for (int i = 0; i < static_cast<int>(apszInsignificantKeys.size()); i++)
85
5.26k
        CPLFree(apszInsignificantKeys[i]);
86
87
50.8k
    for (int i = 0; i < static_cast<int>(apszIgnoreKeys.size()); i++)
88
46.4k
        CPLFree(apszIgnoreKeys[i]);
89
90
5.26k
    for (int i = 0; i < static_cast<int>(m_oComputedAttributes.size()); i++)
91
877
    {
92
877
        sqlite3_finalize(m_oComputedAttributes[i].hStmt);
93
877
    }
94
4.38k
}
95
96
/************************************************************************/
97
/*                            ResetReading()                            */
98
/************************************************************************/
99
100
void OGROSMLayer::ResetReading()
101
0
{
102
0
    if (!m_bResetReadingAllowed || m_poDS->IsInterleavedReading())
103
0
        return;
104
105
0
    m_poDS->MyResetReading();
106
0
}
107
108
/************************************************************************/
109
/*                         ForceResetReading()                          */
110
/************************************************************************/
111
112
void OGROSMLayer::ForceResetReading()
113
0
{
114
0
    m_apoFeatures.clear();
115
0
    m_nFeatureArrayIndex = 0;
116
0
    m_bResetReadingAllowed = false;
117
0
}
118
119
/************************************************************************/
120
/*                         SetAttributeFilter()                         */
121
/************************************************************************/
122
123
OGRErr OGROSMLayer::SetAttributeFilter(const char *pszAttrQuery)
124
0
{
125
0
    if (pszAttrQuery == nullptr && m_pszAttrQueryString == nullptr)
126
0
        return OGRERR_NONE;
127
0
    if (pszAttrQuery != nullptr && m_pszAttrQueryString != nullptr &&
128
0
        strcmp(pszAttrQuery, m_pszAttrQueryString) == 0)
129
0
        return OGRERR_NONE;
130
131
0
    OGRErr eErr = OGRLayer::SetAttributeFilter(pszAttrQuery);
132
0
    if (eErr != OGRERR_NONE)
133
0
        return eErr;
134
135
0
    if (m_nFeatureArrayIndex == 0)
136
0
    {
137
0
        if (!m_poDS->IsInterleavedReading())
138
0
        {
139
0
            m_poDS->MyResetReading();
140
0
        }
141
0
    }
142
0
    else
143
0
    {
144
0
        CPLError(CE_Warning, CPLE_AppDefined,
145
0
                 "The new attribute filter will "
146
0
                 "not be taken into account immediately. It is advised to "
147
0
                 "set attribute filters for all needed layers, before "
148
0
                 "reading *any* layer");
149
0
    }
150
151
0
    return OGRERR_NONE;
152
0
}
153
154
/************************************************************************/
155
/*                          GetFeatureCount()                           */
156
/************************************************************************/
157
158
GIntBig OGROSMLayer::GetFeatureCount(int bForce)
159
0
{
160
0
    if (m_poDS->IsFeatureCountEnabled())
161
0
        return OGRLayer::GetFeatureCount(bForce);
162
163
0
    return -1;
164
0
}
165
166
/************************************************************************/
167
/*                           GetNextFeature()                           */
168
/************************************************************************/
169
170
OGRFeature *OGROSMLayer::GetNextFeature()
171
3.17k
{
172
3.17k
    OGROSMLayer *poNewCurLayer = nullptr;
173
3.17k
    OGRFeature *poFeature = MyGetNextFeature(&poNewCurLayer, nullptr, nullptr);
174
3.17k
    m_poDS->SetCurrentLayer(poNewCurLayer);
175
3.17k
    return poFeature;
176
3.17k
}
177
178
OGRFeature *OGROSMLayer::MyGetNextFeature(OGROSMLayer **ppoNewCurLayer,
179
                                          GDALProgressFunc pfnProgress,
180
                                          void *pProgressData)
181
3.17k
{
182
3.17k
    *ppoNewCurLayer = m_poDS->GetCurrentLayer();
183
3.17k
    m_bResetReadingAllowed = true;
184
185
3.17k
    if (m_apoFeatures.empty())
186
2.87k
    {
187
2.87k
        if (m_poDS->IsInterleavedReading())
188
0
        {
189
0
            if (*ppoNewCurLayer == nullptr)
190
0
            {
191
0
                *ppoNewCurLayer = this;
192
0
            }
193
0
            else if (*ppoNewCurLayer != this)
194
0
            {
195
0
                return nullptr;
196
0
            }
197
198
            // If too many features have been accumulated in another layer, we
199
            // force a switch to that layer, so that it gets emptied.
200
0
            for (int i = 0; i < m_poDS->GetLayerCount(); i++)
201
0
            {
202
0
                if (m_poDS->m_apoLayers[i].get() != this &&
203
0
                    m_poDS->m_apoLayers[i]->m_apoFeatures.size() >
204
0
                        SWITCH_THRESHOLD)
205
0
                {
206
0
                    *ppoNewCurLayer = m_poDS->m_apoLayers[i].get();
207
0
                    CPLDebug("OSM",
208
0
                             "Switching to '%s' as they are too many "
209
0
                             "features in '%s'",
210
0
                             m_poDS->m_apoLayers[i]->GetName(), GetName());
211
0
                    return nullptr;
212
0
                }
213
0
            }
214
215
            // Read some more data and accumulate features.
216
0
            m_poDS->ParseNextChunk(m_nIdxLayer, pfnProgress, pProgressData);
217
218
0
            if (m_apoFeatures.empty())
219
0
            {
220
                // If there are really no more features to read in the
221
                // current layer, force a switch to another non-empty layer.
222
223
0
                for (int i = 0; i < m_poDS->GetLayerCount(); i++)
224
0
                {
225
0
                    if (m_poDS->m_apoLayers[i].get() != this &&
226
0
                        !m_poDS->m_apoLayers[i]->m_apoFeatures.empty())
227
0
                    {
228
0
                        *ppoNewCurLayer = m_poDS->m_apoLayers[i].get();
229
0
                        CPLDebug("OSM",
230
0
                                 "Switching to '%s' as they are "
231
0
                                 "no more feature in '%s'",
232
0
                                 m_poDS->m_apoLayers[i]->GetName(), GetName());
233
0
                        return nullptr;
234
0
                    }
235
0
                }
236
237
                /* Game over : no more data to read from the stream */
238
0
                *ppoNewCurLayer = nullptr;
239
0
                return nullptr;
240
0
            }
241
0
        }
242
2.87k
        else
243
2.87k
        {
244
2.87k
            while (true)
245
2.87k
            {
246
2.87k
                int bRet =
247
2.87k
                    m_poDS->ParseNextChunk(m_nIdxLayer, nullptr, nullptr);
248
                // cppcheck-suppress knownConditionTrueFalse
249
2.87k
                if (!m_apoFeatures.empty())
250
57
                    break;
251
2.81k
                if (bRet == FALSE)
252
2.81k
                    return nullptr;
253
2.81k
            }
254
2.87k
        }
255
2.87k
    }
256
257
358
    auto poFeature = std::move(m_apoFeatures[m_nFeatureArrayIndex]);
258
358
    m_nFeatureArrayIndex++;
259
260
358
    if (m_nFeatureArrayIndex == m_apoFeatures.size())
261
95
    {
262
95
        m_nFeatureArrayIndex = 0;
263
95
        m_apoFeatures.clear();
264
95
    }
265
266
358
    return poFeature.release();
267
3.17k
}
268
269
/************************************************************************/
270
/*                           TestCapability()                           */
271
/************************************************************************/
272
273
int OGROSMLayer::TestCapability(const char *pszCap) const
274
0
{
275
0
    if (EQUAL(pszCap, OLCFastGetExtent))
276
0
    {
277
0
        OGREnvelope sExtent;
278
0
        if (m_poDS->GetNativeExtent(&sExtent) == OGRERR_NONE)
279
0
            return TRUE;
280
0
    }
281
282
0
    return FALSE;
283
0
}
284
285
/************************************************************************/
286
/*                             AddToArray()                             */
287
/************************************************************************/
288
289
bool OGROSMLayer::AddToArray(std::unique_ptr<OGRFeature> poFeature,
290
                             bool bCheckFeatureThreshold)
291
358
{
292
358
    if (bCheckFeatureThreshold && m_apoFeatures.size() > MAX_THRESHOLD)
293
0
    {
294
0
        if (!m_bHasWarnedTooManyFeatures)
295
0
        {
296
0
            CPLError(
297
0
                CE_Failure, CPLE_AppDefined,
298
0
                "Too many features have accumulated in %s layer. "
299
0
                "Use the OGR_INTERLEAVED_READING=YES configuration option, "
300
0
                "or the INTERLEAVED_READING=YES open option, or the "
301
0
                "GDALDataset::GetNextFeature() / GDALDatasetGetNextFeature() "
302
0
                "API.",
303
0
                GetName());
304
0
        }
305
0
        m_bHasWarnedTooManyFeatures = true;
306
0
        return false;
307
0
    }
308
309
358
    try
310
358
    {
311
358
        m_apoFeatures.push_back(std::move(poFeature));
312
358
    }
313
358
    catch (const std::exception &)
314
358
    {
315
0
        CPLError(CE_Failure, CPLE_OutOfMemory,
316
0
                 "For layer %s, cannot resize feature array to %" PRIu64
317
0
                 " features",
318
0
                 GetName(), static_cast<uint64_t>(m_apoFeatures.size()) + 1);
319
0
        return false;
320
0
    }
321
322
358
    return true;
323
358
}
324
325
/************************************************************************/
326
/*                      EvaluateAttributeFilter()                       */
327
/************************************************************************/
328
329
int OGROSMLayer::EvaluateAttributeFilter(OGRFeature *poFeature)
330
0
{
331
0
    return (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature));
332
0
}
333
334
/************************************************************************/
335
/*                             AddFeature()                             */
336
/************************************************************************/
337
338
bool OGROSMLayer::AddFeature(std::unique_ptr<OGRFeature> poFeature,
339
                             bool bAttrFilterAlreadyEvaluated,
340
                             bool *pbFilteredOut, bool bCheckFeatureThreshold)
341
358
{
342
358
    if (!m_bUserInterested)
343
0
    {
344
0
        if (pbFilteredOut)
345
0
            *pbFilteredOut = true;
346
0
        return true;
347
0
    }
348
349
358
    OGRGeometry *poGeom = poFeature->GetGeometryRef();
350
358
    if (poGeom)
351
358
        poGeom->assignSpatialReference(m_poSRS);
352
353
358
    if ((m_poFilterGeom == nullptr || FilterGeometry(poGeom)) &&
354
358
        (m_poAttrQuery == nullptr || bAttrFilterAlreadyEvaluated ||
355
0
         m_poAttrQuery->Evaluate(poFeature.get())))
356
358
    {
357
358
        if (!AddToArray(std::move(poFeature), bCheckFeatureThreshold))
358
0
        {
359
0
            return false;
360
0
        }
361
358
    }
362
0
    else
363
0
    {
364
0
        if (pbFilteredOut)
365
0
            *pbFilteredOut = true;
366
0
        return true;
367
0
    }
368
369
358
    if (pbFilteredOut)
370
358
        *pbFilteredOut = false;
371
358
    return true;
372
358
}
373
374
/************************************************************************/
375
/*                             IGetExtent()                             */
376
/************************************************************************/
377
378
OGRErr OGROSMLayer::IGetExtent(int /* iGeomField */, OGREnvelope *psExtent,
379
                               bool /* bForce */)
380
0
{
381
0
    if (m_poDS->GetNativeExtent(psExtent) == OGRERR_NONE)
382
0
        return OGRERR_NONE;
383
384
0
    return OGRERR_FAILURE;
385
0
}
386
387
/************************************************************************/
388
/*                       GetLaunderedFieldName()                        */
389
/************************************************************************/
390
391
const char *OGROSMLayer::GetLaunderedFieldName(const char *pszName)
392
45.6k
{
393
45.6k
    if (m_poDS->DoesAttributeNameLaundering() &&
394
45.6k
        strchr(pszName, ':') != nullptr)
395
0
    {
396
0
        size_t i = 0;
397
0
        for (; i < sizeof(szLaunderedFieldName) - 1 && pszName[i] != '\0'; i++)
398
0
        {
399
0
            if (pszName[i] == ':')
400
0
                szLaunderedFieldName[i] = '_';
401
0
            else
402
0
                szLaunderedFieldName[i] = pszName[i];
403
0
        }
404
0
        szLaunderedFieldName[i] = '\0';
405
0
        return szLaunderedFieldName;
406
0
    }
407
408
45.6k
    return pszName;
409
45.6k
}
410
411
/************************************************************************/
412
/*                              AddField()                              */
413
/************************************************************************/
414
415
void OGROSMLayer::AddField(const char *pszName, OGRFieldType eFieldType,
416
                           OGRFieldSubType eSubType)
417
45.6k
{
418
45.6k
    const char *pszLaunderedName = GetLaunderedFieldName(pszName);
419
45.6k
    OGRFieldDefn oField(pszLaunderedName, eFieldType);
420
45.6k
    oField.SetSubType(eSubType);
421
45.6k
    m_poFeatureDefn->AddFieldDefn(&oField);
422
423
45.6k
    int nIndex = m_poFeatureDefn->GetFieldCount() - 1;
424
45.6k
    char *pszDupName = CPLStrdup(pszName);
425
45.6k
    m_apszNames.push_back(pszDupName);
426
45.6k
    m_oMapFieldNameToIndex[pszDupName] = nIndex;
427
428
45.6k
    if (strcmp(pszName, "osm_id") == 0)
429
4.38k
        m_nIndexOSMId = nIndex;
430
431
41.2k
    else if (strcmp(pszName, "osm_way_id") == 0)
432
877
        m_nIndexOSMWayId = nIndex;
433
434
40.3k
    else if (strcmp(pszName, "other_tags") == 0)
435
4.38k
        m_nIndexOtherTags = nIndex;
436
437
35.9k
    else if (strcmp(pszName, "all_tags") == 0)
438
0
        m_nIndexAllTags = nIndex;
439
45.6k
}
440
441
/************************************************************************/
442
/*                           GetFieldIndex()                            */
443
/************************************************************************/
444
445
int OGROSMLayer::GetFieldIndex(const char *pszName)
446
31.9k
{
447
31.9k
    const auto oIter = m_oMapFieldNameToIndex.find(pszName);
448
31.9k
    if (oIter != m_oMapFieldNameToIndex.end())
449
468
        return oIter->second;
450
451
31.5k
    return -1;
452
31.9k
}
453
454
/************************************************************************/
455
/*                        AddInOtherOrAllTags()                         */
456
/************************************************************************/
457
458
int OGROSMLayer::AddInOtherOrAllTags(const char *pszK)
459
31.5k
{
460
31.5k
    bool bAddToOtherTags = false;
461
462
31.5k
    if (aoSetIgnoreKeys.find(pszK) == aoSetIgnoreKeys.end())
463
31.4k
    {
464
31.4k
        char *pszColon = strchr(const_cast<char *>(pszK), ':');
465
31.4k
        if (pszColon)
466
0
        {
467
0
            char chBackup = pszColon[1];
468
0
            pszColon[1] = '\0'; /* Evil but OK */
469
0
            bAddToOtherTags =
470
0
                (aoSetIgnoreKeys.find(pszK) == aoSetIgnoreKeys.end());
471
            // cppcheck-suppress redundantAssignment
472
0
            pszColon[1] = chBackup;
473
0
        }
474
31.4k
        else
475
31.4k
            bAddToOtherTags = true;
476
31.4k
    }
477
478
31.5k
    return bAddToOtherTags;
479
31.5k
}
480
481
/************************************************************************/
482
/*                      OGROSMEscapeStringHSTORE()                      */
483
/************************************************************************/
484
485
static void OGROSMEscapeStringHSTORE(const char *pszV, std::string &sOut)
486
62.8k
{
487
62.8k
    sOut += '"';
488
489
559k
    for (int k = 0; pszV[k] != '\0'; k++)
490
496k
    {
491
496k
        if (pszV[k] == '"' || pszV[k] == '\\')
492
1
            sOut += '\\';
493
496k
        sOut += pszV[k];
494
496k
    }
495
496
62.8k
    sOut += '"';
497
62.8k
}
498
499
/************************************************************************/
500
/*                       OGROSMEscapeStringJSON()                       */
501
/************************************************************************/
502
503
static void OGROSMEscapeStringJSON(const char *pszV, std::string &sOut)
504
0
{
505
0
    sOut += '"';
506
507
0
    for (int k = 0; pszV[k] != '\0'; k++)
508
0
    {
509
0
        const char ch = pszV[k];
510
0
        switch (ch)
511
0
        {
512
0
            case '"':
513
0
                sOut += "\\\"";
514
0
                break;
515
0
            case '\\':
516
0
                sOut += "\\\\";
517
0
                break;
518
0
            case '\n':
519
0
                sOut += "\\n";
520
0
                break;
521
0
            case '\r':
522
0
                sOut += "\\r";
523
0
                break;
524
0
            case '\t':
525
0
                sOut += "\\t";
526
0
                break;
527
0
            default:
528
0
                if (static_cast<unsigned char>(ch) < ' ')
529
0
                    sOut += CPLSPrintf("\\u%04X", ch);
530
0
                else
531
0
                    sOut += ch;
532
0
                break;
533
0
        }
534
0
    }
535
536
0
    sOut += '"';
537
0
}
538
539
/************************************************************************/
540
/*                           GetValueOfTag()                            */
541
/************************************************************************/
542
543
static const char *GetValueOfTag(const char *pszKeyToSearch, unsigned int nTags,
544
                                 const OSMTag *pasTags)
545
936
{
546
96.1k
    for (unsigned int k = 0; k < nTags; k++)
547
95.1k
    {
548
95.1k
        const char *pszK = pasTags[k].pszK;
549
95.1k
        if (strcmp(pszK, pszKeyToSearch) == 0)
550
2
        {
551
2
            return pasTags[k].pszV;
552
2
        }
553
95.1k
    }
554
934
    return nullptr;
555
936
}
556
557
/************************************************************************/
558
/*                         SetFieldsFromTags()                          */
559
/************************************************************************/
560
561
void OGROSMLayer::SetFieldsFromTags(OGRFeature *poFeature, GIntBig nID,
562
                                    bool bIsWayID, unsigned int nTags,
563
                                    const OSMTag *pasTags,
564
                                    const OSMInfo *psInfo)
565
470
{
566
470
    if (!bIsWayID)
567
407
    {
568
407
        poFeature->SetFID(nID);
569
570
407
        if (m_bHasOSMId)
571
407
        {
572
407
            char szID[32];
573
407
            snprintf(szID, sizeof(szID), CPL_FRMT_GIB, nID);
574
407
            poFeature->SetField(m_nIndexOSMId, szID);
575
407
        }
576
407
    }
577
63
    else
578
63
    {
579
63
        poFeature->SetFID(nID);
580
581
63
        if (m_nIndexOSMWayId >= 0)
582
63
        {
583
63
            char szID[32];
584
63
            snprintf(szID, sizeof(szID), CPL_FRMT_GIB, nID);
585
63
            poFeature->SetField(m_nIndexOSMWayId, szID);
586
63
        }
587
63
    }
588
589
470
    if (m_bHasVersion)
590
0
    {
591
0
        poFeature->SetField("osm_version", psInfo->nVersion);
592
0
    }
593
470
    if (m_bHasTimestamp)
594
0
    {
595
0
        if (psInfo->bTimeStampIsStr)
596
0
        {
597
0
            OGRField sField;
598
0
            if (OGRParseXMLDateTime(psInfo->ts.pszTimeStamp, &sField))
599
0
            {
600
0
                poFeature->SetField("osm_timestamp", &sField);
601
0
            }
602
0
        }
603
0
        else
604
0
        {
605
0
            struct tm brokendown;
606
0
            CPLUnixTimeToYMDHMS(psInfo->ts.nTimeStamp, &brokendown);
607
0
            poFeature->SetField("osm_timestamp", brokendown.tm_year + 1900,
608
0
                                brokendown.tm_mon + 1, brokendown.tm_mday,
609
0
                                brokendown.tm_hour, brokendown.tm_min,
610
0
                                static_cast<float>(brokendown.tm_sec), 0);
611
0
        }
612
0
    }
613
470
    if (m_bHasUID)
614
0
    {
615
0
        poFeature->SetField("osm_uid", psInfo->nUID);
616
0
    }
617
470
    if (m_bHasUser)
618
0
    {
619
0
        poFeature->SetField("osm_user", psInfo->pszUserSID);
620
0
    }
621
470
    if (m_bHasChangeset)
622
0
    {
623
0
        poFeature->SetField("osm_changeset", psInfo->nChangeset);
624
0
    }
625
626
470
    m_osAllTagsBuffer.clear();
627
32.4k
    for (unsigned int j = 0; j < nTags; j++)
628
31.9k
    {
629
31.9k
        const char *pszK = pasTags[j].pszK;
630
31.9k
        const char *pszV = pasTags[j].pszV;
631
31.9k
        int nIndex = GetFieldIndex(pszK);
632
31.9k
        if (nIndex >= 0 && nIndex != m_nIndexOSMId)
633
468
        {
634
468
            poFeature->SetField(nIndex, pszV);
635
468
            if (m_nIndexAllTags < 0)
636
468
                continue;
637
468
        }
638
31.5k
        if (m_nIndexAllTags >= 0 || m_nIndexOtherTags >= 0)
639
31.5k
        {
640
31.5k
            if (AddInOtherOrAllTags(pszK))
641
31.4k
            {
642
31.4k
                if (m_poDS->m_bTagsAsHSTORE)
643
31.4k
                {
644
31.4k
                    if (!m_osAllTagsBuffer.empty())
645
31.2k
                        m_osAllTagsBuffer += ',';
646
647
31.4k
                    OGROSMEscapeStringHSTORE(pszK, m_osAllTagsBuffer);
648
649
31.4k
                    m_osAllTagsBuffer += '=';
650
31.4k
                    m_osAllTagsBuffer += '>';
651
652
31.4k
                    OGROSMEscapeStringHSTORE(pszV, m_osAllTagsBuffer);
653
31.4k
                }
654
0
                else
655
0
                {
656
0
                    if (!m_osAllTagsBuffer.empty())
657
0
                        m_osAllTagsBuffer += ',';
658
0
                    else
659
0
                        m_osAllTagsBuffer = '{';
660
0
                    OGROSMEscapeStringJSON(pszK, m_osAllTagsBuffer);
661
0
                    m_osAllTagsBuffer += ':';
662
0
                    OGROSMEscapeStringJSON(pszV, m_osAllTagsBuffer);
663
0
                }
664
31.4k
            }
665
666
#ifdef notdef
667
            if (aoSetWarnKeys.find(pszK) == aoSetWarnKeys.end())
668
            {
669
                aoSetWarnKeys.insert(pszK);
670
                CPLDebug("OSM_KEY", "Ignored key : %s", pszK);
671
            }
672
#endif
673
31.5k
        }
674
31.5k
    }
675
676
470
    if (!m_osAllTagsBuffer.empty())
677
170
    {
678
170
        if (!m_poDS->m_bTagsAsHSTORE)
679
0
        {
680
0
            m_osAllTagsBuffer += '}';
681
0
        }
682
170
        if (m_nIndexAllTags >= 0)
683
0
            poFeature->SetField(m_nIndexAllTags, m_osAllTagsBuffer.c_str());
684
170
        else
685
170
            poFeature->SetField(m_nIndexOtherTags, m_osAllTagsBuffer.c_str());
686
170
    }
687
688
782
    for (size_t i = 0; i < m_oComputedAttributes.size(); i++)
689
312
    {
690
312
        const OGROSMComputedAttribute &oAttr = m_oComputedAttributes[i];
691
312
        if (oAttr.bHardcodedZOrder)
692
312
        {
693
312
            const int nHighwayIdx = oAttr.anIndexToBind[0];
694
312
            const int nBridgeIdx = oAttr.anIndexToBind[1];
695
312
            const int nTunnelIdx = oAttr.anIndexToBind[2];
696
312
            const int nRailwayIdx = oAttr.anIndexToBind[3];
697
312
            const int nLayerIdx = oAttr.anIndexToBind[4];
698
699
312
            int nZOrder = 0;
700
            /*
701
                "SELECT (CASE [highway] WHEN 'minor' THEN 3 WHEN 'road' THEN 3 "
702
                "WHEN 'unclassified' THEN 3 WHEN 'residential' THEN 3 WHEN "
703
                "'tertiary_link' THEN 4 WHEN 'tertiary' THEN 4 WHEN
704
               'secondary_link' " "THEN 6 WHEN 'secondary' THEN 6 WHEN
705
               'primary_link' THEN 7 WHEN "
706
                "'primary' THEN 7 WHEN 'trunk_link' THEN 8 WHEN 'trunk' THEN 8 "
707
                "WHEN 'motorway_link' THEN 9 WHEN 'motorway' THEN 9 ELSE 0 END)
708
               + "
709
                "(CASE WHEN [bridge] IN ('yes', 'true', '1') THEN 10 ELSE 0 END)
710
               + "
711
                "(CASE WHEN [tunnel] IN ('yes', 'true', '1') THEN -10 ELSE 0
712
               END) + "
713
                "(CASE WHEN [railway] IS NOT NULL THEN 5 ELSE 0 END) + "
714
                "(CASE WHEN [layer] IS NOT NULL THEN 10 * CAST([layer] AS
715
               INTEGER) " */
716
717
312
            const char *pszHighway = nullptr;
718
312
            if (nHighwayIdx >= 0)
719
312
            {
720
312
                if (poFeature->IsFieldSetAndNotNull(nHighwayIdx))
721
209
                {
722
209
                    pszHighway = poFeature->GetFieldAsString(nHighwayIdx);
723
209
                }
724
312
            }
725
0
            else
726
0
                pszHighway = GetValueOfTag("highway", nTags, pasTags);
727
312
            if (pszHighway)
728
209
            {
729
209
                if (strcmp(pszHighway, "minor") == 0 ||
730
209
                    strcmp(pszHighway, "road") == 0 ||
731
205
                    strcmp(pszHighway, "unclassified") == 0 ||
732
179
                    strcmp(pszHighway, "residential") == 0)
733
114
                {
734
114
                    nZOrder += 3;
735
114
                }
736
95
                else if (strcmp(pszHighway, "tertiary_link") == 0 ||
737
95
                         strcmp(pszHighway, "tertiary") == 0)
738
9
                {
739
9
                    nZOrder += 4;
740
9
                }
741
86
                else if (strcmp(pszHighway, "secondary_link") == 0 ||
742
86
                         strcmp(pszHighway, "secondary") == 0)
743
1
                {
744
1
                    nZOrder += 6;
745
1
                }
746
85
                else if (strcmp(pszHighway, "primary_link") == 0 ||
747
85
                         strcmp(pszHighway, "primary") == 0)
748
2
                {
749
2
                    nZOrder += 7;
750
2
                }
751
83
                else if (strcmp(pszHighway, "trunk_link") == 0 ||
752
83
                         strcmp(pszHighway, "trunk") == 0)
753
0
                {
754
0
                    nZOrder += 8;
755
0
                }
756
83
                else if (strcmp(pszHighway, "motorway_link") == 0 ||
757
83
                         strcmp(pszHighway, "motorway") == 0)
758
38
                {
759
38
                    nZOrder += 9;
760
38
                }
761
209
            }
762
763
312
            const char *pszBridge = nullptr;
764
312
            if (nBridgeIdx >= 0)
765
0
            {
766
0
                if (poFeature->IsFieldSetAndNotNull(nBridgeIdx))
767
0
                {
768
0
                    pszBridge = poFeature->GetFieldAsString(nBridgeIdx);
769
0
                }
770
0
            }
771
312
            else
772
312
                pszBridge = GetValueOfTag("bridge", nTags, pasTags);
773
312
            if (pszBridge)
774
0
            {
775
0
                if (strcmp(pszBridge, "yes") == 0 ||
776
0
                    strcmp(pszBridge, "true") == 0 ||
777
0
                    strcmp(pszBridge, "1") == 0)
778
0
                {
779
0
                    nZOrder += 10;
780
0
                }
781
0
            }
782
783
312
            const char *pszTunnel = nullptr;
784
312
            if (nTunnelIdx >= 0)
785
0
            {
786
0
                if (poFeature->IsFieldSetAndNotNull(nTunnelIdx))
787
0
                {
788
0
                    pszTunnel = poFeature->GetFieldAsString(nTunnelIdx);
789
0
                }
790
0
            }
791
312
            else
792
312
                pszTunnel = GetValueOfTag("tunnel", nTags, pasTags);
793
312
            if (pszTunnel)
794
0
            {
795
0
                if (strcmp(pszTunnel, "yes") == 0 ||
796
0
                    strcmp(pszTunnel, "true") == 0 ||
797
0
                    strcmp(pszTunnel, "1") == 0)
798
0
                {
799
0
                    nZOrder -= 10;
800
0
                }
801
0
            }
802
803
312
            const char *pszRailway = nullptr;
804
312
            if (nRailwayIdx >= 0)
805
312
            {
806
312
                if (poFeature->IsFieldSetAndNotNull(nRailwayIdx))
807
2
                {
808
2
                    pszRailway = poFeature->GetFieldAsString(nRailwayIdx);
809
2
                }
810
312
            }
811
0
            else
812
0
                pszRailway = GetValueOfTag("railway", nTags, pasTags);
813
312
            if (pszRailway)
814
2
            {
815
2
                nZOrder += 5;
816
2
            }
817
818
312
            const char *pszLayer = nullptr;
819
312
            if (nLayerIdx >= 0)
820
0
            {
821
0
                if (poFeature->IsFieldSetAndNotNull(nLayerIdx))
822
0
                {
823
0
                    pszLayer = poFeature->GetFieldAsString(nLayerIdx);
824
0
                }
825
0
            }
826
312
            else
827
312
                pszLayer = GetValueOfTag("layer", nTags, pasTags);
828
312
            if (pszLayer)
829
2
            {
830
2
                nZOrder += 10 * atoi(pszLayer);
831
2
            }
832
833
312
            poFeature->SetField(oAttr.nIndex, nZOrder);
834
835
312
            continue;
836
312
        }
837
838
0
        for (int j = 0; j < static_cast<int>(oAttr.anIndexToBind.size()); j++)
839
0
        {
840
0
            if (oAttr.anIndexToBind[j] >= 0)
841
0
            {
842
0
                if (!poFeature->IsFieldSetAndNotNull(oAttr.anIndexToBind[j]))
843
0
                {
844
0
                    sqlite3_bind_null(oAttr.hStmt, j + 1);
845
0
                }
846
0
                else
847
0
                {
848
0
                    OGRFieldType eType =
849
0
                        m_poFeatureDefn->GetFieldDefn(oAttr.anIndexToBind[j])
850
0
                            ->GetType();
851
0
                    if (eType == OFTInteger)
852
0
                        sqlite3_bind_int(oAttr.hStmt, j + 1,
853
0
                                         poFeature->GetFieldAsInteger(
854
0
                                             oAttr.anIndexToBind[j]));
855
0
                    else if (eType == OFTInteger64)
856
0
                        sqlite3_bind_int64(oAttr.hStmt, j + 1,
857
0
                                           poFeature->GetFieldAsInteger64(
858
0
                                               oAttr.anIndexToBind[j]));
859
0
                    else if (eType == OFTReal)
860
0
                        sqlite3_bind_double(oAttr.hStmt, j + 1,
861
0
                                            poFeature->GetFieldAsDouble(
862
0
                                                oAttr.anIndexToBind[j]));
863
0
                    else
864
0
                        sqlite3_bind_text(
865
0
                            oAttr.hStmt, j + 1,
866
0
                            poFeature->GetFieldAsString(oAttr.anIndexToBind[j]),
867
0
                            -1, SQLITE_TRANSIENT);
868
0
                }
869
0
            }
870
0
            else
871
0
            {
872
0
                bool bTagFound = false;
873
0
                for (unsigned int k = 0; k < nTags; k++)
874
0
                {
875
0
                    const char *pszK = pasTags[k].pszK;
876
0
                    const char *pszV = pasTags[k].pszV;
877
0
                    if (strcmp(pszK, oAttr.aosAttrToBind[j]) == 0)
878
0
                    {
879
0
                        sqlite3_bind_text(oAttr.hStmt, j + 1, pszV, -1,
880
0
                                          SQLITE_TRANSIENT);
881
0
                        bTagFound = true;
882
0
                        break;
883
0
                    }
884
0
                }
885
0
                if (!bTagFound)
886
0
                    sqlite3_bind_null(oAttr.hStmt, j + 1);
887
0
            }
888
0
        }
889
890
0
        if (sqlite3_step(oAttr.hStmt) == SQLITE_ROW &&
891
0
            sqlite3_column_count(oAttr.hStmt) == 1)
892
0
        {
893
0
            switch (sqlite3_column_type(oAttr.hStmt, 0))
894
0
            {
895
0
                case SQLITE_INTEGER:
896
0
                    poFeature->SetField(
897
0
                        oAttr.nIndex, static_cast<GIntBig>(sqlite3_column_int64(
898
0
                                          oAttr.hStmt, 0)));
899
0
                    break;
900
0
                case SQLITE_FLOAT:
901
0
                    poFeature->SetField(oAttr.nIndex,
902
0
                                        sqlite3_column_double(oAttr.hStmt, 0));
903
0
                    break;
904
0
                case SQLITE_TEXT:
905
0
                    poFeature->SetField(
906
0
                        oAttr.nIndex, reinterpret_cast<const char *>(
907
0
                                          sqlite3_column_text(oAttr.hStmt, 0)));
908
0
                    break;
909
0
                default:
910
0
                    break;
911
0
            }
912
0
        }
913
914
0
        sqlite3_reset(oAttr.hStmt);
915
0
    }
916
470
}
917
918
/************************************************************************/
919
/*                      GetSpatialFilterEnvelope()                      */
920
/************************************************************************/
921
922
const OGREnvelope *OGROSMLayer::GetSpatialFilterEnvelope()
923
323
{
924
323
    if (m_poFilterGeom != nullptr)
925
0
        return &m_sFilterEnvelope;
926
323
    else
927
323
        return nullptr;
928
323
}
929
930
/************************************************************************/
931
/*                        AddInsignificantKey()                         */
932
/************************************************************************/
933
934
void OGROSMLayer::AddInsignificantKey(const char *pszK)
935
5.26k
{
936
5.26k
    char *pszKDup = CPLStrdup(pszK);
937
5.26k
    apszInsignificantKeys.push_back(pszKDup);
938
5.26k
    aoSetInsignificantKeys[pszKDup] = 1;
939
5.26k
}
940
941
/************************************************************************/
942
/*                            AddIgnoreKey()                            */
943
/************************************************************************/
944
945
void OGROSMLayer::AddIgnoreKey(const char *pszK)
946
46.4k
{
947
46.4k
    char *pszKDup = CPLStrdup(pszK);
948
46.4k
    apszIgnoreKeys.push_back(pszKDup);
949
46.4k
    aoSetIgnoreKeys[pszKDup] = 1;
950
46.4k
}
951
952
/************************************************************************/
953
/*                             AddWarnKey()                             */
954
/************************************************************************/
955
956
void OGROSMLayer::AddWarnKey(const char *pszK)
957
46.4k
{
958
46.4k
    aoSetWarnKeys.insert(pszK);
959
46.4k
}
960
961
/************************************************************************/
962
/*                             AddWarnKey()                             */
963
/************************************************************************/
964
965
void OGROSMLayer::AddComputedAttribute(const char *pszName, OGRFieldType eType,
966
                                       const char *pszSQL)
967
877
{
968
877
    if (m_poDS->m_hDBForComputedAttributes == nullptr)
969
877
    {
970
877
        const int rc = sqlite3_open_v2(
971
877
            ":memory:", &(m_poDS->m_hDBForComputedAttributes),
972
877
            SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX,
973
877
            nullptr);
974
877
        if (rc != SQLITE_OK)
975
0
        {
976
0
            CPLError(CE_Failure, CPLE_AppDefined,
977
0
                     "Cannot open temporary sqlite DB");
978
0
            return;
979
0
        }
980
877
    }
981
982
877
    if (m_poFeatureDefn->GetFieldIndex(pszName) >= 0)
983
0
    {
984
0
        CPLError(CE_Failure, CPLE_AppDefined,
985
0
                 "A field with same name %s already exists", pszName);
986
0
        return;
987
0
    }
988
989
877
    CPLString osSQL(pszSQL);
990
877
    const bool bHardcodedZOrder =
991
877
        (eType == OFTInteger) &&
992
877
        strcmp(
993
877
            pszSQL,
994
877
            "SELECT (CASE [highway] WHEN 'minor' THEN 3 WHEN 'road' THEN 3 "
995
877
            "WHEN 'unclassified' THEN 3 WHEN 'residential' THEN 3 WHEN "
996
877
            "'tertiary_link' THEN 4 WHEN 'tertiary' THEN 4 WHEN "
997
877
            "'secondary_link' "
998
877
            "THEN 6 WHEN 'secondary' THEN 6 WHEN 'primary_link' THEN 7 WHEN "
999
877
            "'primary' THEN 7 WHEN 'trunk_link' THEN 8 WHEN 'trunk' THEN 8 "
1000
877
            "WHEN 'motorway_link' THEN 9 WHEN 'motorway' THEN 9 ELSE 0 END) + "
1001
877
            "(CASE WHEN [bridge] IN ('yes', 'true', '1') THEN 10 ELSE 0 END) + "
1002
877
            "(CASE WHEN [tunnel] IN ('yes', 'true', '1') THEN -10 ELSE 0 END) "
1003
877
            "+ "
1004
877
            "(CASE WHEN [railway] IS NOT NULL THEN 5 ELSE 0 END) + "
1005
877
            "(CASE WHEN [layer] IS NOT NULL THEN 10 * CAST([layer] AS INTEGER) "
1006
877
            "ELSE 0 END)") == 0;
1007
877
    std::vector<CPLString> aosAttrToBind;
1008
877
    std::vector<int> anIndexToBind;
1009
877
    size_t nStartSearch = 0;
1010
6.13k
    while (true)
1011
6.13k
    {
1012
6.13k
        size_t nPos = osSQL.find("[", nStartSearch);
1013
6.13k
        if (nPos == std::string::npos)
1014
877
            break;
1015
5.26k
        nStartSearch = nPos + 1;
1016
5.26k
        if (nPos > 0 && osSQL[nPos - 1] != '\\')
1017
5.26k
        {
1018
5.26k
            CPLString osAttr = osSQL.substr(nPos + 1);
1019
5.26k
            size_t nPos2 = osAttr.find("]");
1020
5.26k
            if (nPos2 == std::string::npos)
1021
0
                break;
1022
5.26k
            osAttr.resize(nPos2);
1023
1024
5.26k
            osSQL = osSQL.substr(0, nPos) + "?" +
1025
5.26k
                    osSQL.substr(nPos + 1 + nPos2 + 1);
1026
1027
5.26k
            aosAttrToBind.push_back(osAttr);
1028
5.26k
            anIndexToBind.push_back(m_poFeatureDefn->GetFieldIndex(osAttr));
1029
5.26k
        }
1030
5.26k
    }
1031
877
    while (true)
1032
877
    {
1033
877
        size_t nPos = osSQL.find("\\");
1034
877
        if (nPos == std::string::npos || nPos == osSQL.size() - 1)
1035
877
            break;
1036
0
        osSQL = osSQL.substr(0, nPos) + osSQL.substr(nPos + 1);
1037
0
    }
1038
1039
877
    CPLDebug("OSM", "SQL : \"%s\"", osSQL.c_str());
1040
1041
877
    sqlite3_stmt *hStmt = nullptr;
1042
877
    int rc = sqlite3_prepare_v2(m_poDS->m_hDBForComputedAttributes, osSQL, -1,
1043
877
                                &hStmt, nullptr);
1044
877
    if (rc != SQLITE_OK)
1045
0
    {
1046
0
        CPLError(CE_Failure, CPLE_AppDefined,
1047
0
                 "sqlite3_prepare_v2() failed :  %s",
1048
0
                 sqlite3_errmsg(m_poDS->m_hDBForComputedAttributes));
1049
0
        return;
1050
0
    }
1051
1052
877
    OGRFieldDefn oField(pszName, eType);
1053
877
    m_poFeatureDefn->AddFieldDefn(&oField);
1054
877
    m_oComputedAttributes.push_back(OGROSMComputedAttribute(pszName));
1055
877
    OGROSMComputedAttribute &oComputedAttribute = m_oComputedAttributes.back();
1056
877
    oComputedAttribute.eType = eType;
1057
877
    oComputedAttribute.nIndex = m_poFeatureDefn->GetFieldCount() - 1;
1058
877
    oComputedAttribute.osSQL = pszSQL;
1059
877
    oComputedAttribute.hStmt = hStmt;
1060
877
    oComputedAttribute.aosAttrToBind = std::move(aosAttrToBind);
1061
877
    oComputedAttribute.anIndexToBind = std::move(anIndexToBind);
1062
877
    oComputedAttribute.bHardcodedZOrder = bHardcodedZOrder;
1063
877
}