cu_algorithm.o \
cu_print.o \
cu_wkt.o \
+ cu_wkb.o \
cu_geodetic.o \
cu_measures.o \
cu_libgeom.o \
extern CU_SuiteInfo algorithms_suite;
extern CU_SuiteInfo measures_suite;
extern CU_SuiteInfo wkt_suite;
+extern CU_SuiteInfo wkb_suite;
extern CU_SuiteInfo libgeom_suite;
extern CU_SuiteInfo geodetic_suite;
extern CU_SuiteInfo homogenize_suite;
algorithms_suite,
measures_suite,
wkt_suite,
+ wkb_suite,
libgeom_suite,
geodetic_suite,
homogenize_suite,
--- /dev/null
+/**********************************************************************
+ * $Id$
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ * Copyright 2010 Olivier Courtin <olivier.courtin@oslandia.com>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "CUnit/Basic.h"
+
+#include "libgeom.h"
+#include "cu_tester.h"
+
+/*
+** Global variable to hold WKB strings
+*/
+char *s;
+
+/*
+** The suite initialization function.
+** Create any re-used objects.
+*/
+static int init_wkb_suite(void)
+{
+ s = NULL;
+ return 0;
+}
+
+/*
+** The suite cleanup function.
+** Frees any global objects.
+*/
+static int clean_wkb_suite(void)
+{
+ free(s);
+ s = NULL;
+ return 0;
+}
+
+static char* cu_wkb(char *wkt, uchar variant)
+{
+ LWGEOM *g = lwgeom_from_ewkt(wkt, PARSER_CHECK_NONE);
+ if ( s ) free(s);
+ s = lwgeom_to_wkb(g, variant | WKB_HEX, NULL);
+ lwgeom_free(g);
+ return s;
+}
+
+static void test_wkb_point(void)
+{
+ //printf("%s\n", cu_wkb("POINT(0 0 0 0)", WKB_ISO ));
+}
+
+static void test_wkb_linestring(void){}
+
+static void test_wkb_polygon(void){}
+
+static void test_wkb_multipoint(void){}
+
+static void test_wkb_multilinestring(void){}
+
+static void test_wkb_multipolygon(void){}
+
+static void test_wkb_collection(void){}
+
+static void test_wkb_circularstring(void){}
+
+static void test_wkb_compoundcurve(void){}
+
+static void test_wkb_curvpolygon(void){}
+
+static void test_wkb_multicurve(void){}
+
+static void test_wkb_multisurface(void){}
+
+
+/*
+** Used by test harness to register the tests in this file.
+*/
+
+CU_TestInfo wkb_tests[] = {
+ PG_TEST(test_wkb_point),
+ PG_TEST(test_wkb_linestring),
+ PG_TEST(test_wkb_polygon),
+ PG_TEST(test_wkb_multipoint),
+ PG_TEST(test_wkb_multilinestring),
+ PG_TEST(test_wkb_multipolygon),
+ PG_TEST(test_wkb_collection),
+ PG_TEST(test_wkb_circularstring),
+ PG_TEST(test_wkb_compoundcurve),
+ PG_TEST(test_wkb_curvpolygon),
+ PG_TEST(test_wkb_multicurve),
+ PG_TEST(test_wkb_multisurface),
+ CU_TEST_INFO_NULL
+};
+CU_SuiteInfo wkb_suite = {"WKB Suite", init_wkb_suite, clean_wkb_suite, wkb_tests};
#define WKT_ISO 0x01
#define WKT_SFSQL 0x02
#define WKT_EXTENDED 0x04
-#define WKT_NOTYPE 0x08
-#define WKT_NOPARENS 0x10
+#define WKT_NO_TYPE 0x08 /* Internal use only */
+#define WKT_NO_PARENS 0x10 /* Internal use only */
/**
* Well-Known Binary (WKB) Output Variant Types
#define WKB_SFSQL 0x02
#define WKB_EXTENDED 0x04
#define WKB_NDR 0x08
+#define WKB_HEX 0x10
+#define WKB_NO_NPOINTS 0x20 /* Internal use only */
/**
* Maximum allowed SRID value.
#define WKB_INT_SIZE 4
#define WKB_BYTE_SIZE 1
+/**
+* Look-up table for hex writer
+*/
+static char *hexchr = "0123456789ABCDEF";
+
+
/**
* Optional SRID
*/
{
unsigned int wkb_type = 0;
- uchar type = geom->type;;
+ uchar type = geom->type;
switch( TYPE_GETTYPE(type) )
{
*/
static char* endian_to_wkb_buf(char *buf, uchar variant)
{
- buf[0] = ((variant & WKB_NDR) ? 1 : 0);
- return buf + 1;
+ if( variant & WKB_HEX )
+ {
+ buf[0] = '0';
+ buf[1] = ((variant & WKB_NDR) ? '1' : '0');
+ return buf + 2;
+ }
+ else
+ {
+ buf[0] = ((variant & WKB_NDR) ? 1 : 0);
+ return buf + 1;
+ }
}
+/**
+* SwapBytes?
+*/
+static int wkb_swap_bytes(uchar variant)
+{
+ /* If requested variant matches machine arch, we don't have to swap! */
+ if( ((variant & WKB_NDR) && (BYTE_ORDER == LITTLE_ENDIAN)) ||
+ ((! (variant & WKB_NDR)) && (BYTE_ORDER == BIG_ENDIAN)) )
+ {
+ return LW_FALSE;
+ }
+ return LW_TRUE;
+}
/**
* Integer32
*/
-static char* int32_to_wkb_buf(const int i, char *buf, uchar variant)
+static char* int32_to_wkb_buf(const int ival, char *buf, uchar variant)
{
+ char *iptr = (char*)(&ival);
+ int i = 0;
+
if( sizeof(int) != WKB_INT_SIZE )
{
lwerror("Machine int size is not %d bytes!", WKB_INT_SIZE);
}
- /* If machine arch and requested arch match, don't flip byte order */
- if( ((variant & WKB_NDR) && (BYTE_ORDER == LITTLE_ENDIAN)) ||
- ((! (variant & WKB_NDR)) && (BYTE_ORDER == BIG_ENDIAN)) )
+ LWDEBUGF(4, "Writing value '%d'", ival);
+ if( variant & WKB_HEX )
{
- memcpy(buf, &i, WKB_INT_SIZE);
+ int swap = wkb_swap_bytes(variant);
+ /* Machine/request arch mismatch, so flip byte order */
+ for( i = 0; i < WKB_INT_SIZE; i++ )
+ {
+ int j = (swap ? WKB_INT_SIZE - 1 - i : i);
+ uchar b = iptr[j];
+ /* Top four bits to 0-F */
+ buf[2*i] = hexchr[b >> 4];
+ /* Bottom four bits to 0-F */
+ buf[2*i+1] = hexchr[b & 0x0F];
+ }
+ return buf + (2 * WKB_INT_SIZE);
}
- /* Machine/request arch mismatch, so flip byte order */
else
{
- int j = 0;
- for ( j = 0; j < WKB_INT_SIZE; j++ )
+ /* Machine/request arch mismatch, so flip byte order */
+ if( wkb_swap_bytes(variant) )
+ {
+ for ( i = 0; i < WKB_INT_SIZE; i++ )
+ {
+ buf[i] = iptr[WKB_INT_SIZE - 1 - i];
+ }
+ }
+ /* If machine arch and requested arch match, don't flip byte order */
+ else
{
- buf[j] = (&i)[WKB_INT_SIZE - j];
+ memcpy(buf, iptr, WKB_INT_SIZE);
}
+ return buf + WKB_INT_SIZE;
}
- return buf + WKB_INT_SIZE;
}
/**
*/
static char* double_to_wkb_buf(const double d, char *buf, uchar variant)
{
+ char *dptr = (char*)(&d);
+ int i = 0;
+
if( sizeof(double) != WKB_DOUBLE_SIZE )
{
lwerror("Machine double size is not %d bytes!", WKB_DOUBLE_SIZE);
}
- /* If machine arch and requested arch match, don't flip byte order */
- if( ((variant & WKB_NDR) && (BYTE_ORDER == LITTLE_ENDIAN)) ||
- ((! (variant & WKB_NDR)) && (BYTE_ORDER == BIG_ENDIAN)) )
+
+ if( variant & WKB_HEX )
{
- memcpy(buf, &d, WKB_DOUBLE_SIZE);
+ int swap = wkb_swap_bytes(variant);
+ /* Machine/request arch mismatch, so flip byte order */
+ for( i = 0; i < WKB_DOUBLE_SIZE; i++ )
+ {
+ int j = (swap ? WKB_DOUBLE_SIZE - 1 - i : i);
+ uchar b = dptr[j];
+ /* Top four bits to 0-F */
+ buf[2*i] = hexchr[b >> 4];
+ /* Bottom four bits to 0-F */
+ buf[2*i+1] = hexchr[b & 0x0F];
+ }
+ return buf + (2 * WKB_DOUBLE_SIZE);
}
- /* Machine/request arch mismatch, so flip byte order */
else
{
- int j = 0;
- for ( j = 0; j < WKB_DOUBLE_SIZE; j++ )
+ /* Machine/request arch mismatch, so flip byte order */
+ if( wkb_swap_bytes(variant) )
+ {
+ for ( i = 0; i < WKB_DOUBLE_SIZE; i++ )
+ {
+ buf[i] = dptr[WKB_DOUBLE_SIZE - 1 - i];
+ }
+ }
+ /* If machine arch and requested arch match, don't flip byte order */
+ else
{
- buf[j] = (&d)[WKB_DOUBLE_SIZE - j];
+ memcpy(buf, dptr, WKB_DOUBLE_SIZE);
}
+ return buf + WKB_DOUBLE_SIZE;
}
- return buf + WKB_DOUBLE_SIZE;
}
static size_t ptarray_to_wkb_size(const POINTARRAY *pa, uchar variant)
{
int dims = 2;
+ size_t size = 0;
if( pa->npoints < 1 )
return 0;
if( variant & (WKB_ISO | WKB_EXTENDED) )
dims = TYPE_NDIMS(pa->dims);
+ /* Include the npoints if it's not a POINT type) */
+ if( ! ( variant & WKB_NO_NPOINTS ) )
+ size += WKB_INT_SIZE;
+
/* size of the double list */
- return pa->npoints * dims * WKB_DOUBLE_SIZE;
+ size += pa->npoints * dims * WKB_DOUBLE_SIZE;
+
+ return size;
}
static char* ptarray_to_wkb_buf(const POINTARRAY *pa, char *buf, uchar variant)
if( (variant & WKB_ISO) || (variant & WKB_EXTENDED) )
dims = TYPE_NDIMS(pa->dims);
- /* Set the number of points */
- buf = int32_to_wkb_buf(pa->npoints, buf, variant);
+ /* Set the number of points (if it's not a POINT type) */
+ if( ! ( variant & WKB_NO_NPOINTS ) )
+ buf = int32_to_wkb_buf(pa->npoints, buf, variant);
/* Set the ordinates. */
/* TODO: Ensure that getPoint_internal is always aligned so
the output endian/dims match the internal endian/dims */
for( i = 0; i < pa->npoints; i++ )
{
+ LWDEBUGF(4, "Writing point #%d", i);
dbl_ptr = (double*)getPoint_internal(pa, i);
for( j = 0; j < dims; j++ )
{
+ LWDEBUGF(4, "Writing dimension #%d (buf = %p)", j, buf);
buf = double_to_wkb_buf(dbl_ptr[j], buf, variant);
}
}
+ LWDEBUGF(4, "Done (buf = %p)", buf);
return buf;
}
size += WKB_INT_SIZE;
/* Points */
- size += ptarray_to_wkb_size(pt->point, variant);
+ size += ptarray_to_wkb_size(pt->point, variant | WKB_NO_NPOINTS);
return size;
}
static char* lwpoint_to_wkb_buf(const LWPOINT *pt, char *buf, uchar variant)
{
/* Set the endian flag */
+ LWDEBUGF(4, "Entering function, buf = %p", buf);
buf = endian_to_wkb_buf(buf, variant);
+ LWDEBUGF(4, "Endian set, buf = %p", buf);
/* Set the geometry type */
buf = int32_to_wkb_buf(lwgeom_wkb_type((LWGEOM*)pt, variant), buf, variant);
+ LWDEBUGF(4, "Type set, buf = %p", buf);
/* Set the optional SRID for extended variant */
if ( lwgeom_wkb_needs_srid((LWGEOM*)pt, variant) )
+ {
buf = int32_to_wkb_buf(pt->SRID, buf, variant);
+ LWDEBUGF(4, "SRID set, buf = %p", buf);
+ }
/* Set the coordinates */
- buf = ptarray_to_wkb_buf(pt->point, buf, variant);
+ buf = ptarray_to_wkb_buf(pt->point, buf, variant | WKB_NO_NPOINTS);
+ LWDEBUGF(4, "Pointarray set, buf = %p", buf);
return buf;
}
if ( lwgeom_wkb_needs_srid((LWGEOM*)line, variant) )
size += WKB_INT_SIZE;
- /* Number of points + points */
- size += WKB_INT_SIZE + ptarray_to_wkb_size(line->points, variant);
+ /* Size of point array */
+ size += ptarray_to_wkb_size(line->points, variant);
return size;
}
for( i = 0; i < poly->nrings; i++ )
{
- /* number of points + points */
- size += WKB_INT_SIZE + ptarray_to_wkb_size(poly->rings[i], variant);
+ /* Size of ring point array */
+ size += ptarray_to_wkb_size(poly->rings[i], variant);
}
return size;
default:
lwerror("Unsupported geometry type: %s [%d]", lwgeom_typename(geom->type), TYPE_GETTYPE(geom->type));
}
- /* Return value to keep compiler happy. */
- return 0;
+
+ return size;
}
static char* lwgeom_to_wkb_buf(const LWGEOM *geom, char *buf, uchar variant)
if( geom == NULL )
{
+ LWDEBUG(4,"Cannot convert NULL into WKB.");
lwerror("Cannot convert NULL into WKB.");
return NULL;
}
if( buf_size == 0 )
{
+ LWDEBUG(4,"Error calculating output WKB buffer size.");
lwerror("Error calculating output WKB buffer size.");
return NULL;
}
-
+
+ /* Hex string takes twice as much space as binary + a null character */
+ if( variant & WKB_HEX )
+ {
+ buf_size = 2 * buf_size + 1;
+ LWDEBUGF(4, "Hex WKB output size: %d", buf_size);
+ }
+
+ /* Allocate the buffer */
buf = lwalloc(buf_size);
if( buf == NULL )
{
+ LWDEBUGF(4,"Unable to allocate %d bytes for WKB output buffer.", buf_size);
lwerror("Unable to allocate %d bytes for WKB output buffer.", buf_size);
return NULL;
}
/* Write the WKB into the output buffer */
buf = lwgeom_to_wkb_buf(geom, buf, variant);
- /* The buffer pointer should land at the end of the allocated buffer space. Let's check. */
+ /* Null the last byte if this is a hex output */
+ *buf = '\0';
+ buf++;
+
+ LWDEBUGF(4,"buf (%p) - wkb_out (%p) = %d", buf, wkb_out, buf - wkb_out);
+
+ /* The buffer pointer should now land at the end of the allocated buffer space. Let's check. */
if( buf_size != (buf - wkb_out) )
{
+ LWDEBUG(4,"Output WKB is not the same size as the allocated buffer.");
lwerror("Output WKB is not the same size as the allocated buffer.");
lwfree(wkb_out);
return NULL;
dimensions = TYPE_NDIMS(ptarray->dims);
/* Opening paren? */
- if( ! (variant & WKT_NOPARENS) )
+ if( ! (variant & WKT_NO_PARENS) )
stringbuffer_append(sb, "(");
/* Digits and commas */
}
/* Closing paren? */
- if( ! (variant & WKT_NOPARENS) )
+ if( ! (variant & WKT_NO_PARENS) )
stringbuffer_append(sb, ")");
}
*/
static void lwpoint_to_wkt_sb(const LWPOINT *pt, stringbuffer_t *sb, int precision, uchar variant)
{
- if( ! (variant & WKT_NOTYPE) )
+ if( ! (variant & WKT_NO_TYPE) )
{
stringbuffer_append(sb, "POINT"); /* "POINT" */
dimension_qualifiers_to_wkt_sb((LWGEOM*)pt, sb, variant);
*/
static void lwline_to_wkt_sb(const LWLINE *line, stringbuffer_t *sb, int precision, uchar variant)
{
- if( ! (variant & WKT_NOTYPE) )
+ if( ! (variant & WKT_NO_TYPE) )
{
stringbuffer_append(sb, "LINESTRING"); /* "LINESTRING" */
dimension_qualifiers_to_wkt_sb((LWGEOM*)line, sb, variant);
static void lwpoly_to_wkt_sb(const LWPOLY *poly, stringbuffer_t *sb, int precision, uchar variant)
{
int i = 0;
- if( ! (variant & WKT_NOTYPE) )
+ if( ! (variant & WKT_NO_TYPE) )
{
stringbuffer_append(sb, "POLYGON"); /* "POLYGON" */
dimension_qualifiers_to_wkt_sb((LWGEOM*)poly, sb, variant);
*/
static void lwcircstring_to_wkt_sb(const LWCIRCSTRING *circ, stringbuffer_t *sb, int precision, uchar variant)
{
- if( ! (variant & WKT_NOTYPE) )
+ if( ! (variant & WKT_NO_TYPE) )
{
stringbuffer_append(sb, "CIRCULARSTRING"); /* "CIRCULARSTRING" */
dimension_qualifiers_to_wkt_sb((LWGEOM*)circ, sb, variant);
static void lwmpoint_to_wkt_sb(const LWMPOINT *mpoint, stringbuffer_t *sb, int precision, uchar variant)
{
int i = 0;
- if( ! (variant & WKT_NOTYPE) )
+ if( ! (variant & WKT_NO_TYPE) )
{
stringbuffer_append(sb, "MULTIPOINT"); /* "MULTIPOINT" */
dimension_qualifiers_to_wkt_sb((LWGEOM*)mpoint, sb, variant);
if( i > 0 )
stringbuffer_append(sb, ",");
/* We don't want type strings or parens on our subgeoms */
- lwpoint_to_wkt_sb(mpoint->geoms[i], sb, precision, variant | WKT_NOPARENS | WKT_NOTYPE );
+ lwpoint_to_wkt_sb(mpoint->geoms[i], sb, precision, variant | WKT_NO_PARENS | WKT_NO_TYPE );
}
stringbuffer_append(sb, ")");
}
{
int i = 0;
- if( ! (variant & WKT_NOTYPE) )
+ if( ! (variant & WKT_NO_TYPE) )
{
stringbuffer_append(sb, "MULTILINESTRING"); /* "MULTILINESTRING" */
dimension_qualifiers_to_wkt_sb((LWGEOM*)mline, sb, variant);
if( i > 0 )
stringbuffer_append(sb, ",");
/* We don't want type strings on our subgeoms */
- lwline_to_wkt_sb(mline->geoms[i], sb, precision, variant | WKT_NOTYPE );
+ lwline_to_wkt_sb(mline->geoms[i], sb, precision, variant | WKT_NO_TYPE );
}
stringbuffer_append(sb, ")");
}
{
int i = 0;
- if( ! (variant & WKT_NOTYPE) )
+ if( ! (variant & WKT_NO_TYPE) )
{
stringbuffer_append(sb, "MULTIPOLYGON"); /* "MULTIPOLYGON" */
dimension_qualifiers_to_wkt_sb((LWGEOM*)mpoly, sb, variant);
if( i > 0 )
stringbuffer_append(sb, ",");
/* We don't want type strings on our subgeoms */
- lwpoly_to_wkt_sb(mpoly->geoms[i], sb, precision, variant | WKT_NOTYPE );
+ lwpoly_to_wkt_sb(mpoly->geoms[i], sb, precision, variant | WKT_NO_TYPE );
}
stringbuffer_append(sb, ")");
}
{
int i = 0;
- if( ! (variant & WKT_NOTYPE) )
+ if( ! (variant & WKT_NO_TYPE) )
{
stringbuffer_append(sb, "COMPOUNDCURVE"); /* "COMPOUNDCURVE" */
dimension_qualifiers_to_wkt_sb((LWGEOM*)comp, sb, variant);
/* Linestring subgeoms don't get type identifiers */
if( type == LINETYPE )
{
- lwline_to_wkt_sb((LWLINE*)comp->geoms[i], sb, precision, variant | WKT_NOTYPE );
+ lwline_to_wkt_sb((LWLINE*)comp->geoms[i], sb, precision, variant | WKT_NO_TYPE );
}
/* But circstring subgeoms *do* get type identifiers */
else if( type == CIRCSTRINGTYPE )
{
int i = 0;
- if( ! (variant & WKT_NOTYPE) )
+ if( ! (variant & WKT_NO_TYPE) )
{
stringbuffer_append(sb, "CURVEPOLYGON"); /* "CURVEPOLYGON" */
dimension_qualifiers_to_wkt_sb((LWGEOM*)cpoly, sb, variant);
{
case LINETYPE:
/* Linestring subgeoms don't get type identifiers */
- lwline_to_wkt_sb((LWLINE*)cpoly->rings[i], sb, precision, variant | WKT_NOTYPE );
+ lwline_to_wkt_sb((LWLINE*)cpoly->rings[i], sb, precision, variant | WKT_NO_TYPE );
break;
case CIRCSTRINGTYPE:
/* But circstring subgeoms *do* get type identifiers */
{
int i = 0;
- if( ! (variant & WKT_NOTYPE) )
+ if( ! (variant & WKT_NO_TYPE) )
{
stringbuffer_append(sb, "MULTICURVE"); /* "MULTICURVE" */
dimension_qualifiers_to_wkt_sb((LWGEOM*)mcurv, sb, variant);
{
case LINETYPE:
/* Linestring subgeoms don't get type identifiers */
- lwline_to_wkt_sb((LWLINE*)mcurv->geoms[i], sb, precision, variant | WKT_NOTYPE );
+ lwline_to_wkt_sb((LWLINE*)mcurv->geoms[i], sb, precision, variant | WKT_NO_TYPE );
break;
case CIRCSTRINGTYPE:
/* But circstring subgeoms *do* get type identifiers */
{
int i = 0;
- if( ! (variant & WKT_NOTYPE) )
+ if( ! (variant & WKT_NO_TYPE) )
{
stringbuffer_append(sb, "MULTISURFACE"); /* "MULTISURFACE" */
dimension_qualifiers_to_wkt_sb((LWGEOM*)msurf, sb, variant);
{
case POLYGONTYPE:
/* Linestring subgeoms don't get type identifiers */
- lwpoly_to_wkt_sb((LWPOLY*)msurf->geoms[i], sb, precision, variant | WKT_NOTYPE );
+ lwpoly_to_wkt_sb((LWPOLY*)msurf->geoms[i], sb, precision, variant | WKT_NO_TYPE );
break;
case CURVEPOLYTYPE:
/* But circstring subgeoms *do* get type identifiers */
{
int i = 0;
- if( ! (variant & WKT_NOTYPE) )
+ if( ! (variant & WKT_NO_TYPE) )
{
stringbuffer_append(sb, "GEOMETRYCOLLECTION"); /* "GEOMETRYCOLLECTION" */
dimension_qualifiers_to_wkt_sb((LWGEOM*)collection, sb, variant);