/* * Written by Ralph Mason ralph.masontelogis.com * * Copyright Telogis 2004 * www.telogis.com * * $Id: wktunparse.c 2305 2006-02-06 11:12:22Z strk $ */ #include #include #include /* TO get byte order */ #include #include /* Solaris9 does not provide stdint.h */ /* #include */ #include #include "liblwgeom.h" #include "wktparse.h" /*-- Typedefs ---------------------------------------------- */ typedef uint32_t int4; typedef uchar* (*outfunc)(uchar*,int); typedef uchar* (*outwkbfunc)(uchar*); /*-- Prototypes -------------------------------------------- */ void ensure(int chars); void to_end(void); void write_str(const char* str); void write_double(double val); void write_int(int i); int4 read_int(uchar** geom); double read_double(uchar** geom); uchar* output_point(uchar* geom,int supress); uchar* output_single(uchar* geom,int supress); uchar* output_collection(uchar* geom,outfunc func,int supress); uchar* output_collection_2(uchar* geom,int suppress); uchar* output_multipoint(uchar* geom,int suppress); void write_wkb_hex_bytes(uchar* ptr, unsigned int cnt, size_t size); void write_wkb_bin_bytes(uchar* ptr, unsigned int cnt, size_t size); void write_wkb_bin_flip_bytes(uchar* ptr, unsigned int cnt, size_t size); void write_wkb_hex_flip_bytes(uchar* ptr, unsigned int cnt, size_t size); void write_wkb_int(int i); uchar* output_wkb_collection(uchar* geom,outwkbfunc func); uchar* output_wkb_collection_2(uchar* geom); uchar* output_wkb_point(uchar* geom); uchar* output_wkb(uchar* geom); /*-- Globals ----------------------------------------------- */ static int dims; static allocator local_malloc; static freeor local_free; static char* out_start; static char* out_pos; static int len; static int lwgi; static uchar endianbyte; void (*write_wkb_bytes)(uchar* ptr,unsigned int cnt,size_t size); /*---------------------------------------------------------- */ /* * Ensure there is enough space for chars bytes. * Reallocate memory is this is not the case. */ void ensure(int chars){ int pos = out_pos - out_start; if ( (pos + chars) >= len ){ char* newp =(char*)local_malloc(len*2); memcpy(newp,out_start,len); local_free(out_start); out_start = newp; out_pos = newp + pos; len *=2; } } void to_end(void) { while(*out_pos){ out_pos++; } } void write_str(const char* str) { ensure(32); strcpy(out_pos,str); to_end(); } void write_double(double val){ ensure(32); if (lwgi) sprintf(out_pos,"%.8g",val); else sprintf(out_pos,"%.15g",val); to_end(); } void write_int(int i){ ensure(32); sprintf(out_pos,"%i",i); to_end(); } int4 read_int(uchar** geom) { int4 ret; #ifdef SHRINK_INTS if ( getMachineEndian() == NDR ){ if( (**geom)& 0x01){ ret = **geom >>1; (*geom)++; return ret; } } else{ if( (**geom)& 0x80){ ret = **geom & ~0x80; (*geom)++; return ret; } } #endif memcpy(&ret,*geom,4); #ifdef SHRINK_INTS if ( getMachineEndian() == NDR ){ ret >>= 1; } #endif (*geom)+=4; return ret; } double round(double); double read_double(uchar** geom){ if (lwgi){ double ret = *((int4*)*geom); ret /= 0xb60b60; (*geom)+=4; return ret-180.0; } else{ double ret; memcpy(&ret, *geom, 8); (*geom)+=8; return ret; } } uchar * output_point(uchar* geom,int supress) { int i; for( i = 0 ; i < dims ; i++ ){ write_double(read_double(&geom)); if (i +1 < dims ) write_str(" "); } return geom; } uchar * output_single(uchar* geom,int supress) { write_str("("); geom=output_point(geom,supress); write_str(")"); return geom; } uchar * output_collection(uchar* geom,outfunc func,int supress) { int cnt = read_int(&geom); if ( cnt == 0 ){ write_str(" EMPTY"); } else{ write_str("("); while(cnt--){ geom=func(geom,supress); if ( cnt ){ write_str(","); } } write_str(")"); } return geom; } uchar * output_collection_2(uchar* geom,int suppress) { return output_collection(geom,output_point,suppress); } uchar *output_wkt(uchar* geom, int supress); /* special case for multipoint to supress extra brackets */ uchar *output_multipoint(uchar* geom,int suppress){ unsigned type = *geom & 0x0f; if ( type == POINTTYPE ) return output_point(++geom,suppress); else if ( type == POINTTYPEI ){ lwgi++; geom=output_point(++geom,0); lwgi--; return geom; } return output_wkt(geom,suppress); } /* * Suppress=0 -- write TYPE, M, coords * Suppress=1 -- write TYPE, coords * Suppress=2 -- write only coords */ uchar * output_wkt(uchar* geom, int supress) { unsigned type=*geom++; char writeM=0; dims = TYPE_NDIMS(type); /* ((type & 0x30) >> 4)+2; */ if ( ! supress && !TYPE_HASZ(type) && TYPE_HASM(type) ) writeM=1; /* Skip the bounding box if there is one */ if ( TYPE_HASBBOX(type) ) { geom+=16; } if ( TYPE_HASSRID(type) ) { write_str("SRID=");write_int(read_int(&geom));write_str(";"); } switch(TYPE_GETTYPE(type)) { case POINTTYPE: if ( supress < 2 ) { if (writeM) write_str("POINTM"); else write_str("POINT"); } geom=output_single(geom,0); break; case LINETYPE: if ( supress < 2 ) { if (writeM) write_str("LINESTRINGM"); else write_str("LINESTRING"); } geom = output_collection(geom,output_point,0); break; case POLYGONTYPE: if ( supress < 2 ) { if (writeM) write_str("POLYGONM"); else write_str("POLYGON"); } geom = output_collection(geom,output_collection_2,0); break; case MULTIPOINTTYPE: if ( supress < 2 ) { if (writeM) write_str("MULTIPOINTM"); else write_str("MULTIPOINT"); } geom = output_collection(geom,output_multipoint,2); break; case MULTILINETYPE: if ( supress < 2 ) { if (writeM) write_str("MULTILINESTRINGM"); else write_str("MULTILINESTRING"); } geom = output_collection(geom,output_wkt,2); break; case MULTIPOLYGONTYPE: if ( supress < 2 ) { if (writeM) write_str("MULTIPOLYGONM"); else write_str("MULTIPOLYGON"); } geom = output_collection(geom,output_wkt,2); break; case COLLECTIONTYPE: if ( supress < 2 ) { if (writeM) write_str("GEOMETRYCOLLECTIONM"); else write_str("GEOMETRYCOLLECTION"); } geom = output_collection(geom,output_wkt,1); break; case POINTTYPEI: if ( supress < 2 ) { if (writeM) write_str("POINTM"); else write_str("POINT"); } lwgi++; geom=output_single(geom,0); lwgi--; break; case LINETYPEI: if ( supress < 2 ) { if (writeM) write_str("LINESTRINGM"); else write_str("LINESTRING"); } lwgi++; geom = output_collection(geom,output_point,0); lwgi--; break; case POLYGONTYPEI: if ( supress < 2 ) { if (writeM) write_str("POLYGONM"); else write_str("POLYGON"); } lwgi++; geom =output_collection(geom,output_collection_2,0); lwgi--; break; } return geom; } char * unparse_WKT(uchar* serialized, allocator alloc, freeor free) { if (serialized==NULL) return NULL; local_malloc=alloc; local_free=free; len = 128; out_start = out_pos = alloc(len); lwgi=0; output_wkt(serialized, 0); return out_start; } static char outchr[]={"0123456789ABCDEF" }; /* Write HEX bytes flipping */ void write_wkb_hex_flip_bytes(uchar* ptr, unsigned int cnt, size_t size) { unsigned int bc; /* byte count */ ensure(cnt*2*size); while(cnt--){ for(bc=size; bc; bc--) { *out_pos++ = outchr[ptr[bc-1]>>4]; *out_pos++ = outchr[ptr[bc-1]&0x0F]; } ptr+=size; } } /* Write HEX bytes w/out flipping */ void write_wkb_hex_bytes(uchar* ptr, unsigned int cnt, size_t size) { unsigned int bc; /* byte count */ ensure(cnt*2*size); while(cnt--){ for(bc=0; bc>4]; *out_pos++ = outchr[ptr[bc]&0x0F]; } ptr+=size; } } /* Write BIN bytes flipping */ void write_wkb_bin_flip_bytes(uchar* ptr, unsigned int cnt, size_t size) { unsigned int bc; /* byte count */ ensure(cnt*size); while(cnt--) { for(bc=size; bc; bc--) *out_pos++ = ptr[bc-1]; ptr+=size; } } /* Write BIN bytes w/out flipping */ void write_wkb_bin_bytes(uchar* ptr, unsigned int cnt, size_t size) { unsigned int bc; /* byte count */ ensure(cnt*size); /* Could just use a memcpy here ... */ while(cnt--) { for(bc=0; bc * * Revision 1.11 2004/10/15 07:35:41 strk * Fixed a bug introduced by me (byteorder skipped for inner geoms in WKB) * * Revision 1.10 2004/10/11 14:03:33 strk * Added endiannes specification to unparse_WKB, AsBinary, lwgeom_to_wkb. * ******************************************************************/