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 160 : OGROSMLayer::OGROSMLayer(OGROSMDataSource *poDSIn, int nIdxLayerIn,
55 160 : const char *pszName)
56 : : m_poDS(poDSIn), m_nIdxLayer(nIdxLayerIn),
57 160 : m_poFeatureDefn(new OGRFeatureDefn(pszName)),
58 320 : m_poSRS(new OGRSpatialReference())
59 : {
60 160 : SetDescription(m_poFeatureDefn->GetName());
61 160 : m_poFeatureDefn->Reference();
62 :
63 160 : m_poSRS->SetWellKnownGeogCS("WGS84");
64 160 : m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
65 :
66 160 : if (m_poFeatureDefn->GetGeomFieldCount() != 0)
67 160 : m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(m_poSRS);
68 160 : }
69 :
70 : /************************************************************************/
71 : /* ~OGROSMLayer() */
72 : /************************************************************************/
73 :
74 320 : OGROSMLayer::~OGROSMLayer()
75 : {
76 160 : m_poFeatureDefn->Release();
77 :
78 160 : if (m_poSRS)
79 160 : m_poSRS->Release();
80 :
81 1778 : for (int i = 0; i < static_cast<int>(m_apszNames.size()); i++)
82 1618 : CPLFree(m_apszNames[i]);
83 :
84 345 : for (int i = 0; i < static_cast<int>(apszInsignificantKeys.size()); i++)
85 185 : CPLFree(apszInsignificantKeys[i]);
86 :
87 1798 : for (int i = 0; i < static_cast<int>(apszIgnoreKeys.size()); i++)
88 1638 : CPLFree(apszIgnoreKeys[i]);
89 :
90 191 : for (int i = 0; i < static_cast<int>(m_oComputedAttributes.size()); i++)
91 : {
92 31 : sqlite3_finalize(m_oComputedAttributes[i].hStmt);
93 : }
94 320 : }
95 :
96 : /************************************************************************/
97 : /* ResetReading() */
98 : /************************************************************************/
99 :
100 63 : void OGROSMLayer::ResetReading()
101 : {
102 63 : if (!m_bResetReadingAllowed || m_poDS->IsInterleavedReading())
103 48 : return;
104 :
105 15 : m_poDS->MyResetReading();
106 : }
107 :
108 : /************************************************************************/
109 : /* ForceResetReading() */
110 : /************************************************************************/
111 :
112 310 : void OGROSMLayer::ForceResetReading()
113 : {
114 310 : m_apoFeatures.clear();
115 310 : m_nFeatureArrayIndex = 0;
116 310 : m_bResetReadingAllowed = false;
117 310 : }
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 312 : OGRFeature *OGROSMLayer::MyGetNextFeature(OGROSMLayer **ppoNewCurLayer,
179 : GDALProgressFunc pfnProgress,
180 : void *pProgressData)
181 : {
182 312 : *ppoNewCurLayer = m_poDS->GetCurrentLayer();
183 312 : m_bResetReadingAllowed = true;
184 :
185 312 : if (m_apoFeatures.empty())
186 : {
187 104 : if (m_poDS->IsInterleavedReading())
188 : {
189 36 : if (*ppoNewCurLayer == nullptr)
190 : {
191 0 : *ppoNewCurLayer = this;
192 : }
193 36 : 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 216 : for (int i = 0; i < m_poDS->GetLayerCount(); i++)
201 : {
202 324 : if (m_poDS->m_apoLayers[i].get() != this &&
203 144 : 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 36 : m_poDS->ParseNextChunk(m_nIdxLayer, pfnProgress, pProgressData);
217 :
218 36 : 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 117 : for (int i = 0; i < m_poDS->GetLayerCount(); i++)
224 : {
225 189 : if (m_poDS->m_apoLayers[i].get() != this &&
226 80 : !m_poDS->m_apoLayers[i]->m_apoFeatures.empty())
227 : {
228 21 : *ppoNewCurLayer = m_poDS->m_apoLayers[i].get();
229 21 : CPLDebug("OSM",
230 : "Switching to '%s' as they are "
231 : "no more feature in '%s'",
232 21 : m_poDS->m_apoLayers[i]->GetName(), GetName());
233 21 : return nullptr;
234 : }
235 : }
236 :
237 : /* Game over : no more data to read from the stream */
238 8 : *ppoNewCurLayer = nullptr;
239 8 : 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 480 : auto poFeature = std::move(m_apoFeatures[m_nFeatureArrayIndex]);
258 240 : m_nFeatureArrayIndex++;
259 :
260 240 : if (m_nFeatureArrayIndex == m_apoFeatures.size())
261 : {
262 80 : m_nFeatureArrayIndex = 0;
263 80 : m_apoFeatures.clear();
264 : }
265 :
266 240 : 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 612 : bool OGROSMLayer::AddToArray(std::unique_ptr<OGRFeature> poFeature,
290 : bool bCheckFeatureThreshold)
291 : {
292 612 : 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 612 : 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 612 : 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 647 : bool OGROSMLayer::AddFeature(std::unique_ptr<OGRFeature> poFeature,
339 : bool bAttrFilterAlreadyEvaluated,
340 : bool *pbFilteredOut, bool bCheckFeatureThreshold)
341 : {
342 647 : if (!m_bUserInterested)
343 : {
344 0 : if (pbFilteredOut)
345 0 : *pbFilteredOut = true;
346 0 : return true;
347 : }
348 :
349 647 : OGRGeometry *poGeom = poFeature->GetGeometryRef();
350 647 : if (poGeom)
351 647 : poGeom->assignSpatialReference(m_poSRS);
352 :
353 1294 : if ((m_poFilterGeom == nullptr || FilterGeometry(poGeom)) &&
354 647 : (m_poAttrQuery == nullptr || bAttrFilterAlreadyEvaluated ||
355 40 : m_poAttrQuery->Evaluate(poFeature.get())))
356 : {
357 612 : 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 612 : if (pbFilteredOut)
370 612 : *pbFilteredOut = false;
371 612 : return true;
372 : }
373 :
374 : /************************************************************************/
375 : /* GetExtent() */
376 : /************************************************************************/
377 :
378 3 : OGRErr OGROSMLayer::GetExtent(OGREnvelope *psExtent, int /* bForce */)
379 : {
380 3 : if (m_poDS->GetExtent(psExtent) == OGRERR_NONE)
381 3 : return OGRERR_NONE;
382 :
383 : /* return OGRLayer::GetExtent(psExtent, bForce);*/
384 0 : return OGRERR_FAILURE;
385 : }
386 :
387 : /************************************************************************/
388 : /* GetLaunderedFieldName() */
389 : /************************************************************************/
390 :
391 1618 : const char *OGROSMLayer::GetLaunderedFieldName(const char *pszName)
392 : {
393 3236 : if (m_poDS->DoesAttributeNameLaundering() &&
394 1618 : 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 1616 : return pszName;
409 : }
410 :
411 : /************************************************************************/
412 : /* AddField() */
413 : /************************************************************************/
414 :
415 1618 : void OGROSMLayer::AddField(const char *pszName, OGRFieldType eFieldType,
416 : OGRFieldSubType eSubType)
417 : {
418 1618 : const char *pszLaunderedName = GetLaunderedFieldName(pszName);
419 3236 : OGRFieldDefn oField(pszLaunderedName, eFieldType);
420 1618 : oField.SetSubType(eSubType);
421 1618 : m_poFeatureDefn->AddFieldDefn(&oField);
422 :
423 1618 : int nIndex = m_poFeatureDefn->GetFieldCount() - 1;
424 1618 : char *pszDupName = CPLStrdup(pszName);
425 1618 : m_apszNames.push_back(pszDupName);
426 1618 : m_oMapFieldNameToIndex[pszDupName] = nIndex;
427 :
428 1618 : if (strcmp(pszName, "osm_id") == 0)
429 155 : m_nIndexOSMId = nIndex;
430 :
431 1463 : else if (strcmp(pszName, "osm_way_id") == 0)
432 31 : m_nIndexOSMWayId = nIndex;
433 :
434 1432 : else if (strcmp(pszName, "other_tags") == 0)
435 158 : m_nIndexOtherTags = nIndex;
436 :
437 1274 : else if (strcmp(pszName, "all_tags") == 0)
438 2 : m_nIndexAllTags = nIndex;
439 1618 : }
440 :
441 : /************************************************************************/
442 : /* GetFieldIndex() */
443 : /************************************************************************/
444 :
445 1103 : int OGROSMLayer::GetFieldIndex(const char *pszName)
446 : {
447 1103 : const auto oIter = m_oMapFieldNameToIndex.find(pszName);
448 1103 : if (oIter != m_oMapFieldNameToIndex.end())
449 721 : return oIter->second;
450 :
451 382 : return -1;
452 : }
453 :
454 : /************************************************************************/
455 : /* AddInOtherOrAllTags() */
456 : /************************************************************************/
457 :
458 387 : int OGROSMLayer::AddInOtherOrAllTags(const char *pszK)
459 : {
460 387 : bool bAddToOtherTags = false;
461 :
462 387 : if (aoSetIgnoreKeys.find(pszK) == aoSetIgnoreKeys.end())
463 : {
464 187 : char *pszColon = strchr(const_cast<char *>(pszK), ':');
465 187 : 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 187 : bAddToOtherTags = true;
476 : }
477 :
478 387 : return bAddToOtherTags;
479 : }
480 :
481 : /************************************************************************/
482 : /* OGROSMEscapeStringHSTORE() */
483 : /************************************************************************/
484 :
485 366 : static void OGROSMEscapeStringHSTORE(const char *pszV, std::string &sOut)
486 : {
487 366 : sOut += '"';
488 :
489 2564 : for (int k = 0; pszV[k] != '\0'; k++)
490 : {
491 2198 : if (pszV[k] == '"' || pszV[k] == '\\')
492 0 : sOut += '\\';
493 2198 : sOut += pszV[k];
494 : }
495 :
496 366 : sOut += '"';
497 366 : }
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 1185 : static const char *GetValueOfTag(const char *pszKeyToSearch, unsigned int nTags,
544 : const OSMTag *pasTags)
545 : {
546 3109 : for (unsigned int k = 0; k < nTags; k++)
547 : {
548 1928 : const char *pszK = pasTags[k].pszK;
549 1928 : if (strcmp(pszK, pszKeyToSearch) == 0)
550 : {
551 4 : return pasTags[k].pszV;
552 : }
553 : }
554 1181 : return nullptr;
555 : }
556 :
557 : /************************************************************************/
558 : /* SetFieldsFromTags() */
559 : /************************************************************************/
560 :
561 676 : void OGROSMLayer::SetFieldsFromTags(OGRFeature *poFeature, GIntBig nID,
562 : bool bIsWayID, unsigned int nTags,
563 : const OSMTag *pasTags,
564 : const OSMInfo *psInfo)
565 : {
566 676 : if (!bIsWayID)
567 : {
568 534 : poFeature->SetFID(nID);
569 :
570 534 : if (m_bHasOSMId)
571 : {
572 : char szID[32];
573 533 : snprintf(szID, sizeof(szID), CPL_FRMT_GIB, nID);
574 533 : poFeature->SetField(m_nIndexOSMId, szID);
575 : }
576 : }
577 : else
578 : {
579 142 : poFeature->SetFID(nID);
580 :
581 142 : if (m_nIndexOSMWayId >= 0)
582 : {
583 : char szID[32];
584 142 : snprintf(szID, sizeof(szID), CPL_FRMT_GIB, nID);
585 142 : poFeature->SetField(m_nIndexOSMWayId, szID);
586 : }
587 : }
588 :
589 676 : if (m_bHasVersion)
590 : {
591 0 : poFeature->SetField("osm_version", psInfo->nVersion);
592 : }
593 676 : 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 676 : if (m_bHasUID)
614 : {
615 0 : poFeature->SetField("osm_uid", psInfo->nUID);
616 : }
617 676 : if (m_bHasUser)
618 : {
619 0 : poFeature->SetField("osm_user", psInfo->pszUserSID);
620 : }
621 676 : if (m_bHasChangeset)
622 : {
623 0 : poFeature->SetField("osm_changeset", psInfo->nChangeset);
624 : }
625 :
626 676 : m_osAllTagsBuffer.clear();
627 1779 : for (unsigned int j = 0; j < nTags; j++)
628 : {
629 1103 : const char *pszK = pasTags[j].pszK;
630 1103 : const char *pszV = pasTags[j].pszV;
631 1103 : int nIndex = GetFieldIndex(pszK);
632 1103 : if (nIndex >= 0 && nIndex != m_nIndexOSMId)
633 : {
634 720 : poFeature->SetField(nIndex, pszV);
635 720 : if (m_nIndexAllTags < 0)
636 716 : continue;
637 : }
638 387 : if (m_nIndexAllTags >= 0 || m_nIndexOtherTags >= 0)
639 : {
640 387 : if (AddInOtherOrAllTags(pszK))
641 : {
642 187 : if (m_poDS->m_bTagsAsHSTORE)
643 : {
644 183 : if (!m_osAllTagsBuffer.empty())
645 58 : m_osAllTagsBuffer += ',';
646 :
647 183 : OGROSMEscapeStringHSTORE(pszK, m_osAllTagsBuffer);
648 :
649 183 : m_osAllTagsBuffer += '=';
650 183 : m_osAllTagsBuffer += '>';
651 :
652 183 : 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 676 : if (!m_osAllTagsBuffer.empty())
677 : {
678 128 : if (!m_poDS->m_bTagsAsHSTORE)
679 : {
680 3 : m_osAllTagsBuffer += '}';
681 : }
682 128 : if (m_nIndexAllTags >= 0)
683 4 : poFeature->SetField(m_nIndexAllTags, m_osAllTagsBuffer.c_str());
684 : else
685 124 : poFeature->SetField(m_nIndexOtherTags, m_osAllTagsBuffer.c_str());
686 : }
687 :
688 1074 : for (size_t i = 0; i < m_oComputedAttributes.size(); i++)
689 : {
690 398 : const OGROSMComputedAttribute &oAttr = m_oComputedAttributes[i];
691 398 : if (oAttr.bHardcodedZOrder)
692 : {
693 395 : const int nHighwayIdx = oAttr.anIndexToBind[0];
694 395 : const int nBridgeIdx = oAttr.anIndexToBind[1];
695 395 : const int nTunnelIdx = oAttr.anIndexToBind[2];
696 395 : const int nRailwayIdx = oAttr.anIndexToBind[3];
697 395 : const int nLayerIdx = oAttr.anIndexToBind[4];
698 :
699 395 : 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 395 : const char *pszHighway = nullptr;
718 395 : if (nHighwayIdx >= 0)
719 : {
720 395 : if (poFeature->IsFieldSetAndNotNull(nHighwayIdx))
721 : {
722 297 : pszHighway = poFeature->GetFieldAsString(nHighwayIdx);
723 : }
724 : }
725 : else
726 0 : pszHighway = GetValueOfTag("highway", nTags, pasTags);
727 395 : if (pszHighway)
728 : {
729 297 : if (strcmp(pszHighway, "minor") == 0 ||
730 297 : strcmp(pszHighway, "road") == 0 ||
731 289 : strcmp(pszHighway, "unclassified") == 0 ||
732 237 : strcmp(pszHighway, "residential") == 0)
733 : {
734 228 : nZOrder += 3;
735 : }
736 69 : else if (strcmp(pszHighway, "tertiary_link") == 0 ||
737 69 : strcmp(pszHighway, "tertiary") == 0)
738 : {
739 18 : nZOrder += 4;
740 : }
741 51 : else if (strcmp(pszHighway, "secondary_link") == 0 ||
742 51 : strcmp(pszHighway, "secondary") == 0)
743 : {
744 2 : nZOrder += 6;
745 : }
746 49 : else if (strcmp(pszHighway, "primary_link") == 0 ||
747 49 : strcmp(pszHighway, "primary") == 0)
748 : {
749 4 : nZOrder += 7;
750 : }
751 45 : else if (strcmp(pszHighway, "trunk_link") == 0 ||
752 45 : strcmp(pszHighway, "trunk") == 0)
753 : {
754 0 : nZOrder += 8;
755 : }
756 45 : else if (strcmp(pszHighway, "motorway_link") == 0 ||
757 45 : strcmp(pszHighway, "motorway") == 0)
758 : {
759 21 : nZOrder += 9;
760 : }
761 : }
762 :
763 395 : const char *pszBridge = nullptr;
764 395 : if (nBridgeIdx >= 0)
765 : {
766 0 : if (poFeature->IsFieldSetAndNotNull(nBridgeIdx))
767 : {
768 0 : pszBridge = poFeature->GetFieldAsString(nBridgeIdx);
769 : }
770 : }
771 : else
772 395 : pszBridge = GetValueOfTag("bridge", nTags, pasTags);
773 395 : 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 395 : const char *pszTunnel = nullptr;
784 395 : if (nTunnelIdx >= 0)
785 : {
786 0 : if (poFeature->IsFieldSetAndNotNull(nTunnelIdx))
787 : {
788 0 : pszTunnel = poFeature->GetFieldAsString(nTunnelIdx);
789 : }
790 : }
791 : else
792 395 : pszTunnel = GetValueOfTag("tunnel", nTags, pasTags);
793 395 : 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 395 : const char *pszRailway = nullptr;
804 395 : if (nRailwayIdx >= 0)
805 : {
806 395 : if (poFeature->IsFieldSetAndNotNull(nRailwayIdx))
807 : {
808 4 : pszRailway = poFeature->GetFieldAsString(nRailwayIdx);
809 : }
810 : }
811 : else
812 0 : pszRailway = GetValueOfTag("railway", nTags, pasTags);
813 395 : if (pszRailway)
814 : {
815 4 : nZOrder += 5;
816 : }
817 :
818 395 : const char *pszLayer = nullptr;
819 395 : if (nLayerIdx >= 0)
820 : {
821 0 : if (poFeature->IsFieldSetAndNotNull(nLayerIdx))
822 : {
823 0 : pszLayer = poFeature->GetFieldAsString(nLayerIdx);
824 : }
825 : }
826 : else
827 395 : pszLayer = GetValueOfTag("layer", nTags, pasTags);
828 395 : if (pszLayer)
829 : {
830 4 : nZOrder += 10 * atoi(pszLayer);
831 : }
832 :
833 395 : poFeature->SetField(oAttr.nIndex, nZOrder);
834 :
835 395 : 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 676 : }
917 :
918 : /************************************************************************/
919 : /* GetSpatialFilterEnvelope() */
920 : /************************************************************************/
921 :
922 75 : const OGREnvelope *OGROSMLayer::GetSpatialFilterEnvelope()
923 : {
924 75 : if (m_poFilterGeom != nullptr)
925 1 : return &m_sFilterEnvelope;
926 : else
927 74 : return nullptr;
928 : }
929 :
930 : /************************************************************************/
931 : /* AddInsignificantKey() */
932 : /************************************************************************/
933 :
934 185 : void OGROSMLayer::AddInsignificantKey(const char *pszK)
935 : {
936 185 : char *pszKDup = CPLStrdup(pszK);
937 185 : apszInsignificantKeys.push_back(pszKDup);
938 185 : aoSetInsignificantKeys[pszKDup] = 1;
939 185 : }
940 :
941 : /************************************************************************/
942 : /* AddIgnoreKey() */
943 : /************************************************************************/
944 :
945 1638 : void OGROSMLayer::AddIgnoreKey(const char *pszK)
946 : {
947 1638 : char *pszKDup = CPLStrdup(pszK);
948 1638 : apszIgnoreKeys.push_back(pszKDup);
949 1638 : aoSetIgnoreKeys[pszKDup] = 1;
950 1638 : }
951 :
952 : /************************************************************************/
953 : /* AddWarnKey() */
954 : /************************************************************************/
955 :
956 1638 : void OGROSMLayer::AddWarnKey(const char *pszK)
957 : {
958 1638 : aoSetWarnKeys.insert(pszK);
959 1638 : }
960 :
961 : /************************************************************************/
962 : /* AddWarnKey() */
963 : /************************************************************************/
964 :
965 31 : void OGROSMLayer::AddComputedAttribute(const char *pszName, OGRFieldType eType,
966 : const char *pszSQL)
967 : {
968 31 : if (m_poDS->m_hDBForComputedAttributes == nullptr)
969 : {
970 62 : const int rc = sqlite3_open_v2(
971 31 : ":memory:", &(m_poDS->m_hDBForComputedAttributes),
972 : SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX,
973 : nullptr);
974 31 : 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 31 : 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 31 : CPLString osSQL(pszSQL);
990 31 : const bool bHardcodedZOrder =
991 62 : (eType == OFTInteger) &&
992 31 : 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 31 : std::vector<CPLString> aosAttrToBind;
1008 31 : std::vector<int> anIndexToBind;
1009 31 : size_t nStartSearch = 0;
1010 : while (true)
1011 : {
1012 217 : size_t nPos = osSQL.find("[", nStartSearch);
1013 217 : if (nPos == std::string::npos)
1014 31 : break;
1015 186 : nStartSearch = nPos + 1;
1016 186 : if (nPos > 0 && osSQL[nPos - 1] != '\\')
1017 : {
1018 186 : CPLString osAttr = osSQL.substr(nPos + 1);
1019 186 : size_t nPos2 = osAttr.find("]");
1020 186 : if (nPos2 == std::string::npos)
1021 0 : break;
1022 186 : osAttr.resize(nPos2);
1023 :
1024 372 : osSQL = osSQL.substr(0, nPos) + "?" +
1025 558 : osSQL.substr(nPos + 1 + nPos2 + 1);
1026 :
1027 186 : aosAttrToBind.push_back(osAttr);
1028 186 : anIndexToBind.push_back(m_poFeatureDefn->GetFieldIndex(osAttr));
1029 : }
1030 186 : }
1031 : while (true)
1032 : {
1033 31 : size_t nPos = osSQL.find("\\");
1034 31 : if (nPos == std::string::npos || nPos == osSQL.size() - 1)
1035 31 : break;
1036 0 : osSQL = osSQL.substr(0, nPos) + osSQL.substr(nPos + 1);
1037 0 : }
1038 :
1039 31 : CPLDebug("OSM", "SQL : \"%s\"", osSQL.c_str());
1040 :
1041 31 : sqlite3_stmt *hStmt = nullptr;
1042 31 : int rc = sqlite3_prepare_v2(m_poDS->m_hDBForComputedAttributes, osSQL, -1,
1043 : &hStmt, nullptr);
1044 31 : 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 31 : OGRFieldDefn oField(pszName, eType);
1053 31 : m_poFeatureDefn->AddFieldDefn(&oField);
1054 31 : m_oComputedAttributes.push_back(OGROSMComputedAttribute(pszName));
1055 31 : OGROSMComputedAttribute &oComputedAttribute = m_oComputedAttributes.back();
1056 31 : oComputedAttribute.eType = eType;
1057 31 : oComputedAttribute.nIndex = m_poFeatureDefn->GetFieldCount() - 1;
1058 31 : oComputedAttribute.osSQL = pszSQL;
1059 31 : oComputedAttribute.hStmt = hStmt;
1060 31 : oComputedAttribute.aosAttrToBind = std::move(aosAttrToBind);
1061 31 : oComputedAttribute.anIndexToBind = std::move(anIndexToBind);
1062 31 : oComputedAttribute.bHardcodedZOrder = bHardcodedZOrder;
1063 : }
|