LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/osm - ogrosmdatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1799 1367 76.0 %
Date: 2012-12-26 Functions: 80 61 76.2 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrosmdatasource.cpp 24969 2012-09-24 22:25:50Z rouault $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  Implements OGROSMDataSource class.
       6                 :  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2012, Even Rouault
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "ogr_osm.h"
      31                 : #include "cpl_conv.h"
      32                 : #include "cpl_time.h"
      33                 : #include "ogr_p.h"
      34                 : #include "ogr_api.h"
      35                 : #include "swq.h"
      36                 : #include "gpb.h"
      37                 : #include "ogrlayerdecorator.h"
      38                 : #include "ogrsqliteexecutesql.h"
      39                 : #include "cpl_multiproc.h"
      40                 : 
      41                 : #include <algorithm>
      42                 : 
      43                 : #define LIMIT_IDS_PER_REQUEST 200
      44                 : 
      45                 : #define MAX_NODES_PER_WAY 2000
      46                 : 
      47                 : #define IDX_LYR_POINTS           0
      48                 : #define IDX_LYR_LINES            1
      49                 : #define IDX_LYR_MULTILINESTRINGS 2
      50                 : #define IDX_LYR_MULTIPOLYGONS    3
      51                 : #define IDX_LYR_OTHER_RELATIONS  4
      52                 : 
      53                 : #define DBL_TO_INT(x)            (int)floor((x) * 1e7 + 0.5)
      54                 : #define INT_TO_DBL(x)            ((x) / 1e7)
      55                 : 
      56                 : #define MAX_COUNT_FOR_TAGS_IN_WAY   255  /* must fit on 1 byte */
      57                 : #define MAX_SIZE_FOR_TAGS_IN_WAY    1024
      58                 : 
      59                 : /* 5 bytes for encoding a int : really the worst case scenario ! */
      60                 : #define WAY_BUFFER_SIZE (1 + MAX_NODES_PER_WAY * 2 * 5 + MAX_SIZE_FOR_TAGS_IN_WAY)
      61                 : 
      62                 : /* 65536 * 65536 so we can adress node ids between 0 and 4.2 billion */
      63                 : #define NODE_PER_BUCKET     65536
      64                 :  /* Maximum count of buckets */
      65                 : #define BUCKET_COUNT        65536
      66                 : 
      67                 : #define VALID_ID_FOR_CUSTOM_INDEXING(_id) ((_id) >= 0 && (_id) < (GIntBig)NODE_PER_BUCKET * BUCKET_COUNT)
      68                 : 
      69                 : /* Minimum size of data written on disk, in *uncompressed* case */
      70                 : #define SECTOR_SIZE         512
      71                 : /* Which represents, 64 nodes */
      72                 : /* #define NODE_PER_SECTOR     SECTOR_SIZE / (2 * 4) */
      73                 : #define NODE_PER_SECTOR     64
      74                 : #define NODE_PER_SECTOR_SHIFT   6
      75                 : 
      76                 : /* Per bucket, we keep track of the absence/presence of sectors */
      77                 : /* only, to reduce memory usage */
      78                 : /* #define BUCKET_BITMAP_SIZE  NODE_PER_BUCKET / (8 * NODE_PER_SECTOR) */
      79                 : #define BUCKET_BITMAP_SIZE  128
      80                 : 
      81                 : /* #define BUCKET_SECTOR_SIZE_ARRAY_SIZE  NODE_PER_BUCKET / NODE_PER_SECTOR */
      82                 : /* Per bucket, we keep track of the real size of the sector. Each sector */
      83                 : /* size is encoded in a single byte, whose value is : */
      84                 : /* (sector_size in bytes - 8 ) / 2, minus 8. 252 means uncompressed */
      85                 : #define BUCKET_SECTOR_SIZE_ARRAY_SIZE   1024
      86                 : 
      87                 : /* compressSize should not be greater than 512, so COMPRESS_SIZE_TO_BYTE() fits on a byte */
      88                 : #define COMPRESS_SIZE_TO_BYTE(nCompressSize)  (((nCompressSize) - 8) / 2)
      89                 : #define ROUND_COMPRESS_SIZE(nCompressSize)    (((nCompressSize) + 1) / 2) * 2;
      90                 : #define COMPRESS_SIZE_FROM_BYTE(byte_on_size) ((byte_on_size) * 2 + 8)
      91                 : 
      92                 : /* Max number of features that are accumulated in pasWayFeaturePairs */
      93                 : #define MAX_DELAYED_FEATURES        75000
      94                 : /* Max number of tags that are accumulated in pasAccumulatedTags */
      95                 : #define MAX_ACCUMULATED_TAGS        MAX_DELAYED_FEATURES * 5
      96                 : /* Max size of the string with tag values that are accumulated in pabyNonRedundantValues */
      97                 : #define MAX_NON_REDUNDANT_VALUES    MAX_DELAYED_FEATURES * 10
      98                 : /* Max number of features that are accumulated in panUnsortedReqIds */
      99                 : #define MAX_ACCUMULATED_NODES       1000000
     100                 : 
     101                 : //#define FAKE_LOOKUP_NODES
     102                 : 
     103                 : //#define DEBUG_MEM_USAGE
     104                 : #ifdef DEBUG_MEM_USAGE
     105                 : size_t GetMaxTotalAllocs();
     106                 : #endif
     107                 : 
     108                 : static void WriteVarInt64(GUIntBig nSVal, GByte** ppabyData);
     109                 : static void WriteVarSInt64(GIntBig nSVal, GByte** ppabyData);
     110                 : 
     111                 : CPL_CVSID("$Id: ogrosmdatasource.cpp 24969 2012-09-24 22:25:50Z rouault $");
     112                 : 
     113                 : class DSToBeOpened
     114               4 : {
     115                 :     public:
     116                 :         GIntBig                 nPID;
     117                 :         CPLString               osDSName;
     118                 :         CPLString               osInterestLayers;
     119                 : };
     120                 : 
     121                 : static void                      *hMutex = NULL;
     122             713 : static std::vector<DSToBeOpened>  oListDSToBeOpened;
     123                 : 
     124                 : /************************************************************************/
     125                 : /*                    AddInterestLayersForDSName()                      */
     126                 : /************************************************************************/
     127                 : 
     128               1 : static void AddInterestLayersForDSName(const CPLString& osDSName,
     129                 :                                        const CPLString& osInterestLayers)
     130                 : {
     131               1 :     CPLMutexHolder oMutexHolder(&hMutex);
     132               1 :     DSToBeOpened oDSToBeOpened;
     133               1 :     oDSToBeOpened.nPID = CPLGetPID();
     134               1 :     oDSToBeOpened.osDSName = osDSName;
     135               1 :     oDSToBeOpened.osInterestLayers = osInterestLayers;
     136               1 :     oListDSToBeOpened.push_back( oDSToBeOpened );
     137               1 : }
     138                 : 
     139                 : /************************************************************************/
     140                 : /*                    GetInterestLayersForDSName()                      */
     141                 : /************************************************************************/
     142                 : 
     143              10 : static CPLString GetInterestLayersForDSName(const CPLString& osDSName)
     144                 : {
     145              10 :     CPLMutexHolder oMutexHolder(&hMutex);
     146              10 :     GIntBig nPID = CPLGetPID();
     147              10 :     for(int i = 0; i < (int)oListDSToBeOpened.size(); i++)
     148                 :     {
     149               1 :         if( oListDSToBeOpened[i].nPID == nPID &&
     150                 :             oListDSToBeOpened[i].osDSName == osDSName )
     151                 :         {
     152               1 :             CPLString osInterestLayers = oListDSToBeOpened[i].osInterestLayers;
     153               1 :             oListDSToBeOpened.erase(oListDSToBeOpened.begin()+i);
     154               1 :             return osInterestLayers;
     155                 :         }
     156                 :     }
     157               9 :     return "";
     158                 : }
     159                 : 
     160                 : /************************************************************************/
     161                 : /*                        OGROSMDataSource()                            */
     162                 : /************************************************************************/
     163                 : 
     164             134 : OGROSMDataSource::OGROSMDataSource()
     165                 : 
     166                 : {
     167             134 :     nLayers = 0;
     168             134 :     papoLayers = NULL;
     169             134 :     pszName = NULL;
     170             134 :     bInterleavedReading = -1;
     171             134 :     poCurrentLayer = NULL;
     172             134 :     psParser = NULL;
     173             134 :     bHasParsedFirstChunk = FALSE;
     174             134 :     bStopParsing = FALSE;
     175                 : #ifdef HAVE_SQLITE_VFS
     176             134 :     pMyVFS = NULL;
     177                 : #endif
     178             134 :     hDB = NULL;
     179             134 :     hInsertNodeStmt = NULL;
     180             134 :     hInsertWayStmt = NULL;
     181             134 :     hInsertPolygonsStandaloneStmt = NULL;
     182             134 :     hDeletePolygonsStandaloneStmt = NULL;
     183             134 :     hSelectPolygonsStandaloneStmt = NULL;
     184             134 :     bHasRowInPolygonsStandalone = FALSE;
     185             134 :     nNodesInTransaction = 0;
     186             134 :     bInTransaction = FALSE;
     187             134 :     pahSelectNodeStmt = NULL;
     188             134 :     pahSelectWayStmt = NULL;
     189             134 :     pasLonLatCache = NULL;
     190             134 :     bInMemoryTmpDB = FALSE;
     191             134 :     bMustUnlink = TRUE;
     192             134 :     nMaxSizeForInMemoryDBInMB = 0;
     193             134 :     bReportAllNodes = FALSE;
     194             134 :     bReportAllWays = FALSE;
     195             134 :     bFeatureAdded = FALSE;
     196                 : 
     197             134 :     bIndexPoints = TRUE;
     198             134 :     bUsePointsIndex = TRUE;
     199             134 :     bIndexWays = TRUE;
     200             134 :     bUseWaysIndex = TRUE;
     201                 : 
     202             134 :     poResultSetLayer = NULL;
     203             134 :     bIndexPointsBackup = FALSE;
     204             134 :     bUsePointsIndexBackup = FALSE;
     205             134 :     bIndexWaysBackup = FALSE;
     206             134 :     bUseWaysIndexBackup = FALSE;
     207                 : 
     208             134 :     bIsFeatureCountEnabled = FALSE;
     209                 : 
     210             134 :     bAttributeNameLaundering = TRUE;
     211                 : 
     212             134 :     pabyWayBuffer = NULL;
     213                 : 
     214             134 :     nWaysProcessed = 0;
     215             134 :     nRelationsProcessed = 0;
     216                 : 
     217             134 :     bCustomIndexing = TRUE;
     218             134 :     bCompressNodes = FALSE;
     219                 : 
     220             134 :     bInMemoryNodesFile = FALSE;
     221             134 :     bMustUnlinkNodesFile = TRUE;
     222             134 :     fpNodes = NULL;
     223             134 :     nNodesFileSize = 0;
     224                 : 
     225             134 :     nPrevNodeId = -INT_MAX;
     226             134 :     nBucketOld = -1;
     227             134 :     nOffInBucketReducedOld = -1;
     228             134 :     pabySector = NULL;
     229             134 :     papsBuckets = NULL;
     230                 : 
     231             134 :     nReqIds = 0;
     232             134 :     panReqIds = NULL;
     233             134 :     pasLonLatArray = NULL;
     234             134 :     nUnsortedReqIds = 0;
     235             134 :     panUnsortedReqIds = NULL;
     236             134 :     nWayFeaturePairs = 0;
     237             134 :     pasWayFeaturePairs = NULL;
     238             134 :     nAccumulatedTags = 0;
     239             134 :     pasAccumulatedTags = NULL;
     240             134 :     nNonRedundantValuesLen = 0;
     241             134 :     pabyNonRedundantValues = NULL;
     242             134 :     nNextKeyIndex = 0;
     243                 : 
     244             134 :     bNeedsToSaveWayInfo = FALSE;
     245             134 : }
     246                 : 
     247                 : /************************************************************************/
     248                 : /*                          ~OGROSMDataSource()                         */
     249                 : /************************************************************************/
     250                 : 
     251             134 : OGROSMDataSource::~OGROSMDataSource()
     252                 : 
     253                 : {
     254                 :     int i;
     255             184 :     for(i=0;i<nLayers;i++)
     256              50 :         delete papoLayers[i];
     257             134 :     CPLFree(papoLayers);
     258                 : 
     259             134 :     CPLFree(pszName);
     260                 : 
     261             134 :     if( psParser != NULL )
     262              10 :         CPLDebug("OSM", "Number of bytes read in file : " CPL_FRMT_GUIB, OSM_GetBytesRead(psParser));
     263             134 :     OSM_Close(psParser);
     264                 : 
     265             134 :     CPLFree(pasLonLatCache);
     266             134 :     CPLFree(pabyWayBuffer);
     267                 : 
     268             134 :     if( hDB != NULL )
     269              10 :         CloseDB();
     270                 : 
     271                 : #ifdef HAVE_SQLITE_VFS
     272             134 :     if (pMyVFS)
     273                 :     {
     274              10 :         sqlite3_vfs_unregister(pMyVFS);
     275              10 :         CPLFree(pMyVFS->pAppData);
     276              10 :         CPLFree(pMyVFS);
     277                 :     }
     278                 : #endif
     279                 : 
     280             134 :     if( osTmpDBName.size() && bMustUnlink )
     281                 :     {
     282              10 :         const char* pszVal = CPLGetConfigOption("OSM_UNLINK_TMPFILE", "YES");
     283              10 :         if( !EQUAL(pszVal, "NOT_EVEN_AT_END") )
     284              10 :             VSIUnlink(osTmpDBName);
     285                 :     }
     286                 : 
     287             134 :     CPLFree(panReqIds);
     288             134 :     CPLFree(pasLonLatArray);
     289             134 :     CPLFree(panUnsortedReqIds);
     290                 : 
     291             134 :     for( i = 0; i < nWayFeaturePairs; i++)
     292                 :     {
     293               0 :         delete pasWayFeaturePairs[i].poFeature;
     294                 :     }
     295             134 :     CPLFree(pasWayFeaturePairs);
     296             134 :     CPLFree(pasAccumulatedTags);
     297             134 :     CPLFree(pabyNonRedundantValues);
     298                 : 
     299                 : #ifdef OSM_DEBUG
     300                 :     FILE* f;
     301                 :     f = fopen("keys.txt", "wt");
     302                 :     for(i=0;i<(int)asKeys.size();i++)
     303                 :     {
     304                 :         KeyDesc* psKD = asKeys[i];
     305                 :         fprintf(f, "%08d idx=%d %s\n",
     306                 :                 psKD->nOccurences,
     307                 :                 psKD->nKeyIndex,
     308                 :                 psKD->pszK);
     309                 :     }
     310                 :     fclose(f);
     311                 : #endif
     312                 : 
     313             146 :     for(i=0;i<(int)asKeys.size();i++)
     314                 :     {
     315              12 :         KeyDesc* psKD = asKeys[i];
     316              12 :         CPLFree(psKD->pszK);
     317              36 :         for(int j=0;j<(int)psKD->asValues.size();j++)
     318              24 :             CPLFree(psKD->asValues[j]);
     319              12 :         delete psKD;
     320                 :     }
     321                 : 
     322             134 :     if( fpNodes )
     323               9 :         VSIFCloseL(fpNodes);
     324             134 :     if( osNodesFilename.size() && bMustUnlinkNodesFile )
     325                 :     {
     326               9 :         const char* pszVal = CPLGetConfigOption("OSM_UNLINK_TMPFILE", "YES");
     327               9 :         if( !EQUAL(pszVal, "NOT_EVEN_AT_END") )
     328               9 :             VSIUnlink(osNodesFilename);
     329                 :     }
     330                 : 
     331             134 :     CPLFree(pabySector);
     332             134 :     if( papsBuckets )
     333                 :     {
     334          589833 :         for( i = 0; i < BUCKET_COUNT; i++)
     335                 :         {
     336          589824 :             if( bCompressNodes )
     337           65536 :                 CPLFree(papsBuckets[i].u.panSectorSize);
     338                 :             else
     339          524288 :                 CPLFree(papsBuckets[i].u.pabyBitmap);
     340                 :         }
     341               9 :         CPLFree(papsBuckets);
     342                 :     }
     343             134 : }
     344                 : 
     345                 : /************************************************************************/
     346                 : /*                             CloseDB()                               */
     347                 : /************************************************************************/
     348                 : 
     349              10 : void OGROSMDataSource::CloseDB()
     350                 : {
     351                 :     int i;
     352                 : 
     353              10 :     if( hInsertNodeStmt != NULL )
     354              10 :         sqlite3_finalize( hInsertNodeStmt );
     355              10 :     hInsertNodeStmt = NULL;
     356                 : 
     357              10 :     if( hInsertWayStmt != NULL )
     358              10 :         sqlite3_finalize( hInsertWayStmt );
     359              10 :     hInsertWayStmt = NULL;
     360                 : 
     361              10 :     if( hInsertPolygonsStandaloneStmt != NULL )
     362              10 :         sqlite3_finalize( hInsertPolygonsStandaloneStmt );
     363              10 :     hInsertPolygonsStandaloneStmt = NULL;
     364                 : 
     365              10 :     if( hDeletePolygonsStandaloneStmt != NULL )
     366              10 :         sqlite3_finalize( hDeletePolygonsStandaloneStmt );
     367              10 :     hDeletePolygonsStandaloneStmt = NULL;
     368                 : 
     369              10 :     if( hSelectPolygonsStandaloneStmt != NULL )
     370              10 :         sqlite3_finalize( hSelectPolygonsStandaloneStmt );
     371              10 :     hSelectPolygonsStandaloneStmt = NULL;
     372                 : 
     373              10 :     if( pahSelectNodeStmt != NULL )
     374                 :     {
     375            2010 :         for(i = 0; i < LIMIT_IDS_PER_REQUEST; i++)
     376                 :         {
     377            2000 :             if( pahSelectNodeStmt[i] != NULL )
     378            2000 :                 sqlite3_finalize( pahSelectNodeStmt[i] );
     379                 :         }
     380              10 :         CPLFree(pahSelectNodeStmt);
     381              10 :         pahSelectNodeStmt = NULL;
     382                 :     }
     383                 : 
     384              10 :     if( pahSelectWayStmt != NULL )
     385                 :     {
     386            2010 :         for(i = 0; i < LIMIT_IDS_PER_REQUEST; i++)
     387                 :         {
     388            2000 :             if( pahSelectWayStmt[i] != NULL )
     389            2000 :                 sqlite3_finalize( pahSelectWayStmt[i] );
     390                 :         }
     391              10 :         CPLFree(pahSelectWayStmt);
     392              10 :         pahSelectWayStmt = NULL;
     393                 :     }
     394                 : 
     395              10 :     if( bInTransaction )
     396              10 :         CommitTransaction();
     397                 : 
     398              10 :     sqlite3_close(hDB);
     399              10 :     hDB = NULL;
     400              10 : }
     401                 : 
     402                 : /************************************************************************/
     403                 : /*                             IndexPoint()                             */
     404                 : /************************************************************************/
     405                 : 
     406                 : static const GByte abyBitsCount[] = {
     407                 : 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
     408                 : 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
     409                 : 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
     410                 : 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
     411                 : 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
     412                 : 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
     413                 : 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
     414                 : 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
     415                 : 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
     416                 : 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
     417                 : 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
     418                 : 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
     419                 : 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
     420                 : 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
     421                 : 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
     422                 : 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
     423                 : };
     424                 : 
     425             180 : int OGROSMDataSource::IndexPoint(OSMNode* psNode)
     426                 : {
     427             180 :     if( !bIndexPoints )
     428              54 :         return TRUE;
     429                 : 
     430             126 :     if( bCustomIndexing)
     431             117 :         return IndexPointCustom(psNode);
     432                 :     else
     433               9 :         return IndexPointSQLite(psNode);
     434                 : }
     435                 : 
     436                 : /************************************************************************/
     437                 : /*                          IndexPointSQLite()                          */
     438                 : /************************************************************************/
     439                 : 
     440               9 : int OGROSMDataSource::IndexPointSQLite(OSMNode* psNode)
     441                 : {
     442               9 :     sqlite3_bind_int64( hInsertNodeStmt, 1, psNode->nID );
     443                 : 
     444                 :     LonLat sLonLat;
     445               9 :     sLonLat.nLon = DBL_TO_INT(psNode->dfLon);
     446               9 :     sLonLat.nLat = DBL_TO_INT(psNode->dfLat);
     447                 : 
     448               9 :     sqlite3_bind_blob( hInsertNodeStmt, 2, &sLonLat, sizeof(sLonLat), SQLITE_STATIC );
     449                 : 
     450               9 :     int rc = sqlite3_step( hInsertNodeStmt );
     451               9 :     sqlite3_reset( hInsertNodeStmt );
     452               9 :     if( !(rc == SQLITE_OK || rc == SQLITE_DONE) )
     453                 :     {
     454                 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed inserting node " CPL_FRMT_GIB ": %s",
     455               0 :             psNode->nID, sqlite3_errmsg(hDB));
     456                 :     }
     457                 : 
     458               9 :     return TRUE;
     459                 : }
     460                 : 
     461                 : /************************************************************************/
     462                 : /*                           FlushCurrentSector()                       */
     463                 : /************************************************************************/
     464                 : 
     465              12 : int OGROSMDataSource::FlushCurrentSector()
     466                 : {
     467                 : #ifndef FAKE_LOOKUP_NODES
     468              12 :     if( bCompressNodes )
     469               1 :         return FlushCurrentSectorCompressedCase();
     470                 :     else
     471              11 :         return FlushCurrentSectorNonCompressedCase();
     472                 : #else
     473                 :     return TRUE;
     474                 : #endif
     475                 : }
     476                 : 
     477                 : /************************************************************************/
     478                 : /*                     FlushCurrentSectorCompressedCase()               */
     479                 : /************************************************************************/
     480                 : 
     481               1 : int OGROSMDataSource::FlushCurrentSectorCompressedCase()
     482                 : {
     483                 :     GByte abyOutBuffer[2 * SECTOR_SIZE];
     484               1 :     GByte* pabyOut = abyOutBuffer;
     485               1 :     LonLat* pasLonLatIn = (LonLat*)pabySector;
     486               1 :     int nLastLon = 0, nLastLat = 0;
     487               1 :     int bLastValid = FALSE;
     488                 :     int i;
     489                 : 
     490                 :     CPLAssert((NODE_PER_SECTOR % 8) == 0);
     491               1 :     memset(abyOutBuffer, 0, NODE_PER_SECTOR / 8);
     492               1 :     pabyOut += NODE_PER_SECTOR / 8;
     493              65 :     for(i = 0; i < NODE_PER_SECTOR; i++)
     494                 :     {
     495              64 :         if( pasLonLatIn[i].nLon || pasLonLatIn[i].nLat )
     496                 :         {
     497               9 :             abyOutBuffer[i >> 3] |= (1 << (i % 8));
     498               9 :             if( bLastValid )
     499                 :             {
     500               8 :                 GIntBig nDiff64Lon = (GIntBig)pasLonLatIn[i].nLon - (GIntBig)nLastLon;
     501               8 :                 GIntBig nDiff64Lat = pasLonLatIn[i].nLat - nLastLat;
     502               8 :                 WriteVarSInt64(nDiff64Lon, &pabyOut);
     503               8 :                 WriteVarSInt64(nDiff64Lat, &pabyOut);
     504                 :             }
     505                 :             else
     506                 :             {
     507               1 :                 memcpy(pabyOut, &pasLonLatIn[i], sizeof(LonLat));
     508               1 :                 pabyOut += sizeof(LonLat);
     509                 :             }
     510               9 :             bLastValid = TRUE;
     511                 : 
     512               9 :             nLastLon = pasLonLatIn[i].nLon;
     513               9 :             nLastLat = pasLonLatIn[i].nLat;
     514                 :         }
     515                 :     }
     516                 : 
     517               1 :     size_t nCompressSize = (size_t)(pabyOut - abyOutBuffer);
     518               1 :     CPLAssert(nCompressSize < sizeof(abyOutBuffer) - 1);
     519               1 :     abyOutBuffer[nCompressSize] = 0;
     520                 : 
     521               1 :     nCompressSize = ROUND_COMPRESS_SIZE(nCompressSize);
     522                 :     GByte* pabyToWrite;
     523               1 :     if(nCompressSize >= SECTOR_SIZE)
     524                 :     {
     525               0 :         nCompressSize = SECTOR_SIZE;
     526               0 :         pabyToWrite = pabySector;
     527                 :     }
     528                 :     else
     529               1 :         pabyToWrite = abyOutBuffer;
     530                 : 
     531               1 :     if( VSIFWriteL(pabyToWrite, 1, nCompressSize, fpNodes) == nCompressSize )
     532                 :     {
     533               1 :         memset(pabySector, 0, SECTOR_SIZE);
     534               1 :         nNodesFileSize += nCompressSize;
     535                 : 
     536               1 :         Bucket* psBucket = &papsBuckets[nBucketOld];
     537               1 :         psBucket->u.panSectorSize[nOffInBucketReducedOld] =
     538               1 :                                     COMPRESS_SIZE_TO_BYTE(nCompressSize);
     539                 : 
     540               1 :         return TRUE;
     541                 :     }
     542                 : 
     543               0 :     return FALSE;
     544                 : }
     545                 : 
     546                 : /************************************************************************/
     547                 : /*                   FlushCurrentSectorNonCompressedCase()              */
     548                 : /************************************************************************/
     549                 : 
     550              11 : int OGROSMDataSource::FlushCurrentSectorNonCompressedCase()
     551                 : {
     552              11 :    if( VSIFWriteL(pabySector, 1, SECTOR_SIZE, fpNodes) == SECTOR_SIZE )
     553                 :     {
     554              11 :         memset(pabySector, 0, SECTOR_SIZE);
     555              11 :         nNodesFileSize += SECTOR_SIZE;
     556              11 :         return TRUE;
     557                 :     }
     558                 : 
     559               0 :     return FALSE;
     560                 : }
     561                 : 
     562                 : /************************************************************************/
     563                 : /*                          IndexPointCustom()                          */
     564                 : /************************************************************************/
     565                 : 
     566             117 : int OGROSMDataSource::IndexPointCustom(OSMNode* psNode)
     567                 : {
     568             117 :     if( psNode->nID <= nPrevNodeId)
     569                 :     {
     570                 :         CPLError(CE_Failure, CPLE_AppDefined,
     571               0 :                  "Non increasing node id. Use OSM_USE_CUSTOM_INDEXING=NO");
     572               0 :         bStopParsing = TRUE;
     573               0 :         return FALSE;
     574                 :     }
     575             117 :     if( !VALID_ID_FOR_CUSTOM_INDEXING(psNode->nID) )
     576                 :     {
     577                 :         CPLError(CE_Failure, CPLE_AppDefined,
     578                 :                  "Unsupported node id value (" CPL_FRMT_GIB "). Use OSM_USE_CUSTOM_INDEXING=NO",
     579               0 :                  psNode->nID);
     580               0 :         bStopParsing = TRUE;
     581               0 :         return FALSE;
     582                 :     }
     583                 : 
     584             117 :     int nBucket = (int)(psNode->nID / NODE_PER_BUCKET);
     585             117 :     int nOffInBucket = psNode->nID % NODE_PER_BUCKET;
     586             117 :     int nOffInBucketReduced = nOffInBucket >> NODE_PER_SECTOR_SHIFT;
     587             117 :     int nOffInBucketReducedRemainer = nOffInBucket & ((1 << NODE_PER_SECTOR_SHIFT) - 1);
     588             117 :     Bucket* psBucket = &papsBuckets[nBucket];
     589                 : 
     590             117 :     if( !bCompressNodes )
     591                 :     {
     592             108 :         int nBitmapIndex = nOffInBucketReduced / 8;
     593             108 :         int nBitmapRemainer = nOffInBucketReduced % 8;
     594             108 :         psBucket->u.pabyBitmap[nBitmapIndex] |= (1 << nBitmapRemainer);
     595                 :     }
     596                 : 
     597             117 :     if( nBucket != nBucketOld )
     598                 :     {
     599              13 :         CPLAssert(nBucket > nBucketOld);
     600              13 :         if( nBucketOld >= 0 )
     601                 :         {
     602               0 :             if( !FlushCurrentSector() )
     603                 :             {
     604               0 :                 bStopParsing = TRUE;
     605               0 :                 return FALSE;
     606                 :             }
     607                 :         }
     608              13 :         nBucketOld = nBucket;
     609              13 :         nOffInBucketReducedOld = nOffInBucketReduced;
     610              13 :         CPLAssert(psBucket->nOff == -1);
     611              13 :         psBucket->nOff = VSIFTellL(fpNodes);
     612                 :     }
     613             104 :     else if( nOffInBucketReduced != nOffInBucketReducedOld )
     614                 :     {
     615               0 :         CPLAssert(nOffInBucketReduced > nOffInBucketReducedOld);
     616               0 :         if( !FlushCurrentSector() )
     617                 :         {
     618               0 :             bStopParsing = TRUE;
     619               0 :             return FALSE;
     620                 :         }
     621               0 :         nOffInBucketReducedOld = nOffInBucketReduced;
     622                 :     }
     623                 : 
     624             117 :     LonLat* psLonLat = (LonLat*)(pabySector + sizeof(LonLat) * nOffInBucketReducedRemainer);
     625             117 :     psLonLat->nLon = DBL_TO_INT(psNode->dfLon);
     626             117 :     psLonLat->nLat = DBL_TO_INT(psNode->dfLat);
     627                 : 
     628             117 :     nPrevNodeId = psNode->nID;
     629                 : 
     630             117 :     return TRUE;
     631                 : }
     632                 : 
     633                 : /************************************************************************/
     634                 : /*                             NotifyNodes()                            */
     635                 : /************************************************************************/
     636                 : 
     637              28 : void OGROSMDataSource::NotifyNodes(unsigned int nNodes, OSMNode* pasNodes)
     638                 : {
     639                 :     unsigned int i;
     640                 : 
     641                 :     const OGREnvelope* psEnvelope =
     642              28 :         papoLayers[IDX_LYR_POINTS]->GetSpatialFilterEnvelope();
     643                 : 
     644             208 :     for(i = 0; i < nNodes; i++)
     645                 :     {
     646                 :         /* If the point doesn't fit into the envelope of the spatial filter */
     647                 :         /* then skip it */
     648             180 :         if( psEnvelope != NULL &&
     649               0 :             !(pasNodes[i].dfLon >= psEnvelope->MinX &&
     650               0 :               pasNodes[i].dfLon <= psEnvelope->MaxX &&
     651               0 :               pasNodes[i].dfLat >= psEnvelope->MinY &&
     652               0 :               pasNodes[i].dfLat <= psEnvelope->MaxY) )
     653               0 :             continue;
     654                 : 
     655             180 :         if( !IndexPoint(&pasNodes[i]) )
     656               0 :             break;
     657                 : 
     658             180 :         if( !papoLayers[IDX_LYR_POINTS]->IsUserInterested() )
     659              81 :             continue;
     660                 : 
     661                 :         unsigned int j;
     662              99 :         int bInterestingTag = bReportAllNodes;
     663              99 :         OSMTag* pasTags = pasNodes[i].pasTags;
     664                 : 
     665              99 :         if( !bReportAllNodes )
     666                 :         {
     667              99 :             for(j = 0; j < pasNodes[i].nTags; j++)
     668                 :             {
     669              11 :                 const char* pszK = pasTags[j].pszK;
     670              11 :                 if( papoLayers[IDX_LYR_POINTS]->IsSignificantKey(pszK) )
     671                 :                 {
     672              11 :                     bInterestingTag = TRUE;
     673              11 :                     break;
     674                 :                 }
     675                 :             }
     676                 :         }
     677                 : 
     678              99 :         if( bInterestingTag )
     679                 :         {
     680                 :             OGRFeature* poFeature = new OGRFeature(
     681              11 :                         papoLayers[IDX_LYR_POINTS]->GetLayerDefn());
     682                 : 
     683                 :             poFeature->SetGeometryDirectly(
     684              22 :                 new OGRPoint(pasNodes[i].dfLon, pasNodes[i].dfLat));
     685                 : 
     686              11 :             papoLayers[IDX_LYR_POINTS]->SetFieldsFromTags(
     687              22 :                 poFeature, pasNodes[i].nID, FALSE, pasNodes[i].nTags, pasTags, &pasNodes[i].sInfo );
     688                 : 
     689              11 :             int bFilteredOut = FALSE;
     690              11 :             if( !papoLayers[IDX_LYR_POINTS]->AddFeature(poFeature, FALSE, &bFilteredOut) )
     691                 :             {
     692               0 :                 bStopParsing = TRUE;
     693               0 :                 break;
     694                 :             }
     695              11 :             else if (!bFilteredOut)
     696              10 :                 bFeatureAdded = TRUE;
     697                 :         }
     698                 :     }
     699              28 : }
     700                 : 
     701              28 : static void OGROSMNotifyNodes (unsigned int nNodes, OSMNode* pasNodes,
     702                 :                                OSMContext* psOSMContext, void* user_data)
     703                 : {
     704              28 :     ((OGROSMDataSource*) user_data)->NotifyNodes(nNodes, pasNodes);
     705              28 : }
     706                 : 
     707                 : /************************************************************************/
     708                 : /*                            LookupNodes()                             */
     709                 : /************************************************************************/
     710                 : 
     711              15 : void OGROSMDataSource::LookupNodes( )
     712                 : {
     713              15 :     if( bCustomIndexing )
     714              14 :         LookupNodesCustom();
     715                 :     else
     716               1 :         LookupNodesSQLite();
     717              15 : }
     718                 : 
     719                 : /************************************************************************/
     720                 : /*                           LookupNodesSQLite()                        */
     721                 : /************************************************************************/
     722                 : 
     723               1 : void OGROSMDataSource::LookupNodesSQLite( )
     724                 : {
     725                 :     unsigned int iCur;
     726                 :     unsigned int i;
     727                 : 
     728               1 :     CPLAssert(nUnsortedReqIds <= MAX_ACCUMULATED_NODES);
     729                 : 
     730               1 :     nReqIds = 0;
     731              27 :     for(i = 0; i < nUnsortedReqIds; i++)
     732                 :     {
     733              26 :         GIntBig id = panUnsortedReqIds[i];
     734              26 :         panReqIds[nReqIds++] = id;
     735                 :     }
     736                 : 
     737               1 :     std::sort(panReqIds, panReqIds + nReqIds);
     738                 : 
     739                 :     /* Remove duplicates */
     740               1 :     unsigned int j = 0;
     741              27 :     for(i = 0; i < nReqIds; i++)
     742                 :     {
     743              26 :         if (!(i > 0 && panReqIds[i] == panReqIds[i-1]))
     744              12 :             panReqIds[j++] = panReqIds[i];
     745                 :     }
     746               1 :     nReqIds = j;
     747                 : 
     748               1 :     iCur = 0;
     749               1 :     j = 0;
     750               3 :     while( iCur < nReqIds )
     751                 :     {
     752               1 :         unsigned int nToQuery = nReqIds - iCur;
     753               1 :         if( nToQuery > LIMIT_IDS_PER_REQUEST )
     754               0 :             nToQuery = LIMIT_IDS_PER_REQUEST;
     755                 : 
     756               1 :         sqlite3_stmt* hStmt = pahSelectNodeStmt[nToQuery-1];
     757              13 :         for(i=iCur;i<iCur + nToQuery;i++)
     758                 :         {
     759              12 :              sqlite3_bind_int64( hStmt, i - iCur +1, panReqIds[i] );
     760                 :         }
     761               1 :         iCur += nToQuery;
     762                 : 
     763              10 :         while( sqlite3_step(hStmt) == SQLITE_ROW )
     764                 :         {
     765               8 :             GIntBig id = sqlite3_column_int(hStmt, 0);
     766               8 :             LonLat* psLonLat = (LonLat*)sqlite3_column_blob(hStmt, 1);
     767                 : 
     768               8 :             panReqIds[j] = id;
     769               8 :             pasLonLatArray[j].nLon = psLonLat->nLon;
     770               8 :             pasLonLatArray[j].nLat = psLonLat->nLat;
     771               8 :             j++;
     772                 :         }
     773                 : 
     774               1 :         sqlite3_reset(hStmt);
     775                 :     }
     776               1 :     nReqIds = j;
     777               1 : }
     778                 : 
     779                 : /************************************************************************/
     780                 : /*                            ReadVarSInt64()                           */
     781                 : /************************************************************************/
     782                 : 
     783             352 : static GIntBig ReadVarSInt64(GByte** ppabyPtr)
     784                 : {
     785             352 :     GIntBig nSVal64 = ReadVarInt64(ppabyPtr);
     786             352 :     GIntBig nDiff64 = ((nSVal64 & 1) == 0) ? (((GUIntBig)nSVal64) >> 1) : -(((GUIntBig)nSVal64) >> 1)-1;
     787             352 :     return nDiff64;
     788                 : }
     789                 : 
     790                 : /************************************************************************/
     791                 : /*                           DecompressSector()                         */
     792                 : /************************************************************************/
     793                 : 
     794               1 : static int DecompressSector(GByte* pabyIn, int nSectorSize, GByte* pabyOut)
     795                 : {
     796               1 :     GByte* pabyPtr = pabyIn;
     797               1 :     LonLat* pasLonLatOut = (LonLat*) pabyOut;
     798               1 :     int nLastLon = 0, nLastLat = 0;
     799               1 :     int bLastValid = FALSE;
     800                 :     int i;
     801                 : 
     802               1 :     pabyPtr += NODE_PER_SECTOR / 8;
     803              65 :     for(i = 0; i < NODE_PER_SECTOR; i++)
     804                 :     {
     805              64 :         if( pabyIn[i >> 3] & (1 << (i % 8)) )
     806                 :         {
     807               9 :             if( bLastValid )
     808                 :             {
     809               8 :                 pasLonLatOut[i].nLon = nLastLon + ReadVarSInt64(&pabyPtr);
     810               8 :                 pasLonLatOut[i].nLat = nLastLat + ReadVarSInt64(&pabyPtr);
     811                 :             }
     812                 :             else
     813                 :             {
     814               1 :                 bLastValid = TRUE;
     815               1 :                 memcpy(&(pasLonLatOut[i]), pabyPtr, sizeof(LonLat));
     816               1 :                 pabyPtr += sizeof(LonLat);
     817                 :             }
     818                 : 
     819               9 :             nLastLon = pasLonLatOut[i].nLon;
     820               9 :             nLastLat = pasLonLatOut[i].nLat;
     821                 :         }
     822                 :         else
     823                 :         {
     824              55 :             pasLonLatOut[i].nLon = 0;
     825              55 :             pasLonLatOut[i].nLat = 0;
     826                 :         }
     827                 :     }
     828                 : 
     829               1 :     int nRead = (int)(pabyPtr - pabyIn);
     830               1 :     nRead = ROUND_COMPRESS_SIZE(nRead);
     831               1 :     return( nRead == nSectorSize );
     832                 : }
     833                 : 
     834                 : /************************************************************************/
     835                 : /*                           LookupNodesCustom()                        */
     836                 : /************************************************************************/
     837                 : 
     838              14 : void OGROSMDataSource::LookupNodesCustom( )
     839                 : {
     840              14 :     nReqIds = 0;
     841                 : 
     842              14 :     if( nBucketOld >= 0 )
     843                 :     {
     844              12 :         if( !FlushCurrentSector() )
     845                 :         {
     846               0 :             bStopParsing = TRUE;
     847               0 :             return;
     848                 :         }
     849                 : 
     850              12 :         nBucketOld = -1;
     851                 :     }
     852                 : 
     853                 :     unsigned int i;
     854                 : 
     855              14 :     CPLAssert(nUnsortedReqIds <= MAX_ACCUMULATED_NODES);
     856                 : 
     857             290 :     for(i = 0; i < nUnsortedReqIds; i++)
     858                 :     {
     859             276 :         GIntBig id = panUnsortedReqIds[i];
     860                 : 
     861             276 :         if( !VALID_ID_FOR_CUSTOM_INDEXING(id) )
     862               0 :             continue;
     863                 : 
     864             276 :         int nBucket = (int)(id / NODE_PER_BUCKET);
     865             276 :         int nOffInBucket = id % NODE_PER_BUCKET;
     866             276 :         int nOffInBucketReduced = nOffInBucket >> NODE_PER_SECTOR_SHIFT;
     867             276 :         Bucket* psBucket = &papsBuckets[nBucket];
     868                 : 
     869             276 :         if( bCompressNodes )
     870                 :         {
     871              26 :             if( !(psBucket->u.panSectorSize[nOffInBucketReduced]) )
     872               5 :                 continue;
     873                 :         }
     874                 :         else
     875                 :         {
     876             250 :             int nBitmapIndex = nOffInBucketReduced / 8;
     877             250 :             int nBitmapRemainer = nOffInBucketReduced % 8;
     878             250 :             if( !(psBucket->u.pabyBitmap[nBitmapIndex] & (1 << nBitmapRemainer)) )
     879              50 :                 continue;
     880                 :         }
     881                 : 
     882             221 :         panReqIds[nReqIds++] = id;
     883                 :     }
     884                 : 
     885              14 :     std::sort(panReqIds, panReqIds + nReqIds);
     886                 : 
     887                 :     /* Remove duplicates */
     888              14 :     unsigned int j = 0;
     889             235 :     for(i = 0; i < nReqIds; i++)
     890                 :     {
     891             221 :         if (!(i > 0 && panReqIds[i] == panReqIds[i-1]))
     892              88 :             panReqIds[j++] = panReqIds[i];
     893                 :     }
     894              14 :     nReqIds = j;
     895                 : 
     896                 : #ifdef FAKE_LOOKUP_NODES
     897                 :     for(i = 0; i < nReqIds; i++)
     898                 :     {
     899                 :         pasLonLatArray[i].nLon = 0;
     900                 :         pasLonLatArray[i].nLat = 0;
     901                 :     }
     902                 : #else
     903              14 :     if( bCompressNodes )
     904               1 :         LookupNodesCustomCompressedCase();
     905                 :     else
     906              13 :         LookupNodesCustomNonCompressedCase();
     907                 : #endif
     908                 : }
     909                 : 
     910                 : /************************************************************************/
     911                 : /*                      LookupNodesCustomCompressedCase()               */
     912                 : /************************************************************************/
     913                 : 
     914               1 : void OGROSMDataSource::LookupNodesCustomCompressedCase()
     915                 : {
     916                 :     unsigned int i;
     917               1 :     unsigned int j = 0;
     918                 : #define SECURITY_MARGIN     (8 + 8 + 2 * NODE_PER_SECTOR)
     919                 :     GByte abyRawSector[SECTOR_SIZE + SECURITY_MARGIN];
     920               1 :     memset(abyRawSector + SECTOR_SIZE, 0, SECURITY_MARGIN);
     921                 : 
     922               1 :     int nBucketOld = -1;
     923               1 :     int nOffInBucketReducedOld = -1;
     924               1 :     int k = 0;
     925               1 :     int nOffFromBucketStart = 0;
     926                 : 
     927               9 :     for(i = 0; i < nReqIds; i++)
     928                 :     {
     929               8 :         GIntBig id = panReqIds[i];
     930                 : 
     931               8 :         int nBucket = (int)(id / NODE_PER_BUCKET);
     932               8 :         int nOffInBucket = id % NODE_PER_BUCKET;
     933               8 :         int nOffInBucketReduced = nOffInBucket >> NODE_PER_SECTOR_SHIFT;
     934               8 :         int nOffInBucketReducedRemainer = nOffInBucket & ((1 << NODE_PER_SECTOR_SHIFT) - 1);
     935                 : 
     936               8 :         if( nBucket != nBucketOld )
     937                 :         {
     938               1 :             nOffInBucketReducedOld = -1;
     939               1 :             k = 0;
     940               1 :             nOffFromBucketStart = 0;
     941                 :         }
     942                 : 
     943               8 :         if ( nOffInBucketReduced != nOffInBucketReducedOld )
     944                 :         {
     945               1 :             Bucket* psBucket = &papsBuckets[nBucket];
     946               1 :             int nSectorSize = COMPRESS_SIZE_FROM_BYTE(psBucket->u.panSectorSize[nOffInBucketReduced]);
     947                 : 
     948                 :             /* If we stay in the same bucket, we can reuse the previously */
     949                 :             /* computed offset, instead of starting from bucket start */
     950               1 :             for(; k < nOffInBucketReduced; k++)
     951                 :             {
     952               0 :                 if( psBucket->u.panSectorSize[k] )
     953               0 :                     nOffFromBucketStart += COMPRESS_SIZE_FROM_BYTE(psBucket->u.panSectorSize[k]);
     954                 :             }
     955                 : 
     956               1 :             VSIFSeekL(fpNodes, psBucket->nOff + nOffFromBucketStart, SEEK_SET);
     957               1 :             if( nSectorSize == SECTOR_SIZE )
     958                 :             {
     959               0 :                 if( VSIFReadL(pabySector, 1, SECTOR_SIZE, fpNodes) != SECTOR_SIZE )
     960                 :                 {
     961                 :                     CPLError(CE_Failure,  CPLE_AppDefined,
     962               0 :                             "Cannot read node " CPL_FRMT_GIB, id);
     963               0 :                     continue;
     964                 :                     // FIXME ?
     965                 :                 }
     966                 :             }
     967                 :             else
     968                 :             {
     969               1 :                 if( (int)VSIFReadL(abyRawSector, 1, nSectorSize, fpNodes) != nSectorSize )
     970                 :                 {
     971                 :                     CPLError(CE_Failure,  CPLE_AppDefined,
     972               0 :                             "Cannot read sector for node " CPL_FRMT_GIB, id);
     973               0 :                     continue;
     974                 :                     // FIXME ?
     975                 :                 }
     976               1 :                 abyRawSector[nSectorSize] = 0;
     977                 : 
     978               1 :                 if( !DecompressSector(abyRawSector, nSectorSize, pabySector) )
     979                 :                 {
     980                 :                     CPLError(CE_Failure,  CPLE_AppDefined,
     981               0 :                             "Error while uncompressing sector for node " CPL_FRMT_GIB, id);
     982               0 :                     continue;
     983                 :                     // FIXME ?
     984                 :                 }
     985                 :             }
     986                 : 
     987               1 :             nBucketOld = nBucket;
     988               1 :             nOffInBucketReducedOld = nOffInBucketReduced;
     989                 :         }
     990                 : 
     991               8 :         panReqIds[j] = id;
     992                 :         memcpy(pasLonLatArray + j,
     993                 :                pabySector + nOffInBucketReducedRemainer * sizeof(LonLat),
     994               8 :                sizeof(LonLat));
     995                 : 
     996               8 :         if( pasLonLatArray[j].nLon || pasLonLatArray[j].nLat )
     997               8 :             j++;
     998                 :     }
     999               1 :     nReqIds = j;
    1000               1 : }
    1001                 : 
    1002                 : /************************************************************************/
    1003                 : /*                    LookupNodesCustomNonCompressedCase()              */
    1004                 : /************************************************************************/
    1005                 : 
    1006              13 : void OGROSMDataSource::LookupNodesCustomNonCompressedCase()
    1007                 : {
    1008                 :     unsigned int i;
    1009              13 :     unsigned int j = 0;
    1010                 : 
    1011              93 :     for(i = 0; i < nReqIds; i++)
    1012                 :     {
    1013              80 :         GIntBig id = panReqIds[i];
    1014                 : 
    1015              80 :         int nBucket = (int)(id / NODE_PER_BUCKET);
    1016              80 :         int nOffInBucket = id % NODE_PER_BUCKET;
    1017              80 :         int nOffInBucketReduced = nOffInBucket >> NODE_PER_SECTOR_SHIFT;
    1018              80 :         int nOffInBucketReducedRemainer = nOffInBucket & ((1 << NODE_PER_SECTOR_SHIFT) - 1);
    1019                 : 
    1020              80 :         int nBitmapIndex = nOffInBucketReduced / 8;
    1021              80 :         int nBitmapRemainer = nOffInBucketReduced % 8;
    1022              80 :         Bucket* psBucket = &papsBuckets[nBucket];
    1023                 : 
    1024                 :         int k;
    1025              80 :         int nSector = 0;
    1026              80 :         for(k = 0; k < nBitmapIndex; k++)
    1027               0 :             nSector += abyBitsCount[psBucket->u.pabyBitmap[k]];
    1028              80 :         if (nBitmapRemainer)
    1029               0 :             nSector += abyBitsCount[psBucket->u.pabyBitmap[nBitmapIndex] & ((1 << nBitmapRemainer) - 1)];
    1030                 : 
    1031              80 :         VSIFSeekL(fpNodes, psBucket->nOff + nSector * SECTOR_SIZE + nOffInBucketReducedRemainer * sizeof(LonLat), SEEK_SET);
    1032              80 :         if( VSIFReadL(pasLonLatArray + j, 1, sizeof(LonLat), fpNodes) != sizeof(LonLat) )
    1033                 :         {
    1034                 :             CPLError(CE_Failure,  CPLE_AppDefined,
    1035               0 :                      "Cannot read node " CPL_FRMT_GIB, id);
    1036                 :             // FIXME ?
    1037                 :         }
    1038                 :         else
    1039                 :         {
    1040              80 :             panReqIds[j] = id;
    1041              80 :             if( pasLonLatArray[j].nLon || pasLonLatArray[j].nLat )
    1042              80 :                 j++;
    1043                 :         }
    1044                 :     }
    1045              13 :     nReqIds = j;
    1046              13 : }
    1047                 : 
    1048                 : /************************************************************************/
    1049                 : /*                            WriteVarInt()                             */
    1050                 : /************************************************************************/
    1051                 : 
    1052              36 : static void WriteVarInt(unsigned int nVal, GByte** ppabyData)
    1053                 : {
    1054              36 :     GByte* pabyData = *ppabyData;
    1055               0 :     while(TRUE)
    1056                 :     {
    1057              36 :         if( (nVal & (~0x7f)) == 0 )
    1058                 :         {
    1059              36 :             *pabyData = (GByte)nVal;
    1060              36 :             *ppabyData = pabyData + 1;
    1061                 :             return;
    1062                 :         }
    1063                 : 
    1064               0 :         *pabyData = 0x80 | (GByte)(nVal & 0x7f);
    1065               0 :         nVal >>= 7;
    1066               0 :         pabyData ++;
    1067                 :     }
    1068                 : }
    1069                 : 
    1070                 : /************************************************************************/
    1071                 : /*                           WriteVarInt64()                            */
    1072                 : /************************************************************************/
    1073                 : 
    1074               0 : static void WriteVarInt64(GUIntBig nVal, GByte** ppabyData)
    1075                 : {
    1076               0 :     GByte* pabyData = *ppabyData;
    1077               0 :     while(TRUE)
    1078                 :     {
    1079               0 :         if( (nVal & (~0x7f)) == 0 )
    1080                 :         {
    1081               0 :             *pabyData = (GByte)nVal;
    1082               0 :             *ppabyData = pabyData + 1;
    1083                 :             return;
    1084                 :         }
    1085                 : 
    1086               0 :         *pabyData = 0x80 | (GByte)(nVal & 0x7f);
    1087               0 :         nVal >>= 7;
    1088               0 :         pabyData ++;
    1089                 :     }
    1090                 : }
    1091                 : 
    1092                 : /************************************************************************/
    1093                 : /*                           WriteVarSInt64()                           */
    1094                 : /************************************************************************/
    1095                 : 
    1096             412 : static void WriteVarSInt64(GIntBig nSVal, GByte** ppabyData)
    1097                 : {
    1098                 :     GIntBig nVal;
    1099             412 :     if( nSVal >= 0 )
    1100             319 :         nVal = nSVal << 1;
    1101                 :     else
    1102              93 :         nVal = ((-1-nSVal) << 1) + 1;
    1103                 : 
    1104             412 :     GByte* pabyData = *ppabyData;
    1105             645 :     while(TRUE)
    1106                 :     {
    1107            1057 :         if( (nVal & (~0x7f)) == 0 )
    1108                 :         {
    1109             412 :             *pabyData = (GByte)nVal;
    1110             412 :             *ppabyData = pabyData + 1;
    1111                 :             return;
    1112                 :         }
    1113                 : 
    1114             645 :         *pabyData = 0x80 | (GByte)(nVal & 0x7f);
    1115             645 :         nVal >>= 7;
    1116             645 :         pabyData ++;
    1117                 :     }
    1118                 : }
    1119                 : 
    1120                 : /************************************************************************/
    1121                 : /*                             CompressWay()                            */
    1122                 : /************************************************************************/
    1123                 : 
    1124              66 : int OGROSMDataSource::CompressWay ( unsigned int nTags, IndexedKVP* pasTags,
    1125                 :                                     int nPoints, LonLat* pasLonLatPairs,
    1126                 :                                     OSMInfo* psInfo,
    1127                 :                                     GByte* pabyCompressedWay )
    1128                 : {
    1129              66 :     GByte* pabyPtr = pabyCompressedWay;
    1130              66 :     pabyPtr ++;
    1131                 : 
    1132              66 :     int nTagCount = 0;
    1133              66 :     CPLAssert(nTags < MAX_COUNT_FOR_TAGS_IN_WAY);
    1134              84 :     for(unsigned int iTag = 0; iTag < nTags; iTag++)
    1135                 :     {
    1136              18 :         if ((int)(pabyPtr - pabyCompressedWay) + 2 >= MAX_SIZE_FOR_TAGS_IN_WAY)
    1137                 :         {
    1138               0 :             break;
    1139                 :         }
    1140                 : 
    1141              18 :         WriteVarInt(pasTags[iTag].nKeyIndex, &pabyPtr);
    1142                 : 
    1143                 :         /* to fit in 2 bytes, the theoretical limit would be 127 * 128 + 127 */
    1144              18 :         if( pasTags[iTag].bVIsIndex )
    1145                 :         {
    1146              18 :             if ((int)(pabyPtr - pabyCompressedWay) + 2 >= MAX_SIZE_FOR_TAGS_IN_WAY)
    1147                 :             {
    1148               0 :                 break;
    1149                 :             }
    1150                 : 
    1151              18 :             WriteVarInt(pasTags[iTag].u.nValueIndex, &pabyPtr);
    1152                 :         }
    1153                 :         else
    1154                 :         {
    1155                 :             const char* pszV = (const char*)pabyNonRedundantValues +
    1156               0 :                 pasTags[iTag].u.nOffsetInpabyNonRedundantValues;
    1157                 : 
    1158               0 :             int nLenV = strlen(pszV) + 1;
    1159               0 :             if ((int)(pabyPtr - pabyCompressedWay) + 2 + nLenV >= MAX_SIZE_FOR_TAGS_IN_WAY)
    1160                 :             {
    1161               0 :                 break;
    1162                 :             }
    1163                 : 
    1164               0 :             WriteVarInt(0, &pabyPtr);
    1165                 : 
    1166               0 :             memcpy(pabyPtr, pszV, nLenV);
    1167               0 :             pabyPtr += nLenV;
    1168                 :         }
    1169                 : 
    1170              18 :         nTagCount ++;
    1171                 :     }
    1172                 : 
    1173              66 :     pabyCompressedWay[0] = (GByte) nTagCount;
    1174                 : 
    1175              66 :     if( bNeedsToSaveWayInfo )
    1176                 :     {
    1177               0 :         if( psInfo != NULL )
    1178                 :         {
    1179               0 :             *pabyPtr = 1;
    1180               0 :             pabyPtr ++;
    1181                 : 
    1182               0 :             WriteVarInt64(psInfo->ts.nTimeStamp, &pabyPtr);
    1183               0 :             WriteVarInt64(psInfo->nChangeset, &pabyPtr);
    1184               0 :             WriteVarInt(psInfo->nVersion, &pabyPtr);
    1185               0 :             WriteVarInt(psInfo->nUID, &pabyPtr);
    1186                 :             // FIXME : do something with pszUserSID
    1187                 :         }
    1188                 :         else
    1189                 :         {
    1190               0 :             *pabyPtr = 0;
    1191               0 :             pabyPtr ++;
    1192                 :         }
    1193                 :     }
    1194                 : 
    1195              66 :     memcpy(pabyPtr, &(pasLonLatPairs[0]), sizeof(LonLat));
    1196              66 :     pabyPtr += sizeof(LonLat);
    1197             264 :     for(int i=1;i<nPoints;i++)
    1198                 :     {
    1199                 :         GIntBig nDiff64;
    1200                 : 
    1201             198 :         nDiff64 = (GIntBig)pasLonLatPairs[i].nLon - (GIntBig)pasLonLatPairs[i-1].nLon;
    1202             198 :         WriteVarSInt64(nDiff64, &pabyPtr);
    1203                 : 
    1204             198 :         nDiff64 = pasLonLatPairs[i].nLat - pasLonLatPairs[i-1].nLat;
    1205             198 :         WriteVarSInt64(nDiff64, &pabyPtr);
    1206                 :     }
    1207              66 :     int nBufferSize = (int)(pabyPtr - pabyCompressedWay);
    1208              66 :     return nBufferSize;
    1209                 : }
    1210                 : 
    1211                 : /************************************************************************/
    1212                 : /*                             UncompressWay()                          */
    1213                 : /************************************************************************/
    1214                 : 
    1215              48 : int OGROSMDataSource::UncompressWay( int nBytes, GByte* pabyCompressedWay,
    1216                 :                                      LonLat* pasCoords,
    1217                 :                                      unsigned int* pnTags, OSMTag* pasTags,
    1218                 :                                      OSMInfo* psInfo )
    1219                 : {
    1220              48 :     GByte* pabyPtr = pabyCompressedWay;
    1221              48 :     unsigned int nTags = *pabyPtr;
    1222              48 :     pabyPtr ++;
    1223                 : 
    1224              48 :     if (pnTags)
    1225              15 :         *pnTags = nTags;
    1226                 : 
    1227                 :     /* TODO? : some additional safety checks */
    1228              71 :     for(unsigned int iTag = 0; iTag < nTags; iTag++)
    1229                 :     {
    1230              23 :         int nK = ReadVarInt32(&pabyPtr);
    1231              23 :         int nV = ReadVarInt32(&pabyPtr);
    1232              23 :         GByte* pszV = NULL;
    1233              23 :         if( nV == 0 )
    1234                 :         {
    1235               0 :             pszV = pabyPtr;
    1236               0 :             while(*pabyPtr != '\0')
    1237               0 :                 pabyPtr ++;
    1238               0 :             pabyPtr ++;
    1239                 :         }
    1240                 : 
    1241              23 :         if( pasTags )
    1242                 :         {
    1243              15 :             CPLAssert(nK >= 0 && nK < (int)asKeys.size());
    1244              15 :             pasTags[iTag].pszK = asKeys[nK]->pszK;
    1245              15 :             CPLAssert(nV == 0 || (nV > 0 && nV < (int)asKeys[nK]->asValues.size()));
    1246              15 :             pasTags[iTag].pszV = nV ? asKeys[nK]->asValues[nV] : (const char*) pszV;
    1247                 :         }
    1248                 :     }
    1249                 : 
    1250              48 :     if( bNeedsToSaveWayInfo )
    1251                 :     {
    1252               0 :         if( *pabyPtr )
    1253                 :         {
    1254               0 :             pabyPtr ++;
    1255                 : 
    1256                 :             OSMInfo sInfo;
    1257               0 :             if( psInfo == NULL )
    1258               0 :                 psInfo = &sInfo;
    1259                 : 
    1260               0 :             psInfo->ts.nTimeStamp = ReadVarInt64(&pabyPtr);
    1261               0 :             psInfo->nChangeset = ReadVarInt64(&pabyPtr);
    1262               0 :             psInfo->nVersion = ReadVarInt32(&pabyPtr);
    1263               0 :             psInfo->nUID = ReadVarInt32(&pabyPtr);
    1264                 : 
    1265               0 :             psInfo->bTimeStampIsStr = FALSE;
    1266               0 :             psInfo->pszUserSID = ""; // FIXME
    1267                 :         }
    1268                 :         else
    1269               0 :             pabyPtr ++;
    1270                 :     }
    1271                 : 
    1272              48 :     memcpy(&pasCoords[0].nLon, pabyPtr, sizeof(int));
    1273              48 :     memcpy(&pasCoords[0].nLat, pabyPtr + sizeof(int), sizeof(int));
    1274              48 :     pabyPtr += 2 * sizeof(int);
    1275              48 :     int nPoints = 1;
    1276             168 :     do
    1277                 :     {
    1278             168 :         pasCoords[nPoints].nLon = pasCoords[nPoints-1].nLon + ReadVarSInt64(&pabyPtr);
    1279             168 :         pasCoords[nPoints].nLat = pasCoords[nPoints-1].nLat + ReadVarSInt64(&pabyPtr);
    1280                 : 
    1281             168 :         nPoints ++;
    1282                 :     } while (pabyPtr < pabyCompressedWay + nBytes);
    1283                 : 
    1284              48 :     return nPoints;
    1285                 : }
    1286                 : 
    1287                 : /************************************************************************/
    1288                 : /*                              IndexWay()                              */
    1289                 : /************************************************************************/
    1290                 : 
    1291              69 : void OGROSMDataSource::IndexWay(GIntBig nWayID,
    1292                 :                                 unsigned int nTags, IndexedKVP* pasTags,
    1293                 :                                 LonLat* pasLonLatPairs, int nPairs,
    1294                 :                                 OSMInfo* psInfo)
    1295                 : {
    1296              69 :     if( !bIndexWays )
    1297               3 :         return;
    1298                 : 
    1299              66 :     sqlite3_bind_int64( hInsertWayStmt, 1, nWayID );
    1300                 : 
    1301              66 :     int nBufferSize = CompressWay (nTags, pasTags, nPairs, pasLonLatPairs, psInfo, pabyWayBuffer);
    1302              66 :     CPLAssert(nBufferSize <= WAY_BUFFER_SIZE);
    1303                 :     sqlite3_bind_blob( hInsertWayStmt, 2, pabyWayBuffer,
    1304              66 :                        nBufferSize, SQLITE_STATIC );
    1305                 : 
    1306              66 :     int rc = sqlite3_step( hInsertWayStmt );
    1307              66 :     sqlite3_reset( hInsertWayStmt );
    1308              66 :     if( !(rc == SQLITE_OK || rc == SQLITE_DONE) )
    1309                 :     {
    1310                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1311                 :                 "Failed inserting way " CPL_FRMT_GIB ": %s",
    1312               0 :                 nWayID, sqlite3_errmsg(hDB));
    1313                 :     }
    1314                 : }
    1315                 : 
    1316                 : /************************************************************************/
    1317                 : /*                              FindNode()                              */
    1318                 : /************************************************************************/
    1319                 : 
    1320             243 : int OGROSMDataSource::FindNode(GIntBig nID)
    1321                 : {
    1322             243 :     int iFirst = 0;
    1323             243 :     int iLast = nReqIds - 1;
    1324             980 :     while(iFirst <= iLast)
    1325                 :     {
    1326             677 :         int iMid = (iFirst + iLast) / 2;
    1327             677 :         if( nID < panReqIds[iMid])
    1328             212 :             iLast = iMid - 1;
    1329             465 :         else if( nID > panReqIds[iMid])
    1330             282 :             iFirst = iMid + 1;
    1331                 :         else
    1332             183 :             return iMid;
    1333                 :     }
    1334              60 :     return -1;
    1335                 : }
    1336                 : 
    1337                 : /************************************************************************/
    1338                 : /*                         ProcessWaysBatch()                           */
    1339                 : /************************************************************************/
    1340                 : 
    1341              13 : void OGROSMDataSource::ProcessWaysBatch()
    1342                 : {
    1343              13 :     if( nWayFeaturePairs == 0 ) return;
    1344                 : 
    1345                 :     //printf("nodes = %d, features = %d\n", nUnsortedReqIds, nWayFeaturePairs);
    1346              13 :     LookupNodes();
    1347                 : 
    1348                 :     int iPair;
    1349              94 :     for(iPair = 0; iPair < nWayFeaturePairs; iPair ++)
    1350                 :     {
    1351              81 :         WayFeaturePair* psWayFeaturePairs = &pasWayFeaturePairs[iPair];
    1352                 : 
    1353              81 :         int bIsArea = psWayFeaturePairs->bIsArea;
    1354                 : 
    1355              81 :         unsigned int nFound = 0;
    1356                 :         unsigned int i;
    1357              81 :         int nIdx = -1;
    1358             381 :         for(i=0;i<psWayFeaturePairs->nRefs;i++)
    1359                 :         {
    1360             357 :             if( nIdx >= 0 && psWayFeaturePairs->panNodeRefs[i] == psWayFeaturePairs->panNodeRefs[i-1] + 1 )
    1361                 :             {
    1362             114 :                 if( nIdx+1 < (int)nReqIds && panReqIds[nIdx+1] == psWayFeaturePairs->panNodeRefs[i] )
    1363              57 :                     nIdx ++;
    1364                 :                 else
    1365               0 :                     nIdx = -1;
    1366                 :             }
    1367                 :             else
    1368             243 :                 nIdx = FindNode( psWayFeaturePairs->panNodeRefs[i] );
    1369             300 :             if (nIdx >= 0)
    1370                 :             {
    1371             240 :                 pasLonLatCache[nFound].nLon = pasLonLatArray[nIdx].nLon;
    1372             240 :                 pasLonLatCache[nFound].nLat = pasLonLatArray[nIdx].nLat;
    1373             240 :                 nFound ++;
    1374                 :             }
    1375                 :         }
    1376                 : 
    1377              81 :         if( nFound > 0 && bIsArea )
    1378                 :         {
    1379              33 :             pasLonLatCache[nFound].nLon = pasLonLatCache[0].nLon;
    1380              33 :             pasLonLatCache[nFound].nLat = pasLonLatCache[0].nLat;
    1381              33 :             nFound ++;
    1382                 :         }
    1383                 : 
    1384              81 :         if( nFound < 2 )
    1385                 :         {
    1386                 :             CPLDebug("OSM", "Way " CPL_FRMT_GIB " with %d nodes that could be found. Discarding it",
    1387              12 :                     psWayFeaturePairs->nWayID, nFound);
    1388              12 :             delete psWayFeaturePairs->poFeature;
    1389              12 :             psWayFeaturePairs->poFeature = NULL;
    1390              12 :             psWayFeaturePairs->bIsArea = FALSE;
    1391              12 :             continue;
    1392                 :         }
    1393                 : 
    1394              69 :         if( bIsArea && papoLayers[IDX_LYR_MULTIPOLYGONS]->IsUserInterested() )
    1395                 :         {
    1396                 :             IndexWay(psWayFeaturePairs->nWayID,
    1397                 :                      psWayFeaturePairs->nTags,
    1398                 :                      psWayFeaturePairs->pasTags,
    1399                 :                      pasLonLatCache, (int)nFound,
    1400              27 :                      &psWayFeaturePairs->sInfo);
    1401                 :         }
    1402                 :         else
    1403                 :             IndexWay(psWayFeaturePairs->nWayID, 0, NULL,
    1404              42 :                      pasLonLatCache, (int)nFound, NULL);
    1405                 : 
    1406              69 :         if( psWayFeaturePairs->poFeature == NULL )
    1407                 :         {
    1408              56 :             continue;
    1409                 :         }
    1410                 : 
    1411                 :         OGRLineString* poLS;
    1412                 :         OGRGeometry* poGeom;
    1413                 : 
    1414              13 :         poLS = new OGRLineString();
    1415              13 :         poGeom = poLS;
    1416                 : 
    1417              13 :         poLS->setNumPoints((int)nFound);
    1418              57 :         for(i=0;i<nFound;i++)
    1419                 :         {
    1420                 :             poLS->setPoint(i,
    1421              44 :                         INT_TO_DBL(pasLonLatCache[i].nLon),
    1422              88 :                         INT_TO_DBL(pasLonLatCache[i].nLat));
    1423                 :         }
    1424                 : 
    1425              13 :         psWayFeaturePairs->poFeature->SetGeometryDirectly(poGeom);
    1426                 : 
    1427              13 :         if( nFound != psWayFeaturePairs->nRefs )
    1428                 :             CPLDebug("OSM", "For way " CPL_FRMT_GIB ", got only %d nodes instead of %d",
    1429                 :                    psWayFeaturePairs->nWayID, nFound,
    1430               6 :                    psWayFeaturePairs->nRefs);
    1431                 : 
    1432              13 :         int bFilteredOut = FALSE;
    1433              13 :         if( !papoLayers[IDX_LYR_LINES]->AddFeature(psWayFeaturePairs->poFeature,
    1434                 :                                                    psWayFeaturePairs->bAttrFilterAlreadyEvaluated,
    1435                 :                                                    &bFilteredOut) )
    1436               0 :             bStopParsing = TRUE;
    1437              13 :         else if (!bFilteredOut)
    1438              13 :             bFeatureAdded = TRUE;
    1439                 :     }
    1440                 : 
    1441              13 :     if( papoLayers[IDX_LYR_MULTIPOLYGONS]->IsUserInterested() )
    1442                 :     {
    1443              72 :         for(iPair = 0; iPair < nWayFeaturePairs; iPair ++)
    1444                 :         {
    1445              63 :             WayFeaturePair* psWayFeaturePairs = &pasWayFeaturePairs[iPair];
    1446                 : 
    1447              63 :             if( psWayFeaturePairs->bIsArea &&
    1448                 :                 (psWayFeaturePairs->nTags || bReportAllWays) )
    1449                 :             {
    1450              18 :                 sqlite3_bind_int64( hInsertPolygonsStandaloneStmt , 1, psWayFeaturePairs->nWayID );
    1451                 : 
    1452              18 :                 int rc = sqlite3_step( hInsertPolygonsStandaloneStmt );
    1453              18 :                 sqlite3_reset( hInsertPolygonsStandaloneStmt );
    1454              18 :                 if( !(rc == SQLITE_OK || rc == SQLITE_DONE) )
    1455                 :                 {
    1456                 :                     CPLError(CE_Failure, CPLE_AppDefined,
    1457                 :                             "Failed inserting into polygons_standalone " CPL_FRMT_GIB ": %s",
    1458               0 :                             psWayFeaturePairs->nWayID, sqlite3_errmsg(hDB));
    1459                 :                 }
    1460                 :             }
    1461                 :         }
    1462                 :     }
    1463                 : 
    1464              13 :     nWayFeaturePairs = 0;
    1465              13 :     nUnsortedReqIds = 0;
    1466                 : 
    1467              13 :     nAccumulatedTags = 0;
    1468              13 :     nNonRedundantValuesLen = 0;
    1469                 : }
    1470                 : 
    1471                 : /************************************************************************/
    1472                 : /*                              NotifyWay()                             */
    1473                 : /************************************************************************/
    1474                 : 
    1475             160 : void OGROSMDataSource::NotifyWay (OSMWay* psWay)
    1476                 : {
    1477                 :     unsigned int i;
    1478                 : 
    1479             160 :     nWaysProcessed++;
    1480             160 :     if( (nWaysProcessed % 10000) == 0 )
    1481                 :     {
    1482               0 :         CPLDebug("OSM", "Ways processed : %d", nWaysProcessed);
    1483                 : #ifdef DEBUG_MEM_USAGE
    1484                 :         CPLDebug("OSM", "GetMaxTotalAllocs() = " CPL_FRMT_GUIB, (GUIntBig)GetMaxTotalAllocs());
    1485                 : #endif
    1486                 :     }
    1487                 : 
    1488             160 :     if( !bUsePointsIndex )
    1489              48 :         return;
    1490                 : 
    1491                 :     //printf("way %d : %d nodes\n", (int)psWay->nID, (int)psWay->nRefs);
    1492             112 :     if( psWay->nRefs > MAX_NODES_PER_WAY )
    1493                 :     {
    1494                 :         CPLError(CE_Failure, CPLE_NotSupported,
    1495                 :                  "Ways with more than %d nodes are not supported",
    1496               0 :                  MAX_NODES_PER_WAY);
    1497               0 :         return;
    1498                 :     }
    1499                 : 
    1500             112 :     if( psWay->nRefs < 2 )
    1501                 :     {
    1502                 :         CPLDebug("OSM", "Way " CPL_FRMT_GIB " with %d nodes. Discarding it",
    1503              14 :                  psWay->nID, psWay->nRefs);
    1504              14 :         return;
    1505                 :     }
    1506                 : 
    1507                 :     /* Is a closed way a polygon ? */
    1508              98 :     int bIsArea = FALSE;
    1509              98 :     if( psWay->panNodeRefs[0] == psWay->panNodeRefs[psWay->nRefs - 1] )
    1510                 :     {
    1511             140 :         for(i=0;i<psWay->nTags;i++)
    1512                 :         {
    1513              84 :             const char* pszK = psWay->pasTags[i].pszK;
    1514              84 :             if( strcmp(pszK, "area") == 0 )
    1515                 :             {
    1516              42 :                 if( strcmp(psWay->pasTags[i].pszV, "yes") == 0 )
    1517                 :                 {
    1518              42 :                     bIsArea = TRUE;
    1519                 :                 }
    1520               0 :                 else if( strcmp(psWay->pasTags[i].pszV, "no") == 0 )
    1521                 :                 {
    1522               0 :                     bIsArea = FALSE;
    1523               0 :                     break;
    1524                 :                 }
    1525                 :             }
    1526              42 :             else if( aoSetClosedWaysArePolygons.find(pszK) !=
    1527                 :                      aoSetClosedWaysArePolygons.end() )
    1528                 :             {
    1529              14 :                 bIsArea = TRUE;
    1530                 :             }
    1531                 :         }
    1532                 :     }
    1533                 : 
    1534              98 :     OGRFeature* poFeature = NULL;
    1535                 : 
    1536              98 :     int bInterestingTag = bReportAllWays;
    1537              98 :     if( !bIsArea && !bReportAllWays )
    1538                 :     {
    1539              56 :         for(i=0;i<psWay->nTags;i++)
    1540                 :         {
    1541              42 :             const char* pszK = psWay->pasTags[i].pszK;
    1542              42 :             if( papoLayers[IDX_LYR_LINES]->IsSignificantKey(pszK) )
    1543                 :             {
    1544              42 :                 bInterestingTag = TRUE;
    1545              42 :                 break;
    1546                 :             }
    1547                 :         }
    1548                 :     }
    1549                 : 
    1550              98 :     int bAttrFilterAlreadyEvaluated = FALSE;
    1551              98 :     if( !bIsArea && papoLayers[IDX_LYR_LINES]->IsUserInterested() && bInterestingTag )
    1552                 :     {
    1553              24 :         poFeature = new OGRFeature(papoLayers[IDX_LYR_LINES]->GetLayerDefn());
    1554                 : 
    1555              24 :         papoLayers[IDX_LYR_LINES]->SetFieldsFromTags(
    1556              48 :             poFeature, psWay->nID, FALSE, psWay->nTags, psWay->pasTags, &psWay->sInfo );
    1557                 : 
    1558                 :         /* Optimization : if we have an attribute filter, that does not require geometry, */
    1559                 :         /* and if we don't need to index ways, then we can just evaluate the attribute */
    1560                 :         /* filter without the geometry */
    1561              36 :         if( papoLayers[IDX_LYR_LINES]->HasAttributeFilter() &&
    1562               6 :             !papoLayers[IDX_LYR_LINES]->AttributeFilterEvaluationNeedsGeometry() &&
    1563                 :             !bIndexWays )
    1564                 :         {
    1565               6 :             if( !papoLayers[IDX_LYR_LINES]->EvaluateAttributeFilter(poFeature) )
    1566                 :             {
    1567               5 :                 delete poFeature;
    1568               5 :                 return;
    1569                 :             }
    1570               1 :             bAttrFilterAlreadyEvaluated = TRUE;
    1571                 :         }
    1572                 :     }
    1573              74 :     else if( !bIndexWays )
    1574                 :     {
    1575              12 :         return;
    1576                 :     }
    1577                 : 
    1578              81 :     if( nUnsortedReqIds + psWay->nRefs > MAX_ACCUMULATED_NODES ||
    1579                 :         nWayFeaturePairs == MAX_DELAYED_FEATURES ||
    1580                 :         nAccumulatedTags + psWay->nTags > MAX_ACCUMULATED_TAGS ||
    1581                 :         nNonRedundantValuesLen + 1024 > MAX_NON_REDUNDANT_VALUES )
    1582                 :     {
    1583               0 :         ProcessWaysBatch();
    1584                 :     }
    1585                 : 
    1586              81 :     WayFeaturePair* psWayFeaturePairs = &pasWayFeaturePairs[nWayFeaturePairs];
    1587                 : 
    1588              81 :     psWayFeaturePairs->nWayID = psWay->nID;
    1589              81 :     psWayFeaturePairs->nRefs = psWay->nRefs - bIsArea;
    1590              81 :     psWayFeaturePairs->panNodeRefs = panUnsortedReqIds + nUnsortedReqIds;
    1591              81 :     psWayFeaturePairs->poFeature = poFeature;
    1592              81 :     psWayFeaturePairs->bIsArea = bIsArea;
    1593              81 :     psWayFeaturePairs->bAttrFilterAlreadyEvaluated = bAttrFilterAlreadyEvaluated;
    1594                 : 
    1595              81 :     if( bIsArea && papoLayers[IDX_LYR_MULTIPOLYGONS]->IsUserInterested() )
    1596                 :     {
    1597              27 :         int nTagCount = 0;
    1598                 : 
    1599              27 :         if( bNeedsToSaveWayInfo )
    1600                 :         {
    1601               0 :             if( !psWay->sInfo.bTimeStampIsStr )
    1602                 :                 psWayFeaturePairs->sInfo.ts.nTimeStamp =
    1603               0 :                     psWay->sInfo.ts.nTimeStamp;
    1604                 :             else
    1605                 :             {
    1606                 :                 int year, month, day, hour, minute, TZ;
    1607                 :                 float second;
    1608               0 :                 if (OGRParseXMLDateTime(psWay->sInfo.ts.pszTimeStamp, &year, &month, &day,
    1609                 :                                         &hour, &minute, &second, &TZ))
    1610                 :                 {
    1611                 :                     struct tm brokendown;
    1612               0 :                     brokendown.tm_year = year - 1900;
    1613               0 :                     brokendown.tm_mon = month - 1;
    1614               0 :                     brokendown.tm_mday = day;
    1615               0 :                     brokendown.tm_hour = hour;
    1616               0 :                     brokendown.tm_min = minute;
    1617               0 :                     brokendown.tm_sec = (int)(second + .5);
    1618                 :                     psWayFeaturePairs->sInfo.ts.nTimeStamp =
    1619               0 :                         CPLYMDHMSToUnixTime(&brokendown);
    1620                 :                 }
    1621                 :                 else
    1622               0 :                     psWayFeaturePairs->sInfo.ts.nTimeStamp = 0;
    1623                 :             }
    1624               0 :             psWayFeaturePairs->sInfo.nChangeset = psWay->sInfo.nChangeset;
    1625               0 :             psWayFeaturePairs->sInfo.nVersion = psWay->sInfo.nVersion;
    1626               0 :             psWayFeaturePairs->sInfo.nUID = psWay->sInfo.nUID;
    1627               0 :             psWayFeaturePairs->sInfo.bTimeStampIsStr = FALSE;
    1628               0 :             psWayFeaturePairs->sInfo.pszUserSID = ""; // FIXME
    1629                 :         }
    1630                 :         else
    1631                 :         {
    1632              27 :             psWayFeaturePairs->sInfo.ts.nTimeStamp = 0;
    1633              27 :             psWayFeaturePairs->sInfo.nChangeset = 0;
    1634              27 :             psWayFeaturePairs->sInfo.nVersion = 0;
    1635              27 :             psWayFeaturePairs->sInfo.nUID = 0;
    1636              27 :             psWayFeaturePairs->sInfo.bTimeStampIsStr = FALSE;
    1637              27 :             psWayFeaturePairs->sInfo.pszUserSID = "";
    1638                 :         }
    1639                 : 
    1640              27 :         psWayFeaturePairs->pasTags = pasAccumulatedTags + nAccumulatedTags;
    1641                 : 
    1642              72 :         for(unsigned int iTag = 0; iTag < psWay->nTags; iTag++)
    1643                 :         {
    1644              45 :             const char* pszK = psWay->pasTags[iTag].pszK;
    1645              45 :             const char* pszV = psWay->pasTags[iTag].pszV;
    1646                 : 
    1647              45 :             if (strcmp(pszK, "area") == 0)
    1648              27 :                 continue;
    1649              18 :             if (strcmp(pszK, "created_by") == 0)
    1650               0 :                 continue;
    1651              18 :             if (strcmp(pszK, "converted_by") == 0)
    1652               0 :                 continue;
    1653              18 :             if (strcmp(pszK, "note") == 0)
    1654               0 :                 continue;
    1655              18 :             if (strcmp(pszK, "todo") == 0)
    1656               0 :                 continue;
    1657              18 :             if (strcmp(pszK, "fixme") == 0)
    1658               0 :                 continue;
    1659              18 :             if (strcmp(pszK, "FIXME") == 0)
    1660               0 :                 continue;
    1661                 : 
    1662                 :             std::map<const char*, KeyDesc*, ConstCharComp>::iterator oIterK =
    1663              18 :                 aoMapIndexedKeys.find(pszK);
    1664                 :             KeyDesc* psKD;
    1665              18 :             if (oIterK == aoMapIndexedKeys.end())
    1666                 :             {
    1667              18 :                 if( nNextKeyIndex >= 32768 ) /* somewhat arbitrary */
    1668                 :                 {
    1669               0 :                     if( nNextKeyIndex == 32768 )
    1670                 :                     {
    1671                 :                         CPLError(CE_Failure, CPLE_AppDefined,
    1672               0 :                                  "Too many different keys in file");
    1673               0 :                         nNextKeyIndex ++; /* to avoid next warnings */
    1674                 :                     }
    1675               0 :                     continue;
    1676                 :                 }
    1677              18 :                 psKD = new KeyDesc();
    1678              18 :                 psKD->pszK = CPLStrdup(pszK);
    1679              18 :                 psKD->nKeyIndex = nNextKeyIndex ++;
    1680                 :                 //CPLDebug("OSM", "nNextKeyIndex=%d", nNextKeyIndex);
    1681              18 :                 psKD->nOccurences = 0;
    1682              18 :                 psKD->asValues.push_back(CPLStrdup(""));
    1683              18 :                 aoMapIndexedKeys[psKD->pszK] = psKD;
    1684              18 :                 asKeys.push_back(psKD);
    1685                 :             }
    1686                 :             else
    1687               0 :                 psKD = oIterK->second;
    1688              18 :             psKD->nOccurences ++;
    1689                 : 
    1690              18 :             pasAccumulatedTags[nAccumulatedTags].nKeyIndex = psKD->nKeyIndex;
    1691                 : 
    1692                 :             /* to fit in 2 bytes, the theoretical limit would be 127 * 128 + 127 */
    1693              18 :             if( psKD->asValues.size() < 1024 )
    1694                 :             {
    1695              18 :                 std::map<const char*, int, ConstCharComp>::iterator oIterV;
    1696              18 :                 oIterV = psKD->anMapV.find(pszV);
    1697                 :                 int nValueIndex;
    1698              18 :                 if (oIterV == psKD->anMapV.end())
    1699                 :                 {
    1700              18 :                     char* pszVDup = CPLStrdup(pszV);
    1701              18 :                     nValueIndex = (int)psKD->asValues.size();
    1702              18 :                     psKD->anMapV[pszVDup] = nValueIndex;
    1703              18 :                     psKD->asValues.push_back(pszVDup);
    1704                 :                 }
    1705                 :                 else
    1706               0 :                     nValueIndex = oIterV->second;
    1707                 : 
    1708              18 :                 pasAccumulatedTags[nAccumulatedTags].bVIsIndex = TRUE;
    1709              18 :                 pasAccumulatedTags[nAccumulatedTags].u.nValueIndex = nValueIndex;
    1710                 :             }
    1711                 :             else
    1712                 :             {
    1713               0 :                 int nLenV = strlen(pszV) + 1;
    1714                 : 
    1715               0 :                 if( psKD->asValues.size() == 1024 )
    1716                 :                 {
    1717                 :                     CPLDebug("OSM", "More than %d different values for tag %s",
    1718               0 :                             1024, pszK);
    1719               0 :                     psKD->asValues.push_back(CPLStrdup(""));  /* to avoid next warnings */
    1720                 :                 }
    1721                 : 
    1722               0 :                 CPLAssert( nNonRedundantValuesLen + nLenV <= MAX_NON_REDUNDANT_VALUES );
    1723               0 :                 memcpy(pabyNonRedundantValues + nNonRedundantValuesLen, pszV, nLenV);
    1724               0 :                 pasAccumulatedTags[nAccumulatedTags].bVIsIndex = FALSE;
    1725               0 :                 pasAccumulatedTags[nAccumulatedTags].u.nOffsetInpabyNonRedundantValues = nNonRedundantValuesLen;
    1726               0 :                 nNonRedundantValuesLen += nLenV;
    1727                 :             }
    1728              18 :             nAccumulatedTags ++;
    1729                 : 
    1730              18 :             nTagCount ++;
    1731              18 :             if( nTagCount == MAX_COUNT_FOR_TAGS_IN_WAY )
    1732               0 :                 break;
    1733                 :         }
    1734                 : 
    1735              27 :         psWayFeaturePairs->nTags = nTagCount;
    1736                 :     }
    1737                 :     else
    1738                 :     {
    1739              54 :         psWayFeaturePairs->sInfo.ts.nTimeStamp = 0;
    1740              54 :         psWayFeaturePairs->sInfo.nChangeset = 0;
    1741              54 :         psWayFeaturePairs->sInfo.nVersion = 0;
    1742              54 :         psWayFeaturePairs->sInfo.nUID = 0;
    1743              54 :         psWayFeaturePairs->sInfo.bTimeStampIsStr = FALSE;
    1744              54 :         psWayFeaturePairs->sInfo.pszUserSID = "";
    1745                 : 
    1746              54 :         psWayFeaturePairs->nTags = 0;
    1747              54 :         psWayFeaturePairs->pasTags = NULL;
    1748                 :     }
    1749                 : 
    1750              81 :     nWayFeaturePairs++;
    1751                 : 
    1752              81 :     memcpy(panUnsortedReqIds + nUnsortedReqIds, psWay->panNodeRefs, sizeof(GIntBig) * (psWay->nRefs - bIsArea));
    1753              81 :     nUnsortedReqIds += (psWay->nRefs - bIsArea);
    1754                 : }
    1755                 : 
    1756             160 : static void OGROSMNotifyWay (OSMWay* psWay, OSMContext* psOSMContext, void* user_data)
    1757                 : {
    1758             160 :     ((OGROSMDataSource*) user_data)->NotifyWay(psWay);
    1759             160 : }
    1760                 : 
    1761                 : /************************************************************************/
    1762                 : /*                            LookupWays()                              */
    1763                 : /************************************************************************/
    1764                 : 
    1765              34 : unsigned int OGROSMDataSource::LookupWays( std::map< GIntBig, std::pair<int,void*> >& aoMapWays,
    1766                 :                                            OSMRelation* psRelation )
    1767                 : {
    1768              34 :     unsigned int nFound = 0;
    1769              34 :     unsigned int iCur = 0;
    1770                 :     unsigned int i;
    1771                 : 
    1772             102 :     while( iCur < psRelation->nMembers )
    1773                 :     {
    1774              34 :         unsigned int nToQuery = 0;
    1775              96 :         for(i=iCur;i<psRelation->nMembers;i++)
    1776                 :         {
    1777             122 :             if( psRelation->pasMembers[i].eType == MEMBER_WAY &&
    1778              60 :                 strcmp(psRelation->pasMembers[i].pszRole, "subarea") != 0 )
    1779                 :             {
    1780              60 :                 nToQuery ++;
    1781              60 :                 if( nToQuery == LIMIT_IDS_PER_REQUEST )
    1782               0 :                     break;
    1783                 :             }
    1784                 :         }
    1785                 : 
    1786              34 :         if( nToQuery == 0)
    1787               0 :             break;
    1788                 : 
    1789              34 :         unsigned int iLastI = (i == psRelation->nMembers) ? i : i + 1;
    1790                 : 
    1791              34 :         sqlite3_stmt* hStmt = pahSelectWayStmt[nToQuery-1];
    1792              34 :         unsigned int nBindIndex = 1;
    1793              96 :         for(i=iCur;i<iLastI;i++)
    1794                 :         {
    1795             122 :             if( psRelation->pasMembers[i].eType == MEMBER_WAY &&
    1796              60 :                 strcmp(psRelation->pasMembers[i].pszRole, "subarea") != 0 )
    1797                 :             {
    1798                 :                 sqlite3_bind_int64( hStmt, nBindIndex,
    1799              60 :                                     psRelation->pasMembers[i].nID );
    1800              60 :                 nBindIndex ++;
    1801                 :             }
    1802                 :         }
    1803              34 :         iCur = iLastI;
    1804                 : 
    1805             119 :         while( sqlite3_step(hStmt) == SQLITE_ROW )
    1806                 :         {
    1807              51 :             GIntBig id = sqlite3_column_int(hStmt, 0);
    1808              51 :             if( aoMapWays.find(id) == aoMapWays.end() )
    1809                 :             {
    1810              51 :                 int nBlobSize = sqlite3_column_bytes(hStmt, 1);
    1811              51 :                 const void* blob = sqlite3_column_blob(hStmt, 1);
    1812              51 :                 void* blob_dup = CPLMalloc(nBlobSize);
    1813              51 :                 memcpy(blob_dup, blob, nBlobSize);
    1814              51 :                 aoMapWays[id] = std::pair<int,void*>(nBlobSize, blob_dup);
    1815                 :             }
    1816              51 :             nFound++;
    1817                 :         }
    1818                 : 
    1819              34 :         sqlite3_reset(hStmt);
    1820                 :     }
    1821                 : 
    1822              34 :     return nFound;
    1823                 : }
    1824                 : 
    1825                 : /************************************************************************/
    1826                 : /*                          BuildMultiPolygon()                         */
    1827                 : /************************************************************************/
    1828                 : 
    1829              26 : OGRGeometry* OGROSMDataSource::BuildMultiPolygon(OSMRelation* psRelation,
    1830                 :                                                  unsigned int* pnTags,
    1831                 :                                                  OSMTag* pasTags)
    1832                 : {
    1833                 : 
    1834              26 :     std::map< GIntBig, std::pair<int,void*> > aoMapWays;
    1835              26 :     LookupWays( aoMapWays, psRelation );
    1836                 : 
    1837              26 :     int bMissing = FALSE;
    1838                 :     unsigned int i;
    1839              69 :     for(i = 0; i < psRelation->nMembers; i ++ )
    1840                 :     {
    1841             104 :         if( psRelation->pasMembers[i].eType == MEMBER_WAY &&
    1842              52 :             strcmp(psRelation->pasMembers[i].pszRole, "subarea") != 0 )
    1843                 :         {
    1844              52 :             if( aoMapWays.find( psRelation->pasMembers[i].nID ) == aoMapWays.end() )
    1845                 :             {
    1846                 :                 CPLDebug("OSM", "Relation " CPL_FRMT_GIB " has missing ways. Ignoring it",
    1847               9 :                         psRelation->nID);
    1848               9 :                 bMissing = TRUE;
    1849               9 :                 break;
    1850                 :             }
    1851                 :         }
    1852                 :     }
    1853                 : 
    1854              26 :     OGRGeometry* poRet = NULL;
    1855              26 :     OGRMultiLineString* poMLS = NULL;
    1856              26 :     OGRGeometry** papoPolygons = NULL;
    1857              26 :     int nPolys = 0;
    1858                 : 
    1859              26 :     if( bMissing )
    1860               9 :         goto cleanup;
    1861                 : 
    1862              17 :     poMLS = new OGRMultiLineString();
    1863                 :     papoPolygons = (OGRGeometry**) CPLMalloc(
    1864              34 :         sizeof(OGRGeometry*) *  psRelation->nMembers);
    1865              17 :     nPolys = 0;
    1866                 : 
    1867              17 :     if( pnTags != NULL )
    1868               9 :         *pnTags = 0;
    1869                 : 
    1870              51 :     for(i = 0; i < psRelation->nMembers; i ++ )
    1871                 :     {
    1872              68 :         if( psRelation->pasMembers[i].eType == MEMBER_WAY &&
    1873              34 :             strcmp(psRelation->pasMembers[i].pszRole, "subarea") != 0  )
    1874                 :         {
    1875              34 :             const std::pair<int, void*>& oGeom = aoMapWays[ psRelation->pasMembers[i].nID ];
    1876                 : 
    1877              34 :             LonLat* pasCoords = (LonLat*) pasLonLatCache;
    1878                 :             int nPoints;
    1879                 : 
    1880              52 :             if( pnTags != NULL && *pnTags == 0 &&
    1881               9 :                 strcmp(psRelation->pasMembers[i].pszRole, "outer") == 0 )
    1882                 :             {
    1883               9 :                 int nCompressedWaySize = oGeom.first;
    1884               9 :                 GByte* pabyCompressedWay = (GByte*) oGeom.second;
    1885                 : 
    1886               9 :                 memcpy(pabyWayBuffer, pabyCompressedWay, nCompressedWaySize);
    1887                 : 
    1888                 :                 nPoints = UncompressWay (nCompressedWaySize, pabyWayBuffer,
    1889                 :                                          pasCoords,
    1890               9 :                                          pnTags, pasTags, NULL );
    1891                 :             }
    1892                 :             else
    1893                 :             {
    1894                 :                 nPoints = UncompressWay (oGeom.first, (GByte*) oGeom.second, pasCoords,
    1895              25 :                                          NULL, NULL, NULL);
    1896                 :             }
    1897                 : 
    1898                 :             OGRLineString* poLS;
    1899                 : 
    1900             102 :             if ( pasCoords[0].nLon == pasCoords[nPoints - 1].nLon &&
    1901              34 :                  pasCoords[0].nLat == pasCoords[nPoints - 1].nLat )
    1902                 :             {
    1903              34 :                 OGRPolygon* poPoly = new OGRPolygon();
    1904              68 :                 OGRLinearRing* poRing = new OGRLinearRing();
    1905              34 :                 poPoly->addRingDirectly(poRing);
    1906              34 :                 papoPolygons[nPolys ++] = poPoly;
    1907              34 :                 poLS = poRing;
    1908                 : 
    1909              34 :                 if( strcmp(psRelation->pasMembers[i].pszRole, "outer") == 0 )
    1910                 :                 {
    1911              17 :                     sqlite3_bind_int64( hDeletePolygonsStandaloneStmt, 1, psRelation->pasMembers[i].nID );
    1912              17 :                     sqlite3_step( hDeletePolygonsStandaloneStmt );
    1913              17 :                     sqlite3_reset( hDeletePolygonsStandaloneStmt );
    1914                 :                 }
    1915                 :             }
    1916                 :             else
    1917                 :             {
    1918               0 :                 poLS = new OGRLineString();
    1919               0 :                 poMLS->addGeometryDirectly(poLS);
    1920                 :             }
    1921                 : 
    1922              34 :             poLS->setNumPoints(nPoints);
    1923             204 :             for(int j=0;j<nPoints;j++)
    1924                 :             {
    1925                 :                 poLS->setPoint( j,
    1926             170 :                                 INT_TO_DBL(pasCoords[j].nLon),
    1927             340 :                                 INT_TO_DBL(pasCoords[j].nLat) );
    1928                 :             }
    1929                 : 
    1930                 :         }
    1931                 :     }
    1932                 : 
    1933              17 :     if( poMLS->getNumGeometries() > 0 )
    1934                 :     {
    1935                 :         OGRGeometryH hPoly = OGRBuildPolygonFromEdges( (OGRGeometryH) poMLS,
    1936                 :                                                         TRUE,
    1937                 :                                                         FALSE,
    1938                 :                                                         0,
    1939               0 :                                                         NULL );
    1940               0 :         if( hPoly != NULL && OGR_G_GetGeometryType(hPoly) == wkbPolygon )
    1941                 :         {
    1942               0 :             OGRPolygon* poSuperPoly = (OGRPolygon* ) hPoly;
    1943               0 :             for(i = 0; i < 1 + (unsigned int)poSuperPoly->getNumInteriorRings(); i++)
    1944                 :             {
    1945               0 :                 OGRPolygon* poPoly = new OGRPolygon();
    1946                 :                 OGRLinearRing* poRing =  (i == 0) ? poSuperPoly->getExteriorRing() :
    1947               0 :                                                     poSuperPoly->getInteriorRing(i - 1);
    1948               0 :                 if( poRing != NULL && poRing->getNumPoints() >= 4 &&
    1949                 :                     poRing->getX(0) == poRing->getX(poRing->getNumPoints() -1) &&
    1950                 :                     poRing->getY(0) == poRing->getY(poRing->getNumPoints() -1) )
    1951                 :                 {
    1952               0 :                     poPoly->addRing( poRing );
    1953               0 :                     papoPolygons[nPolys ++] = poPoly;
    1954                 :                 }
    1955                 :             }
    1956                 :         }
    1957                 : 
    1958               0 :         OGR_G_DestroyGeometry(hPoly);
    1959                 :     }
    1960              17 :     delete poMLS;
    1961                 : 
    1962              17 :     if( nPolys > 0 )
    1963                 :     {
    1964              17 :         int bIsValidGeometry = FALSE;
    1965              17 :         const char* apszOptions[2] = { "METHOD=DEFAULT", NULL };
    1966                 :         OGRGeometry* poGeom = OGRGeometryFactory::organizePolygons(
    1967              17 :             papoPolygons, nPolys, &bIsValidGeometry, apszOptions );
    1968                 : 
    1969              17 :         if( poGeom != NULL && poGeom->getGeometryType() == wkbPolygon )
    1970                 :         {
    1971              17 :             OGRMultiPolygon* poMulti = new OGRMultiPolygon();
    1972              17 :             poMulti->addGeometryDirectly(poGeom);
    1973              17 :             poGeom = poMulti;
    1974                 :         }
    1975                 : 
    1976              17 :         if( poGeom != NULL && poGeom->getGeometryType() == wkbMultiPolygon )
    1977                 :         {
    1978              17 :             poRet = poGeom;
    1979                 :         }
    1980                 :         else
    1981                 :         {
    1982                 :             CPLDebug("OSM", "Relation " CPL_FRMT_GIB ": Geometry has incompatible type : %s",
    1983                 :                      psRelation->nID,
    1984               0 :                      poGeom != NULL ? OGR_G_GetGeometryName((OGRGeometryH)poGeom) : "null" );
    1985               0 :             delete poGeom;
    1986                 :         }
    1987                 :     }
    1988                 : 
    1989              17 :     CPLFree(papoPolygons);
    1990                 : 
    1991                 : cleanup:
    1992                 :     /* Cleanup */
    1993              26 :     std::map< GIntBig, std::pair<int,void*> >::iterator oIter;
    1994              69 :     for( oIter = aoMapWays.begin(); oIter != aoMapWays.end(); ++oIter )
    1995              43 :         CPLFree(oIter->second.second);
    1996                 : 
    1997              26 :     return poRet;
    1998                 : }
    1999                 : 
    2000                 : /************************************************************************/
    2001                 : /*                          BuildGeometryCollection()                   */
    2002                 : /************************************************************************/
    2003                 : 
    2004               8 : OGRGeometry* OGROSMDataSource::BuildGeometryCollection(OSMRelation* psRelation, int bMultiLineString)
    2005                 : {
    2006               8 :     std::map< GIntBig, std::pair<int,void*> > aoMapWays;
    2007               8 :     LookupWays( aoMapWays, psRelation );
    2008                 : 
    2009                 :     unsigned int i;
    2010                 : 
    2011                 :     OGRGeometryCollection* poColl;
    2012               8 :     if( bMultiLineString )
    2013               6 :         poColl = new OGRMultiLineString();
    2014                 :     else
    2015               2 :         poColl = new OGRGeometryCollection();
    2016                 : 
    2017              18 :     for(i = 0; i < psRelation->nMembers; i ++ )
    2018                 :     {
    2019              12 :         if( psRelation->pasMembers[i].eType == MEMBER_NODE && !bMultiLineString )
    2020                 :         {
    2021               2 :             nUnsortedReqIds = 1;
    2022               2 :             panUnsortedReqIds[0] = psRelation->pasMembers[i].nID;
    2023               2 :             LookupNodes();
    2024               2 :             if( nReqIds == 1 )
    2025                 :             {
    2026                 :                 poColl->addGeometryDirectly(new OGRPoint(
    2027               2 :                     INT_TO_DBL(pasLonLatArray[0].nLon),
    2028               4 :                     INT_TO_DBL(pasLonLatArray[0].nLat)));
    2029                 :             }
    2030                 :         }
    2031              24 :         else if( psRelation->pasMembers[i].eType == MEMBER_WAY &&
    2032               8 :                  strcmp(psRelation->pasMembers[i].pszRole, "subarea") != 0  &&
    2033               8 :                  aoMapWays.find( psRelation->pasMembers[i].nID ) != aoMapWays.end() )
    2034                 :         {
    2035               8 :             const std::pair<int, void*>& oGeom = aoMapWays[ psRelation->pasMembers[i].nID ];
    2036                 : 
    2037               8 :             LonLat* pasCoords = (LonLat*) pasLonLatCache;
    2038               8 :             int nPoints = UncompressWay (oGeom.first, (GByte*) oGeom.second, pasCoords, NULL, NULL, NULL);
    2039                 : 
    2040                 :             OGRLineString* poLS;
    2041                 : 
    2042               8 :             poLS = new OGRLineString();
    2043               8 :             poColl->addGeometryDirectly(poLS);
    2044                 : 
    2045               8 :             poLS->setNumPoints(nPoints);
    2046              24 :             for(int j=0;j<nPoints;j++)
    2047                 :             {
    2048                 :                 poLS->setPoint( j,
    2049              16 :                                 INT_TO_DBL(pasCoords[j].nLon),
    2050              32 :                                 INT_TO_DBL(pasCoords[j].nLat) );
    2051                 :             }
    2052                 : 
    2053                 :         }
    2054                 :     }
    2055                 : 
    2056               8 :     if( poColl->getNumGeometries() == 0 )
    2057                 :     {
    2058               0 :         delete poColl;
    2059               0 :         poColl = NULL;
    2060                 :     }
    2061                 : 
    2062                 :     /* Cleanup */
    2063               8 :     std::map< GIntBig, std::pair<int,void*> >::iterator oIter;
    2064              16 :     for( oIter = aoMapWays.begin(); oIter != aoMapWays.end(); ++oIter )
    2065               8 :         CPLFree(oIter->second.second);
    2066                 : 
    2067               8 :     return poColl;
    2068                 : }
    2069                 : 
    2070                 : /************************************************************************/
    2071                 : /*                            NotifyRelation()                          */
    2072                 : /************************************************************************/
    2073                 : 
    2074             100 : void OGROSMDataSource::NotifyRelation (OSMRelation* psRelation)
    2075                 : {
    2076                 :     unsigned int i;
    2077                 : 
    2078             100 :     if( nWayFeaturePairs != 0 )
    2079              13 :         ProcessWaysBatch();
    2080                 : 
    2081             100 :     nRelationsProcessed++;
    2082             100 :     if( (nRelationsProcessed % 10000) == 0 )
    2083                 :     {
    2084               0 :         CPLDebug("OSM", "Relations processed : %d", nRelationsProcessed);
    2085                 : #ifdef DEBUG_MEM_USAGE
    2086                 :         CPLDebug("OSM", "GetMaxTotalAllocs() = " CPL_FRMT_GUIB, (GUIntBig)GetMaxTotalAllocs());
    2087                 : #endif
    2088                 :     }
    2089                 : 
    2090             100 :     if( !bUseWaysIndex )
    2091              45 :         return;
    2092                 : 
    2093              55 :     int bMultiPolygon = FALSE;
    2094              55 :     int bMultiLineString = FALSE;
    2095              55 :     int bInterestingTagFound = FALSE;
    2096              55 :     const char* pszTypeV = NULL;
    2097             121 :     for(i = 0; i < psRelation->nTags; i ++ )
    2098                 :     {
    2099              66 :         const char* pszK = psRelation->pasTags[i].pszK;
    2100              66 :         if( strcmp(pszK, "type") == 0 )
    2101                 :         {
    2102              55 :             const char* pszV = psRelation->pasTags[i].pszV;
    2103              55 :             pszTypeV = pszV;
    2104              88 :             if( strcmp(pszV, "multipolygon") == 0 ||
    2105                 :                 strcmp(pszV, "boundary") == 0)
    2106                 :             {
    2107              33 :                 bMultiPolygon = TRUE;
    2108                 :             }
    2109              22 :             else if( strcmp(pszV, "multilinestring") == 0 ||
    2110                 :                      strcmp(pszV, "route") == 0 )
    2111                 :             {
    2112              11 :                 bMultiLineString = TRUE;
    2113                 :             }
    2114                 :         }
    2115              11 :         else if ( strcmp(pszK, "created_by") != 0 )
    2116              11 :             bInterestingTagFound = TRUE;
    2117                 :     }
    2118                 : 
    2119                 :     /* Optimization : if we have an attribute filter, that does not require geometry, */
    2120                 :     /* then we can just evaluate the attribute filter without the geometry */
    2121                 :     int iCurLayer = (bMultiPolygon) ?    IDX_LYR_MULTIPOLYGONS :
    2122                 :                     (bMultiLineString) ? IDX_LYR_MULTILINESTRINGS :
    2123              55 :                                          IDX_LYR_OTHER_RELATIONS;
    2124              55 :     if( !papoLayers[iCurLayer]->IsUserInterested() )
    2125              19 :         return;
    2126                 : 
    2127              36 :     OGRFeature* poFeature = NULL;
    2128                 : 
    2129              59 :     if( !(bMultiPolygon && !bInterestingTagFound) && /* we cannot do early filtering for multipolygon that has no interesting tag, since we may fetch attributes from ways */
    2130              18 :         papoLayers[iCurLayer]->HasAttributeFilter() &&
    2131               5 :         !papoLayers[iCurLayer]->AttributeFilterEvaluationNeedsGeometry() )
    2132                 :     {
    2133               5 :         poFeature = new OGRFeature(papoLayers[iCurLayer]->GetLayerDefn());
    2134                 : 
    2135               5 :         papoLayers[iCurLayer]->SetFieldsFromTags( poFeature,
    2136                 :                                                   psRelation->nID,
    2137                 :                                                   FALSE,
    2138                 :                                                   psRelation->nTags,
    2139                 :                                                   psRelation->pasTags,
    2140              10 :                                                   &psRelation->sInfo);
    2141                 : 
    2142               5 :         if( !papoLayers[iCurLayer]->EvaluateAttributeFilter(poFeature) )
    2143                 :         {
    2144               2 :             delete poFeature;
    2145               2 :             return;
    2146                 :         }
    2147                 :     }
    2148                 : 
    2149                 :     OGRGeometry* poGeom;
    2150                 : 
    2151              34 :     unsigned int nExtraTags = 0;
    2152                 :     OSMTag pasExtraTags[1 + MAX_COUNT_FOR_TAGS_IN_WAY];
    2153                 : 
    2154              34 :     if( bMultiPolygon )
    2155                 :     {
    2156              26 :         if( !bInterestingTagFound )
    2157                 :         {
    2158              18 :             poGeom = BuildMultiPolygon(psRelation, &nExtraTags, pasExtraTags);
    2159              18 :             CPLAssert(nExtraTags <= MAX_COUNT_FOR_TAGS_IN_WAY);
    2160              18 :             pasExtraTags[nExtraTags].pszK = "type";
    2161              18 :             pasExtraTags[nExtraTags].pszV = pszTypeV;
    2162              18 :             nExtraTags ++;
    2163                 :         }
    2164                 :         else
    2165               8 :             poGeom = BuildMultiPolygon(psRelation, NULL, NULL);
    2166                 :     }
    2167                 :     else
    2168               8 :         poGeom = BuildGeometryCollection(psRelation, bMultiLineString);
    2169                 : 
    2170              34 :     if( poGeom != NULL )
    2171                 :     {
    2172                 :         int bAttrFilterAlreadyEvaluated;
    2173              25 :         if( poFeature == NULL )
    2174                 :         {
    2175              22 :             poFeature = new OGRFeature(papoLayers[iCurLayer]->GetLayerDefn());
    2176                 : 
    2177              22 :             papoLayers[iCurLayer]->SetFieldsFromTags( poFeature,
    2178                 :                                                       psRelation->nID,
    2179                 :                                                       FALSE,
    2180                 :                                                       nExtraTags ? nExtraTags : psRelation->nTags,
    2181                 :                                                       nExtraTags ? pasExtraTags : psRelation->pasTags,
    2182              53 :                                                       &psRelation->sInfo);
    2183                 : 
    2184              22 :             bAttrFilterAlreadyEvaluated = FALSE;
    2185                 :         }
    2186                 :         else
    2187               3 :             bAttrFilterAlreadyEvaluated = TRUE;
    2188                 : 
    2189              25 :         poFeature->SetGeometryDirectly(poGeom);
    2190                 : 
    2191              25 :         int bFilteredOut = FALSE;
    2192              25 :         if( !papoLayers[iCurLayer]->AddFeature( poFeature,
    2193                 :                                                 bAttrFilterAlreadyEvaluated,
    2194                 :                                                 &bFilteredOut ) )
    2195               0 :             bStopParsing = TRUE;
    2196              25 :         else if (!bFilteredOut)
    2197              23 :             bFeatureAdded = TRUE;
    2198                 :     }
    2199                 :     else
    2200               9 :         delete poFeature;
    2201                 : }
    2202                 : 
    2203             100 : static void OGROSMNotifyRelation (OSMRelation* psRelation,
    2204                 :                                   OSMContext* psOSMContext, void* user_data)
    2205                 : {
    2206             100 :     ((OGROSMDataSource*) user_data)->NotifyRelation(psRelation);
    2207             100 : }
    2208                 : 
    2209                 : 
    2210                 : /************************************************************************/
    2211                 : /*                      ProcessPolygonsStandalone()                     */
    2212                 : /************************************************************************/
    2213                 : 
    2214              11 : void OGROSMDataSource::ProcessPolygonsStandalone()
    2215                 : {
    2216              11 :     unsigned int nTags = 0;
    2217                 :     OSMTag pasTags[MAX_COUNT_FOR_TAGS_IN_WAY];
    2218                 :     OSMInfo sInfo;
    2219              11 :     int bFirst = TRUE;
    2220                 : 
    2221              11 :     sInfo.ts.nTimeStamp = 0;
    2222              11 :     sInfo.nChangeset = 0;
    2223              11 :     sInfo.nVersion = 0;
    2224              11 :     sInfo.nUID = 0;
    2225              11 :     sInfo.bTimeStampIsStr = FALSE;
    2226              11 :     sInfo.pszUserSID = "";
    2227                 : 
    2228              11 :     if( !bHasRowInPolygonsStandalone )
    2229              11 :         bHasRowInPolygonsStandalone = (sqlite3_step(hSelectPolygonsStandaloneStmt) == SQLITE_ROW);
    2230                 : 
    2231              34 :     while( bHasRowInPolygonsStandalone &&
    2232               6 :            papoLayers[IDX_LYR_MULTIPOLYGONS]->nFeatureArraySize < 10000 )
    2233                 :     {
    2234               6 :         if( bFirst )
    2235                 :         {
    2236               6 :             CPLDebug("OSM", "Remaining standalone polygons");
    2237               6 :             bFirst = FALSE;
    2238                 :         }
    2239                 : 
    2240               6 :         GIntBig id = sqlite3_column_int(hSelectPolygonsStandaloneStmt, 0);
    2241                 : 
    2242               6 :         sqlite3_bind_int64( pahSelectWayStmt[0], 1, id );
    2243               6 :         if( sqlite3_step(pahSelectWayStmt[0]) == SQLITE_ROW )
    2244                 :         {
    2245               6 :             int nBlobSize = sqlite3_column_bytes(pahSelectWayStmt[0], 1);
    2246               6 :             const void* blob = sqlite3_column_blob(pahSelectWayStmt[0], 1);
    2247                 : 
    2248               6 :             LonLat* pasCoords = (LonLat*) pasLonLatCache;
    2249                 : 
    2250                 :             int nPoints = UncompressWay (nBlobSize, (GByte*) blob,
    2251                 :                                          pasCoords,
    2252               6 :                                          &nTags, pasTags, &sInfo );
    2253               6 :             CPLAssert(nTags <= MAX_COUNT_FOR_TAGS_IN_WAY);
    2254                 : 
    2255                 :             OGRLineString* poLS;
    2256                 : 
    2257               6 :             OGRMultiPolygon* poMulti = new OGRMultiPolygon();
    2258              12 :             OGRPolygon* poPoly = new OGRPolygon();
    2259              12 :             OGRLinearRing* poRing = new OGRLinearRing();
    2260               6 :             poMulti->addGeometryDirectly(poPoly);
    2261               6 :             poPoly->addRingDirectly(poRing);
    2262               6 :             poLS = poRing;
    2263                 : 
    2264               6 :             poLS->setNumPoints(nPoints);
    2265              36 :             for(int j=0;j<nPoints;j++)
    2266                 :             {
    2267                 :                 poLS->setPoint( j,
    2268              30 :                                 INT_TO_DBL(pasCoords[j].nLon),
    2269              60 :                                 INT_TO_DBL(pasCoords[j].nLat) );
    2270                 :             }
    2271                 : 
    2272               6 :             OGRFeature* poFeature = new OGRFeature(papoLayers[IDX_LYR_MULTIPOLYGONS]->GetLayerDefn());
    2273                 : 
    2274               6 :             papoLayers[IDX_LYR_MULTIPOLYGONS]->SetFieldsFromTags( poFeature,
    2275                 :                                                                   id,
    2276                 :                                                                   TRUE,
    2277                 :                                                                   nTags,
    2278                 :                                                                   pasTags,
    2279              12 :                                                                   &sInfo);
    2280                 : 
    2281               6 :             poFeature->SetGeometryDirectly(poMulti);
    2282                 : 
    2283               6 :             int bFilteredOut = FALSE;
    2284               6 :             if( !papoLayers[IDX_LYR_MULTIPOLYGONS]->AddFeature( poFeature,
    2285                 :                                                     FALSE,
    2286                 :                                                     &bFilteredOut ) )
    2287                 :             {
    2288               0 :                 bStopParsing = TRUE;
    2289               0 :                 break;
    2290                 :             }
    2291               6 :             else if (!bFilteredOut)
    2292               6 :                 bFeatureAdded = TRUE;
    2293                 : 
    2294                 :         }
    2295                 :         else
    2296               0 :             CPLAssert(FALSE);
    2297                 : 
    2298               6 :         sqlite3_reset(pahSelectWayStmt[0]);
    2299                 : 
    2300               6 :         bHasRowInPolygonsStandalone = (sqlite3_step(hSelectPolygonsStandaloneStmt) == SQLITE_ROW);
    2301                 :     }
    2302              11 : }
    2303                 : 
    2304                 : /************************************************************************/
    2305                 : /*                             NotifyBounds()                           */
    2306                 : /************************************************************************/
    2307                 : 
    2308               1 : void OGROSMDataSource::NotifyBounds (double dfXMin, double dfYMin,
    2309                 :                                      double dfXMax, double dfYMax)
    2310                 : {
    2311               1 :     sExtent.MinX = dfXMin;
    2312               1 :     sExtent.MinY = dfYMin;
    2313               1 :     sExtent.MaxX = dfXMax;
    2314               1 :     sExtent.MaxY = dfYMax;
    2315               1 :     bExtentValid = TRUE;
    2316                 : 
    2317                 :     CPLDebug("OSM", "Got bounds : minx=%f, miny=%f, maxx=%f, maxy=%f",
    2318               1 :              dfXMin, dfYMin, dfXMax, dfYMax);
    2319               1 : }
    2320                 : 
    2321               1 : static void OGROSMNotifyBounds( double dfXMin, double dfYMin,
    2322                 :                                 double dfXMax, double dfYMax,
    2323                 :                                 OSMContext* psCtxt, void* user_data )
    2324                 : {
    2325                 :     ((OGROSMDataSource*) user_data)->NotifyBounds(dfXMin, dfYMin,
    2326               1 :                                                   dfXMax, dfYMax);
    2327               1 : }
    2328                 : 
    2329                 : /************************************************************************/
    2330                 : /*                                Open()                                */
    2331                 : /************************************************************************/
    2332                 : 
    2333             134 : int OGROSMDataSource::Open( const char * pszFilename, int bUpdateIn)
    2334                 : 
    2335                 : {
    2336             134 :     const char* pszExt = CPLGetExtension(pszFilename);
    2337             134 :     if( !EQUAL(pszExt, "pbf") &&
    2338                 :         !EQUAL(pszExt, "osm") &&
    2339                 :         !EQUALN(pszFilename, "/vsicurl_streaming/", strlen("/vsicurl_streaming/")) &&
    2340                 :         strcmp(pszFilename, "/vsistdin/") != 0 &&
    2341                 :         strcmp(pszFilename, "/dev/stdin/") != 0 )
    2342             124 :         return FALSE;
    2343                 : 
    2344              10 :     pszName = CPLStrdup( pszFilename );
    2345                 : 
    2346                 :     psParser = OSM_Open( pszName,
    2347                 :                          OGROSMNotifyNodes,
    2348                 :                          OGROSMNotifyWay,
    2349                 :                          OGROSMNotifyRelation,
    2350                 :                          OGROSMNotifyBounds,
    2351              10 :                          this );
    2352              10 :     if( psParser == NULL )
    2353               0 :         return FALSE;
    2354                 : 
    2355              10 :     if (bUpdateIn)
    2356                 :     {
    2357                 :         CPLError(CE_Failure, CPLE_NotSupported,
    2358               0 :                  "OGR/OSM driver does not support opening a file in update mode");
    2359               0 :         return FALSE;
    2360                 :     }
    2361                 : 
    2362                 :     /* The following 4 config options are only usefull for debugging */
    2363              10 :     bIndexPoints = CSLTestBoolean(CPLGetConfigOption("OSM_INDEX_POINTS", "YES"));
    2364              10 :     bUsePointsIndex = CSLTestBoolean(CPLGetConfigOption("OSM_USE_POINTS_INDEX", "YES"));
    2365              10 :     bIndexWays = CSLTestBoolean(CPLGetConfigOption("OSM_INDEX_WAYS", "YES"));
    2366              10 :     bUseWaysIndex = CSLTestBoolean(CPLGetConfigOption("OSM_USE_WAYS_INDEX", "YES"));
    2367                 : 
    2368              10 :     bCustomIndexing = CSLTestBoolean(CPLGetConfigOption("OSM_USE_CUSTOM_INDEXING", "YES"));
    2369              10 :     if( !bCustomIndexing )
    2370               1 :         CPLDebug("OSM", "Using SQLite indexing for points");
    2371              10 :     bCompressNodes = CSLTestBoolean(CPLGetConfigOption("OSM_COMPRESS_NODES", "NO"));
    2372              10 :     if( bCompressNodes )
    2373               1 :         CPLDebug("OSM", "Using compression for nodes DB");
    2374                 : 
    2375              10 :     nLayers = 5;
    2376              10 :     papoLayers = (OGROSMLayer**) CPLMalloc(nLayers * sizeof(OGROSMLayer*));
    2377                 : 
    2378              10 :     papoLayers[IDX_LYR_POINTS] = new OGROSMLayer(this, "points");
    2379              10 :     papoLayers[IDX_LYR_POINTS]->GetLayerDefn()->SetGeomType(wkbPoint);
    2380                 : 
    2381              20 :     papoLayers[IDX_LYR_LINES] = new OGROSMLayer(this, "lines");
    2382              10 :     papoLayers[IDX_LYR_LINES]->GetLayerDefn()->SetGeomType(wkbLineString);
    2383                 : 
    2384              20 :     papoLayers[IDX_LYR_MULTILINESTRINGS] = new OGROSMLayer(this, "multilinestrings");
    2385              10 :     papoLayers[IDX_LYR_MULTILINESTRINGS]->GetLayerDefn()->SetGeomType(wkbMultiLineString);
    2386                 : 
    2387              20 :     papoLayers[IDX_LYR_MULTIPOLYGONS] = new OGROSMLayer(this, "multipolygons");
    2388              10 :     papoLayers[IDX_LYR_MULTIPOLYGONS]->GetLayerDefn()->SetGeomType(wkbMultiPolygon);
    2389                 : 
    2390              20 :     papoLayers[IDX_LYR_OTHER_RELATIONS] = new OGROSMLayer(this, "other_relations");
    2391              10 :     papoLayers[IDX_LYR_OTHER_RELATIONS]->GetLayerDefn()->SetGeomType(wkbGeometryCollection);
    2392                 : 
    2393              10 :     if( !ParseConf() )
    2394                 :     {
    2395                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2396               0 :                  "Could not parse configuration file for OSM import");
    2397               0 :         return FALSE;
    2398                 :     }
    2399                 : 
    2400                 :     bNeedsToSaveWayInfo =
    2401              10 :         ( papoLayers[IDX_LYR_MULTIPOLYGONS]->HasTimestamp() ||
    2402              10 :           papoLayers[IDX_LYR_MULTIPOLYGONS]->HasChangeset() ||
    2403              10 :           papoLayers[IDX_LYR_MULTIPOLYGONS]->HasVersion() ||
    2404              10 :           papoLayers[IDX_LYR_MULTIPOLYGONS]->HasUID() ||
    2405              50 :           papoLayers[IDX_LYR_MULTIPOLYGONS]->HasUser() );
    2406                 : 
    2407              10 :     pasLonLatCache = (LonLat*)VSIMalloc(MAX_NODES_PER_WAY * sizeof(LonLat));
    2408              10 :     pabyWayBuffer = (GByte*)VSIMalloc(WAY_BUFFER_SIZE);
    2409                 : 
    2410              10 :     panReqIds = (GIntBig*)VSIMalloc(MAX_ACCUMULATED_NODES * sizeof(GIntBig));
    2411              10 :     pasLonLatArray = (LonLat*)VSIMalloc(MAX_ACCUMULATED_NODES * sizeof(LonLat));
    2412              10 :     panUnsortedReqIds = (GIntBig*)VSIMalloc(MAX_ACCUMULATED_NODES * sizeof(GIntBig));
    2413              10 :     pasWayFeaturePairs = (WayFeaturePair*)VSIMalloc(MAX_DELAYED_FEATURES * sizeof(WayFeaturePair));
    2414              10 :     pasAccumulatedTags = (IndexedKVP*) VSIMalloc(MAX_ACCUMULATED_TAGS * sizeof(IndexedKVP));
    2415              10 :     pabyNonRedundantValues = (GByte*) VSIMalloc(MAX_NON_REDUNDANT_VALUES);
    2416                 : 
    2417              10 :     if( pasLonLatCache == NULL ||
    2418                 :         pabyWayBuffer == NULL ||
    2419                 :         panReqIds == NULL ||
    2420                 :         pasLonLatArray == NULL ||
    2421                 :         panUnsortedReqIds == NULL ||
    2422                 :         pasWayFeaturePairs == NULL ||
    2423                 :         pasAccumulatedTags == NULL ||
    2424                 :         pabyNonRedundantValues == NULL )
    2425                 :     {
    2426                 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    2427               0 :                  "Out-of-memory when allocating one of the buffer used for the processing.");
    2428               0 :         return FALSE;
    2429                 :     }
    2430                 : 
    2431              10 :     nMaxSizeForInMemoryDBInMB = atoi(CPLGetConfigOption("OSM_MAX_TMPFILE_SIZE", "100"));
    2432              10 :     GIntBig nSize = (GIntBig)nMaxSizeForInMemoryDBInMB * 1024 * 1024;
    2433              10 :     if (nSize < 0 || (GIntBig)(size_t)nSize != nSize)
    2434                 :     {
    2435               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for OSM_MAX_TMPFILE_SIZE. Using 100 instead.");
    2436               0 :         nMaxSizeForInMemoryDBInMB = 100;
    2437               0 :         nSize = (GIntBig)nMaxSizeForInMemoryDBInMB * 1024 * 1024;
    2438                 :     }
    2439                 : 
    2440              10 :     if( bCustomIndexing )
    2441                 :     {
    2442               9 :         pabySector = (GByte*) VSICalloc(1, SECTOR_SIZE);
    2443               9 :         papsBuckets = (Bucket*) VSIMalloc(sizeof(Bucket) * BUCKET_COUNT);
    2444                 :         size_t i;
    2445               9 :         int bOOM = FALSE;
    2446               9 :         if( papsBuckets )
    2447                 :         {
    2448          589833 :             for(i = 0; i < BUCKET_COUNT && !bOOM; i++)
    2449                 :             {
    2450          589824 :                 papsBuckets[i].nOff = -1;
    2451          589824 :                 if( bCompressNodes )
    2452                 :                 {
    2453           65536 :                     papsBuckets[i].u.panSectorSize = (GByte*)VSICalloc(1, BUCKET_SECTOR_SIZE_ARRAY_SIZE);
    2454           65536 :                     if( papsBuckets[i].u.panSectorSize == NULL )
    2455               0 :                         bOOM = TRUE;
    2456                 :                 }
    2457                 :                 else
    2458                 :                 {
    2459          524288 :                     papsBuckets[i].u.pabyBitmap = (GByte*)VSICalloc(1, BUCKET_BITMAP_SIZE);
    2460          524288 :                     if( papsBuckets[i].u.pabyBitmap == NULL )
    2461               0 :                         bOOM = TRUE;
    2462                 :                 }
    2463                 :             }
    2464                 :         }
    2465                 : 
    2466               9 :         if( pabySector == NULL || papsBuckets == NULL || bOOM )
    2467                 :         {
    2468                 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    2469               0 :                     "Out-of-memory when allocating one of the buffer used for the processing.");
    2470               0 :             return FALSE;
    2471                 :         }
    2472                 : 
    2473               9 :         bInMemoryNodesFile = TRUE;
    2474               9 :         osNodesFilename.Printf("/vsimem/osm_importer/osm_temp_nodes_%p", this);
    2475               9 :         fpNodes = VSIFOpenL(osNodesFilename, "wb+");
    2476               9 :         if( fpNodes == NULL )
    2477                 :         {
    2478               0 :             return FALSE;
    2479                 :         }
    2480                 : 
    2481               9 :         CPLPushErrorHandler(CPLQuietErrorHandler);
    2482               9 :         int bSuccess = VSIFSeekL(fpNodes, (vsi_l_offset) (nSize * 3 / 4), SEEK_SET) == 0;
    2483               9 :         CPLPopErrorHandler();
    2484                 : 
    2485               9 :         if( bSuccess )
    2486                 :         {
    2487               9 :             VSIFSeekL(fpNodes, 0, SEEK_SET);
    2488               9 :             VSIFTruncateL(fpNodes, 0);
    2489                 :         }
    2490                 :         else
    2491                 :         {
    2492               0 :             CPLDebug("OSM", "Not enough memory for in-memory file. Using disk temporary file instead.");
    2493                 : 
    2494               0 :             VSIFCloseL(fpNodes);
    2495               0 :             fpNodes = NULL;
    2496               0 :             VSIUnlink(osNodesFilename);
    2497                 : 
    2498               0 :             bInMemoryNodesFile = FALSE;
    2499               0 :             osNodesFilename = CPLGenerateTempFilename("osm_tmp_nodes");
    2500                 : 
    2501               0 :             fpNodes = VSIFOpenL(osNodesFilename, "wb+");
    2502               0 :             if( fpNodes == NULL )
    2503                 :             {
    2504               0 :                 return FALSE;
    2505                 :             }
    2506                 : 
    2507                 :             /* On Unix filesystems, you can remove a file even if it */
    2508                 :             /* opened */
    2509               0 :             const char* pszVal = CPLGetConfigOption("OSM_UNLINK_TMPFILE", "YES");
    2510               0 :             if( EQUAL(pszVal, "YES") )
    2511                 :             {
    2512               0 :                 CPLPushErrorHandler(CPLQuietErrorHandler);
    2513               0 :                 bMustUnlinkNodesFile = VSIUnlink( osNodesFilename ) != 0;
    2514               0 :                 CPLPopErrorHandler();
    2515                 :             }
    2516                 : 
    2517               0 :             return FALSE;
    2518                 :         }
    2519                 :     }
    2520                 : 
    2521              10 :     int bRet = CreateTempDB();
    2522              10 :     if( bRet )
    2523                 :     {
    2524              10 :         CPLString osInterestLayers = GetInterestLayersForDSName(GetName());
    2525              10 :         if( osInterestLayers.size() )
    2526                 :         {
    2527               1 :             ExecuteSQL( osInterestLayers, NULL, NULL );
    2528              10 :         }
    2529                 :     }
    2530              10 :     return bRet;
    2531                 : }
    2532                 : 
    2533                 : /************************************************************************/
    2534                 : /*                             CreateTempDB()                           */
    2535                 : /************************************************************************/
    2536                 : 
    2537              10 : int OGROSMDataSource::CreateTempDB()
    2538                 : {
    2539              10 :     char* pszErrMsg = NULL;
    2540                 : 
    2541              10 :     int rc = 0;
    2542              10 :     int bIsExisting = FALSE;
    2543              10 :     int bSuccess = FALSE;
    2544                 : 
    2545                 : #ifdef HAVE_SQLITE_VFS
    2546              10 :     const char* pszExistingTmpFile = CPLGetConfigOption("OSM_EXISTING_TMPFILE", NULL);
    2547              10 :     if ( pszExistingTmpFile != NULL )
    2548                 :     {
    2549               0 :         bSuccess = TRUE;
    2550               0 :         bIsExisting = TRUE;
    2551                 :         rc = sqlite3_open_v2( pszExistingTmpFile, &hDB,
    2552                 :                               SQLITE_OPEN_READWRITE | SQLITE_OPEN_NOMUTEX,
    2553               0 :                               NULL );
    2554                 :     }
    2555                 :     else
    2556                 :     {
    2557              10 :         osTmpDBName.Printf("/vsimem/osm_importer/osm_temp_%p.sqlite", this);
    2558                 : 
    2559                 :         /* On 32 bit, the virtual memory space is scarce, so we need to reserve it right now */
    2560                 :         /* Won't hurt on 64 bit either. */
    2561              10 :         VSILFILE* fp = VSIFOpenL(osTmpDBName, "wb");
    2562              10 :         if( fp )
    2563                 :         {
    2564              10 :             GIntBig nSize = (GIntBig)nMaxSizeForInMemoryDBInMB * 1024 * 1024;
    2565              10 :             if( bCustomIndexing && bInMemoryNodesFile )
    2566               9 :                 nSize = nSize * 1 / 4;
    2567                 : 
    2568              10 :             CPLPushErrorHandler(CPLQuietErrorHandler);
    2569              10 :             bSuccess = VSIFSeekL(fp, (vsi_l_offset) nSize, SEEK_SET) == 0;
    2570              10 :             CPLPopErrorHandler();
    2571                 : 
    2572              10 :             if( bSuccess )
    2573              10 :                  VSIFTruncateL(fp, 0);
    2574                 : 
    2575              10 :             VSIFCloseL(fp);
    2576                 : 
    2577              10 :             if( !bSuccess )
    2578                 :             {
    2579               0 :                 CPLDebug("OSM", "Not enough memory for in-memory file. Using disk temporary file instead.");
    2580               0 :                 VSIUnlink(osTmpDBName);
    2581                 :             }
    2582                 :         }
    2583                 : 
    2584              10 :         if( bSuccess )
    2585                 :         {
    2586              10 :             bInMemoryTmpDB = TRUE;
    2587              10 :             pMyVFS = OGRSQLiteCreateVFS(NULL, this);
    2588              10 :             sqlite3_vfs_register(pMyVFS, 0);
    2589                 :             rc = sqlite3_open_v2( osTmpDBName.c_str(), &hDB,
    2590                 :                                 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX,
    2591              10 :                                 pMyVFS->zName );
    2592                 :         }
    2593                 :     }
    2594                 : #endif
    2595                 : 
    2596              10 :     if( !bSuccess )
    2597                 :     {
    2598               0 :         osTmpDBName = CPLGenerateTempFilename("osm_tmp");
    2599               0 :         rc = sqlite3_open( osTmpDBName.c_str(), &hDB );
    2600                 : 
    2601                 :         /* On Unix filesystems, you can remove a file even if it */
    2602                 :         /* opened */
    2603               0 :         if( rc == SQLITE_OK )
    2604                 :         {
    2605               0 :             const char* pszVal = CPLGetConfigOption("OSM_UNLINK_TMPFILE", "YES");
    2606               0 :             if( EQUAL(pszVal, "YES") )
    2607                 :             {
    2608               0 :                 CPLPushErrorHandler(CPLQuietErrorHandler);
    2609               0 :                 bMustUnlink = VSIUnlink( osTmpDBName ) != 0;
    2610               0 :                 CPLPopErrorHandler();
    2611                 :             }
    2612                 :         }
    2613                 :     }
    2614                 : 
    2615              10 :     if( rc != SQLITE_OK )
    2616                 :     {
    2617                 :         CPLError( CE_Failure, CPLE_OpenFailed,
    2618                 :                   "sqlite3_open(%s) failed: %s",
    2619               0 :                   osTmpDBName.c_str(), sqlite3_errmsg( hDB ) );
    2620               0 :         return FALSE;
    2621                 :     }
    2622                 : 
    2623              10 :     if( !SetDBOptions() )
    2624                 :     {
    2625               0 :         return FALSE;
    2626                 :     }
    2627                 : 
    2628              10 :     if( !bIsExisting )
    2629                 :     {
    2630                 :         rc = sqlite3_exec( hDB,
    2631                 :                         "CREATE TABLE nodes (id INTEGER PRIMARY KEY, coords BLOB)",
    2632              10 :                         NULL, NULL, &pszErrMsg );
    2633              10 :         if( rc != SQLITE_OK )
    2634                 :         {
    2635                 :             CPLError( CE_Failure, CPLE_AppDefined,
    2636               0 :                     "Unable to create table nodes : %s", pszErrMsg );
    2637               0 :             sqlite3_free( pszErrMsg );
    2638               0 :             return FALSE;
    2639                 :         }
    2640                 : 
    2641                 :         rc = sqlite3_exec( hDB,
    2642                 :                         "CREATE TABLE ways (id INTEGER PRIMARY KEY, data BLOB)",
    2643              10 :                         NULL, NULL, &pszErrMsg );
    2644              10 :         if( rc != SQLITE_OK )
    2645                 :         {
    2646                 :             CPLError( CE_Failure, CPLE_AppDefined,
    2647               0 :                     "Unable to create table ways : %s", pszErrMsg );
    2648               0 :             sqlite3_free( pszErrMsg );
    2649               0 :             return FALSE;
    2650                 :         }
    2651                 : 
    2652                 :         rc = sqlite3_exec( hDB,
    2653                 :                         "CREATE TABLE polygons_standalone (id INTEGER PRIMARY KEY)",
    2654              10 :                         NULL, NULL, &pszErrMsg );
    2655              10 :         if( rc != SQLITE_OK )
    2656                 :         {
    2657                 :             CPLError( CE_Failure, CPLE_AppDefined,
    2658               0 :                     "Unable to create table polygons_standalone : %s", pszErrMsg );
    2659               0 :             sqlite3_free( pszErrMsg );
    2660               0 :             return FALSE;
    2661                 :         }
    2662                 :     }
    2663                 : 
    2664              10 :     return CreatePreparedStatements();
    2665                 : }
    2666                 : /************************************************************************/
    2667                 : /*                            SetDBOptions()                            */
    2668                 : /************************************************************************/
    2669                 : 
    2670              10 : int OGROSMDataSource::SetDBOptions()
    2671                 : {
    2672              10 :     char* pszErrMsg = NULL;
    2673                 :     int rc;
    2674                 : 
    2675              10 :     rc = sqlite3_exec( hDB, "PRAGMA synchronous = OFF", NULL, NULL, &pszErrMsg );
    2676              10 :     if( rc != SQLITE_OK )
    2677                 :     {
    2678                 :         CPLError( CE_Failure, CPLE_AppDefined,
    2679                 :                     "Unable to run PRAGMA synchronous : %s",
    2680               0 :                     pszErrMsg );
    2681               0 :         sqlite3_free( pszErrMsg );
    2682               0 :         return FALSE;
    2683                 :     }
    2684                 : 
    2685              10 :     rc = sqlite3_exec( hDB, "PRAGMA journal_mode = OFF", NULL, NULL, &pszErrMsg );
    2686              10 :     if( rc != SQLITE_OK )
    2687                 :     {
    2688                 :         CPLError( CE_Failure, CPLE_AppDefined,
    2689                 :                     "Unable to run PRAGMA journal_mode : %s",
    2690               0 :                     pszErrMsg );
    2691               0 :         sqlite3_free( pszErrMsg );
    2692               0 :         return FALSE;
    2693                 :     }
    2694                 : 
    2695              10 :     rc = sqlite3_exec( hDB, "PRAGMA temp_store = MEMORY", NULL, NULL, &pszErrMsg );
    2696              10 :     if( rc != SQLITE_OK )
    2697                 :     {
    2698                 :         CPLError( CE_Failure, CPLE_AppDefined,
    2699                 :                     "Unable to run PRAGMA temp_store : %s",
    2700               0 :                     pszErrMsg );
    2701               0 :         sqlite3_free( pszErrMsg );
    2702               0 :         return FALSE;
    2703                 :     }
    2704                 : 
    2705              10 :     if( !SetCacheSize() )
    2706               0 :         return FALSE;
    2707                 : 
    2708              10 :     if( !StartTransaction() )
    2709               0 :         return FALSE;
    2710                 : 
    2711              10 :     return TRUE;
    2712                 : }
    2713                 : 
    2714                 : /************************************************************************/
    2715                 : /*                              SetCacheSize()                          */
    2716                 : /************************************************************************/
    2717                 : 
    2718              10 : int OGROSMDataSource::SetCacheSize()
    2719                 : {
    2720                 :     int rc;
    2721              10 :     const char* pszSqliteCacheMB = CPLGetConfigOption("OSM_SQLITE_CACHE", NULL);
    2722              10 :     if (pszSqliteCacheMB != NULL)
    2723                 :     {
    2724               0 :         char* pszErrMsg = NULL;
    2725                 :         char **papszResult;
    2726                 :         int nRowCount, nColCount;
    2727                 :         int iSqliteCachePages;
    2728               0 :         int iSqlitePageSize = -1;
    2729               0 :         int iSqliteCacheBytes = atoi( pszSqliteCacheMB ) * 1024 * 1024;
    2730                 : 
    2731                 :         /* querying the current PageSize */
    2732                 :         rc = sqlite3_get_table( hDB, "PRAGMA page_size",
    2733                 :                                 &papszResult, &nRowCount, &nColCount,
    2734               0 :                                 &pszErrMsg );
    2735               0 :         if( rc == SQLITE_OK )
    2736                 :         {
    2737                 :             int iRow;
    2738               0 :             for (iRow = 1; iRow <= nRowCount; iRow++)
    2739                 :             {
    2740               0 :                 iSqlitePageSize = atoi( papszResult[(iRow * nColCount) + 0] );
    2741                 :             }
    2742               0 :             sqlite3_free_table(papszResult);
    2743                 :         }
    2744               0 :         if( iSqlitePageSize < 0 )
    2745                 :         {
    2746                 :             CPLError( CE_Failure, CPLE_AppDefined,
    2747                 :                       "Unable to run PRAGMA page_size : %s",
    2748               0 :                       pszErrMsg ? pszErrMsg : sqlite3_errmsg(hDB) );
    2749               0 :             sqlite3_free( pszErrMsg );
    2750               0 :             return TRUE;
    2751                 :         }
    2752                 : 
    2753                 :         /* computing the CacheSize as #Pages */
    2754               0 :         iSqliteCachePages = iSqliteCacheBytes / iSqlitePageSize;
    2755               0 :         if( iSqliteCachePages <= 0)
    2756               0 :             return TRUE;
    2757                 : 
    2758                 :         rc = sqlite3_exec( hDB, CPLSPrintf( "PRAGMA cache_size = %d",
    2759                 :                                             iSqliteCachePages ),
    2760               0 :                            NULL, NULL, &pszErrMsg );
    2761               0 :         if( rc != SQLITE_OK )
    2762                 :         {
    2763                 :             CPLError( CE_Warning, CPLE_AppDefined,
    2764                 :                       "Unrecognized value for PRAGMA cache_size : %s",
    2765               0 :                       pszErrMsg );
    2766               0 :             sqlite3_free( pszErrMsg );
    2767               0 :             rc = SQLITE_OK;
    2768                 :         }
    2769                 :     }
    2770              10 :     return TRUE;
    2771                 : }
    2772                 : 
    2773                 : /************************************************************************/
    2774                 : /*                        CreatePreparedStatements()                    */
    2775                 : /************************************************************************/
    2776                 : 
    2777              10 : int OGROSMDataSource::CreatePreparedStatements()
    2778                 : {
    2779                 :     int rc;
    2780                 : 
    2781                 :     rc = sqlite3_prepare( hDB, "INSERT INTO nodes (id, coords) VALUES (?,?)", -1,
    2782              10 :                           &hInsertNodeStmt, NULL );
    2783              10 :     if( rc != SQLITE_OK )
    2784                 :     {
    2785                 :         CPLError( CE_Failure, CPLE_AppDefined,
    2786               0 :                   "sqlite3_prepare() failed :  %s", sqlite3_errmsg(hDB) );
    2787               0 :         return FALSE;
    2788                 :     }
    2789                 : 
    2790              10 :     pahSelectNodeStmt = (sqlite3_stmt**) CPLCalloc(sizeof(sqlite3_stmt*), LIMIT_IDS_PER_REQUEST);
    2791                 : 
    2792                 :     char szTmp[LIMIT_IDS_PER_REQUEST*2 + 128];
    2793              10 :     strcpy(szTmp, "SELECT id, coords FROM nodes WHERE id IN (");
    2794              10 :     int nLen = strlen(szTmp);
    2795            2010 :     for(int i=0;i<LIMIT_IDS_PER_REQUEST;i++)
    2796                 :     {
    2797            2000 :         if(i == 0)
    2798                 :         {
    2799              10 :             strcpy(szTmp + nLen, "?) ORDER BY id ASC");
    2800              10 :             nLen += 2;
    2801                 :         }
    2802                 :         else
    2803                 :         {
    2804            1990 :             strcpy(szTmp + nLen -1, ",?) ORDER BY id ASC");
    2805            1990 :             nLen += 2;
    2806                 :         }
    2807            2000 :         rc = sqlite3_prepare( hDB, szTmp, -1, &pahSelectNodeStmt[i], NULL );
    2808            2000 :         if( rc != SQLITE_OK )
    2809                 :         {
    2810                 :             CPLError( CE_Failure, CPLE_AppDefined,
    2811               0 :                     "sqlite3_prepare() failed :  %s", sqlite3_errmsg(hDB) );
    2812               0 :             return FALSE;
    2813                 :         }
    2814                 :     }
    2815                 : 
    2816                 :     rc = sqlite3_prepare( hDB, "INSERT INTO ways (id, data) VALUES (?,?)", -1,
    2817              10 :                           &hInsertWayStmt, NULL );
    2818              10 :     if( rc != SQLITE_OK )
    2819                 :     {
    2820                 :         CPLError( CE_Failure, CPLE_AppDefined,
    2821               0 :                   "sqlite3_prepare() failed :  %s", sqlite3_errmsg(hDB) );
    2822               0 :         return FALSE;
    2823                 :     }
    2824                 : 
    2825              10 :     pahSelectWayStmt = (sqlite3_stmt**) CPLCalloc(sizeof(sqlite3_stmt*), LIMIT_IDS_PER_REQUEST);
    2826                 : 
    2827              10 :     strcpy(szTmp, "SELECT id, data FROM ways WHERE id IN (");
    2828              10 :     nLen = strlen(szTmp);
    2829            2010 :     for(int i=0;i<LIMIT_IDS_PER_REQUEST;i++)
    2830                 :     {
    2831            2000 :         if(i == 0)
    2832                 :         {
    2833              10 :             strcpy(szTmp + nLen, "?)");
    2834              10 :             nLen += 2;
    2835                 :         }
    2836                 :         else
    2837                 :         {
    2838            1990 :             strcpy(szTmp + nLen -1, ",?)");
    2839            1990 :             nLen += 2;
    2840                 :         }
    2841            2000 :         rc = sqlite3_prepare( hDB, szTmp, -1, &pahSelectWayStmt[i], NULL );
    2842            2000 :         if( rc != SQLITE_OK )
    2843                 :         {
    2844                 :             CPLError( CE_Failure, CPLE_AppDefined,
    2845               0 :                     "sqlite3_prepare() failed :  %s", sqlite3_errmsg(hDB) );
    2846               0 :             return FALSE;
    2847                 :         }
    2848                 :     }
    2849                 : 
    2850                 :     rc = sqlite3_prepare( hDB, "INSERT INTO polygons_standalone (id) VALUES (?)", -1,
    2851              10 :                           &hInsertPolygonsStandaloneStmt, NULL );
    2852              10 :     if( rc != SQLITE_OK )
    2853                 :     {
    2854                 :         CPLError( CE_Failure, CPLE_AppDefined,
    2855               0 :                   "sqlite3_prepare() failed :  %s", sqlite3_errmsg(hDB) );
    2856               0 :         return FALSE;
    2857                 :     }
    2858                 : 
    2859                 :     rc = sqlite3_prepare( hDB, "DELETE FROM polygons_standalone WHERE id = ?", -1,
    2860              10 :                           &hDeletePolygonsStandaloneStmt, NULL );
    2861              10 :     if( rc != SQLITE_OK )
    2862                 :     {
    2863                 :         CPLError( CE_Failure, CPLE_AppDefined,
    2864               0 :                   "sqlite3_prepare() failed :  %s", sqlite3_errmsg(hDB) );
    2865               0 :         return FALSE;
    2866                 :     }
    2867                 : 
    2868                 :     rc = sqlite3_prepare( hDB, "SELECT id FROM polygons_standalone ORDER BY id", -1,
    2869              10 :                           &hSelectPolygonsStandaloneStmt, NULL );
    2870              10 :     if( rc != SQLITE_OK )
    2871                 :     {
    2872                 :         CPLError( CE_Failure, CPLE_AppDefined,
    2873               0 :                 "sqlite3_prepare() failed :  %s", sqlite3_errmsg(hDB) );
    2874               0 :         return FALSE;
    2875                 :     }
    2876                 : 
    2877              10 :     return TRUE;
    2878                 : }
    2879                 : 
    2880                 : /************************************************************************/
    2881                 : /*                           StartTransaction()                         */
    2882                 : /************************************************************************/
    2883                 : 
    2884              10 : int OGROSMDataSource::StartTransaction()
    2885                 : {
    2886              10 :     if( bInTransaction )
    2887               0 :         return FALSE;
    2888                 : 
    2889              10 :     char* pszErrMsg = NULL;
    2890              10 :     int rc = sqlite3_exec( hDB, "BEGIN", NULL, NULL, &pszErrMsg );
    2891              10 :     if( rc != SQLITE_OK )
    2892                 :     {
    2893                 :         CPLError( CE_Failure, CPLE_AppDefined,
    2894               0 :                   "Unable to start transaction : %s", pszErrMsg );
    2895               0 :         sqlite3_free( pszErrMsg );
    2896               0 :         return FALSE;
    2897                 :     }
    2898                 : 
    2899              10 :     bInTransaction = TRUE;
    2900                 : 
    2901              10 :     return TRUE;
    2902                 : }
    2903                 : 
    2904                 : /************************************************************************/
    2905                 : /*                           CommitTransaction()                        */
    2906                 : /************************************************************************/
    2907                 : 
    2908              10 : int OGROSMDataSource::CommitTransaction()
    2909                 : {
    2910              10 :     if( !bInTransaction )
    2911               0 :         return FALSE;
    2912                 : 
    2913              10 :     bInTransaction = FALSE;
    2914                 : 
    2915              10 :     char* pszErrMsg = NULL;
    2916              10 :     int rc = sqlite3_exec( hDB, "COMMIT", NULL, NULL, &pszErrMsg );
    2917              10 :     if( rc != SQLITE_OK )
    2918                 :     {
    2919                 :         CPLError( CE_Failure, CPLE_AppDefined,
    2920               0 :                   "Unable to commit transaction : %s", pszErrMsg );
    2921               0 :         sqlite3_free( pszErrMsg );
    2922               0 :         return FALSE;
    2923                 :     }
    2924                 : 
    2925              10 :     return TRUE;
    2926                 : }
    2927                 : 
    2928                 : /************************************************************************/
    2929                 : /*                           ParseConf()                                */
    2930                 : /************************************************************************/
    2931                 : 
    2932              10 : int OGROSMDataSource::ParseConf()
    2933                 : {
    2934              10 :     const char *pszFilename = CPLGetConfigOption("OSM_CONFIG_FILE", NULL);
    2935              10 :     if( pszFilename == NULL )
    2936              10 :         pszFilename = CPLFindFile( "gdal", "osmconf.ini" );
    2937              10 :     if( pszFilename == NULL )
    2938                 :     {
    2939               0 :         CPLError(CE_Warning, CPLE_AppDefined, "Cannot find osmconf.ini configuration file");
    2940               0 :         return FALSE;
    2941                 :     }
    2942                 : 
    2943              10 :     VSILFILE* fpConf = VSIFOpenL(pszFilename, "rb");
    2944              10 :     if( fpConf == NULL )
    2945               0 :         return FALSE;
    2946                 : 
    2947                 :     const char* pszLine;
    2948              10 :     int iCurLayer = -1;
    2949                 : 
    2950                 :     int i;
    2951                 : 
    2952            1020 :     while((pszLine = CPLReadLine2L(fpConf, -1, NULL)) != NULL)
    2953                 :     {
    2954            1000 :         if(pszLine[0] == '[' && pszLine[strlen(pszLine)-1] == ']' )
    2955                 :         {
    2956              50 :             iCurLayer = -1;
    2957              50 :             pszLine ++;
    2958              50 :             ((char*)pszLine)[strlen(pszLine)-1] = '\0'; /* Evil but OK */
    2959             150 :             for(i = 0; i < nLayers; i++)
    2960                 :             {
    2961             150 :                 if( strcmp(pszLine, papoLayers[i]->GetName()) == 0 )
    2962                 :                 {
    2963              50 :                     iCurLayer = i;
    2964              50 :                     break;
    2965                 :                 }
    2966                 :             }
    2967              50 :             if( iCurLayer < 0 )
    2968                 :             {
    2969                 :                 CPLError(CE_Warning, CPLE_AppDefined,
    2970                 :                          "Layer '%s' mentionned in %s is unknown to the driver",
    2971               0 :                          pszLine, pszFilename);
    2972                 :             }
    2973              50 :             continue;
    2974                 :         }
    2975                 : 
    2976             950 :         if( strncmp(pszLine, "closed_ways_are_polygons=",
    2977                 :                     strlen("closed_ways_are_polygons=")) == 0)
    2978                 :         {
    2979              10 :             char** papszTokens = CSLTokenizeString2(pszLine, "=", 0);
    2980              10 :             if( CSLCount(papszTokens) == 2)
    2981                 :             {
    2982              10 :                 char** papszTokens2 = CSLTokenizeString2(papszTokens[1], ",", 0);
    2983             340 :                 for(int i=0;papszTokens2[i] != NULL;i++)
    2984                 :                 {
    2985             160 :                     aoSetClosedWaysArePolygons.insert(papszTokens2[i]);
    2986                 :                 }
    2987              10 :                 CSLDestroy(papszTokens2);
    2988                 :             }
    2989              10 :             CSLDestroy(papszTokens);
    2990                 :         }
    2991                 : 
    2992             940 :         else if(strncmp(pszLine, "report_all_nodes=", strlen("report_all_nodes=")) == 0)
    2993                 :         {
    2994               0 :             if( strcmp(pszLine + strlen("report_all_nodes="), "no") == 0 )
    2995                 :             {
    2996               0 :                 bReportAllNodes = FALSE;
    2997                 :             }
    2998               0 :             else if( strcmp(pszLine + strlen("report_all_nodes="), "yes") == 0 )
    2999                 :             {
    3000               0 :                 bReportAllNodes = TRUE;
    3001                 :             }
    3002                 :         }
    3003                 : 
    3004             940 :         else if(strncmp(pszLine, "report_all_ways=", strlen("report_all_ways=")) == 0)
    3005                 :         {
    3006               0 :             if( strcmp(pszLine + strlen("report_all_ways="), "no") == 0 )
    3007                 :             {
    3008               0 :                 bReportAllWays = FALSE;
    3009                 :             }
    3010               0 :             else if( strcmp(pszLine + strlen("report_all_ways="), "yes") == 0 )
    3011                 :             {
    3012               0 :                 bReportAllWays = TRUE;
    3013                 :             }
    3014                 :         }
    3015                 : 
    3016             940 :         else if(strncmp(pszLine, "attribute_name_laundering=", strlen("attribute_name_laundering=")) == 0)
    3017                 :         {
    3018              10 :             if( strcmp(pszLine + strlen("attribute_name_laundering="), "no") == 0 )
    3019                 :             {
    3020               0 :                 bAttributeNameLaundering = FALSE;
    3021                 :             }
    3022              10 :             else if( strcmp(pszLine + strlen("attribute_name_laundering="), "yes") == 0 )
    3023                 :             {
    3024              10 :                 bAttributeNameLaundering = TRUE;
    3025                 :             }
    3026                 :         }
    3027                 : 
    3028             930 :         else if( iCurLayer >= 0 )
    3029                 :         {
    3030             780 :             char** papszTokens = CSLTokenizeString2(pszLine, "=", 0);
    3031             780 :             if( CSLCount(papszTokens) == 2 && strcmp(papszTokens[0], "other_tags") == 0 )
    3032                 :             {
    3033               0 :                 if( strcmp(papszTokens[1], "no") == 0 )
    3034               0 :                     papoLayers[iCurLayer]->SetHasOtherTags(FALSE);
    3035               0 :                 else if( strcmp(papszTokens[1], "yes") == 0 )
    3036               0 :                     papoLayers[iCurLayer]->SetHasOtherTags(TRUE);
    3037                 :             }
    3038             780 :             else if( CSLCount(papszTokens) == 2 && strcmp(papszTokens[0], "osm_id") == 0 )
    3039                 :             {
    3040              50 :                 if( strcmp(papszTokens[1], "no") == 0 )
    3041               0 :                     papoLayers[iCurLayer]->SetHasOSMId(FALSE);
    3042              50 :                 else if( strcmp(papszTokens[1], "yes") == 0 )
    3043                 :                 {
    3044              50 :                     papoLayers[iCurLayer]->SetHasOSMId(TRUE);
    3045              50 :                     papoLayers[iCurLayer]->AddField("osm_id", OFTString);
    3046                 : 
    3047              50 :                     if( iCurLayer == IDX_LYR_MULTIPOLYGONS )
    3048              10 :                         papoLayers[iCurLayer]->AddField("osm_way_id", OFTString);
    3049                 :                 }
    3050                 :             }
    3051             730 :              else if( CSLCount(papszTokens) == 2 && strcmp(papszTokens[0], "osm_version") == 0 )
    3052                 :             {
    3053              50 :                 if( strcmp(papszTokens[1], "no") == 0 )
    3054              50 :                     papoLayers[iCurLayer]->SetHasVersion(FALSE);
    3055               0 :                 else if( strcmp(papszTokens[1], "yes") == 0 )
    3056                 :                 {
    3057               0 :                     papoLayers[iCurLayer]->SetHasVersion(TRUE);
    3058               0 :                     papoLayers[iCurLayer]->AddField("osm_version", OFTInteger);
    3059                 :                 }
    3060                 :             }
    3061             680 :             else if( CSLCount(papszTokens) == 2 && strcmp(papszTokens[0], "osm_timestamp") == 0 )
    3062                 :             {
    3063              50 :                 if( strcmp(papszTokens[1], "no") == 0 )
    3064              50 :                     papoLayers[iCurLayer]->SetHasTimestamp(FALSE);
    3065               0 :                 else if( strcmp(papszTokens[1], "yes") == 0 )
    3066                 :                 {
    3067               0 :                     papoLayers[iCurLayer]->SetHasTimestamp(TRUE);
    3068               0 :                     papoLayers[iCurLayer]->AddField("osm_timestamp", OFTDateTime);
    3069                 :                 }
    3070                 :             }
    3071             630 :             else if( CSLCount(papszTokens) == 2 && strcmp(papszTokens[0], "osm_uid") == 0 )
    3072                 :             {
    3073              50 :                 if( strcmp(papszTokens[1], "no") == 0 )
    3074              50 :                     papoLayers[iCurLayer]->SetHasUID(FALSE);
    3075               0 :                 else if( strcmp(papszTokens[1], "yes") == 0 )
    3076                 :                 {
    3077               0 :                     papoLayers[iCurLayer]->SetHasUID(TRUE);
    3078               0 :                     papoLayers[iCurLayer]->AddField("osm_uid", OFTInteger);
    3079                 :                 }
    3080                 :             }
    3081             580 :             else if( CSLCount(papszTokens) == 2 && strcmp(papszTokens[0], "osm_user") == 0 )
    3082                 :             {
    3083              50 :                 if( strcmp(papszTokens[1], "no") == 0 )
    3084              50 :                     papoLayers[iCurLayer]->SetHasUser(FALSE);
    3085               0 :                 else if( strcmp(papszTokens[1], "yes") == 0 )
    3086                 :                 {
    3087               0 :                     papoLayers[iCurLayer]->SetHasUser(TRUE);
    3088               0 :                     papoLayers[iCurLayer]->AddField("osm_user", OFTString);
    3089                 :                 }
    3090                 :             }
    3091             530 :             else if( CSLCount(papszTokens) == 2 && strcmp(papszTokens[0], "osm_changeset") == 0 )
    3092                 :             {
    3093              50 :                 if( strcmp(papszTokens[1], "no") == 0 )
    3094              50 :                     papoLayers[iCurLayer]->SetHasChangeset(FALSE);
    3095               0 :                 else if( strcmp(papszTokens[1], "yes") == 0 )
    3096                 :                 {
    3097               0 :                     papoLayers[iCurLayer]->SetHasChangeset(TRUE);
    3098               0 :                     papoLayers[iCurLayer]->AddField("osm_changeset", OFTInteger);
    3099                 :                 }
    3100                 :             }
    3101             480 :             else if( CSLCount(papszTokens) == 2 && strcmp(papszTokens[0], "attributes") == 0 )
    3102                 :             {
    3103              50 :                 char** papszTokens2 = CSLTokenizeString2(papszTokens[1], ",", 0);
    3104             440 :                 for(int i=0;papszTokens2[i] != NULL;i++)
    3105                 :                 {
    3106             390 :                     papoLayers[iCurLayer]->AddField(papszTokens2[i], OFTString);
    3107                 :                 }
    3108              50 :                 CSLDestroy(papszTokens2);
    3109                 :             }
    3110             430 :             else if ( CSLCount(papszTokens) == 2 && strcmp(papszTokens[0], "unsignificant") == 0 )
    3111                 :             {
    3112              10 :                 char** papszTokens2 = CSLTokenizeString2(papszTokens[1], ",", 0);
    3113              60 :                 for(int i=0;papszTokens2[i] != NULL;i++)
    3114                 :                 {
    3115              50 :                     papoLayers[iCurLayer]->AddUnsignificantKey(papszTokens2[i]);
    3116                 :                 }
    3117              10 :                 CSLDestroy(papszTokens2);
    3118                 :             }
    3119             420 :             else if ( CSLCount(papszTokens) == 2 && strcmp(papszTokens[0], "ignore") == 0 )
    3120                 :             {
    3121              50 :                 char** papszTokens2 = CSLTokenizeString2(papszTokens[1], ",", 0);
    3122             530 :                 for(int i=0;papszTokens2[i] != NULL;i++)
    3123                 :                 {
    3124             480 :                     papoLayers[iCurLayer]->AddIgnoreKey(papszTokens2[i]);
    3125             480 :                     papoLayers[iCurLayer]->AddWarnKey(papszTokens2[i]);
    3126                 :                 }
    3127              50 :                 CSLDestroy(papszTokens2);
    3128                 :             }
    3129             780 :             CSLDestroy(papszTokens);
    3130                 :         }
    3131                 :     }
    3132                 : 
    3133              60 :     for(i=0;i<nLayers;i++)
    3134                 :     {
    3135              50 :         if( papoLayers[i]->HasOtherTags() )
    3136              50 :             papoLayers[i]->AddField("other_tags", OFTString);
    3137                 :     }
    3138                 : 
    3139              10 :     VSIFCloseL(fpConf);
    3140                 : 
    3141              10 :     return TRUE;
    3142                 : }
    3143                 : 
    3144                 : /************************************************************************/
    3145                 : /*                           ResetReading()                            */
    3146                 : /************************************************************************/
    3147                 : 
    3148              23 : int OGROSMDataSource::ResetReading()
    3149                 : {
    3150              23 :     if( hDB == NULL )
    3151               0 :         return FALSE;
    3152              23 :     if( bCustomIndexing && fpNodes == NULL )
    3153               0 :         return FALSE;
    3154                 : 
    3155              23 :     OSM_ResetReading(psParser);
    3156                 : 
    3157              23 :     char* pszErrMsg = NULL;
    3158              23 :     int rc = sqlite3_exec( hDB, "DELETE FROM nodes", NULL, NULL, &pszErrMsg );
    3159              23 :     if( rc != SQLITE_OK )
    3160                 :     {
    3161                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3162               0 :                   "Unable to DELETE FROM nodes : %s", pszErrMsg );
    3163               0 :         sqlite3_free( pszErrMsg );
    3164               0 :         return FALSE;
    3165                 :     }
    3166                 : 
    3167              23 :     rc = sqlite3_exec( hDB, "DELETE FROM ways", NULL, NULL, &pszErrMsg );
    3168              23 :     if( rc != SQLITE_OK )
    3169                 :     {
    3170                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3171               0 :                   "Unable to DELETE FROM ways : %s", pszErrMsg );
    3172               0 :         sqlite3_free( pszErrMsg );
    3173               0 :         return FALSE;
    3174                 :     }
    3175                 : 
    3176              23 :     rc = sqlite3_exec( hDB, "DELETE FROM polygons_standalone", NULL, NULL, &pszErrMsg );
    3177              23 :     if( rc != SQLITE_OK )
    3178                 :     {
    3179                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3180               0 :                   "Unable to DELETE FROM polygons_standalone : %s", pszErrMsg );
    3181               0 :         sqlite3_free( pszErrMsg );
    3182               0 :         return FALSE;
    3183                 :     }
    3184              23 :     bHasRowInPolygonsStandalone = FALSE;
    3185                 : 
    3186                 :     {
    3187                 :         int i;
    3188              23 :         for( i = 0; i < nWayFeaturePairs; i++)
    3189                 :         {
    3190               0 :             delete pasWayFeaturePairs[i].poFeature;
    3191                 :         }
    3192              23 :         nWayFeaturePairs = 0;
    3193              23 :         nUnsortedReqIds = 0;
    3194              23 :         nReqIds = 0;
    3195              23 :         nAccumulatedTags = 0;
    3196              23 :         nNonRedundantValuesLen = 0;
    3197                 : 
    3198              29 :         for(i=0;i<(int)asKeys.size();i++)
    3199                 :         {
    3200               6 :             KeyDesc* psKD = asKeys[i];
    3201               6 :             CPLFree(psKD->pszK);
    3202              18 :             for(int j=0;j<(int)psKD->asValues.size();j++)
    3203              12 :                 CPLFree(psKD->asValues[j]);
    3204               6 :             delete psKD;
    3205                 :         }
    3206              23 :         asKeys.resize(0);
    3207              23 :         aoMapIndexedKeys.clear();
    3208              23 :         nNextKeyIndex = 0;
    3209                 :     }
    3210                 : 
    3211              23 :     if( bCustomIndexing )
    3212                 :     {
    3213              23 :         nPrevNodeId = -1;
    3214              23 :         nBucketOld = -1;
    3215              23 :         nOffInBucketReducedOld = -1;
    3216                 : 
    3217              23 :         VSIFSeekL(fpNodes, 0, SEEK_SET);
    3218              23 :         VSIFTruncateL(fpNodes, 0);
    3219              23 :         nNodesFileSize = 0;
    3220                 : 
    3221              23 :         memset(pabySector, 0, SECTOR_SIZE);
    3222         1507351 :         for(int i = 0; i < BUCKET_COUNT; i++)
    3223                 :         {
    3224         1507328 :             papsBuckets[i].nOff = -1;
    3225         1507328 :             if( bCompressNodes )
    3226               0 :                 memset(papsBuckets[i].u.panSectorSize, 0, BUCKET_SECTOR_SIZE_ARRAY_SIZE);
    3227                 :             else
    3228         1507328 :                 memset(papsBuckets[i].u.pabyBitmap, 0, BUCKET_BITMAP_SIZE);
    3229                 :         }
    3230                 :     }
    3231                 : 
    3232             138 :     for(int i=0;i<nLayers;i++)
    3233                 :     {
    3234             115 :         papoLayers[i]->ForceResetReading();
    3235                 :     }
    3236                 : 
    3237              23 :     bStopParsing = FALSE;
    3238                 : 
    3239              23 :     return TRUE;
    3240                 : }
    3241                 : 
    3242                 : /************************************************************************/
    3243                 : /*                           ParseNextChunk()                           */
    3244                 : /************************************************************************/
    3245                 : 
    3246              64 : int OGROSMDataSource::ParseNextChunk()
    3247                 : {
    3248              64 :     if( bStopParsing )
    3249              38 :         return FALSE;
    3250                 : 
    3251              26 :     bHasParsedFirstChunk = TRUE;
    3252              26 :     bFeatureAdded = FALSE;
    3253              23 :     while( TRUE )
    3254                 :     {
    3255                 : #ifdef DEBUG_MEM_USAGE
    3256                 :         static int counter = 0;
    3257                 :         counter ++;
    3258                 :         if ((counter % 1000) == 0)
    3259                 :             CPLDebug("OSM", "GetMaxTotalAllocs() = " CPL_FRMT_GUIB, (GUIntBig)GetMaxTotalAllocs());
    3260                 : #endif
    3261                 : 
    3262              49 :         OSMRetCode eRet = OSM_ProcessBlock(psParser);
    3263              49 :         if( eRet == OSM_EOF || eRet == OSM_ERROR )
    3264                 :         {
    3265              11 :             if( eRet == OSM_EOF )
    3266                 :             {
    3267              11 :                 if( nWayFeaturePairs != 0 )
    3268               0 :                     ProcessWaysBatch();
    3269                 : 
    3270              11 :                 ProcessPolygonsStandalone();
    3271                 : 
    3272              11 :                 if( !bHasRowInPolygonsStandalone )
    3273              11 :                     bStopParsing = TRUE;
    3274                 : 
    3275              11 :                 return bFeatureAdded || bHasRowInPolygonsStandalone;
    3276                 :             }
    3277                 :             else
    3278                 :             {
    3279                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    3280                 :                          "An error occured during the parsing of data around byte " CPL_FRMT_GUIB,
    3281               0 :                          OSM_GetBytesRead(psParser));
    3282                 : 
    3283               0 :                 bStopParsing = TRUE;
    3284               0 :                 return FALSE;
    3285                 :             }
    3286                 :         }
    3287                 :         else
    3288                 :         {
    3289              38 :             if( bInMemoryTmpDB )
    3290                 :             {
    3291              38 :                 if( !TransferToDiskIfNecesserary() )
    3292               0 :                     return FALSE;
    3293                 :             }
    3294                 : 
    3295              38 :             if( bFeatureAdded )
    3296                 :                 break;
    3297                 :         }
    3298                 :     }
    3299                 : 
    3300              15 :     return TRUE;
    3301                 : }
    3302                 : 
    3303                 : /************************************************************************/
    3304                 : /*                    TransferToDiskIfNecesserary()                     */
    3305                 : /************************************************************************/
    3306                 : 
    3307              38 : int OGROSMDataSource::TransferToDiskIfNecesserary()
    3308                 : {
    3309              38 :     if( bInMemoryNodesFile )
    3310                 :     {
    3311              36 :         if( nNodesFileSize / 1024 / 1024 > 3 * nMaxSizeForInMemoryDBInMB / 4 )
    3312                 :         {
    3313               0 :             bInMemoryNodesFile = FALSE;
    3314                 : 
    3315               0 :             VSIFCloseL(fpNodes);
    3316               0 :             fpNodes = NULL;
    3317                 : 
    3318               0 :             CPLString osNewTmpDBName;
    3319               0 :             osNewTmpDBName = CPLGenerateTempFilename("osm_tmp_nodes");
    3320                 : 
    3321                 :             CPLDebug("OSM", "%s too big for RAM. Transfering it onto disk in %s",
    3322               0 :                      osNodesFilename.c_str(), osNewTmpDBName.c_str());
    3323                 : 
    3324               0 :             if( CPLCopyFile( osNewTmpDBName, osNodesFilename ) != 0 )
    3325                 :             {
    3326                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    3327                 :                          "Cannot copy %s to %s",
    3328               0 :                          osNodesFilename.c_str(), osNewTmpDBName.c_str() );
    3329               0 :                 VSIUnlink(osNewTmpDBName);
    3330               0 :                 bStopParsing = TRUE;
    3331               0 :                 return FALSE;
    3332                 :             }
    3333                 : 
    3334               0 :             VSIUnlink(osNodesFilename);
    3335                 : 
    3336               0 :             if( bInMemoryTmpDB )
    3337                 :             {
    3338                 :                 /* Try to grow the sqlite in memory-db to the full space now */
    3339                 :                 /* it has been freed. */
    3340               0 :                 VSILFILE* fp = VSIFOpenL(osTmpDBName, "rb+");
    3341               0 :                 if( fp )
    3342                 :                 {
    3343               0 :                     VSIFSeekL(fp, 0, SEEK_END);
    3344               0 :                     vsi_l_offset nCurSize = VSIFTellL(fp);
    3345               0 :                     GIntBig nNewSize = ((GIntBig)nMaxSizeForInMemoryDBInMB) * 1024 * 1024;
    3346               0 :                     CPLPushErrorHandler(CPLQuietErrorHandler);
    3347               0 :                     int bSuccess = VSIFSeekL(fp, (vsi_l_offset) nNewSize, SEEK_SET) == 0;
    3348               0 :                     CPLPopErrorHandler();
    3349                 : 
    3350               0 :                     if( bSuccess )
    3351               0 :                         VSIFTruncateL(fp, nCurSize);
    3352                 : 
    3353               0 :                     VSIFCloseL(fp);
    3354                 :                 }
    3355                 :             }
    3356                 : 
    3357               0 :             osNodesFilename = osNewTmpDBName;
    3358                 : 
    3359               0 :             fpNodes = VSIFOpenL(osNodesFilename, "rb+");
    3360               0 :             if( fpNodes == NULL )
    3361                 :             {
    3362               0 :                 bStopParsing = TRUE;
    3363               0 :                 return FALSE;
    3364                 :             }
    3365                 : 
    3366               0 :             VSIFSeekL(fpNodes, 0, SEEK_END);
    3367                 : 
    3368                 :             /* On Unix filesystems, you can remove a file even if it */
    3369                 :             /* opened */
    3370               0 :             const char* pszVal = CPLGetConfigOption("OSM_UNLINK_TMPFILE", "YES");
    3371               0 :             if( EQUAL(pszVal, "YES") )
    3372                 :             {
    3373               0 :                 CPLPushErrorHandler(CPLQuietErrorHandler);
    3374               0 :                 bMustUnlinkNodesFile = VSIUnlink( osNodesFilename ) != 0;
    3375               0 :                 CPLPopErrorHandler();
    3376               0 :             }
    3377                 :         }
    3378                 :     }
    3379                 : 
    3380              38 :     if( bInMemoryTmpDB )
    3381                 :     {
    3382                 :         VSIStatBufL sStat;
    3383                 : 
    3384              38 :         int nLimitMB = nMaxSizeForInMemoryDBInMB;
    3385              38 :         if( bCustomIndexing && bInMemoryNodesFile )
    3386              36 :             nLimitMB = nLimitMB * 1 / 4;
    3387                 : 
    3388              38 :         if( VSIStatL( osTmpDBName, &sStat ) == 0 &&
    3389                 :             sStat.st_size / 1024 / 1024 > nLimitMB )
    3390                 :         {
    3391               0 :             bInMemoryTmpDB = FALSE;
    3392                 : 
    3393               0 :             CloseDB();
    3394                 : 
    3395               0 :             CPLString osNewTmpDBName;
    3396                 :             int rc;
    3397                 : 
    3398               0 :             osNewTmpDBName = CPLGenerateTempFilename("osm_tmp");
    3399                 : 
    3400                 :             CPLDebug("OSM", "%s too big for RAM. Transfering it onto disk in %s",
    3401               0 :                      osTmpDBName.c_str(), osNewTmpDBName.c_str());
    3402                 : 
    3403               0 :             if( CPLCopyFile( osNewTmpDBName, osTmpDBName ) != 0 )
    3404                 :             {
    3405                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    3406                 :                          "Cannot copy %s to %s",
    3407               0 :                          osTmpDBName.c_str(), osNewTmpDBName.c_str() );
    3408               0 :                 VSIUnlink(osNewTmpDBName);
    3409               0 :                 bStopParsing = TRUE;
    3410               0 :                 return FALSE;
    3411                 :             }
    3412                 : 
    3413               0 :             VSIUnlink(osTmpDBName);
    3414                 : 
    3415               0 :             osTmpDBName = osNewTmpDBName;
    3416                 : 
    3417                 : #ifdef HAVE_SQLITE_VFS
    3418                 :             rc = sqlite3_open_v2( osTmpDBName.c_str(), &hDB,
    3419                 :                                   SQLITE_OPEN_READWRITE | SQLITE_OPEN_NOMUTEX,
    3420               0 :                                   NULL );
    3421                 : #else
    3422                 :             rc = sqlite3_open( osTmpDBName.c_str(), &hDB );
    3423                 : #endif
    3424               0 :             if( rc != SQLITE_OK )
    3425                 :             {
    3426                 :                 CPLError( CE_Failure, CPLE_OpenFailed,
    3427                 :                         "sqlite3_open(%s) failed: %s",
    3428               0 :                         osTmpDBName.c_str(), sqlite3_errmsg( hDB ) );
    3429               0 :                 bStopParsing = TRUE;
    3430               0 :                 CloseDB();
    3431               0 :                 return FALSE;
    3432                 :             }
    3433                 : 
    3434                 :             /* On Unix filesystems, you can remove a file even if it */
    3435                 :             /* opened */
    3436               0 :             const char* pszVal = CPLGetConfigOption("OSM_UNLINK_TMPFILE", "YES");
    3437               0 :             if( EQUAL(pszVal, "YES") )
    3438                 :             {
    3439               0 :                 CPLPushErrorHandler(CPLQuietErrorHandler);
    3440               0 :                 bMustUnlink = VSIUnlink( osTmpDBName ) != 0;
    3441               0 :                 CPLPopErrorHandler();
    3442                 :             }
    3443                 : 
    3444               0 :             if( !SetDBOptions() || !CreatePreparedStatements() )
    3445                 :             {
    3446               0 :                 bStopParsing = TRUE;
    3447               0 :                 CloseDB();
    3448               0 :                 return FALSE;
    3449               0 :             }
    3450                 :         }
    3451                 :     }
    3452                 : 
    3453              38 :     return TRUE;
    3454                 : }
    3455                 : 
    3456                 : /************************************************************************/
    3457                 : /*                           TestCapability()                           */
    3458                 : /************************************************************************/
    3459                 : 
    3460               0 : int OGROSMDataSource::TestCapability( const char * pszCap )
    3461                 : 
    3462                 : {
    3463               0 :     return FALSE;
    3464                 : }
    3465                 : 
    3466                 : /************************************************************************/
    3467                 : /*                              GetLayer()                              */
    3468                 : /************************************************************************/
    3469                 : 
    3470             239 : OGRLayer *OGROSMDataSource::GetLayer( int iLayer )
    3471                 : 
    3472                 : {
    3473             239 :     if( iLayer < 0 || iLayer >= nLayers )
    3474               0 :         return NULL;
    3475                 :     else
    3476             239 :         return papoLayers[iLayer];
    3477                 : }
    3478                 : 
    3479                 : /************************************************************************/
    3480                 : /*                             GetExtent()                              */
    3481                 : /************************************************************************/
    3482                 : 
    3483               1 : OGRErr OGROSMDataSource::GetExtent( OGREnvelope *psExtent )
    3484                 : {
    3485               1 :     if (!bHasParsedFirstChunk)
    3486                 :     {
    3487               1 :         bHasParsedFirstChunk = TRUE;
    3488               1 :         OSM_ProcessBlock(psParser);
    3489                 :     }
    3490                 : 
    3491               1 :     if (bExtentValid)
    3492                 :     {
    3493               1 :         memcpy(psExtent, &sExtent, sizeof(sExtent));
    3494               1 :         return OGRERR_NONE;
    3495                 :     }
    3496                 : 
    3497               0 :     return OGRERR_FAILURE;
    3498                 : }
    3499                 : 
    3500                 : 
    3501                 : /************************************************************************/
    3502                 : /*                   OGROSMSingleFeatureLayer                           */
    3503                 : /************************************************************************/
    3504                 : 
    3505                 : class OGROSMSingleFeatureLayer : public OGRLayer
    3506                 : {
    3507                 :   private:
    3508                 :     int                 nVal;
    3509                 :     char               *pszVal;
    3510                 :     OGRFeatureDefn     *poFeatureDefn;
    3511                 :     int                 iNextShapeId;
    3512                 : 
    3513                 :   public:
    3514                 :                         OGROSMSingleFeatureLayer( const char* pszLayerName,
    3515                 :                                                      int nVal );
    3516                 :                         OGROSMSingleFeatureLayer( const char* pszLayerName,
    3517                 :                                                      const char *pszVal );
    3518                 :                         ~OGROSMSingleFeatureLayer();
    3519                 : 
    3520               0 :     virtual void        ResetReading() { iNextShapeId = 0; }
    3521                 :     virtual OGRFeature *GetNextFeature();
    3522               0 :     virtual OGRFeatureDefn *GetLayerDefn() { return poFeatureDefn; }
    3523               0 :     virtual int         TestCapability( const char * ) { return FALSE; }
    3524                 : };
    3525                 : 
    3526                 : 
    3527                 : /************************************************************************/
    3528                 : /*                    OGROSMSingleFeatureLayer()                        */
    3529                 : /************************************************************************/
    3530                 : 
    3531               0 : OGROSMSingleFeatureLayer::OGROSMSingleFeatureLayer(  const char* pszLayerName,
    3532               0 :                                                      int nVal )
    3533                 : {
    3534               0 :     poFeatureDefn = new OGRFeatureDefn( "SELECT" );
    3535               0 :     poFeatureDefn->Reference();
    3536               0 :     OGRFieldDefn oField( pszLayerName, OFTInteger );
    3537               0 :     poFeatureDefn->AddFieldDefn( &oField );
    3538                 : 
    3539               0 :     iNextShapeId = 0;
    3540               0 :     this->nVal = nVal;
    3541               0 :     pszVal = NULL;
    3542               0 : }
    3543                 : 
    3544                 : /************************************************************************/
    3545                 : /*                    OGROSMSingleFeatureLayer()                        */
    3546                 : /************************************************************************/
    3547                 : 
    3548               0 : OGROSMSingleFeatureLayer::OGROSMSingleFeatureLayer(  const char* pszLayerName,
    3549               0 :                                                      const char *pszVal )
    3550                 : {
    3551               0 :     poFeatureDefn = new OGRFeatureDefn( "SELECT" );
    3552               0 :     poFeatureDefn->Reference();
    3553               0 :     OGRFieldDefn oField( pszLayerName, OFTString );
    3554               0 :     poFeatureDefn->AddFieldDefn( &oField );
    3555                 : 
    3556               0 :     iNextShapeId = 0;
    3557               0 :     nVal = 0;
    3558               0 :     this->pszVal = CPLStrdup(pszVal);
    3559               0 : }
    3560                 : 
    3561                 : /************************************************************************/
    3562                 : /*                    ~OGROSMSingleFeatureLayer()                       */
    3563                 : /************************************************************************/
    3564                 : 
    3565               0 : OGROSMSingleFeatureLayer::~OGROSMSingleFeatureLayer()
    3566                 : {
    3567               0 :     poFeatureDefn->Release();
    3568               0 :     CPLFree(pszVal);
    3569               0 : }
    3570                 : 
    3571                 : /************************************************************************/
    3572                 : /*                           GetNextFeature()                           */
    3573                 : /************************************************************************/
    3574                 : 
    3575               0 : OGRFeature * OGROSMSingleFeatureLayer::GetNextFeature()
    3576                 : {
    3577               0 :     if (iNextShapeId != 0)
    3578               0 :         return NULL;
    3579                 : 
    3580               0 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    3581               0 :     if (pszVal)
    3582               0 :         poFeature->SetField(0, pszVal);
    3583                 :     else
    3584               0 :         poFeature->SetField(0, nVal);
    3585               0 :     poFeature->SetFID(iNextShapeId ++);
    3586               0 :     return poFeature;
    3587                 : }
    3588                 : 
    3589                 : /************************************************************************/
    3590                 : /*                      OGROSMResultLayerDecorator                      */
    3591                 : /************************************************************************/
    3592                 : 
    3593                 : class OGROSMResultLayerDecorator : public OGRLayerDecorator
    3594               1 : {
    3595                 :         CPLString               osDSName;
    3596                 :         CPLString               osInterestLayers;
    3597                 : 
    3598                 :     public:
    3599               1 :         OGROSMResultLayerDecorator(OGRLayer* poLayer,
    3600                 :                                    CPLString osDSName,
    3601                 :                                    CPLString osInterestLayers) :
    3602                 :                                         OGRLayerDecorator(poLayer, TRUE),
    3603                 :                                         osDSName(osDSName),
    3604               1 :                                         osInterestLayers(osInterestLayers) {}
    3605                 : 
    3606               1 :         virtual int         GetFeatureCount( int bForce = TRUE )
    3607                 :         {
    3608                 :             /* When we run GetFeatureCount() with SQLite SQL dialect, */
    3609                 :             /* the OSM dataset will be re-opened. Make sure that it is */
    3610                 :             /* re-opened with the same interest layers */
    3611               1 :             AddInterestLayersForDSName(osDSName, osInterestLayers);
    3612               1 :             return OGRLayerDecorator::GetFeatureCount(bForce);
    3613                 :         }
    3614                 : };
    3615                 : 
    3616                 : /************************************************************************/
    3617                 : /*                             ExecuteSQL()                             */
    3618                 : /************************************************************************/
    3619                 : 
    3620              32 : OGRLayer * OGROSMDataSource::ExecuteSQL( const char *pszSQLCommand,
    3621                 :                                          OGRGeometry *poSpatialFilter,
    3622                 :                                          const char *pszDialect )
    3623                 : 
    3624                 : {
    3625                 : /* -------------------------------------------------------------------- */
    3626                 : /*      Special GetBytesRead() command                                  */
    3627                 : /* -------------------------------------------------------------------- */
    3628              32 :     if (strcmp(pszSQLCommand, "GetBytesRead()") == 0)
    3629                 :     {
    3630                 :         char szVal[64];
    3631               0 :         sprintf(szVal, CPL_FRMT_GUIB, OSM_GetBytesRead(psParser));
    3632               0 :         return new OGROSMSingleFeatureLayer( "GetBytesRead", szVal );
    3633                 :     }
    3634                 : 
    3635              32 :     if( poResultSetLayer != NULL )
    3636                 :     {
    3637                 :         CPLError(CE_Failure, CPLE_NotSupported,
    3638               0 :                  "A SQL result layer is still in use. Please delete it first");
    3639               0 :         return NULL;
    3640                 :     }
    3641                 : 
    3642                 : /* -------------------------------------------------------------------- */
    3643                 : /*      Special SET interest_layers = command                           */
    3644                 : /* -------------------------------------------------------------------- */
    3645              32 :     if (strncmp(pszSQLCommand, "SET interest_layers =", 21) == 0)
    3646                 :     {
    3647              18 :         char** papszTokens = CSLTokenizeString2(pszSQLCommand + 21, ",", CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
    3648                 :         int i;
    3649                 : 
    3650             108 :         for(i=0; i < nLayers; i++)
    3651                 :         {
    3652              90 :             papoLayers[i]->SetDeclareInterest(FALSE);
    3653                 :         }
    3654                 : 
    3655              48 :         for(i=0; papszTokens[i] != NULL; i++)
    3656                 :         {
    3657              30 :             OGROSMLayer* poLayer = (OGROSMLayer*) GetLayerByName(papszTokens[i]);
    3658              30 :             if( poLayer != NULL )
    3659                 :             {
    3660              27 :                 poLayer->SetDeclareInterest(TRUE);
    3661                 :             }
    3662                 :         }
    3663                 : 
    3664              45 :         if( papoLayers[IDX_LYR_POINTS]->IsUserInterested() &&
    3665               9 :             !papoLayers[IDX_LYR_LINES]->IsUserInterested() &&
    3666               6 :             !papoLayers[IDX_LYR_MULTILINESTRINGS]->IsUserInterested() &&
    3667               6 :             !papoLayers[IDX_LYR_MULTIPOLYGONS]->IsUserInterested() &&
    3668               6 :             !papoLayers[IDX_LYR_OTHER_RELATIONS]->IsUserInterested())
    3669                 :         {
    3670               6 :             if( CPLGetConfigOption("OSM_INDEX_POINTS", NULL) == NULL )
    3671                 :             {
    3672               6 :                 CPLDebug("OSM", "Disabling indexing of nodes");
    3673               6 :                 bIndexPoints = FALSE;
    3674                 :             }
    3675               6 :             if( CPLGetConfigOption("OSM_USE_POINTS_INDEX", NULL) == NULL )
    3676                 :             {
    3677               6 :                 bUsePointsIndex = FALSE;
    3678                 :             }
    3679               6 :             if( CPLGetConfigOption("OSM_INDEX_WAYS", NULL) == NULL )
    3680                 :             {
    3681               6 :                 CPLDebug("OSM", "Disabling indexing of ways");
    3682               6 :                 bIndexWays = FALSE;
    3683                 :             }
    3684               6 :             if( CPLGetConfigOption("OSM_USE_WAYS_INDEX", NULL) == NULL )
    3685                 :             {
    3686               6 :                 bUseWaysIndex = FALSE;
    3687                 :             }
    3688                 :         }
    3689              24 :         else if( papoLayers[IDX_LYR_LINES]->IsUserInterested() &&
    3690               6 :                  !papoLayers[IDX_LYR_MULTILINESTRINGS]->IsUserInterested() &&
    3691               3 :                  !papoLayers[IDX_LYR_MULTIPOLYGONS]->IsUserInterested() &&
    3692               3 :                  !papoLayers[IDX_LYR_OTHER_RELATIONS]->IsUserInterested() )
    3693                 :         {
    3694               3 :             if( CPLGetConfigOption("OSM_INDEX_WAYS", NULL) == NULL )
    3695                 :             {
    3696               3 :                 CPLDebug("OSM", "Disabling indexing of ways");
    3697               3 :                 bIndexWays = FALSE;
    3698                 :             }
    3699               3 :             if( CPLGetConfigOption("OSM_USE_WAYS_INDEX", NULL) == NULL )
    3700                 :             {
    3701               3 :                 bUseWaysIndex = FALSE;
    3702                 :             }
    3703                 :         }
    3704                 : 
    3705              18 :         CSLDestroy(papszTokens);
    3706                 : 
    3707              18 :         return NULL;
    3708                 :     }
    3709                 : 
    3710              28 :     while(*pszSQLCommand == ' ')
    3711               0 :         pszSQLCommand ++;
    3712                 : 
    3713                 :     /* Try to analyse the SQL command to get the interest table */
    3714              14 :     if( EQUALN(pszSQLCommand, "SELECT", 5) )
    3715                 :     {
    3716              14 :         int bLayerAlreadyAdded = FALSE;
    3717              14 :         CPLString osInterestLayers = "SET interest_layers =";
    3718                 : 
    3719              15 :         if( pszDialect != NULL && EQUAL(pszDialect, "SQLITE") )
    3720                 :         {
    3721               1 :             std::set<LayerDesc> oSetLayers = OGRSQLiteGetReferencedLayers(pszSQLCommand);
    3722               1 :             std::set<LayerDesc>::iterator oIter = oSetLayers.begin();
    3723               2 :             for(; oIter != oSetLayers.end(); ++oIter)
    3724                 :             {
    3725               1 :                 const LayerDesc& oLayerDesc = *oIter;
    3726               1 :                 if( oLayerDesc.osDSName.size() == 0 )
    3727                 :                 {
    3728               1 :                     if( bLayerAlreadyAdded ) osInterestLayers += ",";
    3729               1 :                     bLayerAlreadyAdded = TRUE;
    3730               1 :                     osInterestLayers += oLayerDesc.osLayerName;
    3731                 :                 }
    3732               1 :             }
    3733                 :         }
    3734                 :         else
    3735                 :         {
    3736              13 :             swq_select sSelectInfo;
    3737                 : 
    3738              13 :             CPLPushErrorHandler(CPLQuietErrorHandler);
    3739              13 :             CPLErr eErr = sSelectInfo.preparse( pszSQLCommand );
    3740              13 :             CPLPopErrorHandler();
    3741                 : 
    3742              13 :             if( eErr == CPLE_None )
    3743                 :             {
    3744              13 :                 swq_select* pCurSelect = &sSelectInfo;
    3745              39 :                 while(pCurSelect != NULL)
    3746                 :                 {
    3747              26 :                     for( int iTable = 0; iTable < pCurSelect->table_count; iTable++ )
    3748                 :                     {
    3749              13 :                         swq_table_def *psTableDef = pCurSelect->table_defs + iTable;
    3750              13 :                         if( psTableDef->data_source == NULL )
    3751                 :                         {
    3752              13 :                             if( bLayerAlreadyAdded ) osInterestLayers += ",";
    3753              13 :                             bLayerAlreadyAdded = TRUE;
    3754              13 :                             osInterestLayers += psTableDef->table_name;
    3755                 :                         }
    3756                 :                     }
    3757              13 :                     pCurSelect = pCurSelect->poOtherSelect;
    3758                 :                 }
    3759              13 :             }
    3760                 :         }
    3761                 : 
    3762              14 :         if( bLayerAlreadyAdded )
    3763                 :         {
    3764                 :             /* Backup current optimization parameters */
    3765              14 :             abSavedDeclaredInterest.resize(0);
    3766              84 :             for(int i=0; i < nLayers; i++)
    3767                 :             {
    3768              70 :                 abSavedDeclaredInterest.push_back(papoLayers[i]->IsUserInterested());
    3769                 :             }
    3770              14 :             bIndexPointsBackup = bIndexPoints;
    3771              14 :             bUsePointsIndexBackup = bUsePointsIndex;
    3772              14 :             bIndexWaysBackup = bIndexWays;
    3773              14 :             bUseWaysIndexBackup = bUseWaysIndex;
    3774                 : 
    3775                 :             /* Update optimization parameters */
    3776              14 :             ExecuteSQL(osInterestLayers, NULL, NULL);
    3777                 : 
    3778              14 :             ResetReading();
    3779                 : 
    3780                 :             /* Run the request */
    3781                 :             poResultSetLayer = OGRDataSource::ExecuteSQL( pszSQLCommand,
    3782                 :                                                             poSpatialFilter,
    3783              14 :                                                             pszDialect );
    3784                 : 
    3785                 :             /* If the user explicitely run a COUNT() request, then do it ! */
    3786              14 :             if( poResultSetLayer )
    3787                 :             {
    3788              14 :                 if( pszDialect != NULL && EQUAL(pszDialect, "SQLITE") )
    3789                 :                 {
    3790                 :                     poResultSetLayer = new OGROSMResultLayerDecorator(
    3791               1 :                                 poResultSetLayer, GetName(), osInterestLayers);
    3792                 :                 }
    3793              14 :                 bIsFeatureCountEnabled = TRUE;
    3794                 :             }
    3795                 : 
    3796              14 :             return poResultSetLayer;
    3797               0 :         }
    3798                 :     }
    3799                 : 
    3800                 :     return OGRDataSource::ExecuteSQL( pszSQLCommand,
    3801                 :                                       poSpatialFilter,
    3802               0 :                                       pszDialect );
    3803                 : }
    3804                 : 
    3805                 : /************************************************************************/
    3806                 : /*                          ReleaseResultSet()                          */
    3807                 : /************************************************************************/
    3808                 : 
    3809              14 : void OGROSMDataSource::ReleaseResultSet( OGRLayer * poLayer )
    3810                 : 
    3811                 : {
    3812              14 :     if( poLayer != NULL && poLayer == poResultSetLayer )
    3813                 :     {
    3814              14 :         poResultSetLayer = NULL;
    3815                 : 
    3816              14 :         bIsFeatureCountEnabled = FALSE;
    3817                 : 
    3818                 :         /* Restore backup'ed optimization parameters */
    3819              84 :         for(int i=0; i < nLayers; i++)
    3820                 :         {
    3821              70 :             papoLayers[i]->SetDeclareInterest(abSavedDeclaredInterest[i]);
    3822                 :         }
    3823              14 :         if( bIndexPointsBackup && !bIndexPoints )
    3824               5 :             CPLDebug("OSM", "Re-enabling indexing of nodes");
    3825              14 :         bIndexPoints = bIndexPointsBackup;
    3826              14 :         bUsePointsIndex = bUsePointsIndexBackup;
    3827              14 :         if( bIndexWaysBackup && !bIndexWays )
    3828               8 :             CPLDebug("OSM", "Re-enabling indexing of ways");
    3829              14 :         bIndexWays = bIndexWaysBackup;
    3830              14 :         bUseWaysIndex = bUseWaysIndexBackup;
    3831              14 :         abSavedDeclaredInterest.resize(0);
    3832                 :     }
    3833                 : 
    3834              14 :     delete poLayer;
    3835              14 : }
    3836                 : 
    3837                 : /************************************************************************/
    3838                 : /*                         IsInterleavedReading()                       */
    3839                 : /************************************************************************/
    3840                 : 
    3841              71 : int OGROSMDataSource::IsInterleavedReading()
    3842                 : {
    3843              71 :     if( bInterleavedReading < 0 )
    3844                 :     {
    3845                 :         bInterleavedReading = CSLTestBoolean(
    3846              10 :                         CPLGetConfigOption("OGR_INTERLEAVED_READING", "NO"));
    3847              10 :         CPLDebug("OSM", "OGR_INTERLEAVED_READING = %d", bInterleavedReading);
    3848                 :     }
    3849              71 :     return bInterleavedReading;
    3850            2139 : }

Generated by: LCOV version 1.7