From: David Blasby Date: Thu, 11 Mar 2004 00:54:37 +0000 (+0000) Subject: Should be working (with a tonne of notices) for points lines and polygons (2d X-Git-Tag: pgis_0_8_2~73 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=72d7890d7959b3dbd637997253df9f631d87a3ad;p=postgis Should be working (with a tonne of notices) for points lines and polygons (2d and 3d) git-svn-id: http://svn.osgeo.org/postgis/trunk@486 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/lwgeom/lwgeom.h b/lwgeom/lwgeom.h index 39c1ebeb4..f22d6226c 100644 --- a/lwgeom/lwgeom.h +++ b/lwgeom/lwgeom.h @@ -8,9 +8,9 @@ -#define TWODIMS 00 -#define THREEDIMS 01 -#define FOURDIMS 10 +#define TWODIMS 0 +#define THREEDIMS 1 +#define FOURDIMS 2 typedef struct { @@ -113,12 +113,12 @@ extern int pointArray_ptsize(POINTARRAY *pa); LWGEOM types are an 8-bit char in this format: -xxSDtttt +xSDDtttt WHERE x = unused S = 4 byte SRID attached (0= not attached (-1), 1= attached) - D = dimentionality (0=2d, 1=3d) + DD = dimentionality (0=2d, 1=3d, 2= 4d) tttt = actual type (as per the WKB type): enum wkbGeometryType { @@ -409,6 +409,12 @@ extern void pfree_POINTARRAY(POINTARRAY *pa); extern uint32 get_uint32(char *loc); extern int32 get_int32(char *loc); +extern void printPA(POINTARRAY *pa); +extern void printLWLINE(LWLINE *line); +extern void printLWPOLY(LWPOLY *poly); +extern void printBYTES(unsigned char *a, int n); +extern void deparse_hex(unsigned char str, unsigned char *result); + //------------------------------------------------------------ //------------------------------------------------------------ diff --git a/lwgeom/lwgeom.sql.in b/lwgeom/lwgeom.sql.in index e69de29bb..43f68c74b 100644 --- a/lwgeom/lwgeom.sql.in +++ b/lwgeom/lwgeom.sql.in @@ -0,0 +1,47 @@ +BEGIN; + +CREATE OR REPLACE FUNCTION lwgeom_in(cstring) + RETURNS lwgeom + AS '/net/lion/raid/share/Refractions/Projects/PostGIS/work_dave2/postgis/lwgeom/liblwgeom.so.0.1','LWGEOM_in' + LANGUAGE 'C' WITH (isstrict,iscachable); + +CREATE OR REPLACE FUNCTION lwgeom_out(lwgeom) + RETURNS cstring + AS '/net/lion/raid/share/Refractions/Projects/PostGIS/work_dave2/postgis/lwgeom/liblwgeom.so.0.1','LWGEOM_out' + LANGUAGE 'C' WITH (isstrict,iscachable); + +CREATE TYPE lwgeom ( + internallength = variable, + input = lwgeom_in, + output = lwgeom_out, + storage = main +); + + +CREATE FUNCTION lwgeom(wkb) + RETURNS lwgeom + AS '/net/lion/raid/share/Refractions/Projects/PostGIS/work_dave2/postgis/lwgeom/liblwgeom.so.0.1','LWGEOMFromWKB' + LANGUAGE 'C' WITH (isstrict,iscachable); + + +CREATE FUNCTION wkb(lwgeom) + RETURNS wkb + AS '/net/lion/raid/share/Refractions/Projects/PostGIS/work_dave2/postgis/lwgeom/liblwgeom.so.0.1','WKBFromLWGEOM' + LANGUAGE 'C' WITH (isstrict,iscachable); + +COMMIT; + + +---- test stuff + +select geometry(wkb(lwgeom(asbinary('POINT(1 2)'::geometry)))); +select geometry(wkb(lwgeom(asbinary('POINT(1 2 3)'::geometry)))); + +select geometry(wkb(lwgeom(asbinary('LINESTRING(1 2, 3 4)'::geometry)))); +select geometry(wkb(lwgeom(asbinary('LINESTRING(1 2 -999, 3 4 -999, 5 6 -999)'::geometry)))); + + +select geometry(wkb(lwgeom(asbinary('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))'::geometry)))); +select geometry(wkb(lwgeom(asbinary('POLYGON((0 0 -99, 10 0 -99, 10 10 -99, 0 10 -99, 0 0 -99))'::geometry)))); + + diff --git a/lwgeom/lwgeom_api.c b/lwgeom/lwgeom_api.c index 77a1eb2f4..1afc66122 100644 --- a/lwgeom/lwgeom_api.c +++ b/lwgeom/lwgeom_api.c @@ -224,9 +224,7 @@ BOX3D *combine_boxes(BOX3D *b1, BOX3D *b2) 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 ); @@ -251,9 +249,7 @@ void getPoint3d_p(POINTARRAY *pa, int n, char *point) 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 ); @@ -281,9 +277,7 @@ POINT2D getPoint2d(POINTARRAY *pa, int n) 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 ); @@ -304,9 +298,7 @@ void getPoint2d_p(POINTARRAY *pa, int n, char *point) 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 ); @@ -322,6 +314,9 @@ POINTARRAY *pointArray_construct(char *points, char is3d, uint32 npoints) 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; @@ -388,12 +383,12 @@ int pointArray_ptsize(POINTARRAY *pa) 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) @@ -472,7 +467,10 @@ LWLINE *lwline_deserialize(char *serialized_form) 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)) { @@ -494,6 +492,7 @@ LWLINE *lwline_deserialize(char *serialized_form) result->points = pa; result->is3d = lwgeom_is3d(type); +//elog(NOTICE,"npoints in deserialize line = %i",npoints); return result; } @@ -507,6 +506,7 @@ char *lwline_serialize(LWLINE *line) int t; char *loc; +elog(NOTICE,"lwline_serialize::entry"); hasSRID = (line->SRID != -1); if (hasSRID) @@ -518,9 +518,13 @@ char *lwline_serialize(LWLINE *line) } 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); @@ -532,6 +536,8 @@ char *lwline_serialize(LWLINE *line) loc += 4; } + memcpy(loc, &line->points->npoints, sizeof(int32)); + loc +=4; //copy in points if (line->is3d) @@ -550,6 +556,7 @@ char *lwline_serialize(LWLINE *line) loc += 16; // size of a 2d point } } + printBYTES((unsigned char *)result, size); return result; } @@ -571,7 +578,7 @@ uint32 lwline_findlength(char *serialized_line) 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)) { @@ -586,6 +593,9 @@ uint32 lwline_findlength(char *serialized_line) // 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; @@ -831,8 +841,9 @@ LWPOLY *lwpoly_deserialize(char *serialized_form) } 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;trings[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; @@ -895,12 +907,15 @@ char *lwpoly_serialize(LWPOLY *poly) } memcpy(loc, &poly->nrings, sizeof(int32)); // nrings + loc+=4; + + for (t=0;tnrings;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) @@ -908,15 +923,16 @@ char *lwpoly_serialize(LWPOLY *poly) for (u=0;uis3d); + 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; tnpoints;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;tis3d); + elog(NOTICE," SRID = %i", (int)poly->SRID); + elog(NOTICE," nrings = %i", (int)poly->nrings); + for (t=0;tnrings;t++) + { + elog(NOTICE," RING # %i :",t); + printPA(poly->rings[t]); + } + elog(NOTICE,"}"); +} diff --git a/lwgeom/lwgeom_inout.c b/lwgeom/lwgeom_inout.c index fe4468b76..11977db66 100644 --- a/lwgeom/lwgeom_inout.c +++ b/lwgeom/lwgeom_inout.c @@ -16,6 +16,14 @@ #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); @@ -36,6 +44,11 @@ extern char *lwline_to_wkb(LWLINE *line, char desiredWKBEndian, int *wkbsize); 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 @@ -43,22 +56,125 @@ extern char *lwpoly_to_wkb(LWPOLY *poly, char desiredWKBEndian, int *wkbsize); 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;t1) && ( ! 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); @@ -123,6 +239,11 @@ char *wkb_to_lwgeom(char *wkb, int SRID,int *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: @@ -133,14 +254,21 @@ char *wkb_to_lwgeom(char *wkb, int SRID,int *size) 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: @@ -153,6 +281,10 @@ char *wkb_to_lwgeom(char *wkb, int SRID,int *size) case COLLECTIONTYPE: break; } +#ifdef DEBUG + elog(NOTICE,"wkb_to_lwgeom:returning"); +#endif + return result; } @@ -175,11 +307,20 @@ LWPOINT *wkb_point_to_lwpoint(char *wkb,int SRID) 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); } @@ -211,7 +352,7 @@ LWLINE *wkb_line_to_lwline(char *wkb,int SRID) flipPoints(wkb+9,npoints,dims); pa = pointArray_construct(wkb+9, dims, npoints); - +printPA(pa); return lwline_construct(dims, SRID, pa); } @@ -244,10 +385,11 @@ LWPOLY *wkb_poly_to_lwpoly(char *wkb,int SRID) nrings = get_uint32(wkb+5); - loc = wkb+5; + loc = wkb+9; //point size + ptsize =16; if (dims == FOURDIMS) { ptsize = 32; @@ -271,7 +413,7 @@ LWPOLY *wkb_poly_to_lwpoly(char *wkb,int SRID) // 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; @@ -296,6 +438,10 @@ char *lwgeom_to_wkb(char *serialized_form,int *wkblength,char desiredWKBEndian) 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) { @@ -310,7 +456,9 @@ char *lwgeom_to_wkb(char *serialized_form,int *wkblength,char desiredWKBEndian) 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; @@ -334,6 +482,10 @@ char *lwpoint_to_wkb(LWPOINT *pt, char desiredWKBEndian, int *wkbsize) 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 @@ -342,6 +494,13 @@ char *lwpoint_to_wkb(LWPOINT *pt, char desiredWKBEndian, int *wkbsize) 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); @@ -361,7 +520,9 @@ char *lwline_to_wkb(LWLINE *line, char desiredWKBEndian, int *wkbsize) 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); @@ -372,9 +533,13 @@ char *lwline_to_wkb(LWLINE *line, char desiredWKBEndian, int *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; } @@ -518,3 +683,237 @@ uint32 constructWKBType(int simple_type, char dims) 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); +} +