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