return result; //error
}
- size = sizeof(double)*2; // x,y
- if (pa->is3d)
- size += sizeof(double); //(x,y) & z
+ size = pointArray_ptsize(pa);
// this does x,y
memcpy(&result.x, &pa->serialized_pointlist[size*n],sizeof(double)*2 );
return ; //error
}
- size = sizeof(double)*2; // x,y
- if (pa->is3d)
- size += sizeof(double); //(x,y) & z
+ size = pointArray_ptsize(pa);
// this does x,y
memcpy(point, &pa->serialized_pointlist[size*n],sizeof(double)*2 );
return result; //error
}
- size = sizeof(double)*2; // x,y
- if (pa->is3d)
- size += sizeof(double); //(x,y) & z
+ size = pointArray_ptsize(pa);
// this does x,y
memcpy(&result.x, &pa->serialized_pointlist[size*n],sizeof(double)*2 );
return; //error
}
- size = sizeof(double)*2; // x,y
- if (pa->is3d)
- size += sizeof(double); //(x,y) & z
+ size = pointArray_ptsize(pa);
// this does x,y
memcpy(point, &pa->serialized_pointlist[size*n],sizeof(double)*2 );
POINTARRAY *pa;
pa = (POINTARRAY*)palloc(sizeof(pa));
+ if (is3d>2)
+ elog(ERROR,"pointArray_construct:: called with dims = %i", (int) is3d);
+
pa->is3d = is3d;
pa->npoints = npoints;
pa->serialized_pointlist = points;
bool lwgeom_hasSRID(char type)
{
- return (type & 0x20);
+ return (type & 0x40);
}
bool lwgeom_is3d(char type)
{
- return (type & 0x10);
+ return ( (type & 0x30) >>4);
}
int lwgeom_getType(char type)
if ( lwgeom_getType(type) != LINETYPE)
+ {
+ elog(ERROR,"lwline_deserialize: attempt to deserialize a line when its not really a line");
return NULL;
+ }
if ( lwgeom_hasSRID(type))
{
result->points = pa;
result->is3d = lwgeom_is3d(type);
+//elog(NOTICE,"npoints in deserialize line = %i",npoints);
return result;
}
int t;
char *loc;
+elog(NOTICE,"lwline_serialize::entry");
hasSRID = (line->SRID != -1);
if (hasSRID)
}
else
{
- size += 16 * line->points->npoints; //x,y,z
+ size += 16 * line->points->npoints; //x,y
}
+ size+=4; // npoints
+
+elog(NOTICE,"lwline_serialize:: size = %i",size);
+
result = palloc(size);
result[0] = lwgeom_makeType(line->is3d,hasSRID, LINETYPE);
loc += 4;
}
+ memcpy(loc, &line->points->npoints, sizeof(int32));
+ loc +=4;
//copy in points
if (line->is3d)
loc += 16; // size of a 2d point
}
}
+ printBYTES((unsigned char *)result, size);
return result;
}
uint32 npoints;
if ( lwgeom_getType(type) != LINETYPE)
- return -9999;
+ elog(ERROR,"lwline_findlength::attempt to find the length of a non-line");
if ( lwgeom_hasSRID(type))
{
// we've read the type (1 byte) and SRID (4 bytes, if present)
npoints = get_uint32(loc);
+elog(NOTICE,"npoint in lwline_findlength= %i",npoints);
+ result += 4; //npoints
+
if (lwgeom_is3d(type) )
{
return result + npoints * 24;
}
nrings = get_uint32(loc);
+ result->nrings = nrings;
loc +=4;
-
+elog(NOTICE,"lwpoly_deserialize:: polygon with %i rings",nrings);
result->rings = (POINTARRAY**) palloc(nrings* sizeof(POINTARRAY*));
for (t =0;t<nrings;t++)
total_points += poly->rings[t]->npoints;
}
if (poly->is3d)
- size += 24*npoints;
+ size += 24*total_points;
else
- size += 16*npoints;
+ size += 16*total_points;
result = palloc(size);
+ elog(NOTICE,"lwpoly_serialize size = %i", size);
result[0] = lwgeom_makeType(poly->is3d,hasSRID, POLYGONTYPE);
loc = result+1;
}
memcpy(loc, &poly->nrings, sizeof(int32)); // nrings
+ loc+=4;
+
+
for (t=0;t<poly->nrings;t++)
{
POINTARRAY *pa = poly->rings[t];
npoints = poly->rings[t]->npoints;
-
+elog(NOTICE,"doing ring #%i with %i points",t,npoints);
memcpy(loc, &npoints, sizeof(int32)); //npoints this ring
loc+=4;
if (poly->is3d)
for (u=0;u<npoints;u++)
{
getPoint3d_p(pa, u, loc);
- loc+= 24*npoints;
+ loc+= 24;
}
}
else
{
for (u=0;u<npoints;u++)
{
+elog(NOTICE,"pt %i",u);
getPoint2d_p(pa, u, loc);
- loc+= 16*npoints;
+ loc+= 16;
}
}
}
+//************************************************
+//** debugging routines
+
+
+void printLWLINE(LWLINE *line)
+{
+ elog(NOTICE,"LWLINE {");
+ elog(NOTICE," is3d = %i", (int)line->is3d);
+ elog(NOTICE," SRID = %i", (int)line->SRID);
+ printPA(line->points);
+ elog(NOTICE,"}");
+}
+
+
+void printPA(POINTARRAY *pa)
+{
+ int t;
+ POINT2D pt2;
+ POINT3D pt3;
+
+ elog(NOTICE," POINTARRAY{");
+ elog(NOTICE," is3d =%i, ptsize=%i", (int) pa->is3d,pointArray_ptsize(pa));
+ elog(NOTICE," npoints = %i", pa->npoints);
+
+ for (t =0; t<pa->npoints;t++)
+ {
+ if (pa->is3d == TWODIMS)
+ {
+ pt2 = getPoint2d(pa,t);
+ elog(NOTICE," %i : %lf,%lf",t,pt2.x,pt2.y);
+ }
+ if (pa->is3d == THREEDIMS)
+ {
+ pt3 = getPoint3d(pa,t);
+ elog(NOTICE," %i : %lf,%lf,%lf",t,pt3.x,pt3.y,pt3.z);
+ }
+ }
+
+ elog(NOTICE," }");
+}
+
+void printBYTES(unsigned char *a, int n)
+{
+ int t;
+ char buff[3];
+
+ buff[2] = 0; //null terminate
+
+ elog(NOTICE," BYTE ARRAY (n=%i) {", n);
+ for (t=0;t<n;t++)
+ {
+ deparse_hex(a[t], buff);
+ elog(NOTICE, " %i : %s", t,buff );
+ }
+ elog(NOTICE, " }");
+}
+
+void printLWPOLY(LWPOLY *poly)
+{
+ int t;
+ elog(NOTICE,"LWPOLY {");
+ elog(NOTICE," is3d = %i", (int)poly->is3d);
+ elog(NOTICE," SRID = %i", (int)poly->SRID);
+ elog(NOTICE," nrings = %i", (int)poly->nrings);
+ for (t=0;t<poly->nrings;t++)
+ {
+ elog(NOTICE," RING # %i :",t);
+ printPA(poly->rings[t]);
+ }
+ elog(NOTICE,"}");
+}
#include "lwgeom.h"
+
+
+#define DEBUG
+
+
+
+
+
extern char *wkb_to_lwgeom(char *wkb, int SRID,int *size);
extern char *lwgeom_to_wkb(char *serialized_form,int *wkblength,char desiredWKBEndian);
extern void swap_char(char *a,char *b);
extern char *lwpoint_to_wkb(LWPOINT *point, char desiredWKBEndian, int *wkbsize);
extern char *lwpoly_to_wkb(LWPOLY *poly, char desiredWKBEndian, int *wkbsize);
+
+extern unsigned char parse_hex(char *str);
+extern void deparse_hex(unsigned char str, unsigned char *result);
+
+
// 3d or 4d. There is NOT a (x,y,m) point type!!!
#define WKB3DOFFSET 0x80000000
#define WKB4DOFFSET 0x40000000
Datum LWGEOMFromWKB(PG_FUNCTION_ARGS);
Datum WKBFromLWGEOM(PG_FUNCTION_ARGS);
+
+Datum LWGEOM_in(PG_FUNCTION_ARGS);
+Datum LWGEOM_out(PG_FUNCTION_ARGS);
+
+
+// WKB structure -- exactly the same as TEXT
+typedef struct Well_known_bin {
+ int32 size; // total size of this structure
+ unsigned char data[1]; //THIS HOLD VARIABLE LENGTH DATA
+} WellKnownBinary;
+
+
+
+PG_FUNCTION_INFO_V1(LWGEOM_in);
+Datum LWGEOM_in(PG_FUNCTION_ARGS)
+{
+ char *str = PG_GETARG_CSTRING(0);
+ WellKnownBinary *wkb;
+ char *result,*lwgeom;
+ int size;
+ int t;
+ int input_str_len;
+
+ int SRID = -1; //default (change)
+
+ input_str_len = strlen(str);
+
+ if ( ( ( (int)(input_str_len/2.0) ) *2.0) != input_str_len)
+ {
+ elog(ERROR,"LWGEOM_in parser - should be even number of characters!");
+ PG_RETURN_NULL();
+ }
+
+ if (strspn(str,"0123456789ABCDEF") != strlen(str) )
+ {
+ elog(ERROR,"WKB_in parser - input contains bad characters. Should only have '0123456789ABCDEF'!");
+ PG_RETURN_NULL();
+ }
+ size = (input_str_len/2) + 4;
+ wkb = (WellKnownBinary *) palloc(size);
+ wkb->size = size;
+
+ for (t=0;t<input_str_len/2;t++)
+ {
+ ((unsigned char *)wkb)[t+4] = parse_hex( &str[t*2]) ;
+ }
+
+ //have WKB string (and we can safely modify it)
+ lwgeom = wkb_to_lwgeom(((char *) wkb)+4, SRID,&size);
+
+ pfree(wkb); // no longer referenced!
+
+ result = palloc(size+4);
+
+ memcpy(result+4, lwgeom, size);
+ size+=4;
+ memcpy(result, &size, 4);
+
+ pfree(lwgeom);
+
+ PG_RETURN_POINTER(result);
+}
+
+PG_FUNCTION_INFO_V1(LWGEOM_out);
+Datum LWGEOM_out(PG_FUNCTION_ARGS)
+{
+ char *lwgeom = (char *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+ char *result;
+ int size_result;
+ int t;
+ int size;
+
+ char *wkb = lwgeom_to_wkb(lwgeom+4,&size,1); // 0=XDR, 1=NDR
+
+ size_result = size *2 +1; //+1 for null char
+ result = palloc (size_result);
+ result[size_result-1] = 0; //null terminate
+
+ for (t=0; t< size; t++)
+ {
+ deparse_hex( ((unsigned char *) wkb)[t], &result[t*2]);
+ }
+
+ pfree(wkb);
+
+ PG_RETURN_CSTRING(result);
+}
+
+
+
// LWGEOMFromWKB(wkb, [SRID] )
PG_FUNCTION_INFO_V1(LWGEOMFromWKB);
Datum LWGEOMFromWKB(PG_FUNCTION_ARGS)
{
char *wkb_input = (char *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
- int SRID ;
+ int SRID = -1;
int size;
char *lwgeom;
char * result;
+ char *wkb_copy;
+
- if ( ! PG_ARGISNULL(1) )
+ if ( ( PG_NARGS()>1) && ( ! PG_ARGISNULL(1) ))
SRID = PG_GETARG_INT32(1);
else
SRID = -1;
- lwgeom = wkb_to_lwgeom(wkb_input, SRID,&size);
+#ifdef DEBUG
+ elog(NOTICE,"LWGEOMFromWKB: entry with SRID=%i\n",SRID);
+#endif
+
+ // need to do this because there might be a bunch of endian flips!
+ wkb_copy = palloc( *((int32 *) wkb_input));
+ memcpy(wkb_copy, wkb_input+4, *((int32 *) wkb_input) -4);
+
+ lwgeom = wkb_to_lwgeom(wkb_copy, SRID,&size);
+
+ pfree(wkb_copy); // no longer referenced!
+
result = palloc(size+4);
memcpy(result+4, lwgeom, size);
dims = wkb_dims(wkbtype);
simpletype = wkb_simpletype(wkbtype);
+#ifdef DEBUG
+ elog(NOTICE,"wkb_to_lwgeom: entry with SRID=%i, dims=%i, simpletype=%i\n",SRID,(int) dims, (int) simpletype);
+#endif
+
+
switch (simpletype)
{
case POINTTYPE:
break;
case LINETYPE:
line = wkb_line_to_lwline(wkb, SRID);
+ printLWLINE(line);
+ elog(NOTICE,"have line with %i points",line->points->npoints);
result = lwline_serialize(line);
+ elog(NOTICE,"serialized it");
*size = lwline_findlength(result);
+ elog(NOTICE,"serialized length=%i",*size);
pfree_line(line);
break;
case POLYGONTYPE:
poly = wkb_poly_to_lwpoly(wkb, SRID);
+ printLWPOLY(poly);
result = lwpoly_serialize(poly);
+ elog(NOTICE,"serialized polygon");
*size = lwpoly_findlength(result);
+ elog(NOTICE,"serialized polygon has length = %i",*size);
pfree_polygon(poly);
break;
case MULTIPOINTTYPE:
case COLLECTIONTYPE:
break;
}
+#ifdef DEBUG
+ elog(NOTICE,"wkb_to_lwgeom:returning");
+#endif
+
return result;
}
dims = wkb_dims(wkbtype);
simpletype = wkb_simpletype(wkbtype);
+#ifdef DEBUG
+ elog(NOTICE,"wkb_point_to_lwpoint: entry with SRID=%i, dims=%i, simpletype=%i\n",SRID,(int) dims, (int) simpletype);
+#endif
+
+
+
+
if (simpletype != POINTTYPE)
elog(ERROR,"WKB::point parser - go wrong type");
pa = pointArray_construct(wkb+5, dims, 1);
+
+
return lwpoint_construct(dims, SRID, pa);
}
flipPoints(wkb+9,npoints,dims);
pa = pointArray_construct(wkb+9, dims, npoints);
-
+printPA(pa);
return lwline_construct(dims, SRID, pa);
}
nrings = get_uint32(wkb+5);
- loc = wkb+5;
+ loc = wkb+9;
//point size
+ ptsize =16;
if (dims == FOURDIMS)
{
ptsize = 32;
// read a ring
if (need_flip)
flipPoints(loc+4,npoints,dims);
-
+elog(NOTICE,"wkb_poly_to_lwpoly:: doing ring %i with %i points", t, npoints);
pa = pointArray_construct(loc+4, dims, npoints);
loc += 4;
LWPOLY *poly;
char *multigeom = NULL;
+#ifdef DEBUG
+ elog(NOTICE,"lwgeom_to_wkb: entry with simpletype=%i, dims=%i\n",(int) simple_type,(int) lwgeom_is3d( serialized_form[0]) );
+#endif
+
switch (simple_type)
{
pfree_line(line);
break;
case POLYGONTYPE:
+ elog(NOTICE,"lwgeom_to_wkb :: deserializing polygon");
poly = lwpoly_deserialize(serialized_form);
+ printLWPOLY(poly);
result = lwpoly_to_wkb(poly, desiredWKBEndian, wkblength);
pfree_polygon(poly );
break;
uint32 wkbtype ;
bool need_flip = requiresflip( desiredWKBEndian );
+#ifdef DEBUG
+ elog(NOTICE,"lwpoint_to_wkb: pa dims = %i\n", (int)pt->point->is3d );
+#endif
+
*wkbsize = 1+ 4+ ptsize; //endian, type, point
result[0] = desiredWKBEndian; //endian flag
wkbtype = constructWKBType(POINTTYPE, pt->point->is3d);
+
+#ifdef DEBUG
+ elog(NOTICE,"lwpoint_to_wkb: entry with wkbtype=%i, pa dims = %i\n",wkbtype, (int)pt->point->is3d );
+#endif
+
+
+
memcpy(result+1, &wkbtype, 4);
if (need_flip)
flip_endian_int32(result+1);
bool need_flip = requiresflip( desiredWKBEndian );
- *wkbsize = 1+ 4+ line->points->npoints * ptsize; //endian, type, points
+printLWLINE(line);
+
+ *wkbsize = 1+ 4+4+ line->points->npoints * ptsize; //endian, type, npoints, points
result = palloc(*wkbsize);
if (need_flip)
flip_endian_int32(result+1);
- memcpy(result+5, line->points->serialized_pointlist, pointArray_ptsize(line->points) * line->points->npoints);
+ memcpy(result+5, &line->points->npoints, 4);
if (need_flip)
- flipPoints(result+5, line->points->npoints, line->points->is3d);
+ flip_endian_int32(result+5);
+
+ memcpy(result+9, line->points->serialized_pointlist, ptsize * line->points->npoints);
+ if (need_flip)
+ flipPoints(result+9, line->points->npoints, line->points->is3d);
return result;
}
return simple_type | 0x40000000;
}
+
+//given one byte, populate result with two byte representing
+// the hex number
+// ie deparse_hex( 255, mystr)
+// -> mystr[0] = 'F' and mystr[1] = 'F'
+// no error checking done
+void deparse_hex(unsigned char str, unsigned char *result)
+{
+ int input_high;
+ int input_low;
+
+ input_high = (str>>4);
+ input_low = (str & 0x0F);
+
+ switch (input_high)
+ {
+ case 0:
+ result[0] = '0';
+ break;
+ case 1:
+ result[0] = '1';
+ break;
+ case 2:
+ result[0] = '2';
+ break;
+ case 3:
+ result[0] = '3';
+ break;
+ case 4:
+ result[0] = '4';
+ break;
+ case 5:
+ result[0] = '5';
+ break;
+ case 6:
+ result[0] = '6';
+ break;
+ case 7:
+ result[0] = '7';
+ break;
+ case 8:
+ result[0] = '8';
+ break;
+ case 9:
+ result[0] = '9';
+ break;
+ case 10:
+ result[0] = 'A';
+ break;
+ case 11:
+ result[0] = 'B';
+ break;
+ case 12:
+ result[0] = 'C';
+ break;
+ case 13:
+ result[0] = 'D';
+ break;
+ case 14:
+ result[0] = 'E';
+ break;
+ case 15:
+ result[0] = 'F';
+ break;
+ }
+
+ switch (input_low)
+ {
+ case 0:
+ result[1] = '0';
+ break;
+ case 1:
+ result[1] = '1';
+ break;
+ case 2:
+ result[1] = '2';
+ break;
+ case 3:
+ result[1] = '3';
+ break;
+ case 4:
+ result[1] = '4';
+ break;
+ case 5:
+ result[1] = '5';
+ break;
+ case 6:
+ result[1] = '6';
+ break;
+ case 7:
+ result[1] = '7';
+ break;
+ case 8:
+ result[1] = '8';
+ break;
+ case 9:
+ result[1] = '9';
+ break;
+ case 10:
+ result[1] = 'A';
+ break;
+ case 11:
+ result[1] = 'B';
+ break;
+ case 12:
+ result[1] = 'C';
+ break;
+ case 13:
+ result[1] = 'D';
+ break;
+ case 14:
+ result[1] = 'E';
+ break;
+ case 15:
+ result[1] = 'F';
+ break;
+ }
+}
+
+
+//given a string with at least 2 chars in it, convert them to
+// a byte value. No error checking done!
+unsigned char parse_hex(char *str)
+{
+ //do this a little brute force to make it faster
+
+ unsigned char result_high = 0;
+ unsigned char result_low = 0;
+
+ switch (str[0])
+ {
+ case '0' :
+ result_high = 0;
+ break;
+ case '1' :
+ result_high = 1;
+ break;
+ case '2' :
+ result_high = 2;
+ break;
+ case '3' :
+ result_high = 3;
+ break;
+ case '4' :
+ result_high = 4;
+ break;
+ case '5' :
+ result_high = 5;
+ break;
+ case '6' :
+ result_high = 6;
+ break;
+ case '7' :
+ result_high = 7;
+ break;
+ case '8' :
+ result_high = 8;
+ break;
+ case '9' :
+ result_high = 9;
+ break;
+ case 'A' :
+ result_high = 10;
+ break;
+ case 'B' :
+ result_high = 11;
+ break;
+ case 'C' :
+ result_high = 12;
+ break;
+ case 'D' :
+ result_high = 13;
+ break;
+ case 'E' :
+ result_high = 14;
+ break;
+ case 'F' :
+ result_high = 15;
+ break;
+ }
+ switch (str[1])
+ {
+ case '0' :
+ result_low = 0;
+ break;
+ case '1' :
+ result_low = 1;
+ break;
+ case '2' :
+ result_low = 2;
+ break;
+ case '3' :
+ result_low = 3;
+ break;
+ case '4' :
+ result_low = 4;
+ break;
+ case '5' :
+ result_low = 5;
+ break;
+ case '6' :
+ result_low = 6;
+ break;
+ case '7' :
+ result_low = 7;
+ break;
+ case '8' :
+ result_low = 8;
+ break;
+ case '9' :
+ result_low = 9;
+ break;
+ case 'A' :
+ result_low = 10;
+ break;
+ case 'B' :
+ result_low = 11;
+ break;
+ case 'C' :
+ result_low = 12;
+ break;
+ case 'D' :
+ result_low = 13;
+ break;
+ case 'E' :
+ result_low = 14;
+ break;
+ case 'F' :
+ result_low = 15;
+ break;
+ }
+ return (unsigned char) ((result_high<<4) + result_low);
+}
+