/** * COLLECTION, MULTIPOINTTYPE, MULTILINETYPE, MULTIPOLYGONTYPE, COMPOUNDTYPE, * MULTICURVETYPE, MULTISURFACETYPE, * TINTYPE */ static LWCOLLECTION* lwcollection_from_wkb_state(wkb_parse_state *s) { uint32_t ngeoms = integer_from_wkb_state(s); LWCOLLECTION *col = lwcollection_construct_empty(s->lwtype, s->srid, s->has_z, s->has_m); LWGEOM *geom = NULL; int i; LWDEBUGF(4,"Collection has %d components", ngeoms); /* Empty collection? */ if ( ngeoms == 0 ) return col; /* Be strict in polyhedral surface closures */ if ( s->lwtype == POLYHEDRALSURFACETYPE ) s->check |= LW_PARSER_CHECK_ZCLOSURE; for ( i = 0; i < ngeoms; i++ ) { geom = lwgeom_from_wkb_state(s); if ( lwcollection_add_lwgeom(col, geom) == NULL ) { lwerror("Unable to add geometry (%p) to collection (%p)", geom, col); return NULL; } } return col; }
/** * POINTARRAY * Read a dynamically sized point array and advance the parse state forward. * First read the number of points, then read the points. */ static POINTARRAY* ptarray_from_wkb_state(wkb_parse_state *s) { POINTARRAY *pa = NULL; size_t pa_size; uint32_t ndims = 2; uint32_t npoints = 0; static uint32_t maxpoints = 4294967295 / WKB_DOUBLE_SIZE / 4; /* Calculate the size of this point array. */ npoints = integer_from_wkb_state(s); if (npoints > maxpoints) { lwerror("point array length (%d) is too large"); } LWDEBUGF(4,"Pointarray has %d points", npoints); if( s->has_z ) ndims++; if( s->has_m ) ndims++; pa_size = npoints * ndims * WKB_DOUBLE_SIZE; /* Empty! */ if( npoints == 0 ) return ptarray_construct(s->has_z, s->has_m, npoints); /* Does the data we want to read exist? */ wkb_parse_state_check(s, pa_size); /* If we're in a native endianness, we can just copy the data directly! */ if( ! s->swap_bytes ) { pa = ptarray_construct_copy_data(s->has_z, s->has_m, npoints, (uint8_t*)s->pos); s->pos += pa_size; } /* Otherwise we have to read each double, separately. */ else { int i = 0; double *dlist; pa = ptarray_construct(s->has_z, s->has_m, npoints); dlist = (double*)(pa->serialized_pointlist); for( i = 0; i < npoints * ndims; i++ ) { dlist[i] = double_from_wkb_state(s); } } return pa; }
/** * TRIANGLE * Read a WKB triangle, starting just after the endian byte, * type number and optional srid number. Advance the parse state * forward appropriately. * Triangles are encoded like polygons in WKB, but more like linestrings * as lwgeometries. */ static LWTRIANGLE* lwtriangle_from_wkb_state(wkb_parse_state *s) { uint32_t nrings = integer_from_wkb_state(s); LWTRIANGLE *tri = lwtriangle_construct_empty(s->srid, s->has_z, s->has_m); POINTARRAY *pa = NULL; /* Empty triangle? */ if( nrings == 0 ) return tri; /* Should be only one ring. */ if ( nrings != 1 ) lwerror("Triangle has wrong number of rings: %d", nrings); /* There's only one ring, we hope? */ pa = ptarray_from_wkb_state(s); /* If there's no points, return an empty triangle. */ if( pa == NULL ) return tri; /* 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", lwtype_name(s->lwtype)); lwerror("%s must have at least four points", lwtype_name(s->lwtype)); return NULL; } if( s->check & LW_PARSER_CHECK_CLOSURE && ! ptarray_is_closed(pa) ) { lwerror("%s must have closed rings", lwtype_name(s->lwtype)); return NULL; } if( s->check & LW_PARSER_CHECK_ZCLOSURE && ! ptarray_is_closed_z(pa) ) { lwerror("%s must have closed rings", lwtype_name(s->lwtype)); return NULL; } /* Empty TRIANGLE starts w/ empty POINTARRAY, free it first */ if (tri->points) ptarray_free(tri->points); tri->points = pa; return tri; }
/** * POLYGON * Read a WKB polygon, starting just after the endian byte, * type number and optional srid number. Advance the parse state * forward appropriately. * First read the number of rings, then read each ring * (which are structured as point arrays) */ static LWPOLY* lwpoly_from_wkb_state(wkb_parse_state *s) { uint32_t nrings = integer_from_wkb_state(s); int i = 0; LWPOLY *poly = lwpoly_construct_empty(s->srid, 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++ ) { POINTARRAY *pa = ptarray_from_wkb_state(s); if( pa == NULL ) continue; /* 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; } /* Check that first and last points are the same. */ if( s->check & LW_PARSER_CHECK_CLOSURE && ! ptarray_is_closed_2d(pa) ) { LWDEBUGF(2, "%s must have closed rings", lwtype_name(s->lwtype)); lwerror("%s must have closed rings", 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; }
/** * CURVEPOLYTYPE */ static LWCURVEPOLY* lwcurvepoly_from_wkb_state(wkb_parse_state *s) { uint32_t ngeoms = integer_from_wkb_state(s); LWCURVEPOLY *cp = lwcurvepoly_construct_empty(s->srid, s->has_z, s->has_m); LWGEOM *geom = NULL; int i; /* Empty collection? */ if ( ngeoms == 0 ) return cp; for ( i = 0; i < ngeoms; i++ ) { geom = lwgeom_from_wkb_state(s); if ( lwcurvepoly_add_ring(cp, geom) == LW_FAILURE ) lwerror("Unable to add geometry (%p) to curvepoly (%p)", geom, cp); } return cp; }
/** * GEOMETRY * Generic handling for WKB geometries. The front of every WKB geometry * (including those embedded in collections) is an endian byte, a type * number and an optional srid number. We handle all those here, then pass * to the appropriate handler for the specific type. */ LWGEOM* lwgeom_from_wkb_state(wkb_parse_state *s) { char wkb_little_endian; uint32_t wkb_type; LWDEBUG(4,"Entered function"); /* Fail when handed incorrect starting byte */ wkb_little_endian = byte_from_wkb_state(s); if( wkb_little_endian != 1 && wkb_little_endian != 0 ) { LWDEBUG(4,"Leaving due to bad first byte!"); lwerror("Invalid endian flag value encountered."); return NULL; } /* Check the endianness of our input */ s->swap_bytes = LW_FALSE; if( getMachineEndian() == NDR ) /* Machine arch is little */ { if ( ! wkb_little_endian ) /* Data is big! */ s->swap_bytes = LW_TRUE; } else /* Machine arch is big */ { if ( wkb_little_endian ) /* Data is little! */ s->swap_bytes = LW_TRUE; } /* Read the type number */ wkb_type = integer_from_wkb_state(s); LWDEBUGF(4,"Got WKB type number: 0x%X", wkb_type); lwtype_from_wkb_state(s, wkb_type); /* Read the SRID, if necessary */ if( s->has_srid ) { s->srid = clamp_srid(integer_from_wkb_state(s)); /* TODO: warn on explicit UNKNOWN srid ? */ LWDEBUGF(4,"Got SRID: %u", s->srid); } /* Do the right thing */ switch( s->lwtype ) { case POINTTYPE: return (LWGEOM*)lwpoint_from_wkb_state(s); break; case LINETYPE: return (LWGEOM*)lwline_from_wkb_state(s); break; case CIRCSTRINGTYPE: return (LWGEOM*)lwcircstring_from_wkb_state(s); break; case POLYGONTYPE: return (LWGEOM*)lwpoly_from_wkb_state(s); break; case TRIANGLETYPE: return (LWGEOM*)lwtriangle_from_wkb_state(s); break; case CURVEPOLYTYPE: return (LWGEOM*)lwcurvepoly_from_wkb_state(s); break; case MULTIPOINTTYPE: case MULTILINETYPE: case MULTIPOLYGONTYPE: case COMPOUNDTYPE: case MULTICURVETYPE: case MULTISURFACETYPE: case POLYHEDRALSURFACETYPE: case TINTYPE: case COLLECTIONTYPE: return (LWGEOM*)lwcollection_from_wkb_state(s); break; /* Unknown type! */ default: lwerror("Unsupported geometry type: %s [%d]", lwtype_name(s->lwtype), s->lwtype); } /* Return value to keep compiler happy. */ return NULL; }