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