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