Coverage Report

Created: 2026-10-10 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgis/liblwgeom/lwin_twkb.c
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * PostGIS - Spatial Types for PostgreSQL
4
 * http://postgis.net
5
 * Copyright (C) 2026 Darafei Praliaskouski <me@komzpa.net>
6
 *
7
 * PostGIS is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation, either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * PostGIS is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with PostGIS.  If not, see <http://www.gnu.org/licenses/>.
19
 *
20
 **********************************************************************
21
 *
22
 * Copyright (C) 2014 Nicklas Avén
23
 *
24
 **********************************************************************/
25
26
#include <math.h>
27
#include <limits.h>
28
#include <string.h>
29
#include "liblwgeom_internal.h"
30
#include "lwgeom_log.h"
31
#include "varint.h"
32
33
176k
#define TWKB_IN_MAXCOORDS 4
34
/** Max depth in a geometry. Matches the WKB parser recursion limit. */
35
6.28k
#define LW_PARSER_MAX_DEPTH 200
36
37
/**
38
* Used for passing the parse state between the parsing functions.
39
*/
40
typedef struct
41
{
42
  /* Pointers to the bytes */
43
  const uint8_t *twkb; /* Points to start of TWKB */
44
  const uint8_t *twkb_end; /* Points to end of TWKB */
45
  const uint8_t *pos; /* Current read position */
46
47
  uint32_t check; /* Simple validity checks on geometries */
48
  uint32_t lwtype; /* Current type we are handling */
49
  uint8_t depth;   /* Current recursion level, to prevent stack overflows */
50
51
  uint8_t has_bbox;
52
  uint8_t has_size;
53
  uint8_t has_idlist;
54
  uint8_t has_z;
55
  uint8_t has_m;
56
  uint8_t is_empty;
57
  uint8_t error;
58
59
  /* Precision factors to convert ints to double */
60
  double factor;
61
  double factor_z;
62
  double factor_m;
63
64
  uint64_t size;
65
66
  /* Info about current geometry */
67
  uint8_t magic_byte; /* the magic byte contain info about if twkb contain id, size info, bboxes and precision */
68
69
  int ndims; /* Number of dimensions */
70
71
  int64_t *coords; /* An array to keep delta values from 4 dimensions */
72
73
} twkb_parse_state;
74
75
76
/**
77
* Internal function declarations.
78
*/
79
LWGEOM* lwgeom_from_twkb_state(twkb_parse_state *s);
80
81
82
/**********************************************************************/
83
84
/**
85
* Check that we are not about to read off the end of the WKB
86
* array.
87
*/
88
static inline void twkb_parse_state_advance(twkb_parse_state *s, size_t next)
89
1.72M
{
90
1.72M
  size_t remaining = (s->pos <= s->twkb_end) ? (size_t)(s->twkb_end - s->pos) : 0;
91
92
1.72M
  if (next > remaining)
93
93
  {
94
93
    s->error = LW_TRUE;
95
93
    lwerror("%s: TWKB structure does not match expected size!", __func__);
96
93
    s->pos = s->twkb_end;
97
93
    return;
98
93
  }
99
100
1.72M
  s->pos += next;
101
1.72M
}
102
103
static inline int64_t twkb_parse_state_varint(twkb_parse_state *s)
104
833k
{
105
833k
  size_t size;
106
833k
  int64_t val = varint_s64_decode(s->pos, s->twkb_end, &size);
107
833k
  if (size == 0)
108
0
    s->error = LW_TRUE;
109
833k
  twkb_parse_state_advance(s, size);
110
833k
  return val;
111
833k
}
112
113
static inline uint64_t twkb_parse_state_uvarint(twkb_parse_state *s)
114
304k
{
115
304k
  size_t size;
116
304k
  uint64_t val = varint_u64_decode(s->pos, s->twkb_end, &size);
117
304k
  if (size == 0)
118
0
    s->error = LW_TRUE;
119
304k
  twkb_parse_state_advance(s, size);
120
304k
  return val;
121
304k
}
122
123
static inline double twkb_parse_state_double(twkb_parse_state *s, double factor)
124
21.1k
{
125
21.1k
  size_t size;
126
21.1k
  int64_t val = varint_s64_decode(s->pos, s->twkb_end, &size);
127
21.1k
  if (size == 0)
128
0
    s->error = LW_TRUE;
129
21.1k
  twkb_parse_state_advance(s, size);
130
21.1k
  return val / factor;
131
21.1k
}
132
133
static inline void twkb_parse_state_varint_skip(twkb_parse_state *s)
134
494k
{
135
494k
  size_t size = varint_size(s->pos, s->twkb_end);
136
137
494k
  if ( ! size )
138
186
  {
139
186
    s->error = LW_TRUE;
140
186
    lwerror("%s: no varint to skip", __func__);
141
186
  }
142
143
494k
  twkb_parse_state_advance(s, size);
144
494k
  return;
145
494k
}
146
147
static inline uint32_t
148
twkb_parse_state_uvarint32(twkb_parse_state *s)
149
303k
{
150
303k
  uint64_t val = twkb_parse_state_uvarint(s);
151
152
303k
  if (val > UINT32_MAX)
153
543
  {
154
543
    s->error = LW_TRUE;
155
543
    lwerror("%s: TWKB count exceeds uint32_t", __func__);
156
543
    return 0;
157
543
  }
158
159
302k
  return (uint32_t)val;
160
303k
}
161
162
static inline int
163
twkb_parse_state_has_min_bytes(twkb_parse_state *s, uint32_t count, size_t min_bytes)
164
211k
{
165
211k
  const size_t remaining = (size_t)(s->twkb_end - s->pos);
166
167
  /* TWKB counts are trusted only after proving that the remaining buffer can
168
   * hold the smallest possible payload for that many elements. This rejects
169
   * impossible allocation requests before constructors size their arrays.
170
   */
171
211k
  if (min_bytes != 0 && count > remaining / min_bytes)
172
746
  {
173
746
    s->error = LW_TRUE;
174
746
    lwerror("%s: TWKB element count exceeds remaining payload", __func__);
175
746
    return LW_FALSE;
176
746
  }
177
178
210k
  return LW_TRUE;
179
211k
}
180
181
/** Implements *pa += b using explicit wraparound semantics. */
182
#if defined(__clang__) && __clang_major__ >= 4
183
__attribute__((no_sanitize("unsigned-integer-overflow")))
184
#endif
185
static inline void
186
safe_add_int64(int64_t *pa, int64_t b)
187
833k
{
188
833k
  uint64_t u_a = (uint64_t)*pa;
189
833k
  uint64_t u_b = (uint64_t)b;
190
833k
  u_a += u_b;
191
833k
  memcpy(pa, &u_a, sizeof(int64_t));
192
833k
}
193
194
static inline void
195
twkb_parse_state_accum_coord(twkb_parse_state *s, int coord_index)
196
833k
{
197
833k
  safe_add_int64(&s->coords[coord_index], twkb_parse_state_varint(s));
198
833k
}
199
200
static uint32_t lwtype_from_twkb_type(uint8_t twkb_type)
201
35.3k
{
202
35.3k
  switch (twkb_type)
203
35.3k
  {
204
13.9k
    case 1:
205
13.9k
      return POINTTYPE;
206
1.20k
    case 2:
207
1.20k
      return LINETYPE;
208
1.12k
    case 3:
209
1.12k
      return POLYGONTYPE;
210
7.25k
    case 4:
211
7.25k
      return MULTIPOINTTYPE;
212
1.78k
    case 5:
213
1.78k
      return MULTILINETYPE;
214
2.46k
    case 6:
215
2.46k
      return MULTIPOLYGONTYPE;
216
7.48k
    case 7:
217
7.48k
      return COLLECTIONTYPE;
218
219
39
    default: /* Error! */
220
39
      lwerror("Unknown WKB type");
221
39
      return 0;
222
35.3k
  }
223
0
  return 0;
224
35.3k
}
225
226
/**
227
* Byte
228
* Read a byte and advance the parse state forward.
229
*/
230
static uint8_t byte_from_twkb_state(twkb_parse_state *s)
231
71.8k
{
232
71.8k
  uint8_t val = 0;
233
234
  /* CUnit records lwerror and continues, while PostgreSQL and the fuzzers
235
   * abort through their error handlers. Keep the bounds check local so this
236
   * byte helper is safe under both execution models.
237
   */
238
71.8k
  if ((s->twkb_end - s->pos) >= WKB_BYTE_SIZE)
239
71.8k
    val = *(s->pos);
240
71.8k
  twkb_parse_state_advance(s, WKB_BYTE_SIZE);
241
71.8k
  return val;
242
71.8k
}
243
244
245
/**
246
* POINTARRAY
247
* Read a dynamically sized point array and advance the parse state forward.
248
*/
249
static POINTARRAY* ptarray_from_twkb_state(twkb_parse_state *s, uint32_t npoints)
250
197k
{
251
197k
  POINTARRAY *pa = NULL;
252
197k
  uint32_t ndims = s->ndims;
253
197k
  uint32_t i;
254
197k
  uint32_t j;
255
197k
  double *dlist;
256
197k
  double factors[TWKB_IN_MAXCOORDS];
257
258
197k
  LWDEBUG(2,"Entering ptarray_from_twkb_state");
259
197k
  LWDEBUGF(4,"Pointarray has %d points", npoints);
260
261
  /* Empty! */
262
197k
  if( npoints == 0 )
263
30
    return ptarray_construct_empty(s->has_z, s->has_m, 0);
264
265
197k
  if (!twkb_parse_state_has_min_bytes(s, npoints, s->ndims))
266
0
    return NULL;
267
268
197k
  factors[0] = s->factor;
269
197k
  factors[1] = s->factor;
270
197k
  j = 2;
271
197k
  if (s->has_z)
272
940
    factors[j++] = s->factor_z;
273
197k
  if (s->has_m)
274
1.16k
    factors[j++] = s->factor_m;
275
276
197k
  pa = ptarray_construct(s->has_z, s->has_m, npoints);
277
197k
  dlist = (double*)(pa->serialized_pointlist);
278
607k
  for( i = 0; i < npoints; i++ )
279
409k
  {
280
1.24M
    for (j = 0; j < ndims; j++)
281
833k
    {
282
833k
      twkb_parse_state_accum_coord(s, j);
283
833k
      dlist[ndims * i + j] = s->coords[j] / factors[j];
284
833k
    }
285
409k
  }
286
287
197k
  return pa;
288
197k
}
289
290
/**
291
* POINT
292
*/
293
static LWPOINT* lwpoint_from_twkb_state(twkb_parse_state *s)
294
172k
{
295
172k
  static uint32_t npoints = 1;
296
172k
  POINTARRAY *pa;
297
298
172k
  LWDEBUG(2,"Entering lwpoint_from_twkb_state");
299
300
172k
  if ( s->is_empty )
301
13.4k
    return lwpoint_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m);
302
303
158k
  pa = ptarray_from_twkb_state(s, npoints);
304
158k
  return lwpoint_construct(SRID_UNKNOWN, NULL, pa);
305
172k
}
306
307
/**
308
* LINESTRING
309
*/
310
static LWLINE* lwline_from_twkb_state(twkb_parse_state *s)
311
184k
{
312
184k
  uint32_t npoints;
313
184k
  POINTARRAY *pa;
314
315
184k
  LWDEBUG(2,"Entering lwline_from_twkb_state");
316
317
184k
  if ( s->is_empty )
318
718
    return lwline_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m);
319
320
  /* Read number of points */
321
183k
  npoints = twkb_parse_state_uvarint32(s);
322
323
183k
  if ( npoints == 0 )
324
182k
    return lwline_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m);
325
326
  /* Read coordinates */
327
1.07k
  pa = ptarray_from_twkb_state(s, npoints);
328
329
1.07k
  if (pa == NULL)
330
0
    return lwline_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m);
331
332
1.07k
  if( s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 2 )
333
0
  {
334
0
    lwerror("%s must have at least two points", lwtype_name(s->lwtype));
335
0
    return NULL;
336
0
  }
337
338
1.07k
  return lwline_construct(SRID_UNKNOWN, NULL, pa);
339
1.07k
}
340
341
/**
342
* POLYGON
343
*/
344
static LWPOLY* lwpoly_from_twkb_state(twkb_parse_state *s)
345
71.1k
{
346
71.1k
  uint32_t nrings;
347
71.1k
  uint32_t i;
348
71.1k
  LWPOLY *poly;
349
350
71.1k
  LWDEBUG(2,"Entering lwpoly_from_twkb_state");
351
352
71.1k
  if ( s->is_empty )
353
503
    return lwpoly_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m);
354
355
  /* Read number of rings */
356
70.6k
  nrings = twkb_parse_state_uvarint32(s);
357
358
  /* Start w/ empty polygon */
359
70.6k
  poly = lwpoly_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m);
360
361
70.6k
  LWDEBUGF(4,"Polygon has %d rings", nrings);
362
363
  /* Empty polygon? */
364
70.6k
  if( nrings == 0 )
365
68.9k
    return poly;
366
367
1.63k
  if (!twkb_parse_state_has_min_bytes(s, nrings, 1))
368
0
    return poly;
369
370
40.1k
  for( i = 0; i < nrings; i++ )
371
38.5k
  {
372
    /* Ret number of points */
373
38.5k
    uint32_t npoints = twkb_parse_state_uvarint32(s);
374
38.5k
    POINTARRAY *pa = ptarray_from_twkb_state(s, npoints);
375
376
    /* Skip empty rings */
377
38.5k
    if (pa == NULL)
378
0
      continue;
379
380
    /* Force first and last points to be the same. */
381
38.5k
    if( ! ptarray_is_closed_2d(pa) )
382
3.00k
    {
383
3.00k
      POINT4D pt;
384
3.00k
      getPoint4d_p(pa, 0, &pt);
385
3.00k
      ptarray_append_point(pa, &pt, LW_FALSE);
386
3.00k
    }
387
388
    /* Check for at least four points. */
389
38.5k
    if( s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 4 )
390
0
    {
391
0
      LWDEBUGF(2, "%s must have at least four points in each ring", lwtype_name(s->lwtype));
392
0
      lwerror("%s must have at least four points in each ring", lwtype_name(s->lwtype));
393
0
      return NULL;
394
0
    }
395
396
    /* Add ring to polygon */
397
38.5k
    if ( lwpoly_add_ring(poly, pa) == LW_FAILURE )
398
0
    {
399
0
      LWDEBUG(2, "Unable to add ring to polygon");
400
0
      lwerror("Unable to add ring to polygon");
401
0
    }
402
403
38.5k
  }
404
1.63k
  return poly;
405
1.63k
}
406
407
408
/**
409
* MULTIPOINT
410
*/
411
static LWCOLLECTION* lwmultipoint_from_twkb_state(twkb_parse_state *s)
412
7.24k
{
413
7.24k
  uint32_t ngeoms, i;
414
7.24k
  LWGEOM *geom = NULL;
415
7.24k
  LWCOLLECTION *col = lwcollection_construct_empty(s->lwtype, SRID_UNKNOWN, s->has_z, s->has_m);
416
417
7.24k
  LWDEBUG(2,"Entering lwmultipoint_from_twkb_state");
418
419
7.24k
  if ( s->is_empty )
420
5.99k
    return col;
421
422
  /* Read number of geometries */
423
1.24k
  ngeoms = twkb_parse_state_uvarint32(s);
424
1.24k
  LWDEBUGF(4,"Number of geometries %d", ngeoms);
425
426
1.24k
  if (s->has_idlist && !twkb_parse_state_has_min_bytes(s, ngeoms, 1))
427
0
    return col;
428
429
  /* It has an idlist, we need to skip that */
430
1.24k
  if ( s->has_idlist )
431
525
  {
432
130k
    for ( i = 0; i < ngeoms; i++ )
433
130k
      twkb_parse_state_varint_skip(s);
434
525
  }
435
436
1.24k
  if (!twkb_parse_state_has_min_bytes(s, ngeoms, s->ndims))
437
0
    return col;
438
439
159k
  for ( i = 0; i < ngeoms; i++ )
440
158k
  {
441
158k
    geom = lwpoint_as_lwgeom(lwpoint_from_twkb_state(s));
442
158k
    if ( lwcollection_add_lwgeom(col, geom) == NULL )
443
0
    {
444
0
      lwerror("Unable to add geometry (%p) to collection (%p)", (void *) geom, (void *) col);
445
0
      return NULL;
446
0
    }
447
158k
  }
448
449
1.24k
  return col;
450
1.24k
}
451
452
/**
453
* MULTILINESTRING
454
*/
455
static LWCOLLECTION* lwmultiline_from_twkb_state(twkb_parse_state *s)
456
1.76k
{
457
1.76k
  uint32_t ngeoms, i;
458
1.76k
  LWGEOM *geom = NULL;
459
1.76k
  LWCOLLECTION *col = lwcollection_construct_empty(s->lwtype, SRID_UNKNOWN, s->has_z, s->has_m);
460
461
1.76k
  LWDEBUG(2,"Entering lwmultilinestring_from_twkb_state");
462
463
1.76k
  if ( s->is_empty )
464
564
    return col;
465
466
  /* Read number of geometries */
467
1.20k
  ngeoms = twkb_parse_state_uvarint32(s);
468
469
1.20k
  LWDEBUGF(4,"Number of geometries %d",ngeoms);
470
471
1.20k
  if (s->has_idlist && !twkb_parse_state_has_min_bytes(s, ngeoms, 1))
472
0
    return col;
473
474
  /* It has an idlist, we need to skip that */
475
1.20k
  if ( s->has_idlist )
476
481
  {
477
111k
    for ( i = 0; i < ngeoms; i++ )
478
110k
      twkb_parse_state_varint_skip(s);
479
481
  }
480
481
1.20k
  if (!twkb_parse_state_has_min_bytes(s, ngeoms, 1))
482
0
    return col;
483
484
184k
  for ( i = 0; i < ngeoms; i++ )
485
183k
  {
486
183k
    geom = lwline_as_lwgeom(lwline_from_twkb_state(s));
487
183k
    if ( lwcollection_add_lwgeom(col, geom) == NULL )
488
0
    {
489
0
      lwerror("Unable to add geometry (%p) to collection (%p)", (void *) geom, (void *) col);
490
0
      return NULL;
491
0
    }
492
183k
  }
493
494
1.20k
  return col;
495
1.20k
}
496
497
/**
498
* MULTIPOLYGON
499
*/
500
static LWCOLLECTION* lwmultipoly_from_twkb_state(twkb_parse_state *s)
501
2.45k
{
502
2.45k
  uint32_t ngeoms, i;
503
2.45k
  LWGEOM *geom = NULL;
504
2.45k
  LWCOLLECTION *col = lwcollection_construct_empty(s->lwtype, SRID_UNKNOWN, s->has_z, s->has_m);
505
506
2.45k
  LWDEBUG(2,"Entering lwmultipolygon_from_twkb_state");
507
508
2.45k
  if ( s->is_empty )
509
915
    return col;
510
511
  /* Read number of geometries */
512
1.54k
  ngeoms = twkb_parse_state_uvarint32(s);
513
1.54k
  LWDEBUGF(4,"Number of geometries %d",ngeoms);
514
515
1.54k
  if (s->has_idlist && !twkb_parse_state_has_min_bytes(s, ngeoms, 1))
516
0
    return col;
517
518
  /* It has an idlist, we need to skip that */
519
1.54k
  if ( s->has_idlist )
520
516
  {
521
111k
    for ( i = 0; i < ngeoms; i++ )
522
110k
      twkb_parse_state_varint_skip(s);
523
516
  }
524
525
1.54k
  if (!twkb_parse_state_has_min_bytes(s, ngeoms, 1))
526
0
    return col;
527
528
71.5k
  for ( i = 0; i < ngeoms; i++ )
529
70.0k
  {
530
70.0k
    geom = lwpoly_as_lwgeom(lwpoly_from_twkb_state(s));
531
70.0k
    if ( lwcollection_add_lwgeom(col, geom) == NULL )
532
0
    {
533
0
      lwerror("Unable to add geometry (%p) to collection (%p)", (void *) geom, (void *) col);
534
0
      return NULL;
535
0
    }
536
70.0k
  }
537
538
1.54k
  return col;
539
1.54k
}
540
541
542
/**
543
* COLLECTION, MULTIPOINTTYPE, MULTILINETYPE, MULTIPOLYGONTYPE
544
**/
545
static LWCOLLECTION* lwcollection_from_twkb_state(twkb_parse_state *s)
546
7.45k
{
547
7.45k
  uint32_t ngeoms, i;
548
7.45k
  LWGEOM *geom = NULL;
549
7.45k
  LWCOLLECTION *col = lwcollection_construct_empty(s->lwtype, SRID_UNKNOWN, s->has_z, s->has_m);
550
7.45k
  uint8_t start_depth = s->depth;
551
552
7.45k
  LWDEBUG(2,"Entering lwcollection_from_twkb_state");
553
554
7.45k
  if ( s->is_empty )
555
1.17k
    return col;
556
557
  /* Read number of geometries */
558
6.28k
  ngeoms = twkb_parse_state_uvarint32(s);
559
560
6.28k
  LWDEBUGF(4,"Number of geometries %d",ngeoms);
561
562
6.28k
  if (s->has_idlist && !twkb_parse_state_has_min_bytes(s, ngeoms, 1))
563
0
    return col;
564
565
  /* It has an idlist, we need to skip that */
566
6.28k
  if ( s->has_idlist )
567
988
  {
568
143k
    for ( i = 0; i < ngeoms; i++ )
569
142k
      twkb_parse_state_varint_skip(s);
570
988
  }
571
572
6.28k
  if (!twkb_parse_state_has_min_bytes(s, ngeoms, 2))
573
0
    return col;
574
575
6.28k
  s->depth++;
576
6.28k
  if (s->depth >= LW_PARSER_MAX_DEPTH)
577
3
  {
578
3
    lwcollection_free(col);
579
3
    lwerror("Geometry has too many chained collections");
580
3
    s->depth = start_depth;
581
3
    return NULL;
582
3
  }
583
584
39.0k
  for ( i = 0; i < ngeoms; i++ )
585
32.7k
  {
586
32.7k
    geom = lwgeom_from_twkb_state(s);
587
32.7k
    if (!geom || lwcollection_add_lwgeom(col, geom) == NULL)
588
0
    {
589
0
      lwgeom_free(geom);
590
0
      lwcollection_free(col);
591
0
      s->depth = start_depth;
592
0
      return NULL;
593
0
    }
594
32.7k
  }
595
596
6.28k
  s->depth--;
597
598
6.28k
  return col;
599
6.28k
}
600
601
602
static void header_from_twkb_state(twkb_parse_state *s)
603
35.3k
{
604
35.3k
  LWDEBUG(2,"Entering magicbyte_from_twkb_state");
605
606
35.3k
  uint8_t extended_dims;
607
608
  /* Read the first two bytes */
609
35.3k
  uint8_t type_precision = byte_from_twkb_state(s);
610
35.3k
  uint8_t metadata = byte_from_twkb_state(s);
611
612
  /* Strip type and precision out of first byte */
613
35.3k
  uint8_t type = type_precision & 0x0F;
614
35.3k
  int8_t precision = unzigzag8((type_precision & 0xF0) >> 4);
615
616
  /* Convert TWKB type to internal type */
617
35.3k
  s->lwtype = lwtype_from_twkb_type(type);
618
619
  /* Convert the precision into factor */
620
35.3k
  s->factor = pow(10, (double)precision);
621
622
  /* Strip metadata flags out of second byte */
623
35.3k
  s->has_bbox   =  metadata & 0x01;
624
35.3k
  s->has_size   = (metadata & 0x02) >> 1;
625
35.3k
  s->has_idlist = (metadata & 0x04) >> 2;
626
35.3k
  extended_dims = (metadata & 0x08) >> 3;
627
35.3k
  s->is_empty   = (metadata & 0x10) >> 4;
628
629
  /* Flag for higher dims means read a third byte */
630
35.3k
  if ( extended_dims )
631
1.19k
  {
632
1.19k
    int8_t precision_z, precision_m;
633
634
1.19k
    extended_dims = byte_from_twkb_state(s);
635
636
    /* Strip Z/M presence and precision from ext byte */
637
1.19k
    s->has_z    = (extended_dims & 0x01);
638
1.19k
    s->has_m    = (extended_dims & 0x02) >> 1;
639
1.19k
    precision_z = (extended_dims & 0x1C) >> 2;
640
1.19k
    precision_m = (extended_dims & 0xE0) >> 5;
641
642
    /* Convert the precision into factor */
643
1.19k
    s->factor_z = pow(10, (double)precision_z);
644
1.19k
    s->factor_m = pow(10, (double)precision_m);
645
1.19k
  }
646
34.1k
  else
647
34.1k
  {
648
34.1k
    s->has_z = 0;
649
34.1k
    s->has_m = 0;
650
34.1k
    s->factor_z = 0;
651
34.1k
    s->factor_m = 0;
652
34.1k
  }
653
654
  /* Read the size, if there is one */
655
35.3k
  if ( s->has_size )
656
1.53k
  {
657
1.53k
    s->size = twkb_parse_state_uvarint(s);
658
1.53k
  }
659
660
  /* Calculate the number of dimensions */
661
35.3k
  s->ndims = 2 + s->has_z + s->has_m;
662
663
35.3k
  return;
664
35.3k
}
665
666
667
668
/**
669
* Generic handling for TWKB geometries. The front of every TWKB geometry
670
* (including those embedded in collections) is a type byte and metadata byte,
671
* then optional size, bbox, etc. Read those, then switch to particular type
672
* handling code.
673
*/
674
LWGEOM* lwgeom_from_twkb_state(twkb_parse_state *s)
675
35.3k
{
676
35.3k
  GBOX bbox;
677
35.3k
  LWGEOM *geom = NULL;
678
35.3k
  uint32_t has_bbox = LW_FALSE;
679
35.3k
  int i;
680
681
  /* Read the first two bytes, and optional */
682
  /* extended precision info and optional size info */
683
35.3k
  header_from_twkb_state(s);
684
685
  /* Just experienced a geometry header, so now we */
686
  /* need to reset our coordinate deltas */
687
176k
  for ( i = 0; i < TWKB_IN_MAXCOORDS; i++ )
688
141k
  {
689
141k
    s->coords[i] = 0.0;
690
141k
  }
691
692
  /* Read the bounding box, is there is one */
693
35.3k
  if ( s->has_bbox )
694
4.89k
  {
695
    /* Initialize */
696
4.89k
    has_bbox = s->has_bbox;
697
4.89k
    memset(&bbox, 0, sizeof(GBOX));
698
4.89k
    bbox.flags = lwflags(s->has_z, s->has_m, 0);
699
700
    /* X */
701
4.89k
    bbox.xmin = twkb_parse_state_double(s, s->factor);
702
4.89k
    bbox.xmax = bbox.xmin + twkb_parse_state_double(s, s->factor);
703
    /* Y */
704
4.89k
    bbox.ymin = twkb_parse_state_double(s, s->factor);
705
4.89k
    bbox.ymax = bbox.ymin + twkb_parse_state_double(s, s->factor);
706
    /* Z */
707
4.89k
    if ( s->has_z )
708
325
    {
709
325
      bbox.zmin = twkb_parse_state_double(s, s->factor_z);
710
325
      bbox.zmax = bbox.zmin + twkb_parse_state_double(s, s->factor_z);
711
325
    }
712
    /* M */
713
4.89k
    if ( s->has_m )
714
553
    {
715
553
      bbox.mmin = twkb_parse_state_double(s, s->factor_m);
716
553
      bbox.mmax = bbox.mmin + twkb_parse_state_double(s, s->factor_m);
717
553
    }
718
4.89k
  }
719
720
  /* Switch to code for the particular type we're dealing with */
721
35.3k
  switch( s->lwtype )
722
35.3k
  {
723
13.9k
    case POINTTYPE:
724
13.9k
      geom = lwpoint_as_lwgeom(lwpoint_from_twkb_state(s));
725
13.9k
      break;
726
1.19k
    case LINETYPE:
727
1.19k
      geom = lwline_as_lwgeom(lwline_from_twkb_state(s));
728
1.19k
      break;
729
1.11k
    case POLYGONTYPE:
730
1.11k
      geom = lwpoly_as_lwgeom(lwpoly_from_twkb_state(s));
731
1.11k
      break;
732
7.24k
    case MULTIPOINTTYPE:
733
7.24k
      geom = lwcollection_as_lwgeom(lwmultipoint_from_twkb_state(s));
734
7.24k
      break;
735
1.76k
    case MULTILINETYPE:
736
1.76k
      geom = lwcollection_as_lwgeom(lwmultiline_from_twkb_state(s));
737
1.76k
      break;
738
2.45k
    case MULTIPOLYGONTYPE:
739
2.45k
      geom = lwcollection_as_lwgeom(lwmultipoly_from_twkb_state(s));
740
2.45k
      break;
741
7.45k
    case COLLECTIONTYPE:
742
7.45k
      geom = lwcollection_as_lwgeom(lwcollection_from_twkb_state(s));
743
7.45k
      break;
744
    /* Unknown type! */
745
0
    default:
746
0
      s->error = LW_TRUE;
747
0
      lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(s->lwtype));
748
0
      break;
749
35.3k
  }
750
751
29.4k
  if (s->error)
752
0
  {
753
0
    lwgeom_free(geom);
754
0
    return NULL;
755
0
  }
756
757
29.4k
  if (has_bbox && geom)
758
4.19k
    geom->bbox = gbox_clone(&bbox);
759
760
29.4k
  return geom;
761
29.4k
}
762
763
764
/**
765
* WKB inputs *must* have a declared size, to prevent malformed WKB from reading
766
* off the end of the memory segment (this stops a malevolent user from declaring
767
* a one-ring polygon to have 10 rings, causing the WKB reader to walk off the
768
* end of the memory).
769
*
770
* Check is a bitmask of: LW_PARSER_CHECK_MINPOINTS, LW_PARSER_CHECK_ODD,
771
* LW_PARSER_CHECK_CLOSURE, LW_PARSER_CHECK_NONE, LW_PARSER_CHECK_ALL
772
*/
773
LWGEOM* lwgeom_from_twkb(const uint8_t *twkb, size_t twkb_size, char check)
774
2.62k
{
775
2.62k
  int64_t coords[TWKB_IN_MAXCOORDS] = {0, 0, 0, 0};
776
2.62k
  twkb_parse_state s;
777
778
2.62k
  LWDEBUG(2,"Entering lwgeom_from_twkb");
779
2.62k
  LWDEBUGF(4,"twkb_size: %d",(int) twkb_size);
780
781
  /* Zero out the state */
782
2.62k
  memset(&s, 0, sizeof(twkb_parse_state));
783
784
  /* Initialize the state appropriately */
785
2.62k
  s.twkb = s.pos = twkb;
786
2.62k
  s.twkb_end = twkb + twkb_size;
787
2.62k
  s.check = check;
788
2.62k
  s.coords = coords;
789
790
  /* Read the rest of the geometry */
791
2.62k
  return lwgeom_from_twkb_state(&s);
792
2.62k
}