Coverage Report

Created: 2026-07-25 06:50

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