From 81b33875e407bdf4bb7ee69baf51c1ea7b6106b1 Mon Sep 17 00:00:00 2001
From: David Blasby <dblasby@gmail.com>
Date: Tue, 4 Sep 2001 19:30:12 +0000
Subject: [PATCH] Added support to make WKB a full type.

git-svn-id: http://svn.osgeo.org/postgis/trunk@60 b70326c6-7e19-0410-871a-916f4a2858ee
---
 postgis.h       |  12 ++
 postgis.sql.in  |  17 ++-
 postgis_fn.c    |   5 +-
 postgis_inout.c | 298 +++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 326 insertions(+), 6 deletions(-)

diff --git a/postgis.h b/postgis.h
index ca4f1347c..c65f5b470 100644
--- a/postgis.h
+++ b/postgis.h
@@ -205,6 +205,13 @@ typedef struct geomkey {
 } GEOMETRYKEY; 
 
 
+// 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;
+
+
 //prototypes 
 
      int isspace(int c);
@@ -312,6 +319,8 @@ double distance_seg_seg(POINT3D *A, POINT3D *B, POINT3D *C, POINT3D *D);
 bool point_in_poly(POINT3D *p, POLYGON3D *poly);
 
 void print_point_debug(POINT3D *p);
+unsigned char	parse_hex(char *str);
+void deparse_hex(unsigned char str, unsigned char *result);
 
 
 char *geometry_to_text(GEOMETRY  *geometry);
@@ -412,6 +421,9 @@ Datum centroid(PG_FUNCTION_ARGS);
 
 Datum postgis_gist_sel(PG_FUNCTION_ARGS);
 
+Datum WKB_in(PG_FUNCTION_ARGS);
+Datum WKB_out(PG_FUNCTION_ARGS);
+
 
 //for GIST index
 typedef char* (*BINARY_UNION)(char*, char*, int*);
diff --git a/postgis.sql.in b/postgis.sql.in
index b7a1c9ef6..803a52950 100644
--- a/postgis.sql.in
+++ b/postgis.sql.in
@@ -241,11 +241,22 @@ CREATE TYPE BOX3D (
 	output = BOX3D_out
 );
 
+create function WKB_in(opaque)
+	RETURNS WKB
+   AS '@MODULE_FILENAME@','WKB_in'
+   LANGUAGE 'c' with (isstrict);
+
+create function WKB_out(opaque)
+	RETURNS opaque
+   AS '@MODULE_FILENAME@','WKB_out'
+   LANGUAGE 'c' with (isstrict);
+
+
 CREATE TYPE WKB (
-	alignment = double,
 	internallength = VARIABLE,
-	input =  textin,
-	output =  textout
+	input =  WKB_in,
+	output =  WKB_out,
+	storage= extended
 );
 
 
diff --git a/postgis_fn.c b/postgis_fn.c
index fd4e1fa23..c0d226a10 100644
--- a/postgis_fn.c
+++ b/postgis_fn.c
@@ -2192,4 +2192,7 @@ Datum centroid(PG_FUNCTION_ARGS)
 	pfree(cent);
 	PG_RETURN_POINTER(result);
 
-}
\ No newline at end of file
+}
+
+
+
diff --git a/postgis_inout.c b/postgis_inout.c
index 3ca444078..2a27e9314 100644
--- a/postgis_inout.c
+++ b/postgis_inout.c
@@ -2764,7 +2764,7 @@ Datum asbinary_specify(PG_FUNCTION_ARGS)
 
 	if  ( ( strcmp(VARDATA(type) ,"xdr") == 0 ) || (strcmp(VARDATA(type) ,"XDR") == 0) )
 	{
-printf("requested XDR\n");
+//printf("requested XDR\n");
 		if (BYTE_ORDER == BIG_ENDIAN)
 			PG_RETURN_POINTER(to_wkb(geom, FALSE));
 		else
@@ -2772,7 +2772,7 @@ printf("requested XDR\n");
 	}
 	else
 	{
-printf("requested NDR\n");
+//printf("requested NDR\n");
 		if (BYTE_ORDER == LITTLE_ENDIAN)
 			PG_RETURN_POINTER(to_wkb(geom, FALSE));
 		else
@@ -3060,3 +3060,297 @@ LINE3D	*make_line(int	npoints, POINT3D	*pts, int	*size)
 	return result;
 }
 
+//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;
+	unsigned char		result_low;
+
+	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);
+}
+
+
+// input is a string with hex chars in it.  Convert to binary and put in the result
+PG_FUNCTION_INFO_V1(WKB_in);
+Datum WKB_in(PG_FUNCTION_ARGS)
+{
+	char	   		*str = PG_GETARG_CSTRING(0);
+	WellKnownBinary 	*result;
+	int			size;
+	int			t;
+	int			input_str_len;
+
+//printf("wkb_in called\n");
+
+	input_str_len = strlen(str);
+
+	if  ( ( ( (int)(input_str_len/2.0) ) *2.0) != input_str_len)
+	{
+		elog(ERROR,"WKB_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;
+	result = (WellKnownBinary *) palloc(size);
+	result->size = size;
+	
+	for (t=0;t<input_str_len/2;t++)
+	{
+		((unsigned char *)result)[t+4] = parse_hex( &str[t*2]) ;
+	}
+	PG_RETURN_POINTER(result);
+}
+
+
+//given a WKB structure, convert it to Hex and put it in a string
+PG_FUNCTION_INFO_V1(WKB_out);
+Datum WKB_out(PG_FUNCTION_ARGS)
+{
+	WellKnownBinary		      *WKB = (WellKnownBinary *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+	char					*result;
+	int					size_result;
+	int					t;
+
+//printf("wkb_out called\n");
+
+	size_result = (WKB->size - 4) *2 +1; //+1 for null char
+	result = palloc (size_result);
+	result[size_result-1] = 0; //null terminate
+
+	for (t=0; t< (WKB->size -4); t++)
+	{
+		deparse_hex( ((unsigned char *) WKB)[4 + t], &result[t*2]);			
+	}
+	PG_RETURN_CSTRING(result);	
+}
+
+
-- 
2.40.0