LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/osm - ogrosmdatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1871 1455 77.8 %
Date: 2013-03-30 Functions: 82 69 84.1 %

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

Generated by: LCOV version 1.7