Coverage Report

Created: 2025-06-13 06:18

/src/gdal/ogr/ogr_wkb.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  OGR
4
 * Purpose:  WKB geometry related methods
5
 * Author:   Even Rouault <even dot rouault at spatialys.com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2022, Even Rouault <even dot rouault at spatialys.com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#include "cpl_error.h"
14
#include "ogr_wkb.h"
15
#include "ogr_core.h"
16
#include "ogr_geometry.h"
17
#include "ogr_p.h"
18
19
#include <algorithm>
20
#include <cmath>
21
#include <climits>
22
#include <limits>
23
24
#include <algorithm>
25
#include <limits>
26
27
#define USE_FAST_FLOAT
28
#ifdef USE_FAST_FLOAT
29
#include "include_fast_float.h"
30
#endif
31
32
/************************************************************************/
33
/*                          OGRWKBNeedSwap()                            */
34
/************************************************************************/
35
36
static inline bool OGRWKBNeedSwap(GByte b)
37
0
{
38
0
#if CPL_IS_LSB
39
0
    const bool bNeedSwap = b == 0;
40
#else
41
    const bool bNeedSwap = b == 1;
42
#endif
43
0
    return bNeedSwap;
44
0
}
45
46
/************************************************************************/
47
/*                        OGRWKBReadUInt32()                            */
48
/************************************************************************/
49
50
static inline uint32_t OGRWKBReadUInt32(const GByte *pabyWkb, bool bNeedSwap)
51
0
{
52
0
    uint32_t nVal;
53
0
    memcpy(&nVal, pabyWkb, sizeof(nVal));
54
0
    if (bNeedSwap)
55
0
        CPL_SWAP32PTR(&nVal);
56
0
    return nVal;
57
0
}
58
59
/************************************************************************/
60
/*                        OGRWKBReadFloat64()                           */
61
/************************************************************************/
62
63
static inline double OGRWKBReadFloat64(const GByte *pabyWkb, bool bNeedSwap)
64
0
{
65
0
    double dfVal;
66
0
    memcpy(&dfVal, pabyWkb, sizeof(dfVal));
67
0
    if (bNeedSwap)
68
0
        CPL_SWAP64PTR(&dfVal);
69
0
    return dfVal;
70
0
}
71
72
/************************************************************************/
73
/*                        OGRWKBRingGetArea()                           */
74
/************************************************************************/
75
76
static bool OGRWKBRingGetArea(const GByte *&pabyWkb, size_t &nWKBSize, int nDim,
77
                              bool bNeedSwap, double &dfArea)
78
0
{
79
0
    const uint32_t nPoints = OGRWKBReadUInt32(pabyWkb, bNeedSwap);
80
0
    if (nPoints >= 4 &&
81
0
        (nWKBSize - sizeof(uint32_t)) / (nDim * sizeof(double)) >= nPoints)
82
0
    {
83
0
        nWKBSize -= sizeof(uint32_t) + nDim * sizeof(double);
84
0
        pabyWkb += sizeof(uint32_t);
85
        // Computation according to Green's Theorem
86
        // Cf OGRSimpleCurve::get_LinearArea()
87
0
        double x_m1 = OGRWKBReadFloat64(pabyWkb, bNeedSwap);
88
0
        double y_m1 = OGRWKBReadFloat64(pabyWkb + sizeof(double), bNeedSwap);
89
0
        double y_m2 = y_m1;
90
0
        dfArea = 0;
91
0
        pabyWkb += nDim * sizeof(double);
92
0
        for (uint32_t i = 1; i < nPoints; ++i)
93
0
        {
94
0
            const double x = OGRWKBReadFloat64(pabyWkb, bNeedSwap);
95
0
            const double y =
96
0
                OGRWKBReadFloat64(pabyWkb + sizeof(double), bNeedSwap);
97
0
            pabyWkb += nDim * sizeof(double);
98
0
            dfArea += x_m1 * (y - y_m2);
99
0
            y_m2 = y_m1;
100
0
            x_m1 = x;
101
0
            y_m1 = y;
102
0
        }
103
0
        dfArea += x_m1 * (y_m1 - y_m2);
104
0
        dfArea = 0.5 * std::fabs(dfArea);
105
0
        return true;
106
0
    }
107
0
    return false;
108
0
}
109
110
/************************************************************************/
111
/*                         OGRWKBGetGeomType()                          */
112
/************************************************************************/
113
114
bool OGRWKBGetGeomType(const GByte *pabyWkb, size_t nWKBSize, bool &bNeedSwap,
115
                       uint32_t &nType)
116
0
{
117
0
    if (nWKBSize >= 5)
118
0
    {
119
0
        bNeedSwap = OGRWKBNeedSwap(pabyWkb[0]);
120
0
        nType = OGRWKBReadUInt32(pabyWkb + 1, bNeedSwap);
121
0
        return true;
122
0
    }
123
0
    return false;
124
0
}
125
126
/************************************************************************/
127
/*                        OGRWKBPolygonGetArea()                        */
128
/************************************************************************/
129
130
bool OGRWKBPolygonGetArea(const GByte *&pabyWkb, size_t &nWKBSize,
131
                          double &dfArea)
132
0
{
133
0
    bool bNeedSwap;
134
0
    uint32_t nType;
135
0
    if (nWKBSize < 9 || !OGRWKBGetGeomType(pabyWkb, nWKBSize, bNeedSwap, nType))
136
0
        return false;
137
138
0
    int nDims = 2;
139
0
    if (nType == wkbPolygon)
140
0
    {
141
        // do nothing
142
0
    }
143
0
    else if (nType == wkbPolygon + 1000 ||  // wkbPolygonZ
144
0
             nType == wkbPolygon25D || nType == wkbPolygonM)
145
0
    {
146
0
        nDims = 3;
147
0
    }
148
0
    else if (nType == wkbPolygonZM)
149
0
    {
150
0
        nDims = 4;
151
0
    }
152
0
    else
153
0
    {
154
0
        return false;
155
0
    }
156
157
0
    const uint32_t nRings = OGRWKBReadUInt32(pabyWkb + 5, bNeedSwap);
158
0
    if ((nWKBSize - 9) / sizeof(uint32_t) >= nRings)
159
0
    {
160
0
        pabyWkb += 9;
161
0
        nWKBSize -= 9;
162
0
        dfArea = 0;
163
0
        if (nRings > 0)
164
0
        {
165
0
            if (!OGRWKBRingGetArea(pabyWkb, nWKBSize, nDims, bNeedSwap, dfArea))
166
0
                return false;
167
0
            for (uint32_t i = 1; i < nRings; ++i)
168
0
            {
169
0
                double dfRingArea;
170
0
                if (!OGRWKBRingGetArea(pabyWkb, nWKBSize, nDims, bNeedSwap,
171
0
                                       dfRingArea))
172
0
                    return false;
173
0
                dfArea -= dfRingArea;
174
0
            }
175
0
        }
176
0
        return true;
177
0
    }
178
0
    return false;
179
0
}
180
181
/************************************************************************/
182
/*                    OGRWKBMultiPolygonGetArea()                       */
183
/************************************************************************/
184
185
bool OGRWKBMultiPolygonGetArea(const GByte *&pabyWkb, size_t &nWKBSize,
186
                               double &dfArea)
187
0
{
188
0
    if (nWKBSize < 9)
189
0
        return false;
190
191
0
    const bool bNeedSwap = OGRWKBNeedSwap(pabyWkb[0]);
192
0
    const uint32_t nPolys = OGRWKBReadUInt32(pabyWkb + 5, bNeedSwap);
193
0
    if ((nWKBSize - 9) / 9 >= nPolys)
194
0
    {
195
0
        pabyWkb += 9;
196
0
        nWKBSize -= 9;
197
0
        dfArea = 0;
198
0
        for (uint32_t i = 0; i < nPolys; ++i)
199
0
        {
200
0
            double dfPolyArea;
201
0
            if (!OGRWKBPolygonGetArea(pabyWkb, nWKBSize, dfPolyArea))
202
0
                return false;
203
0
            dfArea += dfPolyArea;
204
0
        }
205
0
        return true;
206
0
    }
207
0
    return false;
208
0
}
209
210
/************************************************************************/
211
/*                            WKBFromEWKB()                             */
212
/************************************************************************/
213
214
const GByte *WKBFromEWKB(GByte *pabyEWKB, size_t nEWKBSize, size_t &nWKBSizeOut,
215
                         int *pnSRIDOut)
216
0
{
217
0
    if (nEWKBSize < 5U)
218
0
    {
219
0
        CPLError(CE_Failure, CPLE_AppDefined, "Invalid EWKB content : %u bytes",
220
0
                 static_cast<unsigned>(nEWKBSize));
221
0
        return nullptr;
222
0
    }
223
224
0
    const GByte *pabyWKB = pabyEWKB;
225
226
    /* -------------------------------------------------------------------- */
227
    /*      PostGIS EWKB format includes an SRID, but this won't be         */
228
    /*      understood by OGR, so if the SRID flag is set, we remove the    */
229
    /*      SRID (bytes at offset 5 to 8).                                  */
230
    /* -------------------------------------------------------------------- */
231
0
    if (nEWKBSize > 9 &&
232
0
        ((pabyEWKB[0] == 0 /* big endian */ && (pabyEWKB[1] & 0x20)) ||
233
0
         (pabyEWKB[0] != 0 /* little endian */ && (pabyEWKB[4] & 0x20))))
234
0
    {
235
0
        if (pnSRIDOut)
236
0
        {
237
0
            memcpy(pnSRIDOut, pabyEWKB + 5, 4);
238
0
            const OGRwkbByteOrder eByteOrder =
239
0
                (pabyEWKB[0] == 0 ? wkbXDR : wkbNDR);
240
0
            if (OGR_SWAP(eByteOrder))
241
0
                *pnSRIDOut = CPL_SWAP32(*pnSRIDOut);
242
0
        }
243
244
        // Drop the SRID flag
245
0
        if (pabyEWKB[0] == 0)
246
0
            pabyEWKB[1] &= (~0x20);
247
0
        else
248
0
            pabyEWKB[4] &= (~0x20);
249
250
        // Move 5 first bytes of EWKB 4 bytes later to create regular WKB
251
0
        memmove(pabyEWKB + 4, pabyEWKB, 5);
252
0
        memset(pabyEWKB, 0, 4);
253
        // and make pabyWKB point to that
254
0
        pabyWKB += 4;
255
0
        nWKBSizeOut = nEWKBSize - 4;
256
0
    }
257
0
    else
258
0
    {
259
0
        if (pnSRIDOut)
260
0
        {
261
0
            *pnSRIDOut = INT_MIN;
262
0
        }
263
0
        nWKBSizeOut = nEWKBSize;
264
0
    }
265
266
0
    return pabyWKB;
267
0
}
268
269
/************************************************************************/
270
/*                     OGRWKBReadUInt32AtOffset()                       */
271
/************************************************************************/
272
273
static uint32_t OGRWKBReadUInt32AtOffset(const uint8_t *data,
274
                                         OGRwkbByteOrder eByteOrder,
275
                                         size_t &iOffset)
276
0
{
277
0
    uint32_t v;
278
0
    memcpy(&v, data + iOffset, sizeof(v));
279
0
    iOffset += sizeof(v);
280
0
    if (OGR_SWAP(eByteOrder))
281
0
    {
282
0
        CPL_SWAP32PTR(&v);
283
0
    }
284
0
    return v;
285
0
}
286
287
/************************************************************************/
288
/*                         ReadWKBPointSequence()                       */
289
/************************************************************************/
290
291
template <bool INCLUDE_Z, typename EnvelopeType>
292
static bool ReadWKBPointSequence(const uint8_t *data, size_t size,
293
                                 OGRwkbByteOrder eByteOrder, int nDim,
294
                                 bool bHasZ, size_t &iOffset,
295
                                 EnvelopeType &sEnvelope)
296
0
{
297
0
    const uint32_t nPoints =
298
0
        OGRWKBReadUInt32AtOffset(data, eByteOrder, iOffset);
299
0
    if (nPoints > (size - iOffset) / (nDim * sizeof(double)))
300
0
        return false;
301
0
    double dfX = 0;
302
0
    double dfY = 0;
303
0
    [[maybe_unused]] double dfZ = 0;
304
0
    for (uint32_t j = 0; j < nPoints; j++)
305
0
    {
306
0
        memcpy(&dfX, data + iOffset, sizeof(double));
307
0
        memcpy(&dfY, data + iOffset + sizeof(double), sizeof(double));
308
        if constexpr (INCLUDE_Z)
309
0
        {
310
0
            if (bHasZ)
311
0
                memcpy(&dfZ, data + iOffset + 2 * sizeof(double),
312
0
                       sizeof(double));
313
0
        }
314
0
        iOffset += nDim * sizeof(double);
315
0
        if (OGR_SWAP(eByteOrder))
316
0
        {
317
0
            CPL_SWAP64PTR(&dfX);
318
0
            CPL_SWAP64PTR(&dfY);
319
            if constexpr (INCLUDE_Z)
320
0
            {
321
0
                CPL_SWAP64PTR(&dfZ);
322
0
            }
323
0
        }
324
0
        sEnvelope.MinX = std::min(sEnvelope.MinX, dfX);
325
0
        sEnvelope.MinY = std::min(sEnvelope.MinY, dfY);
326
0
        sEnvelope.MaxX = std::max(sEnvelope.MaxX, dfX);
327
0
        sEnvelope.MaxY = std::max(sEnvelope.MaxY, dfY);
328
        if constexpr (INCLUDE_Z)
329
0
        {
330
0
            if (bHasZ)
331
0
            {
332
0
                sEnvelope.MinZ = std::min(sEnvelope.MinZ, dfZ);
333
0
                sEnvelope.MaxZ = std::max(sEnvelope.MaxZ, dfZ);
334
0
            }
335
0
        }
336
0
    }
337
0
    return true;
338
0
}
Unexecuted instantiation: ogr_wkb.cpp:bool ReadWKBPointSequence<false, OGREnvelope>(unsigned char const*, unsigned long, OGRwkbByteOrder, int, bool, unsigned long&, OGREnvelope&)
Unexecuted instantiation: ogr_wkb.cpp:bool ReadWKBPointSequence<true, OGREnvelope3D>(unsigned char const*, unsigned long, OGRwkbByteOrder, int, bool, unsigned long&, OGREnvelope3D&)
339
340
/************************************************************************/
341
/*                         ReadWKBRingSequence()                        */
342
/************************************************************************/
343
344
template <bool INCLUDE_Z, typename EnvelopeType>
345
static bool ReadWKBRingSequence(const uint8_t *data, size_t size,
346
                                OGRwkbByteOrder eByteOrder, int nDim,
347
                                bool bHasZ, size_t &iOffset,
348
                                EnvelopeType &sEnvelope)
349
0
{
350
0
    const uint32_t nRings = OGRWKBReadUInt32AtOffset(data, eByteOrder, iOffset);
351
0
    if (nRings > (size - iOffset) / sizeof(uint32_t))
352
0
        return false;
353
0
    for (uint32_t i = 0; i < nRings; i++)
354
0
    {
355
0
        if (iOffset + sizeof(uint32_t) > size)
356
0
            return false;
357
0
        if (!ReadWKBPointSequence<INCLUDE_Z>(data, size, eByteOrder, nDim,
358
0
                                             bHasZ, iOffset, sEnvelope))
359
0
            return false;
360
0
    }
361
0
    return true;
362
0
}
Unexecuted instantiation: ogr_wkb.cpp:bool ReadWKBRingSequence<false, OGREnvelope>(unsigned char const*, unsigned long, OGRwkbByteOrder, int, bool, unsigned long&, OGREnvelope&)
Unexecuted instantiation: ogr_wkb.cpp:bool ReadWKBRingSequence<true, OGREnvelope3D>(unsigned char const*, unsigned long, OGRwkbByteOrder, int, bool, unsigned long&, OGREnvelope3D&)
363
364
/************************************************************************/
365
/*                        OGRWKBGetBoundingBox()                        */
366
/************************************************************************/
367
368
constexpr uint32_t WKB_PREFIX_SIZE = 1 + sizeof(uint32_t);
369
constexpr uint32_t MIN_WKB_SIZE = WKB_PREFIX_SIZE + sizeof(uint32_t);
370
371
template <bool INCLUDE_Z, typename EnvelopeType>
372
static bool OGRWKBGetBoundingBox(const uint8_t *data, size_t size,
373
                                 size_t &iOffset, EnvelopeType &sEnvelope,
374
                                 int nRec)
375
0
{
376
0
    if (size - iOffset < MIN_WKB_SIZE)
377
0
        return false;
378
0
    const int nByteOrder = DB2_V72_FIX_BYTE_ORDER(data[iOffset]);
379
0
    if (!(nByteOrder == wkbXDR || nByteOrder == wkbNDR))
380
0
        return false;
381
0
    const OGRwkbByteOrder eByteOrder = static_cast<OGRwkbByteOrder>(nByteOrder);
382
383
0
    OGRwkbGeometryType eGeometryType = wkbUnknown;
384
0
    OGRReadWKBGeometryType(data + iOffset, wkbVariantIso, &eGeometryType);
385
0
    iOffset += 5;
386
0
    const auto eFlatType = wkbFlatten(eGeometryType);
387
0
    const bool bHasZ = CPL_TO_BOOL(OGR_GT_HasZ(eGeometryType));
388
0
    const int nDim = 2 + (bHasZ ? 1 : 0) + (OGR_GT_HasM(eGeometryType) ? 1 : 0);
389
390
0
    if (eFlatType == wkbPoint)
391
0
    {
392
0
        if (size - iOffset < nDim * sizeof(double))
393
0
            return false;
394
0
        double dfX = 0;
395
0
        double dfY = 0;
396
0
        [[maybe_unused]] double dfZ = 0;
397
0
        memcpy(&dfX, data + iOffset, sizeof(double));
398
0
        memcpy(&dfY, data + iOffset + sizeof(double), sizeof(double));
399
        if constexpr (INCLUDE_Z)
400
0
        {
401
0
            if (bHasZ)
402
0
                memcpy(&dfZ, data + iOffset + 2 * sizeof(double),
403
0
                       sizeof(double));
404
0
        }
405
0
        iOffset += nDim * sizeof(double);
406
0
        if (OGR_SWAP(eByteOrder))
407
0
        {
408
0
            CPL_SWAP64PTR(&dfX);
409
0
            CPL_SWAP64PTR(&dfY);
410
            if constexpr (INCLUDE_Z)
411
0
            {
412
0
                CPL_SWAP64PTR(&dfZ);
413
0
            }
414
0
        }
415
0
        if (std::isnan(dfX))
416
0
        {
417
            // Point empty
418
0
            sEnvelope = EnvelopeType();
419
0
        }
420
0
        else
421
0
        {
422
0
            sEnvelope.MinX = dfX;
423
0
            sEnvelope.MinY = dfY;
424
0
            sEnvelope.MaxX = dfX;
425
0
            sEnvelope.MaxY = dfY;
426
            if constexpr (INCLUDE_Z)
427
0
            {
428
0
                if (bHasZ)
429
0
                {
430
0
                    sEnvelope.MinZ = dfZ;
431
0
                    sEnvelope.MaxZ = dfZ;
432
0
                }
433
0
            }
434
0
        }
435
0
        return true;
436
0
    }
437
438
0
    if (eFlatType == wkbLineString || eFlatType == wkbCircularString)
439
0
    {
440
0
        sEnvelope = EnvelopeType();
441
442
0
        return ReadWKBPointSequence<INCLUDE_Z>(data, size, eByteOrder, nDim,
443
0
                                               bHasZ, iOffset, sEnvelope);
444
0
    }
445
446
0
    if (eFlatType == wkbPolygon || eFlatType == wkbTriangle)
447
0
    {
448
0
        sEnvelope = EnvelopeType();
449
450
0
        return ReadWKBRingSequence<INCLUDE_Z>(data, size, eByteOrder, nDim,
451
0
                                              bHasZ, iOffset, sEnvelope);
452
0
    }
453
454
0
    if (eFlatType == wkbMultiPoint)
455
0
    {
456
0
        sEnvelope = EnvelopeType();
457
458
0
        uint32_t nParts = OGRWKBReadUInt32AtOffset(data, eByteOrder, iOffset);
459
0
        if (nParts >
460
0
            (size - iOffset) / (WKB_PREFIX_SIZE + nDim * sizeof(double)))
461
0
            return false;
462
0
        double dfX = 0;
463
0
        double dfY = 0;
464
0
        [[maybe_unused]] double dfZ = 0;
465
0
        for (uint32_t k = 0; k < nParts; k++)
466
0
        {
467
0
            iOffset += WKB_PREFIX_SIZE;
468
0
            memcpy(&dfX, data + iOffset, sizeof(double));
469
0
            memcpy(&dfY, data + iOffset + sizeof(double), sizeof(double));
470
            if constexpr (INCLUDE_Z)
471
0
            {
472
0
                if (bHasZ)
473
0
                    memcpy(&dfZ, data + iOffset + 2 * sizeof(double),
474
0
                           sizeof(double));
475
0
            }
476
0
            iOffset += nDim * sizeof(double);
477
0
            if (OGR_SWAP(eByteOrder))
478
0
            {
479
0
                CPL_SWAP64PTR(&dfX);
480
0
                CPL_SWAP64PTR(&dfY);
481
                if constexpr (INCLUDE_Z)
482
0
                {
483
0
                    CPL_SWAP64PTR(&dfZ);
484
0
                }
485
0
            }
486
0
            sEnvelope.MinX = std::min(sEnvelope.MinX, dfX);
487
0
            sEnvelope.MinY = std::min(sEnvelope.MinY, dfY);
488
0
            sEnvelope.MaxX = std::max(sEnvelope.MaxX, dfX);
489
0
            sEnvelope.MaxY = std::max(sEnvelope.MaxY, dfY);
490
            if constexpr (INCLUDE_Z)
491
0
            {
492
0
                if (bHasZ)
493
0
                {
494
0
                    sEnvelope.MinZ = std::min(sEnvelope.MinZ, dfZ);
495
0
                    sEnvelope.MaxZ = std::max(sEnvelope.MaxZ, dfZ);
496
0
                }
497
0
            }
498
0
        }
499
0
        return true;
500
0
    }
501
502
0
    if (eFlatType == wkbMultiLineString)
503
0
    {
504
0
        sEnvelope = EnvelopeType();
505
506
0
        const uint32_t nParts =
507
0
            OGRWKBReadUInt32AtOffset(data, eByteOrder, iOffset);
508
0
        if (nParts > (size - iOffset) / MIN_WKB_SIZE)
509
0
            return false;
510
0
        for (uint32_t k = 0; k < nParts; k++)
511
0
        {
512
0
            if (iOffset + MIN_WKB_SIZE > size)
513
0
                return false;
514
0
            iOffset += WKB_PREFIX_SIZE;
515
0
            if (!ReadWKBPointSequence<INCLUDE_Z>(data, size, eByteOrder, nDim,
516
0
                                                 bHasZ, iOffset, sEnvelope))
517
0
                return false;
518
0
        }
519
0
        return true;
520
0
    }
521
522
0
    if (eFlatType == wkbMultiPolygon)
523
0
    {
524
0
        sEnvelope = EnvelopeType();
525
526
0
        const uint32_t nParts =
527
0
            OGRWKBReadUInt32AtOffset(data, eByteOrder, iOffset);
528
0
        if (nParts > (size - iOffset) / MIN_WKB_SIZE)
529
0
            return false;
530
0
        for (uint32_t k = 0; k < nParts; k++)
531
0
        {
532
0
            if (iOffset + MIN_WKB_SIZE > size)
533
0
                return false;
534
0
            CPLAssert(data[iOffset] == eByteOrder);
535
0
            iOffset += WKB_PREFIX_SIZE;
536
0
            if (!ReadWKBRingSequence<INCLUDE_Z>(data, size, eByteOrder, nDim,
537
0
                                                bHasZ, iOffset, sEnvelope))
538
0
                return false;
539
0
        }
540
0
        return true;
541
0
    }
542
543
0
    if (eFlatType == wkbGeometryCollection || eFlatType == wkbCompoundCurve ||
544
0
        eFlatType == wkbCurvePolygon || eFlatType == wkbMultiCurve ||
545
0
        eFlatType == wkbMultiSurface || eFlatType == wkbPolyhedralSurface ||
546
0
        eFlatType == wkbTIN)
547
0
    {
548
0
        if (nRec == 128)
549
0
            return false;
550
0
        sEnvelope = EnvelopeType();
551
552
0
        const uint32_t nParts =
553
0
            OGRWKBReadUInt32AtOffset(data, eByteOrder, iOffset);
554
0
        if (nParts > (size - iOffset) / MIN_WKB_SIZE)
555
0
            return false;
556
0
        EnvelopeType sEnvelopeSubGeom;
557
0
        for (uint32_t k = 0; k < nParts; k++)
558
0
        {
559
0
            if (!OGRWKBGetBoundingBox<INCLUDE_Z>(data, size, iOffset,
560
0
                                                 sEnvelopeSubGeom, nRec + 1))
561
0
                return false;
562
0
            sEnvelope.Merge(sEnvelopeSubGeom);
563
0
        }
564
0
        return true;
565
0
    }
566
567
0
    return false;
568
0
}
Unexecuted instantiation: ogr_wkb.cpp:bool OGRWKBGetBoundingBox<false, OGREnvelope>(unsigned char const*, unsigned long, unsigned long&, OGREnvelope&, int)
Unexecuted instantiation: ogr_wkb.cpp:bool OGRWKBGetBoundingBox<true, OGREnvelope3D>(unsigned char const*, unsigned long, unsigned long&, OGREnvelope3D&, int)
569
570
/************************************************************************/
571
/*                        OGRWKBGetBoundingBox()                        */
572
/************************************************************************/
573
574
bool OGRWKBGetBoundingBox(const GByte *pabyWkb, size_t nWKBSize,
575
                          OGREnvelope &sEnvelope)
576
0
{
577
0
    size_t iOffset = 0;
578
0
    return OGRWKBGetBoundingBox<false>(pabyWkb, nWKBSize, iOffset, sEnvelope,
579
0
                                       0);
580
0
}
581
582
/************************************************************************/
583
/*                        OGRWKBGetBoundingBox()                        */
584
/************************************************************************/
585
586
bool OGRWKBGetBoundingBox(const GByte *pabyWkb, size_t nWKBSize,
587
                          OGREnvelope3D &sEnvelope)
588
0
{
589
0
    size_t iOffset = 0;
590
0
    return OGRWKBGetBoundingBox<true>(pabyWkb, nWKBSize, iOffset, sEnvelope, 0);
591
0
}
592
593
/************************************************************************/
594
/*              OGRWKBIntersectsPointSequencePessimistic()              */
595
/************************************************************************/
596
597
static bool OGRWKBIntersectsPointSequencePessimistic(
598
    const uint8_t *data, const size_t size, const OGRwkbByteOrder eByteOrder,
599
    const int nDim, size_t &iOffsetInOut, const OGREnvelope &sEnvelope,
600
    bool &bErrorOut)
601
0
{
602
0
    const uint32_t nPoints =
603
0
        OGRWKBReadUInt32AtOffset(data, eByteOrder, iOffsetInOut);
604
0
    if (nPoints > (size - iOffsetInOut) / (nDim * sizeof(double)))
605
0
    {
606
0
        bErrorOut = true;
607
0
        return false;
608
0
    }
609
610
0
    double dfX = 0;
611
0
    double dfY = 0;
612
0
    for (uint32_t j = 0; j < nPoints; j++)
613
0
    {
614
0
        memcpy(&dfX, data + iOffsetInOut, sizeof(double));
615
0
        memcpy(&dfY, data + iOffsetInOut + sizeof(double), sizeof(double));
616
0
        iOffsetInOut += nDim * sizeof(double);
617
0
        if (OGR_SWAP(eByteOrder))
618
0
        {
619
0
            CPL_SWAP64PTR(&dfX);
620
0
            CPL_SWAP64PTR(&dfY);
621
0
        }
622
0
        if (dfX >= sEnvelope.MinX && dfY >= sEnvelope.MinY &&
623
0
            dfX <= sEnvelope.MaxX && dfY <= sEnvelope.MaxY)
624
0
        {
625
0
            return true;
626
0
        }
627
0
    }
628
629
0
    return false;
630
0
}
631
632
/************************************************************************/
633
/*               OGRWKBIntersectsRingSequencePessimistic()              */
634
/************************************************************************/
635
636
static bool OGRWKBIntersectsRingSequencePessimistic(
637
    const uint8_t *data, const size_t size, const OGRwkbByteOrder eByteOrder,
638
    const int nDim, size_t &iOffsetInOut, const OGREnvelope &sEnvelope,
639
    bool &bErrorOut)
640
0
{
641
0
    const uint32_t nRings =
642
0
        OGRWKBReadUInt32AtOffset(data, eByteOrder, iOffsetInOut);
643
0
    if (nRings > (size - iOffsetInOut) / sizeof(uint32_t))
644
0
    {
645
0
        bErrorOut = true;
646
0
        return false;
647
0
    }
648
0
    if (nRings == 0)
649
0
        return false;
650
0
    if (iOffsetInOut + sizeof(uint32_t) > size)
651
0
    {
652
0
        bErrorOut = true;
653
0
        return false;
654
0
    }
655
0
    if (OGRWKBIntersectsPointSequencePessimistic(
656
0
            data, size, eByteOrder, nDim, iOffsetInOut, sEnvelope, bErrorOut))
657
0
    {
658
0
        return true;
659
0
    }
660
0
    if (bErrorOut)
661
0
        return false;
662
663
    // skip inner rings
664
0
    for (uint32_t i = 1; i < nRings; ++i)
665
0
    {
666
0
        if (iOffsetInOut + sizeof(uint32_t) > size)
667
0
        {
668
0
            bErrorOut = true;
669
0
            return false;
670
0
        }
671
0
        const uint32_t nPoints =
672
0
            OGRWKBReadUInt32AtOffset(data, eByteOrder, iOffsetInOut);
673
0
        if (nPoints > (size - iOffsetInOut) / (nDim * sizeof(double)))
674
0
        {
675
0
            bErrorOut = true;
676
0
            return false;
677
0
        }
678
0
        iOffsetInOut += sizeof(double) * nPoints * nDim;
679
0
    }
680
0
    return false;
681
0
}
682
683
/************************************************************************/
684
/*                  OGRWKBIntersectsPessimistic()                         */
685
/************************************************************************/
686
687
static bool OGRWKBIntersectsPessimistic(const GByte *data, const size_t size,
688
                                        size_t &iOffsetInOut,
689
                                        const OGREnvelope &sEnvelope,
690
                                        const int nRec, bool &bErrorOut)
691
0
{
692
0
    if (size - iOffsetInOut < MIN_WKB_SIZE)
693
0
    {
694
0
        bErrorOut = true;
695
0
        return false;
696
0
    }
697
0
    const int nByteOrder = DB2_V72_FIX_BYTE_ORDER(data[iOffsetInOut]);
698
0
    if (!(nByteOrder == wkbXDR || nByteOrder == wkbNDR))
699
0
    {
700
0
        bErrorOut = true;
701
0
        return false;
702
0
    }
703
0
    const OGRwkbByteOrder eByteOrder = static_cast<OGRwkbByteOrder>(nByteOrder);
704
705
0
    OGRwkbGeometryType eGeometryType = wkbUnknown;
706
0
    OGRReadWKBGeometryType(data + iOffsetInOut, wkbVariantIso, &eGeometryType);
707
0
    iOffsetInOut += 5;
708
0
    const auto eFlatType = wkbFlatten(eGeometryType);
709
0
    const int nDim = 2 + (OGR_GT_HasZ(eGeometryType) ? 1 : 0) +
710
0
                     (OGR_GT_HasM(eGeometryType) ? 1 : 0);
711
712
0
    if (eFlatType == wkbPoint)
713
0
    {
714
0
        if (size - iOffsetInOut < nDim * sizeof(double))
715
0
            return false;
716
0
        double dfX = 0;
717
0
        double dfY = 0;
718
0
        memcpy(&dfX, data + iOffsetInOut, sizeof(double));
719
0
        memcpy(&dfY, data + iOffsetInOut + sizeof(double), sizeof(double));
720
0
        iOffsetInOut += nDim * sizeof(double);
721
0
        if (OGR_SWAP(eByteOrder))
722
0
        {
723
0
            CPL_SWAP64PTR(&dfX);
724
0
            CPL_SWAP64PTR(&dfY);
725
0
        }
726
0
        if (std::isnan(dfX))
727
0
        {
728
0
            return false;
729
0
        }
730
0
        else
731
0
        {
732
0
            return dfX >= sEnvelope.MinX && dfX <= sEnvelope.MaxX &&
733
0
                   dfY >= sEnvelope.MinY && dfY <= sEnvelope.MaxY;
734
0
        }
735
0
    }
736
737
0
    if (eFlatType == wkbLineString || eFlatType == wkbCircularString)
738
0
    {
739
0
        return OGRWKBIntersectsPointSequencePessimistic(
740
0
            data, size, eByteOrder, nDim, iOffsetInOut, sEnvelope, bErrorOut);
741
0
    }
742
743
0
    if (eFlatType == wkbPolygon || eFlatType == wkbTriangle)
744
0
    {
745
0
        return OGRWKBIntersectsRingSequencePessimistic(
746
0
            data, size, eByteOrder, nDim, iOffsetInOut, sEnvelope, bErrorOut);
747
0
    }
748
749
0
    if (eFlatType == wkbMultiPoint || eFlatType == wkbMultiLineString ||
750
0
        eFlatType == wkbMultiPolygon || eFlatType == wkbGeometryCollection ||
751
0
        eFlatType == wkbCompoundCurve || eFlatType == wkbCurvePolygon ||
752
0
        eFlatType == wkbMultiCurve || eFlatType == wkbMultiSurface ||
753
0
        eFlatType == wkbPolyhedralSurface || eFlatType == wkbTIN)
754
0
    {
755
0
        if (nRec == 128)
756
0
        {
757
0
            bErrorOut = true;
758
0
            return false;
759
0
        }
760
0
        const uint32_t nParts =
761
0
            OGRWKBReadUInt32AtOffset(data, eByteOrder, iOffsetInOut);
762
0
        if (nParts > (size - iOffsetInOut) / MIN_WKB_SIZE)
763
0
        {
764
0
            bErrorOut = true;
765
0
            return false;
766
0
        }
767
0
        for (uint32_t k = 0; k < nParts; k++)
768
0
        {
769
0
            if (OGRWKBIntersectsPessimistic(data, size, iOffsetInOut, sEnvelope,
770
0
                                            nRec + 1, bErrorOut))
771
0
            {
772
0
                return true;
773
0
            }
774
0
            else if (bErrorOut)
775
0
            {
776
0
                return false;
777
0
            }
778
0
        }
779
0
        return false;
780
0
    }
781
782
0
    bErrorOut = true;
783
0
    return false;
784
0
}
785
786
/************************************************************************/
787
/*                  OGRWKBIntersectsPessimistic()                       */
788
/************************************************************************/
789
790
/* Returns whether the geometry (pabyWkb, nWKBSize) intersects, for sure,
791
 * the passed envelope.
792
 * When it returns true, the geometry intersects the envelope.
793
 * When it returns false, the geometry may or may not intersect the envelope.
794
 */
795
bool OGRWKBIntersectsPessimistic(const GByte *pabyWkb, size_t nWKBSize,
796
                                 const OGREnvelope &sEnvelope)
797
0
{
798
0
    size_t iOffsetInOut = 0;
799
0
    bool bErrorOut = false;
800
0
    bool bRet = OGRWKBIntersectsPessimistic(pabyWkb, nWKBSize, iOffsetInOut,
801
0
                                            sEnvelope, 0, bErrorOut);
802
0
    if (!bRet && !bErrorOut)
803
0
    {
804
        // The following assert only holds if there is no trailing data
805
        // after the WKB
806
        // CPLAssert(iOffsetInOut == nWKBSize);
807
0
    }
808
0
    return bRet;
809
0
}
810
811
/************************************************************************/
812
/*                            epsilonEqual()                            */
813
/************************************************************************/
814
815
static inline bool epsilonEqual(double a, double b, double eps)
816
0
{
817
0
    return ::fabs(a - b) < eps;
818
0
}
819
820
/************************************************************************/
821
/*                     OGRWKBIsClockwiseRing()                          */
822
/************************************************************************/
823
824
static inline double GetX(const GByte *data, uint32_t i, int nDim,
825
                          bool bNeedSwap)
826
0
{
827
0
    double dfX;
828
0
    memcpy(&dfX, data + static_cast<size_t>(i) * nDim * sizeof(double),
829
0
           sizeof(double));
830
0
    if (bNeedSwap)
831
0
        CPL_SWAP64PTR(&dfX);
832
0
    return dfX;
833
0
}
834
835
static inline double GetY(const GByte *data, uint32_t i, int nDim,
836
                          bool bNeedSwap)
837
0
{
838
0
    double dfY;
839
0
    memcpy(&dfY, data + (static_cast<size_t>(i) * nDim + 1) * sizeof(double),
840
0
           sizeof(double));
841
0
    if (bNeedSwap)
842
0
        CPL_SWAP64PTR(&dfY);
843
0
    return dfY;
844
0
}
845
846
static bool OGRWKBIsClockwiseRing(const GByte *data, const uint32_t nPoints,
847
                                  const int nDim, const bool bNeedSwap)
848
0
{
849
0
    constexpr double EPSILON = 1.0E-5;
850
851
    // WARNING: keep in sync OGRLineString::isClockwise(),
852
    // OGRCurve::isClockwise() and OGRWKBIsClockwiseRing()
853
854
0
    bool bUseFallback = false;
855
856
    // Find the lowest rightmost vertex.
857
0
    uint32_t v = 0;  // Used after for.
858
0
    double vX = GetX(data, v, nDim, bNeedSwap);
859
0
    double vY = GetY(data, v, nDim, bNeedSwap);
860
0
    for (uint32_t i = 1; i < nPoints - 1; i++)
861
0
    {
862
        // => v < end.
863
0
        const double y = GetY(data, i, nDim, bNeedSwap);
864
0
        if (y < vY)
865
0
        {
866
0
            v = i;
867
0
            vX = GetX(data, i, nDim, bNeedSwap);
868
0
            vY = y;
869
0
            bUseFallback = false;
870
0
        }
871
0
        else if (y == vY)
872
0
        {
873
0
            const double x = GetX(data, i, nDim, bNeedSwap);
874
0
            if (x > vX)
875
0
            {
876
0
                v = i;
877
0
                vX = x;
878
                // vY = y;
879
0
                bUseFallback = false;
880
0
            }
881
0
            else if (x == vX)
882
0
            {
883
                // Two vertex with same coordinates are the lowest rightmost
884
                // vertex.  Cannot use that point as the pivot (#5342).
885
0
                bUseFallback = true;
886
0
            }
887
0
        }
888
0
    }
889
890
    // Previous.
891
0
    uint32_t next = (v == 0) ? nPoints - 2 : v - 1;
892
0
    if (epsilonEqual(GetX(data, next, nDim, bNeedSwap), vX, EPSILON) &&
893
0
        epsilonEqual(GetY(data, next, nDim, bNeedSwap), vY, EPSILON))
894
0
    {
895
        // Don't try to be too clever by retrying with a next point.
896
        // This can lead to false results as in the case of #3356.
897
0
        bUseFallback = true;
898
0
    }
899
900
0
    const double dx0 = GetX(data, next, nDim, bNeedSwap) - vX;
901
0
    const double dy0 = GetY(data, next, nDim, bNeedSwap) - vY;
902
903
    // Following.
904
0
    next = v + 1;
905
0
    if (next >= nPoints - 1)
906
0
    {
907
0
        next = 0;
908
0
    }
909
910
0
    if (epsilonEqual(GetX(data, next, nDim, bNeedSwap), vX, EPSILON) &&
911
0
        epsilonEqual(GetY(data, next, nDim, bNeedSwap), vY, EPSILON))
912
0
    {
913
        // Don't try to be too clever by retrying with a next point.
914
        // This can lead to false results as in the case of #3356.
915
0
        bUseFallback = true;
916
0
    }
917
918
0
    const double dx1 = GetX(data, next, nDim, bNeedSwap) - vX;
919
0
    const double dy1 = GetY(data, next, nDim, bNeedSwap) - vY;
920
921
0
    const double crossproduct = dx1 * dy0 - dx0 * dy1;
922
923
0
    if (!bUseFallback)
924
0
    {
925
0
        if (crossproduct > 0)  // CCW
926
0
            return false;
927
0
        else if (crossproduct < 0)  // CW
928
0
            return true;
929
0
    }
930
931
    // This is a degenerate case: the extent of the polygon is less than EPSILON
932
    // or 2 nearly identical points were found.
933
    // Try with Green Formula as a fallback, but this is not a guarantee
934
    // as we'll probably be affected by numerical instabilities.
935
936
0
    double dfSum = GetX(data, 0, nDim, bNeedSwap) *
937
0
                   (GetY(data, 1, nDim, bNeedSwap) -
938
0
                    GetY(data, nPoints - 1, nDim, bNeedSwap));
939
940
0
    for (uint32_t i = 1; i < nPoints - 1; i++)
941
0
    {
942
0
        dfSum += GetX(data, i, nDim, bNeedSwap) *
943
0
                 (GetY(data, i + 1, nDim, bNeedSwap) -
944
0
                  GetY(data, i - 1, nDim, bNeedSwap));
945
0
    }
946
947
0
    dfSum += GetX(data, nPoints - 1, nDim, bNeedSwap) *
948
0
             (GetY(data, 0, nDim, bNeedSwap) -
949
0
              GetX(data, nPoints - 2, nDim, bNeedSwap));
950
951
0
    return dfSum < 0;
952
0
}
953
954
/************************************************************************/
955
/*                OGRWKBFixupCounterClockWiseExternalRing()             */
956
/************************************************************************/
957
958
static bool OGRWKBFixupCounterClockWiseExternalRingInternal(
959
    GByte *data, size_t size, size_t &iOffsetInOut, const int nRec)
960
0
{
961
0
    if (size - iOffsetInOut < MIN_WKB_SIZE)
962
0
    {
963
0
        return false;
964
0
    }
965
0
    const int nByteOrder = DB2_V72_FIX_BYTE_ORDER(data[iOffsetInOut]);
966
0
    if (!(nByteOrder == wkbXDR || nByteOrder == wkbNDR))
967
0
    {
968
0
        return false;
969
0
    }
970
0
    const OGRwkbByteOrder eByteOrder = static_cast<OGRwkbByteOrder>(nByteOrder);
971
972
0
    OGRwkbGeometryType eGeometryType = wkbUnknown;
973
0
    OGRReadWKBGeometryType(data + iOffsetInOut, wkbVariantIso, &eGeometryType);
974
0
    iOffsetInOut += 5;
975
0
    const auto eFlatType = wkbFlatten(eGeometryType);
976
0
    const int nDim = 2 + (OGR_GT_HasZ(eGeometryType) ? 1 : 0) +
977
0
                     (OGR_GT_HasM(eGeometryType) ? 1 : 0);
978
979
0
    if (eFlatType == wkbPolygon)
980
0
    {
981
0
        const uint32_t nRings =
982
0
            OGRWKBReadUInt32AtOffset(data, eByteOrder, iOffsetInOut);
983
0
        if (nRings > (size - iOffsetInOut) / sizeof(uint32_t))
984
0
        {
985
0
            return false;
986
0
        }
987
0
        for (uint32_t iRing = 0; iRing < nRings; ++iRing)
988
0
        {
989
0
            if (iOffsetInOut + sizeof(uint32_t) > size)
990
0
                return false;
991
0
            const uint32_t nPoints =
992
0
                OGRWKBReadUInt32AtOffset(data, eByteOrder, iOffsetInOut);
993
0
            const size_t sizeOfPoint = nDim * sizeof(double);
994
0
            if (nPoints > (size - iOffsetInOut) / sizeOfPoint)
995
0
            {
996
0
                return false;
997
0
            }
998
999
0
            if (nPoints >= 4)
1000
0
            {
1001
0
                const bool bIsClockwiseRing = OGRWKBIsClockwiseRing(
1002
0
                    data + iOffsetInOut, nPoints, nDim, OGR_SWAP(eByteOrder));
1003
0
                if ((bIsClockwiseRing && iRing == 0) ||
1004
0
                    (!bIsClockwiseRing && iRing > 0))
1005
0
                {
1006
0
                    GByte abyTmp[4 * sizeof(double)];
1007
0
                    for (uint32_t i = 0; i < nPoints / 2; ++i)
1008
0
                    {
1009
0
                        GByte *pBegin = data + iOffsetInOut + i * sizeOfPoint;
1010
0
                        GByte *pEnd = data + iOffsetInOut +
1011
0
                                      (nPoints - 1 - i) * sizeOfPoint;
1012
0
                        memcpy(abyTmp, pBegin, sizeOfPoint);
1013
0
                        memcpy(pBegin, pEnd, sizeOfPoint);
1014
0
                        memcpy(pEnd, abyTmp, sizeOfPoint);
1015
0
                    }
1016
0
                }
1017
0
            }
1018
1019
0
            iOffsetInOut += nPoints * sizeOfPoint;
1020
0
        }
1021
0
    }
1022
1023
0
    if (eFlatType == wkbGeometryCollection || eFlatType == wkbMultiPolygon ||
1024
0
        eFlatType == wkbMultiSurface)
1025
0
    {
1026
0
        if (nRec == 128)
1027
0
        {
1028
0
            return false;
1029
0
        }
1030
0
        const uint32_t nParts =
1031
0
            OGRWKBReadUInt32AtOffset(data, eByteOrder, iOffsetInOut);
1032
0
        if (nParts > (size - iOffsetInOut) / MIN_WKB_SIZE)
1033
0
        {
1034
0
            return false;
1035
0
        }
1036
0
        for (uint32_t k = 0; k < nParts; k++)
1037
0
        {
1038
0
            if (!OGRWKBFixupCounterClockWiseExternalRingInternal(
1039
0
                    data, size, iOffsetInOut, nRec))
1040
0
            {
1041
0
                return false;
1042
0
            }
1043
0
        }
1044
0
    }
1045
1046
0
    return true;
1047
0
}
1048
1049
/** Modifies the geometry such that exterior rings of polygons are
1050
 * counter-clockwise oriented and inner rings clockwise oriented.
1051
 */
1052
void OGRWKBFixupCounterClockWiseExternalRing(GByte *pabyWkb, size_t nWKBSize)
1053
0
{
1054
0
    size_t iOffsetInOut = 0;
1055
0
    OGRWKBFixupCounterClockWiseExternalRingInternal(
1056
0
        pabyWkb, nWKBSize, iOffsetInOut, /* nRec = */ 0);
1057
0
}
1058
1059
/************************************************************************/
1060
/*                        OGRWKBPointUpdater()                          */
1061
/************************************************************************/
1062
1063
0
OGRWKBPointUpdater::OGRWKBPointUpdater() = default;
1064
1065
0
OGRWKBPointUpdater::~OGRWKBPointUpdater() = default;
1066
1067
/************************************************************************/
1068
/*              OGRWKBIntersectsPointSequencePessimistic()              */
1069
/************************************************************************/
1070
1071
static bool OGRWKBUpdatePointsSequence(uint8_t *data, const size_t size,
1072
                                       OGRWKBPointUpdater &oUpdater,
1073
                                       const OGRwkbByteOrder eByteOrder,
1074
                                       const int nDim, const bool bHasZ,
1075
                                       const bool bHasM, size_t &iOffsetInOut)
1076
0
{
1077
0
    const uint32_t nPoints =
1078
0
        OGRWKBReadUInt32AtOffset(data, eByteOrder, iOffsetInOut);
1079
0
    if (nPoints > (size - iOffsetInOut) / (nDim * sizeof(double)))
1080
0
    {
1081
0
        return false;
1082
0
    }
1083
0
    const bool bNeedSwap = OGR_SWAP(eByteOrder);
1084
0
    for (uint32_t j = 0; j < nPoints; j++)
1085
0
    {
1086
0
        void *pdfX = data + iOffsetInOut;
1087
0
        void *pdfY = data + iOffsetInOut + sizeof(double);
1088
0
        void *pdfZ = bHasZ ? data + iOffsetInOut + 2 * sizeof(double) : nullptr;
1089
0
        void *pdfM =
1090
0
            bHasM ? data + iOffsetInOut + (bHasZ ? 3 : 2) * sizeof(double)
1091
0
                  : nullptr;
1092
0
        if (!oUpdater.update(bNeedSwap, pdfX, pdfY, pdfZ, pdfM))
1093
0
            return false;
1094
1095
0
        iOffsetInOut += nDim * sizeof(double);
1096
0
    }
1097
1098
0
    return true;
1099
0
}
1100
1101
/************************************************************************/
1102
/*                        OGRWKBVisitRingSequence()                     */
1103
/************************************************************************/
1104
1105
static bool OGRWKBVisitRingSequence(uint8_t *data, const size_t size,
1106
                                    OGRWKBPointUpdater &oUpdater,
1107
                                    const OGRwkbByteOrder eByteOrder,
1108
                                    const int nDim, const bool bHasZ,
1109
                                    const bool bHasM, size_t &iOffsetInOut)
1110
0
{
1111
0
    const uint32_t nRings =
1112
0
        OGRWKBReadUInt32AtOffset(data, eByteOrder, iOffsetInOut);
1113
0
    if (nRings > (size - iOffsetInOut) / sizeof(uint32_t))
1114
0
    {
1115
0
        return false;
1116
0
    }
1117
1118
0
    for (uint32_t i = 0; i < nRings; ++i)
1119
0
    {
1120
0
        if (iOffsetInOut + sizeof(uint32_t) > size)
1121
0
        {
1122
0
            return false;
1123
0
        }
1124
0
        if (!OGRWKBUpdatePointsSequence(data, size, oUpdater, eByteOrder, nDim,
1125
0
                                        bHasZ, bHasM, iOffsetInOut))
1126
0
        {
1127
0
            return false;
1128
0
        }
1129
0
    }
1130
0
    return true;
1131
0
}
1132
1133
/************************************************************************/
1134
/*                      OGRWKBUpdatePoints()                             */
1135
/************************************************************************/
1136
1137
static bool OGRWKBUpdatePoints(uint8_t *data, const size_t size,
1138
                               OGRWKBPointUpdater &oUpdater,
1139
                               size_t &iOffsetInOut, const int nRec)
1140
0
{
1141
0
    if (size - iOffsetInOut < MIN_WKB_SIZE)
1142
0
    {
1143
0
        return false;
1144
0
    }
1145
0
    const int nByteOrder = DB2_V72_FIX_BYTE_ORDER(data[iOffsetInOut]);
1146
0
    if (!(nByteOrder == wkbXDR || nByteOrder == wkbNDR))
1147
0
    {
1148
0
        return false;
1149
0
    }
1150
0
    const OGRwkbByteOrder eByteOrder = static_cast<OGRwkbByteOrder>(nByteOrder);
1151
1152
0
    OGRwkbGeometryType eGeometryType = wkbUnknown;
1153
0
    OGRReadWKBGeometryType(data + iOffsetInOut, wkbVariantIso, &eGeometryType);
1154
0
    iOffsetInOut += 5;
1155
0
    const auto eFlatType = wkbFlatten(eGeometryType);
1156
1157
0
    if (eFlatType == wkbGeometryCollection || eFlatType == wkbCompoundCurve ||
1158
0
        eFlatType == wkbCurvePolygon || eFlatType == wkbMultiPoint ||
1159
0
        eFlatType == wkbMultiLineString || eFlatType == wkbMultiPolygon ||
1160
0
        eFlatType == wkbMultiCurve || eFlatType == wkbMultiSurface ||
1161
0
        eFlatType == wkbPolyhedralSurface || eFlatType == wkbTIN)
1162
0
    {
1163
0
        if (nRec == 128)
1164
0
            return false;
1165
1166
0
        const uint32_t nParts =
1167
0
            OGRWKBReadUInt32AtOffset(data, eByteOrder, iOffsetInOut);
1168
0
        if (nParts > (size - iOffsetInOut) / MIN_WKB_SIZE)
1169
0
        {
1170
0
            return false;
1171
0
        }
1172
0
        for (uint32_t k = 0; k < nParts; k++)
1173
0
        {
1174
0
            if (!OGRWKBUpdatePoints(data, size, oUpdater, iOffsetInOut,
1175
0
                                    nRec + 1))
1176
0
                return false;
1177
0
        }
1178
0
        return true;
1179
0
    }
1180
1181
0
    const bool bHasZ = OGR_GT_HasZ(eGeometryType);
1182
0
    const bool bHasM = OGR_GT_HasM(eGeometryType);
1183
0
    const int nDim = 2 + (bHasZ ? 1 : 0) + (bHasM ? 1 : 0);
1184
1185
0
    if (eFlatType == wkbPoint)
1186
0
    {
1187
0
        if (size - iOffsetInOut < nDim * sizeof(double))
1188
0
            return false;
1189
0
        void *pdfX = data + iOffsetInOut;
1190
0
        void *pdfY = data + iOffsetInOut + sizeof(double);
1191
0
        void *pdfZ = bHasZ ? data + iOffsetInOut + 2 * sizeof(double) : nullptr;
1192
0
        void *pdfM =
1193
0
            bHasM ? data + iOffsetInOut + (bHasZ ? 3 : 2) * sizeof(double)
1194
0
                  : nullptr;
1195
0
        const bool bNeedSwap = OGR_SWAP(eByteOrder);
1196
0
        if (!oUpdater.update(bNeedSwap, pdfX, pdfY, pdfZ, pdfM))
1197
0
            return false;
1198
0
        iOffsetInOut += nDim * sizeof(double);
1199
0
        return true;
1200
0
    }
1201
1202
0
    if (eFlatType == wkbLineString || eFlatType == wkbCircularString)
1203
0
    {
1204
0
        return OGRWKBUpdatePointsSequence(data, size, oUpdater, eByteOrder,
1205
0
                                          nDim, bHasZ, bHasM, iOffsetInOut);
1206
0
    }
1207
1208
0
    if (eFlatType == wkbPolygon || eFlatType == wkbTriangle)
1209
0
    {
1210
0
        return OGRWKBVisitRingSequence(data, size, oUpdater, eByteOrder, nDim,
1211
0
                                       bHasZ, bHasM, iOffsetInOut);
1212
0
    }
1213
1214
0
    CPLDebug("OGR", "Unknown WKB geometry type");
1215
0
    return false;
1216
0
}
1217
1218
/** Visit all points of a WKB geometry to update them.
1219
 */
1220
bool OGRWKBUpdatePoints(GByte *pabyWkb, size_t nWKBSize,
1221
                        OGRWKBPointUpdater &oUpdater)
1222
0
{
1223
0
    size_t iOffsetInOut = 0;
1224
0
    return OGRWKBUpdatePoints(pabyWkb, nWKBSize, oUpdater, iOffsetInOut,
1225
0
                              /* nRec = */ 0);
1226
0
}
1227
1228
/************************************************************************/
1229
/*                    OGRWKBTransformCache::clear()                     */
1230
/************************************************************************/
1231
1232
#ifdef OGR_WKB_TRANSFORM_ALL_AT_ONCE
1233
void OGRWKBTransformCache::clear()
1234
{
1235
    abNeedSwap.clear();
1236
    abIsEmpty.clear();
1237
    apdfX.clear();
1238
    apdfY.clear();
1239
    apdfZ.clear();
1240
    apdfM.clear();
1241
    adfX.clear();
1242
    adfY.clear();
1243
    adfZ.clear();
1244
    adfM.clear();
1245
    anErrorCodes.clear();
1246
}
1247
#endif
1248
1249
/************************************************************************/
1250
/*                         OGRWKBTransform()                            */
1251
/************************************************************************/
1252
1253
/** Visit all points of a WKB geometry to transform them.
1254
 */
1255
bool OGRWKBTransform(GByte *pabyWkb, size_t nWKBSize,
1256
                     OGRCoordinateTransformation *poCT,
1257
                     [[maybe_unused]] OGRWKBTransformCache &oCache,
1258
                     OGREnvelope3D &sEnvelope)
1259
0
{
1260
0
#ifndef OGR_WKB_TRANSFORM_ALL_AT_ONCE
1261
0
    struct OGRWKBPointUpdaterReproj final : public OGRWKBPointUpdater
1262
0
    {
1263
0
        OGRCoordinateTransformation *m_poCT;
1264
0
        OGREnvelope3D &m_sEnvelope;
1265
1266
0
        explicit OGRWKBPointUpdaterReproj(OGRCoordinateTransformation *poCTIn,
1267
0
                                          OGREnvelope3D &sEnvelopeIn)
1268
0
            : m_poCT(poCTIn), m_sEnvelope(sEnvelopeIn)
1269
0
        {
1270
0
        }
1271
1272
0
        bool update(bool bNeedSwap, void *x, void *y, void *z,
1273
0
                    void * /* m */) override
1274
0
        {
1275
0
            double dfX, dfY, dfZ;
1276
0
            memcpy(&dfX, x, sizeof(double));
1277
0
            memcpy(&dfY, y, sizeof(double));
1278
0
            if (bNeedSwap)
1279
0
            {
1280
0
                CPL_SWAP64PTR(&dfX);
1281
0
                CPL_SWAP64PTR(&dfY);
1282
0
            }
1283
0
            if (!(std::isnan(dfX) && std::isnan(dfY)))
1284
0
            {
1285
0
                if (z)
1286
0
                {
1287
0
                    memcpy(&dfZ, z, sizeof(double));
1288
0
                    if (bNeedSwap)
1289
0
                    {
1290
0
                        CPL_SWAP64PTR(&dfZ);
1291
0
                    }
1292
0
                }
1293
0
                else
1294
0
                    dfZ = 0;
1295
0
                int nErrorCode = 0;
1296
0
                m_poCT->TransformWithErrorCodes(1, &dfX, &dfY, &dfZ, nullptr,
1297
0
                                                &nErrorCode);
1298
0
                if (nErrorCode)
1299
0
                    return false;
1300
0
                m_sEnvelope.Merge(dfX, dfY, dfZ);
1301
0
                if (bNeedSwap)
1302
0
                {
1303
0
                    CPL_SWAP64PTR(&dfX);
1304
0
                    CPL_SWAP64PTR(&dfY);
1305
0
                    CPL_SWAP64PTR(&dfZ);
1306
0
                }
1307
0
                memcpy(x, &dfX, sizeof(double));
1308
0
                memcpy(y, &dfY, sizeof(double));
1309
0
                if (z)
1310
0
                    memcpy(z, &dfZ, sizeof(double));
1311
0
            }
1312
0
            return true;
1313
0
        }
1314
1315
0
      private:
1316
0
        OGRWKBPointUpdaterReproj(const OGRWKBPointUpdaterReproj &) = delete;
1317
0
        OGRWKBPointUpdaterReproj &
1318
0
        operator=(const OGRWKBPointUpdaterReproj &) = delete;
1319
0
    };
1320
1321
0
    sEnvelope = OGREnvelope3D();
1322
0
    OGRWKBPointUpdaterReproj oUpdater(poCT, sEnvelope);
1323
0
    return OGRWKBUpdatePoints(pabyWkb, nWKBSize, oUpdater);
1324
1325
#else
1326
    struct OGRWKBPointUpdaterReproj final : public OGRWKBPointUpdater
1327
    {
1328
        OGRWKBTransformCache &m_oCache;
1329
1330
        explicit OGRWKBPointUpdaterReproj(OGRWKBTransformCache &oCacheIn)
1331
            : m_oCache(oCacheIn)
1332
        {
1333
        }
1334
1335
        bool update(bool bNeedSwap, void *x, void *y, void *z,
1336
                    void * /* m */) override
1337
        {
1338
            m_oCache.abNeedSwap.push_back(bNeedSwap);
1339
            m_oCache.apdfX.push_back(x);
1340
            m_oCache.apdfY.push_back(y);
1341
            m_oCache.apdfZ.push_back(z);
1342
            return true;
1343
        }
1344
    };
1345
1346
    oCache.clear();
1347
    OGRWKBPointUpdaterReproj oUpdater(oCache);
1348
    if (!OGRWKBUpdatePoints(pabyWkb, nWKBSize, oUpdater))
1349
        return false;
1350
1351
    oCache.adfX.resize(oCache.apdfX.size());
1352
    oCache.adfY.resize(oCache.apdfX.size());
1353
    oCache.adfZ.resize(oCache.apdfX.size());
1354
1355
    for (size_t i = 0; i < oCache.apdfX.size(); ++i)
1356
    {
1357
        memcpy(&oCache.adfX[i], oCache.apdfX[i], sizeof(double));
1358
        memcpy(&oCache.adfY[i], oCache.apdfY[i], sizeof(double));
1359
        if (oCache.apdfZ[i])
1360
            memcpy(&oCache.adfZ[i], oCache.apdfZ[i], sizeof(double));
1361
        if (oCache.abNeedSwap[i])
1362
        {
1363
            CPL_SWAP64PTR(&oCache.adfX[i]);
1364
            CPL_SWAP64PTR(&oCache.adfY[i]);
1365
            CPL_SWAP64PTR(&oCache.adfZ[i]);
1366
        }
1367
        oCache.abIsEmpty.push_back(std::isnan(oCache.adfX[i]) &&
1368
                                   std::isnan(oCache.adfY[i]));
1369
    }
1370
1371
    oCache.anErrorCodes.resize(oCache.apdfX.size());
1372
    poCT->TransformWithErrorCodes(static_cast<int>(oCache.apdfX.size()),
1373
                                  oCache.adfX.data(), oCache.adfY.data(),
1374
                                  oCache.adfZ.data(), nullptr,
1375
                                  oCache.anErrorCodes.data());
1376
1377
    for (size_t i = 0; i < oCache.apdfX.size(); ++i)
1378
    {
1379
        if (!oCache.abIsEmpty[i] && oCache.anErrorCodes[i])
1380
            return false;
1381
    }
1382
1383
    sEnvelope = OGREnvelope3D();
1384
    for (size_t i = 0; i < oCache.apdfX.size(); ++i)
1385
    {
1386
        if (oCache.abIsEmpty[i])
1387
        {
1388
            oCache.adfX[i] = std::numeric_limits<double>::quiet_NaN();
1389
            oCache.adfY[i] = std::numeric_limits<double>::quiet_NaN();
1390
            oCache.adfZ[i] = std::numeric_limits<double>::quiet_NaN();
1391
        }
1392
        else
1393
        {
1394
            sEnvelope.Merge(oCache.adfX[i], oCache.adfY[i], oCache.adfZ[i]);
1395
        }
1396
        if (oCache.abNeedSwap[i])
1397
        {
1398
            CPL_SWAP64PTR(&oCache.adfX[i]);
1399
            CPL_SWAP64PTR(&oCache.adfY[i]);
1400
            CPL_SWAP64PTR(&oCache.adfZ[i]);
1401
        }
1402
        memcpy(oCache.apdfX[i], &oCache.adfX[i], sizeof(double));
1403
        memcpy(oCache.apdfY[i], &oCache.adfY[i], sizeof(double));
1404
        if (oCache.apdfZ[i])
1405
            memcpy(oCache.apdfZ[i], &oCache.adfZ[i], sizeof(double));
1406
    }
1407
1408
    return true;
1409
#endif
1410
0
}
1411
1412
/************************************************************************/
1413
/*                         OGRAppendBuffer()                            */
1414
/************************************************************************/
1415
1416
0
OGRAppendBuffer::OGRAppendBuffer() = default;
1417
1418
/************************************************************************/
1419
/*                        ~OGRAppendBuffer()                            */
1420
/************************************************************************/
1421
1422
0
OGRAppendBuffer::~OGRAppendBuffer() = default;
1423
1424
/************************************************************************/
1425
/*                       OGRWKTToWKBTranslator()                        */
1426
/************************************************************************/
1427
1428
OGRWKTToWKBTranslator::OGRWKTToWKBTranslator(OGRAppendBuffer &oAppendBuffer)
1429
0
    : m_oAppendBuffer(oAppendBuffer)
1430
0
{
1431
#ifndef USE_FAST_FLOAT
1432
    // Test if current locale decimal separator is decimal point
1433
    char szTest[10];
1434
    snprintf(szTest, sizeof(szTest), "%f", 1.5);
1435
    m_bCanUseStrtod = strchr(szTest, '.') != nullptr;
1436
#endif
1437
0
    CPL_IGNORE_RET_VAL(m_bCanUseStrtod);
1438
0
}
1439
1440
/************************************************************************/
1441
/*                          TranslateWKT()                              */
1442
/************************************************************************/
1443
1444
size_t OGRWKTToWKBTranslator::TranslateWKT(void *pabyWKTStart, size_t nLength,
1445
                                           bool bCanAlterByteAfter)
1446
0
{
1447
0
    const char *pszPtrStart = static_cast<const char *>(pabyWKTStart);
1448
    // Optimize single-part single-ring multipolygon WKT->WKB translation
1449
0
    if (bCanAlterByteAfter && nLength > strlen("MULTIPOLYGON") &&
1450
0
        EQUALN(pszPtrStart, "MULTIPOLYGON", strlen("MULTIPOLYGON")))
1451
0
    {
1452
0
        int nCountOpenPar = 0;
1453
0
        size_t nCountComma = 0;
1454
0
        bool bHasZ = false;
1455
0
        bool bHasM = false;
1456
1457
0
        char *pszEnd = static_cast<char *>(pabyWKTStart) + nLength;
1458
0
        const char chBackup = *pszEnd;
1459
0
        *pszEnd = 0;
1460
1461
        // Checks that the multipolygon consists of a single part with
1462
        // only an exterior ring.
1463
0
        for (const char *pszPtr = pszPtrStart + strlen("MULTIPOLYGON"); *pszPtr;
1464
0
             ++pszPtr)
1465
0
        {
1466
0
            const char ch = *pszPtr;
1467
0
            if (ch == 'Z')
1468
0
                bHasZ = true;
1469
0
            else if (ch == 'M')
1470
0
                bHasM = true;
1471
0
            if (ch == '(')
1472
0
            {
1473
0
                nCountOpenPar++;
1474
0
                if (nCountOpenPar == 4)
1475
0
                    break;
1476
0
            }
1477
0
            else if (ch == ')')
1478
0
            {
1479
0
                nCountOpenPar--;
1480
0
                if (nCountOpenPar < 0)
1481
0
                    break;
1482
0
            }
1483
0
            else if (ch == ',')
1484
0
            {
1485
0
                if (nCountOpenPar < 3)
1486
0
                {
1487
                    // multipart / multi-ring
1488
0
                    break;
1489
0
                }
1490
0
                nCountComma++;
1491
0
            }
1492
0
        }
1493
0
        const int nDim = 2 + (bHasZ ? 1 : 0) + (bHasM ? 1 : 0);
1494
0
        if (nCountOpenPar == 0 && nCountComma > 0 &&
1495
0
            nCountComma < std::numeric_limits<uint32_t>::max())
1496
0
        {
1497
0
            const uint32_t nVerticesCount =
1498
0
                static_cast<uint32_t>(nCountComma + 1);
1499
0
            const size_t nWKBSize =
1500
0
                sizeof(GByte) +     // Endianness
1501
0
                sizeof(uint32_t) +  // multipolygon WKB geometry type
1502
0
                sizeof(uint32_t) +  // number of parts
1503
0
                sizeof(GByte) +     // Endianness
1504
0
                sizeof(uint32_t) +  // polygon WKB geometry type
1505
0
                sizeof(uint32_t) +  // number of rings
1506
0
                sizeof(uint32_t) +  // number of vertices
1507
0
                nDim * sizeof(double) * nVerticesCount;
1508
0
            GByte *const pabyCurStart = static_cast<GByte *>(
1509
0
                m_oAppendBuffer.GetPtrForNewBytes(nWKBSize));
1510
0
            if (!pabyCurStart)
1511
0
            {
1512
0
                return static_cast<size_t>(-1);
1513
0
            }
1514
0
            GByte *pabyCur = pabyCurStart;
1515
            // Multipolygon byte order
1516
0
            {
1517
0
                *pabyCur = wkbNDR;
1518
0
                pabyCur++;
1519
0
            }
1520
            // Multipolygon geometry type
1521
0
            {
1522
0
                uint32_t nWKBGeomType =
1523
0
                    wkbMultiPolygon + (bHasZ ? 1000 : 0) + (bHasM ? 2000 : 0);
1524
0
                CPL_LSBPTR32(&nWKBGeomType);
1525
0
                memcpy(pabyCur, &nWKBGeomType, sizeof(uint32_t));
1526
0
                pabyCur += sizeof(uint32_t);
1527
0
            }
1528
            // Number of parts
1529
0
            {
1530
0
                uint32_t nOne = 1;
1531
0
                CPL_LSBPTR32(&nOne);
1532
0
                memcpy(pabyCur, &nOne, sizeof(uint32_t));
1533
0
                pabyCur += sizeof(uint32_t);
1534
0
            }
1535
            // Polygon byte order
1536
0
            {
1537
0
                *pabyCur = wkbNDR;
1538
0
                pabyCur++;
1539
0
            }
1540
            // Polygon geometry type
1541
0
            {
1542
0
                uint32_t nWKBGeomType =
1543
0
                    wkbPolygon + (bHasZ ? 1000 : 0) + (bHasM ? 2000 : 0);
1544
0
                CPL_LSBPTR32(&nWKBGeomType);
1545
0
                memcpy(pabyCur, &nWKBGeomType, sizeof(uint32_t));
1546
0
                pabyCur += sizeof(uint32_t);
1547
0
            }
1548
            // Number of rings
1549
0
            {
1550
0
                uint32_t nOne = 1;
1551
0
                CPL_LSBPTR32(&nOne);
1552
0
                memcpy(pabyCur, &nOne, sizeof(uint32_t));
1553
0
                pabyCur += sizeof(uint32_t);
1554
0
            }
1555
            // Number of vertices
1556
0
            {
1557
0
                uint32_t nVerticesCountToWrite = nVerticesCount;
1558
0
                CPL_LSBPTR32(&nVerticesCountToWrite);
1559
0
                memcpy(pabyCur, &nVerticesCountToWrite, sizeof(uint32_t));
1560
0
                pabyCur += sizeof(uint32_t);
1561
0
            }
1562
0
            uint32_t nDoubleCount = 0;
1563
0
            const uint32_t nExpectedDoubleCount = nVerticesCount * nDim;
1564
0
            for (const char *pszPtr = pszPtrStart + strlen("MULTIPOLYGON");
1565
0
                 *pszPtr;
1566
0
                 /* nothing */)
1567
0
            {
1568
0
                const char ch = *pszPtr;
1569
0
                if (ch == '-' || ch == '.' || (ch >= '0' && ch <= '9'))
1570
0
                {
1571
0
                    nDoubleCount++;
1572
0
                    if (nDoubleCount > nExpectedDoubleCount)
1573
0
                    {
1574
0
                        break;
1575
0
                    }
1576
0
#ifdef USE_FAST_FLOAT
1577
0
                    double dfVal;
1578
0
                    auto answer = fast_float::from_chars(pszPtr, pszEnd, dfVal);
1579
0
                    if (answer.ec != std::errc())
1580
0
                    {
1581
0
                        nDoubleCount = 0;
1582
0
                        break;
1583
0
                    }
1584
0
                    pszPtr = answer.ptr;
1585
#else
1586
                    char *endptr = nullptr;
1587
                    const double dfVal =
1588
                        m_bCanUseStrtod ? strtod(pszPtr, &endptr)
1589
                                        : CPLStrtodDelim(pszPtr, &endptr, '.');
1590
                    pszPtr = endptr;
1591
#endif
1592
0
                    CPL_LSBPTR64(&dfVal);
1593
0
                    memcpy(pabyCur, &dfVal, sizeof(double));
1594
0
                    pabyCur += sizeof(double);
1595
0
                }
1596
0
                else
1597
0
                {
1598
0
                    ++pszPtr;
1599
0
                }
1600
0
            }
1601
0
            if (nDoubleCount == nExpectedDoubleCount)
1602
0
            {
1603
0
                CPLAssert(static_cast<size_t>(pabyCur - pabyCurStart) ==
1604
0
                          nWKBSize);
1605
                // cppcheck-suppress selfAssignment
1606
0
                *pszEnd = chBackup;
1607
0
                return nWKBSize;
1608
0
            }
1609
0
            else
1610
0
            {
1611
0
                CPLError(CE_Failure, CPLE_AppDefined,
1612
0
                         "Invalid WKT geometry: %s", pszPtrStart);
1613
                // cppcheck-suppress selfAssignment
1614
0
                *pszEnd = chBackup;
1615
0
                return static_cast<size_t>(-1);
1616
0
            }
1617
0
        }
1618
        // cppcheck-suppress selfAssignment
1619
0
        *pszEnd = chBackup;
1620
0
    }
1621
1622
    // General case going through a OGRGeometry
1623
0
    std::unique_ptr<OGRGeometry> poGeometry = nullptr;
1624
0
    if (bCanAlterByteAfter)
1625
0
    {
1626
        // Slight optimization for all geometries but the final one, to
1627
        // avoid creating a new string each time.
1628
        // We set the ending byte to '\0' and restore it back after parsing
1629
        // the WKT
1630
0
        char *pszEnd = static_cast<char *>(pabyWKTStart) + nLength;
1631
0
        const char chBackup = *pszEnd;
1632
0
        *pszEnd = 0;
1633
0
        poGeometry = OGRGeometryFactory::createFromWkt(pszPtrStart).first;
1634
        // cppcheck-suppress selfAssignment
1635
0
        *pszEnd = chBackup;
1636
0
    }
1637
0
    else
1638
0
    {
1639
0
        std::string osTmp;
1640
0
        osTmp.assign(pszPtrStart, nLength);
1641
0
        poGeometry = OGRGeometryFactory::createFromWkt(osTmp.c_str()).first;
1642
0
    }
1643
0
    if (!poGeometry)
1644
0
    {
1645
0
        CPLError(CE_Failure, CPLE_AppDefined, "Invalid WKT geometry");
1646
0
        return static_cast<size_t>(-1);
1647
0
    }
1648
0
    const size_t nWKBSize = poGeometry->WkbSize();
1649
0
    GByte *pabyWKB =
1650
0
        static_cast<GByte *>(m_oAppendBuffer.GetPtrForNewBytes(nWKBSize));
1651
0
    if (!pabyWKB)
1652
0
    {
1653
0
        return static_cast<size_t>(-1);
1654
0
    }
1655
0
    poGeometry->exportToWkb(wkbNDR, pabyWKB, wkbVariantIso);
1656
0
    return nWKBSize;
1657
0
}