2
* Written by Ralph Mason ralph.mason<at>telogis.com
4
* Copyright Telogis 2004
11
#include "liblwgeom.h"
16
#include <sys/types.h>
17
#include <netinet/in.h>
18
#include <netinet/in_systm.h>
19
#include <netinet/ip.h>
22
void set_zm(char z, char m);
23
void close_parser(void);
25
typedef unsigned long int4;
27
typedef struct tag_tuple tuple;
29
struct tag_outputstate{
33
typedef struct tag_outputstate output_state;
34
typedef void (*output_func)(tuple* this,output_state* out);
35
typedef void (*read_col_func)(const uchar**f);
43
static int ferror_occured;
44
static allocator local_malloc;
45
static report_error error_func;
60
struct tag_tuple *next;
70
/* create integer version */
72
/* input is integer (wkb only)*/
78
linked list of all tuples
84
stack of open geometries
93
double *first_point=NULL;
94
double *last_point=NULL;
96
/* External functions */
97
extern void init_parser(const uchar *);
100
tuple* alloc_tuple(output_func of,size_t size);
101
static void error(const char* err);
102
void free_tuple(tuple* to_free);
104
void alloc_stack_tuple(int type,output_func of,size_t size);
105
void check_dims(int num);
106
void WRITE_DOUBLES(output_state* out,double* points, int cnt);
108
void WRITE_INT4(output_state * out,int4 val);
110
void write_size(tuple* this,output_state* out);
111
void alloc_lwgeom(int srid);
112
void write_point_2(tuple* this,output_state* out);
113
void write_point_3(tuple* this,output_state* out);
114
void write_point_4(tuple* this,output_state* out);
115
void write_point_2i(tuple* this,output_state* out);
116
void write_point_3i(tuple* this,output_state* out);
117
void write_point_4i(tuple* this,output_state* out);
118
void alloc_point_2d(double x,double y);
119
void alloc_point_3d(double x,double y,double z);
120
void alloc_point_4d(double x,double y,double z,double m);
121
void write_type(tuple* this,output_state* out);
122
void write_count(tuple* this,output_state* out);
123
void write_type_count(tuple* this,output_state* out);
124
void alloc_point(void);
125
void alloc_linestring(void);
126
void alloc_polygon(void);
127
void alloc_multipoint(void);
128
void alloc_multilinestring(void);
129
void alloc_multipolygon(void);
130
void alloc_geomertycollection(void);
131
void alloc_counter(void);
132
void alloc_empty(void);
133
uchar* make_lwgeom(void);
134
uchar strhex_readbyte(const uchar* in);
135
uchar read_wkb_byte(const uchar** in);
136
void read_wkb_bytes(const uchar** in,uchar* out, int cnt);
137
int4 read_wkb_int(const uchar** in);
138
double read_wkb_double(const uchar** in,int convert_from_int);
139
void read_wkb_point(const uchar** b);
140
void read_collection(const uchar** b,read_col_func f);
141
void read_collection2(const uchar** b);
142
void parse_wkb(const uchar** b);
143
void alloc_wkb(const uchar* parser);
144
uchar* parse_it(const uchar* geometry,allocator allocfunc,report_error errfunc);
145
uchar* parse_lwg(const uchar* geometry,allocator allocfunc,report_error errfunc);
146
uchar* parse_lwgi(const uchar* geometry,allocator allocfunc,report_error errfunc);
149
set_srid(double d_srid)
157
srid=(int)(d_srid+0.1);
161
alloc_tuple(output_func of,size_t size)
163
tuple* ret = free_list;
166
int toalloc = (ALLOC_CHUNKS /sizeof(tuple));
167
ret = malloc( toalloc *sizeof(tuple) );
178
return alloc_tuple(of,size);
181
free_list = ret->next;
185
if ( the_geom.last ) {
186
the_geom.last->next = ret;
190
the_geom.first = the_geom.last = ret;
193
the_geom.alloc_size += size;
199
error(const char* err)
206
free_tuple(tuple* to_free)
209
tuple* list_end = to_free;
214
while(list_end->next){
215
list_end=list_end->next;
218
list_end->next = free_list;
225
the_geom.stack->uu.nn.num++;
229
Allocate a 'counting' tuple
232
alloc_stack_tuple(int type,output_func of,size_t size)
237
p = alloc_tuple(of,size);
238
p->uu.nn.stack_next = the_geom.stack;
239
p->uu.nn.type = type;
240
p->uu.nn.size_here = the_geom.alloc_size;
248
the_geom.stack = the_geom.stack->uu.nn.stack_next;
254
if ( the_geom.stack->uu.nn.num < minpoints){
255
error("geometry requires more points");
257
if ( checkclosed && first_point && last_point) {
258
if ( memcmp(first_point, last_point,
259
sizeof(double)*the_geom.ndims) )
261
error("geometry contains non-closed rings");
264
the_geom.stack = the_geom.stack->uu.nn.stack_next;
271
if( the_geom.ndims != num){
272
if (the_geom.ndims) {
273
error("Can not mix dimentionality in a geometry");
275
the_geom.ndims = num;
276
if ( num > 2 ) the_geom.hasZ = 1;
277
if ( num > 3 ) the_geom.hasM = 1;
282
#define WRITE_INT4_REAL(x,y) { memcpy(x->pos,&y,4); x->pos+=4;}
283
#define WRITE_INT4_REAL_MULTIPLE(x,y,z) { memcpy(x->pos,&y,z*4); x->pos+=(z*4);}
286
we can shrink ints to one byte if they are less than 127
287
by setting the extra bit. Because if the different byte
288
ordering possibilities we need to set the lsb on little
289
endian to show a packed one and the msb on a big endian
294
WRITE_INT4(output_state * out,int4 val)
297
if ( getMachineEndian() == NDR ){
304
*out->pos++ = (uchar)val;
305
the_geom.alloc_size-=3;
308
if ( getMachineEndian() == NDR ){
311
WRITE_INT4_REAL(out,val);
315
#define WRITE_INT4 WRITE_INT4_REAL
320
WRITE_DOUBLES(output_state* out,double* points, int cnt)
327
vals[i] = (int4)(((points[i]+180.0)*0xB60B60)+.5);
329
memcpy(out->pos,vals,sizeof(int4)*cnt);
330
out->pos+=sizeof(int4)*cnt;
333
memcpy(out->pos,points,sizeof(double)*cnt);
334
out->pos+=sizeof(double)*cnt;
340
write_size(tuple* this,output_state* out)
342
WRITE_INT4_REAL(out,the_geom.alloc_size);
346
alloc_lwgeom(int srid)
349
the_geom.alloc_size=0;
355
//Free if used already
356
if ( the_geom.first ){
357
free_tuple(the_geom.first);
358
the_geom.first=the_geom.last=NULL;
362
the_geom.alloc_size+=4;
365
the_geom.stack = alloc_tuple(write_size,4);
369
write_point_2(tuple* this,output_state* out)
371
WRITE_DOUBLES(out,this->uu.points,2);
375
write_point_3(tuple* this,output_state* out)
377
WRITE_DOUBLES(out,this->uu.points,3);
381
write_point_4(tuple* this,output_state* out)
383
WRITE_DOUBLES(out,this->uu.points,4);
387
write_point_2i(tuple* this,output_state* out)
389
WRITE_INT4_REAL_MULTIPLE(out,this->uu.points,2);
393
write_point_3i(tuple* this,output_state* out)
395
WRITE_INT4_REAL_MULTIPLE(out,this->uu.points,3);
399
write_point_4i(tuple* this,output_state* out)
401
WRITE_INT4_REAL_MULTIPLE(out,this->uu.points,4);
405
alloc_point_2d(double x,double y)
407
tuple* p = alloc_tuple(write_point_2,the_geom.lwgi?8:16);
411
/* keep track of point */
413
if ( ! the_geom.stack->uu.nn.num )
414
first_point = p->uu.points;
415
last_point = p->uu.points;
423
alloc_point_3d(double x,double y,double z)
425
tuple* p = alloc_tuple(write_point_3,the_geom.lwgi?12:24);
430
/* keep track of point */
432
if ( ! the_geom.stack->uu.nn.num )
433
first_point = p->uu.points;
434
last_point = p->uu.points;
442
alloc_point_4d(double x,double y,double z,double m)
444
tuple* p = alloc_tuple(write_point_4,the_geom.lwgi?16:32);
450
/* keep track of point */
452
if ( ! the_geom.stack->uu.nn.num )
453
first_point = p->uu.points;
454
last_point = p->uu.points;
462
write_type(tuple* this,output_state* out)
466
//Empty handler - switch back
467
if ( this->uu.nn.type == 0xff )
468
this->uu.nn.type = COLLECTIONTYPE;
470
type |= this->uu.nn.type;
472
if (the_geom.ndims) //Support empty
474
TYPE_SETZM(type, the_geom.hasZ, the_geom.hasM);
477
if ( the_geom.srid != -1 ){
484
if ( the_geom.srid != -1 ){
485
//Only the first geometry will have a srid attached
486
WRITE_INT4(out,the_geom.srid);
492
write_count(tuple* this,output_state* out)
494
int num = this->uu.nn.num;
499
write_type_count(tuple* this,output_state* out)
501
write_type(this,out);
502
write_count(this,out);
509
alloc_stack_tuple(POINTTYPEI,write_type,1);
511
alloc_stack_tuple(POINTTYPE,write_type,1);
518
alloc_linestring(void)
521
alloc_stack_tuple(LINETYPEI,write_type,1);
523
alloc_stack_tuple(LINETYPE,write_type,1);
533
alloc_stack_tuple(POLYGONTYPEI, write_type,1);
535
alloc_stack_tuple(POLYGONTYPE, write_type,1);
542
alloc_multipoint(void)
544
alloc_stack_tuple(MULTIPOINTTYPE,write_type,1);
548
alloc_multilinestring(void)
550
alloc_stack_tuple(MULTILINETYPE,write_type,1);
554
alloc_multipolygon(void)
556
alloc_stack_tuple(MULTIPOLYGONTYPE,write_type,1);
560
alloc_geomertycollection(void)
562
alloc_stack_tuple(COLLECTIONTYPE,write_type,1);
568
alloc_stack_tuple(0,write_count,4);
574
tuple* st = the_geom.stack;
575
//Find the last geometry
576
while(st->uu.nn.type == 0){
577
st =st->uu.nn.stack_next;
581
free_tuple(st->next);
583
//Put an empty geometry collection on the top of the stack
586
the_geom.alloc_size=st->uu.nn.size_here;
588
//Mark as a empty stop
589
if (st->uu.nn.type != 0xFF){
591
st->of = write_type_count;
592
the_geom.alloc_size+=4;
593
st->uu.nn.size_here=the_geom.alloc_size;
606
out_c = (uchar*)local_malloc(the_geom.alloc_size);
608
cur = the_geom.first ;
615
//if ints shrink then we need to rewrite the size smaller
617
write_size(NULL,&out);
623
lwg_parse_yyerror(char* s)
625
error("parse error - invalid geometry");
626
//error_func("parse error - invalid geometry");
631
Table below generated using this ruby.
633
a=(0..0xff).to_a.collect{|x|0xff};('0'..'9').each{|x|a[x[0]]=x[0]-'0'[0]}
634
('a'..'f').each{|x|v=x[0]-'a'[0]+10;a[x[0]]=a[x.upcase[0]]=v}
635
puts '{'+a.join(",")+'}'
638
static const uchar to_hex[] = {
639
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
640
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
641
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
642
0,1,2,3,4,5,6,7,8,9,255,255,255,255,255,255,255,10,11,12,13,14,
643
15,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
644
255,255,255,255,255,255,255,255,255,255,255,10,11,12,13,14,15,255,
645
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
646
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
647
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
648
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
649
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
650
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
651
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
652
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
653
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
654
255,255,255,255,255,255,255,255};
657
strhex_readbyte(const uchar* in)
660
if ( ! ferror_occured){
661
error("invalid wkb");
665
return to_hex[(int)*in]<<4 | to_hex[(int)*(in+1)];
669
read_wkb_byte(const uchar** in)
671
uchar ret = strhex_readbyte(*in);
679
read_wkb_bytes(const uchar** in,uchar* out, int cnt)
682
while(cnt--) *out++ = read_wkb_byte(in);
686
while(cnt--) *out-- = read_wkb_byte(in);
691
read_wkb_int(const uchar** in)
694
read_wkb_bytes(in,(uchar*)&ret,4);
699
read_wkb_double(const uchar** in,int convert_from_int)
703
if ( ! convert_from_int){
704
read_wkb_bytes(in,(uchar*)&ret,8);
707
ret = read_wkb_int(in);
714
read_wkb_point(const uchar** b)
720
if(the_geom.lwgi && the_geom.from_lwgi ){
721
//Special case - reading from lwgi to lwgi
722
//we don't want to go via doubles in the middle.
723
switch(the_geom.ndims){
724
case 2: p=alloc_tuple(write_point_2i,8); break;
725
case 3: p=alloc_tuple(write_point_3i,12); break;
726
case 4: p=alloc_tuple(write_point_4i,16); break;
729
for(i=0;i<the_geom.ndims;i++){
730
p->uu.pointsi[i]=read_wkb_int(b);
734
int mul = the_geom.lwgi ? 1 : 2;
736
switch(the_geom.ndims){
737
case 2: p=alloc_tuple(write_point_2,8*mul); break;
738
case 3: p=alloc_tuple(write_point_3,12*mul); break;
739
case 4: p=alloc_tuple(write_point_4,16*mul); break;
742
for(i=0;i<the_geom.ndims;i++){
743
p->uu.points[i]=read_wkb_double(b,the_geom.from_lwgi);
748
check_dims(the_geom.ndims);
752
read_collection(const uchar** b,read_col_func f)
754
int4 cnt=read_wkb_int(b);
758
if ( ferror_occured ) return;
766
read_collection2(const uchar** b)
768
return read_collection(b,read_wkb_point);
772
parse_wkb(const uchar** b)
775
uchar xdr = read_wkb_byte(b);
780
if ( xdr != getMachineEndian() )
785
type = read_wkb_int(b);
787
//quick exit on error
788
if ( ferror_occured ) return;
791
if (type & WKBZOFFSET)
796
else the_geom.hasZ = 0;
797
if (type & WKBMOFFSET)
802
else the_geom.hasM = 0;
804
if (type & WKBSRIDFLAG )
806
// local (in-EWKB) srid spec overrides SRID=#;
807
localsrid = read_wkb_int(b);
808
if ( localsrid != -1 )
810
if ( the_geom.srid == -1 ) the_geom.alloc_size += 4;
811
the_geom.srid = localsrid;
817
if ( the_geom.lwgi ){
819
if ( type<= POLYGONTYPE )
820
alloc_stack_tuple(type +9,write_type,1);
822
alloc_stack_tuple(type,write_type,1);
825
//If we are writing lwg and are reading wbki
827
if (towrite > COLLECTIONTYPE ){
830
alloc_stack_tuple(towrite,write_type,1);
839
read_collection(b,read_wkb_point);
843
read_collection(b,read_collection2);
848
case MULTIPOLYGONTYPE:
850
read_collection(b,parse_wkb);
854
the_geom.from_lwgi=1;
859
the_geom.from_lwgi=1;
860
read_collection(b,read_wkb_point);
864
the_geom.from_lwgi=1;
865
read_collection(b,read_collection2);
869
error("Invalid type in wbk");
872
the_geom.from_lwgi=0;
879
alloc_wkb(const uchar* parser)
885
Parse a string and return a LW_GEOM
888
parse_it(const uchar* geometry,allocator allocfunc,report_error errfunc)
891
local_malloc = allocfunc;
896
init_parser(geometry);
903
return make_lwgeom();
907
parse_lwg(const uchar* geometry,allocator allocfunc,report_error errfunc)
910
return parse_it(geometry,allocfunc,errfunc);
914
parse_lwgi(const uchar* geometry,allocator allocfunc,report_error errfunc)
917
return parse_it(geometry,allocfunc,errfunc);
921
set_zm(char z, char m)
925
the_geom.ndims = 2+z+m;