• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 15712133003

17 Jun 2025 03:54PM UTC coverage: 71.056% (-0.007%) from 71.063%
15712133003

Pull #12573

github

web-flow
Merge c0909dec8 into a11400768
Pull Request #12573: gdal raster/vector reproject: enhance completion for --dst-crs to take into extent of input dataset

195 of 211 new or added lines in 13 files covered. (92.42%)

26122 existing lines in 50 files now uncovered.

571979 of 804971 relevant lines covered (71.06%)

250740.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.13
/ogr/ogrsf_frmts/osm/ogrosmlayer.cpp
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
#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,
190✔
55
                         const char *pszName)
190✔
56
    : m_poDS(poDSIn), m_nIdxLayer(nIdxLayerIn),
57
      m_poFeatureDefn(new OGRFeatureDefn(pszName)),
190✔
58
      m_poSRS(new OGRSpatialReference())
380✔
59
{
60
    SetDescription(m_poFeatureDefn->GetName());
190✔
61
    m_poFeatureDefn->Reference();
190✔
62

63
    m_poSRS->SetWellKnownGeogCS("WGS84");
190✔
64
    m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
190✔
65

66
    if (m_poFeatureDefn->GetGeomFieldCount() != 0)
190✔
67
        m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(m_poSRS);
190✔
68
}
190✔
69

70
/************************************************************************/
71
/*                          ~OGROSMLayer()                           */
72
/************************************************************************/
73

74
OGROSMLayer::~OGROSMLayer()
380✔
75
{
76
    m_poFeatureDefn->Release();
190✔
77

78
    if (m_poSRS)
190✔
79
        m_poSRS->Release();
190✔
80

81
    for (int i = 0; i < static_cast<int>(m_apszNames.size()); i++)
2,120✔
82
        CPLFree(m_apszNames[i]);
1,930✔
83

84
    for (int i = 0; i < static_cast<int>(apszInsignificantKeys.size()); i++)
411✔
85
        CPLFree(apszInsignificantKeys[i]);
221✔
86

87
    for (int i = 0; i < static_cast<int>(apszIgnoreKeys.size()); i++)
2,146✔
88
        CPLFree(apszIgnoreKeys[i]);
1,956✔
89

90
    for (int i = 0; i < static_cast<int>(m_oComputedAttributes.size()); i++)
227✔
91
    {
92
        sqlite3_finalize(m_oComputedAttributes[i].hStmt);
37✔
93
    }
94
}
380✔
95

96
/************************************************************************/
97
/*                            ResetReading()                            */
98
/************************************************************************/
99

100
void OGROSMLayer::ResetReading()
68✔
101
{
102
    if (!m_bResetReadingAllowed || m_poDS->IsInterleavedReading())
68✔
103
        return;
53✔
104

105
    m_poDS->MyResetReading();
15✔
106
}
107

108
/************************************************************************/
109
/*                        ForceResetReading()                           */
110
/************************************************************************/
111

112
void OGROSMLayer::ForceResetReading()
330✔
113
{
114
    m_apoFeatures.clear();
330✔
115
    m_nFeatureArrayIndex = 0;
330✔
116
    m_bResetReadingAllowed = false;
330✔
117
}
330✔
118

119
/************************************************************************/
120
/*                        SetAttributeFilter()                          */
121
/************************************************************************/
122

123
OGRErr OGROSMLayer::SetAttributeFilter(const char *pszAttrQuery)
39✔
124
{
125
    if (pszAttrQuery == nullptr && m_pszAttrQueryString == nullptr)
39✔
126
        return OGRERR_NONE;
11✔
127
    if (pszAttrQuery != nullptr && m_pszAttrQueryString != nullptr &&
28✔
128
        strcmp(pszAttrQuery, m_pszAttrQueryString) == 0)
14✔
129
        return OGRERR_NONE;
×
130

131
    OGRErr eErr = OGRLayer::SetAttributeFilter(pszAttrQuery);
28✔
132
    if (eErr != OGRERR_NONE)
28✔
133
        return eErr;
×
134

135
    if (m_nFeatureArrayIndex == 0)
28✔
136
    {
137
        if (!m_poDS->IsInterleavedReading())
28✔
138
        {
139
            m_poDS->MyResetReading();
28✔
140
        }
141
    }
142
    else
143
    {
144
        CPLError(CE_Warning, CPLE_AppDefined,
×
145
                 "The new attribute filter will "
146
                 "not be taken into account immediately. It is advised to "
147
                 "set attribute filters for all needed layers, before "
148
                 "reading *any* layer");
149
    }
150

151
    return OGRERR_NONE;
28✔
152
}
153

154
/************************************************************************/
155
/*                          GetFeatureCount()                           */
156
/************************************************************************/
157

158
GIntBig OGROSMLayer::GetFeatureCount(int bForce)
×
159
{
160
    if (m_poDS->IsFeatureCountEnabled())
×
161
        return OGRLayer::GetFeatureCount(bForce);
×
162

163
    return -1;
×
164
}
165

166
/************************************************************************/
167
/*                           GetNextFeature()                           */
168
/************************************************************************/
169

170
OGRFeature *OGROSMLayer::GetNextFeature()
237✔
171
{
172
    OGROSMLayer *poNewCurLayer = nullptr;
237✔
173
    OGRFeature *poFeature = MyGetNextFeature(&poNewCurLayer, nullptr, nullptr);
237✔
174
    m_poDS->SetCurrentLayer(poNewCurLayer);
237✔
175
    return poFeature;
237✔
176
}
177

178
OGRFeature *OGROSMLayer::MyGetNextFeature(OGROSMLayer **ppoNewCurLayer,
416✔
179
                                          GDALProgressFunc pfnProgress,
180
                                          void *pProgressData)
181
{
182
    *ppoNewCurLayer = m_poDS->GetCurrentLayer();
416✔
183
    m_bResetReadingAllowed = true;
416✔
184

185
    if (m_apoFeatures.empty())
416✔
186
    {
187
        if (m_poDS->IsInterleavedReading())
152✔
188
        {
189
            if (*ppoNewCurLayer == nullptr)
84✔
190
            {
191
                *ppoNewCurLayer = this;
×
192
            }
193
            else if (*ppoNewCurLayer != this)
84✔
194
            {
195
                return nullptr;
×
196
            }
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
            for (int i = 0; i < m_poDS->GetLayerCount(); i++)
504✔
201
            {
202
                if (m_poDS->m_apoLayers[i].get() != this &&
756✔
203
                    m_poDS->m_apoLayers[i]->m_apoFeatures.size() >
336✔
204
                        SWITCH_THRESHOLD)
205
                {
206
                    *ppoNewCurLayer = m_poDS->m_apoLayers[i].get();
×
207
                    CPLDebug("OSM",
×
208
                             "Switching to '%s' as they are too many "
209
                             "features in '%s'",
210
                             m_poDS->m_apoLayers[i]->GetName(), GetName());
×
211
                    return nullptr;
×
212
                }
213
            }
214

215
            // Read some more data and accumulate features.
216
            m_poDS->ParseNextChunk(m_nIdxLayer, pfnProgress, pProgressData);
84✔
217

218
            if (m_apoFeatures.empty())
84✔
219
            {
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
                for (int i = 0; i < m_poDS->GetLayerCount(); i++)
277✔
224
                {
225
                    if (m_poDS->m_apoLayers[i].get() != this &&
453✔
226
                        !m_poDS->m_apoLayers[i]->m_apoFeatures.empty())
192✔
227
                    {
228
                        *ppoNewCurLayer = m_poDS->m_apoLayers[i].get();
53✔
229
                        CPLDebug("OSM",
53✔
230
                                 "Switching to '%s' as they are "
231
                                 "no more feature in '%s'",
232
                                 m_poDS->m_apoLayers[i]->GetName(), GetName());
53✔
233
                        return nullptr;
53✔
234
                    }
235
                }
236

237
                /* Game over : no more data to read from the stream */
238
                *ppoNewCurLayer = nullptr;
16✔
239
                return nullptr;
16✔
240
            }
241
        }
242
        else
243
        {
244
            while (true)
245
            {
246
                int bRet =
247
                    m_poDS->ParseNextChunk(m_nIdxLayer, nullptr, nullptr);
72✔
248
                // cppcheck-suppress knownConditionTrueFalse
249
                if (!m_apoFeatures.empty())
72✔
250
                    break;
25✔
251
                if (bRet == FALSE)
47✔
252
                    return nullptr;
43✔
253
            }
4✔
254
        }
255
    }
256

257
    auto poFeature = std::move(m_apoFeatures[m_nFeatureArrayIndex]);
608✔
258
    m_nFeatureArrayIndex++;
304✔
259

260
    if (m_nFeatureArrayIndex == m_apoFeatures.size())
304✔
261
    {
262
        m_nFeatureArrayIndex = 0;
120✔
263
        m_apoFeatures.clear();
120✔
264
    }
265

266
    return poFeature.release();
304✔
267
}
268

269
/************************************************************************/
270
/*                           TestCapability()                           */
271
/************************************************************************/
272

273
int OGROSMLayer::TestCapability(const char *pszCap)
37✔
274
{
275
    if (EQUAL(pszCap, OLCFastGetExtent))
37✔
276
    {
277
        OGREnvelope sExtent;
×
NEW
278
        if (m_poDS->GetNativeExtent(&sExtent) == OGRERR_NONE)
×
279
            return TRUE;
×
280
    }
281

282
    return FALSE;
37✔
283
}
284

285
/************************************************************************/
286
/*                             AddToArray()                             */
287
/************************************************************************/
288

289
bool OGROSMLayer::AddToArray(std::unique_ptr<OGRFeature> poFeature,
676✔
290
                             bool bCheckFeatureThreshold)
291
{
292
    if (bCheckFeatureThreshold && m_apoFeatures.size() > MAX_THRESHOLD)
676✔
293
    {
294
        if (!m_bHasWarnedTooManyFeatures)
×
295
        {
296
            CPLError(
×
297
                CE_Failure, CPLE_AppDefined,
298
                "Too many features have accumulated in %s layer. "
299
                "Use the OGR_INTERLEAVED_READING=YES configuration option, "
300
                "or the INTERLEAVED_READING=YES open option, or the "
301
                "GDALDataset::GetNextFeature() / GDALDatasetGetNextFeature() "
302
                "API.",
303
                GetName());
×
304
        }
305
        m_bHasWarnedTooManyFeatures = true;
×
306
        return false;
×
307
    }
308

309
    try
310
    {
311
        m_apoFeatures.push_back(std::move(poFeature));
676✔
312
    }
313
    catch (const std::exception &)
×
314
    {
315
        CPLError(CE_Failure, CPLE_OutOfMemory,
×
316
                 "For layer %s, cannot resize feature array to %" PRIu64
317
                 " features",
318
                 GetName(), static_cast<uint64_t>(m_apoFeatures.size()) + 1);
×
319
        return false;
×
320
    }
321

322
    return true;
676✔
323
}
324

325
/************************************************************************/
326
/*                        EvaluateAttributeFilter()                     */
327
/************************************************************************/
328

329
int OGROSMLayer::EvaluateAttributeFilter(OGRFeature *poFeature)
11✔
330
{
331
    return (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature));
11✔
332
}
333

334
/************************************************************************/
335
/*                             AddFeature()                             */
336
/************************************************************************/
337

338
bool OGROSMLayer::AddFeature(std::unique_ptr<OGRFeature> poFeature,
711✔
339
                             bool bAttrFilterAlreadyEvaluated,
340
                             bool *pbFilteredOut, bool bCheckFeatureThreshold)
341
{
342
    if (!m_bUserInterested)
711✔
343
    {
344
        if (pbFilteredOut)
×
345
            *pbFilteredOut = true;
×
346
        return true;
×
347
    }
348

349
    OGRGeometry *poGeom = poFeature->GetGeometryRef();
711✔
350
    if (poGeom)
711✔
351
        poGeom->assignSpatialReference(m_poSRS);
711✔
352

353
    if ((m_poFilterGeom == nullptr || FilterGeometry(poGeom)) &&
1,422✔
354
        (m_poAttrQuery == nullptr || bAttrFilterAlreadyEvaluated ||
711✔
355
         m_poAttrQuery->Evaluate(poFeature.get())))
40✔
356
    {
357
        if (!AddToArray(std::move(poFeature), bCheckFeatureThreshold))
676✔
358
        {
359
            return false;
×
360
        }
361
    }
362
    else
363
    {
364
        if (pbFilteredOut)
35✔
365
            *pbFilteredOut = true;
35✔
366
        return true;
35✔
367
    }
368

369
    if (pbFilteredOut)
676✔
370
        *pbFilteredOut = false;
676✔
371
    return true;
676✔
372
}
373

374
/************************************************************************/
375
/*                            IGetExtent()                              */
376
/************************************************************************/
377

378
OGRErr OGROSMLayer::IGetExtent(int /* iGeomField */, OGREnvelope *psExtent,
3✔
379
                               bool /* bForce */)
380
{
381
    if (m_poDS->GetNativeExtent(psExtent) == OGRERR_NONE)
3✔
382
        return OGRERR_NONE;
3✔
383

384
    return OGRERR_FAILURE;
×
385
}
386

387
/************************************************************************/
388
/*                          GetLaunderedFieldName()                     */
389
/************************************************************************/
390

391
const char *OGROSMLayer::GetLaunderedFieldName(const char *pszName)
1,930✔
392
{
393
    if (m_poDS->DoesAttributeNameLaundering() &&
3,860✔
394
        strchr(pszName, ':') != nullptr)
1,930✔
395
    {
396
        size_t i = 0;
2✔
397
        for (; i < sizeof(szLaunderedFieldName) - 1 && pszName[i] != '\0'; i++)
17✔
398
        {
399
            if (pszName[i] == ':')
15✔
400
                szLaunderedFieldName[i] = '_';
2✔
401
            else
402
                szLaunderedFieldName[i] = pszName[i];
13✔
403
        }
404
        szLaunderedFieldName[i] = '\0';
2✔
405
        return szLaunderedFieldName;
2✔
406
    }
407

408
    return pszName;
1,928✔
409
}
410

411
/************************************************************************/
412
/*                              AddField()                              */
413
/************************************************************************/
414

415
void OGROSMLayer::AddField(const char *pszName, OGRFieldType eFieldType,
1,930✔
416
                           OGRFieldSubType eSubType)
417
{
418
    const char *pszLaunderedName = GetLaunderedFieldName(pszName);
1,930✔
419
    OGRFieldDefn oField(pszLaunderedName, eFieldType);
3,860✔
420
    oField.SetSubType(eSubType);
1,930✔
421
    m_poFeatureDefn->AddFieldDefn(&oField);
1,930✔
422

423
    int nIndex = m_poFeatureDefn->GetFieldCount() - 1;
1,930✔
424
    char *pszDupName = CPLStrdup(pszName);
1,930✔
425
    m_apszNames.push_back(pszDupName);
1,930✔
426
    m_oMapFieldNameToIndex[pszDupName] = nIndex;
1,930✔
427

428
    if (strcmp(pszName, "osm_id") == 0)
1,930✔
429
        m_nIndexOSMId = nIndex;
185✔
430

431
    else if (strcmp(pszName, "osm_way_id") == 0)
1,745✔
432
        m_nIndexOSMWayId = nIndex;
37✔
433

434
    else if (strcmp(pszName, "other_tags") == 0)
1,708✔
435
        m_nIndexOtherTags = nIndex;
188✔
436

437
    else if (strcmp(pszName, "all_tags") == 0)
1,520✔
438
        m_nIndexAllTags = nIndex;
2✔
439
}
1,930✔
440

441
/************************************************************************/
442
/*                              GetFieldIndex()                         */
443
/************************************************************************/
444

445
int OGROSMLayer::GetFieldIndex(const char *pszName)
1,215✔
446
{
447
    const auto oIter = m_oMapFieldNameToIndex.find(pszName);
1,215✔
448
    if (oIter != m_oMapFieldNameToIndex.end())
1,215✔
449
        return oIter->second;
809✔
450

451
    return -1;
406✔
452
}
453

454
/************************************************************************/
455
/*                         AddInOtherOrAllTags()                        */
456
/************************************************************************/
457

458
int OGROSMLayer::AddInOtherOrAllTags(const char *pszK)
411✔
459
{
460
    bool bAddToOtherTags = false;
411✔
461

462
    if (aoSetIgnoreKeys.find(pszK) == aoSetIgnoreKeys.end())
411✔
463
    {
464
        char *pszColon = strchr(const_cast<char *>(pszK), ':');
211✔
465
        if (pszColon)
211✔
466
        {
467
            char chBackup = pszColon[1];
×
468
            pszColon[1] = '\0'; /* Evil but OK */
×
469
            bAddToOtherTags =
470
                (aoSetIgnoreKeys.find(pszK) == aoSetIgnoreKeys.end());
×
471
            // cppcheck-suppress redundantAssignment
472
            pszColon[1] = chBackup;
×
473
        }
474
        else
475
            bAddToOtherTags = true;
211✔
476
    }
477

478
    return bAddToOtherTags;
411✔
479
}
480

481
/************************************************************************/
482
/*                     OGROSMEscapeStringHSTORE()                       */
483
/************************************************************************/
484

485
static void OGROSMEscapeStringHSTORE(const char *pszV, std::string &sOut)
414✔
486
{
487
    sOut += '"';
414✔
488

489
    for (int k = 0; pszV[k] != '\0'; k++)
2,756✔
490
    {
491
        if (pszV[k] == '"' || pszV[k] == '\\')
2,342✔
492
            sOut += '\\';
×
493
        sOut += pszV[k];
2,342✔
494
    }
495

496
    sOut += '"';
414✔
497
}
414✔
498

499
/************************************************************************/
500
/*                     OGROSMEscapeStringJSON()                         */
501
/************************************************************************/
502

503
static void OGROSMEscapeStringJSON(const char *pszV, std::string &sOut)
8✔
504
{
505
    sOut += '"';
8✔
506

507
    for (int k = 0; pszV[k] != '\0'; k++)
37✔
508
    {
509
        const char ch = pszV[k];
29✔
510
        switch (ch)
29✔
511
        {
512
            case '"':
1✔
513
                sOut += "\\\"";
1✔
514
                break;
1✔
515
            case '\\':
1✔
516
                sOut += "\\\\";
1✔
517
                break;
1✔
518
            case '\n':
1✔
519
                sOut += "\\n";
1✔
520
                break;
1✔
521
            case '\r':
1✔
522
                sOut += "\\r";
1✔
523
                break;
1✔
524
            case '\t':
1✔
525
                sOut += "\\t";
1✔
526
                break;
1✔
527
            default:
24✔
528
                if (static_cast<unsigned char>(ch) < ' ')
24✔
529
                    sOut += CPLSPrintf("\\u%04X", ch);
×
530
                else
531
                    sOut += ch;
24✔
532
                break;
24✔
533
        }
534
    }
535

536
    sOut += '"';
8✔
537
}
8✔
538

539
/************************************************************************/
540
/*                            GetValueOfTag()                           */
541
/************************************************************************/
542

543
static const char *GetValueOfTag(const char *pszKeyToSearch, unsigned int nTags,
1,257✔
544
                                 const OSMTag *pasTags)
545
{
546
    for (unsigned int k = 0; k < nTags; k++)
3,277✔
547
    {
548
        const char *pszK = pasTags[k].pszK;
2,024✔
549
        if (strcmp(pszK, pszKeyToSearch) == 0)
2,024✔
550
        {
551
            return pasTags[k].pszV;
4✔
552
        }
553
    }
554
    return nullptr;
1,253✔
555
}
556

557
/************************************************************************/
558
/*                        SetFieldsFromTags()                           */
559
/************************************************************************/
560

561
void OGROSMLayer::SetFieldsFromTags(OGRFeature *poFeature, GIntBig nID,
748✔
562
                                    bool bIsWayID, unsigned int nTags,
563
                                    const OSMTag *pasTags,
564
                                    const OSMInfo *psInfo)
565
{
566
    if (!bIsWayID)
748✔
567
    {
568
        poFeature->SetFID(nID);
598✔
569

570
        if (m_bHasOSMId)
598✔
571
        {
572
            char szID[32];
573
            snprintf(szID, sizeof(szID), CPL_FRMT_GIB, nID);
597✔
574
            poFeature->SetField(m_nIndexOSMId, szID);
597✔
575
        }
576
    }
577
    else
578
    {
579
        poFeature->SetFID(nID);
150✔
580

581
        if (m_nIndexOSMWayId >= 0)
150✔
582
        {
583
            char szID[32];
584
            snprintf(szID, sizeof(szID), CPL_FRMT_GIB, nID);
150✔
585
            poFeature->SetField(m_nIndexOSMWayId, szID);
150✔
586
        }
587
    }
588

589
    if (m_bHasVersion)
748✔
590
    {
591
        poFeature->SetField("osm_version", psInfo->nVersion);
×
592
    }
593
    if (m_bHasTimestamp)
748✔
594
    {
595
        if (psInfo->bTimeStampIsStr)
×
596
        {
597
            OGRField sField;
598
            if (OGRParseXMLDateTime(psInfo->ts.pszTimeStamp, &sField))
×
599
            {
600
                poFeature->SetField("osm_timestamp", &sField);
×
601
            }
602
        }
603
        else
604
        {
605
            struct tm brokendown;
606
            CPLUnixTimeToYMDHMS(psInfo->ts.nTimeStamp, &brokendown);
×
607
            poFeature->SetField("osm_timestamp", brokendown.tm_year + 1900,
×
608
                                brokendown.tm_mon + 1, brokendown.tm_mday,
×
609
                                brokendown.tm_hour, brokendown.tm_min,
610
                                static_cast<float>(brokendown.tm_sec), 0);
×
611
        }
612
    }
613
    if (m_bHasUID)
748✔
614
    {
615
        poFeature->SetField("osm_uid", psInfo->nUID);
×
616
    }
617
    if (m_bHasUser)
748✔
618
    {
619
        poFeature->SetField("osm_user", psInfo->pszUserSID);
×
620
    }
621
    if (m_bHasChangeset)
748✔
622
    {
623
        poFeature->SetField("osm_changeset", psInfo->nChangeset);
×
624
    }
625

626
    m_osAllTagsBuffer.clear();
748✔
627
    for (unsigned int j = 0; j < nTags; j++)
1,963✔
628
    {
629
        const char *pszK = pasTags[j].pszK;
1,215✔
630
        const char *pszV = pasTags[j].pszV;
1,215✔
631
        int nIndex = GetFieldIndex(pszK);
1,215✔
632
        if (nIndex >= 0 && nIndex != m_nIndexOSMId)
1,215✔
633
        {
634
            poFeature->SetField(nIndex, pszV);
808✔
635
            if (m_nIndexAllTags < 0)
808✔
636
                continue;
804✔
637
        }
638
        if (m_nIndexAllTags >= 0 || m_nIndexOtherTags >= 0)
411✔
639
        {
640
            if (AddInOtherOrAllTags(pszK))
411✔
641
            {
642
                if (m_poDS->m_bTagsAsHSTORE)
211✔
643
                {
644
                    if (!m_osAllTagsBuffer.empty())
207✔
645
                        m_osAllTagsBuffer += ',';
66✔
646

647
                    OGROSMEscapeStringHSTORE(pszK, m_osAllTagsBuffer);
207✔
648

649
                    m_osAllTagsBuffer += '=';
207✔
650
                    m_osAllTagsBuffer += '>';
207✔
651

652
                    OGROSMEscapeStringHSTORE(pszV, m_osAllTagsBuffer);
207✔
653
                }
654
                else
655
                {
656
                    if (!m_osAllTagsBuffer.empty())
4✔
657
                        m_osAllTagsBuffer += ',';
1✔
658
                    else
659
                        m_osAllTagsBuffer = '{';
3✔
660
                    OGROSMEscapeStringJSON(pszK, m_osAllTagsBuffer);
4✔
661
                    m_osAllTagsBuffer += ':';
4✔
662
                    OGROSMEscapeStringJSON(pszV, m_osAllTagsBuffer);
4✔
663
                }
664
            }
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
        }
674
    }
675

676
    if (!m_osAllTagsBuffer.empty())
748✔
677
    {
678
        if (!m_poDS->m_bTagsAsHSTORE)
144✔
679
        {
680
            m_osAllTagsBuffer += '}';
3✔
681
        }
682
        if (m_nIndexAllTags >= 0)
144✔
683
            poFeature->SetField(m_nIndexAllTags, m_osAllTagsBuffer.c_str());
4✔
684
        else
685
            poFeature->SetField(m_nIndexOtherTags, m_osAllTagsBuffer.c_str());
140✔
686
    }
687

688
    for (size_t i = 0; i < m_oComputedAttributes.size(); i++)
1,170✔
689
    {
690
        const OGROSMComputedAttribute &oAttr = m_oComputedAttributes[i];
422✔
691
        if (oAttr.bHardcodedZOrder)
422✔
692
        {
693
            const int nHighwayIdx = oAttr.anIndexToBind[0];
419✔
694
            const int nBridgeIdx = oAttr.anIndexToBind[1];
419✔
695
            const int nTunnelIdx = oAttr.anIndexToBind[2];
419✔
696
            const int nRailwayIdx = oAttr.anIndexToBind[3];
419✔
697
            const int nLayerIdx = oAttr.anIndexToBind[4];
419✔
698

699
            int nZOrder = 0;
419✔
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
            const char *pszHighway = nullptr;
419✔
718
            if (nHighwayIdx >= 0)
419✔
719
            {
720
                if (poFeature->IsFieldSetAndNotNull(nHighwayIdx))
419✔
721
                {
722
                    pszHighway = poFeature->GetFieldAsString(nHighwayIdx);
305✔
723
                }
724
            }
725
            else
726
                pszHighway = GetValueOfTag("highway", nTags, pasTags);
×
727
            if (pszHighway)
419✔
728
            {
729
                if (strcmp(pszHighway, "minor") == 0 ||
305✔
730
                    strcmp(pszHighway, "road") == 0 ||
305✔
731
                    strcmp(pszHighway, "unclassified") == 0 ||
297✔
732
                    strcmp(pszHighway, "residential") == 0)
245✔
733
                {
734
                    nZOrder += 3;
228✔
735
                }
736
                else if (strcmp(pszHighway, "tertiary_link") == 0 ||
77✔
737
                         strcmp(pszHighway, "tertiary") == 0)
77✔
738
                {
739
                    nZOrder += 4;
18✔
740
                }
741
                else if (strcmp(pszHighway, "secondary_link") == 0 ||
59✔
742
                         strcmp(pszHighway, "secondary") == 0)
59✔
743
                {
744
                    nZOrder += 6;
2✔
745
                }
746
                else if (strcmp(pszHighway, "primary_link") == 0 ||
57✔
747
                         strcmp(pszHighway, "primary") == 0)
57✔
748
                {
749
                    nZOrder += 7;
4✔
750
                }
751
                else if (strcmp(pszHighway, "trunk_link") == 0 ||
53✔
752
                         strcmp(pszHighway, "trunk") == 0)
53✔
753
                {
754
                    nZOrder += 8;
×
755
                }
756
                else if (strcmp(pszHighway, "motorway_link") == 0 ||
53✔
757
                         strcmp(pszHighway, "motorway") == 0)
53✔
758
                {
759
                    nZOrder += 9;
29✔
760
                }
761
            }
762

763
            const char *pszBridge = nullptr;
419✔
764
            if (nBridgeIdx >= 0)
419✔
765
            {
766
                if (poFeature->IsFieldSetAndNotNull(nBridgeIdx))
×
767
                {
768
                    pszBridge = poFeature->GetFieldAsString(nBridgeIdx);
×
769
                }
770
            }
771
            else
772
                pszBridge = GetValueOfTag("bridge", nTags, pasTags);
419✔
773
            if (pszBridge)
419✔
774
            {
775
                if (strcmp(pszBridge, "yes") == 0 ||
×
776
                    strcmp(pszBridge, "true") == 0 ||
×
777
                    strcmp(pszBridge, "1") == 0)
×
778
                {
779
                    nZOrder += 10;
×
780
                }
781
            }
782

783
            const char *pszTunnel = nullptr;
419✔
784
            if (nTunnelIdx >= 0)
419✔
785
            {
786
                if (poFeature->IsFieldSetAndNotNull(nTunnelIdx))
×
787
                {
788
                    pszTunnel = poFeature->GetFieldAsString(nTunnelIdx);
×
789
                }
790
            }
791
            else
792
                pszTunnel = GetValueOfTag("tunnel", nTags, pasTags);
419✔
793
            if (pszTunnel)
419✔
794
            {
795
                if (strcmp(pszTunnel, "yes") == 0 ||
×
796
                    strcmp(pszTunnel, "true") == 0 ||
×
797
                    strcmp(pszTunnel, "1") == 0)
×
798
                {
799
                    nZOrder -= 10;
×
800
                }
801
            }
802

803
            const char *pszRailway = nullptr;
419✔
804
            if (nRailwayIdx >= 0)
419✔
805
            {
806
                if (poFeature->IsFieldSetAndNotNull(nRailwayIdx))
419✔
807
                {
808
                    pszRailway = poFeature->GetFieldAsString(nRailwayIdx);
4✔
809
                }
810
            }
811
            else
812
                pszRailway = GetValueOfTag("railway", nTags, pasTags);
×
813
            if (pszRailway)
419✔
814
            {
815
                nZOrder += 5;
4✔
816
            }
817

818
            const char *pszLayer = nullptr;
419✔
819
            if (nLayerIdx >= 0)
419✔
820
            {
821
                if (poFeature->IsFieldSetAndNotNull(nLayerIdx))
×
822
                {
823
                    pszLayer = poFeature->GetFieldAsString(nLayerIdx);
×
824
                }
825
            }
826
            else
827
                pszLayer = GetValueOfTag("layer", nTags, pasTags);
419✔
828
            if (pszLayer)
419✔
829
            {
830
                nZOrder += 10 * atoi(pszLayer);
4✔
831
            }
832

833
            poFeature->SetField(oAttr.nIndex, nZOrder);
419✔
834

835
            continue;
419✔
836
        }
837

838
        for (int j = 0; j < static_cast<int>(oAttr.anIndexToBind.size()); j++)
21✔
839
        {
840
            if (oAttr.anIndexToBind[j] >= 0)
18✔
841
            {
842
                if (!poFeature->IsFieldSetAndNotNull(oAttr.anIndexToBind[j]))
3✔
843
                {
844
                    sqlite3_bind_null(oAttr.hStmt, j + 1);
2✔
845
                }
846
                else
847
                {
848
                    OGRFieldType eType =
849
                        m_poFeatureDefn->GetFieldDefn(oAttr.anIndexToBind[j])
1✔
850
                            ->GetType();
1✔
851
                    if (eType == OFTInteger)
1✔
852
                        sqlite3_bind_int(oAttr.hStmt, j + 1,
×
853
                                         poFeature->GetFieldAsInteger(
854
                                             oAttr.anIndexToBind[j]));
×
855
                    else if (eType == OFTInteger64)
1✔
856
                        sqlite3_bind_int64(oAttr.hStmt, j + 1,
×
857
                                           poFeature->GetFieldAsInteger64(
858
                                               oAttr.anIndexToBind[j]));
×
859
                    else if (eType == OFTReal)
1✔
860
                        sqlite3_bind_double(oAttr.hStmt, j + 1,
×
861
                                            poFeature->GetFieldAsDouble(
862
                                                oAttr.anIndexToBind[j]));
×
863
                    else
864
                        sqlite3_bind_text(
1✔
865
                            oAttr.hStmt, j + 1,
1✔
866
                            poFeature->GetFieldAsString(oAttr.anIndexToBind[j]),
1✔
867
                            -1, SQLITE_TRANSIENT);
868
                }
869
            }
870
            else
871
            {
872
                bool bTagFound = false;
15✔
873
                for (unsigned int k = 0; k < nTags; k++)
35✔
874
                {
875
                    const char *pszK = pasTags[k].pszK;
20✔
876
                    const char *pszV = pasTags[k].pszV;
20✔
877
                    if (strcmp(pszK, oAttr.aosAttrToBind[j]) == 0)
20✔
878
                    {
879
                        sqlite3_bind_text(oAttr.hStmt, j + 1, pszV, -1,
×
880
                                          SQLITE_TRANSIENT);
881
                        bTagFound = true;
×
882
                        break;
×
883
                    }
884
                }
885
                if (!bTagFound)
15✔
886
                    sqlite3_bind_null(oAttr.hStmt, j + 1);
15✔
887
            }
888
        }
889

890
        if (sqlite3_step(oAttr.hStmt) == SQLITE_ROW &&
6✔
891
            sqlite3_column_count(oAttr.hStmt) == 1)
3✔
892
        {
893
            switch (sqlite3_column_type(oAttr.hStmt, 0))
3✔
894
            {
895
                case SQLITE_INTEGER:
3✔
896
                    poFeature->SetField(
3✔
897
                        oAttr.nIndex, static_cast<GIntBig>(sqlite3_column_int64(
3✔
898
                                          oAttr.hStmt, 0)));
3✔
899
                    break;
3✔
900
                case SQLITE_FLOAT:
×
901
                    poFeature->SetField(oAttr.nIndex,
×
902
                                        sqlite3_column_double(oAttr.hStmt, 0));
×
903
                    break;
×
904
                case SQLITE_TEXT:
×
905
                    poFeature->SetField(
×
906
                        oAttr.nIndex, reinterpret_cast<const char *>(
×
907
                                          sqlite3_column_text(oAttr.hStmt, 0)));
×
908
                    break;
×
909
                default:
×
910
                    break;
×
911
            }
912
        }
913

914
        sqlite3_reset(oAttr.hStmt);
3✔
915
    }
916
}
748✔
917

918
/************************************************************************/
919
/*                      GetSpatialFilterEnvelope()                      */
920
/************************************************************************/
921

922
const OGREnvelope *OGROSMLayer::GetSpatialFilterEnvelope()
83✔
923
{
924
    if (m_poFilterGeom != nullptr)
83✔
925
        return &m_sFilterEnvelope;
3✔
926
    else
927
        return nullptr;
80✔
928
}
929

930
/************************************************************************/
931
/*                        AddInsignificantKey()                         */
932
/************************************************************************/
933

934
void OGROSMLayer::AddInsignificantKey(const char *pszK)
221✔
935
{
936
    char *pszKDup = CPLStrdup(pszK);
221✔
937
    apszInsignificantKeys.push_back(pszKDup);
221✔
938
    aoSetInsignificantKeys[pszKDup] = 1;
221✔
939
}
221✔
940

941
/************************************************************************/
942
/*                          AddIgnoreKey()                              */
943
/************************************************************************/
944

945
void OGROSMLayer::AddIgnoreKey(const char *pszK)
1,956✔
946
{
947
    char *pszKDup = CPLStrdup(pszK);
1,956✔
948
    apszIgnoreKeys.push_back(pszKDup);
1,956✔
949
    aoSetIgnoreKeys[pszKDup] = 1;
1,956✔
950
}
1,956✔
951

952
/************************************************************************/
953
/*                           AddWarnKey()                               */
954
/************************************************************************/
955

956
void OGROSMLayer::AddWarnKey(const char *pszK)
1,956✔
957
{
958
    aoSetWarnKeys.insert(pszK);
1,956✔
959
}
1,956✔
960

961
/************************************************************************/
962
/*                           AddWarnKey()                               */
963
/************************************************************************/
964

965
void OGROSMLayer::AddComputedAttribute(const char *pszName, OGRFieldType eType,
37✔
966
                                       const char *pszSQL)
967
{
968
    if (m_poDS->m_hDBForComputedAttributes == nullptr)
37✔
969
    {
970
        const int rc = sqlite3_open_v2(
74✔
971
            ":memory:", &(m_poDS->m_hDBForComputedAttributes),
37✔
972
            SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX,
973
            nullptr);
974
        if (rc != SQLITE_OK)
37✔
975
        {
976
            CPLError(CE_Failure, CPLE_AppDefined,
×
977
                     "Cannot open temporary sqlite DB");
978
            return;
×
979
        }
980
    }
981

982
    if (m_poFeatureDefn->GetFieldIndex(pszName) >= 0)
37✔
983
    {
984
        CPLError(CE_Failure, CPLE_AppDefined,
×
985
                 "A field with same name %s already exists", pszName);
986
        return;
×
987
    }
988

989
    CPLString osSQL(pszSQL);
37✔
990
    const bool bHardcodedZOrder =
37✔
991
        (eType == OFTInteger) &&
74✔
992
        strcmp(
37✔
993
            pszSQL,
994
            "SELECT (CASE [highway] WHEN 'minor' THEN 3 WHEN 'road' THEN 3 "
995
            "WHEN 'unclassified' THEN 3 WHEN 'residential' THEN 3 WHEN "
996
            "'tertiary_link' THEN 4 WHEN 'tertiary' THEN 4 WHEN "
997
            "'secondary_link' "
998
            "THEN 6 WHEN 'secondary' THEN 6 WHEN 'primary_link' THEN 7 WHEN "
999
            "'primary' THEN 7 WHEN 'trunk_link' THEN 8 WHEN 'trunk' THEN 8 "
1000
            "WHEN 'motorway_link' THEN 9 WHEN 'motorway' THEN 9 ELSE 0 END) + "
1001
            "(CASE WHEN [bridge] IN ('yes', 'true', '1') THEN 10 ELSE 0 END) + "
1002
            "(CASE WHEN [tunnel] IN ('yes', 'true', '1') THEN -10 ELSE 0 END) "
1003
            "+ "
1004
            "(CASE WHEN [railway] IS NOT NULL THEN 5 ELSE 0 END) + "
1005
            "(CASE WHEN [layer] IS NOT NULL THEN 10 * CAST([layer] AS INTEGER) "
1006
            "ELSE 0 END)") == 0;
1007
    std::vector<CPLString> aosAttrToBind;
37✔
1008
    std::vector<int> anIndexToBind;
37✔
1009
    size_t nStartSearch = 0;
37✔
1010
    while (true)
1011
    {
1012
        size_t nPos = osSQL.find("[", nStartSearch);
259✔
1013
        if (nPos == std::string::npos)
259✔
1014
            break;
37✔
1015
        nStartSearch = nPos + 1;
222✔
1016
        if (nPos > 0 && osSQL[nPos - 1] != '\\')
222✔
1017
        {
1018
            CPLString osAttr = osSQL.substr(nPos + 1);
222✔
1019
            size_t nPos2 = osAttr.find("]");
222✔
1020
            if (nPos2 == std::string::npos)
222✔
1021
                break;
×
1022
            osAttr.resize(nPos2);
222✔
1023

1024
            osSQL = osSQL.substr(0, nPos) + "?" +
444✔
1025
                    osSQL.substr(nPos + 1 + nPos2 + 1);
666✔
1026

1027
            aosAttrToBind.push_back(osAttr);
222✔
1028
            anIndexToBind.push_back(m_poFeatureDefn->GetFieldIndex(osAttr));
222✔
1029
        }
1030
    }
222✔
1031
    while (true)
1032
    {
1033
        size_t nPos = osSQL.find("\\");
37✔
1034
        if (nPos == std::string::npos || nPos == osSQL.size() - 1)
37✔
1035
            break;
37✔
1036
        osSQL = osSQL.substr(0, nPos) + osSQL.substr(nPos + 1);
×
1037
    }
×
1038

1039
    CPLDebug("OSM", "SQL : \"%s\"", osSQL.c_str());
37✔
1040

1041
    sqlite3_stmt *hStmt = nullptr;
37✔
1042
    int rc = sqlite3_prepare_v2(m_poDS->m_hDBForComputedAttributes, osSQL, -1,
37✔
1043
                                &hStmt, nullptr);
1044
    if (rc != SQLITE_OK)
37✔
1045
    {
1046
        CPLError(CE_Failure, CPLE_AppDefined,
×
1047
                 "sqlite3_prepare_v2() failed :  %s",
1048
                 sqlite3_errmsg(m_poDS->m_hDBForComputedAttributes));
×
1049
        return;
×
1050
    }
1051

1052
    OGRFieldDefn oField(pszName, eType);
37✔
1053
    m_poFeatureDefn->AddFieldDefn(&oField);
37✔
1054
    m_oComputedAttributes.push_back(OGROSMComputedAttribute(pszName));
37✔
1055
    OGROSMComputedAttribute &oComputedAttribute = m_oComputedAttributes.back();
37✔
1056
    oComputedAttribute.eType = eType;
37✔
1057
    oComputedAttribute.nIndex = m_poFeatureDefn->GetFieldCount() - 1;
37✔
1058
    oComputedAttribute.osSQL = pszSQL;
37✔
1059
    oComputedAttribute.hStmt = hStmt;
37✔
1060
    oComputedAttribute.aosAttrToBind = std::move(aosAttrToBind);
37✔
1061
    oComputedAttribute.anIndexToBind = std::move(anIndexToBind);
37✔
1062
    oComputedAttribute.bHardcodedZOrder = bHardcodedZOrder;
37✔
1063
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc