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