#include "liblwgeom_internal.h"
#include "liblwgeom.h"
-#include "lwout_twkb.c"
+#include "varint.h"
#include "cu_tester.h"
-
-static void do_test_unsigned_varint(uint64_t nr,int expected_size, char* expected_res)
+static void do_test_s32_varint(int32_t nr,int expected_size, char* expected_res)
{
uint8_t buf[8];
int size;
+ char *hex;
- size = u_getvarint_size(nr);
+ size = varint_s32_encoded_size(nr);
CU_ASSERT_EQUAL(size,expected_size);
- u_varint_to_twkb_buf(nr, buf);
- CU_ASSERT_STRING_EQUAL( hexbytes_from_bytes(buf,size),expected_res);
+ varint_s32_encode_buf(nr, buf);
+ hex = hexbytes_from_bytes(buf,size);
+ if ( strcmp(hex,expected_res) ) {
+ printf("Expected: %s\nObtained: %s\n", expected_res, hex);
+ }
+ CU_ASSERT_STRING_EQUAL(hex, expected_res);
+ lwfree(hex);
}
-static void do_test_signed_varint(uint64_t nr,int expected_size, char* expected_res)
+static void do_test_u64_varint(uint64_t nr,int expected_size, char* expected_res)
{
uint8_t buf[8];
int size;
+ char *hex;
- size = u_getvarint_size(nr);
+ size = varint_u64_encoded_size(nr);
CU_ASSERT_EQUAL(size,expected_size);
- s_varint_to_twkb_buf(nr, buf);
- CU_ASSERT_STRING_EQUAL( hexbytes_from_bytes(buf,size),expected_res);
+ varint_u64_encode_buf(nr, buf);
+ hex = hexbytes_from_bytes(buf,size);
+ if ( strcmp(hex,expected_res) ) {
+ printf("Expected: %s\nObtained: %s\n", expected_res, hex);
+ }
+ CU_ASSERT_STRING_EQUAL(hex, expected_res);
+ lwfree(hex);
}
+static void do_test_s64_varint(int64_t nr,int expected_size, char* expected_res)
+{
+ uint8_t buf[8];
+ int size;
+ char *hex;
+
+ size = varint_s64_encoded_size(nr);
+ CU_ASSERT_EQUAL(size,expected_size);
+ varint_s64_encode_buf(nr, buf);
+ hex = hexbytes_from_bytes(buf,size);
+ if ( strcmp(hex,expected_res) ) {
+ printf("Expected: %s\nObtained: %s\n", expected_res, hex);
+ }
+ CU_ASSERT_STRING_EQUAL(hex, expected_res);
+ lwfree(hex);
+}
static void test_varint(void)
{
- do_test_unsigned_varint(1,1, "01");
- do_test_unsigned_varint(300,2, "AC02");
- do_test_unsigned_varint(150,2, "9601");
+ do_test_u64_varint(1, 1, "01");
+ do_test_u64_varint(300, 2, "AC02");
+ do_test_u64_varint(150, 2, "9601");
- do_test_signed_varint(1,1, "02");
+ do_test_s64_varint(1, 1, "02");
+ do_test_s64_varint(-1, 1, "01");
+ do_test_s64_varint(-2, 1, "03");
+#if 0 /* FIXME! */
+ do_test_s64_varint(2147483647, 4, "FFFFFFFE");
+ do_test_s64_varint(-2147483648, 4, "FFFFFFFF");
+#endif
+
+ /* TODO: test signed/unsigned 32bit varints */
}
**********************************************************************/
#include "lwout_twkb.h"
-
+#include "varint.h"
/*
* GeometryType
return buf + 1;
}
-/**
-Encodes a value as varInt described here:
-https://developers.google.com/protocol-buffers/docs/encoding#varints
-*/
-int s_getvarint_size(int64_t val)
-{
-
- LWDEBUGF(2, "Entered s_getvarint_size",0);
- if(val<min_s_varint||val>max_s_varint)
- lwerror("Value is out of range for signed varint (%ld to %ld)",min_s_varint, max_s_varint);
- uint64_t q;
- int n=0;
-
- q = (val << 1) ^ (val >> 63);
- while ((q>>(7*(n+1))) >0)
- {
- n++;
- }
- n++;
- return n;
-}
-
-/**
-Encodes a value as signed varInt
-https://developers.google.com/protocol-buffers/docs/encoding#varints
-*/
-int u_getvarint_size(uint64_t val)
-{
- LWDEBUGF(2, "Entered u_getvarint_size",0);
-
- if(val>max_varint)
- lwerror("Value is out of range for unsigned varint (0 to %ld)", max_varint);
- uint64_t q;
- int n=0;
- q =val;
- while ((q>>(7*(n+1))) >0)
- {
- n++;
- }
- n++;
- return n;
-}
-
-/**
-Function for encoding a value as varInt and putting it in the buffer
-*/
-static uint8_t* u_varint_to_twkb_buf(uint64_t val, uint8_t *buf)
-{
- LWDEBUGF(2, "Entered u_varint_to_twkb_buf",0);
- LWDEBUGF(4, "Writing value %d",val);
- uint64_t q;
- int n,grp;
- q =val;
- n=0;
-
- while ((q>>(7*(n+1))) >0)
- {
- grp=128^(127&(q>>(7*n)));
- buf[n]=grp;
- n++;
- }
- grp=127&(q>>(7*n));
- buf[n]=grp;
- n++;
-
- return buf+=n;
-}
-
-/**
-Function for encoding a varInt value as signed
-*/
-static uint8_t* s_varint_to_twkb_buf(int64_t val, uint8_t *buf)
-{
- LWDEBUGF(2, "Entered s_varint_to_twkb_buf",0);
- LWDEBUGF(4, "Writing value %d",val);
- uint64_t q;
- q = (val << 1) ^ (val >> 63);
-
- return u_varint_to_twkb_buf(q, buf);
-}
-
-
/*
* Empty
*/
/* Endian flag/precision + id + type number + npoints*/
size_t size = WKB_BYTE_SIZE + WKB_BYTE_SIZE;
/*size of ID*/
- size += s_getvarint_size((int64_t) id);
+ size += varint_s64_encoded_size((int64_t) id);
/*size of npoints*/
- size += u_getvarint_size((uint64_t) 0);
+ size += varint_u64_encoded_size((uint64_t) 0);
return size;
}
buf = uint8_to_twkb_buf(flag,buf);
/* Set the geometry id */
- buf = s_varint_to_twkb_buf(id, buf);
+ buf = varint_s64_encode_buf(id, buf);
/* Set the geometry type */
buf = uint8_to_twkb_buf(wkb_type,buf);
/* Set nrings/npoints/ngeoms to zero */
- buf = u_varint_to_twkb_buf(0, buf);
+ buf = varint_u64_encode_buf(0, buf);
return buf;
}
if ( ! ( variant & WKB_NO_NPOINTS ) )
{
LWDEBUGF(4, "We add space for npoints",0);
- size+=u_getvarint_size(pa->npoints);
+ size+=varint_u64_encoded_size(pa->npoints);
}
LWDEBUGF(4, "Refvalue dim 1 is %d",accum_rel[0]);
LWDEBUGF(4, "dim nr %d, refvalue is %d",j, accum_rel[j]);
r=(int64_t) lround(factor*dbl_ptr[j]-accum_rel[j]);
accum_rel[j]+=r;
- size += s_getvarint_size((int64_t) r);
+ size += varint_s64_encoded_size((int64_t) r);
LWDEBUGF(4, "deltavalue = %d and resulting refvalue is %d",r,accum_rel[j]);
}
}
/* Set the number of points (if it's not a POINT type) */
if ( ! ( variant & WKB_NO_NPOINTS ) )
{
- buf = u_varint_to_twkb_buf(pa->npoints,buf);
+ buf = varint_u64_encode_buf(pa->npoints,buf);
LWDEBUGF(4, "Register npoints:%d",pa->npoints);
}
r=(int64_t) lround(factor*dbl_ptr[j]-accum_rel[j]);
LWDEBUGF(4, "deltavalue: %d, ",r );
accum_rel[j]+=r;
- //add the actual coordinate
- //s= getvarint((long) r, &ret, LW_TRUE);
- //memcpy(buf, &ret, s);
- //buf+=s;
- buf = s_varint_to_twkb_buf(r,buf);
+ buf = varint_s64_encode_buf(r,buf);
}
}
//LWDEBUGF(4, "Done (buf = %p)", buf);
/*One byte for type declaration*/
size_t size = WKB_BYTE_SIZE;
/*One integer holding number of geometries*/
- size += u_getvarint_size((uint64_t) n);
+ size += varint_u64_encoded_size((uint64_t) n);
int i;
for (i=0;i<n;i++)
size_t size = 0;
/* geometry id, if not subgeometry in type 4,5 or 6*/
if (variant & TWKB_ID)
- size += s_getvarint_size((int64_t) id);
+ size += varint_s64_encoded_size((int64_t) id);
/* Points */
size += ptarray_to_twkb_size(pt->point, variant | WKB_NO_NPOINTS, prec,refpoint,method);
buf = uint8_to_twkb_buf(type_flag,buf);
/* Set number of geometries */
- buf = u_varint_to_twkb_buf(n, buf);
+ buf = varint_u64_encode_buf(n, buf);
for (i=0;i<n;i++)
{
/* Set the geometry id, if not subgeometry in type 4,5 or 6*/
if (variant & TWKB_ID)
- buf = s_varint_to_twkb_buf(id, buf);
+ buf = varint_s64_encode_buf(id, buf);
/* Set the coordinates */
/*One byte for type declaration*/
size_t size = WKB_BYTE_SIZE;
/*One integer holding number of lines*/
- size += u_getvarint_size((uint64_t) n);
+ size += varint_u64_encoded_size((uint64_t) n);
int i;
for (i=0;i<n;i++)
{
size_t size = 0;
/* geometry id, if not subgeometry in type 4,5 or 6*/
if (variant & TWKB_ID)
- size += s_getvarint_size((int64_t) id);
+ size += varint_s64_encoded_size((int64_t) id);
/* Size of point array */
size += ptarray_to_twkb_size(line->points,variant,prec,refpoint,method);
buf = uint8_to_twkb_buf(type_flag,buf);
/* Set number of geometries */
- buf = u_varint_to_twkb_buf(n, buf);
+ buf = varint_u64_encode_buf(n, buf);
for (i=0;i<n;i++)
{
li=(geom_array+i);
/* Set the geometry id, if not subgeometry in type 4,5 or 6*/
if (variant & TWKB_ID)
- buf = s_varint_to_twkb_buf(id, buf);
+ buf = varint_s64_encode_buf(id, buf);
/* Set the coordinates */
/*One byte for type declaration*/
size_t size = WKB_BYTE_SIZE;
/*One integer holding number of collections*/
- size +=u_getvarint_size((uint64_t) n);
+ size +=varint_u64_encoded_size((uint64_t) n);
int i;
for (i=0;i<n;i++)
{
size_t size = 0;
/* geometry id, if not subgeometry in type 4,5 or 6*/
if (variant & TWKB_ID)
- size += s_getvarint_size((int64_t) id);
+ size += varint_s64_encoded_size((int64_t) id);
/*nrings*/
- size += u_getvarint_size((uint64_t) poly->nrings);
+ size += varint_u64_encoded_size((uint64_t) poly->nrings);
LWDEBUGF(2, "we have %d rings to iterate",poly->nrings);
for ( i = 0; i < poly->nrings; i++ )
LWDEBUGF(4, "Writing ndims '%d'", dims);
buf = uint8_to_twkb_buf(type_flag,buf);
/* Set number of geometries */
- buf = u_varint_to_twkb_buf(n, buf);
+ buf = varint_u64_encode_buf(n, buf);
for (i=0;i<n;i++)
{
/* Set the geometry id, if not subgeometry in type 4,5 or 6*/
if (variant & TWKB_ID)
- buf = s_varint_to_twkb_buf(id, buf);
+ buf = varint_s64_encode_buf(id, buf);
/* Set the number of rings */
- buf = u_varint_to_twkb_buf(poly->nrings, buf);
+ buf = varint_u64_encode_buf(poly->nrings, buf);
for ( i = 0; i < poly->nrings; i++ )
{
/*One byte for type declaration*/
size_t size = WKB_BYTE_SIZE;
/*One integer holding number of collections*/
- size += u_getvarint_size((uint64_t) n);
+ size += varint_u64_encoded_size((uint64_t) n);
int i;
for (i=0;i<n;i++)
{
size_t size = 0;
/* geometry id, if not subgeometry in type 4,5 or 6*/
if (variant & TWKB_ID)
- size += s_getvarint_size((int64_t) id);
+ size += varint_s64_encoded_size((int64_t) id);
/* size of geoms */
- size += u_getvarint_size((uint64_t) col->ngeoms);
+ size += varint_u64_encoded_size((uint64_t) col->ngeoms);
int i = 0;
for ( i = 0; i < col->ngeoms; i++ )
LWDEBUGF(4, "Writing ndims '%d'", dims);
buf = uint8_to_twkb_buf(type_flag,buf);
/* Set number of geometries */
- buf = u_varint_to_twkb_buf(n, buf);
+ buf = varint_u64_encode_buf(n, buf);
for (i=0;i<n;i++)
{
/* Set the geometry id, if not subgeometry in type 4,5 or 6*/
if (variant & TWKB_ID)
- buf = s_varint_to_twkb_buf(id, buf);
+ buf = varint_s64_encode_buf(id, buf);
/* Set the number of rings */
- buf = u_varint_to_twkb_buf(col->ngeoms, buf);
+ buf = varint_u64_encode_buf(col->ngeoms, buf);
/* Write the sub-geometries. Sub-geometries do not get SRIDs, they
inherit from their parents. */
for ( i = 0; i < col->ngeoms; i++ )
if(chk_homogenity==0)
return NULL;
if(chk_homogenity>1)
- buf_size = 2+u_getvarint_size((uint64_t) chk_homogenity);
+ buf_size = 2+varint_u64_encoded_size((uint64_t) chk_homogenity);
else
buf_size=1;
buf = uint8_to_twkb_buf(type_flag,buf);
/* Set number of geometries */
- buf = u_varint_to_twkb_buf(chk_homogenity, buf);
+ buf = varint_u64_encode_buf(chk_homogenity, buf);
}
/* Write the WKB into the output buffer
--- /dev/null
+/**********************************************************************
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.net
+ *
+ * Copyright (C) 2014 Sandro Santilli <strk@keybit.net>
+ * Copyright (C) 2013 Nicklas Avén
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************
+ *
+ * Handle varInt values, as described here:
+ * http://developers.google.com/protocol-buffers/docs/encoding#varints
+ *
+ **********************************************************************/
+
+#include "varint.h"
+#include "lwgeom_log.h"
+#include "liblwgeom.h"
+
+/**
+ * Constants to find the range of Varint.
+ * Since Varint only uses 7 bits instead of 8 in each byte a 8 byte varint
+ * only uses 56 bits for the number and 8 for telling if next byte is used
+ */
+const int64_t varint_u64_max = ((int64_t) 1<<56) - 1;
+const int64_t varint_s64_min = (int64_t) -1<<55;
+const int64_t varint_s64_max = ((int64_t)1<<55) - 1;
+const int32_t varint_u32_max = ((int32_t) 1<<28) - 1;
+const int32_t varint_s32_min = (int32_t) -1<<27;
+const int32_t varint_s32_max = ((int32_t)1<<27) - 1;
+
+static unsigned
+_varint_u64_encoded_size(uint64_t q)
+{
+ int n=0;
+ while ((q>>(7*(n+1))) >0) ++n;
+ return ++n;
+}
+
+static uint8_t*
+_varint_u64_encode_buf(uint64_t q, uint8_t *buf)
+{
+ int n=0, grp;
+ while ((q>>(7*(n+1))) >0)
+ {
+ grp=128^(127&(q>>(7*n)));
+ buf[n++]=grp;
+ }
+ grp=127&(q>>(7*n));
+ buf[n++]=grp;
+
+ return buf+=n;
+}
+
+unsigned
+varint_u32_encoded_size(uint32_t val)
+{
+ LWDEBUGF(2, "Entered varint_u32_encoded_size, value %u", val);
+
+ if( val>varint_u32_max ) {
+ lwerror("Value is out of range for unsigned 32bit varint (0 to %ld)",
+ varint_u32_max);
+ }
+
+ return _varint_u64_encoded_size(val); /* implicit upcast to 64bit int */
+}
+
+uint8_t*
+varint_u32_encode_buf(uint32_t val, uint8_t *buf)
+{
+ LWDEBUGF(2, "Entered varint_u32_encode_buf, value %u", val);
+ return _varint_u64_encode_buf(val, buf); /* implicit upcast to 64bit */
+}
+
+unsigned
+varint_s32_encoded_size(int32_t val)
+{
+ LWDEBUGF(2, "Entered varint_s32_encoded_size, value %d", val);
+
+ if(val<varint_s32_min||val>varint_s32_max) {
+ lwerror("Value is out of range for signed 32bit varint (%d to %d)",
+ varint_s32_min, varint_s32_max);
+ }
+
+ uint32_t q = (val << 1) ^ (val >> 31); /* zig-zag encode */
+ return _varint_u64_encoded_size(q); /* implicit upcast to 64bit int */
+}
+
+uint8_t*
+varint_s32_encode_buf(int32_t val, uint8_t *buf)
+{
+ LWDEBUGF(2, "Entered varint_s32_encode_buf, value %d", val);
+ uint32_t q = (val << 1) ^ (val >> 31); /* zig-zag encode */
+ return _varint_u64_encode_buf(q, buf); /* implicit upcast to 64bit */
+}
+
+unsigned
+varint_s64_encoded_size(int64_t val)
+{
+ LWDEBUGF(2, "Entered varint_s64_encoded_size, value %ld", val);
+
+ if(val<varint_s64_min||val>varint_s64_max) {
+ lwerror("Value is out of range for signed 64bit varint (%ld to %ld)",
+ varint_s64_min, varint_s64_max);
+ }
+
+ uint64_t q = (val << 1) ^ (val >> 63); /* zig-zag encode */
+ return _varint_u64_encoded_size(q);
+}
+
+uint8_t*
+varint_s64_encode_buf(int64_t val, uint8_t *buf)
+{
+ LWDEBUGF(2, "Entered varint_s64_encode_buf, value %ld", val);
+
+ uint64_t q = (val << 1) ^ (val >> 63); /* zig-zag encode */
+ return _varint_u64_encode_buf(q, buf);
+}
+
+unsigned
+varint_u64_encoded_size(uint64_t val)
+{
+ LWDEBUGF(2, "Entered varint_u64_encoded_size, value %lu", val);
+
+ if( val>varint_u64_max ) {
+ lwerror("Value is out of range for unsigned 64bit varint (0 to %ld)",
+ varint_u64_max);
+ }
+
+ return _varint_u64_encoded_size(val);
+}
+
+uint8_t*
+varint_u64_encode_buf(uint64_t val, uint8_t *buf)
+{
+ LWDEBUGF(2, "Entered varint_u64_encode_buf, value %lu", val);
+ return _varint_u64_encode_buf(val, buf);
+}