PostGIS  2.5.1dev-r@@SVN_REVISION@@
lwin_twkb.c
Go to the documentation of this file.
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) 2014 Nicklas Avén
22  *
23  **********************************************************************/
24 
25 
26 #include <math.h>
27 #include "liblwgeom_internal.h"
28 #include "lwgeom_log.h"
29 #include "varint.h"
30 
31 #define TWKB_IN_MAXCOORDS 4
32 
36 typedef struct
37 {
38  /* Pointers to the bytes */
39  const uint8_t *twkb; /* Points to start of TWKB */
40  const uint8_t *twkb_end; /* Points to end of TWKB */
41  const uint8_t *pos; /* Current read position */
42 
43  uint32_t check; /* Simple validity checks on geometries */
44  uint32_t lwtype; /* Current type we are handling */
45 
52 
53  /* Precision factors to convert ints to double */
54  double factor;
55  double factor_z;
56  double factor_m;
57 
58  uint64_t size;
59 
60  /* Info about current geometry */
61  uint8_t magic_byte; /* the magic byte contain info about if twkb contain id, size info, bboxes and precision */
62 
63  int ndims; /* Number of dimensions */
64 
65  int64_t *coords; /* An array to keep delta values from 4 dimensions */
66 
68 
69 
74 
75 
76 /**********************************************************************/
77 
82 static inline void twkb_parse_state_advance(twkb_parse_state *s, size_t next)
83 {
84  if( (s->pos + next) > s->twkb_end)
85  {
86  lwerror("%s: TWKB structure does not match expected size!", __func__);
87  // lwnotice("TWKB structure does not match expected size!");
88  }
89 
90  s->pos += next;
91 }
92 
94 {
95  size_t size;
96  int64_t val = varint_s64_decode(s->pos, s->twkb_end, &size);
97  twkb_parse_state_advance(s, size);
98  return val;
99 }
100 
102 {
103  size_t size;
104  uint64_t val = varint_u64_decode(s->pos, s->twkb_end, &size);
105  twkb_parse_state_advance(s, size);
106  return val;
107 }
108 
109 static inline double twkb_parse_state_double(twkb_parse_state *s, double factor)
110 {
111  size_t size;
112  int64_t val = varint_s64_decode(s->pos, s->twkb_end, &size);
113  twkb_parse_state_advance(s, size);
114  return val / factor;
115 }
116 
118 {
119  size_t size = varint_size(s->pos, s->twkb_end);
120 
121  if ( ! size )
122  lwerror("%s: no varint to skip", __func__);
123 
124  twkb_parse_state_advance(s, size);
125  return;
126 }
127 
128 
129 
131 {
132  switch (twkb_type)
133  {
134  case 1:
135  return POINTTYPE;
136  case 2:
137  return LINETYPE;
138  case 3:
139  return POLYGONTYPE;
140  case 4:
141  return MULTIPOINTTYPE;
142  case 5:
143  return MULTILINETYPE;
144  case 6:
145  return MULTIPOLYGONTYPE;
146  case 7:
147  return COLLECTIONTYPE;
148 
149  default: /* Error! */
150  lwerror("Unknown WKB type");
151  return 0;
152  }
153  return 0;
154 }
155 
161 {
162  uint8_t val = *(s->pos);
164  return val;
165 }
166 
167 
173 {
174  POINTARRAY *pa = NULL;
175  uint32_t ndims = s->ndims;
176  uint32_t i;
177  double *dlist;
178 
179  LWDEBUG(2,"Entering ptarray_from_twkb_state");
180  LWDEBUGF(4,"Pointarray has %d points", npoints);
181 
182  /* Empty! */
183  if( npoints == 0 )
184  return ptarray_construct_empty(s->has_z, s->has_m, 0);
185 
186  pa = ptarray_construct(s->has_z, s->has_m, npoints);
187  dlist = (double*)(pa->serialized_pointlist);
188  for( i = 0; i < npoints; i++ )
189  {
190  int j = 0;
191  /* X */
192  s->coords[j] += twkb_parse_state_varint(s);
193  dlist[ndims*i + j] = s->coords[j] / s->factor;
194  j++;
195  /* Y */
196  s->coords[j] += twkb_parse_state_varint(s);
197  dlist[ndims*i + j] = s->coords[j] / s->factor;
198  j++;
199  /* Z */
200  if ( s->has_z )
201  {
202  s->coords[j] += twkb_parse_state_varint(s);
203  dlist[ndims*i + j] = s->coords[j] / s->factor_z;
204  j++;
205  }
206  /* M */
207  if ( s->has_m )
208  {
209  s->coords[j] += twkb_parse_state_varint(s);
210  dlist[ndims*i + j] = s->coords[j] / s->factor_m;
211  j++;
212  }
213  }
214 
215  return pa;
216 }
217 
222 {
223  static uint32_t npoints = 1;
224  POINTARRAY *pa;
225 
226  LWDEBUG(2,"Entering lwpoint_from_twkb_state");
227 
228  if ( s->is_empty )
230 
231  pa = ptarray_from_twkb_state(s, npoints);
232  return lwpoint_construct(SRID_UNKNOWN, NULL, pa);
233 }
234 
239 {
240  uint32_t npoints;
241  POINTARRAY *pa;
242 
243  LWDEBUG(2,"Entering lwline_from_twkb_state");
244 
245  if ( s->is_empty )
247 
248  /* Read number of points */
249  npoints = twkb_parse_state_uvarint(s);
250 
251  if ( npoints == 0 )
253 
254  /* Read coordinates */
255  pa = ptarray_from_twkb_state(s, npoints);
256 
257  if( pa == NULL )
259 
260  if( s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 2 )
261  {
262  lwerror("%s must have at least two points", lwtype_name(s->lwtype));
263  return NULL;
264  }
265 
266  return lwline_construct(SRID_UNKNOWN, NULL, pa);
267 }
268 
273 {
274  uint32_t nrings;
275  uint32_t i;
276  LWPOLY *poly;
277 
278  LWDEBUG(2,"Entering lwpoly_from_twkb_state");
279 
280  if ( s->is_empty )
282 
283  /* Read number of rings */
284  nrings = twkb_parse_state_uvarint(s);
285 
286  /* Start w/ empty polygon */
288 
289  LWDEBUGF(4,"Polygon has %d rings", nrings);
290 
291  /* Empty polygon? */
292  if( nrings == 0 )
293  return poly;
294 
295  for( i = 0; i < nrings; i++ )
296  {
297  /* Ret number of points */
298  uint32_t npoints = twkb_parse_state_uvarint(s);
299  POINTARRAY *pa = ptarray_from_twkb_state(s, npoints);
300 
301  /* Skip empty rings */
302  if( pa == NULL )
303  continue;
304 
305  /* Force first and last points to be the same. */
306  if( ! ptarray_is_closed_2d(pa) )
307  {
308  POINT4D pt;
309  getPoint4d_p(pa, 0, &pt);
310  ptarray_append_point(pa, &pt, LW_FALSE);
311  }
312 
313  /* Check for at least four points. */
314  if( s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 4 )
315  {
316  LWDEBUGF(2, "%s must have at least four points in each ring", lwtype_name(s->lwtype));
317  lwerror("%s must have at least four points in each ring", lwtype_name(s->lwtype));
318  return NULL;
319  }
320 
321  /* Add ring to polygon */
322  if ( lwpoly_add_ring(poly, pa) == LW_FAILURE )
323  {
324  LWDEBUG(2, "Unable to add ring to polygon");
325  lwerror("Unable to add ring to polygon");
326  }
327 
328  }
329  return poly;
330 }
331 
332 
337 {
338  int ngeoms, i;
339  LWGEOM *geom = NULL;
341 
342  LWDEBUG(2,"Entering lwmultipoint_from_twkb_state");
343 
344  if ( s->is_empty )
345  return col;
346 
347  /* Read number of geometries */
348  ngeoms = twkb_parse_state_uvarint(s);
349  LWDEBUGF(4,"Number of geometries %d", ngeoms);
350 
351  /* It has an idlist, we need to skip that */
352  if ( s->has_idlist )
353  {
354  for ( i = 0; i < ngeoms; i++ )
356  }
357 
358  for ( i = 0; i < ngeoms; i++ )
359  {
361  if ( lwcollection_add_lwgeom(col, geom) == NULL )
362  {
363  lwerror("Unable to add geometry (%p) to collection (%p)", geom, col);
364  return NULL;
365  }
366  }
367 
368  return col;
369 }
370 
375 {
376  int ngeoms, i;
377  LWGEOM *geom = NULL;
379 
380  LWDEBUG(2,"Entering lwmultilinestring_from_twkb_state");
381 
382  if ( s->is_empty )
383  return col;
384 
385  /* Read number of geometries */
386  ngeoms = twkb_parse_state_uvarint(s);
387 
388  LWDEBUGF(4,"Number of geometries %d",ngeoms);
389 
390  /* It has an idlist, we need to skip that */
391  if ( s->has_idlist )
392  {
393  for ( i = 0; i < ngeoms; i++ )
395  }
396 
397  for ( i = 0; i < ngeoms; i++ )
398  {
400  if ( lwcollection_add_lwgeom(col, geom) == NULL )
401  {
402  lwerror("Unable to add geometry (%p) to collection (%p)", geom, col);
403  return NULL;
404  }
405  }
406 
407  return col;
408 }
409 
414 {
415  int ngeoms, i;
416  LWGEOM *geom = NULL;
418 
419  LWDEBUG(2,"Entering lwmultipolygon_from_twkb_state");
420 
421  if ( s->is_empty )
422  return col;
423 
424  /* Read number of geometries */
425  ngeoms = twkb_parse_state_uvarint(s);
426  LWDEBUGF(4,"Number of geometries %d",ngeoms);
427 
428  /* It has an idlist, we need to skip that */
429  if ( s->has_idlist )
430  {
431  for ( i = 0; i < ngeoms; i++ )
433  }
434 
435  for ( i = 0; i < ngeoms; i++ )
436  {
438  if ( lwcollection_add_lwgeom(col, geom) == NULL )
439  {
440  lwerror("Unable to add geometry (%p) to collection (%p)", geom, col);
441  return NULL;
442  }
443  }
444 
445  return col;
446 }
447 
448 
453 {
454  int ngeoms, i;
455  LWGEOM *geom = NULL;
457 
458  LWDEBUG(2,"Entering lwcollection_from_twkb_state");
459 
460  if ( s->is_empty )
461  return col;
462 
463  /* Read number of geometries */
464  ngeoms = twkb_parse_state_uvarint(s);
465 
466  LWDEBUGF(4,"Number of geometries %d",ngeoms);
467 
468  /* It has an idlist, we need to skip that */
469  if ( s->has_idlist )
470  {
471  for ( i = 0; i < ngeoms; i++ )
473  }
474 
475  for ( i = 0; i < ngeoms; i++ )
476  {
477  geom = lwgeom_from_twkb_state(s);
478  if ( lwcollection_add_lwgeom(col, geom) == NULL )
479  {
480  lwerror("Unable to add geometry (%p) to collection (%p)", geom, col);
481  return NULL;
482  }
483  }
484 
485 
486  return col;
487 }
488 
489 
491 {
492  LWDEBUG(2,"Entering magicbyte_from_twkb_state");
493 
494  uint8_t extended_dims;
495 
496  /* Read the first two bytes */
497  uint8_t type_precision = byte_from_twkb_state(s);
498  uint8_t metadata = byte_from_twkb_state(s);
499 
500  /* Strip type and precision out of first byte */
501  uint8_t type = type_precision & 0x0F;
502  int8_t precision = unzigzag8((type_precision & 0xF0) >> 4);
503 
504  /* Convert TWKB type to internal type */
505  s->lwtype = lwtype_from_twkb_type(type);
506 
507  /* Convert the precision into factor */
508  s->factor = pow(10, (double)precision);
509 
510  /* Strip metadata flags out of second byte */
511  s->has_bbox = metadata & 0x01;
512  s->has_size = (metadata & 0x02) >> 1;
513  s->has_idlist = (metadata & 0x04) >> 2;
514  extended_dims = (metadata & 0x08) >> 3;
515  s->is_empty = (metadata & 0x10) >> 4;
516 
517  /* Flag for higher dims means read a third byte */
518  if ( extended_dims )
519  {
520  int8_t precision_z, precision_m;
521 
522  extended_dims = byte_from_twkb_state(s);
523 
524  /* Strip Z/M presence and precision from ext byte */
525  s->has_z = (extended_dims & 0x01);
526  s->has_m = (extended_dims & 0x02) >> 1;
527  precision_z = (extended_dims & 0x1C) >> 2;
528  precision_m = (extended_dims & 0xE0) >> 5;
529 
530  /* Convert the precision into factor */
531  s->factor_z = pow(10, (double)precision_z);
532  s->factor_m = pow(10, (double)precision_m);
533  }
534  else
535  {
536  s->has_z = 0;
537  s->has_m = 0;
538  s->factor_z = 0;
539  s->factor_m = 0;
540  }
541 
542  /* Read the size, if there is one */
543  if ( s->has_size )
544  {
546  }
547 
548  /* Calculate the number of dimensions */
549  s->ndims = 2 + s->has_z + s->has_m;
550 
551  return;
552 }
553 
554 
555 
563 {
564  GBOX bbox;
565  LWGEOM *geom = NULL;
566  uint32_t has_bbox = LW_FALSE;
567  int i;
568 
569  /* Read the first two bytes, and optional */
570  /* extended precision info and optional size info */
572 
573  /* Just experienced a geometry header, so now we */
574  /* need to reset our coordinate deltas */
575  for ( i = 0; i < TWKB_IN_MAXCOORDS; i++ )
576  {
577  s->coords[i] = 0.0;
578  }
579 
580  /* Read the bounding box, is there is one */
581  if ( s->has_bbox )
582  {
583  /* Initialize */
584  has_bbox = s->has_bbox;
585  memset(&bbox, 0, sizeof(GBOX));
586  bbox.flags = gflags(s->has_z, s->has_m, 0);
587 
588  /* X */
589  bbox.xmin = twkb_parse_state_double(s, s->factor);
590  bbox.xmax = bbox.xmin + twkb_parse_state_double(s, s->factor);
591  /* Y */
592  bbox.ymin = twkb_parse_state_double(s, s->factor);
593  bbox.ymax = bbox.ymin + twkb_parse_state_double(s, s->factor);
594  /* Z */
595  if ( s->has_z )
596  {
597  bbox.zmin = twkb_parse_state_double(s, s->factor_z);
598  bbox.zmax = bbox.zmin + twkb_parse_state_double(s, s->factor_z);
599  }
600  /* M */
601  if ( s->has_m )
602  {
603  bbox.mmin = twkb_parse_state_double(s, s->factor_m);
604  bbox.mmax = bbox.mmin + twkb_parse_state_double(s, s->factor_m);
605  }
606  }
607 
608  /* Switch to code for the particular type we're dealing with */
609  switch( s->lwtype )
610  {
611  case POINTTYPE:
613  break;
614  case LINETYPE:
616  break;
617  case POLYGONTYPE:
619  break;
620  case MULTIPOINTTYPE:
622  break;
623  case MULTILINETYPE:
625  break;
626  case MULTIPOLYGONTYPE:
628  break;
629  case COLLECTIONTYPE:
631  break;
632  /* Unknown type! */
633  default:
634  lwerror("Unsupported geometry type: %s [%d]", lwtype_name(s->lwtype), s->lwtype);
635  break;
636  }
637 
638  if ( has_bbox )
639  {
640  geom->bbox = gbox_clone(&bbox);
641  }
642 
643  return geom;
644 }
645 
646 
656 LWGEOM* lwgeom_from_twkb(const uint8_t *twkb, size_t twkb_size, char check)
657 {
658  int64_t coords[TWKB_IN_MAXCOORDS] = {0, 0, 0, 0};
660 
661  LWDEBUG(2,"Entering lwgeom_from_twkb");
662  LWDEBUGF(4,"twkb_size: %d",(int) twkb_size);
663 
664  /* Zero out the state */
665  memset(&s, 0, sizeof(twkb_parse_state));
666 
667  /* Initialize the state appropriately */
668  s.twkb = s.pos = twkb;
669  s.twkb_end = twkb + twkb_size;
670  s.check = check;
671  s.coords = coords;
672 
673  /* Read the rest of the geometry */
674  return lwgeom_from_twkb_state(&s);
675 }
#define LINETYPE
Definition: liblwgeom.h:85
uint8_t has_z
Definition: lwin_twkb.c:49
uint8_t is_empty
Definition: lwin_twkb.c:51
double factor_z
Definition: lwin_twkb.c:55
#define WKB_BYTE_SIZE
POINTARRAY * ptarray_construct(char hasz, char hasm, uint32_t npoints)
Construct an empty pointarray, allocating storage and setting the npoints, but not filling in any inf...
Definition: ptarray.c:62
GBOX * bbox
Definition: liblwgeom.h:400
LWLINE * lwline_construct_empty(int srid, char hasz, char hasm)
Definition: lwline.c:64
uint8_t * serialized_pointlist
Definition: liblwgeom.h:368
uint64_t size
Definition: lwin_twkb.c:58
static LWLINE * lwline_from_twkb_state(twkb_parse_state *s)
LINESTRING.
Definition: lwin_twkb.c:238
static LWCOLLECTION * lwcollection_from_twkb_state(twkb_parse_state *s)
COLLECTION, MULTIPOINTTYPE, MULTILINETYPE, MULTIPOLYGONTYPE.
Definition: lwin_twkb.c:452
#define LW_PARSER_CHECK_MINPOINTS
Parser check flags.
Definition: liblwgeom.h:1999
#define POLYGONTYPE
Definition: liblwgeom.h:86
double xmax
Definition: liblwgeom.h:295
uint8_t has_m
Definition: lwin_twkb.c:50
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition: ptarray.c:70
#define MULTIPOINTTYPE
Definition: liblwgeom.h:87
const uint8_t * twkb_end
Definition: lwin_twkb.c:40
uint32_t check
Definition: lwin_twkb.c:43
static LWPOLY * lwpoly_from_twkb_state(twkb_parse_state *s)
POLYGON.
Definition: lwin_twkb.c:272
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
uint8_t has_idlist
Definition: lwin_twkb.c:48
static uint32_t lwtype_from_twkb_type(uint8_t twkb_type)
Definition: lwin_twkb.c:130
static POINTARRAY * ptarray_from_twkb_state(twkb_parse_state *s, uint32_t npoints)
POINTARRAY Read a dynamically sized point array and advance the parse state forward.
Definition: lwin_twkb.c:172
size_t varint_size(const uint8_t *the_start, const uint8_t *the_end)
Definition: varint.c:147
LWPOINT * lwpoint_construct_empty(int srid, char hasz, char hasm)
Definition: lwpoint.c:151
const uint8_t * twkb
Definition: lwin_twkb.c:39
uint8_t has_bbox
Definition: lwin_twkb.c:46
int ptarray_is_closed_2d(const POINTARRAY *pa)
Definition: ptarray.c:695
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:320
static uint8_t byte_from_twkb_state(twkb_parse_state *s)
Byte Read a byte and advance the parse state forward.
Definition: lwin_twkb.c:160
int64_t varint_s64_decode(const uint8_t *the_start, const uint8_t *the_end, size_t *size)
Definition: varint.c:102
#define LW_FAILURE
Definition: liblwgeom.h:78
unsigned int uint32_t
Definition: uthash.h:78
double zmax
Definition: liblwgeom.h:299
double ymin
Definition: liblwgeom.h:296
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:218
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:330
#define TWKB_IN_MAXCOORDS
Definition: lwin_twkb.c:31
double xmin
Definition: liblwgeom.h:294
int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int allow_duplicates)
Append a point to the end of an existing POINTARRAY If allow_duplicate is LW_FALSE, then a duplicate point will not be added.
Definition: ptarray.c:156
#define LW_FALSE
Definition: liblwgeom.h:76
int64_t * coords
Definition: lwin_twkb.c:65
uint32_t lwtype
Definition: lwin_twkb.c:44
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:187
uint8_t precision
Definition: cu_in_twkb.c:25
double factor_m
Definition: lwin_twkb.c:56
double ymax
Definition: liblwgeom.h:297
static LWCOLLECTION * lwmultipoint_from_twkb_state(twkb_parse_state *s)
MULTIPOINT.
Definition: lwin_twkb.c:336
char * s
Definition: cu_in_wkt.c:23
Used for passing the parse state between the parsing functions.
Definition: lwin_twkb.c:36
static uint64_t twkb_parse_state_uvarint(twkb_parse_state *s)
Definition: lwin_twkb.c:101
uint8_t flags
Definition: liblwgeom.h:293
static LWCOLLECTION * lwmultipoly_from_twkb_state(twkb_parse_state *s)
MULTIPOLYGON.
Definition: lwin_twkb.c:413
uint8_t gflags(int hasz, int hasm, int geodetic)
Construct a new flags char.
Definition: g_util.c:145
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition: lwgeom_api.c:113
static LWPOINT * lwpoint_from_twkb_state(twkb_parse_state *s)
POINT.
Definition: lwin_twkb.c:221
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:89
uint64_t varint_u64_decode(const uint8_t *the_start, const uint8_t *the_end, size_t *size)
Definition: varint.c:109
static double twkb_parse_state_double(twkb_parse_state *s, double factor)
Definition: lwin_twkb.c:109
const uint8_t * pos
Definition: lwin_twkb.c:41
double mmin
Definition: liblwgeom.h:300
double zmin
Definition: liblwgeom.h:298
LWGEOM * lwgeom_from_twkb_state(twkb_parse_state *s)
Internal function declarations.
Definition: lwin_twkb.c:562
static void twkb_parse_state_advance(twkb_parse_state *s, size_t next)
Check that we are not about to read off the end of the WKB array.
Definition: lwin_twkb.c:82
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:84
LWPOLY * lwpoly_construct_empty(int srid, char hasz, char hasm)
Definition: lwpoly.c:161
type
Definition: ovdump.py:41
double mmax
Definition: liblwgeom.h:301
LWGEOM * lwgeom_from_twkb(const uint8_t *twkb, size_t twkb_size, char check)
WKB inputs must have a declared size, to prevent malformed WKB from reading off the end of the memory...
Definition: lwin_twkb.c:656
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:335
int lwpoly_add_ring(LWPOLY *poly, POINTARRAY *pa)
Add a ring, allocating extra space if necessary.
Definition: lwpoly.c:247
GBOX * gbox_clone(const GBOX *gbox)
Definition: g_box.c:52
LWPOINT * lwpoint_construct(int srid, GBOX *bbox, POINTARRAY *point)
Definition: lwpoint.c:129
static LWCOLLECTION * lwmultiline_from_twkb_state(twkb_parse_state *s)
MULTILINESTRING.
Definition: lwin_twkb.c:374
static void header_from_twkb_state(twkb_parse_state *s)
Definition: lwin_twkb.c:490
#define MULTILINETYPE
Definition: liblwgeom.h:88
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int srid, char hasz, char hasm)
Definition: lwcollection.c:94
static int64_t twkb_parse_state_varint(twkb_parse_state *s)
Definition: lwin_twkb.c:93
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
unsigned char uint8_t
Definition: uthash.h:79
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
Definition: lwcollection.c:187
static void twkb_parse_state_varint_skip(twkb_parse_state *s)
Definition: lwin_twkb.c:117
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
uint8_t magic_byte
Definition: lwin_twkb.c:61
#define COLLECTIONTYPE
Definition: liblwgeom.h:90
uint8_t has_size
Definition: lwin_twkb.c:47
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition: lwgeom.c:300
int8_t unzigzag8(uint8_t val)
Definition: varint.c:203
uint32_t npoints
Definition: liblwgeom.h:373