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