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