Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Author: Even Rouault, <even dot rouault at spatialys.com>
5 : * Purpose: OSM XML and OSM PBF parser
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2012-2013, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "osm_parser.h"
30 : #include "gpb.h"
31 :
32 : #include <climits>
33 : #include <cstddef>
34 : #include <cstdio>
35 : #include <cstdlib>
36 : #include <cstring>
37 : #include <algorithm>
38 : #include <exception>
39 : #include <string>
40 : #include <vector>
41 :
42 : #include "cpl_config.h"
43 : #include "cpl_conv.h"
44 : #include "cpl_error.h"
45 : #include "cpl_multiproc.h"
46 : #include "cpl_string.h"
47 : #include "cpl_vsi.h"
48 : #include "cpl_worker_thread_pool.h"
49 :
50 : #ifdef HAVE_EXPAT
51 : #include "ogr_expat.h"
52 : #endif
53 :
54 : // The buffer that are passed to GPB decoding are extended with 0's
55 : // to be sure that we will be able to read a single 64bit value without
56 : // doing checks for each byte.
57 : constexpr int EXTRA_BYTES = 1;
58 :
59 : #ifdef HAVE_EXPAT
60 : constexpr int XML_BUFSIZE = 64 * 1024;
61 : #endif
62 :
63 : // Per OSM PBF spec
64 : constexpr unsigned int MAX_BLOB_HEADER_SIZE = 64 * 1024;
65 :
66 : // Per OSM PBF spec (usually much smaller !)
67 : constexpr unsigned int MAX_BLOB_SIZE = 64 * 1024 * 1024;
68 :
69 : // GDAL implementation limits
70 : constexpr unsigned int MAX_ACC_BLOB_SIZE = 50 * 1024 * 1024;
71 : constexpr unsigned int MAX_ACC_UNCOMPRESSED_SIZE = 100 * 1024 * 1024;
72 : constexpr int N_MAX_JOBS = 1024;
73 :
74 : #if defined(__GNUC__)
75 : #define CPL_NO_INLINE __attribute__((noinline))
76 : #else
77 : #define CPL_NO_INLINE
78 : #endif
79 :
80 : class OSMParsingException : public std::exception
81 : {
82 : std::string m_osMessage;
83 :
84 : public:
85 0 : explicit OSMParsingException(int nLine)
86 0 : : m_osMessage(CPLSPrintf("Parsing error occurred at line %d", nLine))
87 : {
88 0 : }
89 :
90 0 : const char *what() const noexcept override
91 : {
92 0 : return m_osMessage.c_str();
93 : }
94 : };
95 :
96 : #define THROW_OSM_PARSING_EXCEPTION throw OSMParsingException(__LINE__)
97 :
98 : /************************************************************************/
99 : /* INIT_INFO() */
100 : /************************************************************************/
101 :
102 851 : static void INIT_INFO(OSMInfo *sInfo)
103 : {
104 851 : sInfo->ts.nTimeStamp = 0;
105 851 : sInfo->nChangeset = 0;
106 851 : sInfo->nVersion = 0;
107 851 : sInfo->nUID = 0;
108 851 : sInfo->bTimeStampIsStr = false;
109 851 : sInfo->pszUserSID = nullptr;
110 851 : }
111 :
112 : /************************************************************************/
113 : /* _OSMContext */
114 : /************************************************************************/
115 :
116 : typedef struct
117 : {
118 : const GByte *pabySrc;
119 : size_t nSrcSize;
120 : GByte *pabyDstBase;
121 : size_t nDstOffset;
122 : size_t nDstSize;
123 : bool bStatus;
124 : } DecompressionJob;
125 :
126 : struct _OSMContext
127 : {
128 : char *pszStrBuf;
129 : int *panStrOff;
130 : unsigned int nStrCount;
131 : unsigned int nStrAllocated;
132 :
133 : OSMNode *pasNodes;
134 : unsigned int nNodesAllocated;
135 :
136 : OSMTag *pasTags;
137 : unsigned int nTagsAllocated;
138 :
139 : OSMMember *pasMembers;
140 : unsigned int nMembersAllocated;
141 :
142 : GIntBig *panNodeRefs;
143 : unsigned int nNodeRefsAllocated;
144 :
145 : int nGranularity;
146 : int nDateGranularity;
147 : GIntBig nLatOffset;
148 : GIntBig nLonOffset;
149 :
150 : // concatenated protocol buffer messages BLOB_OSMDATA, or single
151 : // BLOB_OSMHEADER
152 : GByte *pabyBlob;
153 : unsigned int nBlobSizeAllocated;
154 : unsigned int nBlobOffset;
155 : unsigned int nBlobSize;
156 :
157 : GByte *pabyBlobHeader; // MAX_BLOB_HEADER_SIZE+EXTRA_BYTES large
158 :
159 : CPLWorkerThreadPool *poWTP;
160 :
161 : GByte *pabyUncompressed;
162 : unsigned int nUncompressedAllocated;
163 : unsigned int nTotalUncompressedSize;
164 :
165 : DecompressionJob asJobs[N_MAX_JOBS];
166 : int nJobs;
167 : int iNextJob;
168 :
169 : #ifdef HAVE_EXPAT
170 : XML_Parser hXMLParser;
171 : bool bEOF;
172 : bool bStopParsing;
173 : bool bHasFoundFeature;
174 : int nWithoutEventCounter;
175 : int nDataHandlerCounter;
176 :
177 : unsigned int nStrLength;
178 : unsigned int nTags;
179 :
180 : bool bInNode;
181 : bool bInWay;
182 : bool bInRelation;
183 :
184 : OSMWay sWay;
185 : OSMRelation sRelation;
186 :
187 : bool bTryToFetchBounds;
188 : #endif
189 :
190 : VSILFILE *fp;
191 :
192 : bool bPBF;
193 :
194 : double dfLeft;
195 : double dfRight;
196 : double dfTop;
197 : double dfBottom;
198 :
199 : GUIntBig nBytesRead;
200 :
201 : NotifyNodesFunc pfnNotifyNodes;
202 : NotifyWayFunc pfnNotifyWay;
203 : NotifyRelationFunc pfnNotifyRelation;
204 : NotifyBoundsFunc pfnNotifyBounds;
205 : void *user_data;
206 : };
207 :
208 : /************************************************************************/
209 : /* ReadBlobHeader() */
210 : /************************************************************************/
211 :
212 : constexpr int BLOBHEADER_IDX_TYPE = 1;
213 : constexpr int BLOBHEADER_IDX_INDEXDATA = 2;
214 : constexpr int BLOBHEADER_IDX_DATASIZE = 3;
215 :
216 : typedef enum
217 : {
218 : BLOB_UNKNOWN,
219 : BLOB_OSMHEADER,
220 : BLOB_OSMDATA
221 : } BlobType;
222 :
223 70 : static bool ReadBlobHeader(const GByte *pabyData, const GByte *pabyDataLimit,
224 : unsigned int *pnBlobSize, BlobType *peBlobType)
225 : {
226 70 : *pnBlobSize = 0;
227 70 : *peBlobType = BLOB_UNKNOWN;
228 :
229 : try
230 : {
231 210 : while (pabyData < pabyDataLimit)
232 : {
233 140 : int nKey = 0;
234 140 : READ_FIELD_KEY(nKey);
235 :
236 140 : if (nKey == MAKE_KEY(BLOBHEADER_IDX_TYPE, WT_DATA))
237 : {
238 70 : unsigned int nDataLength = 0;
239 70 : READ_SIZE(pabyData, pabyDataLimit, nDataLength);
240 :
241 70 : if (nDataLength == 7 && memcmp(pabyData, "OSMData", 7) == 0)
242 : {
243 35 : *peBlobType = BLOB_OSMDATA;
244 : }
245 35 : else if (nDataLength == 9 &&
246 35 : memcmp(pabyData, "OSMHeader", 9) == 0)
247 : {
248 35 : *peBlobType = BLOB_OSMHEADER;
249 : }
250 :
251 70 : pabyData += nDataLength;
252 : }
253 70 : else if (nKey == MAKE_KEY(BLOBHEADER_IDX_INDEXDATA, WT_DATA))
254 : {
255 : // Ignored if found.
256 0 : unsigned int nDataLength = 0;
257 0 : READ_SIZE(pabyData, pabyDataLimit, nDataLength);
258 0 : pabyData += nDataLength;
259 : }
260 70 : else if (nKey == MAKE_KEY(BLOBHEADER_IDX_DATASIZE, WT_VARINT))
261 : {
262 70 : unsigned int nBlobSize = 0;
263 70 : READ_VARUINT32(pabyData, pabyDataLimit, nBlobSize);
264 : // printf("nBlobSize = %d\n", nBlobSize);
265 70 : *pnBlobSize = nBlobSize;
266 : }
267 : else
268 : {
269 0 : SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
270 : }
271 : }
272 :
273 70 : return pabyData == pabyDataLimit;
274 : }
275 0 : catch (const std::exception &e)
276 : {
277 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
278 0 : return false;
279 : }
280 : }
281 :
282 : /************************************************************************/
283 : /* ReadHeaderBBox() */
284 : /************************************************************************/
285 :
286 : constexpr int HEADERBBOX_IDX_LEFT = 1;
287 : constexpr int HEADERBBOX_IDX_RIGHT = 2;
288 : constexpr int HEADERBBOX_IDX_TOP = 3;
289 : constexpr int HEADERBBOX_IDX_BOTTOM = 4;
290 :
291 3 : static bool ReadHeaderBBox(const GByte *pabyData, const GByte *pabyDataLimit,
292 : OSMContext *psCtxt)
293 : {
294 3 : psCtxt->dfLeft = 0.0;
295 3 : psCtxt->dfRight = 0.0;
296 3 : psCtxt->dfTop = 0.0;
297 3 : psCtxt->dfBottom = 0.0;
298 :
299 : try
300 : {
301 15 : while (pabyData < pabyDataLimit)
302 : {
303 12 : int nKey = 0;
304 12 : READ_FIELD_KEY(nKey);
305 :
306 12 : if (nKey == MAKE_KEY(HEADERBBOX_IDX_LEFT, WT_VARINT))
307 : {
308 3 : GIntBig nLeft = 0;
309 3 : READ_VARSINT64(pabyData, pabyDataLimit, nLeft);
310 3 : psCtxt->dfLeft = nLeft * 1e-9;
311 : }
312 9 : else if (nKey == MAKE_KEY(HEADERBBOX_IDX_RIGHT, WT_VARINT))
313 : {
314 3 : GIntBig nRight = 0;
315 3 : READ_VARSINT64(pabyData, pabyDataLimit, nRight);
316 3 : psCtxt->dfRight = nRight * 1e-9;
317 : }
318 6 : else if (nKey == MAKE_KEY(HEADERBBOX_IDX_TOP, WT_VARINT))
319 : {
320 3 : GIntBig nTop = 0;
321 3 : READ_VARSINT64(pabyData, pabyDataLimit, nTop);
322 3 : psCtxt->dfTop = nTop * 1e-9;
323 : }
324 3 : else if (nKey == MAKE_KEY(HEADERBBOX_IDX_BOTTOM, WT_VARINT))
325 : {
326 3 : GIntBig nBottom = 0;
327 3 : READ_VARSINT64(pabyData, pabyDataLimit, nBottom);
328 3 : psCtxt->dfBottom = nBottom * 1e-9;
329 : }
330 : else
331 : {
332 0 : SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
333 : }
334 : }
335 :
336 3 : psCtxt->pfnNotifyBounds(psCtxt->dfLeft, psCtxt->dfBottom,
337 : psCtxt->dfRight, psCtxt->dfTop, psCtxt,
338 : psCtxt->user_data);
339 :
340 3 : return pabyData == pabyDataLimit;
341 : }
342 0 : catch (const std::exception &e)
343 : {
344 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
345 0 : return false;
346 : }
347 : }
348 :
349 : /************************************************************************/
350 : /* ReadOSMHeader() */
351 : /************************************************************************/
352 :
353 : constexpr int OSMHEADER_IDX_BBOX = 1;
354 : constexpr int OSMHEADER_IDX_REQUIRED_FEATURES = 4;
355 : constexpr int OSMHEADER_IDX_OPTIONAL_FEATURES = 5;
356 : constexpr int OSMHEADER_IDX_WRITING_PROGRAM = 16;
357 : constexpr int OSMHEADER_IDX_SOURCE = 17;
358 :
359 : /* Ignored */
360 : constexpr int OSMHEADER_IDX_OSMOSIS_REPLICATION_TIMESTAMP = 32;
361 : constexpr int OSMHEADER_IDX_OSMOSIS_REPLICATION_SEQ_NUMBER = 33;
362 : constexpr int OSMHEADER_IDX_OSMOSIS_REPLICATION_BASE_URL = 34;
363 :
364 35 : static bool ReadOSMHeader(const GByte *pabyData, const GByte *pabyDataLimit,
365 : OSMContext *psCtxt)
366 : {
367 35 : char *pszTxt = nullptr;
368 :
369 : try
370 : {
371 144 : while (pabyData < pabyDataLimit)
372 : {
373 109 : int nKey = 0;
374 109 : READ_FIELD_KEY(nKey);
375 :
376 109 : if (nKey == MAKE_KEY(OSMHEADER_IDX_BBOX, WT_DATA))
377 : {
378 3 : unsigned int nBBOXSize = 0;
379 3 : READ_SIZE(pabyData, pabyDataLimit, nBBOXSize);
380 :
381 3 : if (!ReadHeaderBBox(pabyData, pabyData + nBBOXSize, psCtxt))
382 0 : THROW_OSM_PARSING_EXCEPTION;
383 :
384 3 : pabyData += nBBOXSize;
385 : }
386 106 : else if (nKey == MAKE_KEY(OSMHEADER_IDX_REQUIRED_FEATURES, WT_DATA))
387 : {
388 69 : READ_TEXT(pabyData, pabyDataLimit, pszTxt);
389 : // printf("OSMHEADER_IDX_REQUIRED_FEATURES = %s\n", pszTxt)
390 69 : if (!(strcmp(pszTxt, "OsmSchema-V0.6") == 0 ||
391 34 : strcmp(pszTxt, "DenseNodes") == 0))
392 : {
393 0 : CPLError(CE_Failure, CPLE_NotSupported,
394 : "Error: unsupported required feature : %s",
395 : pszTxt);
396 0 : VSIFree(pszTxt);
397 0 : THROW_OSM_PARSING_EXCEPTION;
398 : }
399 69 : VSIFree(pszTxt);
400 : }
401 37 : else if (nKey == MAKE_KEY(OSMHEADER_IDX_OPTIONAL_FEATURES, WT_DATA))
402 : {
403 0 : READ_TEXT(pabyData, pabyDataLimit, pszTxt);
404 : // printf("OSMHEADER_IDX_OPTIONAL_FEATURES = %s\n", pszTxt);
405 0 : VSIFree(pszTxt);
406 : }
407 37 : else if (nKey == MAKE_KEY(OSMHEADER_IDX_WRITING_PROGRAM, WT_DATA))
408 : {
409 35 : READ_TEXT(pabyData, pabyDataLimit, pszTxt);
410 : // printf("OSMHEADER_IDX_WRITING_PROGRAM = %s\n", pszTxt);
411 35 : VSIFree(pszTxt);
412 : }
413 2 : else if (nKey == MAKE_KEY(OSMHEADER_IDX_SOURCE, WT_DATA))
414 : {
415 2 : READ_TEXT(pabyData, pabyDataLimit, pszTxt);
416 : // printf("OSMHEADER_IDX_SOURCE = %s\n", pszTxt);
417 2 : VSIFree(pszTxt);
418 : }
419 0 : else if (nKey ==
420 : MAKE_KEY(OSMHEADER_IDX_OSMOSIS_REPLICATION_TIMESTAMP,
421 : WT_VARINT))
422 : {
423 0 : SKIP_VARINT(pabyData, pabyDataLimit);
424 : }
425 0 : else if (nKey ==
426 : MAKE_KEY(OSMHEADER_IDX_OSMOSIS_REPLICATION_SEQ_NUMBER,
427 : WT_VARINT))
428 : {
429 0 : SKIP_VARINT(pabyData, pabyDataLimit);
430 : }
431 0 : else if (nKey ==
432 : MAKE_KEY(OSMHEADER_IDX_OSMOSIS_REPLICATION_BASE_URL,
433 : WT_DATA))
434 : {
435 0 : READ_TEXT(pabyData, pabyDataLimit, pszTxt);
436 : /* printf("OSMHEADER_IDX_OSMOSIS_REPLICATION_BASE_URL = %s\n",
437 : * pszTxt); */
438 0 : VSIFree(pszTxt);
439 : }
440 : else
441 : {
442 0 : SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
443 : }
444 : }
445 :
446 35 : return pabyData == pabyDataLimit;
447 : }
448 0 : catch (const std::exception &e)
449 : {
450 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
451 0 : return false;
452 : }
453 : }
454 :
455 : /************************************************************************/
456 : /* ReadStringTable() */
457 : /************************************************************************/
458 :
459 : constexpr int READSTRINGTABLE_IDX_STRING = 1;
460 :
461 35 : static bool ReadStringTable(const GByte *pabyData, const GByte *pabyDataLimit,
462 : OSMContext *psCtxt)
463 : {
464 35 : char *pszStrBuf = (char *)pabyData;
465 :
466 35 : unsigned int nStrCount = 0;
467 35 : int *panStrOff = psCtxt->panStrOff;
468 :
469 35 : psCtxt->pszStrBuf = pszStrBuf;
470 :
471 : try
472 : {
473 35 : if ((unsigned int)(pabyDataLimit - pabyData) > psCtxt->nStrAllocated)
474 : {
475 20 : psCtxt->nStrAllocated =
476 40 : std::max(psCtxt->nStrAllocated * 2,
477 20 : (unsigned int)(pabyDataLimit - pabyData));
478 20 : int *panStrOffNew = (int *)VSI_REALLOC_VERBOSE(
479 : panStrOff, psCtxt->nStrAllocated * sizeof(int));
480 20 : if (panStrOffNew == nullptr)
481 0 : THROW_OSM_PARSING_EXCEPTION;
482 20 : panStrOff = panStrOffNew;
483 : }
484 :
485 70 : while (pabyData < pabyDataLimit)
486 : {
487 35 : int nKey = 0;
488 35 : READ_FIELD_KEY(nKey);
489 :
490 1024 : while (nKey == MAKE_KEY(READSTRINGTABLE_IDX_STRING, WT_DATA))
491 : {
492 1024 : unsigned int nDataLength = 0;
493 1024 : READ_SIZE(pabyData, pabyDataLimit, nDataLength);
494 :
495 1024 : panStrOff[nStrCount++] =
496 1024 : static_cast<int>(pabyData - (GByte *)pszStrBuf);
497 1024 : GByte *pbSaved = const_cast<GByte *>(&pabyData[nDataLength]);
498 :
499 1024 : pabyData += nDataLength;
500 :
501 1024 : if (pabyData < pabyDataLimit)
502 : {
503 989 : READ_FIELD_KEY(nKey);
504 989 : *pbSaved = 0;
505 : /* printf("string[%d] = %s\n", nStrCount-1, pbSaved -
506 : * nDataLength); */
507 : }
508 : else
509 : {
510 35 : *pbSaved = 0;
511 : /* printf("string[%d] = %s\n", nStrCount-1, pbSaved -
512 : * nDataLength); */
513 35 : break;
514 : }
515 : }
516 :
517 35 : if (pabyData < pabyDataLimit)
518 : {
519 0 : SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
520 : }
521 : }
522 :
523 35 : psCtxt->panStrOff = panStrOff;
524 35 : psCtxt->nStrCount = nStrCount;
525 :
526 35 : return pabyData == pabyDataLimit;
527 : }
528 0 : catch (const std::exception &e)
529 : {
530 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
531 0 : psCtxt->panStrOff = panStrOff;
532 0 : psCtxt->nStrCount = nStrCount;
533 0 : return false;
534 : }
535 : }
536 :
537 : /************************************************************************/
538 : /* AddWithOverflowAccepted() */
539 : /************************************************************************/
540 :
541 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
542 24134 : static GIntBig AddWithOverflowAccepted(GIntBig a, GIntBig b)
543 : {
544 : // Assumes complement-to-two signed integer representation and that
545 : // the compiler will safely cast a negative number to unsigned and a
546 : // big unsigned to negative integer.
547 24134 : return static_cast<GIntBig>(static_cast<GUIntBig>(a) +
548 24134 : static_cast<GUIntBig>(b));
549 : }
550 :
551 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
552 3757 : static int AddWithOverflowAccepted(int a, int b)
553 : {
554 : // Assumes complement-to-two signed integer representation and that
555 : // the compiler will safely cast a negative number to unsigned and a
556 : // big unsigned to negative integer.
557 3757 : return static_cast<int>(static_cast<unsigned>(a) +
558 3757 : static_cast<unsigned>(b));
559 : }
560 :
561 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
562 3757 : static unsigned AddWithOverflowAccepted(unsigned a, int b)
563 : {
564 : // Assumes complement-to-two signed integer representation and that
565 : // the compiler will safely cast a negative number to unsigned.
566 3757 : return a + static_cast<unsigned>(b);
567 : }
568 :
569 : /************************************************************************/
570 : /* ReadDenseNodes() */
571 : /************************************************************************/
572 :
573 : constexpr int DENSEINFO_IDX_VERSION = 1;
574 : constexpr int DENSEINFO_IDX_TIMESTAMP = 2;
575 : constexpr int DENSEINFO_IDX_CHANGESET = 3;
576 : constexpr int DENSEINFO_IDX_UID = 4;
577 : constexpr int DENSEINFO_IDX_USER_SID = 5;
578 : constexpr int DENSEINFO_IDX_VISIBLE = 6;
579 :
580 : constexpr int DENSENODES_IDX_ID = 1;
581 : constexpr int DENSENODES_IDX_DENSEINFO = 5;
582 : constexpr int DENSENODES_IDX_LAT = 8;
583 : constexpr int DENSENODES_IDX_LON = 9;
584 : constexpr int DENSENODES_IDX_KEYVALS = 10;
585 :
586 34 : static bool ReadDenseNodes(const GByte *pabyData, const GByte *pabyDataLimit,
587 : OSMContext *psCtxt)
588 : {
589 34 : const GByte *pabyDataIDs = nullptr;
590 34 : const GByte *pabyDataIDsLimit = nullptr;
591 34 : const GByte *pabyDataLat = nullptr;
592 34 : const GByte *pabyDataLon = nullptr;
593 34 : const GByte *apabyData[DENSEINFO_IDX_VISIBLE] = {nullptr, nullptr, nullptr,
594 : nullptr, nullptr, nullptr};
595 34 : const GByte *pabyDataKeyVal = nullptr;
596 34 : unsigned int nMaxTags = 0;
597 :
598 : try
599 : {
600 203 : while (pabyData < pabyDataLimit)
601 : {
602 169 : int nKey = 0;
603 169 : READ_FIELD_KEY(nKey);
604 :
605 169 : if (nKey == MAKE_KEY(DENSENODES_IDX_ID, WT_DATA))
606 : {
607 34 : unsigned int nSize = 0;
608 :
609 34 : if (pabyDataIDs != nullptr)
610 0 : THROW_OSM_PARSING_EXCEPTION;
611 34 : READ_SIZE(pabyData, pabyDataLimit, nSize);
612 :
613 34 : if (nSize > psCtxt->nNodesAllocated)
614 : {
615 19 : psCtxt->nNodesAllocated =
616 19 : std::max(psCtxt->nNodesAllocated * 2, nSize);
617 19 : OSMNode *pasNodesNew = (OSMNode *)VSI_REALLOC_VERBOSE(
618 : psCtxt->pasNodes,
619 : psCtxt->nNodesAllocated * sizeof(OSMNode));
620 19 : if (pasNodesNew == nullptr)
621 0 : THROW_OSM_PARSING_EXCEPTION;
622 19 : psCtxt->pasNodes = pasNodesNew;
623 : }
624 :
625 34 : pabyDataIDs = pabyData;
626 34 : pabyDataIDsLimit = pabyData + nSize;
627 34 : pabyData += nSize;
628 : }
629 135 : else if (nKey == MAKE_KEY(DENSENODES_IDX_DENSEINFO, WT_DATA))
630 : {
631 33 : unsigned int nSize = 0;
632 :
633 33 : READ_SIZE(pabyData, pabyDataLimit, nSize);
634 :
635 : /* Inline reading of DenseInfo structure */
636 :
637 33 : const GByte *pabyDataNewLimit = pabyData + nSize;
638 198 : while (pabyData < pabyDataNewLimit)
639 : {
640 165 : READ_FIELD_KEY(nKey);
641 :
642 165 : const int nFieldNumber = GET_FIELDNUMBER(nKey);
643 165 : if (GET_WIRETYPE(nKey) == WT_DATA &&
644 165 : nFieldNumber >= DENSEINFO_IDX_VERSION &&
645 : nFieldNumber <= DENSEINFO_IDX_VISIBLE)
646 : {
647 165 : if (apabyData[nFieldNumber - 1] != nullptr)
648 0 : THROW_OSM_PARSING_EXCEPTION;
649 165 : READ_SIZE(pabyData, pabyDataNewLimit, nSize);
650 :
651 165 : apabyData[nFieldNumber - 1] = pabyData;
652 165 : pabyData += nSize;
653 : }
654 : else
655 : {
656 0 : SKIP_UNKNOWN_FIELD(pabyData, pabyDataNewLimit, TRUE);
657 : }
658 : }
659 :
660 33 : if (pabyData != pabyDataNewLimit)
661 0 : THROW_OSM_PARSING_EXCEPTION;
662 : }
663 102 : else if (nKey == MAKE_KEY(DENSENODES_IDX_LAT, WT_DATA))
664 : {
665 34 : if (pabyDataLat != nullptr)
666 0 : THROW_OSM_PARSING_EXCEPTION;
667 34 : unsigned int nSize = 0;
668 34 : READ_SIZE(pabyData, pabyDataLimit, nSize);
669 34 : pabyDataLat = pabyData;
670 34 : pabyData += nSize;
671 : }
672 68 : else if (nKey == MAKE_KEY(DENSENODES_IDX_LON, WT_DATA))
673 : {
674 34 : if (pabyDataLon != nullptr)
675 0 : THROW_OSM_PARSING_EXCEPTION;
676 34 : unsigned int nSize = 0;
677 34 : READ_SIZE(pabyData, pabyDataLimit, nSize);
678 34 : pabyDataLon = pabyData;
679 34 : pabyData += nSize;
680 : }
681 34 : else if (nKey == MAKE_KEY(DENSENODES_IDX_KEYVALS, WT_DATA))
682 : {
683 34 : if (pabyDataKeyVal != nullptr)
684 0 : THROW_OSM_PARSING_EXCEPTION;
685 34 : unsigned int nSize = 0;
686 34 : READ_SIZE(pabyData, pabyDataLimit, nSize);
687 :
688 34 : pabyDataKeyVal = pabyData;
689 34 : nMaxTags = nSize / 2;
690 :
691 34 : if (nMaxTags > psCtxt->nTagsAllocated)
692 : {
693 :
694 19 : psCtxt->nTagsAllocated =
695 19 : std::max(psCtxt->nTagsAllocated * 2, nMaxTags);
696 19 : OSMTag *pasTagsNew = (OSMTag *)VSI_REALLOC_VERBOSE(
697 : psCtxt->pasTags,
698 : psCtxt->nTagsAllocated * sizeof(OSMTag));
699 19 : if (pasTagsNew == nullptr)
700 0 : THROW_OSM_PARSING_EXCEPTION;
701 19 : psCtxt->pasTags = pasTagsNew;
702 : }
703 :
704 34 : pabyData += nSize;
705 : }
706 : else
707 : {
708 0 : SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
709 : }
710 : }
711 :
712 34 : if (pabyData != pabyDataLimit)
713 0 : THROW_OSM_PARSING_EXCEPTION;
714 :
715 34 : if (pabyDataIDs != nullptr && pabyDataLat != nullptr &&
716 34 : pabyDataLon != nullptr)
717 : {
718 34 : const GByte *pabyDataVersion = apabyData[DENSEINFO_IDX_VERSION - 1];
719 34 : const GByte *pabyDataTimeStamp =
720 34 : apabyData[DENSEINFO_IDX_TIMESTAMP - 1];
721 34 : const GByte *pabyDataChangeset =
722 34 : apabyData[DENSEINFO_IDX_CHANGESET - 1];
723 34 : const GByte *pabyDataUID = apabyData[DENSEINFO_IDX_UID - 1];
724 34 : const GByte *pabyDataUserSID =
725 34 : apabyData[DENSEINFO_IDX_USER_SID - 1];
726 : /* GByte* pabyDataVisible = apabyData[DENSEINFO_IDX_VISIBLE - 1]; */
727 :
728 34 : GIntBig nID = 0;
729 34 : GIntBig nLat = 0;
730 34 : GIntBig nLon = 0;
731 34 : GIntBig nTimeStamp = 0;
732 34 : GIntBig nChangeset = 0;
733 34 : int nUID = 0;
734 34 : unsigned int nUserSID = 0;
735 34 : int nTags = 0;
736 34 : int nNodes = 0;
737 :
738 34 : const char *pszStrBuf = psCtxt->pszStrBuf;
739 34 : int *panStrOff = psCtxt->panStrOff;
740 34 : const unsigned int nStrCount = psCtxt->nStrCount;
741 34 : OSMTag *pasTags = psCtxt->pasTags;
742 34 : OSMNode *pasNodes = psCtxt->pasNodes;
743 :
744 34 : int nVersion = 0;
745 : /* int nVisible = 1; */
746 :
747 3800 : while (pabyDataIDs < pabyDataIDsLimit)
748 : {
749 : GIntBig nDelta1, nDelta2;
750 3766 : int nKVIndexStart = nTags;
751 :
752 3766 : READ_VARSINT64_NOCHECK(pabyDataIDs, pabyDataIDsLimit, nDelta1);
753 3766 : READ_VARSINT64(pabyDataLat, pabyDataLimit, nDelta2);
754 3766 : nID = AddWithOverflowAccepted(nID, nDelta1);
755 3766 : nLat = AddWithOverflowAccepted(nLat, nDelta2);
756 :
757 3766 : READ_VARSINT64(pabyDataLon, pabyDataLimit, nDelta1);
758 3766 : nLon = AddWithOverflowAccepted(nLon, nDelta1);
759 :
760 3766 : if (pabyDataTimeStamp)
761 : {
762 3757 : READ_VARSINT64(pabyDataTimeStamp, pabyDataLimit, nDelta2);
763 3757 : nTimeStamp = AddWithOverflowAccepted(nTimeStamp, nDelta2);
764 : }
765 3766 : if (pabyDataChangeset)
766 : {
767 3757 : READ_VARSINT64(pabyDataChangeset, pabyDataLimit, nDelta1);
768 3757 : nChangeset = AddWithOverflowAccepted(nChangeset, nDelta1);
769 : }
770 3766 : if (pabyDataVersion)
771 : {
772 3757 : READ_VARINT32(pabyDataVersion, pabyDataLimit, nVersion);
773 : }
774 3766 : if (pabyDataUID)
775 : {
776 3757 : int nDeltaUID = 0;
777 3757 : READ_VARSINT32(pabyDataUID, pabyDataLimit, nDeltaUID);
778 3757 : nUID = AddWithOverflowAccepted(nUID, nDeltaUID);
779 : }
780 3766 : if (pabyDataUserSID)
781 : {
782 3757 : int nDeltaUserSID = 0;
783 3757 : READ_VARSINT32(pabyDataUserSID, pabyDataLimit,
784 : nDeltaUserSID);
785 3757 : nUserSID = AddWithOverflowAccepted(nUserSID, nDeltaUserSID);
786 3757 : if (nUserSID >= nStrCount)
787 0 : THROW_OSM_PARSING_EXCEPTION;
788 : }
789 : /* if( pabyDataVisible )
790 : READ_VARINT32(pabyDataVisible, pabyDataLimit, nVisible); */
791 :
792 3766 : if (pabyDataKeyVal != nullptr && pasTags != nullptr)
793 : {
794 3926 : while (static_cast<unsigned>(nTags) < nMaxTags)
795 : {
796 : unsigned int nKey, nVal;
797 3923 : READ_VARUINT32(pabyDataKeyVal, pabyDataLimit, nKey);
798 3923 : if (nKey == 0)
799 3763 : break;
800 160 : if (nKey >= nStrCount)
801 0 : THROW_OSM_PARSING_EXCEPTION;
802 :
803 160 : READ_VARUINT32(pabyDataKeyVal, pabyDataLimit, nVal);
804 160 : if (nVal >= nStrCount)
805 0 : THROW_OSM_PARSING_EXCEPTION;
806 :
807 160 : pasTags[nTags].pszK = pszStrBuf + panStrOff[nKey];
808 160 : pasTags[nTags].pszV = pszStrBuf + panStrOff[nVal];
809 160 : nTags++;
810 :
811 : /* printf("nKey = %d, nVal = %d\n", nKey, nVal); */
812 : }
813 : }
814 :
815 3766 : if (pasTags != nullptr && nTags > nKVIndexStart)
816 60 : pasNodes[nNodes].pasTags = pasTags + nKVIndexStart;
817 : else
818 3706 : pasNodes[nNodes].pasTags = nullptr;
819 3766 : pasNodes[nNodes].nTags = nTags - nKVIndexStart;
820 :
821 3766 : pasNodes[nNodes].nID = nID;
822 3766 : pasNodes[nNodes].dfLat =
823 3766 : .000000001 * (psCtxt->nLatOffset +
824 3766 : ((double)psCtxt->nGranularity * nLat));
825 3766 : pasNodes[nNodes].dfLon =
826 3766 : .000000001 * (psCtxt->nLonOffset +
827 3766 : ((double)psCtxt->nGranularity * nLon));
828 3766 : if (pasNodes[nNodes].dfLon < -180 ||
829 3766 : pasNodes[nNodes].dfLon > 180 ||
830 3766 : pasNodes[nNodes].dfLat < -90 || pasNodes[nNodes].dfLat > 90)
831 0 : THROW_OSM_PARSING_EXCEPTION;
832 3766 : pasNodes[nNodes].sInfo.bTimeStampIsStr = false;
833 3766 : pasNodes[nNodes].sInfo.ts.nTimeStamp = nTimeStamp;
834 3766 : pasNodes[nNodes].sInfo.nChangeset = nChangeset;
835 3766 : pasNodes[nNodes].sInfo.nVersion = nVersion;
836 3766 : pasNodes[nNodes].sInfo.nUID = nUID;
837 3766 : if (nUserSID >= nStrCount)
838 0 : pasNodes[nNodes].sInfo.pszUserSID = "";
839 : else
840 3766 : pasNodes[nNodes].sInfo.pszUserSID =
841 3766 : pszStrBuf + panStrOff[nUserSID];
842 : /* pasNodes[nNodes].sInfo.nVisible = nVisible; */
843 3766 : nNodes++;
844 : /* printf("nLat = " CPL_FRMT_GIB "\n", nLat); printf("nLon = "
845 : * CPL_FRMT_GIB "\n", nLon); */
846 : }
847 :
848 34 : psCtxt->pfnNotifyNodes(nNodes, pasNodes, psCtxt, psCtxt->user_data);
849 :
850 34 : if (pabyDataIDs != pabyDataIDsLimit)
851 0 : THROW_OSM_PARSING_EXCEPTION;
852 : }
853 :
854 34 : return true;
855 : }
856 0 : catch (const std::exception &e)
857 : {
858 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
859 0 : return false;
860 : }
861 : }
862 :
863 : /************************************************************************/
864 : /* ReadOSMInfo() */
865 : /************************************************************************/
866 :
867 : constexpr int INFO_IDX_VERSION = 1;
868 : constexpr int INFO_IDX_TIMESTAMP = 2;
869 : constexpr int INFO_IDX_CHANGESET = 3;
870 : constexpr int INFO_IDX_UID = 4;
871 : constexpr int INFO_IDX_USER_SID = 5;
872 : constexpr int INFO_IDX_VISIBLE = 6;
873 :
874 : static bool ReadOSMInfo(const GByte *pabyData, const GByte *pabyDataLimit,
875 : OSMInfo *psInfo, OSMContext *psContext) CPL_NO_INLINE;
876 :
877 4896 : static bool ReadOSMInfo(const GByte *pabyData, const GByte *pabyDataLimit,
878 : OSMInfo *psInfo, OSMContext *psContext)
879 : {
880 : try
881 : {
882 4896 : while (pabyData < pabyDataLimit)
883 : {
884 4080 : int nKey = 0;
885 4080 : READ_FIELD_KEY(nKey);
886 :
887 4080 : if (nKey == MAKE_KEY(INFO_IDX_VERSION, WT_VARINT))
888 : {
889 816 : READ_VARINT32(pabyData, pabyDataLimit, psInfo->nVersion);
890 : }
891 3264 : else if (nKey == MAKE_KEY(INFO_IDX_TIMESTAMP, WT_VARINT))
892 : {
893 816 : READ_VARINT64(pabyData, pabyDataLimit, psInfo->ts.nTimeStamp);
894 : }
895 2448 : else if (nKey == MAKE_KEY(INFO_IDX_CHANGESET, WT_VARINT))
896 : {
897 816 : READ_VARINT64(pabyData, pabyDataLimit, psInfo->nChangeset);
898 : }
899 1632 : else if (nKey == MAKE_KEY(INFO_IDX_UID, WT_VARINT))
900 : {
901 816 : READ_VARINT32(pabyData, pabyDataLimit, psInfo->nUID);
902 : }
903 816 : else if (nKey == MAKE_KEY(INFO_IDX_USER_SID, WT_VARINT))
904 : {
905 816 : unsigned int nUserSID = 0;
906 816 : READ_VARUINT32(pabyData, pabyDataLimit, nUserSID);
907 816 : if (nUserSID < psContext->nStrCount)
908 816 : psInfo->pszUserSID =
909 816 : psContext->pszStrBuf + psContext->panStrOff[nUserSID];
910 : }
911 0 : else if (nKey == MAKE_KEY(INFO_IDX_VISIBLE, WT_VARINT))
912 : {
913 0 : SKIP_VARINT(pabyData, pabyDataLimit);
914 : // int nVisible = 0;
915 : // READ_VARINT32(pabyData, pabyDataLimit, /*psInfo->*/nVisible);
916 : }
917 : else
918 : {
919 0 : SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
920 : }
921 : }
922 :
923 816 : return pabyData == pabyDataLimit;
924 : }
925 0 : catch (const std::exception &e)
926 : {
927 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
928 0 : return false;
929 : }
930 : }
931 :
932 : /************************************************************************/
933 : /* ReadNode() */
934 : /************************************************************************/
935 :
936 : /* From
937 : * https://github.com/openstreetmap/osmosis/blob/master/osmosis-osm-binary/src/main/protobuf/osmformat.proto
938 : */
939 : /* The one advertized in http://wiki.openstreetmap.org/wiki/PBF_Format and */
940 : /* used previously seem wrong/old-dated */
941 :
942 : constexpr int NODE_IDX_ID = 1;
943 : constexpr int NODE_IDX_LAT = 8;
944 : constexpr int NODE_IDX_LON = 9;
945 : constexpr int NODE_IDX_KEYS = 2;
946 : constexpr int NODE_IDX_VALS = 3;
947 : constexpr int NODE_IDX_INFO = 4;
948 :
949 9 : static bool ReadNode(const GByte *pabyData, const GByte *pabyDataLimit,
950 : OSMContext *psCtxt)
951 : {
952 : OSMNode sNode;
953 :
954 9 : sNode.nID = 0;
955 9 : sNode.dfLat = 0.0;
956 9 : sNode.dfLon = 0.0;
957 9 : INIT_INFO(&(sNode.sInfo));
958 9 : sNode.nTags = 0;
959 9 : sNode.pasTags = nullptr;
960 :
961 : try
962 : {
963 38 : while (pabyData < pabyDataLimit)
964 : {
965 29 : int nKey = 0;
966 29 : READ_FIELD_KEY(nKey);
967 :
968 29 : if (nKey == MAKE_KEY(NODE_IDX_ID, WT_VARINT))
969 : {
970 9 : READ_VARSINT64_NOCHECK(pabyData, pabyDataLimit, sNode.nID);
971 : }
972 20 : else if (nKey == MAKE_KEY(NODE_IDX_LAT, WT_VARINT))
973 : {
974 9 : GIntBig nLat = 0;
975 9 : READ_VARSINT64_NOCHECK(pabyData, pabyDataLimit, nLat);
976 9 : sNode.dfLat =
977 9 : 0.000000001 * (psCtxt->nLatOffset +
978 9 : ((double)psCtxt->nGranularity * nLat));
979 : }
980 11 : else if (nKey == MAKE_KEY(NODE_IDX_LON, WT_VARINT))
981 : {
982 9 : GIntBig nLon = 0;
983 9 : READ_VARSINT64_NOCHECK(pabyData, pabyDataLimit, nLon);
984 9 : sNode.dfLon =
985 9 : 0.000000001 * (psCtxt->nLonOffset +
986 9 : ((double)psCtxt->nGranularity * nLon));
987 : }
988 2 : else if (nKey == MAKE_KEY(NODE_IDX_KEYS, WT_DATA))
989 : {
990 1 : unsigned int nSize = 0;
991 1 : const GByte *pabyDataNewLimit = nullptr;
992 1 : if (sNode.nTags != 0)
993 0 : THROW_OSM_PARSING_EXCEPTION;
994 1 : READ_SIZE(pabyData, pabyDataLimit, nSize);
995 :
996 1 : if (nSize > psCtxt->nTagsAllocated)
997 : {
998 1 : psCtxt->nTagsAllocated =
999 1 : std::max(psCtxt->nTagsAllocated * 2, nSize);
1000 1 : OSMTag *pasTagsNew = (OSMTag *)VSI_REALLOC_VERBOSE(
1001 : psCtxt->pasTags,
1002 : psCtxt->nTagsAllocated * sizeof(OSMTag));
1003 1 : if (pasTagsNew == nullptr)
1004 0 : THROW_OSM_PARSING_EXCEPTION;
1005 1 : psCtxt->pasTags = pasTagsNew;
1006 : }
1007 :
1008 1 : pabyDataNewLimit = pabyData + nSize;
1009 4 : while (pabyData < pabyDataNewLimit)
1010 : {
1011 3 : unsigned int nKey2 = 0;
1012 3 : READ_VARUINT32(pabyData, pabyDataNewLimit, nKey2);
1013 :
1014 3 : if (nKey2 >= psCtxt->nStrCount)
1015 0 : THROW_OSM_PARSING_EXCEPTION;
1016 :
1017 3 : psCtxt->pasTags[sNode.nTags].pszK =
1018 3 : psCtxt->pszStrBuf + psCtxt->panStrOff[nKey2];
1019 3 : psCtxt->pasTags[sNode.nTags].pszV = "";
1020 3 : sNode.nTags++;
1021 : }
1022 1 : if (pabyData != pabyDataNewLimit)
1023 0 : THROW_OSM_PARSING_EXCEPTION;
1024 : }
1025 1 : else if (nKey == MAKE_KEY(NODE_IDX_VALS, WT_DATA))
1026 : {
1027 1 : unsigned int nIter = 0;
1028 1 : if (sNode.nTags == 0)
1029 0 : THROW_OSM_PARSING_EXCEPTION;
1030 : // unsigned int nSize = 0;
1031 : // READ_VARUINT32(pabyData, pabyDataLimit, nSize);
1032 1 : SKIP_VARINT(pabyData, pabyDataLimit);
1033 :
1034 4 : for (; nIter < sNode.nTags; nIter++)
1035 : {
1036 3 : unsigned int nVal = 0;
1037 3 : READ_VARUINT32(pabyData, pabyDataLimit, nVal);
1038 :
1039 3 : if (nVal >= psCtxt->nStrCount)
1040 0 : THROW_OSM_PARSING_EXCEPTION;
1041 :
1042 3 : psCtxt->pasTags[nIter].pszV =
1043 3 : psCtxt->pszStrBuf + psCtxt->panStrOff[nVal];
1044 : }
1045 : }
1046 0 : else if (nKey == MAKE_KEY(NODE_IDX_INFO, WT_DATA))
1047 : {
1048 0 : unsigned int nSize = 0;
1049 0 : READ_SIZE(pabyData, pabyDataLimit, nSize);
1050 :
1051 0 : if (!ReadOSMInfo(pabyData, pabyDataLimit + nSize, &sNode.sInfo,
1052 : psCtxt))
1053 0 : THROW_OSM_PARSING_EXCEPTION;
1054 :
1055 0 : pabyData += nSize;
1056 : }
1057 : else
1058 : {
1059 0 : SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
1060 : }
1061 : }
1062 :
1063 9 : if (sNode.dfLon < -180 || sNode.dfLon > 180 || sNode.dfLat < -90 ||
1064 9 : sNode.dfLat > 90)
1065 0 : THROW_OSM_PARSING_EXCEPTION;
1066 :
1067 9 : if (pabyData != pabyDataLimit)
1068 0 : THROW_OSM_PARSING_EXCEPTION;
1069 :
1070 9 : if (sNode.nTags)
1071 1 : sNode.pasTags = psCtxt->pasTags;
1072 : else
1073 8 : sNode.pasTags = nullptr;
1074 9 : psCtxt->pfnNotifyNodes(1, &sNode, psCtxt, psCtxt->user_data);
1075 :
1076 9 : return true;
1077 : }
1078 0 : catch (const std::exception &e)
1079 : {
1080 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
1081 0 : return false;
1082 : }
1083 : }
1084 :
1085 : /************************************************************************/
1086 : /* ReadWay() */
1087 : /************************************************************************/
1088 :
1089 : constexpr int WAY_IDX_ID = 1;
1090 : constexpr int WAY_IDX_KEYS = 2;
1091 : constexpr int WAY_IDX_VALS = 3;
1092 : constexpr int WAY_IDX_INFO = 4;
1093 : constexpr int WAY_IDX_REFS = 8;
1094 :
1095 692 : static bool ReadWay(const GByte *pabyData, const GByte *pabyDataLimit,
1096 : OSMContext *psCtxt)
1097 : {
1098 : OSMWay sWay;
1099 692 : sWay.nID = 0;
1100 692 : INIT_INFO(&(sWay.sInfo));
1101 692 : sWay.nTags = 0;
1102 692 : sWay.nRefs = 0;
1103 :
1104 : try
1105 : {
1106 4076 : while (pabyData < pabyDataLimit)
1107 : {
1108 3384 : int nKey = 0;
1109 3384 : READ_FIELD_KEY(nKey);
1110 :
1111 3384 : if (nKey == MAKE_KEY(WAY_IDX_ID, WT_VARINT))
1112 : {
1113 692 : READ_VARINT64(pabyData, pabyDataLimit, sWay.nID);
1114 : }
1115 2692 : else if (nKey == MAKE_KEY(WAY_IDX_KEYS, WT_DATA))
1116 : {
1117 662 : unsigned int nSize = 0;
1118 662 : const GByte *pabyDataNewLimit = nullptr;
1119 662 : if (sWay.nTags != 0)
1120 0 : THROW_OSM_PARSING_EXCEPTION;
1121 662 : READ_SIZE(pabyData, pabyDataLimit, nSize);
1122 :
1123 662 : if (nSize > psCtxt->nTagsAllocated)
1124 : {
1125 0 : psCtxt->nTagsAllocated =
1126 0 : std::max(psCtxt->nTagsAllocated * 2, nSize);
1127 0 : OSMTag *pasTagsNew = (OSMTag *)VSI_REALLOC_VERBOSE(
1128 : psCtxt->pasTags,
1129 : psCtxt->nTagsAllocated * sizeof(OSMTag));
1130 0 : if (pasTagsNew == nullptr)
1131 0 : THROW_OSM_PARSING_EXCEPTION;
1132 0 : psCtxt->pasTags = pasTagsNew;
1133 : }
1134 :
1135 662 : pabyDataNewLimit = pabyData + nSize;
1136 1692 : while (pabyData < pabyDataNewLimit)
1137 : {
1138 1030 : unsigned int nKey2 = 0;
1139 1030 : READ_VARUINT32(pabyData, pabyDataNewLimit, nKey2);
1140 :
1141 1030 : if (nKey2 >= psCtxt->nStrCount)
1142 0 : THROW_OSM_PARSING_EXCEPTION;
1143 :
1144 1030 : psCtxt->pasTags[sWay.nTags].pszK =
1145 1030 : psCtxt->pszStrBuf + psCtxt->panStrOff[nKey2];
1146 1030 : psCtxt->pasTags[sWay.nTags].pszV = "";
1147 1030 : sWay.nTags++;
1148 : }
1149 662 : if (pabyData != pabyDataNewLimit)
1150 0 : THROW_OSM_PARSING_EXCEPTION;
1151 : }
1152 2030 : else if (nKey == MAKE_KEY(WAY_IDX_VALS, WT_DATA))
1153 : {
1154 662 : unsigned int nIter = 0;
1155 662 : if (sWay.nTags == 0)
1156 0 : THROW_OSM_PARSING_EXCEPTION;
1157 : // unsigned int nSize = 0;
1158 : // READ_VARUINT32(pabyData, pabyDataLimit, nSize);
1159 662 : SKIP_VARINT(pabyData, pabyDataLimit);
1160 :
1161 1692 : for (; nIter < sWay.nTags; nIter++)
1162 : {
1163 1030 : unsigned int nVal = 0;
1164 1030 : READ_VARUINT32(pabyData, pabyDataLimit, nVal);
1165 :
1166 1030 : if (nVal >= psCtxt->nStrCount)
1167 0 : THROW_OSM_PARSING_EXCEPTION;
1168 :
1169 1030 : psCtxt->pasTags[nIter].pszV =
1170 1030 : psCtxt->pszStrBuf + psCtxt->panStrOff[nVal];
1171 : }
1172 : }
1173 1368 : else if (nKey == MAKE_KEY(WAY_IDX_INFO, WT_DATA))
1174 : {
1175 676 : unsigned int nSize = 0;
1176 676 : READ_SIZE(pabyData, pabyDataLimit, nSize);
1177 :
1178 676 : if (!ReadOSMInfo(pabyData, pabyData + nSize, &sWay.sInfo,
1179 : psCtxt))
1180 0 : THROW_OSM_PARSING_EXCEPTION;
1181 :
1182 676 : pabyData += nSize;
1183 : }
1184 692 : else if (nKey == MAKE_KEY(WAY_IDX_REFS, WT_DATA))
1185 : {
1186 692 : GIntBig nRefVal = 0;
1187 692 : unsigned int nSize = 0;
1188 692 : const GByte *pabyDataNewLimit = nullptr;
1189 692 : if (sWay.nRefs != 0)
1190 0 : THROW_OSM_PARSING_EXCEPTION;
1191 692 : READ_SIZE(pabyData, pabyDataLimit, nSize);
1192 :
1193 692 : if (nSize > psCtxt->nNodeRefsAllocated)
1194 : {
1195 56 : psCtxt->nNodeRefsAllocated =
1196 56 : std::max(psCtxt->nNodeRefsAllocated * 2, nSize);
1197 56 : GIntBig *panNodeRefsNew = (GIntBig *)VSI_REALLOC_VERBOSE(
1198 : psCtxt->panNodeRefs,
1199 : psCtxt->nNodeRefsAllocated * sizeof(GIntBig));
1200 56 : if (panNodeRefsNew == nullptr)
1201 0 : THROW_OSM_PARSING_EXCEPTION;
1202 56 : psCtxt->panNodeRefs = panNodeRefsNew;
1203 : }
1204 :
1205 692 : pabyDataNewLimit = pabyData + nSize;
1206 5744 : while (pabyData < pabyDataNewLimit)
1207 : {
1208 5052 : GIntBig nDeltaRef = 0;
1209 5052 : READ_VARSINT64_NOCHECK(pabyData, pabyDataNewLimit,
1210 : nDeltaRef);
1211 5052 : nRefVal = AddWithOverflowAccepted(nRefVal, nDeltaRef);
1212 :
1213 5052 : psCtxt->panNodeRefs[sWay.nRefs++] = nRefVal;
1214 : }
1215 :
1216 692 : if (pabyData != pabyDataNewLimit)
1217 0 : THROW_OSM_PARSING_EXCEPTION;
1218 : }
1219 : else
1220 : {
1221 0 : SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
1222 : }
1223 : }
1224 :
1225 692 : if (pabyData != pabyDataLimit)
1226 0 : THROW_OSM_PARSING_EXCEPTION;
1227 :
1228 692 : if (sWay.nTags)
1229 662 : sWay.pasTags = psCtxt->pasTags;
1230 : else
1231 30 : sWay.pasTags = nullptr;
1232 692 : sWay.panNodeRefs = psCtxt->panNodeRefs;
1233 :
1234 692 : psCtxt->pfnNotifyWay(&sWay, psCtxt, psCtxt->user_data);
1235 :
1236 692 : return true;
1237 : }
1238 0 : catch (const std::exception &e)
1239 : {
1240 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
1241 0 : return false;
1242 : }
1243 : }
1244 :
1245 : /************************************************************************/
1246 : /* ReadRelation() */
1247 : /************************************************************************/
1248 :
1249 : constexpr int RELATION_IDX_ID = 1;
1250 : constexpr int RELATION_IDX_KEYS = 2;
1251 : constexpr int RELATION_IDX_VALS = 3;
1252 : constexpr int RELATION_IDX_INFO = 4;
1253 : constexpr int RELATION_IDX_ROLES_SID = 8;
1254 : constexpr int RELATION_IDX_MEMIDS = 9;
1255 : constexpr int RELATION_IDX_TYPES = 10;
1256 :
1257 150 : static bool ReadRelation(const GByte *pabyData, const GByte *pabyDataLimit,
1258 : OSMContext *psCtxt)
1259 : {
1260 : OSMRelation sRelation;
1261 150 : sRelation.nID = 0;
1262 150 : INIT_INFO(&(sRelation.sInfo));
1263 150 : sRelation.nTags = 0;
1264 150 : sRelation.nMembers = 0;
1265 :
1266 : try
1267 : {
1268 1190 : while (pabyData < pabyDataLimit)
1269 : {
1270 1040 : int nKey = 0;
1271 1040 : READ_FIELD_KEY(nKey);
1272 :
1273 1040 : if (nKey == MAKE_KEY(RELATION_IDX_ID, WT_VARINT))
1274 : {
1275 150 : READ_VARINT64(pabyData, pabyDataLimit, sRelation.nID);
1276 : }
1277 890 : else if (nKey == MAKE_KEY(RELATION_IDX_KEYS, WT_DATA))
1278 : {
1279 150 : unsigned int nSize = 0;
1280 150 : const GByte *pabyDataNewLimit = nullptr;
1281 150 : if (sRelation.nTags != 0)
1282 0 : THROW_OSM_PARSING_EXCEPTION;
1283 150 : READ_SIZE(pabyData, pabyDataLimit, nSize);
1284 :
1285 150 : if (nSize > psCtxt->nTagsAllocated)
1286 : {
1287 0 : psCtxt->nTagsAllocated =
1288 0 : std::max(psCtxt->nTagsAllocated * 2, nSize);
1289 0 : OSMTag *pasTagsNew = (OSMTag *)VSI_REALLOC_VERBOSE(
1290 : psCtxt->pasTags,
1291 : psCtxt->nTagsAllocated * sizeof(OSMTag));
1292 0 : if (pasTagsNew == nullptr)
1293 0 : THROW_OSM_PARSING_EXCEPTION;
1294 0 : psCtxt->pasTags = pasTagsNew;
1295 : }
1296 :
1297 150 : pabyDataNewLimit = pabyData + nSize;
1298 330 : while (pabyData < pabyDataNewLimit)
1299 : {
1300 180 : unsigned int nKey2 = 0;
1301 180 : READ_VARUINT32(pabyData, pabyDataNewLimit, nKey2);
1302 :
1303 180 : if (nKey2 >= psCtxt->nStrCount)
1304 0 : THROW_OSM_PARSING_EXCEPTION;
1305 :
1306 180 : psCtxt->pasTags[sRelation.nTags].pszK =
1307 180 : psCtxt->pszStrBuf + psCtxt->panStrOff[nKey2];
1308 180 : psCtxt->pasTags[sRelation.nTags].pszV = "";
1309 180 : sRelation.nTags++;
1310 : }
1311 150 : if (pabyData != pabyDataNewLimit)
1312 0 : THROW_OSM_PARSING_EXCEPTION;
1313 : }
1314 740 : else if (nKey == MAKE_KEY(RELATION_IDX_VALS, WT_DATA))
1315 : {
1316 150 : unsigned int nIter = 0;
1317 150 : if (sRelation.nTags == 0)
1318 0 : THROW_OSM_PARSING_EXCEPTION;
1319 : // unsigned int nSize = 0;
1320 : // READ_VARUINT32(pabyData, pabyDataLimit, nSize);
1321 150 : SKIP_VARINT(pabyData, pabyDataLimit);
1322 :
1323 330 : for (; nIter < sRelation.nTags; nIter++)
1324 : {
1325 180 : unsigned int nVal = 0;
1326 180 : READ_VARUINT32(pabyData, pabyDataLimit, nVal);
1327 :
1328 180 : if (nVal >= psCtxt->nStrCount)
1329 0 : THROW_OSM_PARSING_EXCEPTION;
1330 :
1331 180 : psCtxt->pasTags[nIter].pszV =
1332 180 : psCtxt->pszStrBuf + psCtxt->panStrOff[nVal];
1333 : }
1334 : }
1335 590 : else if (nKey == MAKE_KEY(RELATION_IDX_INFO, WT_DATA))
1336 : {
1337 140 : unsigned int nSize = 0;
1338 140 : READ_SIZE(pabyData, pabyDataLimit, nSize);
1339 :
1340 140 : if (!ReadOSMInfo(pabyData, pabyData + nSize, &sRelation.sInfo,
1341 : psCtxt))
1342 0 : THROW_OSM_PARSING_EXCEPTION;
1343 :
1344 140 : pabyData += nSize;
1345 : }
1346 450 : else if (nKey == MAKE_KEY(RELATION_IDX_ROLES_SID, WT_DATA))
1347 : {
1348 150 : unsigned int nSize = 0;
1349 150 : const GByte *pabyDataNewLimit = nullptr;
1350 150 : if (sRelation.nMembers != 0)
1351 0 : THROW_OSM_PARSING_EXCEPTION;
1352 150 : READ_SIZE(pabyData, pabyDataLimit, nSize);
1353 :
1354 150 : if (nSize > psCtxt->nMembersAllocated)
1355 : {
1356 16 : psCtxt->nMembersAllocated =
1357 16 : std::max(psCtxt->nMembersAllocated * 2, nSize);
1358 16 : OSMMember *pasMembersNew = (OSMMember *)VSI_REALLOC_VERBOSE(
1359 : psCtxt->pasMembers,
1360 : psCtxt->nMembersAllocated * sizeof(OSMMember));
1361 16 : if (pasMembersNew == nullptr)
1362 0 : THROW_OSM_PARSING_EXCEPTION;
1363 16 : psCtxt->pasMembers = pasMembersNew;
1364 : }
1365 :
1366 150 : pabyDataNewLimit = pabyData + nSize;
1367 420 : while (pabyData < pabyDataNewLimit)
1368 : {
1369 270 : unsigned int nRoleSID = 0;
1370 270 : READ_VARUINT32(pabyData, pabyDataNewLimit, nRoleSID);
1371 270 : if (nRoleSID >= psCtxt->nStrCount)
1372 0 : THROW_OSM_PARSING_EXCEPTION;
1373 :
1374 270 : psCtxt->pasMembers[sRelation.nMembers].pszRole =
1375 270 : psCtxt->pszStrBuf + psCtxt->panStrOff[nRoleSID];
1376 270 : psCtxt->pasMembers[sRelation.nMembers].nID = 0;
1377 270 : psCtxt->pasMembers[sRelation.nMembers].eType = MEMBER_NODE;
1378 270 : sRelation.nMembers++;
1379 : }
1380 :
1381 150 : if (pabyData != pabyDataNewLimit)
1382 0 : THROW_OSM_PARSING_EXCEPTION;
1383 : }
1384 300 : else if (nKey == MAKE_KEY(RELATION_IDX_MEMIDS, WT_DATA))
1385 : {
1386 150 : unsigned int nIter = 0;
1387 150 : GIntBig nMemID = 0;
1388 150 : if (sRelation.nMembers == 0)
1389 0 : THROW_OSM_PARSING_EXCEPTION;
1390 : // unsigned int nSize = 0;
1391 : // READ_VARUINT32(pabyData, pabyDataLimit, nSize);
1392 150 : SKIP_VARINT(pabyData, pabyDataLimit);
1393 :
1394 420 : for (; nIter < sRelation.nMembers; nIter++)
1395 : {
1396 270 : GIntBig nDeltaMemID = 0;
1397 270 : READ_VARSINT64(pabyData, pabyDataLimit, nDeltaMemID);
1398 270 : nMemID = AddWithOverflowAccepted(nMemID, nDeltaMemID);
1399 :
1400 270 : psCtxt->pasMembers[nIter].nID = nMemID;
1401 : }
1402 : }
1403 150 : else if (nKey == MAKE_KEY(RELATION_IDX_TYPES, WT_DATA))
1404 : {
1405 150 : unsigned int nIter = 0;
1406 150 : if (sRelation.nMembers == 0)
1407 0 : THROW_OSM_PARSING_EXCEPTION;
1408 150 : unsigned int nSize = 0;
1409 150 : READ_SIZE(pabyData, pabyDataLimit, nSize);
1410 150 : if (nSize != sRelation.nMembers)
1411 0 : THROW_OSM_PARSING_EXCEPTION;
1412 :
1413 420 : for (; nIter < sRelation.nMembers; nIter++)
1414 : {
1415 270 : unsigned int nType = pabyData[nIter];
1416 270 : if (nType > MEMBER_RELATION)
1417 0 : THROW_OSM_PARSING_EXCEPTION;
1418 :
1419 270 : psCtxt->pasMembers[nIter].eType = (OSMMemberType)nType;
1420 : }
1421 150 : pabyData += nSize;
1422 : }
1423 : else
1424 : {
1425 0 : SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
1426 : }
1427 : }
1428 : /* printf("<ReadRelation\n"); */
1429 :
1430 150 : if (pabyData != pabyDataLimit)
1431 0 : THROW_OSM_PARSING_EXCEPTION;
1432 :
1433 150 : if (sRelation.nTags)
1434 150 : sRelation.pasTags = psCtxt->pasTags;
1435 : else
1436 0 : sRelation.pasTags = nullptr;
1437 :
1438 150 : sRelation.pasMembers = psCtxt->pasMembers;
1439 :
1440 150 : psCtxt->pfnNotifyRelation(&sRelation, psCtxt, psCtxt->user_data);
1441 :
1442 150 : return true;
1443 : }
1444 0 : catch (const std::exception &e)
1445 : {
1446 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
1447 0 : return false;
1448 : }
1449 : }
1450 :
1451 : /************************************************************************/
1452 : /* ReadPrimitiveGroup() */
1453 : /************************************************************************/
1454 :
1455 : constexpr int PRIMITIVEGROUP_IDX_NODES = 1;
1456 : // constexpr int PRIMITIVEGROUP_IDX_DENSE = 2;
1457 : // constexpr int PRIMITIVEGROUP_IDX_WAYS = 3;
1458 : constexpr int PRIMITIVEGROUP_IDX_RELATIONS = 4;
1459 : // constexpr int PRIMITIVEGROUP_IDX_CHANGESETS = 5;
1460 :
1461 : typedef bool (*PrimitiveFuncType)(const GByte *pabyData,
1462 : const GByte *pabyDataLimit,
1463 : OSMContext *psCtxt);
1464 :
1465 : static const PrimitiveFuncType apfnPrimitives[] = {ReadNode, ReadDenseNodes,
1466 : ReadWay, ReadRelation};
1467 :
1468 982 : static bool ReadPrimitiveGroup(const GByte *pabyData,
1469 : const GByte *pabyDataLimit, OSMContext *psCtxt)
1470 : {
1471 : try
1472 : {
1473 982 : while (pabyData < pabyDataLimit)
1474 : {
1475 885 : int nKey = 0;
1476 885 : READ_FIELD_KEY(nKey);
1477 :
1478 885 : const int nFieldNumber = GET_FIELDNUMBER(nKey) - 1;
1479 885 : if (GET_WIRETYPE(nKey) == WT_DATA &&
1480 885 : nFieldNumber >= PRIMITIVEGROUP_IDX_NODES - 1 &&
1481 : nFieldNumber <= PRIMITIVEGROUP_IDX_RELATIONS - 1)
1482 : {
1483 885 : unsigned int nSize = 0;
1484 885 : READ_SIZE(pabyData, pabyDataLimit, nSize);
1485 :
1486 885 : if (!apfnPrimitives[nFieldNumber](pabyData, pabyData + nSize,
1487 : psCtxt))
1488 0 : THROW_OSM_PARSING_EXCEPTION;
1489 :
1490 885 : pabyData += nSize;
1491 : }
1492 : else
1493 : {
1494 0 : SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
1495 : }
1496 : }
1497 :
1498 97 : return pabyData == pabyDataLimit;
1499 : }
1500 0 : catch (const std::exception &e)
1501 : {
1502 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
1503 0 : return false;
1504 : }
1505 : }
1506 :
1507 : /************************************************************************/
1508 : /* ReadPrimitiveBlock() */
1509 : /************************************************************************/
1510 :
1511 : constexpr int PRIMITIVEBLOCK_IDX_STRINGTABLE = 1;
1512 : constexpr int PRIMITIVEBLOCK_IDX_PRIMITIVEGROUP = 2;
1513 : constexpr int PRIMITIVEBLOCK_IDX_GRANULARITY = 17;
1514 : constexpr int PRIMITIVEBLOCK_IDX_DATE_GRANULARITY = 18;
1515 : constexpr int PRIMITIVEBLOCK_IDX_LAT_OFFSET = 19;
1516 : constexpr int PRIMITIVEBLOCK_IDX_LON_OFFSET = 20;
1517 :
1518 35 : static bool ReadPrimitiveBlock(const GByte *pabyData,
1519 : const GByte *pabyDataLimit, OSMContext *psCtxt)
1520 : {
1521 35 : const GByte *pabyDataSave = pabyData;
1522 :
1523 35 : psCtxt->pszStrBuf = nullptr;
1524 35 : psCtxt->nStrCount = 0;
1525 35 : psCtxt->nGranularity = 100;
1526 35 : psCtxt->nDateGranularity = 1000;
1527 35 : psCtxt->nLatOffset = 0;
1528 35 : psCtxt->nLonOffset = 0;
1529 :
1530 : try
1531 : {
1532 235 : while (pabyData < pabyDataLimit)
1533 : {
1534 200 : int nKey = 0;
1535 200 : READ_FIELD_KEY(nKey);
1536 :
1537 200 : if (nKey == MAKE_KEY(PRIMITIVEBLOCK_IDX_GRANULARITY, WT_VARINT))
1538 : {
1539 34 : READ_VARINT32(pabyData, pabyDataLimit, psCtxt->nGranularity);
1540 34 : if (psCtxt->nGranularity <= 0)
1541 0 : THROW_OSM_PARSING_EXCEPTION;
1542 : }
1543 166 : else if (nKey ==
1544 : MAKE_KEY(PRIMITIVEBLOCK_IDX_DATE_GRANULARITY, WT_VARINT))
1545 : {
1546 34 : READ_VARINT32(pabyData, pabyDataLimit,
1547 : psCtxt->nDateGranularity);
1548 : }
1549 132 : else if (nKey == MAKE_KEY(PRIMITIVEBLOCK_IDX_LAT_OFFSET, WT_VARINT))
1550 : {
1551 0 : READ_VARINT64(pabyData, pabyDataLimit, psCtxt->nLatOffset);
1552 : }
1553 132 : else if (nKey == MAKE_KEY(PRIMITIVEBLOCK_IDX_LON_OFFSET, WT_VARINT))
1554 : {
1555 0 : READ_VARINT64(pabyData, pabyDataLimit, psCtxt->nLonOffset);
1556 : }
1557 : else
1558 : {
1559 132 : SKIP_UNKNOWN_FIELD_INLINE(pabyData, pabyDataLimit, FALSE);
1560 : }
1561 : }
1562 :
1563 35 : if (pabyData != pabyDataLimit)
1564 0 : THROW_OSM_PARSING_EXCEPTION;
1565 :
1566 35 : pabyData = pabyDataSave;
1567 200 : while (pabyData < pabyDataLimit)
1568 : {
1569 165 : int nKey = 0;
1570 165 : READ_FIELD_KEY(nKey);
1571 :
1572 165 : if (nKey == MAKE_KEY(PRIMITIVEBLOCK_IDX_STRINGTABLE, WT_DATA))
1573 : {
1574 35 : GByte bSaveAfterByte = 0;
1575 35 : GByte *pbSaveAfterByte = nullptr;
1576 35 : if (psCtxt->nStrCount != 0)
1577 0 : THROW_OSM_PARSING_EXCEPTION;
1578 35 : unsigned int nSize = 0;
1579 35 : READ_SIZE(pabyData, pabyDataLimit, nSize);
1580 :
1581 : // Dirty little trick:
1582 : // ReadStringTable() will over-write the byte after the
1583 : // StringTable message with a NUL character, so we backup
1584 : // it to be able to restore it just before issuing the next
1585 : // READ_FIELD_KEY. Then we will re-NUL it to have valid
1586 : // NUL terminated strings.
1587 : // This trick enable us to keep the strings where there are
1588 : // in RAM.
1589 35 : pbSaveAfterByte = const_cast<GByte *>(pabyData + nSize);
1590 35 : bSaveAfterByte = *pbSaveAfterByte;
1591 :
1592 35 : if (!ReadStringTable(pabyData, pabyData + nSize, psCtxt))
1593 0 : THROW_OSM_PARSING_EXCEPTION;
1594 :
1595 35 : pabyData += nSize;
1596 :
1597 35 : *pbSaveAfterByte = bSaveAfterByte;
1598 35 : if (pabyData == pabyDataLimit)
1599 0 : break;
1600 :
1601 35 : READ_FIELD_KEY(nKey);
1602 35 : *pbSaveAfterByte = 0;
1603 :
1604 35 : if (nKey == MAKE_KEY(PRIMITIVEBLOCK_IDX_STRINGTABLE, WT_DATA))
1605 0 : THROW_OSM_PARSING_EXCEPTION;
1606 :
1607 : /* Yes we go on ! */
1608 : }
1609 :
1610 165 : if (nKey == MAKE_KEY(PRIMITIVEBLOCK_IDX_PRIMITIVEGROUP, WT_DATA))
1611 : {
1612 97 : unsigned int nSize = 0;
1613 97 : READ_SIZE(pabyData, pabyDataLimit, nSize);
1614 :
1615 97 : if (!ReadPrimitiveGroup(pabyData, pabyData + nSize, psCtxt))
1616 0 : THROW_OSM_PARSING_EXCEPTION;
1617 :
1618 97 : pabyData += nSize;
1619 : }
1620 : else
1621 : {
1622 68 : SKIP_UNKNOWN_FIELD_INLINE(pabyData, pabyDataLimit, FALSE);
1623 : }
1624 : }
1625 :
1626 35 : return pabyData == pabyDataLimit;
1627 : }
1628 0 : catch (const std::exception &e)
1629 : {
1630 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
1631 0 : return false;
1632 : }
1633 : }
1634 :
1635 : /************************************************************************/
1636 : /* DecompressFunction() */
1637 : /************************************************************************/
1638 :
1639 66 : static void DecompressFunction(void *pDataIn)
1640 : {
1641 66 : DecompressionJob *psJob = static_cast<DecompressionJob *>(pDataIn);
1642 132 : psJob->bStatus = CPLZLibInflate(psJob->pabySrc, psJob->nSrcSize,
1643 66 : psJob->pabyDstBase + psJob->nDstOffset,
1644 66 : psJob->nDstSize, nullptr) != nullptr;
1645 66 : }
1646 :
1647 : /************************************************************************/
1648 : /* RunDecompressionJobs() */
1649 : /************************************************************************/
1650 :
1651 65 : static bool RunDecompressionJobs(OSMContext *psCtxt)
1652 : {
1653 65 : psCtxt->nTotalUncompressedSize = 0;
1654 :
1655 65 : GByte *pabyDstBase = psCtxt->pabyUncompressed;
1656 65 : std::vector<void *> ahJobs;
1657 131 : for (int i = 0; i < psCtxt->nJobs; i++)
1658 : {
1659 66 : psCtxt->asJobs[i].pabyDstBase = pabyDstBase;
1660 66 : if (psCtxt->poWTP)
1661 66 : ahJobs.push_back(&psCtxt->asJobs[i]);
1662 : else
1663 0 : DecompressFunction(&psCtxt->asJobs[i]);
1664 : }
1665 65 : if (psCtxt->poWTP)
1666 : {
1667 65 : psCtxt->poWTP->SubmitJobs(DecompressFunction, ahJobs);
1668 65 : psCtxt->poWTP->WaitCompletion();
1669 : }
1670 :
1671 65 : bool bRet = true;
1672 131 : for (int i = 0; bRet && i < psCtxt->nJobs; i++)
1673 : {
1674 66 : bRet &= psCtxt->asJobs[i].bStatus;
1675 : }
1676 130 : return bRet;
1677 : }
1678 :
1679 : /************************************************************************/
1680 : /* ProcessSingleBlob() */
1681 : /************************************************************************/
1682 :
1683 : // cppcheck-suppress constParameterReference
1684 66 : static bool ProcessSingleBlob(OSMContext *psCtxt, DecompressionJob &sJob,
1685 : BlobType eType)
1686 : {
1687 66 : if (eType == BLOB_OSMHEADER)
1688 : {
1689 66 : return ReadOSMHeader(sJob.pabyDstBase + sJob.nDstOffset,
1690 33 : sJob.pabyDstBase + sJob.nDstOffset + sJob.nDstSize,
1691 33 : psCtxt);
1692 : }
1693 : else
1694 : {
1695 33 : CPLAssert(eType == BLOB_OSMDATA);
1696 66 : return ReadPrimitiveBlock(
1697 33 : sJob.pabyDstBase + sJob.nDstOffset,
1698 33 : sJob.pabyDstBase + sJob.nDstOffset + sJob.nDstSize, psCtxt);
1699 : }
1700 : }
1701 :
1702 : /************************************************************************/
1703 : /* RunDecompressionJobsAndProcessAll() */
1704 : /************************************************************************/
1705 :
1706 33 : static bool RunDecompressionJobsAndProcessAll(OSMContext *psCtxt,
1707 : BlobType eType)
1708 : {
1709 33 : if (!RunDecompressionJobs(psCtxt))
1710 : {
1711 0 : return false;
1712 : }
1713 66 : for (int i = 0; i < psCtxt->nJobs; i++)
1714 : {
1715 33 : if (!ProcessSingleBlob(psCtxt, psCtxt->asJobs[i], eType))
1716 : {
1717 0 : return false;
1718 : }
1719 : }
1720 33 : psCtxt->iNextJob = 0;
1721 33 : psCtxt->nJobs = 0;
1722 33 : return true;
1723 : }
1724 :
1725 : /************************************************************************/
1726 : /* ReadBlob() */
1727 : /************************************************************************/
1728 :
1729 : constexpr int BLOB_IDX_RAW = 1;
1730 : constexpr int BLOB_IDX_RAW_SIZE = 2;
1731 : constexpr int BLOB_IDX_ZLIB_DATA = 3;
1732 :
1733 69 : static bool ReadBlob(OSMContext *psCtxt, BlobType eType)
1734 : {
1735 69 : unsigned int nUncompressedSize = 0;
1736 69 : bool bRet = true;
1737 69 : const GByte *pabyData = psCtxt->pabyBlob + psCtxt->nBlobOffset;
1738 69 : const GByte *pabyLastCheckpointData = pabyData;
1739 69 : const GByte *pabyDataLimit = psCtxt->pabyBlob + psCtxt->nBlobSize;
1740 :
1741 : try
1742 : {
1743 209 : while (pabyData < pabyDataLimit)
1744 : {
1745 140 : int nKey = 0;
1746 140 : READ_FIELD_KEY(nKey);
1747 :
1748 140 : if (nKey == MAKE_KEY(BLOB_IDX_RAW, WT_DATA))
1749 : {
1750 4 : if (psCtxt->nJobs > 0 &&
1751 0 : !RunDecompressionJobsAndProcessAll(psCtxt, eType))
1752 : {
1753 0 : THROW_OSM_PARSING_EXCEPTION;
1754 : }
1755 :
1756 4 : unsigned int nDataLength = 0;
1757 4 : READ_SIZE(pabyData, pabyDataLimit, nDataLength);
1758 4 : if (nDataLength > MAX_BLOB_SIZE)
1759 0 : THROW_OSM_PARSING_EXCEPTION;
1760 :
1761 : // printf("raw data size = %d\n", nDataLength);
1762 :
1763 4 : if (eType == BLOB_OSMHEADER)
1764 : {
1765 : bRet =
1766 2 : ReadOSMHeader(pabyData, pabyData + nDataLength, psCtxt);
1767 : }
1768 2 : else if (eType == BLOB_OSMDATA)
1769 : {
1770 2 : bRet = ReadPrimitiveBlock(pabyData, pabyData + nDataLength,
1771 : psCtxt);
1772 : }
1773 :
1774 4 : pabyData += nDataLength;
1775 : }
1776 136 : else if (nKey == MAKE_KEY(BLOB_IDX_RAW_SIZE, WT_VARINT))
1777 : {
1778 70 : READ_VARUINT32(pabyData, pabyDataLimit, nUncompressedSize);
1779 : // printf("nUncompressedSize = %d\n", nUncompressedSize);
1780 : }
1781 66 : else if (nKey == MAKE_KEY(BLOB_IDX_ZLIB_DATA, WT_DATA))
1782 : {
1783 66 : unsigned int nZlibCompressedSize = 0;
1784 66 : READ_VARUINT32(pabyData, pabyDataLimit, nZlibCompressedSize);
1785 66 : if (CHECK_OOB && nZlibCompressedSize >
1786 66 : psCtxt->nBlobSize - psCtxt->nBlobOffset)
1787 : {
1788 0 : THROW_OSM_PARSING_EXCEPTION;
1789 : }
1790 :
1791 : // printf("nZlibCompressedSize = %d\n", nZlibCompressedSize);
1792 :
1793 66 : if (nUncompressedSize != 0)
1794 : {
1795 66 : if (nUncompressedSize / 100 > nZlibCompressedSize)
1796 : {
1797 : // Too prevent excessive memory allocations
1798 0 : CPLError(CE_Failure, CPLE_AppDefined,
1799 : "Excessive uncompressed vs compressed ratio");
1800 0 : THROW_OSM_PARSING_EXCEPTION;
1801 : }
1802 66 : if (psCtxt->nJobs > 0 &&
1803 1 : (psCtxt->nTotalUncompressedSize >
1804 1 : UINT_MAX - nUncompressedSize ||
1805 1 : psCtxt->nTotalUncompressedSize + nUncompressedSize >
1806 : MAX_ACC_UNCOMPRESSED_SIZE))
1807 : {
1808 0 : pabyData = pabyLastCheckpointData;
1809 0 : break;
1810 : }
1811 66 : unsigned nSizeNeeded =
1812 66 : psCtxt->nTotalUncompressedSize + nUncompressedSize;
1813 66 : if (nSizeNeeded > psCtxt->nUncompressedAllocated)
1814 : {
1815 :
1816 37 : GByte *pabyUncompressedNew = nullptr;
1817 37 : if (psCtxt->nUncompressedAllocated <=
1818 37 : UINT_MAX - psCtxt->nUncompressedAllocated / 3 &&
1819 37 : psCtxt->nUncompressedAllocated +
1820 37 : psCtxt->nUncompressedAllocated / 3 <
1821 : MAX_ACC_UNCOMPRESSED_SIZE)
1822 : {
1823 37 : psCtxt->nUncompressedAllocated =
1824 37 : std::max(psCtxt->nUncompressedAllocated +
1825 37 : psCtxt->nUncompressedAllocated / 3,
1826 37 : nSizeNeeded);
1827 : }
1828 : else
1829 : {
1830 0 : psCtxt->nUncompressedAllocated = nSizeNeeded;
1831 : }
1832 37 : if (psCtxt->nUncompressedAllocated >
1833 : UINT_MAX - EXTRA_BYTES)
1834 0 : THROW_OSM_PARSING_EXCEPTION;
1835 37 : pabyUncompressedNew = (GByte *)VSI_REALLOC_VERBOSE(
1836 : psCtxt->pabyUncompressed,
1837 : psCtxt->nUncompressedAllocated + EXTRA_BYTES);
1838 37 : if (pabyUncompressedNew == nullptr)
1839 0 : THROW_OSM_PARSING_EXCEPTION;
1840 37 : psCtxt->pabyUncompressed = pabyUncompressedNew;
1841 : }
1842 66 : memset(psCtxt->pabyUncompressed + nSizeNeeded, 0,
1843 : EXTRA_BYTES);
1844 :
1845 66 : psCtxt->asJobs[psCtxt->nJobs].pabySrc = pabyData;
1846 66 : psCtxt->asJobs[psCtxt->nJobs].nSrcSize =
1847 66 : nZlibCompressedSize;
1848 66 : psCtxt->asJobs[psCtxt->nJobs].nDstOffset =
1849 66 : psCtxt->nTotalUncompressedSize;
1850 66 : psCtxt->asJobs[psCtxt->nJobs].nDstSize = nUncompressedSize;
1851 66 : psCtxt->nJobs++;
1852 66 : if (psCtxt->poWTP == nullptr || eType != BLOB_OSMDATA)
1853 : {
1854 33 : if (!RunDecompressionJobsAndProcessAll(psCtxt, eType))
1855 : {
1856 0 : THROW_OSM_PARSING_EXCEPTION;
1857 : }
1858 : }
1859 : else
1860 : {
1861 : // Make sure that uncompressed blobs are separated by
1862 : // EXTRA_BYTES in the case where in the future we would
1863 : // implement parallel decoding of them (not sure if
1864 : // that's doable)
1865 33 : psCtxt->nTotalUncompressedSize +=
1866 : nUncompressedSize + EXTRA_BYTES;
1867 : }
1868 : }
1869 :
1870 66 : nUncompressedSize = 0;
1871 66 : pabyData += nZlibCompressedSize;
1872 66 : pabyLastCheckpointData = pabyData;
1873 66 : if (psCtxt->nJobs == N_MAX_JOBS)
1874 0 : break;
1875 : }
1876 : else
1877 : {
1878 0 : SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, TRUE);
1879 : }
1880 : }
1881 :
1882 69 : if (psCtxt->nJobs > 0)
1883 : {
1884 32 : if (!RunDecompressionJobs(psCtxt))
1885 : {
1886 0 : THROW_OSM_PARSING_EXCEPTION;
1887 : }
1888 : // Just process one blob at a time
1889 32 : if (!ProcessSingleBlob(psCtxt, psCtxt->asJobs[0], eType))
1890 : {
1891 0 : THROW_OSM_PARSING_EXCEPTION;
1892 : }
1893 32 : psCtxt->iNextJob = 1;
1894 : }
1895 :
1896 69 : psCtxt->nBlobOffset =
1897 69 : static_cast<unsigned>(pabyData - psCtxt->pabyBlob);
1898 69 : return bRet;
1899 : }
1900 0 : catch (const std::exception &e)
1901 : {
1902 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
1903 0 : return false;
1904 : }
1905 : }
1906 :
1907 : /************************************************************************/
1908 : /* OSM_ProcessBlock() */
1909 : /************************************************************************/
1910 :
1911 72 : static OSMRetCode PBF_ProcessBlock(OSMContext *psCtxt)
1912 : {
1913 : // Process any remaining queued jobs one by one
1914 72 : if (psCtxt->iNextJob < psCtxt->nJobs)
1915 : {
1916 1 : if (!(ProcessSingleBlob(psCtxt, psCtxt->asJobs[psCtxt->iNextJob],
1917 : BLOB_OSMDATA)))
1918 : {
1919 0 : return OSM_ERROR;
1920 : }
1921 1 : psCtxt->iNextJob++;
1922 1 : return OSM_OK;
1923 : }
1924 71 : psCtxt->iNextJob = 0;
1925 71 : psCtxt->nJobs = 0;
1926 :
1927 : // Make sure to finish parsing the last concatenated blocks
1928 71 : if (psCtxt->nBlobOffset < psCtxt->nBlobSize)
1929 : {
1930 0 : return ReadBlob(psCtxt, BLOB_OSMDATA) ? OSM_OK : OSM_ERROR;
1931 : }
1932 71 : psCtxt->nBlobOffset = 0;
1933 71 : psCtxt->nBlobSize = 0;
1934 :
1935 71 : int nBlobCount = 0;
1936 71 : OSMRetCode eRetCode = OSM_OK;
1937 71 : unsigned int nBlobSizeAcc = 0;
1938 71 : BlobType eType = BLOB_UNKNOWN;
1939 : while (true)
1940 : {
1941 : GByte abyHeaderSize[4];
1942 106 : unsigned int nBlobSize = 0;
1943 :
1944 106 : if (VSIFReadL(abyHeaderSize, 4, 1, psCtxt->fp) != 1)
1945 : {
1946 35 : eRetCode = OSM_EOF;
1947 35 : break;
1948 : }
1949 71 : const unsigned int nHeaderSize =
1950 71 : (static_cast<unsigned int>(abyHeaderSize[0]) << 24) |
1951 71 : (abyHeaderSize[1] << 16) | (abyHeaderSize[2] << 8) |
1952 71 : abyHeaderSize[3];
1953 :
1954 71 : psCtxt->nBytesRead += 4;
1955 :
1956 : /* printf("nHeaderSize = %d\n", nHeaderSize); */
1957 71 : if (nHeaderSize > MAX_BLOB_HEADER_SIZE)
1958 : {
1959 1 : eRetCode = OSM_ERROR;
1960 1 : break;
1961 : }
1962 70 : if (VSIFReadL(psCtxt->pabyBlobHeader, 1, nHeaderSize, psCtxt->fp) !=
1963 70 : nHeaderSize)
1964 : {
1965 0 : eRetCode = OSM_ERROR;
1966 0 : break;
1967 : }
1968 :
1969 70 : psCtxt->nBytesRead += nHeaderSize;
1970 :
1971 70 : memset(psCtxt->pabyBlobHeader + nHeaderSize, 0, EXTRA_BYTES);
1972 140 : const bool bRet = ReadBlobHeader(psCtxt->pabyBlobHeader,
1973 70 : psCtxt->pabyBlobHeader + nHeaderSize,
1974 : &nBlobSize, &eType);
1975 70 : if (!bRet || eType == BLOB_UNKNOWN)
1976 : {
1977 0 : eRetCode = OSM_ERROR;
1978 0 : break;
1979 : }
1980 :
1981 : // Limit in OSM PBF spec
1982 70 : if (nBlobSize > MAX_BLOB_SIZE)
1983 : {
1984 0 : eRetCode = OSM_ERROR;
1985 0 : break;
1986 : }
1987 70 : if (nBlobSize + nBlobSizeAcc > psCtxt->nBlobSizeAllocated)
1988 : {
1989 0 : psCtxt->nBlobSizeAllocated = std::max(
1990 0 : std::min(MAX_ACC_BLOB_SIZE, psCtxt->nBlobSizeAllocated * 2),
1991 0 : nBlobSize + nBlobSizeAcc);
1992 0 : GByte *pabyBlobNew = static_cast<GByte *>(VSI_REALLOC_VERBOSE(
1993 : psCtxt->pabyBlob, psCtxt->nBlobSizeAllocated + EXTRA_BYTES));
1994 0 : if (pabyBlobNew == nullptr)
1995 : {
1996 0 : eRetCode = OSM_ERROR;
1997 0 : break;
1998 : }
1999 0 : psCtxt->pabyBlob = pabyBlobNew;
2000 : }
2001 : // Given how Protocol buffer work, we can merge several buffers
2002 : // by just appending them to the previous ones.
2003 70 : if (VSIFReadL(psCtxt->pabyBlob + nBlobSizeAcc, 1, nBlobSize,
2004 70 : psCtxt->fp) != nBlobSize)
2005 : {
2006 0 : eRetCode = OSM_ERROR;
2007 0 : break;
2008 : }
2009 70 : psCtxt->nBytesRead += nBlobSize;
2010 70 : nBlobSizeAcc += nBlobSize;
2011 70 : memset(psCtxt->pabyBlob + nBlobSizeAcc, 0, EXTRA_BYTES);
2012 :
2013 70 : nBlobCount++;
2014 :
2015 70 : if (eType == BLOB_OSMDATA && psCtxt->poWTP != nullptr)
2016 : {
2017 : // Accumulate BLOB_OSMDATA until we reach either the maximum
2018 : // number of jobs or a threshold in bytes
2019 35 : if (nBlobCount == N_MAX_JOBS || nBlobSizeAcc > MAX_ACC_BLOB_SIZE)
2020 : {
2021 : break;
2022 : }
2023 : }
2024 : else
2025 : {
2026 : break;
2027 : }
2028 35 : }
2029 :
2030 71 : if (nBlobCount > 0)
2031 : {
2032 69 : psCtxt->nBlobOffset = 0;
2033 69 : psCtxt->nBlobSize = nBlobSizeAcc;
2034 69 : const bool bRet = ReadBlob(psCtxt, eType);
2035 69 : if (bRet)
2036 : {
2037 69 : if (eRetCode == OSM_EOF &&
2038 34 : (psCtxt->iNextJob < psCtxt->nJobs ||
2039 33 : psCtxt->nBlobOffset < psCtxt->nBlobSize))
2040 : {
2041 1 : eRetCode = OSM_OK;
2042 : }
2043 69 : CPLAssert(psCtxt->iNextJob == psCtxt->nJobs ||
2044 : eType == BLOB_OSMDATA);
2045 : }
2046 : else
2047 : {
2048 0 : eRetCode = OSM_ERROR;
2049 : }
2050 : }
2051 :
2052 71 : return eRetCode;
2053 : }
2054 :
2055 : /************************************************************************/
2056 : /* EmptyNotifyNodesFunc() */
2057 : /************************************************************************/
2058 :
2059 0 : static void EmptyNotifyNodesFunc(unsigned int /* nNodes */,
2060 : OSMNode * /* pasNodes */,
2061 : OSMContext * /* psCtxt */,
2062 : void * /* user_data */)
2063 : {
2064 0 : }
2065 :
2066 : /************************************************************************/
2067 : /* EmptyNotifyWayFunc() */
2068 : /************************************************************************/
2069 :
2070 0 : static void EmptyNotifyWayFunc(OSMWay * /* psWay */, OSMContext * /* psCtxt */,
2071 : void * /* user_data */)
2072 : {
2073 0 : }
2074 :
2075 : /************************************************************************/
2076 : /* EmptyNotifyRelationFunc() */
2077 : /************************************************************************/
2078 :
2079 0 : static void EmptyNotifyRelationFunc(OSMRelation * /* psRelation */,
2080 : OSMContext * /* psCtxt */,
2081 : void * /* user_data */)
2082 : {
2083 0 : }
2084 :
2085 : /************************************************************************/
2086 : /* EmptyNotifyBoundsFunc() */
2087 : /************************************************************************/
2088 :
2089 0 : static void EmptyNotifyBoundsFunc(double /* dfXMin */, double /* dfYMin */,
2090 : double /* dfXMax */, double /* dfYMax */,
2091 : OSMContext * /*psCtxt */,
2092 : void * /* user_data */)
2093 : {
2094 0 : }
2095 :
2096 : #ifdef HAVE_EXPAT
2097 :
2098 : /************************************************************************/
2099 : /* OSM_AddString() */
2100 : /************************************************************************/
2101 :
2102 286 : static const char *OSM_AddString(OSMContext *psCtxt, const char *pszStr)
2103 : {
2104 286 : int nLen = (int)strlen(pszStr);
2105 286 : if (psCtxt->nStrLength + nLen + 1 > psCtxt->nStrAllocated)
2106 : {
2107 0 : CPLError(CE_Failure, CPLE_AppDefined, "String buffer too small");
2108 0 : return "";
2109 : }
2110 286 : char *pszRet = psCtxt->pszStrBuf + psCtxt->nStrLength;
2111 286 : memcpy(pszRet, pszStr, nLen);
2112 286 : pszRet[nLen] = '\0';
2113 286 : psCtxt->nStrLength += nLen + 1;
2114 286 : return pszRet;
2115 : }
2116 :
2117 : /************************************************************************/
2118 : /* OSM_Atoi64() */
2119 : /************************************************************************/
2120 :
2121 261 : static GIntBig OSM_Atoi64(const char *pszString)
2122 : {
2123 261 : return atoll(pszString);
2124 : }
2125 :
2126 : /************************************************************************/
2127 : /* OSM_XML_startElementCbk() */
2128 : /************************************************************************/
2129 :
2130 270 : static void XMLCALL OSM_XML_startElementCbk(void *pUserData,
2131 : const char *pszName,
2132 : const char **ppszAttr)
2133 : {
2134 270 : OSMContext *psCtxt = (OSMContext *)pUserData;
2135 270 : const char **ppszIter = ppszAttr;
2136 :
2137 270 : if (psCtxt->bStopParsing)
2138 0 : return;
2139 :
2140 270 : psCtxt->nWithoutEventCounter = 0;
2141 :
2142 270 : if (psCtxt->bTryToFetchBounds)
2143 : {
2144 15 : if (strcmp(pszName, "bounds") == 0 ||
2145 12 : strcmp(pszName, "bound") == 0 /* osmosis uses bound */)
2146 : {
2147 3 : int nCountCoords = 0;
2148 :
2149 3 : psCtxt->bTryToFetchBounds = false;
2150 :
2151 3 : if (ppszIter)
2152 : {
2153 15 : while (ppszIter[0] != nullptr)
2154 : {
2155 12 : if (strcmp(ppszIter[0], "minlon") == 0)
2156 : {
2157 3 : psCtxt->dfLeft = CPLAtof(ppszIter[1]);
2158 3 : nCountCoords++;
2159 : }
2160 9 : else if (strcmp(ppszIter[0], "minlat") == 0)
2161 : {
2162 3 : psCtxt->dfBottom = CPLAtof(ppszIter[1]);
2163 3 : nCountCoords++;
2164 : }
2165 6 : else if (strcmp(ppszIter[0], "maxlon") == 0)
2166 : {
2167 3 : psCtxt->dfRight = CPLAtof(ppszIter[1]);
2168 3 : nCountCoords++;
2169 : }
2170 3 : else if (strcmp(ppszIter[0], "maxlat") == 0)
2171 : {
2172 3 : psCtxt->dfTop = CPLAtof(ppszIter[1]);
2173 3 : nCountCoords++;
2174 : }
2175 0 : else if (strcmp(ppszIter[0], "box") ==
2176 : 0 /* osmosis uses box */)
2177 : {
2178 : char **papszTokens =
2179 0 : CSLTokenizeString2(ppszIter[1], ",", 0);
2180 0 : if (CSLCount(papszTokens) == 4)
2181 : {
2182 0 : psCtxt->dfBottom = CPLAtof(papszTokens[0]);
2183 0 : psCtxt->dfLeft = CPLAtof(papszTokens[1]);
2184 0 : psCtxt->dfTop = CPLAtof(papszTokens[2]);
2185 0 : psCtxt->dfRight = CPLAtof(papszTokens[3]);
2186 0 : nCountCoords = 4;
2187 : }
2188 0 : CSLDestroy(papszTokens);
2189 : }
2190 12 : ppszIter += 2;
2191 : }
2192 : }
2193 :
2194 3 : if (nCountCoords == 4)
2195 : {
2196 3 : psCtxt->pfnNotifyBounds(psCtxt->dfLeft, psCtxt->dfBottom,
2197 : psCtxt->dfRight, psCtxt->dfTop, psCtxt,
2198 : psCtxt->user_data);
2199 : }
2200 : }
2201 : }
2202 :
2203 270 : if (!psCtxt->bInNode && !psCtxt->bInWay && !psCtxt->bInRelation &&
2204 85 : strcmp(pszName, "node") == 0)
2205 : {
2206 32 : psCtxt->bInNode = true;
2207 32 : psCtxt->bTryToFetchBounds = false;
2208 :
2209 32 : psCtxt->nStrLength = 0;
2210 32 : psCtxt->pszStrBuf[0] = '\0';
2211 32 : psCtxt->nTags = 0;
2212 :
2213 32 : memset(&(psCtxt->pasNodes[0]), 0, sizeof(OSMNode));
2214 32 : psCtxt->pasNodes[0].sInfo.pszUserSID = "";
2215 :
2216 32 : if (ppszIter)
2217 : {
2218 263 : while (ppszIter[0] != nullptr)
2219 : {
2220 231 : if (strcmp(ppszIter[0], "id") == 0)
2221 : {
2222 32 : psCtxt->pasNodes[0].nID = OSM_Atoi64(ppszIter[1]);
2223 : }
2224 199 : else if (strcmp(ppszIter[0], "lat") == 0)
2225 : {
2226 32 : psCtxt->pasNodes[0].dfLat = CPLAtof(ppszIter[1]);
2227 : }
2228 167 : else if (strcmp(ppszIter[0], "lon") == 0)
2229 : {
2230 32 : psCtxt->pasNodes[0].dfLon = CPLAtof(ppszIter[1]);
2231 : }
2232 135 : else if (strcmp(ppszIter[0], "version") == 0)
2233 : {
2234 27 : psCtxt->pasNodes[0].sInfo.nVersion = atoi(ppszIter[1]);
2235 : }
2236 108 : else if (strcmp(ppszIter[0], "changeset") == 0)
2237 : {
2238 27 : psCtxt->pasNodes[0].sInfo.nChangeset =
2239 27 : OSM_Atoi64(ppszIter[1]);
2240 : }
2241 81 : else if (strcmp(ppszIter[0], "user") == 0)
2242 : {
2243 54 : psCtxt->pasNodes[0].sInfo.pszUserSID =
2244 27 : OSM_AddString(psCtxt, ppszIter[1]);
2245 : }
2246 54 : else if (strcmp(ppszIter[0], "uid") == 0)
2247 : {
2248 27 : psCtxt->pasNodes[0].sInfo.nUID = atoi(ppszIter[1]);
2249 : }
2250 27 : else if (strcmp(ppszIter[0], "timestamp") == 0)
2251 : {
2252 54 : psCtxt->pasNodes[0].sInfo.ts.pszTimeStamp =
2253 27 : OSM_AddString(psCtxt, ppszIter[1]);
2254 27 : psCtxt->pasNodes[0].sInfo.bTimeStampIsStr = true;
2255 : }
2256 231 : ppszIter += 2;
2257 : }
2258 : }
2259 : }
2260 :
2261 238 : else if (!psCtxt->bInNode && !psCtxt->bInWay && !psCtxt->bInRelation &&
2262 53 : strcmp(pszName, "way") == 0)
2263 : {
2264 25 : psCtxt->bInWay = true;
2265 :
2266 25 : psCtxt->nStrLength = 0;
2267 25 : psCtxt->pszStrBuf[0] = '\0';
2268 25 : psCtxt->nTags = 0;
2269 :
2270 25 : memset(&(psCtxt->sWay), 0, sizeof(OSMWay));
2271 25 : psCtxt->sWay.sInfo.pszUserSID = "";
2272 :
2273 25 : if (ppszIter)
2274 : {
2275 170 : while (ppszIter[0] != nullptr)
2276 : {
2277 145 : if (strcmp(ppszIter[0], "id") == 0)
2278 : {
2279 25 : psCtxt->sWay.nID = OSM_Atoi64(ppszIter[1]);
2280 : }
2281 120 : else if (strcmp(ppszIter[0], "version") == 0)
2282 : {
2283 24 : psCtxt->sWay.sInfo.nVersion = atoi(ppszIter[1]);
2284 : }
2285 96 : else if (strcmp(ppszIter[0], "changeset") == 0)
2286 : {
2287 24 : psCtxt->sWay.sInfo.nChangeset = OSM_Atoi64(ppszIter[1]);
2288 : }
2289 72 : else if (strcmp(ppszIter[0], "user") == 0)
2290 : {
2291 24 : psCtxt->sWay.sInfo.pszUserSID =
2292 24 : OSM_AddString(psCtxt, ppszIter[1]);
2293 : }
2294 48 : else if (strcmp(ppszIter[0], "uid") == 0)
2295 : {
2296 24 : psCtxt->sWay.sInfo.nUID = atoi(ppszIter[1]);
2297 : }
2298 24 : else if (strcmp(ppszIter[0], "timestamp") == 0)
2299 : {
2300 24 : psCtxt->sWay.sInfo.ts.pszTimeStamp =
2301 24 : OSM_AddString(psCtxt, ppszIter[1]);
2302 24 : psCtxt->sWay.sInfo.bTimeStampIsStr = true;
2303 : }
2304 145 : ppszIter += 2;
2305 : }
2306 : }
2307 : }
2308 :
2309 213 : else if (!psCtxt->bInNode && !psCtxt->bInWay && !psCtxt->bInRelation &&
2310 28 : strcmp(pszName, "relation") == 0)
2311 : {
2312 16 : psCtxt->bInRelation = true;
2313 :
2314 16 : psCtxt->nStrLength = 0;
2315 16 : psCtxt->pszStrBuf[0] = '\0';
2316 16 : psCtxt->nTags = 0;
2317 :
2318 16 : memset(&(psCtxt->sRelation), 0, sizeof(OSMRelation));
2319 16 : psCtxt->sRelation.sInfo.pszUserSID = "";
2320 :
2321 16 : if (ppszIter)
2322 : {
2323 107 : while (ppszIter[0] != nullptr)
2324 : {
2325 91 : if (strcmp(ppszIter[0], "id") == 0)
2326 : {
2327 16 : psCtxt->sRelation.nID = OSM_Atoi64(ppszIter[1]);
2328 : }
2329 75 : else if (strcmp(ppszIter[0], "version") == 0)
2330 : {
2331 15 : psCtxt->sRelation.sInfo.nVersion = atoi(ppszIter[1]);
2332 : }
2333 60 : else if (strcmp(ppszIter[0], "changeset") == 0)
2334 : {
2335 15 : psCtxt->sRelation.sInfo.nChangeset =
2336 15 : OSM_Atoi64(ppszIter[1]);
2337 : }
2338 45 : else if (strcmp(ppszIter[0], "user") == 0)
2339 : {
2340 15 : psCtxt->sRelation.sInfo.pszUserSID =
2341 15 : OSM_AddString(psCtxt, ppszIter[1]);
2342 : }
2343 30 : else if (strcmp(ppszIter[0], "uid") == 0)
2344 : {
2345 15 : psCtxt->sRelation.sInfo.nUID = atoi(ppszIter[1]);
2346 : }
2347 15 : else if (strcmp(ppszIter[0], "timestamp") == 0)
2348 : {
2349 15 : psCtxt->sRelation.sInfo.ts.pszTimeStamp =
2350 15 : OSM_AddString(psCtxt, ppszIter[1]);
2351 15 : psCtxt->sRelation.sInfo.bTimeStampIsStr = true;
2352 : }
2353 91 : ppszIter += 2;
2354 : }
2355 : }
2356 : }
2357 :
2358 197 : else if (psCtxt->bInWay && strcmp(pszName, "nd") == 0)
2359 : {
2360 94 : if (ppszAttr != nullptr && ppszAttr[0] != nullptr &&
2361 94 : strcmp(ppszAttr[0], "ref") == 0)
2362 : {
2363 94 : if (psCtxt->sWay.nRefs < psCtxt->nNodeRefsAllocated)
2364 : {
2365 188 : psCtxt->panNodeRefs[psCtxt->sWay.nRefs] =
2366 94 : OSM_Atoi64(ppszAttr[1]);
2367 94 : psCtxt->sWay.nRefs++;
2368 : }
2369 : else
2370 : {
2371 0 : CPLError(CE_Failure, CPLE_AppDefined,
2372 : "Too many nodes referenced in way " CPL_FRMT_GIB,
2373 : psCtxt->sWay.nID);
2374 : }
2375 : }
2376 : }
2377 :
2378 103 : else if (psCtxt->bInRelation && strcmp(pszName, "member") == 0)
2379 : {
2380 : /* 300 is the recommended value, but there are files with more than 2000
2381 : * so we should be able */
2382 : /* to realloc over that value */
2383 28 : if (psCtxt->sRelation.nMembers >= psCtxt->nMembersAllocated)
2384 : {
2385 0 : int nMembersAllocated = std::max(psCtxt->nMembersAllocated * 2,
2386 0 : psCtxt->sRelation.nMembers + 1);
2387 0 : OSMMember *pasMembersNew = (OSMMember *)VSI_REALLOC_VERBOSE(
2388 : psCtxt->pasMembers, nMembersAllocated * sizeof(OSMMember));
2389 0 : if (pasMembersNew == nullptr)
2390 : {
2391 0 : CPLError(CE_Failure, CPLE_AppDefined,
2392 : "Cannot allocate enough memory to store members of "
2393 : "relation " CPL_FRMT_GIB,
2394 : psCtxt->sRelation.nID);
2395 0 : return;
2396 : }
2397 0 : psCtxt->nMembersAllocated = nMembersAllocated;
2398 0 : psCtxt->pasMembers = pasMembersNew;
2399 : }
2400 :
2401 28 : OSMMember *psMember = &(psCtxt->pasMembers[psCtxt->sRelation.nMembers]);
2402 28 : psCtxt->sRelation.nMembers++;
2403 :
2404 28 : psMember->nID = 0;
2405 28 : psMember->pszRole = "";
2406 28 : psMember->eType = MEMBER_NODE;
2407 :
2408 28 : if (ppszIter)
2409 : {
2410 112 : while (ppszIter[0] != nullptr)
2411 : {
2412 84 : if (strcmp(ppszIter[0], "ref") == 0)
2413 : {
2414 28 : psMember->nID = OSM_Atoi64(ppszIter[1]);
2415 : }
2416 56 : else if (strcmp(ppszIter[0], "type") == 0)
2417 : {
2418 28 : if (strcmp(ppszIter[1], "node") == 0)
2419 3 : psMember->eType = MEMBER_NODE;
2420 25 : else if (strcmp(ppszIter[1], "way") == 0)
2421 25 : psMember->eType = MEMBER_WAY;
2422 0 : else if (strcmp(ppszIter[1], "relation") == 0)
2423 0 : psMember->eType = MEMBER_RELATION;
2424 : }
2425 28 : else if (strcmp(ppszIter[0], "role") == 0)
2426 : {
2427 28 : psMember->pszRole = OSM_AddString(psCtxt, ppszIter[1]);
2428 : }
2429 84 : ppszIter += 2;
2430 : }
2431 28 : }
2432 : }
2433 75 : else if ((psCtxt->bInNode || psCtxt->bInWay || psCtxt->bInRelation) &&
2434 63 : strcmp(pszName, "tag") == 0)
2435 : {
2436 63 : if (psCtxt->nTags == psCtxt->nTagsAllocated)
2437 : {
2438 0 : psCtxt->nTagsAllocated = psCtxt->nTagsAllocated * 2;
2439 0 : OSMTag *pasTagsNew = (OSMTag *)VSI_REALLOC_VERBOSE(
2440 : psCtxt->pasTags, psCtxt->nTagsAllocated * sizeof(OSMTag));
2441 0 : if (pasTagsNew == nullptr)
2442 : {
2443 0 : if (psCtxt->bInNode)
2444 0 : CPLError(CE_Failure, CPLE_AppDefined,
2445 : "Too many tags in node " CPL_FRMT_GIB,
2446 0 : psCtxt->pasNodes[0].nID);
2447 0 : else if (psCtxt->bInWay)
2448 0 : CPLError(CE_Failure, CPLE_AppDefined,
2449 : "Too many tags in way " CPL_FRMT_GIB,
2450 : psCtxt->sWay.nID);
2451 0 : else if (psCtxt->bInRelation)
2452 0 : CPLError(CE_Failure, CPLE_AppDefined,
2453 : "Too many tags in relation " CPL_FRMT_GIB,
2454 : psCtxt->sRelation.nID);
2455 0 : return;
2456 : }
2457 0 : psCtxt->pasTags = pasTagsNew;
2458 : }
2459 :
2460 63 : OSMTag *psTag = &(psCtxt->pasTags[psCtxt->nTags]);
2461 63 : psCtxt->nTags++;
2462 :
2463 63 : psTag->pszK = "";
2464 63 : psTag->pszV = "";
2465 :
2466 63 : if (ppszIter)
2467 : {
2468 189 : while (ppszIter[0] != nullptr)
2469 : {
2470 126 : if (ppszIter[0][0] == 'k')
2471 : {
2472 63 : psTag->pszK = OSM_AddString(psCtxt, ppszIter[1]);
2473 : }
2474 63 : else if (ppszIter[0][0] == 'v')
2475 : {
2476 63 : psTag->pszV = OSM_AddString(psCtxt, ppszIter[1]);
2477 : }
2478 126 : ppszIter += 2;
2479 : }
2480 : }
2481 : }
2482 : }
2483 :
2484 : /************************************************************************/
2485 : /* OSM_XML_endElementCbk() */
2486 : /************************************************************************/
2487 :
2488 268 : static void XMLCALL OSM_XML_endElementCbk(void *pUserData, const char *pszName)
2489 : {
2490 268 : OSMContext *psCtxt = (OSMContext *)pUserData;
2491 :
2492 268 : if (psCtxt->bStopParsing)
2493 0 : return;
2494 :
2495 268 : psCtxt->nWithoutEventCounter = 0;
2496 :
2497 268 : if (psCtxt->bInNode && strcmp(pszName, "node") == 0)
2498 : {
2499 : // Written this way to deal with NaN
2500 32 : if (!(psCtxt->pasNodes[0].dfLon >= -180 &&
2501 32 : psCtxt->pasNodes[0].dfLon <= 180 &&
2502 32 : psCtxt->pasNodes[0].dfLat >= -90 &&
2503 32 : psCtxt->pasNodes[0].dfLat <= 90))
2504 : {
2505 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid lon=%f lat=%f",
2506 0 : psCtxt->pasNodes[0].dfLon, psCtxt->pasNodes[0].dfLat);
2507 : }
2508 : else
2509 : {
2510 32 : psCtxt->pasNodes[0].nTags = psCtxt->nTags;
2511 32 : psCtxt->pasNodes[0].pasTags = psCtxt->pasTags;
2512 :
2513 32 : psCtxt->pfnNotifyNodes(1, psCtxt->pasNodes, psCtxt,
2514 : psCtxt->user_data);
2515 :
2516 32 : psCtxt->bHasFoundFeature = true;
2517 : }
2518 32 : psCtxt->bInNode = false;
2519 : }
2520 :
2521 236 : else if (psCtxt->bInWay && strcmp(pszName, "way") == 0)
2522 : {
2523 25 : psCtxt->sWay.nTags = psCtxt->nTags;
2524 25 : psCtxt->sWay.pasTags = psCtxt->pasTags;
2525 :
2526 25 : psCtxt->sWay.panNodeRefs = psCtxt->panNodeRefs;
2527 :
2528 25 : psCtxt->pfnNotifyWay(&(psCtxt->sWay), psCtxt, psCtxt->user_data);
2529 :
2530 25 : psCtxt->bHasFoundFeature = true;
2531 :
2532 25 : psCtxt->bInWay = false;
2533 : }
2534 :
2535 211 : else if (psCtxt->bInRelation && strcmp(pszName, "relation") == 0)
2536 : {
2537 16 : psCtxt->sRelation.nTags = psCtxt->nTags;
2538 16 : psCtxt->sRelation.pasTags = psCtxt->pasTags;
2539 :
2540 16 : psCtxt->sRelation.pasMembers = psCtxt->pasMembers;
2541 :
2542 16 : psCtxt->pfnNotifyRelation(&(psCtxt->sRelation), psCtxt,
2543 : psCtxt->user_data);
2544 :
2545 16 : psCtxt->bHasFoundFeature = true;
2546 :
2547 16 : psCtxt->bInRelation = false;
2548 : }
2549 : }
2550 :
2551 : /************************************************************************/
2552 : /* dataHandlerCbk() */
2553 : /************************************************************************/
2554 :
2555 66176 : static void XMLCALL OSM_XML_dataHandlerCbk(void *pUserData,
2556 : const char * /* data */,
2557 : int /* nLen */)
2558 : {
2559 66176 : OSMContext *psCtxt = static_cast<OSMContext *>(pUserData);
2560 :
2561 66176 : if (psCtxt->bStopParsing)
2562 0 : return;
2563 :
2564 66176 : psCtxt->nWithoutEventCounter = 0;
2565 :
2566 66176 : psCtxt->nDataHandlerCounter++;
2567 66176 : if (psCtxt->nDataHandlerCounter >= XML_BUFSIZE)
2568 : {
2569 1 : CPLError(CE_Failure, CPLE_AppDefined,
2570 : "File probably corrupted (million laugh pattern)");
2571 1 : XML_StopParser(psCtxt->hXMLParser, XML_FALSE);
2572 1 : psCtxt->bStopParsing = true;
2573 1 : return;
2574 : }
2575 : }
2576 :
2577 : /************************************************************************/
2578 : /* XML_ProcessBlock() */
2579 : /************************************************************************/
2580 :
2581 12 : static OSMRetCode XML_ProcessBlock(OSMContext *psCtxt)
2582 : {
2583 12 : if (psCtxt->bEOF)
2584 3 : return OSM_EOF;
2585 9 : if (psCtxt->bStopParsing)
2586 0 : return OSM_ERROR;
2587 :
2588 9 : psCtxt->bHasFoundFeature = false;
2589 9 : psCtxt->nWithoutEventCounter = 0;
2590 :
2591 0 : do
2592 : {
2593 9 : psCtxt->nDataHandlerCounter = 0;
2594 :
2595 18 : const unsigned int nLen = (unsigned int)VSIFReadL(
2596 9 : psCtxt->pabyBlob, 1, XML_BUFSIZE, psCtxt->fp);
2597 :
2598 9 : psCtxt->nBytesRead += nLen;
2599 :
2600 9 : psCtxt->bEOF = CPL_TO_BOOL(VSIFEofL(psCtxt->fp));
2601 : const int eErr =
2602 18 : XML_Parse(psCtxt->hXMLParser, (const char *)psCtxt->pabyBlob, nLen,
2603 9 : psCtxt->bEOF);
2604 :
2605 9 : if (eErr == XML_STATUS_ERROR)
2606 : {
2607 2 : CPLError(CE_Failure, CPLE_AppDefined,
2608 : "XML parsing of OSM file failed : %s "
2609 : "at line %d, column %d",
2610 : XML_ErrorString(XML_GetErrorCode(psCtxt->hXMLParser)),
2611 2 : (int)XML_GetCurrentLineNumber(psCtxt->hXMLParser),
2612 2 : (int)XML_GetCurrentColumnNumber(psCtxt->hXMLParser));
2613 2 : psCtxt->bStopParsing = true;
2614 : }
2615 9 : psCtxt->nWithoutEventCounter++;
2616 0 : } while (!psCtxt->bEOF && !psCtxt->bStopParsing &&
2617 9 : !psCtxt->bHasFoundFeature && psCtxt->nWithoutEventCounter < 10);
2618 :
2619 9 : if (psCtxt->nWithoutEventCounter == 10)
2620 : {
2621 0 : CPLError(CE_Failure, CPLE_AppDefined,
2622 : "Too much data inside one element. File probably corrupted");
2623 0 : psCtxt->bStopParsing = true;
2624 : }
2625 :
2626 9 : return psCtxt->bStopParsing ? OSM_ERROR : psCtxt->bEOF ? OSM_EOF : OSM_OK;
2627 : }
2628 :
2629 : #endif
2630 :
2631 : /************************************************************************/
2632 : /* OSM_Open() */
2633 : /************************************************************************/
2634 :
2635 31 : OSMContext *OSM_Open(const char *pszFilename, NotifyNodesFunc pfnNotifyNodes,
2636 : NotifyWayFunc pfnNotifyWay,
2637 : NotifyRelationFunc pfnNotifyRelation,
2638 : NotifyBoundsFunc pfnNotifyBounds, void *user_data)
2639 : {
2640 :
2641 31 : VSILFILE *fp = VSIFOpenL(pszFilename, "rb");
2642 31 : if (fp == nullptr)
2643 0 : return nullptr;
2644 :
2645 : GByte abyHeader[1024];
2646 : int nRead =
2647 31 : static_cast<int>(VSIFReadL(abyHeader, 1, sizeof(abyHeader) - 1, fp));
2648 31 : abyHeader[nRead] = '\0';
2649 :
2650 31 : bool bPBF = false;
2651 :
2652 31 : if (strstr((const char *)abyHeader, "<osm") != nullptr)
2653 : {
2654 : /* OSM XML */
2655 : #ifndef HAVE_EXPAT
2656 : CPLError(CE_Failure, CPLE_AppDefined,
2657 : "OSM XML detected, but Expat parser not available");
2658 : VSIFCloseL(fp);
2659 : return nullptr;
2660 : #endif
2661 : }
2662 : else
2663 : {
2664 21 : const int nLimitI = nRead - static_cast<int>(strlen("OSMHeader"));
2665 141 : for (int i = 0; i < nLimitI; i++)
2666 : {
2667 141 : if (memcmp(abyHeader + i, "OSMHeader", strlen("OSMHeader")) == 0)
2668 : {
2669 21 : bPBF = true;
2670 21 : break;
2671 : }
2672 : }
2673 21 : if (!bPBF)
2674 : {
2675 0 : VSIFCloseL(fp);
2676 0 : return nullptr;
2677 : }
2678 : }
2679 :
2680 31 : VSIFSeekL(fp, 0, SEEK_SET);
2681 :
2682 : OSMContext *psCtxt =
2683 31 : static_cast<OSMContext *>(VSI_MALLOC_VERBOSE(sizeof(OSMContext)));
2684 31 : if (psCtxt == nullptr)
2685 : {
2686 0 : VSIFCloseL(fp);
2687 0 : return nullptr;
2688 : }
2689 31 : memset(psCtxt, 0, sizeof(OSMContext));
2690 31 : psCtxt->bPBF = bPBF;
2691 31 : psCtxt->fp = fp;
2692 31 : psCtxt->pfnNotifyNodes = pfnNotifyNodes;
2693 31 : if (pfnNotifyNodes == nullptr)
2694 0 : psCtxt->pfnNotifyNodes = EmptyNotifyNodesFunc;
2695 31 : psCtxt->pfnNotifyWay = pfnNotifyWay;
2696 31 : if (pfnNotifyWay == nullptr)
2697 0 : psCtxt->pfnNotifyWay = EmptyNotifyWayFunc;
2698 31 : psCtxt->pfnNotifyRelation = pfnNotifyRelation;
2699 31 : if (pfnNotifyRelation == nullptr)
2700 0 : psCtxt->pfnNotifyRelation = EmptyNotifyRelationFunc;
2701 31 : psCtxt->pfnNotifyBounds = pfnNotifyBounds;
2702 31 : if (pfnNotifyBounds == nullptr)
2703 0 : psCtxt->pfnNotifyBounds = EmptyNotifyBoundsFunc;
2704 31 : psCtxt->user_data = user_data;
2705 :
2706 31 : if (bPBF)
2707 : {
2708 21 : psCtxt->nBlobSizeAllocated = 64 * 1024 + EXTRA_BYTES;
2709 : }
2710 : #ifdef HAVE_EXPAT
2711 : else
2712 : {
2713 10 : psCtxt->nBlobSizeAllocated = XML_BUFSIZE;
2714 :
2715 10 : psCtxt->nStrAllocated = 1024 * 1024;
2716 10 : psCtxt->pszStrBuf = (char *)VSI_MALLOC_VERBOSE(psCtxt->nStrAllocated);
2717 10 : if (psCtxt->pszStrBuf)
2718 10 : psCtxt->pszStrBuf[0] = '\0';
2719 :
2720 10 : psCtxt->hXMLParser = OGRCreateExpatXMLParser();
2721 10 : XML_SetUserData(psCtxt->hXMLParser, psCtxt);
2722 10 : XML_SetElementHandler(psCtxt->hXMLParser, OSM_XML_startElementCbk,
2723 : OSM_XML_endElementCbk);
2724 10 : XML_SetCharacterDataHandler(psCtxt->hXMLParser, OSM_XML_dataHandlerCbk);
2725 :
2726 10 : psCtxt->bTryToFetchBounds = true;
2727 :
2728 10 : psCtxt->nNodesAllocated = 1;
2729 10 : psCtxt->pasNodes = (OSMNode *)VSI_MALLOC_VERBOSE(
2730 : sizeof(OSMNode) * psCtxt->nNodesAllocated);
2731 :
2732 10 : psCtxt->nTagsAllocated = 256;
2733 10 : psCtxt->pasTags = (OSMTag *)VSI_MALLOC_VERBOSE(sizeof(OSMTag) *
2734 : psCtxt->nTagsAllocated);
2735 :
2736 : /* 300 is the recommended value, but there are files with more than 2000
2737 : * so we should be able */
2738 : /* to realloc over that value */
2739 10 : psCtxt->nMembersAllocated = 2000;
2740 10 : psCtxt->pasMembers = (OSMMember *)VSI_MALLOC_VERBOSE(
2741 : sizeof(OSMMember) * psCtxt->nMembersAllocated);
2742 :
2743 10 : psCtxt->nNodeRefsAllocated = 10000;
2744 10 : psCtxt->panNodeRefs = (GIntBig *)VSI_MALLOC_VERBOSE(
2745 : sizeof(GIntBig) * psCtxt->nNodeRefsAllocated);
2746 :
2747 10 : if (psCtxt->pszStrBuf == nullptr || psCtxt->pasNodes == nullptr ||
2748 10 : psCtxt->pasTags == nullptr || psCtxt->pasMembers == nullptr ||
2749 10 : psCtxt->panNodeRefs == nullptr)
2750 : {
2751 0 : OSM_Close(psCtxt);
2752 0 : return nullptr;
2753 : }
2754 : }
2755 : #endif
2756 :
2757 31 : psCtxt->pabyBlob = (GByte *)VSI_MALLOC_VERBOSE(psCtxt->nBlobSizeAllocated);
2758 31 : if (psCtxt->pabyBlob == nullptr)
2759 : {
2760 0 : OSM_Close(psCtxt);
2761 0 : return nullptr;
2762 : }
2763 31 : psCtxt->pabyBlobHeader =
2764 31 : (GByte *)VSI_MALLOC_VERBOSE(MAX_BLOB_HEADER_SIZE + EXTRA_BYTES);
2765 31 : if (psCtxt->pabyBlobHeader == nullptr)
2766 : {
2767 0 : OSM_Close(psCtxt);
2768 0 : return nullptr;
2769 : }
2770 : const char *pszNumThreads =
2771 31 : CPLGetConfigOption("GDAL_NUM_THREADS", "ALL_CPUS");
2772 31 : int nNumCPUs = CPLGetNumCPUs();
2773 31 : if (pszNumThreads && !EQUAL(pszNumThreads, "ALL_CPUS"))
2774 0 : nNumCPUs = std::max(0, std::min(2 * nNumCPUs, atoi(pszNumThreads)));
2775 31 : if (nNumCPUs > 1)
2776 : {
2777 31 : psCtxt->poWTP = new CPLWorkerThreadPool();
2778 : // coverity[tainted_data]
2779 31 : if (!psCtxt->poWTP->Setup(nNumCPUs, nullptr, nullptr))
2780 : {
2781 0 : delete psCtxt->poWTP;
2782 0 : psCtxt->poWTP = nullptr;
2783 : }
2784 : }
2785 :
2786 31 : return psCtxt;
2787 : }
2788 :
2789 : /************************************************************************/
2790 : /* OSM_Close() */
2791 : /************************************************************************/
2792 :
2793 31 : void OSM_Close(OSMContext *psCtxt)
2794 : {
2795 31 : if (psCtxt == nullptr)
2796 0 : return;
2797 :
2798 : #ifdef HAVE_EXPAT
2799 31 : if (!psCtxt->bPBF)
2800 : {
2801 10 : if (psCtxt->hXMLParser)
2802 10 : XML_ParserFree(psCtxt->hXMLParser);
2803 :
2804 10 : CPLFree(psCtxt->pszStrBuf); /* only for XML case ! */
2805 : }
2806 : #endif
2807 :
2808 31 : VSIFree(psCtxt->pabyBlob);
2809 31 : VSIFree(psCtxt->pabyBlobHeader);
2810 31 : VSIFree(psCtxt->pabyUncompressed);
2811 31 : VSIFree(psCtxt->panStrOff);
2812 31 : VSIFree(psCtxt->pasNodes);
2813 31 : VSIFree(psCtxt->pasTags);
2814 31 : VSIFree(psCtxt->pasMembers);
2815 31 : VSIFree(psCtxt->panNodeRefs);
2816 31 : delete psCtxt->poWTP;
2817 :
2818 31 : VSIFCloseL(psCtxt->fp);
2819 31 : VSIFree(psCtxt);
2820 : }
2821 :
2822 : /************************************************************************/
2823 : /* OSM_ResetReading() */
2824 : /************************************************************************/
2825 :
2826 61 : void OSM_ResetReading(OSMContext *psCtxt)
2827 : {
2828 61 : VSIFSeekL(psCtxt->fp, 0, SEEK_SET);
2829 :
2830 61 : psCtxt->nBytesRead = 0;
2831 61 : psCtxt->nJobs = 0;
2832 61 : psCtxt->iNextJob = 0;
2833 61 : psCtxt->nBlobOffset = 0;
2834 61 : psCtxt->nBlobSize = 0;
2835 61 : psCtxt->nTotalUncompressedSize = 0;
2836 :
2837 : #ifdef HAVE_EXPAT
2838 61 : if (!psCtxt->bPBF)
2839 : {
2840 3 : XML_ParserFree(psCtxt->hXMLParser);
2841 3 : psCtxt->hXMLParser = OGRCreateExpatXMLParser();
2842 3 : XML_SetUserData(psCtxt->hXMLParser, psCtxt);
2843 3 : XML_SetElementHandler(psCtxt->hXMLParser, OSM_XML_startElementCbk,
2844 : OSM_XML_endElementCbk);
2845 3 : XML_SetCharacterDataHandler(psCtxt->hXMLParser, OSM_XML_dataHandlerCbk);
2846 3 : psCtxt->bEOF = false;
2847 3 : psCtxt->bStopParsing = false;
2848 3 : psCtxt->nStrLength = 0;
2849 3 : psCtxt->pszStrBuf[0] = '\0';
2850 3 : psCtxt->nTags = 0;
2851 :
2852 3 : psCtxt->bTryToFetchBounds = true;
2853 3 : psCtxt->bInNode = false;
2854 3 : psCtxt->bInWay = false;
2855 3 : psCtxt->bInRelation = false;
2856 : }
2857 : #endif
2858 61 : }
2859 :
2860 : /************************************************************************/
2861 : /* OSM_ProcessBlock() */
2862 : /************************************************************************/
2863 :
2864 84 : OSMRetCode OSM_ProcessBlock(OSMContext *psCtxt)
2865 : {
2866 : #ifdef HAVE_EXPAT
2867 84 : if (psCtxt->bPBF)
2868 72 : return PBF_ProcessBlock(psCtxt);
2869 : else
2870 12 : return XML_ProcessBlock(psCtxt);
2871 : #else
2872 : return PBF_ProcessBlock(psCtxt);
2873 : #endif
2874 : }
2875 :
2876 : /************************************************************************/
2877 : /* OSM_GetBytesRead() */
2878 : /************************************************************************/
2879 :
2880 51 : GUIntBig OSM_GetBytesRead(OSMContext *psCtxt)
2881 : {
2882 51 : return psCtxt->nBytesRead;
2883 : }
|