9762691237
Make all the "Unsupported geometry type" name themselves by __func__. In case output format doesn't know about TIN/Triangle, output them as GeometryCollection/Polygon. Closes #4399 Closes https://github.com/postgis/postgis/pull/454 git-svn-id: http://svn.osgeo.org/postgis/trunk@17674 b70326c6-7e19-0410-871a-916f4a2858ee
674 lines
16 KiB
C
674 lines
16 KiB
C
/**********************************************************************
|
|
*
|
|
* PostGIS - Spatial Types for PostgreSQL
|
|
* http://postgis.net
|
|
*
|
|
* PostGIS is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* PostGIS is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
**********************************************************************
|
|
*
|
|
* Copyright (C) 2014 Nicklas Avén
|
|
*
|
|
**********************************************************************/
|
|
|
|
|
|
#include <math.h>
|
|
#include "liblwgeom_internal.h"
|
|
#include "lwgeom_log.h"
|
|
#include "varint.h"
|
|
|
|
#define TWKB_IN_MAXCOORDS 4
|
|
|
|
/**
|
|
* Used for passing the parse state between the parsing functions.
|
|
*/
|
|
typedef struct
|
|
{
|
|
/* Pointers to the bytes */
|
|
const uint8_t *twkb; /* Points to start of TWKB */
|
|
const uint8_t *twkb_end; /* Points to end of TWKB */
|
|
const uint8_t *pos; /* Current read position */
|
|
|
|
uint32_t check; /* Simple validity checks on geometries */
|
|
uint32_t lwtype; /* Current type we are handling */
|
|
|
|
uint8_t has_bbox;
|
|
uint8_t has_size;
|
|
uint8_t has_idlist;
|
|
uint8_t has_z;
|
|
uint8_t has_m;
|
|
uint8_t is_empty;
|
|
|
|
/* Precision factors to convert ints to double */
|
|
double factor;
|
|
double factor_z;
|
|
double factor_m;
|
|
|
|
uint64_t size;
|
|
|
|
/* Info about current geometry */
|
|
uint8_t magic_byte; /* the magic byte contain info about if twkb contain id, size info, bboxes and precision */
|
|
|
|
int ndims; /* Number of dimensions */
|
|
|
|
int64_t *coords; /* An array to keep delta values from 4 dimensions */
|
|
|
|
} twkb_parse_state;
|
|
|
|
|
|
/**
|
|
* Internal function declarations.
|
|
*/
|
|
LWGEOM* lwgeom_from_twkb_state(twkb_parse_state *s);
|
|
|
|
|
|
/**********************************************************************/
|
|
|
|
/**
|
|
* Check that we are not about to read off the end of the WKB
|
|
* array.
|
|
*/
|
|
static inline void twkb_parse_state_advance(twkb_parse_state *s, size_t next)
|
|
{
|
|
if( (s->pos + next) > s->twkb_end)
|
|
{
|
|
lwerror("%s: TWKB structure does not match expected size!", __func__);
|
|
// lwnotice("TWKB structure does not match expected size!");
|
|
}
|
|
|
|
s->pos += next;
|
|
}
|
|
|
|
static inline int64_t twkb_parse_state_varint(twkb_parse_state *s)
|
|
{
|
|
size_t size;
|
|
int64_t val = varint_s64_decode(s->pos, s->twkb_end, &size);
|
|
twkb_parse_state_advance(s, size);
|
|
return val;
|
|
}
|
|
|
|
static inline uint64_t twkb_parse_state_uvarint(twkb_parse_state *s)
|
|
{
|
|
size_t size;
|
|
uint64_t val = varint_u64_decode(s->pos, s->twkb_end, &size);
|
|
twkb_parse_state_advance(s, size);
|
|
return val;
|
|
}
|
|
|
|
static inline double twkb_parse_state_double(twkb_parse_state *s, double factor)
|
|
{
|
|
size_t size;
|
|
int64_t val = varint_s64_decode(s->pos, s->twkb_end, &size);
|
|
twkb_parse_state_advance(s, size);
|
|
return val / factor;
|
|
}
|
|
|
|
static inline void twkb_parse_state_varint_skip(twkb_parse_state *s)
|
|
{
|
|
size_t size = varint_size(s->pos, s->twkb_end);
|
|
|
|
if ( ! size )
|
|
lwerror("%s: no varint to skip", __func__);
|
|
|
|
twkb_parse_state_advance(s, size);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
static uint32_t lwtype_from_twkb_type(uint8_t twkb_type)
|
|
{
|
|
switch (twkb_type)
|
|
{
|
|
case 1:
|
|
return POINTTYPE;
|
|
case 2:
|
|
return LINETYPE;
|
|
case 3:
|
|
return POLYGONTYPE;
|
|
case 4:
|
|
return MULTIPOINTTYPE;
|
|
case 5:
|
|
return MULTILINETYPE;
|
|
case 6:
|
|
return MULTIPOLYGONTYPE;
|
|
case 7:
|
|
return COLLECTIONTYPE;
|
|
|
|
default: /* Error! */
|
|
lwerror("Unknown WKB type");
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Byte
|
|
* Read a byte and advance the parse state forward.
|
|
*/
|
|
static uint8_t byte_from_twkb_state(twkb_parse_state *s)
|
|
{
|
|
uint8_t val = *(s->pos);
|
|
twkb_parse_state_advance(s, WKB_BYTE_SIZE);
|
|
return val;
|
|
}
|
|
|
|
|
|
/**
|
|
* POINTARRAY
|
|
* Read a dynamically sized point array and advance the parse state forward.
|
|
*/
|
|
static POINTARRAY* ptarray_from_twkb_state(twkb_parse_state *s, uint32_t npoints)
|
|
{
|
|
POINTARRAY *pa = NULL;
|
|
uint32_t ndims = s->ndims;
|
|
uint32_t i;
|
|
double *dlist;
|
|
|
|
LWDEBUG(2,"Entering ptarray_from_twkb_state");
|
|
LWDEBUGF(4,"Pointarray has %d points", npoints);
|
|
|
|
/* Empty! */
|
|
if( npoints == 0 )
|
|
return ptarray_construct_empty(s->has_z, s->has_m, 0);
|
|
|
|
pa = ptarray_construct(s->has_z, s->has_m, npoints);
|
|
dlist = (double*)(pa->serialized_pointlist);
|
|
for( i = 0; i < npoints; i++ )
|
|
{
|
|
int j = 0;
|
|
/* X */
|
|
s->coords[j] += twkb_parse_state_varint(s);
|
|
dlist[ndims*i + j] = s->coords[j] / s->factor;
|
|
j++;
|
|
/* Y */
|
|
s->coords[j] += twkb_parse_state_varint(s);
|
|
dlist[ndims*i + j] = s->coords[j] / s->factor;
|
|
j++;
|
|
/* Z */
|
|
if ( s->has_z )
|
|
{
|
|
s->coords[j] += twkb_parse_state_varint(s);
|
|
dlist[ndims*i + j] = s->coords[j] / s->factor_z;
|
|
j++;
|
|
}
|
|
/* M */
|
|
if ( s->has_m )
|
|
{
|
|
s->coords[j] += twkb_parse_state_varint(s);
|
|
dlist[ndims*i + j] = s->coords[j] / s->factor_m;
|
|
j++;
|
|
}
|
|
}
|
|
|
|
return pa;
|
|
}
|
|
|
|
/**
|
|
* POINT
|
|
*/
|
|
static LWPOINT* lwpoint_from_twkb_state(twkb_parse_state *s)
|
|
{
|
|
static uint32_t npoints = 1;
|
|
POINTARRAY *pa;
|
|
|
|
LWDEBUG(2,"Entering lwpoint_from_twkb_state");
|
|
|
|
if ( s->is_empty )
|
|
return lwpoint_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m);
|
|
|
|
pa = ptarray_from_twkb_state(s, npoints);
|
|
return lwpoint_construct(SRID_UNKNOWN, NULL, pa);
|
|
}
|
|
|
|
/**
|
|
* LINESTRING
|
|
*/
|
|
static LWLINE* lwline_from_twkb_state(twkb_parse_state *s)
|
|
{
|
|
uint32_t npoints;
|
|
POINTARRAY *pa;
|
|
|
|
LWDEBUG(2,"Entering lwline_from_twkb_state");
|
|
|
|
if ( s->is_empty )
|
|
return lwline_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m);
|
|
|
|
/* Read number of points */
|
|
npoints = twkb_parse_state_uvarint(s);
|
|
|
|
if ( npoints == 0 )
|
|
return lwline_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m);
|
|
|
|
/* Read coordinates */
|
|
pa = ptarray_from_twkb_state(s, npoints);
|
|
|
|
if( pa == NULL )
|
|
return lwline_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m);
|
|
|
|
if( s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 2 )
|
|
{
|
|
lwerror("%s must have at least two points", lwtype_name(s->lwtype));
|
|
return NULL;
|
|
}
|
|
|
|
return lwline_construct(SRID_UNKNOWN, NULL, pa);
|
|
}
|
|
|
|
/**
|
|
* POLYGON
|
|
*/
|
|
static LWPOLY* lwpoly_from_twkb_state(twkb_parse_state *s)
|
|
{
|
|
uint32_t nrings;
|
|
uint32_t i;
|
|
LWPOLY *poly;
|
|
|
|
LWDEBUG(2,"Entering lwpoly_from_twkb_state");
|
|
|
|
if ( s->is_empty )
|
|
return lwpoly_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m);
|
|
|
|
/* Read number of rings */
|
|
nrings = twkb_parse_state_uvarint(s);
|
|
|
|
/* Start w/ empty polygon */
|
|
poly = lwpoly_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m);
|
|
|
|
LWDEBUGF(4,"Polygon has %d rings", nrings);
|
|
|
|
/* Empty polygon? */
|
|
if( nrings == 0 )
|
|
return poly;
|
|
|
|
for( i = 0; i < nrings; i++ )
|
|
{
|
|
/* Ret number of points */
|
|
uint32_t npoints = twkb_parse_state_uvarint(s);
|
|
POINTARRAY *pa = ptarray_from_twkb_state(s, npoints);
|
|
|
|
/* Skip empty rings */
|
|
if( pa == NULL )
|
|
continue;
|
|
|
|
/* Force first and last points to be the same. */
|
|
if( ! ptarray_is_closed_2d(pa) )
|
|
{
|
|
POINT4D pt;
|
|
getPoint4d_p(pa, 0, &pt);
|
|
ptarray_append_point(pa, &pt, LW_FALSE);
|
|
}
|
|
|
|
/* Check for at least four points. */
|
|
if( s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 4 )
|
|
{
|
|
LWDEBUGF(2, "%s must have at least four points in each ring", lwtype_name(s->lwtype));
|
|
lwerror("%s must have at least four points in each ring", lwtype_name(s->lwtype));
|
|
return NULL;
|
|
}
|
|
|
|
/* Add ring to polygon */
|
|
if ( lwpoly_add_ring(poly, pa) == LW_FAILURE )
|
|
{
|
|
LWDEBUG(2, "Unable to add ring to polygon");
|
|
lwerror("Unable to add ring to polygon");
|
|
}
|
|
|
|
}
|
|
return poly;
|
|
}
|
|
|
|
|
|
/**
|
|
* MULTIPOINT
|
|
*/
|
|
static LWCOLLECTION* lwmultipoint_from_twkb_state(twkb_parse_state *s)
|
|
{
|
|
int ngeoms, i;
|
|
LWGEOM *geom = NULL;
|
|
LWCOLLECTION *col = lwcollection_construct_empty(s->lwtype, SRID_UNKNOWN, s->has_z, s->has_m);
|
|
|
|
LWDEBUG(2,"Entering lwmultipoint_from_twkb_state");
|
|
|
|
if ( s->is_empty )
|
|
return col;
|
|
|
|
/* Read number of geometries */
|
|
ngeoms = twkb_parse_state_uvarint(s);
|
|
LWDEBUGF(4,"Number of geometries %d", ngeoms);
|
|
|
|
/* It has an idlist, we need to skip that */
|
|
if ( s->has_idlist )
|
|
{
|
|
for ( i = 0; i < ngeoms; i++ )
|
|
twkb_parse_state_varint_skip(s);
|
|
}
|
|
|
|
for ( i = 0; i < ngeoms; i++ )
|
|
{
|
|
geom = lwpoint_as_lwgeom(lwpoint_from_twkb_state(s));
|
|
if ( lwcollection_add_lwgeom(col, geom) == NULL )
|
|
{
|
|
lwerror("Unable to add geometry (%p) to collection (%p)", geom, col);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return col;
|
|
}
|
|
|
|
/**
|
|
* MULTILINESTRING
|
|
*/
|
|
static LWCOLLECTION* lwmultiline_from_twkb_state(twkb_parse_state *s)
|
|
{
|
|
int ngeoms, i;
|
|
LWGEOM *geom = NULL;
|
|
LWCOLLECTION *col = lwcollection_construct_empty(s->lwtype, SRID_UNKNOWN, s->has_z, s->has_m);
|
|
|
|
LWDEBUG(2,"Entering lwmultilinestring_from_twkb_state");
|
|
|
|
if ( s->is_empty )
|
|
return col;
|
|
|
|
/* Read number of geometries */
|
|
ngeoms = twkb_parse_state_uvarint(s);
|
|
|
|
LWDEBUGF(4,"Number of geometries %d",ngeoms);
|
|
|
|
/* It has an idlist, we need to skip that */
|
|
if ( s->has_idlist )
|
|
{
|
|
for ( i = 0; i < ngeoms; i++ )
|
|
twkb_parse_state_varint_skip(s);
|
|
}
|
|
|
|
for ( i = 0; i < ngeoms; i++ )
|
|
{
|
|
geom = lwline_as_lwgeom(lwline_from_twkb_state(s));
|
|
if ( lwcollection_add_lwgeom(col, geom) == NULL )
|
|
{
|
|
lwerror("Unable to add geometry (%p) to collection (%p)", geom, col);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return col;
|
|
}
|
|
|
|
/**
|
|
* MULTIPOLYGON
|
|
*/
|
|
static LWCOLLECTION* lwmultipoly_from_twkb_state(twkb_parse_state *s)
|
|
{
|
|
int ngeoms, i;
|
|
LWGEOM *geom = NULL;
|
|
LWCOLLECTION *col = lwcollection_construct_empty(s->lwtype, SRID_UNKNOWN, s->has_z, s->has_m);
|
|
|
|
LWDEBUG(2,"Entering lwmultipolygon_from_twkb_state");
|
|
|
|
if ( s->is_empty )
|
|
return col;
|
|
|
|
/* Read number of geometries */
|
|
ngeoms = twkb_parse_state_uvarint(s);
|
|
LWDEBUGF(4,"Number of geometries %d",ngeoms);
|
|
|
|
/* It has an idlist, we need to skip that */
|
|
if ( s->has_idlist )
|
|
{
|
|
for ( i = 0; i < ngeoms; i++ )
|
|
twkb_parse_state_varint_skip(s);
|
|
}
|
|
|
|
for ( i = 0; i < ngeoms; i++ )
|
|
{
|
|
geom = lwpoly_as_lwgeom(lwpoly_from_twkb_state(s));
|
|
if ( lwcollection_add_lwgeom(col, geom) == NULL )
|
|
{
|
|
lwerror("Unable to add geometry (%p) to collection (%p)", geom, col);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return col;
|
|
}
|
|
|
|
|
|
/**
|
|
* COLLECTION, MULTIPOINTTYPE, MULTILINETYPE, MULTIPOLYGONTYPE
|
|
**/
|
|
static LWCOLLECTION* lwcollection_from_twkb_state(twkb_parse_state *s)
|
|
{
|
|
int ngeoms, i;
|
|
LWGEOM *geom = NULL;
|
|
LWCOLLECTION *col = lwcollection_construct_empty(s->lwtype, SRID_UNKNOWN, s->has_z, s->has_m);
|
|
|
|
LWDEBUG(2,"Entering lwcollection_from_twkb_state");
|
|
|
|
if ( s->is_empty )
|
|
return col;
|
|
|
|
/* Read number of geometries */
|
|
ngeoms = twkb_parse_state_uvarint(s);
|
|
|
|
LWDEBUGF(4,"Number of geometries %d",ngeoms);
|
|
|
|
/* It has an idlist, we need to skip that */
|
|
if ( s->has_idlist )
|
|
{
|
|
for ( i = 0; i < ngeoms; i++ )
|
|
twkb_parse_state_varint_skip(s);
|
|
}
|
|
|
|
for ( i = 0; i < ngeoms; i++ )
|
|
{
|
|
geom = lwgeom_from_twkb_state(s);
|
|
if ( lwcollection_add_lwgeom(col, geom) == NULL )
|
|
{
|
|
lwerror("Unable to add geometry (%p) to collection (%p)", geom, col);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
return col;
|
|
}
|
|
|
|
|
|
static void header_from_twkb_state(twkb_parse_state *s)
|
|
{
|
|
LWDEBUG(2,"Entering magicbyte_from_twkb_state");
|
|
|
|
uint8_t extended_dims;
|
|
|
|
/* Read the first two bytes */
|
|
uint8_t type_precision = byte_from_twkb_state(s);
|
|
uint8_t metadata = byte_from_twkb_state(s);
|
|
|
|
/* Strip type and precision out of first byte */
|
|
uint8_t type = type_precision & 0x0F;
|
|
int8_t precision = unzigzag8((type_precision & 0xF0) >> 4);
|
|
|
|
/* Convert TWKB type to internal type */
|
|
s->lwtype = lwtype_from_twkb_type(type);
|
|
|
|
/* Convert the precision into factor */
|
|
s->factor = pow(10, (double)precision);
|
|
|
|
/* Strip metadata flags out of second byte */
|
|
s->has_bbox = metadata & 0x01;
|
|
s->has_size = (metadata & 0x02) >> 1;
|
|
s->has_idlist = (metadata & 0x04) >> 2;
|
|
extended_dims = (metadata & 0x08) >> 3;
|
|
s->is_empty = (metadata & 0x10) >> 4;
|
|
|
|
/* Flag for higher dims means read a third byte */
|
|
if ( extended_dims )
|
|
{
|
|
int8_t precision_z, precision_m;
|
|
|
|
extended_dims = byte_from_twkb_state(s);
|
|
|
|
/* Strip Z/M presence and precision from ext byte */
|
|
s->has_z = (extended_dims & 0x01);
|
|
s->has_m = (extended_dims & 0x02) >> 1;
|
|
precision_z = (extended_dims & 0x1C) >> 2;
|
|
precision_m = (extended_dims & 0xE0) >> 5;
|
|
|
|
/* Convert the precision into factor */
|
|
s->factor_z = pow(10, (double)precision_z);
|
|
s->factor_m = pow(10, (double)precision_m);
|
|
}
|
|
else
|
|
{
|
|
s->has_z = 0;
|
|
s->has_m = 0;
|
|
s->factor_z = 0;
|
|
s->factor_m = 0;
|
|
}
|
|
|
|
/* Read the size, if there is one */
|
|
if ( s->has_size )
|
|
{
|
|
s->size = twkb_parse_state_uvarint(s);
|
|
}
|
|
|
|
/* Calculate the number of dimensions */
|
|
s->ndims = 2 + s->has_z + s->has_m;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Generic handling for TWKB geometries. The front of every TWKB geometry
|
|
* (including those embedded in collections) is a type byte and metadata byte,
|
|
* then optional size, bbox, etc. Read those, then switch to particular type
|
|
* handling code.
|
|
*/
|
|
LWGEOM* lwgeom_from_twkb_state(twkb_parse_state *s)
|
|
{
|
|
GBOX bbox;
|
|
LWGEOM *geom = NULL;
|
|
uint32_t has_bbox = LW_FALSE;
|
|
int i;
|
|
|
|
/* Read the first two bytes, and optional */
|
|
/* extended precision info and optional size info */
|
|
header_from_twkb_state(s);
|
|
|
|
/* Just experienced a geometry header, so now we */
|
|
/* need to reset our coordinate deltas */
|
|
for ( i = 0; i < TWKB_IN_MAXCOORDS; i++ )
|
|
{
|
|
s->coords[i] = 0.0;
|
|
}
|
|
|
|
/* Read the bounding box, is there is one */
|
|
if ( s->has_bbox )
|
|
{
|
|
/* Initialize */
|
|
has_bbox = s->has_bbox;
|
|
memset(&bbox, 0, sizeof(GBOX));
|
|
bbox.flags = lwflags(s->has_z, s->has_m, 0);
|
|
|
|
/* X */
|
|
bbox.xmin = twkb_parse_state_double(s, s->factor);
|
|
bbox.xmax = bbox.xmin + twkb_parse_state_double(s, s->factor);
|
|
/* Y */
|
|
bbox.ymin = twkb_parse_state_double(s, s->factor);
|
|
bbox.ymax = bbox.ymin + twkb_parse_state_double(s, s->factor);
|
|
/* Z */
|
|
if ( s->has_z )
|
|
{
|
|
bbox.zmin = twkb_parse_state_double(s, s->factor_z);
|
|
bbox.zmax = bbox.zmin + twkb_parse_state_double(s, s->factor_z);
|
|
}
|
|
/* M */
|
|
if ( s->has_m )
|
|
{
|
|
bbox.mmin = twkb_parse_state_double(s, s->factor_m);
|
|
bbox.mmax = bbox.mmin + twkb_parse_state_double(s, s->factor_m);
|
|
}
|
|
}
|
|
|
|
/* Switch to code for the particular type we're dealing with */
|
|
switch( s->lwtype )
|
|
{
|
|
case POINTTYPE:
|
|
geom = lwpoint_as_lwgeom(lwpoint_from_twkb_state(s));
|
|
break;
|
|
case LINETYPE:
|
|
geom = lwline_as_lwgeom(lwline_from_twkb_state(s));
|
|
break;
|
|
case POLYGONTYPE:
|
|
geom = lwpoly_as_lwgeom(lwpoly_from_twkb_state(s));
|
|
break;
|
|
case MULTIPOINTTYPE:
|
|
geom = lwcollection_as_lwgeom(lwmultipoint_from_twkb_state(s));
|
|
break;
|
|
case MULTILINETYPE:
|
|
geom = lwcollection_as_lwgeom(lwmultiline_from_twkb_state(s));
|
|
break;
|
|
case MULTIPOLYGONTYPE:
|
|
geom = lwcollection_as_lwgeom(lwmultipoly_from_twkb_state(s));
|
|
break;
|
|
case COLLECTIONTYPE:
|
|
geom = lwcollection_as_lwgeom(lwcollection_from_twkb_state(s));
|
|
break;
|
|
/* Unknown type! */
|
|
default:
|
|
lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(s->lwtype));
|
|
break;
|
|
}
|
|
|
|
if ( has_bbox )
|
|
geom->bbox = gbox_clone(&bbox);
|
|
|
|
return geom;
|
|
}
|
|
|
|
|
|
/**
|
|
* WKB inputs *must* have a declared size, to prevent malformed WKB from reading
|
|
* off the end of the memory segment (this stops a malevolent user from declaring
|
|
* a one-ring polygon to have 10 rings, causing the WKB reader to walk off the
|
|
* end of the memory).
|
|
*
|
|
* Check is a bitmask of: LW_PARSER_CHECK_MINPOINTS, LW_PARSER_CHECK_ODD,
|
|
* LW_PARSER_CHECK_CLOSURE, LW_PARSER_CHECK_NONE, LW_PARSER_CHECK_ALL
|
|
*/
|
|
LWGEOM* lwgeom_from_twkb(const uint8_t *twkb, size_t twkb_size, char check)
|
|
{
|
|
int64_t coords[TWKB_IN_MAXCOORDS] = {0, 0, 0, 0};
|
|
twkb_parse_state s;
|
|
|
|
LWDEBUG(2,"Entering lwgeom_from_twkb");
|
|
LWDEBUGF(4,"twkb_size: %d",(int) twkb_size);
|
|
|
|
/* Zero out the state */
|
|
memset(&s, 0, sizeof(twkb_parse_state));
|
|
|
|
/* Initialize the state appropriately */
|
|
s.twkb = s.pos = twkb;
|
|
s.twkb_end = twkb + twkb_size;
|
|
s.check = check;
|
|
s.coords = coords;
|
|
|
|
/* Read the rest of the geometry */
|
|
return lwgeom_from_twkb_state(&s);
|
|
}
|