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