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