Coverage Report

Created: 2026-08-31 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgis/liblwgeom/lwin_wkb.c
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * PostGIS - Spatial Types for PostgreSQL
4
 * http://postgis.net
5
 *
6
 * PostGIS is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 2 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * PostGIS is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with PostGIS.  If not, see <http://www.gnu.org/licenses/>.
18
 *
19
 **********************************************************************
20
 *
21
 * Copyright (C) 2009 Paul Ramsey <pramsey@cleverelephant.ca>
22
 *
23
 **********************************************************************/
24
25
26
#include "../postgis_config.h"
27
/*#define POSTGIS_DEBUG_LEVEL 4*/
28
#include "liblwgeom_internal.h" /* NOTE: includes lwgeom_log.h */
29
#include "lwgeom_log.h"
30
#include <math.h>
31
#include <limits.h>
32
33
/** Max depth in a geometry. Matches the default YYINITDEPTH for WKT */
34
44.8k
#define LW_PARSER_MAX_DEPTH 200
35
36
/**
37
* Used for passing the parse state between the parsing functions.
38
*/
39
typedef struct
40
{
41
  const uint8_t *wkb; /* Points to start of WKB */
42
  int32_t srid;    /* Current SRID we are handling */
43
  size_t wkb_size; /* Expected size of WKB */
44
  int8_t swap_bytes;  /* Do an endian flip? */
45
  int8_t check;       /* Simple validity checks on geometries */
46
  int8_t lwtype;      /* Current type we are handling */
47
  int8_t has_z;       /* Z? */
48
  int8_t has_m;       /* M? */
49
  int8_t has_srid;    /* SRID? */
50
  int8_t error;       /* An error was found (not enough bytes to read) */
51
  uint8_t depth;      /* Current recursion level (to prevent stack overflows). Maxes at LW_PARSER_MAX_DEPTH */
52
  size_t pos_offset;  /* Current parse offset from wkb */
53
  const uint8_t *pos; /* Current parse position */
54
} wkb_parse_state;
55
56
57
/**
58
* Internal function declarations.
59
*/
60
LWGEOM* lwgeom_from_wkb_state(wkb_parse_state *s);
61
62
63
64
/**********************************************************************/
65
66
/* Our static character->number map. Anything > 15 is invalid */
67
static uint8_t hex2char[256] = {
68
    /* not Hex characters */
69
    20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
70
    20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
71
    20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
72
    /* 0-9 */
73
    0,1,2,3,4,5,6,7,8,9,20,20,20,20,20,20,
74
    /* A-F */
75
    20,10,11,12,13,14,15,20,20,20,20,20,20,20,20,20,
76
    /* not Hex characters */
77
    20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
78
  /* a-f */
79
    20,10,11,12,13,14,15,20,20,20,20,20,20,20,20,20,
80
    20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
81
    /* not Hex characters (upper 128 characters) */
82
    20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
83
    20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
84
    20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
85
    20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
86
    20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
87
    20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
88
    20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
89
    20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20
90
    };
91
92
93
uint8_t* bytes_from_hexbytes(const char *hexbuf, size_t hexsize)
94
0
{
95
0
  uint8_t *buf = NULL;
96
0
  register uint8_t h1, h2;
97
0
  uint32_t i;
98
99
0
  if( hexsize % 2 )
100
0
    lwerror("Invalid hex string, length (%zu) has to be a multiple of two!", hexsize);
101
102
0
  buf = lwalloc(hexsize/2);
103
104
0
  if( ! buf )
105
0
    lwerror("Unable to allocate memory buffer.");
106
107
0
  for( i = 0; i < hexsize/2; i++ )
108
0
  {
109
0
    h1 = hex2char[(uint8_t)hexbuf[2*i]];
110
0
    h2 = hex2char[(uint8_t)hexbuf[2*i+1]];
111
0
    if( h1 > 15 )
112
0
      lwerror("Invalid hex character (%c) encountered", hexbuf[2*i]);
113
0
    if( h2 > 15 )
114
0
      lwerror("Invalid hex character (%c) encountered", hexbuf[2*i+1]);
115
    /* First character is high bits, second is low bits */
116
0
    buf[i] = ((h1 & 0x0F) << 4) | (h2 & 0x0F);
117
0
  }
118
0
  return buf;
119
0
}
120
121
122
/**********************************************************************/
123
124
125
126
/**
127
* Check that we are not about to read off the end of the WKB
128
* array.
129
*/
130
static inline void wkb_parse_state_check(wkb_parse_state *s, size_t next)
131
8.62M
{
132
8.62M
  if (next > s->wkb_size || s->pos_offset > s->wkb_size - next)
133
2.34k
  {
134
2.34k
    lwerror("WKB structure does not match expected size!");
135
2.34k
    s->error = LW_TRUE;
136
2.34k
  }
137
8.62M
}
138
139
static inline void
140
wkb_parse_state_advance(wkb_parse_state *s, size_t next)
141
8.55M
{
142
8.55M
  s->pos_offset += next;
143
8.55M
  s->pos += next;
144
8.55M
}
145
146
static inline int
147
wkb_checked_mul_size(size_t a, size_t b, size_t *result)
148
211k
{
149
211k
  if (a != 0 && b > SIZE_MAX / a)
150
0
    return LW_FALSE;
151
152
211k
  *result = a * b;
153
211k
  return LW_TRUE;
154
211k
}
155
156
static inline int
157
wkb_checked_add_size(size_t a, size_t b, size_t *result)
158
53.5k
{
159
53.5k
  if (b > SIZE_MAX - a)
160
0
    return LW_FALSE;
161
162
53.5k
  *result = a + b;
163
53.5k
  return LW_TRUE;
164
53.5k
}
165
166
/**
167
 * Resolve a raw WKB type number into the parser state' internal type and flags.
168
 *
169
 * Interprets WKB type encodings (including extended flag bits and ISO-style
170
 * 1000/2000/3000 modifiers) and updates the provided parse state:
171
 * - sets s->has_z, s->has_m, s->has_srid according to detected flags,
172
 * - sets s->lwtype to the corresponding internal lwgeom type enum.
173
 *
174
 * Recognizes standard WKB types, ISO extended encodings (where 1000/2000/3000
175
 * ranges indicate Z/M presence), explicit high-bit flag encodings, and a few
176
 * legacy PostGIS values (e.g., old Curve/Surface codes). On unrecognized or
177
 * out-of-range type numbers an error is reported via lwerror and the state is
178
 * left with whatever values were set before the error.
179
 */
180
static void lwtype_from_wkb_state(wkb_parse_state *s, uint32_t wkb_type)
181
381k
{
182
381k
  uint32_t wkb_simple_type;
183
184
381k
  LWDEBUG(4, "Entered function");
185
186
381k
  s->has_z = LW_FALSE;
187
381k
  s->has_m = LW_FALSE;
188
381k
  s->has_srid = LW_FALSE;
189
190
  /* If any of the higher bits are set, this is probably an extended type. */
191
381k
  if( wkb_type & 0xF0000000 )
192
55.5k
  {
193
55.5k
    if( wkb_type & WKBZOFFSET ) s->has_z = LW_TRUE;
194
55.5k
    if( wkb_type & WKBMOFFSET ) s->has_m = LW_TRUE;
195
55.5k
    if( wkb_type & WKBSRIDFLAG ) s->has_srid = LW_TRUE;
196
55.5k
    LWDEBUGF(4, "Extended type: has_z=%d has_m=%d has_srid=%d", s->has_z, s->has_m, s->has_srid);
197
55.5k
  }
198
199
  /* Mask off the flags */
200
381k
  wkb_type = wkb_type & 0x0FFFFFFF;
201
202
  /* Catch strange Oracle WKB type numbers */
203
381k
  if ( wkb_type >= 4000 ) {
204
306
    lwerror("Unknown WKB type (%d)!", wkb_type);
205
306
    return;
206
306
  }
207
208
  /* Strip out just the type number (1-12) from the ISO number (eg 3001-3012) */
209
381k
  wkb_simple_type = wkb_type % 1000;
210
211
  /* Extract the Z/M information from ISO style numbers */
212
381k
  if( wkb_type >= 3000 && wkb_type < 4000 )
213
1.69k
  {
214
1.69k
    s->has_z = LW_TRUE;
215
1.69k
    s->has_m = LW_TRUE;
216
1.69k
  }
217
379k
  else if ( wkb_type >= 2000 && wkb_type < 3000 )
218
543
  {
219
543
    s->has_m = LW_TRUE;
220
543
  }
221
379k
  else if ( wkb_type >= 1000 && wkb_type < 2000 )
222
2.97k
  {
223
2.97k
    s->has_z = LW_TRUE;
224
2.97k
  }
225
226
381k
  switch (wkb_simple_type)
227
381k
  {
228
12.0k
    case WKB_POINT_TYPE:
229
12.0k
      s->lwtype = POINTTYPE;
230
12.0k
      break;
231
82.4k
    case WKB_LINESTRING_TYPE:
232
82.4k
      s->lwtype = LINETYPE;
233
82.4k
      break;
234
8.94k
    case WKB_POLYGON_TYPE:
235
8.94k
      s->lwtype = POLYGONTYPE;
236
8.94k
      break;
237
2.56k
    case WKB_MULTIPOINT_TYPE:
238
2.56k
      s->lwtype = MULTIPOINTTYPE;
239
2.56k
      break;
240
3.26k
    case WKB_MULTILINESTRING_TYPE:
241
3.26k
      s->lwtype = MULTILINETYPE;
242
3.26k
      break;
243
1.60k
    case WKB_MULTIPOLYGON_TYPE:
244
1.60k
      s->lwtype = MULTIPOLYGONTYPE;
245
1.60k
      break;
246
26.8k
    case WKB_GEOMETRYCOLLECTION_TYPE:
247
26.8k
      s->lwtype = COLLECTIONTYPE;
248
26.8k
      break;
249
95.6k
    case WKB_CIRCULARSTRING_TYPE:
250
95.6k
      s->lwtype = CIRCSTRINGTYPE;
251
95.6k
      break;
252
79.0k
    case WKB_COMPOUNDCURVE_TYPE:
253
79.0k
      s->lwtype = COMPOUNDTYPE;
254
79.0k
      break;
255
4.38k
    case WKB_CURVEPOLYGON_TYPE:
256
4.38k
      s->lwtype = CURVEPOLYTYPE;
257
4.38k
      break;
258
2.73k
    case WKB_MULTICURVE_TYPE:
259
2.73k
      s->lwtype = MULTICURVETYPE;
260
2.73k
      break;
261
1.43k
    case WKB_MULTISURFACE_TYPE:
262
1.43k
      s->lwtype = MULTISURFACETYPE;
263
1.43k
      break;
264
4.24k
    case WKB_POLYHEDRALSURFACE_TYPE:
265
4.24k
      s->lwtype = POLYHEDRALSURFACETYPE;
266
4.24k
      break;
267
3.17k
    case WKB_TIN_TYPE:
268
3.17k
      s->lwtype = TINTYPE;
269
3.17k
      break;
270
18.5k
    case WKB_TRIANGLE_TYPE:
271
18.5k
      s->lwtype = TRIANGLETYPE;
272
18.5k
      break;
273
27.2k
    case WKB_NURBSCURVE_TYPE:
274
27.2k
      s->lwtype = NURBSCURVETYPE;
275
27.2k
      break;
276
277
    /* PostGIS 1.5 emits 13, 14 for CurvePolygon, MultiCurve */
278
    /* These numbers aren't SQL/MM (numbers currently only */
279
    /* go up to 12. We can handle the old data here (for now??) */
280
    /* converting them into the lwtypes that are intended. */
281
4.08k
    case WKB_CURVE_TYPE:
282
4.08k
      s->lwtype = CURVEPOLYTYPE;
283
4.08k
      break;
284
3.07k
    case WKB_SURFACE_TYPE:
285
3.07k
      s->lwtype = MULTICURVETYPE;
286
3.07k
      break;
287
288
216
    default: /* Error! */
289
216
      lwerror("Unknown WKB type (%d)! Full WKB type number was (%d).", wkb_simple_type, wkb_type);
290
216
      break;
291
381k
  }
292
293
381k
  LWDEBUGF(4,"Got lwtype %s (%u)", lwtype_name(s->lwtype), s->lwtype);
294
295
381k
  return;
296
381k
}
297
298
/**
299
* Byte
300
* Read a byte and advance the parse state forward.
301
*/
302
static char byte_from_wkb_state(wkb_parse_state *s)
303
2.93M
{
304
2.93M
  char char_value = 0;
305
2.93M
  LWDEBUG(4, "Entered function");
306
307
2.93M
  wkb_parse_state_check(s, WKB_BYTE_SIZE);
308
2.93M
  if (s->error)
309
0
    return 0;
310
2.93M
  LWDEBUG(4, "Passed state check");
311
312
2.93M
  char_value = s->pos[0];
313
2.93M
  LWDEBUGF(4, "Read byte value: %x", char_value);
314
2.93M
  wkb_parse_state_advance(s, WKB_BYTE_SIZE);
315
316
2.93M
  return char_value;
317
2.93M
}
318
319
320
/**
321
* Int32
322
* Read 4-byte integer and advance the parse state forward.
323
*/
324
static uint32_t integer_from_wkb_state(wkb_parse_state *s)
325
856k
{
326
856k
  uint32_t i = 0;
327
328
856k
  wkb_parse_state_check(s, WKB_INT_SIZE);
329
856k
  if (s->error)
330
0
    return 0;
331
332
856k
  memcpy(&i, s->pos, WKB_INT_SIZE);
333
334
  /* Swap? Copy into a stack-allocated integer. */
335
856k
  if( s->swap_bytes )
336
504k
  {
337
504k
    int j = 0;
338
504k
    uint8_t tmp;
339
340
1.51M
    for( j = 0; j < WKB_INT_SIZE/2; j++ )
341
1.00M
    {
342
1.00M
      tmp = ((uint8_t*)(&i))[j];
343
1.00M
      ((uint8_t*)(&i))[j] = ((uint8_t*)(&i))[WKB_INT_SIZE - j - 1];
344
1.00M
      ((uint8_t*)(&i))[WKB_INT_SIZE - j - 1] = tmp;
345
1.00M
    }
346
504k
  }
347
348
856k
  wkb_parse_state_advance(s, WKB_INT_SIZE);
349
856k
  return i;
350
856k
}
351
352
/**
353
* Double
354
* Read an 8-byte double and advance the parse state forward.
355
*/
356
static double double_from_wkb_state(wkb_parse_state *s)
357
4.72M
{
358
4.72M
  double d = 0;
359
360
  /* Check bounds before reading */
361
4.72M
  wkb_parse_state_check(s, WKB_DOUBLE_SIZE);
362
4.72M
  if (s->error) return 0.0;
363
364
4.72M
  memcpy(&d, s->pos, WKB_DOUBLE_SIZE);
365
366
  /* Swap? Copy into a stack-allocated integer. */
367
4.72M
  if( s->swap_bytes )
368
358k
  {
369
358k
    int i = 0;
370
358k
    uint8_t tmp;
371
372
1.79M
    for( i = 0; i < WKB_DOUBLE_SIZE/2; i++ )
373
1.43M
    {
374
1.43M
      tmp = ((uint8_t*)(&d))[i];
375
1.43M
      ((uint8_t*)(&d))[i] = ((uint8_t*)(&d))[WKB_DOUBLE_SIZE - i - 1];
376
1.43M
      ((uint8_t*)(&d))[WKB_DOUBLE_SIZE - i - 1] = tmp;
377
1.43M
    }
378
358k
  }
379
380
4.72M
  wkb_parse_state_advance(s, WKB_DOUBLE_SIZE);
381
4.72M
  return d;
382
4.72M
}
383
384
385
386
/**
387
* Set the swap bytes flag depending on the endianness
388
* of the machine and the endianness of the input data.
389
* If they differ, we must swap, otherwise we can copy.
390
*/
391
static void wkb_swap_bytes(wkb_parse_state *s)
392
1.66M
{
393
1.66M
  char wkb_little_endian;
394
395
  /* Fail when handed incorrect starting byte */
396
1.66M
  wkb_little_endian = byte_from_wkb_state(s);
397
1.66M
  if (s->error)
398
0
    lwerror("Invalid endian flag value encountered.");
399
400
1.66M
  if( wkb_little_endian != 1 && wkb_little_endian != 0 )
401
164
  {
402
164
    s->error = LW_TRUE;
403
164
    lwerror("Invalid endian flag value encountered.");
404
164
  }
405
406
  /* Check the endianness of our input  */
407
1.66M
  s->swap_bytes = LW_FALSE;
408
409
  /* Machine arch is big endian, request is for little */
410
1.66M
  if (IS_BIG_ENDIAN && wkb_little_endian)
411
0
    s->swap_bytes = LW_TRUE;
412
  /* Machine arch is little endian, request is for big */
413
1.66M
  else if ((!IS_BIG_ENDIAN) && (!wkb_little_endian))
414
245k
    s->swap_bytes = LW_TRUE;
415
1.66M
}
416
417
418
419
/**
420
* POINTARRAY
421
* Read a dynamically sized point array and advance the parse state forward.
422
* First read the number of points, then read the points.
423
*/
424
static POINTARRAY* ptarray_from_wkb_state(wkb_parse_state *s)
425
220k
{
426
220k
  POINTARRAY *pa = NULL;
427
220k
  size_t pa_size;
428
220k
  uint32_t npoints = 0;
429
220k
  static uint32_t maxpoints = UINT_MAX / WKB_DOUBLE_SIZE / 4;
430
220k
  uint32_t ndims = 2 + s->has_z + s->has_m;
431
432
  /* Calculate the size of this point array. */
433
220k
  npoints = integer_from_wkb_state(s);
434
220k
  if (s->error)
435
0
    return NULL;
436
437
220k
  if (npoints > maxpoints)
438
36
  {
439
36
    s->error = LW_TRUE;
440
36
    lwerror("Pointarray length (%d) is too large", npoints);
441
36
    return NULL;
442
36
  }
443
444
220k
  LWDEBUGF(4,"Pointarray has %d points", npoints);
445
446
  /* Empty! */
447
220k
  if( npoints == 0 )
448
181k
    return ptarray_construct(s->has_z, s->has_m, npoints);
449
450
  /* Does the data we want to read exist? */
451
38.8k
  if (!wkb_checked_mul_size((size_t)npoints, ndims, &pa_size) ||
452
38.5k
      !wkb_checked_mul_size(pa_size, WKB_DOUBLE_SIZE, &pa_size))
453
0
  {
454
0
    s->error = LW_TRUE;
455
0
    lwerror("Pointarray length (%d) is too large", npoints);
456
0
    return NULL;
457
0
  }
458
38.8k
  wkb_parse_state_check(s, pa_size);
459
38.8k
  if (s->error)
460
0
    return NULL;
461
462
  /* If we're in a native endianness, we can just copy the data directly! */
463
38.8k
  if( ! s->swap_bytes )
464
25.2k
  {
465
25.2k
    pa = ptarray_construct_copy_data(s->has_z, s->has_m, npoints, (uint8_t*)s->pos);
466
25.2k
    wkb_parse_state_advance(s, pa_size);
467
25.2k
  }
468
  /* Otherwise we have to read each double, separately. */
469
13.5k
  else
470
13.5k
  {
471
13.5k
    uint32_t i = 0;
472
13.5k
    double *dlist;
473
13.5k
    pa = ptarray_construct(s->has_z, s->has_m, npoints);
474
13.5k
    dlist = (double*)(pa->serialized_pointlist);
475
320k
    for( i = 0; i < npoints * ndims; i++ )
476
307k
    {
477
307k
      dlist[i] = double_from_wkb_state(s);
478
307k
    }
479
13.5k
  }
480
481
38.8k
  return pa;
482
38.8k
}
483
484
/**
485
* POINT
486
* Read a WKB point, starting just after the endian byte,
487
* type number and optional srid number.
488
* Advance the parse state forward appropriately.
489
* WKB point has just a set of doubles, with the quantity depending on the
490
* dimension of the point, so this looks like a special case of the above
491
* with only one point.
492
*/
493
static LWPOINT* lwpoint_from_wkb_state(wkb_parse_state *s)
494
12.0k
{
495
12.0k
  static uint32_t npoints = 1;
496
12.0k
  POINTARRAY *pa = NULL;
497
12.0k
  size_t pa_size;
498
12.0k
  uint32_t ndims = 2;
499
12.0k
  const POINT2D *pt;
500
501
  /* Count the dimensions. */
502
12.0k
  if( s->has_z ) ndims++;
503
12.0k
  if( s->has_m ) ndims++;
504
12.0k
  pa_size = ndims * WKB_DOUBLE_SIZE;
505
506
  /* Does the data we want to read exist? */
507
12.0k
  wkb_parse_state_check(s, pa_size);
508
12.0k
  if (s->error)
509
0
    return NULL;
510
511
  /* If we're in a native endianness, we can just copy the data directly! */
512
12.0k
  if( ! s->swap_bytes )
513
5.80k
  {
514
5.80k
    pa = ptarray_construct_copy_data(s->has_z, s->has_m, npoints, (uint8_t*)s->pos);
515
5.80k
    wkb_parse_state_advance(s, pa_size);
516
5.80k
  }
517
  /* Otherwise we have to read each double, separately */
518
6.26k
  else
519
6.26k
  {
520
6.26k
    uint32_t i = 0;
521
6.26k
    double *dlist;
522
6.26k
    pa = ptarray_construct(s->has_z, s->has_m, npoints);
523
6.26k
    dlist = (double*)(pa->serialized_pointlist);
524
22.1k
    for( i = 0; i < ndims; i++ )
525
15.8k
    {
526
15.8k
      dlist[i] = double_from_wkb_state(s);
527
15.8k
    }
528
6.26k
  }
529
530
  /* Check for POINT(NaN NaN) ==> POINT EMPTY */
531
12.0k
  pt = getPoint2d_cp(pa, 0);
532
12.0k
  if ( isnan(pt->x) && isnan(pt->y) )
533
704
  {
534
704
    ptarray_free(pa);
535
704
    return lwpoint_construct_empty(s->srid, s->has_z, s->has_m);
536
704
  }
537
11.3k
  else
538
11.3k
  {
539
11.3k
    return lwpoint_construct(s->srid, NULL, pa);
540
11.3k
  }
541
12.0k
}
542
543
/**
544
* LINESTRING
545
* Read a WKB linestring, starting just after the endian byte,
546
* type number and optional srid number. Advance the parse state
547
* forward appropriately.
548
* There is only one pointarray in a linestring. Optionally
549
* check for minimal following of rules (two point minimum).
550
*/
551
static LWLINE* lwline_from_wkb_state(wkb_parse_state *s)
552
82.4k
{
553
82.4k
  POINTARRAY *pa = ptarray_from_wkb_state(s);
554
82.4k
  if (s->error)
555
0
    return NULL;
556
557
82.4k
  if( pa == NULL || pa->npoints == 0 )
558
80.9k
  {
559
80.9k
    if (pa)
560
80.9k
      ptarray_free(pa);
561
80.9k
    return lwline_construct_empty(s->srid, s->has_z, s->has_m);
562
80.9k
  }
563
564
1.50k
  if( s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 2 )
565
8
  {
566
8
    lwerror("%s must have at least two points", lwtype_name(s->lwtype));
567
8
    return NULL;
568
8
  }
569
570
1.49k
  return lwline_construct(s->srid, NULL, pa);
571
1.50k
}
572
573
/**
574
* CIRCULARSTRING
575
* Read a WKB circularstring, starting just after the endian byte,
576
* type number and optional srid number. Advance the parse state
577
* forward appropriately.
578
* There is only one pointarray in a linestring. Optionally
579
* check for minimal following of rules (three point minimum,
580
* odd number of points).
581
*/
582
static LWCIRCSTRING* lwcircstring_from_wkb_state(wkb_parse_state *s)
583
95.6k
{
584
95.6k
  POINTARRAY *pa = ptarray_from_wkb_state(s);
585
95.6k
  if (s->error)
586
0
    return NULL;
587
588
95.6k
  if( pa == NULL || pa->npoints == 0 )
589
93.6k
  {
590
93.6k
    if (pa)
591
93.6k
      ptarray_free(pa);
592
93.6k
    return lwcircstring_construct_empty(s->srid, s->has_z, s->has_m);
593
93.6k
  }
594
595
1.96k
  if( s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 3 )
596
3
  {
597
3
    lwerror("%s must have at least three points", lwtype_name(s->lwtype));
598
3
    return NULL;
599
3
  }
600
601
1.96k
  if( s->check & LW_PARSER_CHECK_ODD && ! (pa->npoints % 2) )
602
72
  {
603
72
    lwerror("%s must have an odd number of points", lwtype_name(s->lwtype));
604
72
    return NULL;
605
72
  }
606
607
1.89k
  return lwcircstring_construct(s->srid, NULL, pa);
608
1.96k
}
609
610
/**
611
* POLYGON
612
* Read a WKB polygon, starting just after the endian byte,
613
* type number and optional srid number. Advance the parse state
614
* forward appropriately.
615
* First read the number of rings, then read each ring
616
* (which are structured as point arrays)
617
*/
618
static LWPOLY* lwpoly_from_wkb_state(wkb_parse_state *s)
619
8.93k
{
620
8.93k
  uint32_t nrings = integer_from_wkb_state(s);
621
8.93k
  if (s->error)
622
0
    return NULL;
623
8.93k
  uint32_t i = 0;
624
8.93k
  LWPOLY *poly = lwpoly_construct_empty(s->srid, s->has_z, s->has_m);
625
626
8.93k
  LWDEBUGF(4,"Polygon has %d rings", nrings);
627
628
  /* Empty polygon? */
629
8.93k
  if( nrings == 0 )
630
6.59k
    return poly;
631
632
40.0k
  for( i = 0; i < nrings; i++ )
633
38.0k
  {
634
38.0k
    POINTARRAY *pa = ptarray_from_wkb_state(s);
635
38.0k
    if (pa == NULL)
636
0
    {
637
0
      lwpoly_free(poly);
638
0
      return NULL;
639
0
    }
640
641
    /* Check for at least four points. */
642
38.0k
    if (s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 4)
643
94
    {
644
94
      lwpoly_free(poly);
645
94
      ptarray_free(pa);
646
94
      LWDEBUGF(2, "%s must have at least four points in each ring", lwtype_name(s->lwtype));
647
94
      lwerror("%s must have at least four points in each ring", lwtype_name(s->lwtype));
648
94
      return NULL;
649
94
    }
650
651
    /* Check that first and last points are the same. */
652
37.9k
    if( s->check & LW_PARSER_CHECK_CLOSURE && ! ptarray_is_closed_2d(pa) )
653
286
    {
654
286
      lwpoly_free(poly);
655
286
      ptarray_free(pa);
656
286
      LWDEBUGF(2, "%s must have closed rings", lwtype_name(s->lwtype));
657
286
      lwerror("%s must have closed rings", lwtype_name(s->lwtype));
658
286
      return NULL;
659
286
    }
660
661
    /* Skip zero-member rings, they add nothing */
662
37.6k
    if ( pa->npoints == 0)
663
6.65k
    {
664
6.65k
      LWDEBUGF(2, "Skipping empty ring [%d]", i);
665
6.65k
      ptarray_free(pa);
666
6.65k
      continue;
667
6.65k
    }
668
669
    /* Add ring to polygon */
670
31.0k
    if ( lwpoly_add_ring(poly, pa) == LW_FAILURE )
671
0
    {
672
0
      lwpoly_free(poly);
673
0
      ptarray_free(pa);
674
0
      LWDEBUG(2, "Unable to add ring to polygon");
675
0
      lwerror("Unable to add ring to polygon");
676
0
      return NULL;
677
0
    }
678
679
31.0k
  }
680
1.96k
  return poly;
681
2.34k
}
682
683
/**
684
* TRIANGLE
685
* Read a WKB triangle, starting just after the endian byte,
686
* type number and optional srid number. Advance the parse state
687
* forward appropriately.
688
* Triangles are encoded like polygons in WKB, but more like linestrings
689
* as lwgeometries.
690
*/
691
static LWTRIANGLE* lwtriangle_from_wkb_state(wkb_parse_state *s)
692
18.5k
{
693
18.5k
  uint32_t nrings = integer_from_wkb_state(s);
694
18.5k
  if (s->error)
695
0
    return NULL;
696
697
  /* Empty triangle? */
698
18.5k
  if( nrings == 0 )
699
13.7k
    return lwtriangle_construct_empty(s->srid, s->has_z, s->has_m);
700
701
  /* Should be only one ring. */
702
4.83k
  if (nrings != 1)
703
129
  {
704
129
    lwerror("Triangle has wrong number of rings: %d", nrings);
705
129
  }
706
707
  /* There's only one ring, we hope? */
708
4.83k
  POINTARRAY *pa = ptarray_from_wkb_state(s);
709
710
  /* If there's no points, return an empty triangle. */
711
4.83k
  if (pa == NULL)
712
0
    return lwtriangle_construct_empty(s->srid, s->has_z, s->has_m);
713
714
  /* Check for at least four points. */
715
4.83k
  if (s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 4)
716
85
  {
717
85
    ptarray_free(pa);
718
85
    lwerror("%s must have at least four points", lwtype_name(s->lwtype));
719
85
    return NULL;
720
85
  }
721
722
4.75k
  if (s->check & LW_PARSER_CHECK_ZCLOSURE && !ptarray_is_closed_z(pa))
723
347
  {
724
347
    ptarray_free(pa);
725
347
    lwerror("%s must have closed rings", lwtype_name(s->lwtype));
726
347
    return NULL;
727
347
  }
728
729
  /* Empty TRIANGLE starts w/ empty POINTARRAY, free it first */
730
4.40k
  return lwtriangle_construct(s->srid, NULL, pa);
731
4.75k
}
732
733
/**
734
* CURVEPOLYTYPE
735
*/
736
static LWCURVEPOLY* lwcurvepoly_from_wkb_state(wkb_parse_state *s)
737
8.46k
{
738
8.46k
  uint32_t ngeoms = integer_from_wkb_state(s);
739
8.46k
  if (s->error)
740
0
    return NULL;
741
8.46k
  LWCURVEPOLY *cp = lwcurvepoly_construct_empty(s->srid, s->has_z, s->has_m);
742
8.46k
  LWGEOM *geom = NULL;
743
8.46k
  uint32_t i;
744
745
  /* Empty collection? */
746
8.46k
  if ( ngeoms == 0 )
747
660
    return cp;
748
749
7.80k
  s->depth++;
750
7.80k
  if (s->depth >= LW_PARSER_MAX_DEPTH)
751
2
  {
752
2
    lwgeom_free((LWGEOM *)cp);
753
2
    lwerror("Geometry has too many chained curves");
754
2
    return NULL;
755
2
  }
756
200k
  for ( i = 0; i < ngeoms; i++ )
757
192k
  {
758
192k
    geom = lwgeom_from_wkb_state(s);
759
192k
    if ( lwcurvepoly_add_ring(cp, geom) == LW_FAILURE )
760
126
    {
761
126
      lwgeom_free(geom);
762
126
      lwgeom_free((LWGEOM *)cp);
763
126
      lwerror("Unable to add geometry (%p) to curvepoly (%p)", (void *) geom, (void *) cp);
764
126
      return NULL;
765
126
    }
766
192k
  }
767
7.67k
  s->depth--;
768
769
7.67k
  return cp;
770
7.80k
}
771
772
/**
773
* POLYHEDRALSURFACETYPE
774
*/
775
776
static LWCOLLECTION* lwcollection_from_wkb_state(wkb_parse_state *s);
777
static LWNURBSCURVE* lwnurbscurve_from_wkb_state(wkb_parse_state *s);
778
779
/**
780
 * Parse a collection (MULTI types, COLLECTION, TINTYPE, COMPOUND, CURVEPOLY, etc.) from WKB state.
781
 *
782
 * Reads the number of component geometries from the WKB parse state, constructs an
783
 * empty LWCOLLECTION of the current s->lwtype/srid/dimension flags, then iteratively
784
 * parses and appends each component geometry using lwgeom_from_wkb_state().
785
 *
786
 * Behavior and side effects:
787
 * - Returns a newly allocated LWCOLLECTION containing the parsed components, or NULL on error.
788
 * - For an empty collection (component count == 0) returns the empty collection.
789
 * - If s->lwtype == POLYHEDRALSURFACETYPE, enables strict Z-closure checking by setting
790
 *   the LW_PARSER_CHECK_ZCLOSURE flag in s->check before parsing components.
791
 * - Increments s->depth while parsing to enforce recursion limits, if depth exceeds
792
 *   LW_PARSER_MAX_DEPTH the function frees allocated resources, reports an error, and returns NULL.
793
 * - On failure to parse or to add a component, frees any allocated geometry/collection and returns NULL.
794
 *
795
 * Return:
796
 *   Pointer to a newly constructed LWCOLLECTION on success, or NULL on failure.
797
 */
798
static LWCOLLECTION* lwcollection_from_wkb_state(wkb_parse_state *s)
799
128k
{
800
128k
  uint32_t ngeoms = integer_from_wkb_state(s);
801
128k
  if (s->error)
802
0
    return NULL;
803
128k
  LWCOLLECTION *col = lwcollection_construct_empty(s->lwtype, s->srid, s->has_z, s->has_m);
804
128k
  LWGEOM *geom = NULL;
805
128k
  uint32_t i;
806
128k
  int8_t prev_check = s->check;
807
128k
  uint8_t start_depth = s->depth;
808
809
128k
  LWDEBUGF(4,"Collection has %d components", ngeoms);
810
811
  /* Empty collection? */
812
128k
  if ( ngeoms == 0 )
813
91.0k
  {
814
91.0k
      s->check = prev_check;
815
91.0k
      return col;
816
91.0k
  }
817
818
  /* Be strict in polyhedral surface closures */
819
36.9k
  if ( s->lwtype == POLYHEDRALSURFACETYPE )
820
3.82k
    s->check |= LW_PARSER_CHECK_ZCLOSURE;
821
822
36.9k
  s->depth++;
823
36.9k
  if (s->depth >= LW_PARSER_MAX_DEPTH)
824
3
  {
825
3
    lwcollection_free(col);
826
3
    lwerror("Geometry has too many chained collections");
827
3
    s->check = prev_check;
828
3
    s->depth = start_depth;
829
3
    return NULL;
830
3
  }
831
218k
  for ( i = 0; i < ngeoms; i++ )
832
181k
  {
833
181k
    geom = lwgeom_from_wkb_state(s);
834
181k
    if (!geom || lwcollection_add_lwgeom(col, geom) == NULL )
835
0
    {
836
0
      lwgeom_free(geom);
837
0
      lwgeom_free((LWGEOM *)col);
838
0
      lwerror("Unable to add geometry (%p) to collection (%p)", (void *) geom, (void *) col);
839
0
      s->check = prev_check;
840
0
      s->depth = start_depth;
841
0
      return NULL;
842
0
    }
843
181k
  }
844
36.9k
  s->depth--;
845
36.9k
  s->check = prev_check;
846
847
36.9k
  return col;
848
36.9k
}
849
850
/**
851
 * Parse an ISO/IEC 13249-3:2016 NURBS curve from the current position of a WKB parse state.
852
 *
853
 * Reads the NURBSCURVE components in WKB order: degree, number of control points,
854
 * per-control-point byte-order marker, coordinates (X, Y, optional Z and M), a 1-byte
855
 * weight-present flag and optional weight value, then the knot count and knot values.
856
 * If control-point count is zero an empty POINTARRAY is constructed with the current
857
 * dimensionality. Knot count must be > 0 per the standard.
858
 *
859
 * On error (invalid data, unexpected EOF, invalid weight bit, allocation failure, or
860
 * missing required knots) the function logs an error, frees any partially-allocated
861
 * resources and returns NULL.
862
 *
863
 * Returns a newly-allocated LWNURBSCURVE on success; the caller owns the returned object.
864
 *
865
 * @return Pointer to constructed LWNURBSCURVE, or NULL on failure.
866
 */
867
static LWNURBSCURVE* lwnurbscurve_from_wkb_state(wkb_parse_state *s)
868
27.2k
{
869
27.2k
  uint32_t degree = 0, nknots = 0, npoints = 0, ndims;
870
27.2k
  double *weights = NULL, *knots = NULL;
871
27.2k
  POINTARRAY *points = NULL;
872
27.2k
  int all_weights_one = 1;
873
27.2k
  size_t pa_size, point_payload_size, weights_size, point_tags_size;
874
27.2k
  static const uint32_t MAXPOINTS = (uint32_t)(UINT_MAX / (WKB_DOUBLE_SIZE * 4));
875
876
  /* ISO/IEC 13249-3:2016 compliant parsing */
877
27.2k
  degree = integer_from_wkb_state(s);
878
27.2k
  if (s->error) return NULL;
879
27.2k
  if (degree < 1 || degree > 10)
880
130
  {
881
130
    lwerror("WKB NURBSCURVE: degree %u outside valid range [1,10]", degree);
882
130
    return NULL;
883
130
  }
884
885
  /* Read control points count */
886
27.1k
  npoints = integer_from_wkb_state(s);
887
27.1k
  if (s->error) return NULL;
888
889
  /* Defensive upper bound (worst-case 4 doubles/point) */
890
27.1k
  if (npoints > MAXPOINTS) {
891
26
    lwerror("WKB NURBSCURVE: control point count (%u) too large", npoints);
892
26
    return NULL;
893
26
  }
894
895
27.0k
  if (npoints > 0 && npoints <= degree) {
896
5
    lwerror("WKB NURBSCURVE: degree %u requires at least %llu control points, got %u",
897
5
            degree, (unsigned long long)degree + 1, npoints);
898
5
    return NULL;
899
5
  }
900
27.0k
  const size_t min_point_size = 2 + (2 + (s->has_z ? 1 : 0) + (s->has_m ? 1 : 0)) * WKB_DOUBLE_SIZE;
901
27.0k
  if (!wkb_checked_mul_size((size_t)npoints, min_point_size, &pa_size))
902
0
  {
903
0
    lwerror("WKB NURBSCURVE: control point count (%u) too large", npoints);
904
0
    return NULL;
905
0
  }
906
27.0k
  wkb_parse_state_check(s, pa_size);
907
27.0k
  if (s->error)
908
0
    return NULL;
909
910
  /* Does the data we want to read exist? */
911
27.0k
  ndims = 2 + s->has_z + s->has_m;
912
27.0k
  if (!wkb_checked_mul_size((size_t)npoints, ndims, &point_payload_size) ||
913
26.7k
      !wkb_checked_mul_size(point_payload_size, WKB_DOUBLE_SIZE, &point_payload_size) ||
914
26.7k
      !wkb_checked_mul_size((size_t)npoints, sizeof(double), &weights_size) ||
915
26.7k
      !wkb_checked_mul_size((size_t)npoints, sizeof(char) * 2, &point_tags_size) ||
916
26.7k
      !wkb_checked_add_size(point_payload_size, weights_size, &pa_size) ||
917
26.7k
      !wkb_checked_add_size(pa_size, point_tags_size, &pa_size))
918
0
  {
919
0
    lwerror("WKB NURBSCURVE: control point count (%u) too large", npoints);
920
0
    return NULL;
921
0
  }
922
27.0k
  wkb_parse_state_check(s, pa_size);
923
27.0k
  if (s->error)
924
0
    return NULL;
925
926
  /* Initialize points array */
927
27.0k
  if (npoints > 0) {
928
4.69k
    int8_t save_swap_butes = s->swap_bytes;
929
930
4.69k
    points = ptarray_construct(s->has_z, s->has_m, npoints);
931
4.69k
    weights = lwalloc(sizeof(double) * npoints);
932
933
    /* ISO format: each control point has structure:
934
     * <byte order> <wkbweightedpoint> <bit> [<wkbweight>]
935
     */
936
937
1.28M
    for (uint32_t i = 0; i < npoints; i++) {
938
1.27M
      POINT4D pt = {0, 0, 0, 0};
939
940
      /* Read byte order for this point (ISO requirement) */
941
1.27M
      wkb_swap_bytes(s);
942
943
      /* Read point coordinates */
944
1.27M
      pt.x = double_from_wkb_state(s);
945
1.27M
      if (s->error) {
946
0
        lwfree(weights);
947
0
        ptarray_free(points);
948
0
        return NULL;
949
0
      }
950
951
1.27M
      pt.y = double_from_wkb_state(s);
952
1.27M
      if (s->error) {
953
0
        lwfree(weights);
954
0
        ptarray_free(points);
955
0
        return NULL;
956
0
      }
957
958
1.27M
      if (s->has_z) {
959
417k
        pt.z = double_from_wkb_state(s);
960
417k
        if (s->error) {
961
0
          lwfree(weights);
962
0
          ptarray_free(points);
963
0
          return NULL;
964
0
        }
965
417k
      }
966
967
1.27M
      if (s->has_m) {
968
147k
        pt.m = double_from_wkb_state(s);
969
147k
        if (s->error) {
970
0
          lwfree(weights);
971
0
          ptarray_free(points);
972
0
          return NULL;
973
0
        }
974
147k
      }
975
976
1.27M
      ptarray_set_point4d(points, i, &pt);
977
978
      /* Read weight bit flag */
979
1.27M
      uint8_t has_weight = byte_from_wkb_state(s);
980
1.27M
      if (s->error) {
981
0
        lwfree(weights);
982
0
        ptarray_free(points);
983
0
        return NULL;
984
0
      }
985
986
1.27M
      if (has_weight == 0) {
987
        /* Default weight = 1.0 */
988
1.27M
        weights[i] = 1.0;
989
1.27M
      } else if (has_weight == 1) {
990
        /* Custom weight follows */
991
3.10k
        weights[i] = double_from_wkb_state(s);
992
3.10k
        if (weights[i] <= 0.0) {
993
5
          lwerror("WKB NURBSCURVE: non-positive weight for point %d", i);
994
5
          lwfree(weights);
995
5
          ptarray_free(points);
996
5
          return NULL;
997
5
        }
998
3.10k
        if (s->error) {
999
0
          lwfree(weights);
1000
0
          ptarray_free(points);
1001
0
          return NULL;
1002
0
        }
1003
3.10k
        if (weights[i] != 1.0) all_weights_one = 0;
1004
3.10k
      } else {
1005
105
        lwerror("WKB NURBSCURVE: invalid weight bit %d for point %d (must be 0 or 1)", has_weight, i);
1006
105
        lwfree(weights);
1007
105
        ptarray_free(points);
1008
105
        return NULL;
1009
105
      }
1010
1011
1.27M
    }
1012
    /* Restore original swap state */
1013
4.58k
    s->swap_bytes = save_swap_butes;
1014
4.58k
  }
1015
1016
  /* Read knots (required by WKB standard) */
1017
26.9k
  nknots = integer_from_wkb_state(s);
1018
26.9k
  if (s->error) {
1019
0
    lwfree(weights);
1020
0
    ptarray_free(points);
1021
0
    return NULL;
1022
0
  }
1023
1024
26.9k
  if (npoints == 0)
1025
21.8k
  {
1026
21.8k
    if (nknots != 0)
1027
119
    {
1028
119
      lwerror("WKB NURBSCURVE EMPTY: expected 0 knots, got %u", nknots);
1029
119
      return NULL;
1030
119
    }
1031
21.7k
    return lwnurbscurve_construct_empty(s->srid, s->has_z, s->has_m);
1032
21.8k
  }
1033
1034
5.07k
  if (nknots == 0) {
1035
28
    lwerror("WKB NURBSCURVE: knots required by standard (got 0)");
1036
28
    lwfree(weights);
1037
28
    ptarray_free(points);
1038
28
    return NULL;
1039
28
  }
1040
1041
  /* Validate knot count against B-spline formula */
1042
5.05k
  uint32_t expected_knots = npoints + degree + 1;
1043
5.05k
  if (nknots != expected_knots) {
1044
255
    lwerror("WKB NURBSCURVE: expected %d knots for degree %d and %d points, got %d",
1045
255
            expected_knots, degree, npoints, nknots);
1046
255
    lwfree(weights);
1047
255
    ptarray_free(points);
1048
255
    return NULL;
1049
255
  }
1050
1051
4.79k
  knots = lwalloc(sizeof(double) * nknots);
1052
1.28M
  for (uint32_t i = 0; i < nknots; i++) {
1053
1.27M
    knots[i] = double_from_wkb_state(s);
1054
1.27M
    if (s->error) {
1055
0
      lwfree(weights);
1056
0
      lwfree(knots);
1057
0
      ptarray_free(points);
1058
0
      return NULL;
1059
0
    }
1060
1.27M
  }
1061
1.27M
  for (uint32_t i = 1; i < nknots; i++) {
1062
1.27M
    if (knots[i] < knots[i-1]) {
1063
16
      lwerror("WKB NURBSCURVE: knot vector must be non-decreasing");
1064
16
      lwfree(weights);
1065
16
      lwfree(knots);
1066
16
      ptarray_free(points);
1067
16
      return NULL;
1068
16
    }
1069
1.27M
  }
1070
1071
4.78k
  uint32_t nweights = all_weights_one ? 0U : npoints;
1072
4.78k
  if (all_weights_one) { lwfree(weights); weights = NULL; }
1073
4.78k
  LWNURBSCURVE *curve = lwnurbscurve_construct(s->srid, NULL, degree, points, weights, knots, nweights, nknots);
1074
4.78k
  if (!curve) {
1075
0
    if (weights) lwfree(weights);
1076
0
    if (knots) lwfree(knots);
1077
0
    if (points) ptarray_free(points); /* constructor did not take ownership on failure */
1078
0
    return NULL;
1079
0
  }
1080
4.78k
  if (weights) lwfree(weights);
1081
4.78k
  if (knots) lwfree(knots);
1082
4.78k
  return curve;
1083
4.78k
}
1084
1085
/**
1086
 * Parse a single WKB geometry from the given parse state and return it as an LWGEOM.
1087
 *
1088
 * Reads the leading endian byte, the WKB type (and optional SRID), updates the parse
1089
 * state (including byte-swap flag, detected lwtype and srid), and dispatches to the
1090
 * specific geometry reader for the detected type. On success returns a newly
1091
 * allocated LWGEOM; on error or unsupported type returns NULL and sets s->error.
1092
 *
1093
 * Side effects:
1094
 * - Advances s->pos as data are consumed.
1095
 * - May set s->swap_bytes, s->lwtype, s->srid and s->error.
1096
 *
1097
 * Return:
1098
 *   Pointer to the parsed LWGEOM, or NULL on error or unsupported geometry type.
1099
 */
1100
LWGEOM* lwgeom_from_wkb_state(wkb_parse_state *s)
1101
382k
{
1102
382k
  uint32_t wkb_type;
1103
1104
382k
  LWDEBUG(4,"Entered function");
1105
1106
382k
  wkb_swap_bytes(s);
1107
1108
  /* Read the type number */
1109
382k
  wkb_type = integer_from_wkb_state(s);
1110
382k
  if (s->error)
1111
0
    return NULL;
1112
382k
  LWDEBUGF(4,"Got WKB type number: 0x%X", wkb_type);
1113
382k
  lwtype_from_wkb_state(s, wkb_type);
1114
1115
  /* Read the SRID, if necessary */
1116
382k
  if( s->has_srid )
1117
9.20k
  {
1118
9.20k
    s->srid = clamp_srid(integer_from_wkb_state(s));
1119
9.20k
    if (s->error)
1120
0
      return NULL;
1121
    /* TODO: warn on explicit UNKNOWN srid ? */
1122
9.20k
    LWDEBUGF(4,"Got SRID: %u", s->srid);
1123
9.20k
  }
1124
1125
  /* Do the right thing */
1126
382k
  switch( s->lwtype )
1127
382k
  {
1128
12.0k
    case POINTTYPE:
1129
12.0k
      return (LWGEOM*)lwpoint_from_wkb_state(s);
1130
0
      break;
1131
82.4k
    case LINETYPE:
1132
82.4k
      return (LWGEOM*)lwline_from_wkb_state(s);
1133
0
      break;
1134
95.6k
    case CIRCSTRINGTYPE:
1135
95.6k
      return (LWGEOM*)lwcircstring_from_wkb_state(s);
1136
0
      break;
1137
8.93k
    case POLYGONTYPE:
1138
8.93k
      return (LWGEOM*)lwpoly_from_wkb_state(s);
1139
0
      break;
1140
18.5k
    case TRIANGLETYPE:
1141
18.5k
      return (LWGEOM*)lwtriangle_from_wkb_state(s);
1142
0
      break;
1143
8.46k
    case CURVEPOLYTYPE:
1144
8.46k
      return (LWGEOM*)lwcurvepoly_from_wkb_state(s);
1145
0
      break;
1146
2.56k
    case MULTIPOINTTYPE:
1147
5.82k
    case MULTILINETYPE:
1148
7.42k
    case MULTIPOLYGONTYPE:
1149
86.5k
    case COMPOUNDTYPE:
1150
92.3k
    case MULTICURVETYPE:
1151
93.7k
    case MULTISURFACETYPE:
1152
97.9k
    case POLYHEDRALSURFACETYPE:
1153
101k
    case TINTYPE:
1154
128k
    case COLLECTIONTYPE:
1155
128k
      return (LWGEOM*)lwcollection_from_wkb_state(s);
1156
0
      break;
1157
27.2k
    case NURBSCURVETYPE:
1158
27.2k
      return (LWGEOM*)lwnurbscurve_from_wkb_state(s);
1159
0
      break;
1160
    /* Unknown type! */
1161
0
    default:
1162
0
      lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(s->lwtype));
1163
382k
  }
1164
1165
  /* Return value to keep compiler happy. */
1166
0
  return NULL;
1167
1168
382k
}
1169
1170
/* TODO add check for SRID consistency */
1171
1172
/**
1173
* WKB inputs *must* have a declared size, to prevent malformed WKB from reading
1174
* off the end of the memory segment (this stops a malevolent user from declaring
1175
* a one-ring polygon to have 10 rings, causing the WKB reader to walk off the
1176
* end of the memory).
1177
*
1178
* Check is a bitmask of: LW_PARSER_CHECK_MINPOINTS, LW_PARSER_CHECK_ODD,
1179
* LW_PARSER_CHECK_CLOSURE, LW_PARSER_CHECK_NONE, LW_PARSER_CHECK_ALL
1180
*/
1181
LWGEOM* lwgeom_from_wkb(const uint8_t *wkb, const size_t wkb_size, const char check)
1182
7.97k
{
1183
7.97k
  wkb_parse_state s;
1184
1185
  /* Initialize the state appropriately */
1186
7.97k
  s.wkb = wkb;
1187
7.97k
  s.wkb_size = wkb_size;
1188
7.97k
  s.swap_bytes = LW_FALSE;
1189
7.97k
  s.check = check;
1190
7.97k
  s.lwtype = 0;
1191
7.97k
  s.srid = SRID_UNKNOWN;
1192
7.97k
  s.has_z = LW_FALSE;
1193
7.97k
  s.has_m = LW_FALSE;
1194
7.97k
  s.has_srid = LW_FALSE;
1195
7.97k
  s.error = LW_FALSE;
1196
7.97k
  s.pos = wkb;
1197
7.97k
  s.pos_offset = 0;
1198
7.97k
  s.depth = 1;
1199
1200
7.97k
  if (!wkb || !wkb_size)
1201
0
    return NULL;
1202
1203
7.97k
  return lwgeom_from_wkb_state(&s);
1204
7.97k
}
1205
1206
LWGEOM* lwgeom_from_hexwkb(const char *hexwkb, const char check)
1207
0
{
1208
0
  int hexwkb_len;
1209
0
  uint8_t *wkb;
1210
0
  LWGEOM *lwgeom;
1211
1212
0
  if ( ! hexwkb )
1213
0
  {
1214
0
    lwerror("lwgeom_from_hexwkb: null input");
1215
0
    return NULL;
1216
0
  }
1217
1218
0
  hexwkb_len = strlen(hexwkb);
1219
0
  wkb = bytes_from_hexbytes(hexwkb, hexwkb_len);
1220
0
  lwgeom = lwgeom_from_wkb(wkb, hexwkb_len/2, check);
1221
0
  lwfree(wkb);
1222
0
  return lwgeom;
1223
0
}