LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/osm - ogrosmlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 379 473 80.1 %
Date: 2024-11-21 22:18:42 Functions: 26 27 96.3 %

          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             : }

Generated by: LCOV version 1.14