~ubuntu-branches/ubuntu/feisty/postgis/feisty

« back to all changes in this revision

Viewing changes to loader/pgsql2shp.c

  • Committer: Bazaar Package Importer
  • Author(s): Alex Bodnaru
  • Date: 2005-05-05 10:02:45 UTC
  • Revision ID: james.westby@ubuntu.com-20050505100245-3005l6jn1jwvpsrw
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**********************************************************************
 
2
 * $Id: pgsql2shp.c,v 1.74 2005/03/25 18:43:07 strk Exp $
 
3
 *
 
4
 * PostGIS - Spatial Types for PostgreSQL
 
5
 * http://postgis.refractions.net
 
6
 * Copyright 2001-2003 Refractions Research Inc.
 
7
 *
 
8
 * This is free software; you can redistribute and/or modify it under
 
9
 * the terms of the GNU General Public Licence. See the COPYING file.
 
10
 * 
 
11
 **********************************************************************
 
12
 *
 
13
 * PostGIS to Shapefile converter
 
14
 *
 
15
 * Original Author: Jeff Lounsbury, jeffloun@refractions.net
 
16
 *
 
17
 * Maintainer: Sandro Santilli, strk@refractions.net
 
18
 *
 
19
 **********************************************************************/
 
20
 
 
21
static char rcsid[] =
 
22
  "$Id: pgsql2shp.c,v 1.74 2005/03/25 18:43:07 strk Exp $";
 
23
 
 
24
#include <stdio.h>
 
25
#include <stdlib.h>
 
26
#include <string.h>
 
27
#include <ctype.h>
 
28
#include <math.h>
 
29
#include <sys/types.h>
 
30
#include "libpq-fe.h"
 
31
#include "shapefil.h"
 
32
#include "getopt.h"
 
33
#include "compat.h"
 
34
 
 
35
#ifdef __CYGWIN__
 
36
#include <sys/param.h>       
 
37
#endif
 
38
 
 
39
#define POINTTYPE       1
 
40
#define LINETYPE        2
 
41
#define POLYGONTYPE     3
 
42
#define MULTIPOINTTYPE  4
 
43
#define MULTILINETYPE   5
 
44
#define MULTIPOLYGONTYPE        6
 
45
#define COLLECTIONTYPE  7
 
46
#define BBOXONLYTYPE    99
 
47
 
 
48
/*
 
49
 * Verbosity:
 
50
 *   set to 1 to see record fetching progress
 
51
 *   set to 2 to see also shapefile creation progress
 
52
 */
 
53
#define VERBOSE 1
 
54
 
 
55
/* Define this to use HEX encoding instead of bytea encoding */
 
56
#define HEXWKB 1
 
57
 
 
58
typedef unsigned long int uint32;
 
59
typedef unsigned char byte;
 
60
 
 
61
/* Global data */
 
62
PGconn *conn;
 
63
int rowbuflen;
 
64
char *geo_col_name, *table, *shp_file, *schema, *usrquery;
 
65
int type_ary[256];
 
66
char *main_scan_query;
 
67
DBFHandle dbf;
 
68
SHPHandle shp;
 
69
int geotype;
 
70
int outshptype;
 
71
char outtype;
 
72
int dswitchprovided;
 
73
int includegid;
 
74
int unescapedattrs;
 
75
int binary;
 
76
SHPObject * (*shape_creator)(byte *, int);
 
77
int big_endian = 0;
 
78
int pgis_major_version;
 
79
 
 
80
/* Prototypes */
 
81
int getMaxFieldSize(PGconn *conn, char *schema, char *table, char *fname);
 
82
int parse_commandline(int ARGC, char **ARGV);
 
83
void usage(int exitstatus);
 
84
char *getTableOID(char *schema, char *table);
 
85
int addRecord(PGresult *res, int residx, int row);
 
86
int initShapefile(char *shp_file, PGresult *res);
 
87
int initialize(void);
 
88
int getGeometryOID(PGconn *conn);
 
89
int getGeometryType(char *schema, char *table, char *geo_col_name);
 
90
int getGeometryMaxDims(char *schema, char *table, char *geo_col_name);
 
91
char *shapetypename(int num);
 
92
int parse_points(char *str, int num_points, double *x,double *y,double *z);
 
93
int num_points(char *str);
 
94
int num_lines(char *str);
 
95
char *scan_to_same_level(char *str);
 
96
int points_per_sublist( char *str, int *npoints, long max_lists);
 
97
int reverse_points(int num_points, double *x, double *y, double *z, double *m);
 
98
int is_clockwise(int num_points,double *x,double *y,double *z);
 
99
int is_bigendian(void);
 
100
SHPObject * shape_creator_wrapper_WKB(byte *str, int idx);
 
101
int get_postgis_major_version(void);
 
102
static void parse_table(char *spec);
 
103
static int create_usrquerytable(void);
 
104
 
 
105
/* WKB functions */
 
106
SHPObject * create_polygon2D_WKB(byte *wkb);
 
107
SHPObject * create_polygon3D_WKB(byte *wkb);
 
108
SHPObject * create_polygon4D_WKB(byte *wkb);
 
109
SHPObject * create_multipoint2D_WKB(byte *wkb);
 
110
SHPObject * create_multipoint3D_WKB(byte *wkb);
 
111
SHPObject * create_multipoint4D_WKB(byte *wkb);
 
112
SHPObject * create_point2D_WKB(byte *wkb);
 
113
SHPObject * create_point3D_WKB(byte *wkb);
 
114
SHPObject * create_point4D_WKB(byte *wkb);
 
115
SHPObject * create_multiline2D_WKB (byte *wkb);
 
116
SHPObject * create_multiline3D_WKB (byte *wkb);
 
117
SHPObject * create_multiline4D_WKB (byte *wkb);
 
118
SHPObject * create_line2D_WKB(byte *wkb);
 
119
SHPObject * create_line3D_WKB(byte *wkb);
 
120
SHPObject * create_line4D_WKB(byte *wkb);
 
121
SHPObject * create_multipolygon2D_WKB(byte *wkb);
 
122
SHPObject * create_multipolygon3D_WKB(byte *wkb);
 
123
SHPObject * create_multipolygon4D_WKB(byte *wkb);
 
124
byte getbyte(byte *c);
 
125
void skipbyte(byte **c);
 
126
byte popbyte(byte **c);
 
127
uint32 popint(byte **c);
 
128
uint32 getint(byte *c);
 
129
void skipint(byte **c);
 
130
double popdouble(byte **c);
 
131
void skipdouble(byte **c);
 
132
void dump_wkb(byte *wkb);
 
133
byte * HexDecode(byte *hex);
 
134
 
 
135
#define WKBZOFFSET 0x80000000
 
136
#define WKBMOFFSET 0x40000000
 
137
#define ZMFLAG(x) (((x)&((WKBZOFFSET)+(WKBMOFFSET)))>>30)
 
138
 
 
139
 
 
140
static void exit_nicely(PGconn *conn){
 
141
        PQfinish(conn);
 
142
        exit(1);
 
143
}
 
144
 
 
145
int
 
146
main(int ARGC, char **ARGV)
 
147
{
 
148
        char *query=NULL;
 
149
        int row;
 
150
        PGresult *res;
 
151
        char fetchquery[256];
 
152
 
 
153
        dbf=NULL;
 
154
        shp=NULL;
 
155
        geotype=-1;
 
156
        shape_creator = NULL;
 
157
        table = NULL;
 
158
        schema = NULL;
 
159
        usrquery = NULL;
 
160
        geo_col_name = NULL;
 
161
        shp_file = NULL;
 
162
        main_scan_query = NULL;
 
163
        rowbuflen=100;
 
164
        outtype = 's';
 
165
        dswitchprovided = 0;
 
166
        includegid=0;
 
167
        unescapedattrs=0;
 
168
        binary = 0;
 
169
#ifdef DEBUG
 
170
        FILE *debug;
 
171
#endif
 
172
 
 
173
        if ( getenv("ROWBUFLEN") ) rowbuflen=atoi(getenv("ROWBUFLEN"));
 
174
 
 
175
        if ( ARGC == 1 ) {
 
176
                usage(0);
 
177
        }
 
178
 
 
179
        if ( ! parse_commandline(ARGC, ARGV) ) {
 
180
                printf("\n**ERROR** invalid option or command parameters\n\n");
 
181
                usage(2);
 
182
        }
 
183
 
 
184
        /* Use table name as shapefile name */
 
185
        if(shp_file == NULL) shp_file = table;
 
186
 
 
187
        /* Make a connection to the specified database, and exit on failure */
 
188
        conn = PQconnectdb("");
 
189
        if (PQstatus(conn) == CONNECTION_BAD) {
 
190
                printf( "%s", PQerrorMessage(conn));
 
191
                exit_nicely(conn);
 
192
        }
 
193
 
 
194
        /* Create temporary table for user query */
 
195
        if ( usrquery ) {
 
196
                if ( ! create_usrquerytable() ) {
 
197
                        exit(2);
 
198
                }
 
199
        }
 
200
 
 
201
#ifdef DEBUG
 
202
        debug = fopen("/tmp/trace.out", "w");
 
203
        PQtrace(conn, debug);
 
204
#endif   /* DEBUG */
 
205
 
 
206
 
 
207
        /* Initialize shapefile and database infos */
 
208
        fprintf(stdout, "Initializing... "); fflush(stdout);
 
209
        if ( ! initialize() ) exit_nicely(conn);
 
210
        fprintf(stdout, "Done (postgis major version: %d).\n",
 
211
                pgis_major_version); 
 
212
 
 
213
        if ( pgis_major_version > 0 && dswitchprovided )
 
214
        {
 
215
                printf("WARNING: -d switch is useless when dumping from postgis-1.0.0+\n");
 
216
        }
 
217
 
 
218
 
 
219
        printf("Output shape: %s\n", shapetypename(outshptype));
 
220
 
 
221
 
 
222
        /*
 
223
         * Begin the transaction
 
224
         * (a cursor can only be defined inside a transaction block)
 
225
         */
 
226
        res=PQexec(conn, "BEGIN");
 
227
        if ( ! res || PQresultStatus(res) != PGRES_COMMAND_OK ) {
 
228
                printf( "%s", PQerrorMessage(conn));
 
229
                exit_nicely(conn);
 
230
        }
 
231
        PQclear(res);
 
232
 
 
233
        /*
 
234
         * Declare a cursor for the main scan query
 
235
         * as set by the initializer function.
 
236
         */
 
237
        query = (char *)malloc(strlen(main_scan_query)+256);
 
238
        if ( binary ) {
 
239
                sprintf(query, "DECLARE cur BINARY CURSOR FOR %s",
 
240
                                main_scan_query);
 
241
        } else {
 
242
                sprintf(query, "DECLARE cur CURSOR FOR %s", main_scan_query);
 
243
        }
 
244
#if VERBOSE > 2
 
245
        printf( "MAINSCAN: %s\n", main_scan_query);
 
246
#endif
 
247
        free(main_scan_query);
 
248
        res = PQexec(conn, query);
 
249
        free(query);
 
250
        if ( ! res || PQresultStatus(res) != PGRES_COMMAND_OK ) {
 
251
                printf( "MainScanQuery: %s", PQerrorMessage(conn));
 
252
                exit_nicely(conn);
 
253
        }
 
254
        PQclear(res);
 
255
 
 
256
        /* Set the fetch query */
 
257
        sprintf(fetchquery, "FETCH %d FROM cur", rowbuflen);
 
258
 
 
259
        fprintf(stdout, "Dumping: "); fflush(stdout);
 
260
        /*
 
261
         * Main scan
 
262
         */
 
263
        row=0;
 
264
        while(1)
 
265
        {
 
266
                int i;
 
267
 
 
268
                /* Fetch next record buffer from cursor */
 
269
#if VERBOSE 
 
270
                fprintf(stdout, "X"); fflush(stdout);
 
271
#endif
 
272
                res = PQexec(conn, fetchquery);
 
273
                if ( ! res || PQresultStatus(res) != PGRES_TUPLES_OK ) {
 
274
                        printf( "RecordFetch: %s",
 
275
                                PQerrorMessage(conn));
 
276
                        exit_nicely(conn);
 
277
                }
 
278
 
 
279
                /* No more rows, break the loop */
 
280
                if ( ! PQntuples(res) ) {
 
281
                        PQclear(res);
 
282
                        break;
 
283
                }
 
284
 
 
285
                for(i=0; i<PQntuples(res); i++)
 
286
                {
 
287
                        /* Add record in all output files */
 
288
                        if ( ! addRecord(res, i, row) ) exit_nicely(conn);
 
289
                        row++; 
 
290
                }
 
291
 
 
292
#if VERBOSE > 2
 
293
                printf("End of result, clearing..."); fflush(stdout);
 
294
#endif
 
295
                PQclear(res);
 
296
#if VERBOSE > 2
 
297
                printf("Done.\n");
 
298
#endif
 
299
        }
 
300
        printf(" [%d rows].\n", row);
 
301
 
 
302
        DBFClose(dbf);
 
303
        if (shp) SHPClose(shp);
 
304
        exit_nicely(conn);
 
305
 
 
306
 
 
307
#ifdef DEBUG
 
308
        fclose(debug);
 
309
#endif   /* DEBUG */
 
310
 
 
311
        return 0;
 
312
}
 
313
 
 
314
 
 
315
 
 
316
SHPObject *
 
317
shape_creator_wrapper_WKB(byte *str, int idx)
 
318
{
 
319
        byte *ptr = str;
 
320
        uint32 type;
 
321
        int ndims;
 
322
        int wkb_big_endian;
 
323
 
 
324
        // skip byte order
 
325
        //skipbyte(&ptr);
 
326
        wkb_big_endian = ! popbyte(&ptr);
 
327
        if ( wkb_big_endian != big_endian )
 
328
        {
 
329
                printf( "Wrong WKB endiannes, dunno how to flip\n");
 
330
                exit(1);
 
331
        }
 
332
 
 
333
        // get type
 
334
        type = getint(ptr);
 
335
 
 
336
        ndims=2;
 
337
        if ( type&WKBZOFFSET ) ndims++;
 
338
        if ( type&WKBMOFFSET )
 
339
        {
 
340
 
 
341
                ndims++;
 
342
        }
 
343
 
 
344
        type &= ~WKBZOFFSET;
 
345
        type &= ~WKBMOFFSET;
 
346
 
 
347
        switch(type)
 
348
        {
 
349
                case MULTILINETYPE:
 
350
                        if ( ndims == 2 )
 
351
                                return create_multiline2D_WKB(str);
 
352
                        else if ( ndims == 3 )
 
353
                                return create_multiline3D_WKB(str);
 
354
                        else if ( ndims == 4 )
 
355
                                return create_multiline4D_WKB(str);
 
356
                                
 
357
                case LINETYPE:
 
358
                        if ( ndims == 2 )
 
359
                                return create_line2D_WKB(str);
 
360
                        else if ( ndims == 3 )
 
361
                                return create_line3D_WKB(str);
 
362
                        else if ( ndims == 4 )
 
363
                                return create_line4D_WKB(str);
 
364
 
 
365
                case POLYGONTYPE:
 
366
                        if ( ndims == 2 )
 
367
                                return create_polygon2D_WKB(str);
 
368
                        else if ( ndims == 3 )
 
369
                                return create_polygon3D_WKB(str);
 
370
                        else if ( ndims == 4 )
 
371
                                return create_polygon4D_WKB(str);
 
372
 
 
373
                case MULTIPOLYGONTYPE:
 
374
                        if ( ndims == 2 )
 
375
                                return create_multipolygon2D_WKB(str);
 
376
                        else if ( ndims == 3 )
 
377
                                return create_multipolygon3D_WKB(str);
 
378
                        else if ( ndims == 4 )
 
379
                                return create_multipolygon4D_WKB(str);
 
380
 
 
381
                case POINTTYPE:
 
382
                        if ( ndims == 2 )
 
383
                                return create_point2D_WKB(str);
 
384
                        else if ( ndims == 3 )
 
385
                                return create_point3D_WKB(str);
 
386
                        else if ( ndims == 4 )
 
387
                                return create_point4D_WKB(str);
 
388
 
 
389
                case MULTIPOINTTYPE:
 
390
                        if ( ndims == 2 )
 
391
                                return create_multipoint2D_WKB(str);
 
392
                        else if ( ndims == 3 )
 
393
                                return create_multipoint3D_WKB(str);
 
394
                        else if ( ndims == 4 )
 
395
                                return create_multipoint4D_WKB(str);
 
396
 
 
397
                default:
 
398
                        printf( "Unknown WKB type (%8.8lx) - (%s:%d)\n",
 
399
                                type, __FILE__, __LINE__);
 
400
                        return NULL;
 
401
        }
 
402
}
 
403
 
 
404
//reads points into x,y,z co-ord arrays
 
405
int parse_points(char *str, int num_points, double *x,double *y,double *z){
 
406
        int     keep_going;
 
407
        int     num_found= 0;
 
408
        char    *end_of_double;
 
409
 
 
410
        if ( (str == NULL) || (str[0] == 0) ){
 
411
                return 0;  //either null string or empty string
 
412
        }
 
413
        
 
414
        //look ahead for the "("
 
415
        str = strchr(str,'(') ;
 
416
        
 
417
        if ( (str == NULL) || (str[1] == 0) ){  // str[0] = '(';
 
418
                return 0;  //either didnt find "(" or its at the end of the string
 
419
        }
 
420
        str++;  //move forward one char
 
421
        keep_going = 1;
 
422
        while (keep_going == 1){
 
423
                
 
424
                //attempt to get the point
 
425
                //scanf is slow, so we use strtod()
 
426
 
 
427
                x[num_found] = (double)strtod(str,&end_of_double);
 
428
                if (end_of_double == str){
 
429
                        return 0; //error occured (nothing parsed)
 
430
                }
 
431
                str = end_of_double;
 
432
                y[num_found] = strtod(str,&end_of_double);
 
433
                if (end_of_double == str){
 
434
                        return 0; //error occured (nothing parsed)
 
435
                }
 
436
                str = end_of_double;
 
437
                z[num_found] = strtod(str,&end_of_double); //will be zero if error occured
 
438
                str = end_of_double;
 
439
                num_found++;
 
440
 
 
441
                str=strpbrk(str,",)");  // look for a "," or ")"
 
442
                if (str != NULL && str[0] == ','){
 
443
                        str++;
 
444
                }
 
445
                keep_going = (str != NULL) && (str[0] != ')');          
 
446
        }
 
447
        return num_found; 
 
448
}
 
449
 
 
450
 
 
451
 
 
452
 
 
453
 
 
454
//returns how many points are in the first list in str
 
455
//
 
456
//  1. scan ahead looking for "("
 
457
//  2. find "," until hit a ")"
 
458
//  3. return number of points found
 
459
//      
 
460
// NOTE: doesnt actually parse the points, so if the 
 
461
//       str contains an invalid geometry, this could give
 
462
//         back the wrong answer.
 
463
//
 
464
// "(1 2 3, 4 5 6),(7 8, 9 10, 11 12 13)" => 2 (2nd list is not included)
 
465
int     num_points(char *str){
 
466
        int             keep_going;
 
467
        int             points_found = 1; //no "," if only one point (and last point)
 
468
                                                
 
469
 
 
470
        if ( (str == NULL) || (str[0] == 0) )
 
471
        {
 
472
                return 0;  //either null string or empty string
 
473
        }
 
474
 
 
475
        //look ahead for the "("
 
476
 
 
477
        str = strchr(str,'(') ;
 
478
        
 
479
        if ( (str == NULL) || (str[1] == 0) )  // str[0] = '(';
 
480
        {
 
481
                return 0;  //either didnt find "(" or its at the end of the string
 
482
        }
 
483
 
 
484
        keep_going = 1;
 
485
        while (keep_going) 
 
486
        {
 
487
                str=strpbrk(str,",)");  // look for a "," or ")"
 
488
                keep_going = (str != NULL);
 
489
                if (keep_going)  // found a , or )
 
490
                {
 
491
                        if (str[0] == ')')
 
492
                        {
 
493
                                //finished
 
494
                                return points_found;
 
495
                        }
 
496
                        else    //str[0] = ","
 
497
                        {
 
498
                                points_found++;
 
499
                                str++; //move 1 char forward    
 
500
                        }
 
501
                }
 
502
        }
 
503
        return points_found; // technically it should return an error.
 
504
}
 
505
 
 
506
//number of sublist in a string.
 
507
 
 
508
// Find the number of lines in a Multiline
 
509
// OR
 
510
// The number of rings in a Polygon
 
511
// OR
 
512
// The number of polygons in a multipolygon
 
513
 
 
514
// ( (..),(..),(..) )  -> 3
 
515
// ( ( (..),(..) ), ( (..) )) -> 2
 
516
// ( ) -> 0
 
517
// scan through the list, for every "(", depth (nesting) increases by 1
 
518
//                                for every ")", depth (nesting) decreases by 1
 
519
// if find a "(" at depth 1, then there is a sub list
 
520
//
 
521
// example: 
 
522
//      "(((..),(..)),((..)))"
 
523
//depth  12333223332112333210
 
524
//        +           +         increase here
 
525
 
 
526
int num_lines(char *str){
 
527
        int     current_depth = 0;
 
528
        int     numb_lists = 0;
 
529
 
 
530
 
 
531
        while ( (str != NULL) && (str[0] != 0) )
 
532
        {
 
533
                str=strpbrk(str,"()"); //look for "(" or ")"
 
534
                if (str != NULL)
 
535
                {
 
536
                        if (str[0] == '(')
 
537
                        {
 
538
                                current_depth++;
 
539
                                if (current_depth == 2)
 
540
                                        numb_lists ++;
 
541
                        }
 
542
                        if (str[0] == ')')
 
543
                        {
 
544
                                current_depth--;
 
545
                                if (current_depth == 0)
 
546
                                        return numb_lists ;
 
547
                        }
 
548
                        str++;
 
549
                }
 
550
        }
 
551
        return numb_lists ; // probably should give an error
 
552
}
 
553
 
 
554
 
 
555
 
 
556
//simple scan-forward to find the next "(" at the same level
 
557
//  ( (), (),(), ),(...
 
558
//                 + return this location
 
559
char *scan_to_same_level(char *str){
 
560
 
 
561
        //scan forward in string looking for at "(" at the same level
 
562
        // as the one its already pointing at
 
563
 
 
564
        int     current_depth = 0;
 
565
        int  first_one=1;
 
566
 
 
567
 
 
568
        while ( (str != NULL) && (str[0] != 0) )
 
569
        {
 
570
                str=strpbrk(str,"()");
 
571
                if (str != NULL)
 
572
                {
 
573
                        if (str[0] == '(')
 
574
                        {
 
575
                                if (!(first_one))
 
576
                                {
 
577
                                        if (current_depth == 0)
 
578
                                                return str;
 
579
                                }
 
580
                                else
 
581
                                        first_one = 0;  //ignore the first opening "("
 
582
                                current_depth++;
 
583
                        }
 
584
                        if (str[0] == ')')
 
585
                        {
 
586
                                current_depth--;
 
587
                        }
 
588
 
 
589
                        str++;
 
590
                }
 
591
        }
 
592
        return str ; // probably should give an error
 
593
}
 
594
 
 
595
 
 
596
 
 
597
 
 
598
 
 
599
 
 
600
// Find out how many points are in each sublist, put the result in the array npoints[]
 
601
//  (for at most max_list sublists)
 
602
//
 
603
//  ( (L1),(L2),(L3) )  --> npoints[0] = points in L1,
 
604
//                                  npoints[1] = points in L2,
 
605
//                                  npoints[2] = points in L3
 
606
//
 
607
// We find these by, again, scanning through str looking for "(" and ")"
 
608
// to determine the current depth.  We dont actually parse the points.
 
609
 
 
610
int points_per_sublist( char *str, int *npoints, long max_lists){
 
611
        //scan through, noting depth and ","s
 
612
 
 
613
        int     current_depth = 0;
 
614
        int     current_list =-1 ;
 
615
 
 
616
 
 
617
        while ( (str != NULL) && (str[0] != 0) )
 
618
        {
 
619
                str=strpbrk(str,"(),");  //find "(" or ")" or ","
 
620
                if (str != NULL)
 
621
                {
 
622
                        if (str[0] == '(')
 
623
                        {
 
624
                                current_depth++;
 
625
                                if (current_depth == 2)
 
626
                                {
 
627
                                        current_list ++;
 
628
                                        if (current_list >=max_lists)
 
629
                                                return 1;                       // too many sub lists found
 
630
                                        npoints[current_list] = 1;
 
631
                                }
 
632
                                // might want to return an error if depth>2
 
633
                        }
 
634
                        if (str[0] == ')')
 
635
                        {
 
636
                                current_depth--;
 
637
                                if (current_depth == 0)
 
638
                                        return 1 ;
 
639
                        }
 
640
                        if (str[0] == ',')
 
641
                        {
 
642
                                if (current_depth==2)
 
643
                                {
 
644
                                        npoints[current_list] ++;       
 
645
                                }
 
646
                        }
 
647
 
 
648
                        str++;
 
649
                }
 
650
        }
 
651
        return 1 ; // probably should give an error
 
652
}
 
653
 
 
654
SHPObject *
 
655
create_multiline3D_WKB (byte *wkb)
 
656
{
 
657
        SHPObject *obj;
 
658
        double *x=NULL, *y=NULL, *zm=NULL;
 
659
        int *part_index=NULL, totpoints=0, nlines=0;
 
660
        int li;
 
661
        int zmflag;
 
662
 
 
663
        // skip byteOrder
 
664
        skipbyte(&wkb);
 
665
 
 
666
        // extract zmflag from type
 
667
        zmflag = ZMFLAG(popint(&wkb));
 
668
 
 
669
        /*
 
670
         * Scan all lines in multiline
 
671
         */
 
672
        nlines=popint(&wkb); // num_wkbLineStrings
 
673
#if VERBOSE > 2
 
674
        printf("Multiline with %d lines\n", nlines);
 
675
#endif
 
676
 
 
677
        part_index = (int *)malloc(sizeof(int)*(nlines));
 
678
        for (li=0; li<nlines; li++)
 
679
        {
 
680
                int npoints, pn;
 
681
 
 
682
                // skip byteOrder and wkbType
 
683
                skipbyte(&wkb); skipint(&wkb);
 
684
 
 
685
                npoints = popint(&wkb);
 
686
 
 
687
#if VERBOSE > 2
 
688
                printf("Line %d has %d points\n", li, npoints);
 
689
#endif
 
690
 
 
691
                x = realloc(x, sizeof(double)*(totpoints+npoints));
 
692
                y = realloc(y, sizeof(double)*(totpoints+npoints));
 
693
                zm = realloc(zm, sizeof(double)*(totpoints+npoints));
 
694
 
 
695
                /* wkb now points at first point */
 
696
                for (pn=0; pn<npoints; pn++)
 
697
                {
 
698
                        x[totpoints+pn] = popdouble(&wkb);
 
699
                        y[totpoints+pn] = popdouble(&wkb);
 
700
                        zm[totpoints+pn] = popdouble(&wkb);
 
701
                }
 
702
 
 
703
                part_index[li] = totpoints;
 
704
                totpoints += npoints;
 
705
        }
 
706
 
 
707
        if ( zmflag == 1 ) {
 
708
                obj = SHPCreateObject(outshptype, -1, nlines,
 
709
                        part_index, NULL, totpoints,
 
710
                        x, y, NULL, zm);
 
711
        } else {
 
712
                obj = SHPCreateObject(outshptype, -1, nlines,
 
713
                        part_index, NULL, totpoints,
 
714
                        x, y, zm, NULL);
 
715
        }
 
716
 
 
717
        free(part_index); free(x); free(y); free(zm);
 
718
 
 
719
        return obj;
 
720
}
 
721
 
 
722
SHPObject *
 
723
create_multiline4D_WKB (byte *wkb)
 
724
{
 
725
        SHPObject *obj;
 
726
        double *x=NULL, *y=NULL, *z=NULL, *m=NULL;
 
727
        int *part_index=NULL, totpoints=0, nlines=0;
 
728
        int li;
 
729
        int zmflag;
 
730
 
 
731
        // skip byteOrder 
 
732
        skipbyte(&wkb); 
 
733
 
 
734
        // extract zmflag from type
 
735
        zmflag = ZMFLAG(popint(&wkb));
 
736
 
 
737
        /*
 
738
         * Scan all lines in multiline
 
739
         */
 
740
        nlines=popint(&wkb); // num_wkbLineStrings
 
741
#if VERBOSE > 2
 
742
        printf("Multiline with %d lines\n", nlines);
 
743
#endif
 
744
 
 
745
        part_index = (int *)malloc(sizeof(int)*(nlines));
 
746
        for (li=0; li<nlines; li++)
 
747
        {
 
748
                int npoints, pn;
 
749
 
 
750
                // skip byteOrder and wkbType
 
751
                skipbyte(&wkb); skipint(&wkb);
 
752
 
 
753
                npoints = popint(&wkb);
 
754
 
 
755
#if VERBOSE > 2
 
756
                printf("Line %d has %d points\n", li, npoints);
 
757
#endif
 
758
 
 
759
                x = realloc(x, sizeof(double)*(totpoints+npoints));
 
760
                y = realloc(y, sizeof(double)*(totpoints+npoints));
 
761
                z = realloc(z, sizeof(double)*(totpoints+npoints));
 
762
                m = realloc(m, sizeof(double)*(totpoints+npoints));
 
763
 
 
764
                /* wkb now points at first point */
 
765
                for (pn=0; pn<npoints; pn++)
 
766
                {
 
767
                        x[totpoints+pn] = popdouble(&wkb);
 
768
                        y[totpoints+pn] = popdouble(&wkb);
 
769
                        z[totpoints+pn] = popdouble(&wkb);
 
770
                        m[totpoints+pn] = popdouble(&wkb);
 
771
                }
 
772
 
 
773
                part_index[li] = totpoints;
 
774
                totpoints += npoints;
 
775
        }
 
776
 
 
777
        obj = SHPCreateObject(outshptype, -1, nlines,
 
778
                part_index, NULL, totpoints,
 
779
                x, y, z, m);
 
780
 
 
781
        free(part_index); free(x); free(y); free(z); free(m);
 
782
 
 
783
        return obj;
 
784
}
 
785
 
 
786
SHPObject *
 
787
create_multiline2D_WKB (byte *wkb)
 
788
{
 
789
        double *x=NULL, *y=NULL;
 
790
        int *part_index=NULL, totpoints=0, nlines=0;
 
791
        int li;
 
792
        SHPObject *obj;
 
793
        int zmflag;
 
794
        
 
795
        // skip byteOrder 
 
796
        skipbyte(&wkb); 
 
797
 
 
798
        // extract zmflag from type
 
799
        zmflag = ZMFLAG(popint(&wkb));
 
800
 
 
801
        /*
 
802
         * Scan all lines in multiline
 
803
         */
 
804
        nlines=popint(&wkb); // num_wkbLineStrings
 
805
#if VERBOSE > 2
 
806
        printf("Multiline with %d lines\n", nlines);
 
807
#endif
 
808
 
 
809
        part_index = (int *)malloc(sizeof(int)*(nlines));
 
810
        for (li=0; li<nlines; li++)
 
811
        {
 
812
                int npoints, pn;
 
813
 
 
814
                // skip byteOrder and wkbType
 
815
                skipbyte(&wkb); skipint(&wkb);
 
816
 
 
817
                npoints = popint(&wkb);
 
818
 
 
819
#if VERBOSE > 2
 
820
                printf("Line %d has %d points\n", li, npoints);
 
821
#endif
 
822
 
 
823
                x = realloc(x, sizeof(double)*(totpoints+npoints));
 
824
                y = realloc(y, sizeof(double)*(totpoints+npoints));
 
825
 
 
826
                /* wkb now points at first point */
 
827
                for (pn=0; pn<npoints; pn++)
 
828
                {
 
829
                        x[totpoints+pn] = popdouble(&wkb);
 
830
                        y[totpoints+pn] = popdouble(&wkb);
 
831
                }
 
832
 
 
833
                part_index[li] = totpoints;
 
834
                totpoints += npoints;
 
835
        }
 
836
 
 
837
 
 
838
        obj = SHPCreateObject(outshptype, -1, nlines,
 
839
                part_index, NULL, totpoints,
 
840
                x, y, NULL, NULL);
 
841
 
 
842
        free(part_index); free(x); free(y);
 
843
 
 
844
        return obj;
 
845
}
 
846
 
 
847
SHPObject *
 
848
create_line4D_WKB (byte *wkb)
 
849
{
 
850
        double *x=NULL, *y=NULL, *z=NULL, *m=NULL;
 
851
        uint32 npoints=0, pn;
 
852
        SHPObject *obj;
 
853
        int zmflag;
 
854
        
 
855
        // skip byteOrder 
 
856
        skipbyte(&wkb); 
 
857
 
 
858
        // extract zmflag from type
 
859
        zmflag = ZMFLAG(popint(&wkb));
 
860
 
 
861
        npoints = popint(&wkb);
 
862
 
 
863
#if VERBOSE > 2
 
864
        printf("Line has %lu points\n", npoints);
 
865
#endif
 
866
 
 
867
        x = malloc(sizeof(double)*(npoints));
 
868
        y = malloc(sizeof(double)*(npoints));
 
869
        z = malloc(sizeof(double)*(npoints));
 
870
        m = malloc(sizeof(double)*(npoints));
 
871
 
 
872
        /* wkb now points at first point */
 
873
        for (pn=0; pn<npoints; pn++)
 
874
        {
 
875
                x[pn] = popdouble(&wkb);
 
876
                y[pn] = popdouble(&wkb);
 
877
                z[pn] = popdouble(&wkb);
 
878
                m[pn] = popdouble(&wkb);
 
879
        }
 
880
 
 
881
        obj = SHPCreateObject(outshptype, -1, 0, NULL, NULL,
 
882
                npoints, x, y, z, m);
 
883
        free(x); free(y); free(z); free(m);
 
884
 
 
885
        return obj;
 
886
}
 
887
 
 
888
SHPObject *
 
889
create_line3D_WKB (byte *wkb)
 
890
{
 
891
        double *x=NULL, *y=NULL, *zm=NULL;
 
892
        uint32 npoints=0, pn;
 
893
        SHPObject *obj;
 
894
        int zmflag;
 
895
        
 
896
        // skip byteOrder 
 
897
        skipbyte(&wkb); 
 
898
 
 
899
        // extract zmflag from type
 
900
        zmflag = ZMFLAG(popint(&wkb));
 
901
 
 
902
        npoints = popint(&wkb);
 
903
 
 
904
#if VERBOSE > 2
 
905
        printf("Line has %lu points\n", npoints);
 
906
#endif
 
907
 
 
908
        x = malloc(sizeof(double)*(npoints));
 
909
        y = malloc(sizeof(double)*(npoints));
 
910
        zm = malloc(sizeof(double)*(npoints));
 
911
 
 
912
        /* wkb now points at first point */
 
913
        for (pn=0; pn<npoints; pn++)
 
914
        {
 
915
                x[pn] = popdouble(&wkb);
 
916
                y[pn] = popdouble(&wkb);
 
917
                zm[pn] = popdouble(&wkb);
 
918
        }
 
919
 
 
920
        if ( zmflag == 1 ) {
 
921
                obj = SHPCreateObject(outshptype, -1, 0, NULL, NULL,
 
922
                        npoints, x, y, NULL, zm);
 
923
        } else {
 
924
                obj = SHPCreateObject(outshptype, -1, 0, NULL, NULL,
 
925
                        npoints, x, y, zm, NULL);
 
926
        }
 
927
 
 
928
        free(x); free(y); free(zm);
 
929
 
 
930
        return obj;
 
931
}
 
932
 
 
933
SHPObject *
 
934
create_line2D_WKB (byte *wkb)
 
935
{
 
936
        double *x=NULL, *y=NULL, *z=NULL;
 
937
        uint32 npoints=0, pn;
 
938
        SHPObject *obj;
 
939
        int zmflag;
 
940
        
 
941
        // skip byteOrder 
 
942
        skipbyte(&wkb); 
 
943
 
 
944
        // extract zmflag from type
 
945
        zmflag = ZMFLAG(popint(&wkb));
 
946
 
 
947
        npoints = popint(&wkb);
 
948
 
 
949
#if VERBOSE > 2
 
950
        printf("Line has %lu points\n", npoints);
 
951
#endif
 
952
 
 
953
        x = malloc(sizeof(double)*(npoints));
 
954
        y = malloc(sizeof(double)*(npoints));
 
955
 
 
956
        /* wkb now points at first point */
 
957
        for (pn=0; pn<npoints; pn++)
 
958
        {
 
959
                x[pn] = popdouble(&wkb);
 
960
                y[pn] = popdouble(&wkb);
 
961
        }
 
962
 
 
963
        obj = SHPCreateSimpleObject(outshptype, npoints, x, y, z);
 
964
        free(x); free(y); 
 
965
 
 
966
        return obj;
 
967
}
 
968
 
 
969
SHPObject *
 
970
create_point4D_WKB(byte *wkb)
 
971
{
 
972
        SHPObject *obj;
 
973
        double x, y, z, m;
 
974
        int zmflag;
 
975
 
 
976
        // skip byteOrder 
 
977
        skipbyte(&wkb); 
 
978
 
 
979
        // extract zmflag from type
 
980
        zmflag = ZMFLAG(popint(&wkb));
 
981
 
 
982
        x = popdouble(&wkb);
 
983
        y = popdouble(&wkb);
 
984
        z = popdouble(&wkb);
 
985
        m = popdouble(&wkb);
 
986
 
 
987
        obj = SHPCreateObject(outshptype, -1, 0, NULL, NULL,
 
988
                1, &x, &y, &z, &m);
 
989
 
 
990
        return obj;
 
991
}
 
992
 
 
993
SHPObject *
 
994
create_point3D_WKB(byte *wkb)
 
995
{
 
996
        SHPObject *obj;
 
997
        double x, y, zm;
 
998
        int zmflag;
 
999
 
 
1000
        // skip byteOrder 
 
1001
        skipbyte(&wkb); 
 
1002
 
 
1003
        // extract zmflag from type
 
1004
        zmflag = ZMFLAG(popint(&wkb));
 
1005
 
 
1006
        x = popdouble(&wkb);
 
1007
        y = popdouble(&wkb);
 
1008
        zm = popdouble(&wkb);
 
1009
 
 
1010
        if ( zmflag == 1 ) {
 
1011
                obj = SHPCreateObject(outshptype, -1, 0, NULL, NULL,
 
1012
                        1, &x, &y, NULL, &zm);
 
1013
        } else {
 
1014
                obj = SHPCreateObject(outshptype, -1, 0, NULL, NULL,
 
1015
                        1, &x, &y, &zm, NULL);
 
1016
        }
 
1017
 
 
1018
        return obj;
 
1019
}
 
1020
 
 
1021
SHPObject *
 
1022
create_point2D_WKB(byte *wkb)
 
1023
{
 
1024
        SHPObject *obj;
 
1025
        double x, y;
 
1026
        int zmflag;
 
1027
 
 
1028
        // skip byteOrder 
 
1029
        skipbyte(&wkb); 
 
1030
 
 
1031
        // extract zmflag from type
 
1032
        zmflag = ZMFLAG(popint(&wkb));
 
1033
 
 
1034
        x = popdouble(&wkb);
 
1035
        y = popdouble(&wkb);
 
1036
 
 
1037
        obj = SHPCreateSimpleObject(outshptype, 1, &x, &y, NULL);
 
1038
 
 
1039
        return obj;
 
1040
}
 
1041
 
 
1042
SHPObject *
 
1043
create_multipoint4D_WKB(byte *wkb)
 
1044
{
 
1045
        SHPObject *obj;
 
1046
        double *x=NULL, *y=NULL, *z=NULL, *m=NULL;
 
1047
        int npoints;
 
1048
        int pn;
 
1049
        int zmflag;
 
1050
 
 
1051
        // skip byteOrder 
 
1052
        skipbyte(&wkb); 
 
1053
 
 
1054
        // extract zmflag from type
 
1055
        zmflag = ZMFLAG(popint(&wkb));
 
1056
 
 
1057
        npoints = popint(&wkb);
 
1058
 
 
1059
        x = (double *)malloc(sizeof(double)*npoints);
 
1060
        y = (double *)malloc(sizeof(double)*npoints);
 
1061
        z = (double *)malloc(sizeof(double)*npoints);
 
1062
        m = (double *)malloc(sizeof(double)*npoints);
 
1063
 
 
1064
        for (pn=0; pn<npoints; pn++)
 
1065
        {
 
1066
                skipbyte(&wkb); // byteOrder
 
1067
                skipint(&wkb);  // wkbType
 
1068
                x[pn]=popdouble(&wkb);
 
1069
                y[pn]=popdouble(&wkb);
 
1070
                z[pn]=popdouble(&wkb);
 
1071
                m[pn]=popdouble(&wkb);
 
1072
        }
 
1073
 
 
1074
        obj = SHPCreateObject(outshptype, -1, 0, NULL, NULL,
 
1075
                npoints, x, y, z, m);
 
1076
 
 
1077
        free(x); free(y); free(z); free(m);
 
1078
 
 
1079
        return obj;
 
1080
}
 
1081
 
 
1082
SHPObject *
 
1083
create_multipoint3D_WKB(byte *wkb)
 
1084
{
 
1085
        SHPObject *obj;
 
1086
        double *x=NULL, *y=NULL, *zm=NULL;
 
1087
        uint32 npoints;
 
1088
        uint32 pn;
 
1089
        int zmflag;
 
1090
 
 
1091
        // skip byteOrder 
 
1092
        skipbyte(&wkb); 
 
1093
 
 
1094
        // extract zmflag from type
 
1095
        zmflag = ZMFLAG(popint(&wkb));
 
1096
 
 
1097
        npoints = popint(&wkb);
 
1098
 
 
1099
        x = (double *)malloc(sizeof(double)*npoints);
 
1100
        y = (double *)malloc(sizeof(double)*npoints);
 
1101
        zm = (double *)malloc(sizeof(double)*npoints);
 
1102
 
 
1103
        for (pn=0; pn<npoints; pn++)
 
1104
        {
 
1105
                skipbyte(&wkb); // byteOrder
 
1106
                skipint(&wkb);  // wkbType
 
1107
                x[pn]=popdouble(&wkb);
 
1108
                y[pn]=popdouble(&wkb);
 
1109
                zm[pn]=popdouble(&wkb);
 
1110
        }
 
1111
 
 
1112
        if ( zmflag == 1 ) {
 
1113
                obj = SHPCreateObject(outshptype, -1, 0, NULL, NULL,
 
1114
                        npoints, x, y, NULL, zm);
 
1115
        } else {
 
1116
                obj = SHPCreateObject(outshptype, -1, 0, NULL, NULL,
 
1117
                        npoints, x, y, zm, NULL);
 
1118
        }
 
1119
 
 
1120
        free(x); free(y); free(zm);
 
1121
 
 
1122
        return obj;
 
1123
}
 
1124
 
 
1125
SHPObject *
 
1126
create_multipoint2D_WKB(byte *wkb)
 
1127
{
 
1128
        SHPObject *obj;
 
1129
        double *x=NULL, *y=NULL;
 
1130
        uint32 npoints;
 
1131
        uint32 pn;
 
1132
        int zmflag;
 
1133
 
 
1134
        // skip byteOrder 
 
1135
        skipbyte(&wkb); 
 
1136
 
 
1137
        // extract zmflag from type
 
1138
        zmflag = ZMFLAG(popint(&wkb));
 
1139
 
 
1140
        npoints = popint(&wkb);
 
1141
 
 
1142
        x = (double *)malloc(sizeof(double)*npoints);
 
1143
        y = (double *)malloc(sizeof(double)*npoints);
 
1144
 
 
1145
        for (pn=0; pn<npoints; pn++)
 
1146
        {
 
1147
                skipbyte(&wkb); // byteOrder
 
1148
                skipint(&wkb);  // wkbType
 
1149
                x[pn]=popdouble(&wkb);
 
1150
                y[pn]=popdouble(&wkb);
 
1151
 
 
1152
        }
 
1153
 
 
1154
        obj = SHPCreateSimpleObject(outshptype,npoints,x,y,NULL);
 
1155
        free(x); free(y); 
 
1156
 
 
1157
        return obj;
 
1158
}
 
1159
 
 
1160
SHPObject *
 
1161
create_polygon2D_WKB(byte *wkb)
 
1162
{
 
1163
        SHPObject *obj;
 
1164
        int ri, nrings, totpoints=0, *part_index=NULL;
 
1165
        double *x=NULL, *y=NULL, *z=NULL;
 
1166
        int zmflag;
 
1167
        
 
1168
        // skip byteOrder 
 
1169
        skipbyte(&wkb); 
 
1170
 
 
1171
        // extract zmflag from type
 
1172
        zmflag = ZMFLAG(popint(&wkb));
 
1173
 
 
1174
        /*
 
1175
         * Scan all rings
 
1176
         */
 
1177
        nrings = popint(&wkb);
 
1178
#if VERBOSE > 2
 
1179
        printf("Polygon with %d rings\n", nrings);
 
1180
#endif
 
1181
        part_index = (int *)malloc(sizeof(int)*nrings);
 
1182
        for (ri=0; ri<nrings; ri++)
 
1183
        {
 
1184
                int pn;
 
1185
                int npoints = popint(&wkb);
 
1186
 
 
1187
                x = realloc(x, sizeof(double)*(totpoints+npoints));
 
1188
                y = realloc(y, sizeof(double)*(totpoints+npoints));
 
1189
 
 
1190
                for (pn=0; pn<npoints; pn++)
 
1191
                {
 
1192
                        x[totpoints+pn] = popdouble(&wkb);
 
1193
                        y[totpoints+pn] = popdouble(&wkb);
 
1194
                }
 
1195
 
 
1196
                /*
 
1197
                 * First ring should be clockwise,
 
1198
                 * other rings should be counter-clockwise
 
1199
                 */
 
1200
                if ( !ri ) {
 
1201
                        if ( ! is_clockwise(npoints, x+totpoints,
 
1202
                                                y+totpoints, NULL) )
 
1203
                        {
 
1204
#if VERBOSE > 2
 
1205
                                printf("Forcing CW\n");
 
1206
#endif
 
1207
                                reverse_points(npoints, x+totpoints,
 
1208
                                                y+totpoints, NULL, NULL);
 
1209
                        }
 
1210
                } else {
 
1211
                        if ( is_clockwise(npoints, x+totpoints,
 
1212
                                                y+totpoints, NULL) )
 
1213
                        {
 
1214
#if VERBOSE > 2
 
1215
                                printf("Forcing CCW\n");
 
1216
#endif
 
1217
                                reverse_points(npoints, x+totpoints,
 
1218
                                                y+totpoints, NULL, NULL);
 
1219
                        }
 
1220
                }
 
1221
 
 
1222
                part_index[ri] = totpoints;
 
1223
                totpoints += npoints;
 
1224
        }
 
1225
 
 
1226
        obj = SHPCreateObject(outshptype, -1, nrings,
 
1227
                part_index, NULL, totpoints,
 
1228
                x, y, z, NULL);
 
1229
 
 
1230
        free(part_index);
 
1231
        free(x); free(y); 
 
1232
 
 
1233
        return obj;
 
1234
}
 
1235
 
 
1236
SHPObject *
 
1237
create_polygon4D_WKB(byte *wkb)
 
1238
{
 
1239
        SHPObject *obj;
 
1240
        int ri, nrings, totpoints=0, *part_index=NULL;
 
1241
        double *x=NULL, *y=NULL, *z=NULL, *m=NULL;
 
1242
        int zmflag;
 
1243
        
 
1244
        // skip byteOrder 
 
1245
        skipbyte(&wkb); 
 
1246
 
 
1247
        // extract zmflag from type
 
1248
        zmflag = ZMFLAG(popint(&wkb));
 
1249
 
 
1250
        /*
 
1251
         * Scan all rings
 
1252
         */
 
1253
        nrings = popint(&wkb);
 
1254
#if VERBOSE > 2
 
1255
        printf("Polygon with %d rings\n", nrings);
 
1256
#endif
 
1257
        part_index = (int *)malloc(sizeof(int)*nrings);
 
1258
        for (ri=0; ri<nrings; ri++)
 
1259
        {
 
1260
                int pn;
 
1261
                int npoints = popint(&wkb);
 
1262
 
 
1263
                x = realloc(x, sizeof(double)*(totpoints+npoints));
 
1264
                y = realloc(y, sizeof(double)*(totpoints+npoints));
 
1265
                z = realloc(z, sizeof(double)*(totpoints+npoints));
 
1266
                m = realloc(m, sizeof(double)*(totpoints+npoints));
 
1267
 
 
1268
                for (pn=0; pn<npoints; pn++)
 
1269
                {
 
1270
                        x[totpoints+pn] = popdouble(&wkb);
 
1271
                        y[totpoints+pn] = popdouble(&wkb);
 
1272
                        z[totpoints+pn] = popdouble(&wkb);
 
1273
                        m[totpoints+pn] = popdouble(&wkb);
 
1274
                }
 
1275
 
 
1276
                /*
 
1277
                 * First ring should be clockwise,
 
1278
                 * other rings should be counter-clockwise
 
1279
                 */
 
1280
                if ( !ri ) {
 
1281
                        if ( ! is_clockwise(npoints, x+totpoints,
 
1282
                                                y+totpoints, z+totpoints) ) {
 
1283
#if VERBOSE > 2
 
1284
                                printf("Forcing CW\n");
 
1285
#endif
 
1286
                                reverse_points(npoints, x+totpoints,
 
1287
                                                y+totpoints, z+totpoints, m+totpoints);
 
1288
                        }
 
1289
                } else {
 
1290
                        if ( is_clockwise(npoints, x+totpoints,
 
1291
                                                y+totpoints, z+totpoints) ) {
 
1292
#if VERBOSE > 2
 
1293
                                printf("Forcing CCW\n");
 
1294
#endif
 
1295
                                reverse_points(npoints, x+totpoints,
 
1296
                                                y+totpoints, z+totpoints, m+totpoints);
 
1297
                        }
 
1298
                }
 
1299
 
 
1300
                part_index[ri] = totpoints;
 
1301
                totpoints += npoints;
 
1302
        }
 
1303
 
 
1304
        obj = SHPCreateObject(outshptype, -1, nrings,
 
1305
                part_index, NULL, totpoints,
 
1306
                x, y, z, m);
 
1307
 
 
1308
        free(part_index);
 
1309
        free(x); free(y); free(z); free(m);
 
1310
 
 
1311
        return obj;
 
1312
}
 
1313
 
 
1314
SHPObject *
 
1315
create_polygon3D_WKB(byte *wkb)
 
1316
{
 
1317
        SHPObject *obj;
 
1318
        int ri, nrings, totpoints=0, *part_index=NULL;
 
1319
        double *x=NULL, *y=NULL, *zm=NULL, *z=NULL;
 
1320
        int zmflag;
 
1321
        
 
1322
        // skip byteOrder 
 
1323
        skipbyte(&wkb); 
 
1324
 
 
1325
        // extract zmflag from type
 
1326
        zmflag = ZMFLAG(popint(&wkb));
 
1327
 
 
1328
        /*
 
1329
         * Scan all rings
 
1330
         */
 
1331
        nrings = popint(&wkb);
 
1332
#if VERBOSE > 2
 
1333
        printf("Polygon with %d rings\n", nrings);
 
1334
#endif
 
1335
        part_index = (int *)malloc(sizeof(int)*nrings);
 
1336
        for (ri=0; ri<nrings; ri++)
 
1337
        {
 
1338
                int pn;
 
1339
                int npoints = popint(&wkb);
 
1340
 
 
1341
                x = realloc(x, sizeof(double)*(totpoints+npoints));
 
1342
                y = realloc(y, sizeof(double)*(totpoints+npoints));
 
1343
                zm = realloc(zm, sizeof(double)*(totpoints+npoints));
 
1344
 
 
1345
                for (pn=0; pn<npoints; pn++)
 
1346
                {
 
1347
                        x[totpoints+pn] = popdouble(&wkb);
 
1348
                        y[totpoints+pn] = popdouble(&wkb);
 
1349
                        zm[totpoints+pn] = popdouble(&wkb);
 
1350
                }
 
1351
 
 
1352
                /*
 
1353
                 * First ring should be clockwise,
 
1354
                 * other rings should be counter-clockwise
 
1355
                 */
 
1356
 
 
1357
                // Set z to NULL if TYPEM
 
1358
                if ( zmflag == 1 ) z = NULL;
 
1359
                else z = zm+totpoints;
 
1360
 
 
1361
                if ( !ri ) {
 
1362
                        if ( ! is_clockwise(npoints, x+totpoints,
 
1363
                                                y+totpoints, z) ) {
 
1364
#if VERBOSE > 2
 
1365
                                printf("Forcing CW\n");
 
1366
#endif
 
1367
                                reverse_points(npoints, x+totpoints,
 
1368
                                                y+totpoints, zm+totpoints, NULL);
 
1369
                        }
 
1370
                } else {
 
1371
                        if ( is_clockwise(npoints, x+totpoints,
 
1372
                                                y+totpoints, z) ) {
 
1373
#if VERBOSE > 2
 
1374
                                printf("Forcing CCW\n");
 
1375
#endif
 
1376
                                reverse_points(npoints, x+totpoints,
 
1377
                                                y+totpoints, zm+totpoints, NULL);
 
1378
                        }
 
1379
                }
 
1380
 
 
1381
                part_index[ri] = totpoints;
 
1382
                totpoints += npoints;
 
1383
        }
 
1384
 
 
1385
        if ( zmflag == 1 ) {
 
1386
                obj = SHPCreateObject(outshptype, -1, nrings,
 
1387
                        part_index, NULL, totpoints,
 
1388
                        x, y, NULL, zm);
 
1389
        } else {
 
1390
                obj = SHPCreateObject(outshptype, -1, nrings,
 
1391
                        part_index, NULL, totpoints,
 
1392
                        x, y, zm, NULL);
 
1393
        }
 
1394
 
 
1395
        free(part_index);
 
1396
        free(x); free(y); free(zm);
 
1397
 
 
1398
        return obj;
 
1399
}
 
1400
 
 
1401
SHPObject *
 
1402
create_multipolygon2D_WKB(byte *wkb)
 
1403
{
 
1404
        SHPObject *obj;
 
1405
        uint32 nrings, nparts=0;
 
1406
        uint32 npolys;
 
1407
        uint32 totpoints=0;
 
1408
        int *part_index=NULL;
 
1409
        uint32 pi;
 
1410
        double *x=NULL, *y=NULL;
 
1411
        int zmflag;
 
1412
 
 
1413
        // skip byteOrder 
 
1414
        skipbyte(&wkb); 
 
1415
 
 
1416
        // extract zmflag from type
 
1417
        zmflag = ZMFLAG(popint(&wkb));
 
1418
 
 
1419
        /*
 
1420
         * Scan all polygons in multipolygon
 
1421
         */
 
1422
        npolys = popint(&wkb);  // num_wkbPolygons
 
1423
#if VERBOSE > 2
 
1424
        printf("Multipolygon with %lu polygons\n", npolys);
 
1425
#endif
 
1426
 
 
1427
        /*
 
1428
         * Now wkb points to a WKBPolygon structure
 
1429
         */
 
1430
        for (pi=0; pi<npolys; pi++)
 
1431
        {
 
1432
                uint32 ri; // ring index
 
1433
 
 
1434
                // skip byteOrder and wkbType
 
1435
                skipbyte(&wkb); skipint(&wkb);
 
1436
 
 
1437
                /*
 
1438
                 * Find total number of points and
 
1439
                 * fill part index
 
1440
                 */
 
1441
 
 
1442
                nrings = popint(&wkb);
 
1443
                part_index = (int *)realloc(part_index,
 
1444
                                sizeof(int)*(nparts+nrings));
 
1445
 
 
1446
#if VERBOSE > 2
 
1447
                printf("Polygon %lu has %lu rings\n", pi, nrings);
 
1448
#endif
 
1449
 
 
1450
                // wkb now points at first ring
 
1451
                for (ri=0; ri<nrings; ri++)
 
1452
                {
 
1453
                        uint32 pn; // point number
 
1454
                        uint32 npoints;
 
1455
 
 
1456
                        npoints = popint(&wkb);
 
1457
 
 
1458
#if VERBOSE > 2
 
1459
                        printf("Ring %lu has %lu points\n", ri, npoints);
 
1460
#endif
 
1461
 
 
1462
                        x = realloc(x, sizeof(double)*(totpoints+npoints));
 
1463
                        y = realloc(y, sizeof(double)*(totpoints+npoints));
 
1464
 
 
1465
                        /* wkb now points at first point */
 
1466
                        for (pn=0; pn<npoints; pn++)
 
1467
                        {
 
1468
                                x[totpoints+pn] = popdouble(&wkb);
 
1469
                                y[totpoints+pn] = popdouble(&wkb);
 
1470
#if VERBOSE > 3
 
1471
        printf("Point%lu (%f,%f)\n", pn, x[totpoints+pn], y[totpoints+pn]);
 
1472
#endif
 
1473
                        }
 
1474
 
 
1475
                        /*
 
1476
                         * First ring should be clockwise,
 
1477
                         * other rings should be counter-clockwise
 
1478
                         */
 
1479
                        if ( !ri ) {
 
1480
                                if (!is_clockwise(npoints, x+totpoints,
 
1481
                                                        y+totpoints, NULL))
 
1482
                                {
 
1483
#if VERBOSE > 2
 
1484
                                        printf("Forcing CW\n");
 
1485
#endif
 
1486
                                        reverse_points(npoints, x+totpoints,
 
1487
                                                        y+totpoints, NULL, NULL);
 
1488
                                }
 
1489
                        } else {
 
1490
                                if (is_clockwise(npoints, x+totpoints,
 
1491
                                                        y+totpoints, NULL))
 
1492
                                {
 
1493
#if VERBOSE > 2
 
1494
                                        printf("Forcing CCW\n");
 
1495
#endif
 
1496
                                        reverse_points(npoints, x+totpoints,
 
1497
                                                        y+totpoints, NULL, NULL);
 
1498
                                }
 
1499
                        }
 
1500
 
 
1501
                        part_index[nparts+ri] = totpoints;
 
1502
                        totpoints += npoints;
 
1503
                }
 
1504
#if VERBOSE > 2
 
1505
                printf("End of rings\n");
 
1506
#endif
 
1507
                nparts += nrings;
 
1508
        }
 
1509
 
 
1510
#if VERBOSE > 2
 
1511
        printf("End of polygons\n");
 
1512
#endif
 
1513
 
 
1514
        obj = SHPCreateObject(outshptype, -1, nparts,
 
1515
                part_index, NULL, totpoints,
 
1516
                x, y, NULL, NULL);
 
1517
 
 
1518
#if VERBOSE > 2
 
1519
        printf("Object created\n");
 
1520
#endif
 
1521
 
 
1522
        free(part_index);
 
1523
        free(x); free(y); 
 
1524
 
 
1525
        return obj;
 
1526
}
 
1527
 
 
1528
SHPObject *
 
1529
create_multipolygon3D_WKB(byte *wkb)
 
1530
{
 
1531
        SHPObject *obj;
 
1532
        int nrings, nparts=0;
 
1533
        uint32 npolys;
 
1534
        int totpoints=0;
 
1535
        int *part_index=NULL;
 
1536
        int pi;
 
1537
        double *x=NULL, *y=NULL, *z=NULL, *zm=NULL;
 
1538
        int zmflag;
 
1539
 
 
1540
        // skip byteOrder 
 
1541
        skipbyte(&wkb); 
 
1542
 
 
1543
        // extract zmflag from type
 
1544
        zmflag = ZMFLAG(popint(&wkb));
 
1545
        
 
1546
        /*
 
1547
         * Scan all polygons in multipolygon
 
1548
         */
 
1549
        npolys = popint(&wkb);  // num_wkbPolygons
 
1550
#if VERBOSE > 2
 
1551
        printf("Multipolygon with %lu polygons\n", npolys);
 
1552
#endif
 
1553
 
 
1554
        /*
 
1555
         * Now wkb points to a WKBPolygon structure
 
1556
         */
 
1557
        for (pi=0; pi<npolys; pi++)
 
1558
        {
 
1559
                int ri; // ring index
 
1560
 
 
1561
                // skip byteOrder and wkbType
 
1562
                skipbyte(&wkb); skipint(&wkb);
 
1563
 
 
1564
                /*
 
1565
                 * Find total number of points and
 
1566
                 * fill part index
 
1567
                 */
 
1568
 
 
1569
                nrings = popint(&wkb);
 
1570
                part_index = (int *)realloc(part_index,
 
1571
                                sizeof(int)*(nparts+nrings));
 
1572
 
 
1573
#if VERBOSE > 2
 
1574
                printf("Polygon %d has %d rings\n", pi, nrings);
 
1575
#endif
 
1576
 
 
1577
                // wkb now points at first ring
 
1578
                for (ri=0; ri<nrings; ri++)
 
1579
                {
 
1580
                        int pn; // point number
 
1581
                        int npoints;
 
1582
 
 
1583
                        npoints = popint(&wkb);
 
1584
 
 
1585
#if VERBOSE > 2
 
1586
                        printf("Ring %d has %d points\n", ri, npoints);
 
1587
#endif
 
1588
 
 
1589
                        x = realloc(x, sizeof(double)*(totpoints+npoints));
 
1590
                        y = realloc(y, sizeof(double)*(totpoints+npoints));
 
1591
                        zm = realloc(zm, sizeof(double)*(totpoints+npoints));
 
1592
 
 
1593
                        /* wkb now points at first point */
 
1594
                        for (pn=0; pn<npoints; pn++)
 
1595
                        {
 
1596
                                x[totpoints+pn] = popdouble(&wkb);
 
1597
                                y[totpoints+pn] = popdouble(&wkb);
 
1598
                                zm[totpoints+pn] = popdouble(&wkb);
 
1599
#if VERBOSE > 3
 
1600
        printf("Point%d (%f,%f)\n", pn, x[totpoints+pn], y[totpoints+pn]);
 
1601
#endif
 
1602
                        }
 
1603
 
 
1604
                        /*
 
1605
                         * First ring should be clockwise,
 
1606
                         * other rings should be counter-clockwise
 
1607
                         */
 
1608
 
 
1609
                        // Set z to NULL if TYPEM
 
1610
                        if ( zmflag == 1 ) z = NULL;
 
1611
                        else z = zm+totpoints;
 
1612
 
 
1613
                        if ( !ri ) {
 
1614
                                if (!is_clockwise(npoints, x+totpoints,
 
1615
                                                        y+totpoints, z))
 
1616
                                {
 
1617
#if VERBOSE > 2
 
1618
                                        printf("Forcing CW\n");
 
1619
#endif
 
1620
                                        reverse_points(npoints, x+totpoints,
 
1621
                                                        y+totpoints, zm+totpoints, NULL);
 
1622
                                }
 
1623
                        } else {
 
1624
                                if (is_clockwise(npoints, x+totpoints,
 
1625
                                                        y+totpoints, z))
 
1626
                                {
 
1627
#if VERBOSE > 2
 
1628
                                        printf("Forcing CCW\n");
 
1629
#endif
 
1630
                                        reverse_points(npoints, x+totpoints,
 
1631
                                                        y+totpoints, zm+totpoints, NULL);
 
1632
                                }
 
1633
                        }
 
1634
 
 
1635
                        part_index[nparts+ri] = totpoints;
 
1636
                        totpoints += npoints;
 
1637
                }
 
1638
#if VERBOSE > 2
 
1639
                printf("End of rings\n");
 
1640
#endif
 
1641
                nparts += nrings;
 
1642
        }
 
1643
 
 
1644
#if VERBOSE > 2
 
1645
        printf("End of polygons\n");
 
1646
#endif
 
1647
 
 
1648
        if ( zmflag == 1 ) {
 
1649
                obj = SHPCreateObject(outshptype, -1, nparts,
 
1650
                        part_index, NULL, totpoints,
 
1651
                        x, y, NULL, zm);
 
1652
        } else {
 
1653
                obj = SHPCreateObject(outshptype, -1, nparts,
 
1654
                        part_index, NULL, totpoints,
 
1655
                        x, y, zm, NULL);
 
1656
        }
 
1657
 
 
1658
#if VERBOSE > 2
 
1659
        printf("Object created\n");
 
1660
#endif
 
1661
 
 
1662
        free(part_index);
 
1663
        free(x); free(y); free(zm);
 
1664
 
 
1665
        return obj;
 
1666
}
 
1667
 
 
1668
SHPObject *
 
1669
create_multipolygon4D_WKB(byte *wkb)
 
1670
{
 
1671
        SHPObject *obj;
 
1672
        int nrings, nparts=0;
 
1673
        uint32 npolys;
 
1674
        int totpoints=0;
 
1675
        int *part_index=NULL;
 
1676
        int pi;
 
1677
        double *x=NULL, *y=NULL, *z=NULL, *m=NULL;
 
1678
        int zmflag;
 
1679
 
 
1680
        // skip byteOrder 
 
1681
        skipbyte(&wkb); 
 
1682
 
 
1683
        // extract zmflag from type
 
1684
        zmflag = ZMFLAG(popint(&wkb));
 
1685
        
 
1686
        /*
 
1687
         * Scan all polygons in multipolygon
 
1688
         */
 
1689
        npolys = popint(&wkb);  // num_wkbPolygons
 
1690
#if VERBOSE > 2
 
1691
        printf("Multipolygon with %lu polygons\n", npolys);
 
1692
#endif
 
1693
 
 
1694
        /*
 
1695
         * Now wkb points to a WKBPolygon structure
 
1696
         */
 
1697
        for (pi=0; pi<npolys; pi++)
 
1698
        {
 
1699
                int ri; // ring index
 
1700
 
 
1701
                // skip byteOrder and wkbType
 
1702
                skipbyte(&wkb); skipint(&wkb);
 
1703
 
 
1704
                /*
 
1705
                 * Find total number of points and
 
1706
                 * fill part index
 
1707
                 */
 
1708
 
 
1709
                nrings = popint(&wkb);
 
1710
                part_index = (int *)realloc(part_index,
 
1711
                                sizeof(int)*(nparts+nrings));
 
1712
 
 
1713
#if VERBOSE > 2
 
1714
                printf("Polygon %d has %d rings\n", pi, nrings);
 
1715
#endif
 
1716
 
 
1717
                // wkb now points at first ring
 
1718
                for (ri=0; ri<nrings; ri++)
 
1719
                {
 
1720
                        int pn; // point number
 
1721
                        int npoints;
 
1722
 
 
1723
                        npoints = popint(&wkb);
 
1724
 
 
1725
#if VERBOSE > 2
 
1726
                        printf("Ring %d has %d points\n", ri, npoints);
 
1727
#endif
 
1728
 
 
1729
                        x = realloc(x, sizeof(double)*(totpoints+npoints));
 
1730
                        y = realloc(y, sizeof(double)*(totpoints+npoints));
 
1731
                        z = realloc(z, sizeof(double)*(totpoints+npoints));
 
1732
                        m = realloc(m, sizeof(double)*(totpoints+npoints));
 
1733
 
 
1734
                        /* wkb now points at first point */
 
1735
                        for (pn=0; pn<npoints; pn++)
 
1736
                        {
 
1737
                                x[totpoints+pn] = popdouble(&wkb);
 
1738
                                y[totpoints+pn] = popdouble(&wkb);
 
1739
                                z[totpoints+pn] = popdouble(&wkb);
 
1740
                                m[totpoints+pn] = popdouble(&wkb);
 
1741
#if VERBOSE > 3
 
1742
        printf("Point%d (%f,%f)\n", pn, x[totpoints+pn], y[totpoints+pn]);
 
1743
#endif
 
1744
                        }
 
1745
 
 
1746
                        /*
 
1747
                         * First ring should be clockwise,
 
1748
                         * other rings should be counter-clockwise
 
1749
                         */
 
1750
                        if ( !ri ) {
 
1751
                                if (!is_clockwise(npoints, x+totpoints,
 
1752
                                                        y+totpoints, z+totpoints))
 
1753
                                {
 
1754
#if VERBOSE > 2
 
1755
                                        printf("Forcing CW\n");
 
1756
#endif
 
1757
                                        reverse_points(npoints, x+totpoints,
 
1758
                                                        y+totpoints, z+totpoints, m+totpoints);
 
1759
                                }
 
1760
                        } else {
 
1761
                                if (is_clockwise(npoints, x+totpoints,
 
1762
                                                        y+totpoints, z+totpoints))
 
1763
                                {
 
1764
#if VERBOSE > 2
 
1765
                                        printf("Forcing CCW\n");
 
1766
#endif
 
1767
                                        reverse_points(npoints, x+totpoints,
 
1768
                                                        y+totpoints, z+totpoints, m+totpoints);
 
1769
                                }
 
1770
                        }
 
1771
 
 
1772
                        part_index[nparts+ri] = totpoints;
 
1773
                        totpoints += npoints;
 
1774
                }
 
1775
#if VERBOSE > 2
 
1776
                printf("End of rings\n");
 
1777
#endif
 
1778
                nparts += nrings;
 
1779
        }
 
1780
 
 
1781
#if VERBOSE > 2
 
1782
        printf("End of polygons\n");
 
1783
#endif
 
1784
 
 
1785
        obj = SHPCreateObject(outshptype, -1, nparts,
 
1786
                part_index, NULL, totpoints,
 
1787
                x, y, z, m);
 
1788
 
 
1789
#if VERBOSE > 2
 
1790
        printf("Object created\n");
 
1791
#endif
 
1792
 
 
1793
        free(part_index);
 
1794
        free(x); free(y); free(z); free(m);
 
1795
 
 
1796
        return obj;
 
1797
}
 
1798
 
 
1799
//Reverse the clockwise-ness of the point list...
 
1800
int
 
1801
reverse_points(int num_points, double *x, double *y, double *z, double *m)
 
1802
{
 
1803
        
 
1804
        int i,j;
 
1805
        double temp;
 
1806
        j = num_points -1;
 
1807
        for(i=0; i <num_points; i++){
 
1808
                if(j <= i){
 
1809
                        break;
 
1810
                }
 
1811
                temp = x[j];
 
1812
                x[j] = x[i];
 
1813
                x[i] = temp;
 
1814
 
 
1815
                temp = y[j];
 
1816
                y[j] = y[i];
 
1817
                y[i] = temp;
 
1818
 
 
1819
                if ( z )
 
1820
                {
 
1821
                        temp = z[j];
 
1822
                        z[j] = z[i];
 
1823
                        z[i] = temp;
 
1824
                }
 
1825
 
 
1826
                if ( m )
 
1827
                {
 
1828
                        temp = m[j];
 
1829
                        m[j] = m[i];
 
1830
                        m[i] = temp;
 
1831
                }
 
1832
 
 
1833
                j--;
 
1834
        }
 
1835
        return 1;
 
1836
}
 
1837
 
 
1838
//return 1 if the points are in clockwise order
 
1839
int is_clockwise(int num_points, double *x, double *y, double *z)
 
1840
{
 
1841
        int i;
 
1842
        double x_change,y_change,area;
 
1843
        double *x_new, *y_new; //the points, translated to the origin for safer accuracy
 
1844
 
 
1845
        x_new = (double *)malloc(sizeof(double) * num_points);  
 
1846
        y_new = (double *)malloc(sizeof(double) * num_points);  
 
1847
        area=0.0;
 
1848
        x_change = x[0];
 
1849
        y_change = y[0];
 
1850
 
 
1851
        for(i=0; i < num_points ; i++){
 
1852
                x_new[i] = x[i] - x_change;
 
1853
                y_new[i] = y[i] - y_change;
 
1854
        }
 
1855
 
 
1856
        for(i=0; i < num_points - 1; i++){
 
1857
                area += (x[i] * y[i+1]) - (y[i] * x[i+1]); //calculate the area 
 
1858
        }
 
1859
        if(area > 0 ){
 
1860
                free(x_new); free(y_new);
 
1861
                return 0; //counter-clockwise
 
1862
        }else{
 
1863
                free(x_new); free(y_new);
 
1864
                return 1; //clockwise
 
1865
        }
 
1866
}
 
1867
 
 
1868
/*
 
1869
 * Returns OID integer on success
 
1870
 * Returns -1 on error.
 
1871
 */
 
1872
int
 
1873
getGeometryOID(PGconn *conn)
 
1874
{
 
1875
        PGresult *res1;
 
1876
        char *temp_int;
 
1877
        int OID;
 
1878
 
 
1879
        res1=PQexec(conn, "select OID from pg_type where typname = 'geometry'");        
 
1880
        if ( ! res1 || PQresultStatus(res1) != PGRES_TUPLES_OK )
 
1881
        {
 
1882
                printf( "OIDQuery: %s", PQerrorMessage(conn));
 
1883
                return -1;
 
1884
        }
 
1885
 
 
1886
        if(PQntuples(res1) <= 0 )
 
1887
        {
 
1888
                printf( "Geometry type unknown "
 
1889
                                "(have you enabled postgis?)\n");
 
1890
                return -1;
 
1891
        }
 
1892
 
 
1893
        temp_int = (char *)PQgetvalue(res1, 0, 0);
 
1894
        OID = atoi(temp_int);
 
1895
        PQclear(res1);
 
1896
        return OID;
 
1897
}
 
1898
 
 
1899
 
 
1900
 
 
1901
 
 
1902
/* 
 
1903
 * Passed result is a 1 row result.
 
1904
 * Return 1 on success.
 
1905
 * Return 0 on failure.
 
1906
 */
 
1907
int
 
1908
addRecord(PGresult *res, int residx, int row)
 
1909
{
 
1910
        int j;
 
1911
        int nFields = PQnfields(res);
 
1912
        int flds = 0; /* number of dbf field */
 
1913
        char *val;
 
1914
        char *v;
 
1915
        size_t junk;
 
1916
 
 
1917
        for (j=0; j<nFields; j++)
 
1918
        {
 
1919
                SHPObject *obj;
 
1920
 
 
1921
                /* Default (not geometry) attribute */
 
1922
                if (type_ary[j] != 9)
 
1923
                {
 
1924
                        /*
 
1925
                         * Transform NULL numbers to '0'
 
1926
                         * This is because the shapelibe
 
1927
                         * won't easly take care of setting
 
1928
                         * nulls unless paying the acquisition
 
1929
                         * of a bug in long integer values
 
1930
                         */
 
1931
                        if ( PQgetisnull(res, residx, j) &&
 
1932
                                ( type_ary[j] == 1 || type_ary[j] == 2 ) )
 
1933
                        {
 
1934
                                val = "0";
 
1935
                        }
 
1936
                        else
 
1937
                        {
 
1938
                                val = PQgetvalue(res, residx, j);
 
1939
                        }
 
1940
#if VERBOSE > 1
 
1941
fprintf(stdout, "s"); fflush(stdout);
 
1942
#endif
 
1943
                        if(!DBFWriteAttributeDirectly(dbf, row, flds, val))
 
1944
                        {
 
1945
                                printf("error(string) - Record could not be "
 
1946
                                                "created\n");
 
1947
                                return 0;
 
1948
                        }
 
1949
                        flds++;
 
1950
                        continue;
 
1951
                }
 
1952
                
 
1953
                /* If we arrived here it is a geometry attribute */
 
1954
 
 
1955
                // Handle NULL shapes
 
1956
                if ( PQgetisnull(res, residx, j) ) {
 
1957
                        obj=SHPCreateSimpleObject(SHPT_NULL,0,NULL,NULL,NULL);
 
1958
                        if ( SHPWriteObject(shp,-1,obj) == -1)
 
1959
                        {
 
1960
                                printf(
 
1961
                                        "Error writing null shape %d\n", row);
 
1962
                                SHPDestroyObject(obj);
 
1963
                                return 0;
 
1964
                        }
 
1965
                        SHPDestroyObject(obj);
 
1966
                        continue;
 
1967
                }
 
1968
 
 
1969
                if ( ! binary )
 
1970
                {
 
1971
                        v = PQgetvalue(res, residx, j);
 
1972
#ifndef HEXWKB
 
1973
                        val = PQunescapeBytea(v, &junk);
 
1974
#else
 
1975
                        if ( pgis_major_version > 0 )
 
1976
                        {
 
1977
                                val = PQunescapeBytea(v, &junk);
 
1978
                        }
 
1979
                        else
 
1980
                        {
 
1981
                                val = HexDecode(v);
 
1982
                        }
 
1983
#endif // HEXWKB
 
1984
#if VERBOSE > 2
 
1985
                dump_wkb(val);
 
1986
#endif // VERBOSE > 2
 
1987
                }
 
1988
                else // binary
 
1989
                {
 
1990
                        val = (char *)PQgetvalue(res, residx, j);
 
1991
                }
 
1992
 
 
1993
#if VERBOSE > 1
 
1994
                fprintf(stdout, "g"); fflush(stdout);
 
1995
#endif
 
1996
 
 
1997
                obj = shape_creator_wrapper_WKB(val, row);
 
1998
                if ( ! obj )
 
1999
                {
 
2000
                        printf( "Error creating shape for record %d "
 
2001
                                        "(geotype is %d)\n", row, geotype);
 
2002
                        return 0;
 
2003
                }
 
2004
                if ( SHPWriteObject(shp,-1,obj) == -1)
 
2005
                {
 
2006
                        printf( "Error writing shape %d\n", row);
 
2007
                        SHPDestroyObject(obj);
 
2008
                        return 0;
 
2009
                }
 
2010
                SHPDestroyObject(obj);
 
2011
 
 
2012
                if ( ! binary ) free(val);
 
2013
        }
 
2014
 
 
2015
#if VERBOSE > 2
 
2016
        printf("Finished adding record %d\n", row);
 
2017
#endif
 
2018
 
 
2019
        return 1;
 
2020
}
 
2021
 
 
2022
/* 
 
2023
 * Return allocate memory. Free after use.
 
2024
 */
 
2025
char *
 
2026
getTableOID(char *schema, char *table)
 
2027
{
 
2028
        PGresult *res3;
 
2029
        char *query;
 
2030
        char *ret;
 
2031
        size_t size;
 
2032
 
 
2033
        size = strlen(table)+256;
 
2034
        if ( schema ) size += strlen(schema)+1;
 
2035
 
 
2036
        query = (char *)malloc(size);
 
2037
 
 
2038
        if ( schema )
 
2039
        {
 
2040
                sprintf(query, "SELECT oid FROM pg_class c, pg_namespace n WHERE c.relnamespace n.oid AND n.nspname = '%s' AND c.relname = '%s'", schema, table);
 
2041
        } else {
 
2042
                sprintf(query, "SELECT oid FROM pg_class WHERE relname = '%s'", table);
 
2043
        }
 
2044
 
 
2045
        res3 = PQexec(conn, query);
 
2046
        free(query);
 
2047
        if ( ! res3 || PQresultStatus(res3) != PGRES_TUPLES_OK ) {
 
2048
                printf( "TableOID: %s", PQerrorMessage(conn));
 
2049
                exit_nicely(conn);
 
2050
        }
 
2051
        if(PQntuples(res3) == 1 ){
 
2052
                ret = strdup(PQgetvalue(res3, 0, 0));
 
2053
        }else if(PQntuples(res3) == 0 ){
 
2054
                printf( "Cannot find relation OID (does table exist?).\n");
 
2055
                PQclear(res3);
 
2056
                return NULL;
 
2057
        }else{
 
2058
                ret = strdup(PQgetvalue(res3, 0, 0));
 
2059
                printf( "Warning: Multiple relations detected, the program will only dump the first relation.\n");
 
2060
        }       
 
2061
        PQclear(res3);
 
2062
        return ret;
 
2063
}
 
2064
 
 
2065
/*
 
2066
 * Return geometry type as defined at top file.
 
2067
 * Return -1 on error.
 
2068
 * Return  0 on unknown or unsupported geometry type.
 
2069
 * Set outtype to 'm' or 'z' depending on input type.
 
2070
 */
 
2071
int
 
2072
getGeometryType(char *schema, char *table, char *geo_col_name)
 
2073
{
 
2074
        char query[1024];
 
2075
        PGresult *res;
 
2076
        char *geo_str; // the geometry type string
 
2077
        int multitype=0;
 
2078
        int basetype=0;
 
2079
        int foundmulti=0;
 
2080
        int foundsingle=0;
 
2081
        int i;
 
2082
 
 
2083
        /**************************************************
 
2084
         * Get what kind of Geometry type is in the table
 
2085
         **************************************************/
 
2086
 
 
2087
        if ( schema )
 
2088
        {
 
2089
                sprintf(query, "SELECT DISTINCT geometrytype(\"%s\") "
 
2090
                        "FROM \"%s\".\"%s\" WHERE NOT geometrytype(\"%s\") "
 
2091
                        "IS NULL", geo_col_name, schema, table, geo_col_name);
 
2092
        }
 
2093
        else
 
2094
        {
 
2095
                sprintf(query, "SELECT DISTINCT geometrytype(\"%s\") "
 
2096
                        "FROM \"%s\" WHERE NOT geometrytype(\"%s\") IS NULL",
 
2097
                        geo_col_name, table, geo_col_name);
 
2098
        }
 
2099
 
 
2100
#if VERBOSE > 2
 
2101
        printf( "%s\n",query);
 
2102
#endif
 
2103
        res = PQexec(conn, query);      
 
2104
        if ( ! res || PQresultStatus(res) != PGRES_TUPLES_OK ) {
 
2105
                printf( "GeometryType: %s", PQerrorMessage(conn));
 
2106
                return -1;
 
2107
        }
 
2108
 
 
2109
        if (PQntuples(res) == 0)
 
2110
        {
 
2111
                printf("ERROR: Cannot determine geometry type (empty table).\n");
 
2112
                PQclear(res);
 
2113
                return -1;
 
2114
        }
 
2115
 
 
2116
        /* This will iterate max 2 times */
 
2117
        for (i=0; i<PQntuples(res); i++)
 
2118
        {
 
2119
                geo_str = PQgetvalue(res, i, 0);
 
2120
                if ( ! strncmp(geo_str, "MULTI", 5) )
 
2121
                {
 
2122
                        foundmulti=1;
 
2123
                        geo_str+=5;
 
2124
                }
 
2125
                else
 
2126
                {
 
2127
                        foundsingle=1;
 
2128
                }
 
2129
 
 
2130
                if ( ! strncmp(geo_str, "LINESTRI", 8) )
 
2131
                {
 
2132
                        if ( basetype && basetype != LINETYPE )
 
2133
                        {
 
2134
                                printf( "ERROR: uncompatible mixed geometry types in table\n");
 
2135
                                PQclear(res);
 
2136
                                return -1;
 
2137
                        }
 
2138
                        basetype = LINETYPE;
 
2139
                        multitype = MULTILINETYPE;
 
2140
                }
 
2141
                else if ( ! strncmp(geo_str, "POLYGON", 7) )
 
2142
                {
 
2143
                        if ( basetype && basetype != POLYGONTYPE )
 
2144
                        {
 
2145
                                printf( "ERROR: uncompatible mixed geometries in table\n");
 
2146
                                PQclear(res);
 
2147
                                return -1;
 
2148
                        }
 
2149
                        basetype = POLYGONTYPE;
 
2150
                        multitype = MULTIPOLYGONTYPE;
 
2151
                }
 
2152
                else if ( ! strncmp(geo_str, "POINT", 5) )
 
2153
                {
 
2154
                        if ( basetype && basetype != POINTTYPE )
 
2155
                        {
 
2156
                                printf( "ERROR: uncompatible mixed geometries in table\n");
 
2157
                                PQclear(res);
 
2158
                                return -1;
 
2159
                        }
 
2160
                        basetype = POINTTYPE;
 
2161
                        multitype = MULTIPOINTTYPE;
 
2162
                }
 
2163
                else
 
2164
                {
 
2165
                        printf( "type '%s' is not Supported at this time.\n",
 
2166
                                geo_str);
 
2167
                        printf( "The DBF file will be created but not the shx "
 
2168
                                "or shp files.\n");
 
2169
                        PQclear(res);
 
2170
                        return 0;
 
2171
                }
 
2172
 
 
2173
        }
 
2174
 
 
2175
        PQclear(res);
 
2176
 
 
2177
        /**************************************************
 
2178
         * Get Geometry dimensions (2d/3dm/3dz/4d)
 
2179
         **************************************************/
 
2180
        if ( pgis_major_version > 0 )
 
2181
                if ( -1 == getGeometryMaxDims(schema, table, geo_col_name) )
 
2182
                        return -1;
 
2183
 
 
2184
        if ( foundmulti )
 
2185
                return multitype;
 
2186
        else
 
2187
                return basetype;
 
2188
 
 
2189
}
 
2190
 
 
2191
/*
 
2192
 * Set global outtype variable to:
 
2193
 *      'm' for 3dm input
 
2194
 *      'z' for 3dz or 4d input
 
2195
 *      's' for 2d
 
2196
 * Return -1 on error, 0 on success.
 
2197
 * Call only on postgis >= 1.0.0
 
2198
 */
 
2199
int
 
2200
getGeometryMaxDims(char *schema, char *table, char *geo_col_name)
 
2201
{
 
2202
        char query[1024];
 
2203
        PGresult *res;
 
2204
        int maxzmflag;
 
2205
 
 
2206
        if ( schema )
 
2207
        {
 
2208
                sprintf(query, "SELECT max(zmflag(\"%s\")) "
 
2209
                        "FROM \"%s\".\"%s\"", 
 
2210
                         geo_col_name, schema, table);
 
2211
        }
 
2212
        else
 
2213
        {
 
2214
                sprintf(query, "SELECT max(zmflag(\"%s\")) "
 
2215
                        "FROM \"%s\"",
 
2216
                        geo_col_name, table);
 
2217
        }
 
2218
 
 
2219
#if VERBOSE > 2
 
2220
        printf("%s\n",query);
 
2221
#endif
 
2222
        res = PQexec(conn, query);      
 
2223
        if ( ! res || PQresultStatus(res) != PGRES_TUPLES_OK ) {
 
2224
                printf( "ZMflagQuery: %s", PQerrorMessage(conn));
 
2225
                PQclear(res);
 
2226
                return -1;
 
2227
        }
 
2228
 
 
2229
        if (PQntuples(res) == 0)
 
2230
        {
 
2231
                printf("ERROR: Cannot determine geometry dimensions (empty table).\n");
 
2232
                PQclear(res);
 
2233
                return -1;
 
2234
        }
 
2235
 
 
2236
        maxzmflag = atoi(PQgetvalue(res, 0, 0));
 
2237
        PQclear(res);
 
2238
 
 
2239
        switch (maxzmflag)
 
2240
        {
 
2241
                case 0:
 
2242
                        outtype = 's';
 
2243
                        break;
 
2244
                case 1:
 
2245
                        outtype = 'm';
 
2246
                        break;
 
2247
                default:
 
2248
                        outtype = 'z';
 
2249
                        break;
 
2250
        }
 
2251
 
 
2252
 
 
2253
        return 0;
 
2254
}
 
2255
 
 
2256
void
 
2257
usage(int status)
 
2258
{
 
2259
        printf("RCSID: %s\n", rcsid);
 
2260
        printf("USAGE: pgsql2shp [<options>] <database> [<schema>.]<table>\n");
 
2261
        printf("       pgsql2shp [<options>] <database> <query>\n");
 
2262
        printf("\n");
 
2263
        printf("OPTIONS:\n");
 
2264
        printf("  -f <filename>  Use this option to specify the name of the file\n");
 
2265
        printf("     to create.\n");
 
2266
        printf("  -h <host>  Allows you to specify connection to a database on a\n");
 
2267
        printf("     machine other than the default.\n");
 
2268
        printf("  -p <port>  Allows you to specify a database port other than the default.\n");
 
2269
        printf("  -P <password>  Connect to the database with the specified password.\n");
 
2270
        printf("  -u <user>  Connect to the database as the specified user.\n");
 
2271
        printf("  -g <geometry_column> Specify the geometry column to be exported.\n");
 
2272
        printf("  -b Use a binary cursor.\n");
 
2273
        printf("  -r Raw mode. Do not assume table has been created by \n");
 
2274
        printf("     the loader. This would not unescape attribute names\n");
 
2275
        printf("     and will not skip the 'gid' attribute.");
 
2276
        printf("\n");
 
2277
        exit (status);
 
2278
}
 
2279
 
 
2280
/* Parse command line parameters */
 
2281
int
 
2282
parse_commandline(int ARGC, char **ARGV)
 
2283
{
 
2284
        int c, curindex;
 
2285
        char buf[1024];
 
2286
 
 
2287
        buf[1023] = '\0'; // just in case...
 
2288
 
 
2289
        /* Parse command line */
 
2290
        while ((c = getopt(ARGC, ARGV, "bf:h:du:p:P:g:r")) != EOF){
 
2291
               switch (c) {
 
2292
               case 'b':
 
2293
                    binary = 1;
 
2294
                    break;
 
2295
               case 'f':
 
2296
                    shp_file = optarg;
 
2297
                    break;
 
2298
               case 'h':
 
2299
                    //setenv("PGHOST", optarg, 1);
 
2300
                    snprintf(buf, 255, "PGHOST=%s", optarg);
 
2301
                    putenv(strdup(buf));
 
2302
                    break;
 
2303
               case 'd':
 
2304
                    dswitchprovided = 1;
 
2305
                    outtype = 'z';
 
2306
                    break;                
 
2307
               case 'r':
 
2308
                    includegid = 1;
 
2309
                    unescapedattrs = 1;
 
2310
                    break;                
 
2311
               case 'u':
 
2312
                    //setenv("PGUSER", optarg, 1);
 
2313
                    snprintf(buf, 255, "PGUSER=%s", optarg);
 
2314
                    putenv(strdup(buf));
 
2315
                    break;
 
2316
               case 'p':
 
2317
                    //setenv("PGPORT", optarg, 1);
 
2318
                    snprintf(buf, 255, "PGPORT=%s", optarg);
 
2319
                    putenv(strdup(buf));
 
2320
                    break;
 
2321
               case 'P':
 
2322
                    //setenv("PGPASSWORD", optarg, 1);
 
2323
                    snprintf(buf, 255, "PGPASSWORD=%s", optarg);
 
2324
                    putenv(strdup(buf));
 
2325
                    break;
 
2326
               case 'g':
 
2327
                    geo_col_name = optarg;
 
2328
                    break;
 
2329
               case '?':
 
2330
                    return 0;
 
2331
               default:
 
2332
                    return 0;
 
2333
               }
 
2334
        }
 
2335
 
 
2336
        curindex=0;
 
2337
        for (; optind<ARGC; optind++){
 
2338
                if (curindex == 0) {
 
2339
                        //setenv("PGDATABASE", ARGV[optind], 1);
 
2340
                        snprintf(buf, 255, "PGDATABASE=%s", ARGV[optind]);
 
2341
                        putenv(strdup(buf));
 
2342
                }else if(curindex == 1){
 
2343
                        parse_table(ARGV[optind]);
 
2344
 
 
2345
                }
 
2346
                curindex++;
 
2347
        }
 
2348
        if (curindex < 2) return 0;
 
2349
        return 1;
 
2350
}
 
2351
 
 
2352
int
 
2353
get_postgis_major_version(void)
 
2354
{
 
2355
        PGresult *res;
 
2356
        char *version;
 
2357
        int ver;
 
2358
        char query[] = "SELECT postgis_version()";
 
2359
        res = PQexec(conn, query);
 
2360
 
 
2361
        if ( ! res || PQresultStatus(res) != PGRES_TUPLES_OK ) {
 
2362
                printf( "Can't detect postgis version:\n");
 
2363
                printf( "PostgisVersionQuery: %s",
 
2364
                        PQerrorMessage(conn));
 
2365
                exit(1);
 
2366
        }
 
2367
 
 
2368
        res = PQexec(conn, query);
 
2369
        version = PQgetvalue(res, 0, 0);
 
2370
        ver = atoi(version);
 
2371
        PQclear(res);
 
2372
        return ver;
 
2373
}
 
2374
 
 
2375
/*
 
2376
 * Initialize shapefile files, main scan query,
 
2377
 * type array.
 
2378
 */
 
2379
int
 
2380
initialize(void)
 
2381
{
 
2382
        PGresult *res;
 
2383
        char *query;
 
2384
        int i;
 
2385
        char buf[256];
 
2386
        int tmpint;
 
2387
        int geo_oid; // geometry oid
 
2388
        int geom_fld = -1;
 
2389
        char *mainscan_flds[256];
 
2390
        int mainscan_nflds=0;
 
2391
        int size;
 
2392
        int gidfound=0;
 
2393
 
 
2394
        /* Detect postgis version */
 
2395
        pgis_major_version = get_postgis_major_version();
 
2396
 
 
2397
        /* Detect host endiannes */
 
2398
        big_endian = is_bigendian();
 
2399
 
 
2400
        /* Query user attributes name, type and size */
 
2401
 
 
2402
        size = strlen(table);
 
2403
        if ( schema ) size += strlen(schema);
 
2404
        size += 256;
 
2405
 
 
2406
        query = (char *)malloc(size);
 
2407
        if ( ! query ) return 0; // out of virtual memory
 
2408
 
 
2409
        if ( schema )
 
2410
        {
 
2411
                sprintf(query, "SELECT a.attname, a.atttypid, a.attlen FROM "
 
2412
                        "pg_attribute a, pg_class c, pg_namespace n WHERE "
 
2413
                        "n.nspname = '%s' AND a.attrelid = c.oid AND "
 
2414
                        "n.oid = c.relnamespace AND "
 
2415
                        "a.atttypid != 0 AND "
 
2416
                        "a.attnum > 0 AND c.relname = '%s'", schema, table);
 
2417
        }
 
2418
        else
 
2419
        {
 
2420
                sprintf(query, "SELECT a.attname, a.atttypid, a.attlen FROM "
 
2421
                        "pg_attribute a, pg_class c WHERE "
 
2422
                        "a.attrelid = c.oid and a.attnum > 0 AND "
 
2423
                        "a.atttypid != 0 AND "
 
2424
                        "c.relname = '%s'", table);
 
2425
        }
 
2426
 
 
2427
 
 
2428
        /* Exec query */
 
2429
#if VERBOSE > 2
 
2430
        printf( "Attribute query: %s\n", query);
 
2431
#endif
 
2432
        res = PQexec(conn, query);
 
2433
        free(query);
 
2434
        if ( ! res || PQresultStatus(res) != PGRES_TUPLES_OK ) {
 
2435
                printf( "Querying for attributes: %s",
 
2436
                        PQerrorMessage(conn));
 
2437
                return 0;
 
2438
        }
 
2439
        if (! PQntuples(res)) {
 
2440
                printf( "Table %s does not exist\n", table);
 
2441
                PQclear(res);
 
2442
                return 0;
 
2443
        }
 
2444
 
 
2445
        /* Create the dbf file */
 
2446
        dbf = DBFCreate(shp_file);
 
2447
        if ( ! dbf ) {
 
2448
                printf( "Could not create dbf file\n");
 
2449
                return 0;
 
2450
        }
 
2451
 
 
2452
 
 
2453
        /* Get geometry oid */
 
2454
        geo_oid = getGeometryOID(conn);
 
2455
        if ( geo_oid == -1 )
 
2456
        {
 
2457
                PQclear(res);
 
2458
                return 0;
 
2459
        }
 
2460
 
 
2461
        /*
 
2462
         * Scan the result setting fields to be returned in mainscan
 
2463
         * query, filling the type_ary, and creating .dbf and .shp files.
 
2464
         */
 
2465
        for (i=0; i<PQntuples(res); i++)
 
2466
        {
 
2467
                int j;
 
2468
                int type, size;
 
2469
                char *fname; // pgsql attribute name
 
2470
                char *ptr;
 
2471
                char field_name[32]; // dbf version of field name
 
2472
 
 
2473
                fname = PQgetvalue(res, i, 0);
 
2474
                type = atoi(PQgetvalue(res, i, 1));
 
2475
                size = atoi(PQgetvalue(res, i, 2));
 
2476
 
 
2477
//printf( "A: %s, T: %d, S: %d\n", fname, type, size);
 
2478
                /*
 
2479
                 * This is a geometry column
 
2480
                 */
 
2481
                if(type == geo_oid)
 
2482
                {
 
2483
                        /* We've already found our geometry column */
 
2484
                        if ( geom_fld != -1 ) continue;
 
2485
 
 
2486
                        /*
 
2487
                         * A geometry attribute name has not been
 
2488
                         * provided: we'll use this one (the first).
 
2489
                         */
 
2490
                        if ( ! geo_col_name )
 
2491
                        {
 
2492
                                geom_fld = mainscan_nflds;
 
2493
                                type_ary[mainscan_nflds]=9; 
 
2494
                                geo_col_name = fname;
 
2495
                                mainscan_flds[mainscan_nflds++] = fname;
 
2496
                        }
 
2497
 
 
2498
                        /*
 
2499
                         * This is exactly the geometry privided
 
2500
                         * by the user.
 
2501
                         */
 
2502
                        else if (!strcmp(geo_col_name,fname))
 
2503
                        {
 
2504
                                geom_fld = mainscan_nflds;
 
2505
                                type_ary[mainscan_nflds]=9; 
 
2506
                                mainscan_flds[mainscan_nflds++] = fname;
 
2507
                        }
 
2508
 
 
2509
                        continue;
 
2510
                }
 
2511
 
 
2512
 
 
2513
                /* 
 
2514
                 * Everything else (non geometries) will be
 
2515
                 * a DBF attribute.
 
2516
                 */
 
2517
 
 
2518
                /* Skip gid (if not asked to do otherwise */
 
2519
                if ( ! strcmp(fname, "gid") )
 
2520
                {
 
2521
                        gidfound = 1;
 
2522
                        if ( ! includegid ) continue;
 
2523
                }
 
2524
 
 
2525
                /* Unescape field name */
 
2526
                ptr = fname;
 
2527
                if ( ! unescapedattrs )
 
2528
                {
 
2529
                        if (*ptr=='_') ptr+=2;
 
2530
                }
 
2531
                /*
 
2532
                 * This needs special handling since both xmin and _xmin
 
2533
                 * becomes __xmin when escaped
 
2534
                 */
 
2535
 
 
2536
 
 
2537
                if(strlen(ptr) <32) strcpy(field_name, ptr);
 
2538
                else
 
2539
                {
 
2540
                        /*
 
2541
                         * TODO: you find an appropriate name if
 
2542
                         * running in RAW mode
 
2543
                         */
 
2544
                        printf("dbf attribute name %s is too long, must be "
 
2545
                                "less than 32 characters.\n", ptr);
 
2546
                        return 0;
 
2547
                }
 
2548
 
 
2549
 
 
2550
                /* make UPPERCASE */
 
2551
                for(j=0; j < strlen(field_name); j++)
 
2552
                        field_name[j] = toupper(field_name[j]);
 
2553
 
 
2554
                /* 
 
2555
                 * make sure the fields all have unique names,
 
2556
                 * 10-digit limit on dbf names...
 
2557
                 */
 
2558
                for(j=0;j<i;j++)
 
2559
                {
 
2560
                        if(strncmp(field_name, PQgetvalue(res, j, 0),10) == 0)
 
2561
                        {
 
2562
                printf("\nWarning: Field '%s' has first 10 characters which "
 
2563
                        "duplicate a previous field name's.\n"
 
2564
                        "Renaming it to be: '",field_name);
 
2565
                                strncpy(field_name,field_name,9);
 
2566
                                field_name[9] = 0;
 
2567
                                sprintf(field_name,"%s%d",field_name,i);
 
2568
                                printf("%s'\n\n",field_name);
 
2569
                        }
 
2570
                }
 
2571
 
 
2572
                /*
 
2573
                 * Find appropriate type of dbf attributes
 
2574
                 */
 
2575
 
 
2576
                /* integer type */
 
2577
                if(type == 20 || type == 21 || type == 23)
 
2578
                {
 
2579
                        if(DBFAddField(dbf, field_name,FTInteger,16,0) == -1)
 
2580
                        {
 
2581
                                printf( "error - Field could not "
 
2582
                                        "be created.\n");
 
2583
                                return 0;
 
2584
                        }
 
2585
                        type_ary[mainscan_nflds]=1;
 
2586
                        mainscan_flds[mainscan_nflds++] = fname;
 
2587
                        continue;
 
2588
                }
 
2589
                
 
2590
                /* double type */
 
2591
                if(type == 700 || type == 701 || type == 1700 )
 
2592
                {
 
2593
                        if(DBFAddField(dbf, field_name,FTDouble,32,10) == -1)
 
2594
                        {
 
2595
                                printf( "error - Field could not "
 
2596
                                                "be created.\n");
 
2597
                                return 0;
 
2598
                        }
 
2599
                        type_ary[mainscan_nflds]=2;
 
2600
                        mainscan_flds[mainscan_nflds++] = fname;
 
2601
                        continue;
 
2602
                }
 
2603
 
 
2604
                /*
 
2605
                 * date field, which we store as a string so we need
 
2606
                 * more width in the column
 
2607
                 */
 
2608
                if(type == 1082)
 
2609
                {
 
2610
                        size = 10;
 
2611
                }
 
2612
 
 
2613
                /*
 
2614
                 * timestamp field, which we store as a string so we need
 
2615
                 * more width in the column
 
2616
                 */
 
2617
                else if(type == 1114)
 
2618
                {
 
2619
                        size = 19;
 
2620
                }
 
2621
 
 
2622
                /*
 
2623
                 * For variable-sized fields we'll use max size in table
 
2624
                 * as dbf field size
 
2625
                 */
 
2626
                else if(size == -1)
 
2627
                {
 
2628
                        size = getMaxFieldSize(conn, schema, table, fname);
 
2629
                        if ( size == -1 ) return 0;
 
2630
                        if ( ! size ) size = 32; // might 0 be a good size ?
 
2631
                }
 
2632
//printf( "FIELD_NAME: %s, SIZE: %d\n", field_name, size);
 
2633
                
 
2634
                /* generic type (use string representation) */
 
2635
                if(DBFAddField(dbf, field_name,FTString,size,0) == -1)
 
2636
                {
 
2637
                        printf( "error - Field could not "
 
2638
                                        "be created.\n");
 
2639
                        return 0;
 
2640
                }
 
2641
                type_ary[mainscan_nflds]=3;
 
2642
                mainscan_flds[mainscan_nflds++] = fname;
 
2643
        }
 
2644
 
 
2645
        /*
 
2646
         * If no geometry has been found
 
2647
         * we have finished with initialization
 
2648
         */
 
2649
        if ( geom_fld == -1 )
 
2650
        {
 
2651
                if ( geo_col_name )
 
2652
                {
 
2653
                        printf( "%s: no such attribute in table %s\n",
 
2654
                                        geo_col_name, table);
 
2655
                        return 0;
 
2656
                }
 
2657
                printf( "No geometry column found.\n");
 
2658
                printf( "The DBF file will be created "
 
2659
                                "but not the shx or shp files.\n");
 
2660
        }
 
2661
 
 
2662
        else
 
2663
        {
 
2664
                /*
 
2665
                 * We now create the appropriate shape (shp) file.
 
2666
                 * And set the shape creator function.
 
2667
                 */
 
2668
                geotype = getGeometryType(schema, table, geo_col_name);
 
2669
                if ( geotype == -1 ) return 0;
 
2670
 
 
2671
                switch (geotype)
 
2672
                {
 
2673
                        case MULTILINETYPE:
 
2674
                        case LINETYPE:
 
2675
                                if (outtype == 'z') outshptype=SHPT_ARCZ;
 
2676
                                else if (outtype == 'm') outshptype=SHPT_ARCM;
 
2677
                                else outshptype=SHPT_ARC;
 
2678
                                break;
 
2679
                                
 
2680
                        case POLYGONTYPE:
 
2681
                        case MULTIPOLYGONTYPE:
 
2682
                                if (outtype == 'z') outshptype=SHPT_POLYGONZ;
 
2683
                                else if (outtype == 'm') outshptype=SHPT_POLYGONM;
 
2684
                                else outshptype=SHPT_POLYGON;
 
2685
                                break;
 
2686
 
 
2687
                        case POINTTYPE:
 
2688
                                if (outtype == 'z') outshptype=SHPT_POINTZ;
 
2689
                                else if (outtype == 'm') outshptype=SHPT_POINTM;
 
2690
                                else outshptype=SHPT_POINT;
 
2691
                                break;
 
2692
 
 
2693
                        case MULTIPOINTTYPE:
 
2694
                                if (outtype == 'z') outshptype=SHPT_MULTIPOINTZ;
 
2695
                                else if (outtype == 'm') outshptype=SHPT_MULTIPOINTM;
 
2696
                                else outshptype=SHPT_MULTIPOINT;
 
2697
                                break;
 
2698
 
 
2699
                        default:
 
2700
                                shp = NULL;
 
2701
                                shape_creator = NULL;
 
2702
                                printf( "You've found a bug! (%s:%d)\n",
 
2703
                                        __FILE__, __LINE__);
 
2704
                                return 0;
 
2705
 
 
2706
                }
 
2707
                shp = SHPCreate(shp_file, outshptype);
 
2708
        }
 
2709
 
 
2710
        /* 
 
2711
         * Ok. Now we should have an array of allocate strings
 
2712
         * representing the fields we'd like to be returned by
 
2713
         * main scan query.
 
2714
         */
 
2715
 
 
2716
        tmpint = strlen(table)+2;
 
2717
        for (i=0; i<mainscan_nflds; i++)
 
2718
                tmpint += strlen(mainscan_flds[i])+32;
 
2719
        main_scan_query = (char *)malloc(tmpint+256);
 
2720
 
 
2721
        sprintf(main_scan_query, "SELECT ");
 
2722
        for (i=0; i<mainscan_nflds; i++)
 
2723
        {
 
2724
                if ( i ) {
 
2725
                        sprintf(buf, ",");
 
2726
                        strcat(main_scan_query, buf);
 
2727
                }
 
2728
 
 
2729
                /* this is the geometry */
 
2730
                if ( type_ary[i] == 9 )
 
2731
                {
 
2732
                        if ( big_endian ) 
 
2733
                        {
 
2734
 
 
2735
 
 
2736
#ifdef HEXWKB
 
2737
                                if ( pgis_major_version > 0 )
 
2738
                                {
 
2739
                                        sprintf(buf, "asEWKB(setSRID(\"%s\", -1), 'XDR')", mainscan_flds[i]);
 
2740
                                }
 
2741
                                else
 
2742
                                {
 
2743
                                        sprintf(buf, "asbinary(\"%s\", 'XDR')",
 
2744
                                                mainscan_flds[i]);
 
2745
                                }
 
2746
#else
 
2747
                                if ( pgis_major_version > 0 )
 
2748
                                {
 
2749
                                        sprintf(buf, "asEWKB(setSRID(\"%s\", -1), 'XDR')", mainscan_flds[i]);
 
2750
                                }
 
2751
                                else
 
2752
                                {
 
2753
                                        sprintf(buf, "asbinary(\"%s\", 'XDR')::bytea", mainscan_flds[i]);
 
2754
                                }
 
2755
#endif
 
2756
 
 
2757
                        }
 
2758
                        else // little_endian
 
2759
                        {
 
2760
 
 
2761
#ifdef HEXWKB
 
2762
                                if ( pgis_major_version > 0 )
 
2763
                                {
 
2764
                                        sprintf(buf, "asEWKB(setSRID(\"%s\", -1), 'NDR')", mainscan_flds[i]);
 
2765
                                }
 
2766
                                else
 
2767
                                {
 
2768
                                        sprintf(buf, "asbinary(\"%s\", 'NDR')",
 
2769
                                                mainscan_flds[i]);
 
2770
                                }
 
2771
#else // ndef HEXWKB
 
2772
                                if ( pgis_major_version > 0 )
 
2773
                                {
 
2774
                                        sprintf(buf, "asEWKB(setSRID(\"%s\", -1), 'NDR')", mainscan_flds[i]);
 
2775
                                }
 
2776
                                else
 
2777
                                {
 
2778
                                        sprintf(buf, "asbinary(\"%s\", 'NDR')::bytea",
 
2779
                                                mainscan_flds[i]);
 
2780
                                }
 
2781
#endif // def HEXWKB
 
2782
 
 
2783
                        }
 
2784
                }
 
2785
                else
 
2786
                {
 
2787
                        if ( binary )
 
2788
                                sprintf(buf, "\"%s\"::text", mainscan_flds[i]);
 
2789
                        else
 
2790
                                sprintf(buf, "\"%s\"", mainscan_flds[i]);
 
2791
                }
 
2792
 
 
2793
                strcat(main_scan_query, buf);
 
2794
        }
 
2795
 
 
2796
        if ( schema )
 
2797
        {
 
2798
                sprintf(buf, " FROM \"%s\".\"%s\"", schema, table);
 
2799
        }
 
2800
        else
 
2801
        {
 
2802
                sprintf(buf, " FROM \"%s\"", table);
 
2803
        }
 
2804
 
 
2805
        strcat(main_scan_query, buf);
 
2806
 
 
2807
        // Order by 'gid' (if found)
 
2808
        if ( gidfound )
 
2809
        {
 
2810
                sprintf(buf, " ORDER BY \"gid\"");
 
2811
                strcat(main_scan_query, buf);
 
2812
        }
 
2813
 
 
2814
        PQclear(res);
 
2815
 
 
2816
        return 1;
 
2817
}
 
2818
 
 
2819
/* 
 
2820
 * Return the maximum octet_length from given table.
 
2821
 * Return -1 on error.
 
2822
 */
 
2823
int
 
2824
getMaxFieldSize(PGconn *conn, char *schema, char *table, char *fname)
 
2825
{
 
2826
        int size;
 
2827
        char *query;
 
2828
        PGresult *res;
 
2829
 
 
2830
        //( this is ugly: don't forget counting the length 
 
2831
        // when changing the fixed query strings )
 
2832
 
 
2833
        if ( schema )
 
2834
        {
 
2835
                query = (char *)malloc(strlen(fname)+strlen(table)+
 
2836
                        strlen(schema)+40); 
 
2837
                sprintf(query,
 
2838
                        "select max(octet_length(\"%s\")) from \"%s\".\"%s\"",
 
2839
                        fname, schema, table);
 
2840
        }
 
2841
        else
 
2842
        {
 
2843
                query = (char *)malloc(strlen(fname)+strlen(table)+40); 
 
2844
                sprintf(query,
 
2845
                        "select max(octet_length(\"%s\")) from \"%s\"",
 
2846
                        fname, table);
 
2847
        }
 
2848
#if VERBOSE > 2
 
2849
        printf( "maxFieldLenQuery: %s\n", query);
 
2850
#endif
 
2851
        res = PQexec(conn, query);
 
2852
        free(query);
 
2853
        if ( ! res || PQresultStatus(res) != PGRES_TUPLES_OK ) {
 
2854
                printf( "Querying for maximum field length: %s",
 
2855
                        PQerrorMessage(conn));
 
2856
                return -1;
 
2857
        }
 
2858
 
 
2859
        if(PQntuples(res) <= 0 )
 
2860
        {
 
2861
                PQclear(res);
 
2862
                return -1;
 
2863
        }
 
2864
        size = atoi(PQgetvalue(res, 0, 0));
 
2865
        PQclear(res);
 
2866
        return size;
 
2867
}
 
2868
 
 
2869
/*
 
2870
 * Input is a NULL-terminated string.
 
2871
 * Output is a binary string.
 
2872
 */
 
2873
byte *
 
2874
HexDecode(byte *hex)
 
2875
{
 
2876
        byte *ret, *retptr, *hexptr;
 
2877
        byte byt;
 
2878
        int len;
 
2879
        
 
2880
        len = strlen(hex)/2;
 
2881
        ret = (byte *)malloc(len);
 
2882
        if ( ! ret )  {
 
2883
                printf( "Out of virtual memory\n");
 
2884
                exit(1);
 
2885
        }
 
2886
 
 
2887
        //printf("Decoding %d bytes", len); fflush(stdout);
 
2888
        hexptr = hex; retptr = ret;
 
2889
 
 
2890
        // for postgis > 0.9.x skip SRID=#; if found
 
2891
        if ( pgis_major_version > 0 )
 
2892
        {
 
2893
                if ( hexptr[0] == 'S' )
 
2894
                {
 
2895
                        hexptr = strchr(hexptr, ';');
 
2896
                        hexptr++;
 
2897
                }
 
2898
        }
 
2899
 
 
2900
        while (*hexptr)
 
2901
        {
 
2902
                /*
 
2903
                 * All these checks on WKB correctness
 
2904
                 * can be avoided, are only here because
 
2905
                 * I keep getting segfaults whereas
 
2906
                 * bytea unescaping works fine...
 
2907
                 */
 
2908
 
 
2909
                //printf("%c", *hexptr);
 
2910
                if ( *hexptr < 58 && *hexptr > 47 )
 
2911
                        byt = (((*hexptr)-48)<<4);
 
2912
                else if ( *hexptr > 64 && *hexptr < 71 )
 
2913
                        byt = (((*hexptr)-55)<<4);
 
2914
                else {
 
2915
                        printf( "Malformed WKB\n");
 
2916
                        exit(1);
 
2917
                }
 
2918
                hexptr++;
 
2919
 
 
2920
                //printf("%c", *hexptr);
 
2921
                if ( *hexptr < 58 && *hexptr > 47 )
 
2922
                        byt |= ((*hexptr)-48);
 
2923
                else if ( *hexptr > 64 && *hexptr < 71 )
 
2924
                        byt |= ((*hexptr)-55);
 
2925
                else {
 
2926
                        printf("Malformed WKB\n");
 
2927
                        exit(1);
 
2928
                }
 
2929
                hexptr++;
 
2930
 
 
2931
                //printf("(%d)", byt);
 
2932
 
 
2933
                *retptr = (byte)byt;
 
2934
                retptr++;
 
2935
        }
 
2936
        //printf(" Done.\n");
 
2937
 
 
2938
        return ret;
 
2939
}
 
2940
 
 
2941
int
 
2942
is_bigendian(void)
 
2943
{
 
2944
        int test = 1;
 
2945
 
 
2946
        if ( (((char *)(&test))[0]) == 1)
 
2947
        {
 
2948
                return 0; //NDR (little_endian)
 
2949
        }
 
2950
        else
 
2951
        {
 
2952
                return 1; //XDR (big_endian)
 
2953
        }
 
2954
}
 
2955
 
 
2956
/*********************************************************************
 
2957
 *
 
2958
 * The following functions might go in a wkb lib
 
2959
 *
 
2960
 * Right now they work on a binary representation, they 
 
2961
 * might work on an exadecimal representation of it as returned
 
2962
 * by text cursors by postgis.
 
2963
 *
 
2964
 *********************************************************************/
 
2965
 
 
2966
void
 
2967
dump_wkb(byte *wkb)
 
2968
{
 
2969
        int byteOrder;
 
2970
        int type;
 
2971
 
 
2972
        printf("\n-----\n");
 
2973
        byteOrder = popbyte(&wkb);
 
2974
        if ( byteOrder == 0 ) printf("ByteOrder: XDR\n");
 
2975
        else if ( byteOrder == 1 ) printf("ByteOrder: NDR\n");
 
2976
        else printf("ByteOrder: unknown (%d)\n", byteOrder);
 
2977
 
 
2978
        type = popint(&wkb); 
 
2979
        if ( type&WKBZOFFSET ) printf ("Has Z!\n");
 
2980
        if ( type&WKBMOFFSET ) printf ("Has M!\n");
 
2981
        type &= ~WKBZOFFSET; // strip Z flag
 
2982
        type &= ~WKBMOFFSET; // strip M flag
 
2983
        printf ("Type: %x\n", type);
 
2984
 
 
2985
        printf("-----\n");
 
2986
}
 
2987
 
 
2988
 
 
2989
void skipbyte(byte **c) {
 
2990
        *c+=1;
 
2991
}
 
2992
 
 
2993
byte getbyte(byte *c) {
 
2994
        return *((char*)c);
 
2995
}
 
2996
 
 
2997
byte popbyte(byte **c) {
 
2998
        return *((*c)++);
 
2999
}
 
3000
 
 
3001
uint32 popint(byte **c) {
 
3002
        uint32 i;
 
3003
        memcpy(&i, *c, 4);
 
3004
        *c+=4;
 
3005
        return i;
 
3006
}
 
3007
 
 
3008
uint32 getint(byte *c) {
 
3009
        uint32 i;
 
3010
        memcpy(&i, c, 4);
 
3011
        return i;
 
3012
}
 
3013
 
 
3014
void skipint(byte **c) {
 
3015
        *c+=4;
 
3016
}
 
3017
 
 
3018
double popdouble(byte **c) {
 
3019
        double d;
 
3020
        memcpy(&d, *c, 8);
 
3021
        *c+=8;
 
3022
        return d;
 
3023
}
 
3024
 
 
3025
void skipdouble(byte **c) {
 
3026
        *c+=8;
 
3027
}
 
3028
 
 
3029
char *
 
3030
shapetypename(int num)
 
3031
{
 
3032
        switch(num)
 
3033
        {
 
3034
                case SHPT_NULL:
 
3035
                        return "Null Shape";
 
3036
                case SHPT_POINT:
 
3037
                        return "Point";
 
3038
                case SHPT_ARC:
 
3039
                        return "PolyLine";
 
3040
                case SHPT_POLYGON:
 
3041
                        return "Polygon";
 
3042
                case SHPT_MULTIPOINT:
 
3043
                        return "MultiPoint";
 
3044
                case SHPT_POINTZ:
 
3045
                        return "PointZ";
 
3046
                case SHPT_ARCZ:
 
3047
                        return "PolyLineZ";
 
3048
                case SHPT_POLYGONZ:
 
3049
                        return "PolygonZ";
 
3050
                case SHPT_MULTIPOINTZ:
 
3051
                        return "MultiPointZ";
 
3052
                case SHPT_POINTM:
 
3053
                        return "PointM";
 
3054
                case SHPT_ARCM:
 
3055
                        return "PolyLineM";
 
3056
                case SHPT_POLYGONM:
 
3057
                        return "PolygonM";
 
3058
                case SHPT_MULTIPOINTM:
 
3059
                        return "MultiPointM";
 
3060
                case SHPT_MULTIPATCH:
 
3061
                        return "MultiPatch";
 
3062
                default:
 
3063
                        return "Unknown";
 
3064
        }
 
3065
}
 
3066
 
 
3067
/*
 
3068
 * Either get a table (and optionally a schema)
 
3069
 * or a query.
 
3070
 * A query starts with a "select" or "SELECT" string.
 
3071
 */
 
3072
static void
 
3073
parse_table(char *spec)
 
3074
{
 
3075
        char *ptr;
 
3076
 
 
3077
        // Spec is a query
 
3078
        if ( strstr(spec, "SELECT ") || strstr(spec, "select ") )
 
3079
        {
 
3080
                usrquery = spec;
 
3081
                table = "__pgsql2shp_tmp_table";
 
3082
        }
 
3083
        else
 
3084
        {
 
3085
                table = spec;
 
3086
                if ( (ptr=strchr(table, '.')) )
 
3087
                {
 
3088
                        *ptr = '\0';
 
3089
                        schema = table;
 
3090
                        table = ptr+1;
 
3091
                }
 
3092
        }
 
3093
}
 
3094
 
 
3095
static int
 
3096
create_usrquerytable(void)
 
3097
{
 
3098
        char *query;
 
3099
        PGresult *res;
 
3100
 
 
3101
        query = malloc(sizeof(table)+sizeof(usrquery)+256);
 
3102
        sprintf(query, "CREATE TEMP TABLE \"%s\" AS %s", table, usrquery);
 
3103
 
 
3104
        printf("Preparing table for user query... ");
 
3105
        fflush(stdout);
 
3106
        res = PQexec(conn, query);
 
3107
        free(query);
 
3108
        if ( ! res || PQresultStatus(res) != PGRES_COMMAND_OK ) {
 
3109
                printf( "Failed: %s\n",
 
3110
                        PQerrorMessage(conn));
 
3111
                return 0;
 
3112
        }
 
3113
        PQclear(res);
 
3114
        printf("Done.\n");
 
3115
        return 1;
 
3116
}
 
3117
 
 
3118
/**********************************************************************
 
3119
 * $Log: pgsql2shp.c,v $
 
3120
 * Revision 1.74  2005/03/25 18:43:07  strk
 
3121
 * Fixed PQunescapeBytearea argument (might give problems on 64bit archs)
 
3122
 *
 
3123
 * Revision 1.73  2005/03/08 11:06:33  strk
 
3124
 * modernized old-style parameter declarations
 
3125
 *
 
3126
 * Revision 1.72  2005/03/04 14:54:03  strk
 
3127
 * Fixed bug in multiline handling.
 
3128
 *
 
3129
 * Revision 1.71  2005/01/31 22:15:22  strk
 
3130
 * Added maintainer notice, to reduce Jeff-strk mail bounces
 
3131
 *
 
3132
 * Revision 1.70  2004/12/22 10:29:09  strk
 
3133
 * Drop useless SRID from geometry when downloading EWKB format.
 
3134
 *
 
3135
 * Revision 1.69  2004/12/15 08:46:47  strk
 
3136
 * Fixed memory leaks depending on input size.
 
3137
 *
 
3138
 * Revision 1.68  2004/11/18 18:14:19  strk
 
3139
 * Added a copy of the PQunescapeBytea function found in libpq of PG>=73
 
3140
 *
 
3141
 * Revision 1.67  2004/10/17 12:16:47  strk
 
3142
 * fixed prototype for user query table
 
3143
 *
 
3144
 * Revision 1.66  2004/10/17 12:15:10  strk
 
3145
 * Bug fixed in multipoint4D creation
 
3146
 *
 
3147
 * Revision 1.65  2004/10/15 08:26:03  strk
 
3148
 * Fixed handling of mixed dimensioned geometries in source table.
 
3149
 *
 
3150
 * Revision 1.64  2004/10/14 09:59:51  strk
 
3151
 * Added support for user query (replacing schema.table)
 
3152
 *
 
3153
 * Revision 1.63  2004/10/11 14:34:40  strk
 
3154
 * Added endiannes specification for postgis-1.0.0+
 
3155
 *
 
3156
 * Revision 1.62  2004/10/07 21:51:05  strk
 
3157
 * Fixed a bug in 4d handling
 
3158
 *
 
3159
 * Revision 1.61  2004/10/07 17:15:28  strk
 
3160
 * Fixed TYPEM handling.
 
3161
 *
 
3162
 * Revision 1.60  2004/10/07 06:54:24  strk
 
3163
 * cleanups
 
3164
 *
 
3165
 * Revision 1.59  2004/10/06 17:04:38  strk
 
3166
 * ZM handling. Log trimmed.
 
3167
 *
 
3168
 * Revision 1.58  2004/09/23 16:14:19  strk
 
3169
 * Added -m / -z switches to control output type: XYM,XYMZ.
 
3170
 *
 
3171
 * Revision 1.57  2004/09/20 17:11:44  strk
 
3172
 * Added -d -d availability notice in help string.
 
3173
 * Added user notice about output shape type.
 
3174
 *
 
3175
 * Revision 1.56  2004/09/20 16:33:05  strk
 
3176
 * Added 4d geometries support.
 
3177
 * Changelog section moved at bottom file.
 
3178
 *
 
3179
 * Revision 1.55  2004/09/20 14:14:43  strk
 
3180
 * Fixed a bug in popbyte. Trapped WKB endiannes errors.
 
3181
 *
 
3182
 * Revision 1.54  2004/09/20 13:49:27  strk
 
3183
 * Postgis-1.x support (LWGEOM) added.
 
3184
 * postgis version detected at runtime.
 
3185
 * Endiannes unchecked ... TODO.
 
3186
 *
 
3187
 **********************************************************************/