~ubuntu-branches/ubuntu/trusty/postgis/trusty-security

« back to all changes in this revision

Viewing changes to liblwgeom/lwgunparse.c

  • Committer: Bazaar Package Importer
  • Author(s): Francesco Paolo Lovergine
  • Date: 2009-12-11 13:10:34 UTC
  • mfrom: (1.1.9 upstream) (5.2.1 experimental)
  • Revision ID: james.westby@ubuntu.com-20091211131034-wmsz69wxvt95pe5r
Tags: 1.4.0-2
* Upload to unstable.
* Better parameterized debian/rules against postgis $(VERSION).
* Added dblatex and libcunit1-dev among build-deps.
* Added postgis_comments.sql to contrib/ SQL templates.
* Dropping 8.3 support, no more supported for squeeze.
  (closes: #559587)
* Do not stop on error in postrm if the target dir does not exist.
  (closes: #560409)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Written by Ralph Mason ralph.mason<at>telogis.com
 
3
 *
 
4
 * Copyright Telogis 2004
 
5
 * www.telogis.com
 
6
 *
 
7
 * $Id: lwgunparse.c 4233 2009-07-01 01:12:40Z mleslie $
 
8
 */
 
9
 
 
10
 
 
11
#include <string.h>
 
12
#include <math.h>
 
13
#include <stdio.h>
 
14
/* Solaris9 does not provide stdint.h */
 
15
/* #include <stdint.h> */
 
16
#include <inttypes.h>
 
17
 
 
18
#include "liblwgeom.h"
 
19
#include "wktparse.h"
 
20
 
 
21
 
 
22
/*-- Typedefs ---------------------------------------------- */
 
23
 
 
24
typedef uint32_t int4;
 
25
typedef uchar* (*outfunc)(uchar*,int);
 
26
typedef uchar* (*outwkbfunc)(uchar*);
 
27
 
 
28
/*-- Prototypes -------------------------------------------- */
 
29
 
 
30
void ensure(int chars);
 
31
void to_end(void);
 
32
void write_str(const char* str);
 
33
void write_double(double val);
 
34
void write_int(int i);
 
35
int4 read_int(uchar** geom);
 
36
double read_double(uchar** geom);
 
37
uchar* output_point(uchar* geom,int supress);
 
38
uchar* output_single(uchar* geom,int supress);
 
39
uchar* output_collection(uchar* geom,outfunc func,int supress);
 
40
uchar* output_line_collection(uchar* geom,outfunc func,int supress);
 
41
uchar* output_polygon_collection(uchar* geom,int suppress);
 
42
uchar* output_polygon_ring_collection(uchar* geom,outfunc func,int supress);
 
43
uchar* output_circstring_collection(uchar* geom,outfunc func,int supress);
 
44
uchar* output_curvepoly(uchar* geom, int supress);
 
45
uchar* output_multipoint(uchar* geom,int suppress);
 
46
uchar* output_compound(uchar* geom, int suppress);
 
47
uchar* output_multisurface(uchar* geom, int suppress);
 
48
 
 
49
void write_wkb_hex_bytes(uchar* ptr, unsigned int cnt, size_t size);
 
50
void write_wkb_bin_bytes(uchar* ptr, unsigned int cnt, size_t size);
 
51
void write_wkb_bin_flip_bytes(uchar* ptr, unsigned int cnt, size_t size);
 
52
void write_wkb_hex_flip_bytes(uchar* ptr, unsigned int cnt, size_t size);
 
53
 
 
54
void write_wkb_int(int i);
 
55
uchar* output_wkb_collection(uchar* geom,outwkbfunc func);
 
56
uchar* output_wkb_polygon_collection(uchar* geom);
 
57
uchar* output_wkb_polygon_ring_collection(uchar* geom,outwkbfunc func);
 
58
uchar* output_wkb_line_collection(uchar* geom,outwkbfunc func);
 
59
uchar* output_wkb_circstring_collection(uchar* geom,outwkbfunc func);
 
60
uchar* output_wkb_point(uchar* geom);
 
61
uchar* output_wkb(uchar* geom);
 
62
 
 
63
/*-- Globals ----------------------------------------------- */
 
64
 
 
65
static int unparser_ferror_occured;
 
66
static int dims;
 
67
static allocator local_malloc;
 
68
static freeor local_free;
 
69
static char*  out_start;
 
70
static char*  out_pos;
 
71
static int len;
 
72
static int lwgi;
 
73
static uchar endianbyte;
 
74
void (*write_wkb_bytes)(uchar* ptr,unsigned int cnt,size_t size);
 
75
 
 
76
/*
 
77
 * Unparser current instance check flags - a bitmap of flags that determine which checks are enabled during the current unparse
 
78
 * (see liblwgeom.h for the related PARSER_CHECK constants)
 
79
 */
 
80
int current_unparser_check_flags;
 
81
 
 
82
/*
 
83
 * Unparser current instance result structure - the result structure being used for the current unparse
 
84
 */
 
85
LWGEOM_UNPARSER_RESULT *current_lwg_unparser_result;
 
86
 
 
87
/*
 
88
 * Unparser error messages
 
89
 *
 
90
 * IMPORTANT: Make sure the order of these messages matches the UNPARSER_ERROR constants in liblwgeom.h!
 
91
 * The 0th element should always be empty since it is unused (error constants start from -1)
 
92
 */
 
93
 
 
94
const char *unparser_error_messages[] =
 
95
    {
 
96
        "",
 
97
        "geometry requires more points",
 
98
        "geometry must have an odd number of points",
 
99
        "geometry contains non-closed rings"
 
100
    };
 
101
 
 
102
/* Macro to return the error message and the current position within WKT */
 
103
#define LWGEOM_WKT_UNPARSER_ERROR(errcode) \
 
104
        do { \
 
105
                if (!unparser_ferror_occured) { \
 
106
                        unparser_ferror_occured = -1 * errcode; \
 
107
                        current_lwg_unparser_result->message = unparser_error_messages[errcode]; \
 
108
                        current_lwg_unparser_result->errlocation = (out_pos - out_start); \
 
109
                } \
 
110
        } while (0);
 
111
 
 
112
/* Macro to return the error message and the current position within WKB */
 
113
#define LWGEOM_WKB_UNPARSER_ERROR(errcode) \
 
114
        do { \
 
115
                if (!unparser_ferror_occured) { \
 
116
                        unparser_ferror_occured = -1 * errcode; \
 
117
                        current_lwg_unparser_result->message = unparser_error_messages[errcode]; \
 
118
                        current_lwg_unparser_result->errlocation = (out_pos - out_start); \
 
119
                } \
 
120
        } while (0);
 
121
 
 
122
/*---------------------------------------------------------- */
 
123
 
 
124
 
 
125
 
 
126
 
 
127
 
 
128
 
 
129
/*
 
130
 * Ensure there is enough space for chars bytes.
 
131
 * Reallocate memory is this is not the case.
 
132
 */
 
133
void
 
134
ensure(int chars)
 
135
{
 
136
 
 
137
        int pos = out_pos - out_start;
 
138
 
 
139
        if (  (pos + chars) >= len )
 
140
        {
 
141
                char* newp =(char*)local_malloc(len*2);
 
142
                memcpy(newp,out_start,len);
 
143
                local_free(out_start);
 
144
                out_start = newp;
 
145
                out_pos = newp + pos;
 
146
                len *=2;
 
147
        }
 
148
}
 
149
 
 
150
void
 
151
to_end(void)
 
152
{
 
153
        while (*out_pos)
 
154
        {
 
155
                out_pos++;
 
156
        }
 
157
}
 
158
 
 
159
void
 
160
write_str(const char* str)
 
161
{
 
162
        ensure(32);
 
163
        strcpy(out_pos,str);
 
164
        to_end();
 
165
}
 
166
 
 
167
void
 
168
write_double(double val)
 
169
{
 
170
        ensure(32);
 
171
        if (lwgi)
 
172
                sprintf(out_pos,"%.8g",val);
 
173
        else
 
174
                sprintf(out_pos,"%.15g",val);
 
175
        to_end();
 
176
}
 
177
 
 
178
void
 
179
write_int(int i)
 
180
{
 
181
        ensure(32);
 
182
        sprintf(out_pos,"%i",i);
 
183
        to_end();
 
184
}
 
185
 
 
186
int4
 
187
read_int(uchar** geom)
 
188
{
 
189
        int4 ret;
 
190
#ifdef SHRINK_INTS
 
191
        if ( getMachineEndian() == NDR )
 
192
        {
 
193
                if ( (**geom)& 0x01)
 
194
                {
 
195
                        ret = **geom >>1;
 
196
                        (*geom)++;
 
197
                        return ret;
 
198
                }
 
199
        }
 
200
        else
 
201
        {
 
202
                if ( (**geom)& 0x80)
 
203
                {
 
204
                        ret = **geom & ~0x80;
 
205
                        (*geom)++;
 
206
                        return ret;
 
207
                }
 
208
        }
 
209
#endif
 
210
        memcpy(&ret,*geom,4);
 
211
 
 
212
#ifdef SHRINK_INTS
 
213
        if ( getMachineEndian() == NDR )
 
214
        {
 
215
                ret >>= 1;
 
216
        }
 
217
#endif
 
218
 
 
219
        (*geom)+=4;
 
220
        return ret;
 
221
}
 
222
 
 
223
double round(double);
 
224
 
 
225
double read_double(uchar** geom)
 
226
{
 
227
        if (lwgi)
 
228
        {
 
229
                double ret = *((int4*)*geom);
 
230
                ret /= 0xb60b60;
 
231
                (*geom)+=4;
 
232
                return ret-180.0;
 
233
        }
 
234
        else
 
235
        {
 
236
                double ret;
 
237
                memcpy(&ret, *geom, 8);
 
238
                (*geom)+=8;
 
239
                return ret;
 
240
        }
 
241
}
 
242
 
 
243
uchar *
 
244
output_point(uchar* geom,int supress)
 
245
{
 
246
        int i;
 
247
 
 
248
        for ( i = 0 ; i < dims ; i++ )
 
249
        {
 
250
                write_double(read_double(&geom));
 
251
                if (i +1 < dims )
 
252
                        write_str(" ");
 
253
        }
 
254
        return geom;
 
255
}
 
256
 
 
257
uchar *
 
258
output_single(uchar* geom,int supress)
 
259
{
 
260
        write_str("(");
 
261
        geom=output_point(geom,supress);
 
262
        write_str(")");
 
263
        return geom;
 
264
}
 
265
 
 
266
/* Output a standard collection */
 
267
uchar *
 
268
output_collection(uchar* geom,outfunc func,int supress)
 
269
{
 
270
        int cnt = read_int(&geom);
 
271
        if ( cnt == 0 )
 
272
        {
 
273
                write_str(" EMPTY");
 
274
        }
 
275
        else
 
276
        {
 
277
                write_str("(");
 
278
                while (cnt--)
 
279
                {
 
280
                        geom=func(geom,supress);
 
281
                        if ( cnt )
 
282
                        {
 
283
                                write_str(",");
 
284
                        }
 
285
                }
 
286
                write_str(")");
 
287
        }
 
288
        return geom;
 
289
}
 
290
 
 
291
/* Output a set of LINESTRING points */
 
292
uchar *
 
293
output_line_collection(uchar* geom,outfunc func,int supress)
 
294
{
 
295
        int cnt = read_int(&geom);
 
296
        int orig_cnt = cnt;
 
297
 
 
298
        if ( cnt == 0 )
 
299
        {
 
300
                write_str(" EMPTY");
 
301
        }
 
302
        else
 
303
        {
 
304
                write_str("(");
 
305
                while (cnt--)
 
306
                {
 
307
                        geom=func(geom,supress);
 
308
                        if ( cnt )
 
309
                        {
 
310
                                write_str(",");
 
311
                        }
 
312
                }
 
313
                write_str(")");
 
314
        }
 
315
 
 
316
        /* Ensure that LINESTRING has a minimum of 2 points */
 
317
        if ((current_unparser_check_flags & PARSER_CHECK_MINPOINTS) && orig_cnt < 2)
 
318
                LWGEOM_WKT_UNPARSER_ERROR(UNPARSER_ERROR_MOREPOINTS);
 
319
 
 
320
        return geom;
 
321
}
 
322
 
 
323
/* Output an individual ring from a POLYGON  */
 
324
uchar *
 
325
output_polygon_ring_collection(uchar* geom,outfunc func,int supress)
 
326
{
 
327
        uchar *temp;
 
328
        int dimcount;
 
329
        double *first_point;
 
330
        double *last_point;
 
331
        int cnt;
 
332
        int orig_cnt;
 
333
 
 
334
        first_point = lwalloc(dims * sizeof(double));
 
335
        last_point = lwalloc(dims * sizeof(double));
 
336
 
 
337
        cnt = read_int(&geom);
 
338
        orig_cnt = cnt;
 
339
        if ( cnt == 0 )
 
340
        {
 
341
                write_str(" EMPTY");
 
342
        }
 
343
        else
 
344
        {
 
345
                write_str("(");
 
346
 
 
347
                /* Store the first point of the ring (use a temp var since read_double alters
 
348
                        the pointer after use) */
 
349
                temp = geom;
 
350
                dimcount = 0;
 
351
                while (dimcount < dims)
 
352
                {
 
353
                        first_point[dimcount] = read_double(&temp);
 
354
                        dimcount++;
 
355
                }
 
356
 
 
357
                while (cnt--)
 
358
                {
 
359
                        geom=func(geom,supress);
 
360
                        if ( cnt )
 
361
                        {
 
362
                                write_str(",");
 
363
                        }
 
364
                }
 
365
                write_str(")");
 
366
 
 
367
                /* Store the last point of the ring (note: we will have moved past it, so we
 
368
                        need to count backwards) */
 
369
                temp = geom - sizeof(double) * dims;
 
370
                dimcount = 0;
 
371
                while (dimcount < dims)
 
372
                {
 
373
                        last_point[dimcount] = read_double(&temp);
 
374
                        dimcount++;
 
375
                }
 
376
 
 
377
                /* Check if they are the same...
 
378
 
 
379
                WARNING: due to various GEOS bugs related to producing rings with incorrect
 
380
                          3rd dimensions, the closure check here for outgoing geometries only checks on 2
 
381
                dimensions. This is currently different to the parser! */
 
382
 
 
383
                if (
 
384
                    (first_point[0] != last_point[0] || first_point[1] != last_point[1] ) &&
 
385
                    (current_unparser_check_flags & PARSER_CHECK_CLOSURE))
 
386
                {
 
387
                        LWGEOM_WKT_UNPARSER_ERROR(UNPARSER_ERROR_UNCLOSED);
 
388
                }
 
389
 
 
390
 
 
391
                /* Ensure that POLYGON has a minimum of 4 points */
 
392
                if ((current_unparser_check_flags & PARSER_CHECK_MINPOINTS) && orig_cnt < 4)
 
393
                {
 
394
                        LWGEOM_WKT_UNPARSER_ERROR(UNPARSER_ERROR_MOREPOINTS);
 
395
                }
 
396
        }
 
397
 
 
398
        lwfree(first_point);
 
399
        lwfree(last_point);
 
400
 
 
401
        return geom;
 
402
}
 
403
 
 
404
/* Ouput the points from a CIRCULARSTRING */
 
405
uchar *
 
406
output_circstring_collection(uchar* geom,outfunc func,int supress)
 
407
{
 
408
        int cnt = read_int(&geom);
 
409
        int orig_cnt = cnt;
 
410
 
 
411
        if ( cnt == 0 )
 
412
        {
 
413
                write_str(" EMPTY");
 
414
        }
 
415
        else
 
416
        {
 
417
                write_str("(");
 
418
                while (cnt--)
 
419
                {
 
420
                        geom=func(geom,supress);
 
421
                        if ( cnt )
 
422
                        {
 
423
                                write_str(",");
 
424
                        }
 
425
                }
 
426
                write_str(")");
 
427
        }
 
428
 
 
429
        /* Ensure that a CIRCULARSTRING has a minimum of 3 points */
 
430
        if ((current_unparser_check_flags & PARSER_CHECK_MINPOINTS) && orig_cnt < 3)
 
431
        {
 
432
                LWGEOM_WKT_UNPARSER_ERROR(UNPARSER_ERROR_MOREPOINTS);
 
433
        }
 
434
 
 
435
        /* Ensure that a CIRCULARSTRING has an odd number of points */
 
436
        if ((current_unparser_check_flags & PARSER_CHECK_ODD) && orig_cnt % 2 != 1)
 
437
        {
 
438
                LWGEOM_WKT_UNPARSER_ERROR(UNPARSER_ERROR_ODDPOINTS);
 
439
        }
 
440
 
 
441
        return geom;
 
442
}
 
443
 
 
444
/* Output a POLYGON consisting of a number of rings */
 
445
uchar *
 
446
output_polygon_collection(uchar* geom,int suppress)
 
447
{
 
448
        return output_polygon_ring_collection(geom,output_point,suppress);
 
449
}
 
450
 
 
451
uchar *output_wkt(uchar* geom, int supress);
 
452
 
 
453
/* special case for multipoint to supress extra brackets */
 
454
uchar *output_multipoint(uchar* geom,int suppress)
 
455
{
 
456
        unsigned char type = *geom & 0x0f;
 
457
 
 
458
        if ( type  == POINTTYPE )
 
459
                return output_point(++geom,suppress);
 
460
        else if ( type == POINTTYPEI )
 
461
        {
 
462
                lwgi++;
 
463
                geom=output_point(++geom,0);
 
464
                lwgi--;
 
465
                return geom;
 
466
        }
 
467
 
 
468
        return output_wkt(geom,suppress);
 
469
}
 
470
 
 
471
/* Special case for compound curves: suppress the LINESTRING prefix from a curve if it appears as
 
472
   a component of a COMPOUNDCURVE, but not CIRCULARSTRING */
 
473
uchar *output_compound(uchar* geom, int suppress)
 
474
{
 
475
        unsigned char type;
 
476
 
 
477
        LWDEBUG(2, "output_compound called.");
 
478
 
 
479
        type=*geom;
 
480
        switch (TYPE_GETTYPE(type))
 
481
        {
 
482
        case LINETYPE:
 
483
                geom = output_wkt(geom,2);
 
484
                break;
 
485
        case CIRCSTRINGTYPE:
 
486
                geom = output_wkt(geom,1);
 
487
                break;
 
488
        }
 
489
        return geom;
 
490
}
 
491
 
 
492
/*
 
493
 * Supress linestring but not circularstring and correctly handle compoundcurve
 
494
 */
 
495
uchar *output_curvepoly(uchar* geom, int supress)
 
496
{
 
497
        unsigned type;
 
498
        type = *geom++;
 
499
 
 
500
        LWDEBUG(2, "output_curvepoly.");
 
501
 
 
502
        switch (TYPE_GETTYPE(type))
 
503
        {
 
504
        case LINETYPE:
 
505
                geom = output_collection(geom,output_point,0);
 
506
                break;
 
507
        case CIRCSTRINGTYPE:
 
508
                write_str("CIRCULARSTRING");
 
509
                geom = output_circstring_collection(geom,output_point,1);
 
510
                break;
 
511
        case COMPOUNDTYPE:
 
512
                write_str("COMPOUNDCURVE");
 
513
                geom = output_collection(geom,output_compound,1);
 
514
                break;
 
515
        }
 
516
        return geom;
 
517
}
 
518
 
 
519
/* Special case for multisurfaces: suppress the POLYGON prefix from a surface if it appears as
 
520
   a component of a MULTISURFACE, but not CURVEPOLYGON */
 
521
uchar *output_multisurface(uchar* geom, int suppress)
 
522
{
 
523
        unsigned char type;
 
524
 
 
525
        LWDEBUG(2, "output_multisurface called.");
 
526
 
 
527
        type=*geom;
 
528
        switch (TYPE_GETTYPE(type))
 
529
        {
 
530
        case POLYGONTYPE:
 
531
                geom = output_wkt(geom,2);
 
532
                break;
 
533
        case CURVEPOLYTYPE:
 
534
                geom = output_wkt(geom,1);
 
535
                break;
 
536
        }
 
537
        return geom;
 
538
}
 
539
 
 
540
/*
 
541
 * Suppress=0 -- write TYPE, M, coords
 
542
 * Suppress=1 -- write TYPE, coords
 
543
 * Suppress=2 -- write only coords
 
544
 */
 
545
uchar *
 
546
output_wkt(uchar* geom, int supress)
 
547
{
 
548
 
 
549
        unsigned char type=*geom++;
 
550
        char writeM=0;
 
551
        dims = TYPE_NDIMS(type); /* ((type & 0x30) >> 4)+2; */
 
552
 
 
553
        LWDEBUG(2, "output_wkt called.");
 
554
 
 
555
        if ( ! supress && !TYPE_HASZ(type) && TYPE_HASM(type) ) writeM=1;
 
556
 
 
557
 
 
558
        /* Skip the bounding box if there is one */
 
559
        if ( TYPE_HASBBOX(type) )
 
560
        {
 
561
                geom+=16;
 
562
        }
 
563
 
 
564
        if ( TYPE_HASSRID(type) )
 
565
        {
 
566
                write_str("SRID=");
 
567
                write_int(read_int(&geom));
 
568
                write_str(";");
 
569
        }
 
570
 
 
571
        switch (TYPE_GETTYPE(type))
 
572
        {
 
573
        case POINTTYPE:
 
574
                if ( supress < 2 )
 
575
                {
 
576
                        if (writeM) write_str("POINTM");
 
577
                        else write_str("POINT");
 
578
                }
 
579
                geom=output_single(geom,0);
 
580
                break;
 
581
        case LINETYPE:
 
582
                if ( supress < 2 )
 
583
                {
 
584
                        if (writeM) write_str("LINESTRINGM");
 
585
                        else write_str("LINESTRING");
 
586
                }
 
587
                geom = output_line_collection(geom,output_point,0);
 
588
                break;
 
589
        case CIRCSTRINGTYPE:
 
590
                if ( supress < 2 )
 
591
                {
 
592
                        if (writeM) write_str("CIRCULARSTRINGM");
 
593
                        else write_str("CIRCULARSTRING");
 
594
                }
 
595
                geom = output_circstring_collection(geom,output_point,0);
 
596
                break;
 
597
        case POLYGONTYPE:
 
598
                if ( supress < 2 )
 
599
                {
 
600
                        if (writeM) write_str("POLYGONM");
 
601
                        else write_str("POLYGON");
 
602
                }
 
603
                geom = output_collection(geom,output_polygon_collection,0);
 
604
                break;
 
605
        case COMPOUNDTYPE:
 
606
                if ( supress < 2 )
 
607
                {
 
608
                        if (writeM) write_str("COMPOUNDCURVEM");
 
609
                        else write_str("COMPOUNDCURVE");
 
610
                }
 
611
                geom = output_collection(geom, output_compound,1);
 
612
                break;
 
613
        case CURVEPOLYTYPE:
 
614
                if (supress < 2)
 
615
                {
 
616
                        if (writeM) write_str("CURVEPOLYGONM");
 
617
                        else write_str("CURVEPOLYGON");
 
618
                }
 
619
                geom = output_collection(geom, output_curvepoly,0);
 
620
                break;
 
621
        case MULTIPOINTTYPE:
 
622
                if ( supress < 2 )
 
623
                {
 
624
                        if (writeM) write_str("MULTIPOINTM");
 
625
                        else write_str("MULTIPOINT");
 
626
                }
 
627
                geom = output_collection(geom,output_multipoint,2);
 
628
                break;
 
629
        case MULTILINETYPE:
 
630
                if ( supress < 2 )
 
631
                {
 
632
                        if (writeM) write_str("MULTILINESTRINGM");
 
633
                        else write_str("MULTILINESTRING");
 
634
                }
 
635
                geom = output_collection(geom,output_wkt,2);
 
636
                break;
 
637
        case MULTICURVETYPE:
 
638
                if ( supress < 2 )
 
639
                {
 
640
                        if (writeM) write_str("MULTICURVEM");
 
641
                        else write_str("MULTICURVE");
 
642
                }
 
643
                geom = output_collection(geom,output_compound,2);
 
644
                break;
 
645
        case MULTIPOLYGONTYPE:
 
646
                if ( supress < 2 )
 
647
                {
 
648
                        if (writeM) write_str("MULTIPOLYGONM");
 
649
                        else write_str("MULTIPOLYGON");
 
650
                }
 
651
                geom = output_collection(geom,output_wkt,2);
 
652
                break;
 
653
        case MULTISURFACETYPE:
 
654
                if ( supress < 2)
 
655
                {
 
656
                        if (writeM) write_str("MULTISURFACEM");
 
657
                        else write_str("MULTISURFACE");
 
658
                }
 
659
                geom = output_collection(geom,output_multisurface,2);
 
660
                break;
 
661
        case COLLECTIONTYPE:
 
662
                if ( supress < 2 )
 
663
                {
 
664
                        if (writeM) write_str("GEOMETRYCOLLECTIONM");
 
665
                        else write_str("GEOMETRYCOLLECTION");
 
666
                }
 
667
                geom = output_collection(geom,output_wkt,1);
 
668
                break;
 
669
 
 
670
        case POINTTYPEI:
 
671
                if ( supress < 2 )
 
672
                {
 
673
                        if (writeM) write_str("POINTM");
 
674
                        else write_str("POINT");
 
675
                }
 
676
                lwgi++;
 
677
                geom=output_single(geom,0);
 
678
                lwgi--;
 
679
                break;
 
680
        case LINETYPEI:
 
681
                if ( supress < 2 )
 
682
                {
 
683
                        if (writeM) write_str("LINESTRINGM");
 
684
                        else write_str("LINESTRING");
 
685
                }
 
686
                lwgi++;
 
687
                geom = output_collection(geom,output_point,0);
 
688
                lwgi--;
 
689
                break;
 
690
        case POLYGONTYPEI:
 
691
                if ( supress < 2 )
 
692
                {
 
693
                        if (writeM) write_str("POLYGONM");
 
694
                        else write_str("POLYGON");
 
695
                }
 
696
                lwgi++;
 
697
                geom = output_collection(geom,output_polygon_collection,0);
 
698
                lwgi--;
 
699
                break;
 
700
        }
 
701
        return geom;
 
702
}
 
703
 
 
704
int
 
705
unparse_WKT(LWGEOM_UNPARSER_RESULT *lwg_unparser_result, uchar* serialized, allocator alloc, freeor free, int flags)
 
706
{
 
707
 
 
708
        LWDEBUGF(2, "unparse_WKT called with parser flags %d.", flags);
 
709
 
 
710
        if (serialized==NULL)
 
711
                return 0;
 
712
 
 
713
        /* Setup the inital parser flags and empty the return struct */
 
714
        current_lwg_unparser_result = lwg_unparser_result;
 
715
        current_unparser_check_flags = flags;
 
716
        lwg_unparser_result->wkoutput = NULL;
 
717
        lwg_unparser_result->size = 0;
 
718
        lwg_unparser_result->serialized_lwgeom = serialized;
 
719
 
 
720
        unparser_ferror_occured = 0;
 
721
        local_malloc=alloc;
 
722
        local_free=free;
 
723
        len = 128;
 
724
        out_start = out_pos = alloc(len);
 
725
        lwgi=0;
 
726
 
 
727
        output_wkt(serialized, 0);
 
728
 
 
729
        /* Store the result in the struct */
 
730
        lwg_unparser_result->wkoutput = out_start;
 
731
        lwg_unparser_result->size = strlen(out_start);
 
732
 
 
733
        return unparser_ferror_occured;
 
734
}
 
735
 
 
736
static char outchr[]=
 
737
    {"0123456789ABCDEF"
 
738
    };
 
739
 
 
740
/* Write HEX bytes flipping */
 
741
void
 
742
write_wkb_hex_flip_bytes(uchar* ptr, unsigned int cnt, size_t size)
 
743
{
 
744
        unsigned int bc; /* byte count */
 
745
 
 
746
        ensure(cnt*2*size);
 
747
 
 
748
        while (cnt--)
 
749
        {
 
750
                for (bc=size; bc; bc--)
 
751
                {
 
752
                        *out_pos++ = outchr[ptr[bc-1]>>4];
 
753
                        *out_pos++ = outchr[ptr[bc-1]&0x0F];
 
754
                }
 
755
                ptr+=size;
 
756
        }
 
757
}
 
758
 
 
759
/* Write HEX bytes w/out flipping */
 
760
void
 
761
write_wkb_hex_bytes(uchar* ptr, unsigned int cnt, size_t size)
 
762
{
 
763
        unsigned int bc; /* byte count */
 
764
 
 
765
        ensure(cnt*2*size);
 
766
 
 
767
        while (cnt--)
 
768
        {
 
769
                for (bc=0; bc<size; bc++)
 
770
                {
 
771
                        *out_pos++ = outchr[ptr[bc]>>4];
 
772
                        *out_pos++ = outchr[ptr[bc]&0x0F];
 
773
                }
 
774
                ptr+=size;
 
775
        }
 
776
}
 
777
 
 
778
/* Write BIN bytes flipping */
 
779
void
 
780
write_wkb_bin_flip_bytes(uchar* ptr, unsigned int cnt, size_t size)
 
781
{
 
782
        unsigned int bc; /* byte count */
 
783
 
 
784
        ensure(cnt*size);
 
785
 
 
786
        while (cnt--)
 
787
        {
 
788
                for (bc=size; bc; bc--)
 
789
                        *out_pos++ = ptr[bc-1];
 
790
                ptr+=size;
 
791
        }
 
792
}
 
793
 
 
794
 
 
795
/* Write BIN bytes w/out flipping */
 
796
void
 
797
write_wkb_bin_bytes(uchar* ptr, unsigned int cnt, size_t size)
 
798
{
 
799
        unsigned int bc; /* byte count */
 
800
 
 
801
        ensure(cnt*size);
 
802
 
 
803
        /* Could just use a memcpy here ... */
 
804
        while (cnt--)
 
805
        {
 
806
                for (bc=0; bc<size; bc++)
 
807
                        *out_pos++ = ptr[bc];
 
808
                ptr+=size;
 
809
        }
 
810
}
 
811
 
 
812
uchar *
 
813
output_wkb_point(uchar* geom)
 
814
{
 
815
        if ( lwgi )
 
816
        {
 
817
                write_wkb_bytes(geom,dims,4);
 
818
                return geom + (4*dims);
 
819
        }
 
820
        else
 
821
        {
 
822
                write_wkb_bytes(geom,dims,8);
 
823
                return geom + (8*dims);
 
824
        }
 
825
}
 
826
 
 
827
void
 
828
write_wkb_int(int i)
 
829
{
 
830
        write_wkb_bytes((uchar*)&i,1,4);
 
831
}
 
832
 
 
833
/* Output a standard collection */
 
834
uchar *
 
835
output_wkb_collection(uchar* geom,outwkbfunc func)
 
836
{
 
837
        int cnt = read_int(&geom);
 
838
 
 
839
        LWDEBUGF(2, "output_wkb_collection: %d iterations loop", cnt);
 
840
 
 
841
        write_wkb_int(cnt);
 
842
        while (cnt--) geom=func(geom);
 
843
        return geom;
 
844
}
 
845
 
 
846
/* Output a set of LINESTRING points */
 
847
uchar *
 
848
output_wkb_line_collection(uchar* geom,outwkbfunc func)
 
849
{
 
850
        int cnt = read_int(&geom);
 
851
        int orig_cnt = cnt;
 
852
 
 
853
        LWDEBUGF(2, "output_wkb_line_collection: %d iterations loop", cnt);
 
854
 
 
855
        write_wkb_int(cnt);
 
856
        while (cnt--) geom=func(geom);
 
857
 
 
858
        /* Ensure that LINESTRING has a minimum of 2 points */
 
859
        if ((current_unparser_check_flags & PARSER_CHECK_MINPOINTS) && orig_cnt < 2)
 
860
        {
 
861
                LWGEOM_WKB_UNPARSER_ERROR(UNPARSER_ERROR_MOREPOINTS);
 
862
        }
 
863
 
 
864
        return geom;
 
865
}
 
866
 
 
867
/* Output an individual ring from a POLYGON  */
 
868
uchar *
 
869
output_wkb_polygon_ring_collection(uchar* geom,outwkbfunc func)
 
870
{
 
871
        uchar *temp;
 
872
        int dimcount;
 
873
        double *first_point;
 
874
        double *last_point;
 
875
        int cnt;
 
876
        int orig_cnt;
 
877
 
 
878
        first_point = lwalloc(dims * sizeof(double));
 
879
        last_point = lwalloc(dims * sizeof(double));
 
880
 
 
881
        cnt = read_int(&geom);
 
882
        orig_cnt = cnt;
 
883
 
 
884
        LWDEBUGF(2, "output_wkb_polygon_ring_collection: %d iterations loop", cnt);
 
885
 
 
886
        write_wkb_int(cnt);
 
887
 
 
888
        /* Store the first point of the ring (use a temp var since read_double alters
 
889
           the pointer after use) */
 
890
        temp = geom;
 
891
        dimcount = 0;
 
892
        while (dimcount < dims)
 
893
        {
 
894
                first_point[dimcount] = read_double(&temp);
 
895
                dimcount++;
 
896
        }
 
897
 
 
898
        while (cnt--) geom=func(geom);
 
899
 
 
900
        /* Store the last point of the ring (note: we will have moved past it, so we
 
901
           need to count backwards) */
 
902
        temp = geom - sizeof(double) * dims;
 
903
        dimcount = 0;
 
904
        while (dimcount < dims)
 
905
        {
 
906
                last_point[dimcount] = read_double(&temp);
 
907
                dimcount++;
 
908
        }
 
909
 
 
910
        /* Check if they are the same... */
 
911
        if (((first_point[0] != last_point[0]) ||
 
912
                (first_point[1] != last_point[1])) &&
 
913
                (current_unparser_check_flags & PARSER_CHECK_CLOSURE))
 
914
        {
 
915
                LWGEOM_WKB_UNPARSER_ERROR(UNPARSER_ERROR_UNCLOSED);
 
916
        }
 
917
 
 
918
        /* Ensure that POLYGON has a minimum of 4 points */
 
919
        if ((current_unparser_check_flags & PARSER_CHECK_MINPOINTS) && orig_cnt < 4)
 
920
        {
 
921
                LWGEOM_WKB_UNPARSER_ERROR(UNPARSER_ERROR_MOREPOINTS);
 
922
        }
 
923
 
 
924
        lwfree(first_point);
 
925
        lwfree(last_point);
 
926
 
 
927
        return geom;
 
928
}
 
929
 
 
930
/* Output a POLYGON consisting of a number of rings */
 
931
uchar *
 
932
output_wkb_polygon_collection(uchar* geom)
 
933
{
 
934
        LWDEBUG(2, "output_wkb_polygon_collection");
 
935
 
 
936
        return output_wkb_polygon_ring_collection(geom,output_wkb_point);
 
937
}
 
938
 
 
939
/* Ouput the points from a CIRCULARSTRING */
 
940
uchar *
 
941
output_wkb_circstring_collection(uchar* geom,outwkbfunc func)
 
942
{
 
943
        int cnt = read_int(&geom);
 
944
        int orig_cnt = cnt;
 
945
 
 
946
        LWDEBUGF(2, "output_wkb_curve_collection: %d iterations loop", cnt);
 
947
 
 
948
        write_wkb_int(cnt);
 
949
        while (cnt--) geom=func(geom);
 
950
 
 
951
        /* Ensure that a CIRCULARSTRING has a minimum of 3 points */
 
952
        if ((current_unparser_check_flags & PARSER_CHECK_MINPOINTS) && orig_cnt < 3)
 
953
        {
 
954
                LWGEOM_WKB_UNPARSER_ERROR(UNPARSER_ERROR_MOREPOINTS);
 
955
        }
 
956
 
 
957
        /* Ensure that a CIRCULARSTRING has an odd number of points */
 
958
        if ((current_unparser_check_flags & PARSER_CHECK_ODD) && orig_cnt % 2 != 1)
 
959
        {
 
960
                LWGEOM_WKB_UNPARSER_ERROR(UNPARSER_ERROR_ODDPOINTS);
 
961
        }
 
962
 
 
963
        return geom;
 
964
}
 
965
 
 
966
uchar *
 
967
output_wkb(uchar* geom)
 
968
{
 
969
        unsigned char type=*geom++;
 
970
        int4 wkbtype;
 
971
 
 
972
        dims = TYPE_NDIMS(type);
 
973
 
 
974
        LWDEBUGF(2, "output_wkb: dims set to %d", dims);
 
975
 
 
976
        /* Skip the bounding box */
 
977
        if ( TYPE_HASBBOX(type) )
 
978
        {
 
979
                geom+=16;
 
980
        }
 
981
 
 
982
        wkbtype = TYPE_GETTYPE(type);
 
983
 
 
984
        if ( TYPE_HASZ(type) )
 
985
                wkbtype |= WKBZOFFSET;
 
986
        if ( TYPE_HASM(type) )
 
987
                wkbtype |= WKBMOFFSET;
 
988
        if ( TYPE_HASSRID(type) )
 
989
        {
 
990
                wkbtype |= WKBSRIDFLAG;
 
991
        }
 
992
 
 
993
 
 
994
        /* Write byteorder (as from WKB specs...) */
 
995
        write_wkb_bytes(&endianbyte,1,1);
 
996
 
 
997
        write_wkb_int(wkbtype);
 
998
 
 
999
        if ( TYPE_HASSRID(type) )
 
1000
        {
 
1001
                write_wkb_int(read_int(&geom));
 
1002
        }
 
1003
 
 
1004
        switch (TYPE_GETTYPE(type))
 
1005
        {
 
1006
        case POINTTYPE:
 
1007
                geom=output_wkb_point(geom);
 
1008
                break;
 
1009
        case LINETYPE:
 
1010
                geom=output_wkb_line_collection(geom,output_wkb_point);
 
1011
                break;
 
1012
        case CIRCSTRINGTYPE:
 
1013
                geom=output_wkb_circstring_collection(geom,output_wkb_point);
 
1014
                break;
 
1015
        case POLYGONTYPE:
 
1016
                geom=output_wkb_collection(geom,output_wkb_polygon_collection);
 
1017
                break;
 
1018
        case COMPOUNDTYPE:
 
1019
                geom=output_wkb_collection(geom,output_wkb);
 
1020
                break;
 
1021
        case CURVEPOLYTYPE:
 
1022
                geom=output_wkb_collection(geom,output_wkb);
 
1023
                break;
 
1024
        case MULTICURVETYPE:
 
1025
        case MULTISURFACETYPE:
 
1026
        case MULTIPOINTTYPE:
 
1027
        case MULTILINETYPE:
 
1028
        case MULTIPOLYGONTYPE:
 
1029
        case COLLECTIONTYPE:
 
1030
                geom = output_wkb_collection(geom,output_wkb);
 
1031
                break;
 
1032
 
 
1033
                /*
 
1034
                        These don't output standard wkb at the moment
 
1035
                        the output and integer version.
 
1036
 
 
1037
                        however you could run it through the wkt parser
 
1038
                        for a lwg and then output that.  There should
 
1039
                        also be a force_to_real_(lwgi)
 
1040
                */
 
1041
        case POINTTYPEI:
 
1042
                lwgi++;
 
1043
                geom=output_wkb_point(geom);
 
1044
                lwgi--;
 
1045
                break;
 
1046
        case LINETYPEI:
 
1047
                lwgi++;
 
1048
                geom = output_wkb_collection(geom,output_wkb_point);
 
1049
                lwgi--;
 
1050
                break;
 
1051
        case POLYGONTYPEI:
 
1052
                lwgi++;
 
1053
                geom = output_wkb_collection(geom,output_wkb_polygon_collection);
 
1054
                lwgi--;
 
1055
                break;
 
1056
        }
 
1057
        return geom;
 
1058
}
 
1059
 
 
1060
int
 
1061
unparse_WKB(LWGEOM_UNPARSER_RESULT *lwg_unparser_result, uchar* serialized, allocator alloc, freeor free, int flags, char endian, uchar hex)
 
1062
{
 
1063
        LWDEBUGF(2, "unparse_WKB(%p,...) called with parser flags %d", serialized, flags);
 
1064
 
 
1065
        if (serialized==0)
 
1066
                return 0;
 
1067
 
 
1068
        /* Setup the inital parser flags and empty the return struct */
 
1069
        current_lwg_unparser_result = lwg_unparser_result;
 
1070
        current_unparser_check_flags = flags;
 
1071
        lwg_unparser_result->wkoutput = NULL;
 
1072
        lwg_unparser_result->size = 0;
 
1073
        lwg_unparser_result->serialized_lwgeom = serialized;
 
1074
 
 
1075
        unparser_ferror_occured = 0;
 
1076
        local_malloc=alloc;
 
1077
        local_free=free;
 
1078
        len = 128;
 
1079
        out_start = out_pos = alloc(len);
 
1080
        lwgi=0;
 
1081
 
 
1082
        if ( endian == (char)-1 )
 
1083
        {
 
1084
                endianbyte = getMachineEndian();
 
1085
                if ( hex ) write_wkb_bytes = write_wkb_hex_bytes;
 
1086
                else write_wkb_bytes = write_wkb_bin_bytes;
 
1087
        }
 
1088
        else
 
1089
        {
 
1090
                endianbyte = endian;
 
1091
                if ( endianbyte != getMachineEndian() )
 
1092
                {
 
1093
                        if ( hex ) write_wkb_bytes = write_wkb_hex_flip_bytes;
 
1094
                        else write_wkb_bytes = write_wkb_bin_flip_bytes;
 
1095
                }
 
1096
                else
 
1097
                {
 
1098
                        if ( hex ) write_wkb_bytes = write_wkb_hex_bytes;
 
1099
                        else write_wkb_bytes = write_wkb_bin_bytes;
 
1100
                }
 
1101
        }
 
1102
 
 
1103
        output_wkb(serialized);
 
1104
 
 
1105
        if ( hex )
 
1106
        {
 
1107
                ensure(1);
 
1108
                *out_pos=0;
 
1109
        }
 
1110
 
 
1111
        /* Store the result in the struct */
 
1112
        lwg_unparser_result->wkoutput = out_start;
 
1113
        lwg_unparser_result->size = (out_pos-out_start);
 
1114
 
 
1115
        return unparser_ferror_occured;
 
1116
}
 
1117
 
 
1118
 
 
1119
/******************************************************************
 
1120
 * $Log$
 
1121
 * Revision 1.23  2006/02/06 11:12:22  strk
 
1122
 * uint32_t typedef moved back from wktparse.h to lwgparse.c and wktunparse.c
 
1123
 *
 
1124
 * Revision 1.22  2006/02/03 20:53:37  strk
 
1125
 * Swapped stdint.h (unavailable on Solaris9) with inttypes.h
 
1126
 *
 
1127
 * Revision 1.21  2006/02/03 09:52:14  strk
 
1128
 * Changed int4 typedefs to use POSIX uint32_t
 
1129
 *
 
1130
 * Revision 1.20  2006/01/09 15:12:02  strk
 
1131
 * ISO C90 comments
 
1132
 *
 
1133
 * Revision 1.19  2005/03/10 18:19:16  strk
 
1134
 * Made void args explicit to make newer compilers happy
 
1135
 *
 
1136
 * Revision 1.18  2005/02/21 16:16:14  strk
 
1137
 * Changed byte to uchar to avoid clashes with win32 headers.
 
1138
 *
 
1139
 * Revision 1.17  2005/02/07 13:21:10  strk
 
1140
 * Replaced DEBUG* macros with PGIS_DEBUG*, to avoid clashes with postgresql DEBUG
 
1141
 *
 
1142
 * Revision 1.16  2005/01/18 09:32:03  strk
 
1143
 * Changed unparse_WKB interface to take an output size pointer and an HEXFORM
 
1144
 * specifier. Reworked code in wktunparse to use function pointers.
 
1145
 *
 
1146
 * Revision 1.15  2004/12/21 15:19:01  strk
 
1147
 * Canonical binary reverted back to EWKB, now supporting SRID inclusion.
 
1148
 *
 
1149
 * Revision 1.14  2004/12/17 11:08:53  strk
 
1150
 * Moved getMachineEndian from parser to liblwgeom.{h,c}.
 
1151
 * Added XDR and NDR defines.
 
1152
 * Fixed all usage of them.
 
1153
 *
 
1154
 * Revision 1.13  2004/10/25 12:27:33  strk
 
1155
 * Removed useless network type includes,
 
1156
 * Added param.h include for BYTE_ORDER defines under win32.
 
1157
 *
 
1158
 * Revision 1.12  2004/10/21 19:48:34  strk
 
1159
 * Stricter syntax fixes. Reported by S�bastien NICAISE <snicaise@iciatechnologies.com>
 
1160
 *
 
1161
 * Revision 1.11  2004/10/15 07:35:41  strk
 
1162
 * Fixed a bug introduced by me (byteorder skipped for inner geoms in WKB)
 
1163
 *
 
1164
 * Revision 1.10  2004/10/11 14:03:33  strk
 
1165
 * Added endiannes specification to unparse_WKB, AsBinary, lwgeom_to_wkb.
 
1166
 *
 
1167
 ******************************************************************/