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