shapes 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,136 @@
1
+ #include <ruby.h>
2
+ #include <stdio.h>
3
+ #include <stdlib.h>
4
+ #include "shapefil.h"
5
+ #include "shapes.h"
6
+
7
+ void Init_shapeslib() {
8
+ VALUE shapesModule = rb_define_module("ShapesLib");
9
+ shapeClass = rb_define_class_under(shapesModule,"ShapeFile",rb_cObject);
10
+ rb_define_module_function(shapesModule,"open_shape",OpenSHP,1);
11
+ rb_define_module_function(shapesModule,"close_shape",CloseSHP,1);
12
+ rb_define_module_function(shapesModule,"create_shape",CreateSHP,2);
13
+ rb_define_module_function(shapesModule,"create_object",CreateObject,6);
14
+ }
15
+
16
+ VALUE OpenSHP(VALUE klass,VALUE filename) {
17
+ VALUE rubyObject;
18
+ struct rbShapeFile *openedFile;
19
+ rubyObject = Data_Make_Struct(shapeClass,struct rbShapeFile,NULL,freeShapeFile,openedFile);
20
+
21
+ char *cFileName = StringValuePtr(filename);
22
+ openedFile->fileHandle = SHPOpen(cFileName,"rb+");
23
+ openedFile->open = 1;
24
+
25
+ rb_obj_call_init(rubyObject,0,0);
26
+ return rubyObject;
27
+ }
28
+
29
+ VALUE CreateSHP(VALUE klass,VALUE filename,VALUE shapeType) {
30
+ VALUE rubyObject;
31
+ struct rbShapeFile *createdFile;
32
+ rubyObject = Data_Make_Struct(shapeClass,struct rbShapeFile,NULL,freeShapeFile,createdFile);
33
+
34
+ const char *cFileName = StringValueCStr(filename);
35
+
36
+ VALUE shapeTypeString = StringValue(shapeType);
37
+ const char *cShapeType = StringValueCStr(shapeTypeString);
38
+
39
+ int shape = ShapeFromString(cShapeType);
40
+
41
+ if (shape == -1) {
42
+ return Qfalse;
43
+ }
44
+
45
+ createdFile->fileHandle = SHPCreate(cFileName,shape);
46
+ createdFile->open = 1;
47
+
48
+ rb_obj_call_init(rubyObject,0,0);
49
+ return rubyObject;
50
+ }
51
+
52
+ VALUE CreateObject(VALUE klass,VALUE handle,VALUE shapeType,VALUE numVertices,VALUE x,VALUE y,VALUE z) {
53
+ struct rbShapeFile *shapeFile;
54
+ Data_Get_Struct(handle,struct rbShapeFile,shapeFile);
55
+ SHPHandle fileHandle = shapeFile->fileHandle;
56
+
57
+ if (!shapeFile->open) {
58
+ return Qfalse;
59
+ }
60
+
61
+ int xlen = RARRAY_LEN(x);
62
+ int ylen = RARRAY_LEN(y);
63
+ int zlen = RARRAY_LEN(z);
64
+
65
+
66
+ int xylen = (xlen < ylen) ? xlen : ylen; //Get the lesser of the two
67
+ int len = (zlen > 0 && zlen < xylen) ? zlen : xylen;
68
+
69
+ const char *cShapeType = StringValueCStr(shapeType);
70
+ int shape = ShapeFromString(cShapeType);
71
+
72
+ if (shape == -1) {
73
+ return Qfalse;
74
+ }
75
+
76
+ double *xs, *ys, *zs;
77
+ xs = (double *)malloc(sizeof(double) * len);
78
+ ys = (double *)malloc(sizeof(double) * len);
79
+ zs = (double *)malloc(sizeof(double) * len);
80
+
81
+ int i;
82
+ for (i = 0;i < len;i++) {
83
+ VALUE ax = rb_ary_pop(x);
84
+ VALUE ay = rb_ary_pop(y);
85
+ VALUE az = rb_ary_pop(z);
86
+
87
+ xs[i] = NUM2DBL(ax);
88
+ ys[i] = NUM2DBL(ay);
89
+
90
+ if (az != Qnil) {
91
+ zs[i] = az;
92
+ }
93
+ }
94
+
95
+ if (zlen == 0) {
96
+ zs = NULL;
97
+ }
98
+
99
+ SHPObject *newObject = SHPCreateSimpleObject(shape,len,xs,ys,zs);
100
+ int objNum = SHPWriteObject(fileHandle,-1,newObject);
101
+ SHPDestroyObject(newObject);
102
+ return INT2NUM(objNum);
103
+ }
104
+
105
+ VALUE CloseSHP(VALUE klass,VALUE handle) {
106
+ struct rbShapeFile *shapeFile;
107
+ Data_Get_Struct(handle,struct rbShapeFile,shapeFile);
108
+ SHPHandle fileHandle = shapeFile->fileHandle;
109
+ shapeFile->open = 0;
110
+ SHPClose(fileHandle);
111
+ return Qtrue;
112
+ }
113
+
114
+ void freeShapeFile(struct rbShapeFile *f) {
115
+ if (f->open) {
116
+ SHPClose(f->fileHandle);
117
+ }
118
+ }
119
+
120
+ int ShapeFromString(const char *cShapeType) {
121
+ int shape;
122
+
123
+ if (strcmp(cShapeType,"point") == 0) {
124
+ shape = SHPT_POINT;
125
+ } else if (strcmp(cShapeType,"arc") == 0) {
126
+ shape = SHPT_ARC;
127
+ } else if (strcmp(cShapeType,"polygon") == 0) {
128
+ shape = SHPT_POLYGON;
129
+ } else if (strcmp(cShapeType,"multipoint") == 0) {
130
+ shape = SHPT_MULTIPOINT;
131
+ } else {
132
+ shape = -1;
133
+ }
134
+
135
+ return shape;
136
+ }
@@ -0,0 +1,12 @@
1
+ struct rbShapeFile {
2
+ int open;
3
+ SHPHandle fileHandle;
4
+ };
5
+
6
+ VALUE shapeClass;
7
+ VALUE OpenSHP(VALUE klass,VALUE filename);
8
+ VALUE CreateSHP(VALUE klass,VALUE filename,VALUE shapeType);
9
+ VALUE CloseSHP(VALUE klass,VALUE handle);
10
+ VALUE CreateObject(VALUE klass,VALUE handle,VALUE shapeType,VALUE numVertices,VALUE x,VALUE y,VALUE z);
11
+ void freeShapeFile(struct rbShapeFile *f);
12
+ int ShapeFromString(const char *cShapeType);
@@ -0,0 +1,2388 @@
1
+ /******************************************************************************
2
+ * $Id: shpopen.c,v 1.73 2012-01-24 22:33:01 fwarmerdam Exp $
3
+ *
4
+ * Project: Shapelib
5
+ * Purpose: Implementation of core Shapefile read/write functions.
6
+ * Author: Frank Warmerdam, warmerdam@pobox.com
7
+ *
8
+ ******************************************************************************
9
+ * Copyright (c) 1999, 2001, Frank Warmerdam
10
+ *
11
+ * This software is available under the following "MIT Style" license,
12
+ * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
13
+ * option is discussed in more detail in shapelib.html.
14
+ *
15
+ * --
16
+ *
17
+ * Permission is hereby granted, free of charge, to any person obtaining a
18
+ * copy of this software and associated documentation files (the "Software"),
19
+ * to deal in the Software without restriction, including without limitation
20
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
21
+ * and/or sell copies of the Software, and to permit persons to whom the
22
+ * Software is furnished to do so, subject to the following conditions:
23
+ *
24
+ * The above copyright notice and this permission notice shall be included
25
+ * in all copies or substantial portions of the Software.
26
+ *
27
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
28
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33
+ * DEALINGS IN THE SOFTWARE.
34
+ ******************************************************************************
35
+ *
36
+ * $Log: shpopen.c,v $
37
+ * Revision 1.73 2012-01-24 22:33:01 fwarmerdam
38
+ * fix memory leak on failure to open .shp (gdal #4410)
39
+ *
40
+ * Revision 1.72 2011-12-11 22:45:28 fwarmerdam
41
+ * fix failure return from SHPOpenLL.
42
+ *
43
+ * Revision 1.71 2011-09-15 03:33:58 fwarmerdam
44
+ * fix missing cast (#2344)
45
+ *
46
+ * Revision 1.70 2011-07-24 05:59:25 fwarmerdam
47
+ * minimize use of CPLError in favor of SAHooks.Error()
48
+ *
49
+ * Revision 1.69 2011-07-24 03:24:22 fwarmerdam
50
+ * fix memory leaks in error cases creating shapefiles (#2061)
51
+ *
52
+ * Revision 1.68 2010-08-27 23:42:52 fwarmerdam
53
+ * add SHPAPI_CALL attribute in code
54
+ *
55
+ * Revision 1.67 2010-07-01 08:15:48 fwarmerdam
56
+ * do not error out on an object with zero vertices
57
+ *
58
+ * Revision 1.66 2010-07-01 07:58:57 fwarmerdam
59
+ * minor cleanup of error handling
60
+ *
61
+ * Revision 1.65 2010-07-01 07:27:13 fwarmerdam
62
+ * white space formatting adjustments
63
+ *
64
+ * Revision 1.64 2010-01-28 11:34:34 fwarmerdam
65
+ * handle the shape file length limits more gracefully (#3236)
66
+ *
67
+ * Revision 1.63 2010-01-28 04:04:40 fwarmerdam
68
+ * improve numerical accuracy of SHPRewind() algs (gdal #3363)
69
+ *
70
+ * Revision 1.62 2010-01-17 05:34:13 fwarmerdam
71
+ * Remove asserts on x/y being null (#2148).
72
+ *
73
+ * Revision 1.61 2010-01-16 05:07:42 fwarmerdam
74
+ * allow 0/nulls in shpcreateobject (#2148)
75
+ *
76
+ * Revision 1.60 2009-09-17 20:50:02 bram
77
+ * on Win32, define snprintf as alias to _snprintf
78
+ *
79
+ * Revision 1.59 2008-03-14 05:25:31 fwarmerdam
80
+ * Correct crash on buggy geometries (gdal #2218)
81
+ *
82
+ * Revision 1.58 2008/01/08 23:28:26 bram
83
+ * on line 2095, use a float instead of a double to avoid a compiler warning
84
+ *
85
+ * Revision 1.57 2007/12/06 07:00:25 fwarmerdam
86
+ * dbfopen now using SAHooks for fileio
87
+ *
88
+ * Revision 1.56 2007/12/04 20:37:56 fwarmerdam
89
+ * preliminary implementation of hooks api for io and errors
90
+ *
91
+ * Revision 1.55 2007/11/21 22:39:56 fwarmerdam
92
+ * close shx file in readonly mode (GDAL #1956)
93
+ *
94
+ * Revision 1.54 2007/11/15 00:12:47 mloskot
95
+ * Backported recent changes from GDAL (Ticket #1415) to Shapelib.
96
+ *
97
+ * Revision 1.53 2007/11/14 22:31:08 fwarmerdam
98
+ * checks after mallocs to detect for corrupted/voluntary broken shapefiles.
99
+ * http://trac.osgeo.org/gdal/ticket/1991
100
+ *
101
+ * Revision 1.52 2007/06/21 15:58:33 fwarmerdam
102
+ * fix for SHPRewindObject when rings touch at one vertex (gdal #976)
103
+ *
104
+ * Revision 1.51 2006/09/04 15:24:01 fwarmerdam
105
+ * Fixed up log message for 1.49.
106
+ *
107
+ * Revision 1.50 2006/09/04 15:21:39 fwarmerdam
108
+ * fix of last fix
109
+ *
110
+ * Revision 1.49 2006/09/04 15:21:00 fwarmerdam
111
+ * MLoskot: Added stronger test of Shapefile reading failures, e.g. truncated
112
+ * files. The problem was discovered by Tim Sutton and reported here
113
+ * https://svn.qgis.org/trac/ticket/200
114
+ *
115
+ * Revision 1.48 2006/01/26 15:07:32 fwarmerdam
116
+ * add bMeasureIsUsed flag from Craig Bruce: Bug 1249
117
+ *
118
+ * Revision 1.47 2006/01/04 20:07:23 fwarmerdam
119
+ * In SHPWriteObject() make sure that the record length is updated
120
+ * when rewriting an existing record.
121
+ *
122
+ * Revision 1.46 2005/02/11 17:17:46 fwarmerdam
123
+ * added panPartStart[0] validation
124
+ *
125
+ * Revision 1.45 2004/09/26 20:09:48 fwarmerdam
126
+ * const correctness changes
127
+ *
128
+ * Revision 1.44 2003/12/29 00:18:39 fwarmerdam
129
+ * added error checking for failed IO and optional CPL error reporting
130
+ *
131
+ * Revision 1.43 2003/12/01 16:20:08 warmerda
132
+ * be careful of zero vertex shapes
133
+ *
134
+ * Revision 1.42 2003/12/01 14:58:27 warmerda
135
+ * added degenerate object check in SHPRewindObject()
136
+ *
137
+ * Revision 1.41 2003/07/08 15:22:43 warmerda
138
+ * avoid warning
139
+ *
140
+ * Revision 1.40 2003/04/21 18:30:37 warmerda
141
+ * added header write/update public methods
142
+ *
143
+ * Revision 1.39 2002/08/26 06:46:56 warmerda
144
+ * avoid c++ comments
145
+ *
146
+ * Revision 1.38 2002/05/07 16:43:39 warmerda
147
+ * Removed debugging printf.
148
+ *
149
+ * Revision 1.37 2002/04/10 17:35:22 warmerda
150
+ * fixed bug in ring reversal code
151
+ *
152
+ * Revision 1.36 2002/04/10 16:59:54 warmerda
153
+ * added SHPRewindObject
154
+ *
155
+ * Revision 1.35 2001/12/07 15:10:44 warmerda
156
+ * fix if .shx fails to open
157
+ *
158
+ * Revision 1.34 2001/11/01 16:29:55 warmerda
159
+ * move pabyRec into SHPInfo for thread safety
160
+ *
161
+ * Revision 1.33 2001/07/03 12:18:15 warmerda
162
+ * Improved cleanup if SHX not found, provied by Riccardo Cohen.
163
+ *
164
+ * Revision 1.32 2001/06/22 01:58:07 warmerda
165
+ * be more careful about establishing initial bounds in face of NULL shapes
166
+ *
167
+ * Revision 1.31 2001/05/31 19:35:29 warmerda
168
+ * added support for writing null shapes
169
+ *
170
+ * Revision 1.30 2001/05/28 12:46:29 warmerda
171
+ * Add some checking on reasonableness of record count when opening.
172
+ *
173
+ * Revision 1.29 2001/05/23 13:36:52 warmerda
174
+ * added use of SHPAPI_CALL
175
+ *
176
+ * Revision 1.28 2001/02/06 22:25:06 warmerda
177
+ * fixed memory leaks when SHPOpen() fails
178
+ *
179
+ * Revision 1.27 2000/07/18 15:21:33 warmerda
180
+ * added better enforcement of -1 for append in SHPWriteObject
181
+ *
182
+ * Revision 1.26 2000/02/16 16:03:51 warmerda
183
+ * added null shape support
184
+ *
185
+ * Revision 1.25 1999/12/15 13:47:07 warmerda
186
+ * Fixed record size settings in .shp file (was 4 words too long)
187
+ * Added stdlib.h.
188
+ *
189
+ * Revision 1.24 1999/11/05 14:12:04 warmerda
190
+ * updated license terms
191
+ *
192
+ * Revision 1.23 1999/07/27 00:53:46 warmerda
193
+ * added support for rewriting shapes
194
+ *
195
+ * Revision 1.22 1999/06/11 19:19:11 warmerda
196
+ * Cleanup pabyRec static buffer on SHPClose().
197
+ *
198
+ * Revision 1.21 1999/06/02 14:57:56 kshih
199
+ * Remove unused variables
200
+ *
201
+ * Revision 1.20 1999/04/19 21:04:17 warmerda
202
+ * Fixed syntax error.
203
+ *
204
+ * Revision 1.19 1999/04/19 21:01:57 warmerda
205
+ * Force access string to binary in SHPOpen().
206
+ *
207
+ * Revision 1.18 1999/04/01 18:48:07 warmerda
208
+ * Try upper case extensions if lower case doesn't work.
209
+ *
210
+ * Revision 1.17 1998/12/31 15:29:39 warmerda
211
+ * Disable writing measure values to multipatch objects if
212
+ * DISABLE_MULTIPATCH_MEASURE is defined.
213
+ *
214
+ * Revision 1.16 1998/12/16 05:14:33 warmerda
215
+ * Added support to write MULTIPATCH. Fixed reading Z coordinate of
216
+ * MULTIPATCH. Fixed record size written for all feature types.
217
+ *
218
+ * Revision 1.15 1998/12/03 16:35:29 warmerda
219
+ * r+b is proper binary access string, not rb+.
220
+ *
221
+ * Revision 1.14 1998/12/03 15:47:56 warmerda
222
+ * Fixed setting of nVertices in SHPCreateObject().
223
+ *
224
+ * Revision 1.13 1998/12/03 15:33:54 warmerda
225
+ * Made SHPCalculateExtents() separately callable.
226
+ *
227
+ * Revision 1.12 1998/11/11 20:01:50 warmerda
228
+ * Fixed bug writing ArcM/Z, and PolygonM/Z for big endian machines.
229
+ *
230
+ * Revision 1.11 1998/11/09 20:56:44 warmerda
231
+ * Fixed up handling of file wide bounds.
232
+ *
233
+ * Revision 1.10 1998/11/09 20:18:51 warmerda
234
+ * Converted to support 3D shapefiles, and use of SHPObject.
235
+ *
236
+ * Revision 1.9 1998/02/24 15:09:05 warmerda
237
+ * Fixed memory leak.
238
+ *
239
+ * Revision 1.8 1997/12/04 15:40:29 warmerda
240
+ * Fixed byte swapping of record number, and record length fields in the
241
+ * .shp file.
242
+ *
243
+ * Revision 1.7 1995/10/21 03:15:58 warmerda
244
+ * Added support for binary file access, the magic cookie 9997
245
+ * and tried to improve the int32 selection logic for 16bit systems.
246
+ *
247
+ * Revision 1.6 1995/09/04 04:19:41 warmerda
248
+ * Added fix for file bounds.
249
+ *
250
+ * Revision 1.5 1995/08/25 15:16:44 warmerda
251
+ * Fixed a couple of problems with big endian systems ... one with bounds
252
+ * and the other with multipart polygons.
253
+ *
254
+ * Revision 1.4 1995/08/24 18:10:17 warmerda
255
+ * Switch to use SfRealloc() to avoid problems with pre-ANSI realloc()
256
+ * functions (such as on the Sun).
257
+ *
258
+ * Revision 1.3 1995/08/23 02:23:15 warmerda
259
+ * Added support for reading bounds, and fixed up problems in setting the
260
+ * file wide bounds.
261
+ *
262
+ * Revision 1.2 1995/08/04 03:16:57 warmerda
263
+ * Added header.
264
+ *
265
+ */
266
+
267
+ #include "shapefil.h"
268
+
269
+ #include <math.h>
270
+ #include <limits.h>
271
+ #include <assert.h>
272
+ #include <stdlib.h>
273
+ #include <string.h>
274
+ #include <stdio.h>
275
+
276
+ SHP_CVSID("$Id: shpopen.c,v 1.73 2012-01-24 22:33:01 fwarmerdam Exp $")
277
+
278
+ typedef unsigned char uchar;
279
+
280
+ #if UINT_MAX == 65535
281
+ typedef unsigned long int32;
282
+ #else
283
+ typedef unsigned int int32;
284
+ #endif
285
+
286
+ #ifndef FALSE
287
+ # define FALSE 0
288
+ # define TRUE 1
289
+ #endif
290
+
291
+ #define ByteCopy( a, b, c ) memcpy( b, a, c )
292
+ #ifndef MAX
293
+ # define MIN(a,b) ((a<b) ? a : b)
294
+ # define MAX(a,b) ((a>b) ? a : b)
295
+ #endif
296
+
297
+ #if defined(WIN32) || defined(_WIN32)
298
+ # ifndef snprintf
299
+ # define snprintf _snprintf
300
+ # endif
301
+ #endif
302
+
303
+ static int bBigEndian;
304
+
305
+
306
+ /************************************************************************/
307
+ /* SwapWord() */
308
+ /* */
309
+ /* Swap a 2, 4 or 8 byte word. */
310
+ /************************************************************************/
311
+
312
+ static void SwapWord( int length, void * wordP )
313
+
314
+ {
315
+ int i;
316
+ uchar temp;
317
+
318
+ for( i=0; i < length/2; i++ )
319
+ {
320
+ temp = ((uchar *) wordP)[i];
321
+ ((uchar *)wordP)[i] = ((uchar *) wordP)[length-i-1];
322
+ ((uchar *) wordP)[length-i-1] = temp;
323
+ }
324
+ }
325
+
326
+ /************************************************************************/
327
+ /* SfRealloc() */
328
+ /* */
329
+ /* A realloc cover function that will access a NULL pointer as */
330
+ /* a valid input. */
331
+ /************************************************************************/
332
+
333
+ static void * SfRealloc( void * pMem, int nNewSize )
334
+
335
+ {
336
+ if( pMem == NULL )
337
+ return( (void *) malloc(nNewSize) );
338
+ else
339
+ return( (void *) realloc(pMem,nNewSize) );
340
+ }
341
+
342
+ /************************************************************************/
343
+ /* SHPWriteHeader() */
344
+ /* */
345
+ /* Write out a header for the .shp and .shx files as well as the */
346
+ /* contents of the index (.shx) file. */
347
+ /************************************************************************/
348
+
349
+ void SHPAPI_CALL SHPWriteHeader( SHPHandle psSHP )
350
+
351
+ {
352
+ uchar abyHeader[100];
353
+ int i;
354
+ int32 i32;
355
+ double dValue;
356
+ int32 *panSHX;
357
+
358
+ if (psSHP->fpSHX == NULL)
359
+ {
360
+ psSHP->sHooks.Error( "SHPWriteHeader failed : SHX file is closed");
361
+ return;
362
+ }
363
+
364
+ /* -------------------------------------------------------------------- */
365
+ /* Prepare header block for .shp file. */
366
+ /* -------------------------------------------------------------------- */
367
+ for( i = 0; i < 100; i++ )
368
+ abyHeader[i] = 0;
369
+
370
+ abyHeader[2] = 0x27; /* magic cookie */
371
+ abyHeader[3] = 0x0a;
372
+
373
+ i32 = psSHP->nFileSize/2; /* file size */
374
+ ByteCopy( &i32, abyHeader+24, 4 );
375
+ if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
376
+
377
+ i32 = 1000; /* version */
378
+ ByteCopy( &i32, abyHeader+28, 4 );
379
+ if( bBigEndian ) SwapWord( 4, abyHeader+28 );
380
+
381
+ i32 = psSHP->nShapeType; /* shape type */
382
+ ByteCopy( &i32, abyHeader+32, 4 );
383
+ if( bBigEndian ) SwapWord( 4, abyHeader+32 );
384
+
385
+ dValue = psSHP->adBoundsMin[0]; /* set bounds */
386
+ ByteCopy( &dValue, abyHeader+36, 8 );
387
+ if( bBigEndian ) SwapWord( 8, abyHeader+36 );
388
+
389
+ dValue = psSHP->adBoundsMin[1];
390
+ ByteCopy( &dValue, abyHeader+44, 8 );
391
+ if( bBigEndian ) SwapWord( 8, abyHeader+44 );
392
+
393
+ dValue = psSHP->adBoundsMax[0];
394
+ ByteCopy( &dValue, abyHeader+52, 8 );
395
+ if( bBigEndian ) SwapWord( 8, abyHeader+52 );
396
+
397
+ dValue = psSHP->adBoundsMax[1];
398
+ ByteCopy( &dValue, abyHeader+60, 8 );
399
+ if( bBigEndian ) SwapWord( 8, abyHeader+60 );
400
+
401
+ dValue = psSHP->adBoundsMin[2]; /* z */
402
+ ByteCopy( &dValue, abyHeader+68, 8 );
403
+ if( bBigEndian ) SwapWord( 8, abyHeader+68 );
404
+
405
+ dValue = psSHP->adBoundsMax[2];
406
+ ByteCopy( &dValue, abyHeader+76, 8 );
407
+ if( bBigEndian ) SwapWord( 8, abyHeader+76 );
408
+
409
+ dValue = psSHP->adBoundsMin[3]; /* m */
410
+ ByteCopy( &dValue, abyHeader+84, 8 );
411
+ if( bBigEndian ) SwapWord( 8, abyHeader+84 );
412
+
413
+ dValue = psSHP->adBoundsMax[3];
414
+ ByteCopy( &dValue, abyHeader+92, 8 );
415
+ if( bBigEndian ) SwapWord( 8, abyHeader+92 );
416
+
417
+ /* -------------------------------------------------------------------- */
418
+ /* Write .shp file header. */
419
+ /* -------------------------------------------------------------------- */
420
+ if( psSHP->sHooks.FSeek( psSHP->fpSHP, 0, 0 ) != 0
421
+ || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHP ) != 1 )
422
+ {
423
+ psSHP->sHooks.Error( "Failure writing .shp header" );
424
+ return;
425
+ }
426
+
427
+ /* -------------------------------------------------------------------- */
428
+ /* Prepare, and write .shx file header. */
429
+ /* -------------------------------------------------------------------- */
430
+ i32 = (psSHP->nRecords * 2 * sizeof(int32) + 100)/2; /* file size */
431
+ ByteCopy( &i32, abyHeader+24, 4 );
432
+ if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
433
+
434
+ if( psSHP->sHooks.FSeek( psSHP->fpSHX, 0, 0 ) != 0
435
+ || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHX ) != 1 )
436
+ {
437
+ psSHP->sHooks.Error( "Failure writing .shx header" );
438
+ return;
439
+ }
440
+
441
+ /* -------------------------------------------------------------------- */
442
+ /* Write out the .shx contents. */
443
+ /* -------------------------------------------------------------------- */
444
+ panSHX = (int32 *) malloc(sizeof(int32) * 2 * psSHP->nRecords);
445
+
446
+ for( i = 0; i < psSHP->nRecords; i++ )
447
+ {
448
+ panSHX[i*2 ] = psSHP->panRecOffset[i]/2;
449
+ panSHX[i*2+1] = psSHP->panRecSize[i]/2;
450
+ if( !bBigEndian ) SwapWord( 4, panSHX+i*2 );
451
+ if( !bBigEndian ) SwapWord( 4, panSHX+i*2+1 );
452
+ }
453
+
454
+ if( (int)psSHP->sHooks.FWrite( panSHX, sizeof(int32)*2, psSHP->nRecords, psSHP->fpSHX )
455
+ != psSHP->nRecords )
456
+ {
457
+ psSHP->sHooks.Error( "Failure writing .shx contents" );
458
+ }
459
+
460
+ free( panSHX );
461
+
462
+ /* -------------------------------------------------------------------- */
463
+ /* Flush to disk. */
464
+ /* -------------------------------------------------------------------- */
465
+ psSHP->sHooks.FFlush( psSHP->fpSHP );
466
+ psSHP->sHooks.FFlush( psSHP->fpSHX );
467
+ }
468
+
469
+ /************************************************************************/
470
+ /* SHPOpen() */
471
+ /************************************************************************/
472
+
473
+ SHPHandle SHPAPI_CALL
474
+ SHPOpen( const char * pszLayer, const char * pszAccess )
475
+
476
+ {
477
+ SAHooks sHooks;
478
+
479
+ SASetupDefaultHooks( &sHooks );
480
+
481
+ return SHPOpenLL( pszLayer, pszAccess, &sHooks );
482
+ }
483
+
484
+ /************************************************************************/
485
+ /* SHPOpen() */
486
+ /* */
487
+ /* Open the .shp and .shx files based on the basename of the */
488
+ /* files or either file name. */
489
+ /************************************************************************/
490
+
491
+ SHPHandle SHPAPI_CALL
492
+ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
493
+
494
+ {
495
+ char *pszFullname, *pszBasename;
496
+ SHPHandle psSHP;
497
+
498
+ uchar *pabyBuf;
499
+ int i;
500
+ double dValue;
501
+
502
+ /* -------------------------------------------------------------------- */
503
+ /* Ensure the access string is one of the legal ones. We */
504
+ /* ensure the result string indicates binary to avoid common */
505
+ /* problems on Windows. */
506
+ /* -------------------------------------------------------------------- */
507
+ if( strcmp(pszAccess,"rb+") == 0 || strcmp(pszAccess,"r+b") == 0
508
+ || strcmp(pszAccess,"r+") == 0 )
509
+ pszAccess = "r+b";
510
+ else
511
+ pszAccess = "rb";
512
+
513
+ /* -------------------------------------------------------------------- */
514
+ /* Establish the byte order on this machine. */
515
+ /* -------------------------------------------------------------------- */
516
+ i = 1;
517
+ if( *((uchar *) &i) == 1 )
518
+ bBigEndian = FALSE;
519
+ else
520
+ bBigEndian = TRUE;
521
+
522
+ /* -------------------------------------------------------------------- */
523
+ /* Initialize the info structure. */
524
+ /* -------------------------------------------------------------------- */
525
+ psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1);
526
+
527
+ psSHP->bUpdated = FALSE;
528
+ memcpy( &(psSHP->sHooks), psHooks, sizeof(SAHooks) );
529
+
530
+ /* -------------------------------------------------------------------- */
531
+ /* Compute the base (layer) name. If there is any extension */
532
+ /* on the passed in filename we will strip it off. */
533
+ /* -------------------------------------------------------------------- */
534
+ pszBasename = (char *) malloc(strlen(pszLayer)+5);
535
+ strcpy( pszBasename, pszLayer );
536
+ for( i = strlen(pszBasename)-1;
537
+ i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
538
+ && pszBasename[i] != '\\';
539
+ i-- ) {}
540
+
541
+ if( pszBasename[i] == '.' )
542
+ pszBasename[i] = '\0';
543
+
544
+ /* -------------------------------------------------------------------- */
545
+ /* Open the .shp and .shx files. Note that files pulled from */
546
+ /* a PC to Unix with upper case filenames won't work! */
547
+ /* -------------------------------------------------------------------- */
548
+ pszFullname = (char *) malloc(strlen(pszBasename) + 5);
549
+ sprintf( pszFullname, "%s.shp", pszBasename ) ;
550
+ psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
551
+ if( psSHP->fpSHP == NULL )
552
+ {
553
+ sprintf( pszFullname, "%s.SHP", pszBasename );
554
+ psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
555
+ }
556
+
557
+ if( psSHP->fpSHP == NULL )
558
+ {
559
+ char *pszMessage = (char *) malloc(strlen(pszBasename)*2+256);
560
+ sprintf( pszMessage, "Unable to open %s.shp or %s.SHP.",
561
+ pszBasename, pszBasename );
562
+ psHooks->Error( pszMessage );
563
+ free( pszMessage );
564
+
565
+ free( psSHP );
566
+ free( pszBasename );
567
+ free( pszFullname );
568
+
569
+ return NULL;
570
+ }
571
+
572
+ sprintf( pszFullname, "%s.shx", pszBasename );
573
+ psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess );
574
+ if( psSHP->fpSHX == NULL )
575
+ {
576
+ sprintf( pszFullname, "%s.SHX", pszBasename );
577
+ psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess );
578
+ }
579
+
580
+ if( psSHP->fpSHX == NULL )
581
+ {
582
+ char *pszMessage = (char *) malloc(strlen(pszBasename)*2+256);
583
+ sprintf( pszMessage, "Unable to open %s.shx or %s.SHX.",
584
+ pszBasename, pszBasename );
585
+ psHooks->Error( pszMessage );
586
+ free( pszMessage );
587
+
588
+ psSHP->sHooks.FClose( psSHP->fpSHP );
589
+ free( psSHP );
590
+ free( pszBasename );
591
+ free( pszFullname );
592
+ return( NULL );
593
+ }
594
+
595
+ free( pszFullname );
596
+ free( pszBasename );
597
+
598
+ /* -------------------------------------------------------------------- */
599
+ /* Read the file size from the SHP file. */
600
+ /* -------------------------------------------------------------------- */
601
+ pabyBuf = (uchar *) malloc(100);
602
+ psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHP );
603
+
604
+ psSHP->nFileSize = ((unsigned int)pabyBuf[24] * 256 * 256 * 256
605
+ + (unsigned int)pabyBuf[25] * 256 * 256
606
+ + (unsigned int)pabyBuf[26] * 256
607
+ + (unsigned int)pabyBuf[27]) * 2;
608
+
609
+ /* -------------------------------------------------------------------- */
610
+ /* Read SHX file Header info */
611
+ /* -------------------------------------------------------------------- */
612
+ if( psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHX ) != 1
613
+ || pabyBuf[0] != 0
614
+ || pabyBuf[1] != 0
615
+ || pabyBuf[2] != 0x27
616
+ || (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d) )
617
+ {
618
+ psSHP->sHooks.Error( ".shx file is unreadable, or corrupt." );
619
+ psSHP->sHooks.FClose( psSHP->fpSHP );
620
+ psSHP->sHooks.FClose( psSHP->fpSHX );
621
+ free( psSHP );
622
+
623
+ return( NULL );
624
+ }
625
+
626
+ psSHP->nRecords = pabyBuf[27] + pabyBuf[26] * 256
627
+ + pabyBuf[25] * 256 * 256 + pabyBuf[24] * 256 * 256 * 256;
628
+ psSHP->nRecords = (psSHP->nRecords*2 - 100) / 8;
629
+
630
+ psSHP->nShapeType = pabyBuf[32];
631
+
632
+ if( psSHP->nRecords < 0 || psSHP->nRecords > 256000000 )
633
+ {
634
+ char szError[200];
635
+
636
+ sprintf( szError,
637
+ "Record count in .shp header is %d, which seems\n"
638
+ "unreasonable. Assuming header is corrupt.",
639
+ psSHP->nRecords );
640
+ psSHP->sHooks.Error( szError );
641
+ psSHP->sHooks.FClose( psSHP->fpSHP );
642
+ psSHP->sHooks.FClose( psSHP->fpSHX );
643
+ free( psSHP );
644
+ free(pabyBuf);
645
+
646
+ return( NULL );
647
+ }
648
+
649
+ /* -------------------------------------------------------------------- */
650
+ /* Read the bounds. */
651
+ /* -------------------------------------------------------------------- */
652
+ if( bBigEndian ) SwapWord( 8, pabyBuf+36 );
653
+ memcpy( &dValue, pabyBuf+36, 8 );
654
+ psSHP->adBoundsMin[0] = dValue;
655
+
656
+ if( bBigEndian ) SwapWord( 8, pabyBuf+44 );
657
+ memcpy( &dValue, pabyBuf+44, 8 );
658
+ psSHP->adBoundsMin[1] = dValue;
659
+
660
+ if( bBigEndian ) SwapWord( 8, pabyBuf+52 );
661
+ memcpy( &dValue, pabyBuf+52, 8 );
662
+ psSHP->adBoundsMax[0] = dValue;
663
+
664
+ if( bBigEndian ) SwapWord( 8, pabyBuf+60 );
665
+ memcpy( &dValue, pabyBuf+60, 8 );
666
+ psSHP->adBoundsMax[1] = dValue;
667
+
668
+ if( bBigEndian ) SwapWord( 8, pabyBuf+68 ); /* z */
669
+ memcpy( &dValue, pabyBuf+68, 8 );
670
+ psSHP->adBoundsMin[2] = dValue;
671
+
672
+ if( bBigEndian ) SwapWord( 8, pabyBuf+76 );
673
+ memcpy( &dValue, pabyBuf+76, 8 );
674
+ psSHP->adBoundsMax[2] = dValue;
675
+
676
+ if( bBigEndian ) SwapWord( 8, pabyBuf+84 ); /* z */
677
+ memcpy( &dValue, pabyBuf+84, 8 );
678
+ psSHP->adBoundsMin[3] = dValue;
679
+
680
+ if( bBigEndian ) SwapWord( 8, pabyBuf+92 );
681
+ memcpy( &dValue, pabyBuf+92, 8 );
682
+ psSHP->adBoundsMax[3] = dValue;
683
+
684
+ free( pabyBuf );
685
+
686
+ /* -------------------------------------------------------------------- */
687
+ /* Read the .shx file to get the offsets to each record in */
688
+ /* the .shp file. */
689
+ /* -------------------------------------------------------------------- */
690
+ psSHP->nMaxRecords = psSHP->nRecords;
691
+
692
+ psSHP->panRecOffset = (unsigned int *)
693
+ malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
694
+ psSHP->panRecSize = (unsigned int *)
695
+ malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
696
+ pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) );
697
+
698
+ if (psSHP->panRecOffset == NULL ||
699
+ psSHP->panRecSize == NULL ||
700
+ pabyBuf == NULL)
701
+ {
702
+ char szError[200];
703
+
704
+ sprintf(szError,
705
+ "Not enough memory to allocate requested memory (nRecords=%d).\n"
706
+ "Probably broken SHP file",
707
+ psSHP->nRecords );
708
+ psSHP->sHooks.Error( szError );
709
+ psSHP->sHooks.FClose( psSHP->fpSHP );
710
+ psSHP->sHooks.FClose( psSHP->fpSHX );
711
+ if (psSHP->panRecOffset) free( psSHP->panRecOffset );
712
+ if (psSHP->panRecSize) free( psSHP->panRecSize );
713
+ if (pabyBuf) free( pabyBuf );
714
+ free( psSHP );
715
+ return( NULL );
716
+ }
717
+
718
+ if( (int) psSHP->sHooks.FRead( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX )
719
+ != psSHP->nRecords )
720
+ {
721
+ char szError[200];
722
+
723
+ sprintf( szError,
724
+ "Failed to read all values for %d records in .shx file.",
725
+ psSHP->nRecords );
726
+ psSHP->sHooks.Error( szError );
727
+
728
+ /* SHX is short or unreadable for some reason. */
729
+ psSHP->sHooks.FClose( psSHP->fpSHP );
730
+ psSHP->sHooks.FClose( psSHP->fpSHX );
731
+ free( psSHP->panRecOffset );
732
+ free( psSHP->panRecSize );
733
+ free( pabyBuf );
734
+ free( psSHP );
735
+
736
+ return( NULL );
737
+ }
738
+
739
+ /* In read-only mode, we can close the SHX now */
740
+ if (strcmp(pszAccess, "rb") == 0)
741
+ {
742
+ psSHP->sHooks.FClose( psSHP->fpSHX );
743
+ psSHP->fpSHX = NULL;
744
+ }
745
+
746
+ for( i = 0; i < psSHP->nRecords; i++ )
747
+ {
748
+ int32 nOffset, nLength;
749
+
750
+ memcpy( &nOffset, pabyBuf + i * 8, 4 );
751
+ if( !bBigEndian ) SwapWord( 4, &nOffset );
752
+
753
+ memcpy( &nLength, pabyBuf + i * 8 + 4, 4 );
754
+ if( !bBigEndian ) SwapWord( 4, &nLength );
755
+
756
+ psSHP->panRecOffset[i] = nOffset*2;
757
+ psSHP->panRecSize[i] = nLength*2;
758
+ }
759
+ free( pabyBuf );
760
+
761
+ return( psSHP );
762
+ }
763
+
764
+ /************************************************************************/
765
+ /* SHPClose() */
766
+ /* */
767
+ /* Close the .shp and .shx files. */
768
+ /************************************************************************/
769
+
770
+ void SHPAPI_CALL
771
+ SHPClose(SHPHandle psSHP )
772
+
773
+ {
774
+ if( psSHP == NULL )
775
+ return;
776
+
777
+ /* -------------------------------------------------------------------- */
778
+ /* Update the header if we have modified anything. */
779
+ /* -------------------------------------------------------------------- */
780
+ if( psSHP->bUpdated )
781
+ SHPWriteHeader( psSHP );
782
+
783
+ /* -------------------------------------------------------------------- */
784
+ /* Free all resources, and close files. */
785
+ /* -------------------------------------------------------------------- */
786
+ free( psSHP->panRecOffset );
787
+ free( psSHP->panRecSize );
788
+
789
+ if ( psSHP->fpSHX != NULL)
790
+ psSHP->sHooks.FClose( psSHP->fpSHX );
791
+ psSHP->sHooks.FClose( psSHP->fpSHP );
792
+
793
+ if( psSHP->pabyRec != NULL )
794
+ {
795
+ free( psSHP->pabyRec );
796
+ }
797
+
798
+ free( psSHP );
799
+ }
800
+
801
+ /************************************************************************/
802
+ /* SHPGetInfo() */
803
+ /* */
804
+ /* Fetch general information about the shape file. */
805
+ /************************************************************************/
806
+
807
+ void SHPAPI_CALL
808
+ SHPGetInfo(SHPHandle psSHP, int * pnEntities, int * pnShapeType,
809
+ double * padfMinBound, double * padfMaxBound )
810
+
811
+ {
812
+ int i;
813
+
814
+ if( psSHP == NULL )
815
+ return;
816
+
817
+ if( pnEntities != NULL )
818
+ *pnEntities = psSHP->nRecords;
819
+
820
+ if( pnShapeType != NULL )
821
+ *pnShapeType = psSHP->nShapeType;
822
+
823
+ for( i = 0; i < 4; i++ )
824
+ {
825
+ if( padfMinBound != NULL )
826
+ padfMinBound[i] = psSHP->adBoundsMin[i];
827
+ if( padfMaxBound != NULL )
828
+ padfMaxBound[i] = psSHP->adBoundsMax[i];
829
+ }
830
+ }
831
+
832
+ /************************************************************************/
833
+ /* SHPCreate() */
834
+ /* */
835
+ /* Create a new shape file and return a handle to the open */
836
+ /* shape file with read/write access. */
837
+ /************************************************************************/
838
+
839
+ SHPHandle SHPAPI_CALL
840
+ SHPCreate( const char * pszLayer, int nShapeType )
841
+
842
+ {
843
+ SAHooks sHooks;
844
+
845
+ SASetupDefaultHooks( &sHooks );
846
+
847
+ return SHPCreateLL( pszLayer, nShapeType, &sHooks );
848
+ }
849
+
850
+ /************************************************************************/
851
+ /* SHPCreate() */
852
+ /* */
853
+ /* Create a new shape file and return a handle to the open */
854
+ /* shape file with read/write access. */
855
+ /************************************************************************/
856
+
857
+ SHPHandle SHPAPI_CALL
858
+ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
859
+
860
+ {
861
+ char *pszBasename = NULL, *pszFullname = NULL;
862
+ int i;
863
+ SAFile fpSHP = NULL, fpSHX = NULL;
864
+ uchar abyHeader[100];
865
+ int32 i32;
866
+ double dValue;
867
+
868
+ /* -------------------------------------------------------------------- */
869
+ /* Establish the byte order on this system. */
870
+ /* -------------------------------------------------------------------- */
871
+ i = 1;
872
+ if( *((uchar *) &i) == 1 )
873
+ bBigEndian = FALSE;
874
+ else
875
+ bBigEndian = TRUE;
876
+
877
+ /* -------------------------------------------------------------------- */
878
+ /* Compute the base (layer) name. If there is any extension */
879
+ /* on the passed in filename we will strip it off. */
880
+ /* -------------------------------------------------------------------- */
881
+ pszBasename = (char *) malloc(strlen(pszLayer)+5);
882
+ strcpy( pszBasename, pszLayer );
883
+ for( i = strlen(pszBasename)-1;
884
+ i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
885
+ && pszBasename[i] != '\\';
886
+ i-- ) {}
887
+
888
+ if( pszBasename[i] == '.' )
889
+ pszBasename[i] = '\0';
890
+
891
+ /* -------------------------------------------------------------------- */
892
+ /* Open the two files so we can write their headers. */
893
+ /* -------------------------------------------------------------------- */
894
+ pszFullname = (char *) malloc(strlen(pszBasename) + 5);
895
+ sprintf( pszFullname, "%s.shp", pszBasename );
896
+ fpSHP = psHooks->FOpen(pszFullname, "wb" );
897
+ if( fpSHP == NULL )
898
+ {
899
+ psHooks->Error( "Failed to create file .shp file." );
900
+ goto error;
901
+ }
902
+
903
+ sprintf( pszFullname, "%s.shx", pszBasename );
904
+ fpSHX = psHooks->FOpen(pszFullname, "wb" );
905
+ if( fpSHX == NULL )
906
+ {
907
+ psHooks->Error( "Failed to create file .shx file." );
908
+ goto error;
909
+ }
910
+
911
+ free( pszFullname ); pszFullname = NULL;
912
+ free( pszBasename ); pszBasename = NULL;
913
+
914
+ /* -------------------------------------------------------------------- */
915
+ /* Prepare header block for .shp file. */
916
+ /* -------------------------------------------------------------------- */
917
+ for( i = 0; i < 100; i++ )
918
+ abyHeader[i] = 0;
919
+
920
+ abyHeader[2] = 0x27; /* magic cookie */
921
+ abyHeader[3] = 0x0a;
922
+
923
+ i32 = 50; /* file size */
924
+ ByteCopy( &i32, abyHeader+24, 4 );
925
+ if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
926
+
927
+ i32 = 1000; /* version */
928
+ ByteCopy( &i32, abyHeader+28, 4 );
929
+ if( bBigEndian ) SwapWord( 4, abyHeader+28 );
930
+
931
+ i32 = nShapeType; /* shape type */
932
+ ByteCopy( &i32, abyHeader+32, 4 );
933
+ if( bBigEndian ) SwapWord( 4, abyHeader+32 );
934
+
935
+ dValue = 0.0; /* set bounds */
936
+ ByteCopy( &dValue, abyHeader+36, 8 );
937
+ ByteCopy( &dValue, abyHeader+44, 8 );
938
+ ByteCopy( &dValue, abyHeader+52, 8 );
939
+ ByteCopy( &dValue, abyHeader+60, 8 );
940
+
941
+ /* -------------------------------------------------------------------- */
942
+ /* Write .shp file header. */
943
+ /* -------------------------------------------------------------------- */
944
+ if( psHooks->FWrite( abyHeader, 100, 1, fpSHP ) != 1 )
945
+ {
946
+ psHooks->Error( "Failed to write .shp header." );
947
+ goto error;
948
+ }
949
+
950
+ /* -------------------------------------------------------------------- */
951
+ /* Prepare, and write .shx file header. */
952
+ /* -------------------------------------------------------------------- */
953
+ i32 = 50; /* file size */
954
+ ByteCopy( &i32, abyHeader+24, 4 );
955
+ if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
956
+
957
+ if( psHooks->FWrite( abyHeader, 100, 1, fpSHX ) != 1 )
958
+ {
959
+ psHooks->Error( "Failed to write .shx header." );
960
+ goto error;
961
+ }
962
+
963
+ /* -------------------------------------------------------------------- */
964
+ /* Close the files, and then open them as regular existing files. */
965
+ /* -------------------------------------------------------------------- */
966
+ psHooks->FClose( fpSHP );
967
+ psHooks->FClose( fpSHX );
968
+
969
+ return( SHPOpenLL( pszLayer, "r+b", psHooks ) );
970
+
971
+ error:
972
+ if (pszFullname) free(pszFullname);
973
+ if (pszBasename) free(pszBasename);
974
+ if (fpSHP) psHooks->FClose( fpSHP );
975
+ if (fpSHX) psHooks->FClose( fpSHX );
976
+ return NULL;
977
+ }
978
+
979
+ /************************************************************************/
980
+ /* _SHPSetBounds() */
981
+ /* */
982
+ /* Compute a bounds rectangle for a shape, and set it into the */
983
+ /* indicated location in the record. */
984
+ /************************************************************************/
985
+
986
+ static void _SHPSetBounds( uchar * pabyRec, SHPObject * psShape )
987
+
988
+ {
989
+ ByteCopy( &(psShape->dfXMin), pabyRec + 0, 8 );
990
+ ByteCopy( &(psShape->dfYMin), pabyRec + 8, 8 );
991
+ ByteCopy( &(psShape->dfXMax), pabyRec + 16, 8 );
992
+ ByteCopy( &(psShape->dfYMax), pabyRec + 24, 8 );
993
+
994
+ if( bBigEndian )
995
+ {
996
+ SwapWord( 8, pabyRec + 0 );
997
+ SwapWord( 8, pabyRec + 8 );
998
+ SwapWord( 8, pabyRec + 16 );
999
+ SwapWord( 8, pabyRec + 24 );
1000
+ }
1001
+ }
1002
+
1003
+ /************************************************************************/
1004
+ /* SHPComputeExtents() */
1005
+ /* */
1006
+ /* Recompute the extents of a shape. Automatically done by */
1007
+ /* SHPCreateObject(). */
1008
+ /************************************************************************/
1009
+
1010
+ void SHPAPI_CALL
1011
+ SHPComputeExtents( SHPObject * psObject )
1012
+
1013
+ {
1014
+ int i;
1015
+
1016
+ /* -------------------------------------------------------------------- */
1017
+ /* Build extents for this object. */
1018
+ /* -------------------------------------------------------------------- */
1019
+ if( psObject->nVertices > 0 )
1020
+ {
1021
+ psObject->dfXMin = psObject->dfXMax = psObject->padfX[0];
1022
+ psObject->dfYMin = psObject->dfYMax = psObject->padfY[0];
1023
+ psObject->dfZMin = psObject->dfZMax = psObject->padfZ[0];
1024
+ psObject->dfMMin = psObject->dfMMax = psObject->padfM[0];
1025
+ }
1026
+
1027
+ for( i = 0; i < psObject->nVertices; i++ )
1028
+ {
1029
+ psObject->dfXMin = MIN(psObject->dfXMin, psObject->padfX[i]);
1030
+ psObject->dfYMin = MIN(psObject->dfYMin, psObject->padfY[i]);
1031
+ psObject->dfZMin = MIN(psObject->dfZMin, psObject->padfZ[i]);
1032
+ psObject->dfMMin = MIN(psObject->dfMMin, psObject->padfM[i]);
1033
+
1034
+ psObject->dfXMax = MAX(psObject->dfXMax, psObject->padfX[i]);
1035
+ psObject->dfYMax = MAX(psObject->dfYMax, psObject->padfY[i]);
1036
+ psObject->dfZMax = MAX(psObject->dfZMax, psObject->padfZ[i]);
1037
+ psObject->dfMMax = MAX(psObject->dfMMax, psObject->padfM[i]);
1038
+ }
1039
+ }
1040
+
1041
+ /************************************************************************/
1042
+ /* SHPCreateObject() */
1043
+ /* */
1044
+ /* Create a shape object. It should be freed with */
1045
+ /* SHPDestroyObject(). */
1046
+ /************************************************************************/
1047
+
1048
+ SHPObject SHPAPI_CALL1(*)
1049
+ SHPCreateObject( int nSHPType, int nShapeId, int nParts,
1050
+ const int * panPartStart, const int * panPartType,
1051
+ int nVertices, const double *padfX, const double *padfY,
1052
+ const double * padfZ, const double * padfM )
1053
+
1054
+ {
1055
+ SHPObject *psObject;
1056
+ int i, bHasM, bHasZ;
1057
+
1058
+ psObject = (SHPObject *) calloc(1,sizeof(SHPObject));
1059
+ psObject->nSHPType = nSHPType;
1060
+ psObject->nShapeId = nShapeId;
1061
+ psObject->bMeasureIsUsed = FALSE;
1062
+
1063
+ /* -------------------------------------------------------------------- */
1064
+ /* Establish whether this shape type has M, and Z values. */
1065
+ /* -------------------------------------------------------------------- */
1066
+ if( nSHPType == SHPT_ARCM
1067
+ || nSHPType == SHPT_POINTM
1068
+ || nSHPType == SHPT_POLYGONM
1069
+ || nSHPType == SHPT_MULTIPOINTM )
1070
+ {
1071
+ bHasM = TRUE;
1072
+ bHasZ = FALSE;
1073
+ }
1074
+ else if( nSHPType == SHPT_ARCZ
1075
+ || nSHPType == SHPT_POINTZ
1076
+ || nSHPType == SHPT_POLYGONZ
1077
+ || nSHPType == SHPT_MULTIPOINTZ
1078
+ || nSHPType == SHPT_MULTIPATCH )
1079
+ {
1080
+ bHasM = TRUE;
1081
+ bHasZ = TRUE;
1082
+ }
1083
+ else
1084
+ {
1085
+ bHasM = FALSE;
1086
+ bHasZ = FALSE;
1087
+ }
1088
+
1089
+ /* -------------------------------------------------------------------- */
1090
+ /* Capture parts. Note that part type is optional, and */
1091
+ /* defaults to ring. */
1092
+ /* -------------------------------------------------------------------- */
1093
+ if( nSHPType == SHPT_ARC || nSHPType == SHPT_POLYGON
1094
+ || nSHPType == SHPT_ARCM || nSHPType == SHPT_POLYGONM
1095
+ || nSHPType == SHPT_ARCZ || nSHPType == SHPT_POLYGONZ
1096
+ || nSHPType == SHPT_MULTIPATCH )
1097
+ {
1098
+ psObject->nParts = MAX(1,nParts);
1099
+
1100
+ psObject->panPartStart = (int *)
1101
+ calloc(sizeof(int), psObject->nParts);
1102
+ psObject->panPartType = (int *)
1103
+ malloc(sizeof(int) * psObject->nParts);
1104
+
1105
+ psObject->panPartStart[0] = 0;
1106
+ psObject->panPartType[0] = SHPP_RING;
1107
+
1108
+ for( i = 0; i < nParts; i++ )
1109
+ {
1110
+ if( psObject->panPartStart != NULL )
1111
+ psObject->panPartStart[i] = panPartStart[i];
1112
+
1113
+ if( panPartType != NULL )
1114
+ psObject->panPartType[i] = panPartType[i];
1115
+ else
1116
+ psObject->panPartType[i] = SHPP_RING;
1117
+ }
1118
+
1119
+ if( psObject->panPartStart[0] != 0 )
1120
+ psObject->panPartStart[0] = 0;
1121
+ }
1122
+
1123
+ /* -------------------------------------------------------------------- */
1124
+ /* Capture vertices. Note that X, Y, Z and M are optional. */
1125
+ /* -------------------------------------------------------------------- */
1126
+ if( nVertices > 0 )
1127
+ {
1128
+ psObject->padfX = (double *) calloc(sizeof(double),nVertices);
1129
+ psObject->padfY = (double *) calloc(sizeof(double),nVertices);
1130
+ psObject->padfZ = (double *) calloc(sizeof(double),nVertices);
1131
+ psObject->padfM = (double *) calloc(sizeof(double),nVertices);
1132
+
1133
+ for( i = 0; i < nVertices; i++ )
1134
+ {
1135
+ if( padfX != NULL )
1136
+ psObject->padfX[i] = padfX[i];
1137
+ if( padfY != NULL )
1138
+ psObject->padfY[i] = padfY[i];
1139
+ if( padfZ != NULL && bHasZ )
1140
+ psObject->padfZ[i] = padfZ[i];
1141
+ if( padfM != NULL && bHasM )
1142
+ psObject->padfM[i] = padfM[i];
1143
+ }
1144
+ if( padfM != NULL && bHasM )
1145
+ psObject->bMeasureIsUsed = TRUE;
1146
+ }
1147
+
1148
+ /* -------------------------------------------------------------------- */
1149
+ /* Compute the extents. */
1150
+ /* -------------------------------------------------------------------- */
1151
+ psObject->nVertices = nVertices;
1152
+ SHPComputeExtents( psObject );
1153
+
1154
+ return( psObject );
1155
+ }
1156
+
1157
+ /************************************************************************/
1158
+ /* SHPCreateSimpleObject() */
1159
+ /* */
1160
+ /* Create a simple (common) shape object. Destroy with */
1161
+ /* SHPDestroyObject(). */
1162
+ /************************************************************************/
1163
+
1164
+ SHPObject SHPAPI_CALL1(*)
1165
+ SHPCreateSimpleObject( int nSHPType, int nVertices,
1166
+ const double * padfX, const double * padfY,
1167
+ const double * padfZ )
1168
+
1169
+ {
1170
+ return( SHPCreateObject( nSHPType, -1, 0, NULL, NULL,
1171
+ nVertices, padfX, padfY, padfZ, NULL ) );
1172
+ }
1173
+
1174
+ /************************************************************************/
1175
+ /* SHPWriteObject() */
1176
+ /* */
1177
+ /* Write out the vertices of a new structure. Note that it is */
1178
+ /* only possible to write vertices at the end of the file. */
1179
+ /************************************************************************/
1180
+
1181
+ int SHPAPI_CALL
1182
+ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
1183
+
1184
+ {
1185
+ unsigned int nRecordOffset, nRecordSize=0;
1186
+ int i;
1187
+ uchar *pabyRec;
1188
+ int32 i32;
1189
+
1190
+ psSHP->bUpdated = TRUE;
1191
+
1192
+ /* -------------------------------------------------------------------- */
1193
+ /* Ensure that shape object matches the type of the file it is */
1194
+ /* being written to. */
1195
+ /* -------------------------------------------------------------------- */
1196
+ assert( psObject->nSHPType == psSHP->nShapeType
1197
+ || psObject->nSHPType == SHPT_NULL );
1198
+
1199
+ /* -------------------------------------------------------------------- */
1200
+ /* Ensure that -1 is used for appends. Either blow an */
1201
+ /* assertion, or if they are disabled, set the shapeid to -1 */
1202
+ /* for appends. */
1203
+ /* -------------------------------------------------------------------- */
1204
+ assert( nShapeId == -1
1205
+ || (nShapeId >= 0 && nShapeId < psSHP->nRecords) );
1206
+
1207
+ if( nShapeId != -1 && nShapeId >= psSHP->nRecords )
1208
+ nShapeId = -1;
1209
+
1210
+ /* -------------------------------------------------------------------- */
1211
+ /* Add the new entity to the in memory index. */
1212
+ /* -------------------------------------------------------------------- */
1213
+ if( nShapeId == -1 && psSHP->nRecords+1 > psSHP->nMaxRecords )
1214
+ {
1215
+ psSHP->nMaxRecords =(int) ( psSHP->nMaxRecords * 1.3 + 100);
1216
+
1217
+ psSHP->panRecOffset = (unsigned int *)
1218
+ SfRealloc(psSHP->panRecOffset,sizeof(unsigned int) * psSHP->nMaxRecords );
1219
+ psSHP->panRecSize = (unsigned int *)
1220
+ SfRealloc(psSHP->panRecSize,sizeof(unsigned int) * psSHP->nMaxRecords );
1221
+ }
1222
+
1223
+ /* -------------------------------------------------------------------- */
1224
+ /* Initialize record. */
1225
+ /* -------------------------------------------------------------------- */
1226
+ pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double)
1227
+ + psObject->nParts * 8 + 128);
1228
+
1229
+ /* -------------------------------------------------------------------- */
1230
+ /* Extract vertices for a Polygon or Arc. */
1231
+ /* -------------------------------------------------------------------- */
1232
+ if( psObject->nSHPType == SHPT_POLYGON
1233
+ || psObject->nSHPType == SHPT_POLYGONZ
1234
+ || psObject->nSHPType == SHPT_POLYGONM
1235
+ || psObject->nSHPType == SHPT_ARC
1236
+ || psObject->nSHPType == SHPT_ARCZ
1237
+ || psObject->nSHPType == SHPT_ARCM
1238
+ || psObject->nSHPType == SHPT_MULTIPATCH )
1239
+ {
1240
+ int32 nPoints, nParts;
1241
+ int i;
1242
+
1243
+ nPoints = psObject->nVertices;
1244
+ nParts = psObject->nParts;
1245
+
1246
+ _SHPSetBounds( pabyRec + 12, psObject );
1247
+
1248
+ if( bBigEndian ) SwapWord( 4, &nPoints );
1249
+ if( bBigEndian ) SwapWord( 4, &nParts );
1250
+
1251
+ ByteCopy( &nPoints, pabyRec + 40 + 8, 4 );
1252
+ ByteCopy( &nParts, pabyRec + 36 + 8, 4 );
1253
+
1254
+ nRecordSize = 52;
1255
+
1256
+ /*
1257
+ * Write part start positions.
1258
+ */
1259
+ ByteCopy( psObject->panPartStart, pabyRec + 44 + 8,
1260
+ 4 * psObject->nParts );
1261
+ for( i = 0; i < psObject->nParts; i++ )
1262
+ {
1263
+ if( bBigEndian ) SwapWord( 4, pabyRec + 44 + 8 + 4*i );
1264
+ nRecordSize += 4;
1265
+ }
1266
+
1267
+ /*
1268
+ * Write multipatch part types if needed.
1269
+ */
1270
+ if( psObject->nSHPType == SHPT_MULTIPATCH )
1271
+ {
1272
+ memcpy( pabyRec + nRecordSize, psObject->panPartType,
1273
+ 4*psObject->nParts );
1274
+ for( i = 0; i < psObject->nParts; i++ )
1275
+ {
1276
+ if( bBigEndian ) SwapWord( 4, pabyRec + nRecordSize );
1277
+ nRecordSize += 4;
1278
+ }
1279
+ }
1280
+
1281
+ /*
1282
+ * Write the (x,y) vertex values.
1283
+ */
1284
+ for( i = 0; i < psObject->nVertices; i++ )
1285
+ {
1286
+ ByteCopy( psObject->padfX + i, pabyRec + nRecordSize, 8 );
1287
+ ByteCopy( psObject->padfY + i, pabyRec + nRecordSize + 8, 8 );
1288
+
1289
+ if( bBigEndian )
1290
+ SwapWord( 8, pabyRec + nRecordSize );
1291
+
1292
+ if( bBigEndian )
1293
+ SwapWord( 8, pabyRec + nRecordSize + 8 );
1294
+
1295
+ nRecordSize += 2 * 8;
1296
+ }
1297
+
1298
+ /*
1299
+ * Write the Z coordinates (if any).
1300
+ */
1301
+ if( psObject->nSHPType == SHPT_POLYGONZ
1302
+ || psObject->nSHPType == SHPT_ARCZ
1303
+ || psObject->nSHPType == SHPT_MULTIPATCH )
1304
+ {
1305
+ ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
1306
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1307
+ nRecordSize += 8;
1308
+
1309
+ ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
1310
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1311
+ nRecordSize += 8;
1312
+
1313
+ for( i = 0; i < psObject->nVertices; i++ )
1314
+ {
1315
+ ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
1316
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1317
+ nRecordSize += 8;
1318
+ }
1319
+ }
1320
+
1321
+ /*
1322
+ * Write the M values, if any.
1323
+ */
1324
+ if( psObject->bMeasureIsUsed
1325
+ && (psObject->nSHPType == SHPT_POLYGONM
1326
+ || psObject->nSHPType == SHPT_ARCM
1327
+ #ifndef DISABLE_MULTIPATCH_MEASURE
1328
+ || psObject->nSHPType == SHPT_MULTIPATCH
1329
+ #endif
1330
+ || psObject->nSHPType == SHPT_POLYGONZ
1331
+ || psObject->nSHPType == SHPT_ARCZ) )
1332
+ {
1333
+ ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
1334
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1335
+ nRecordSize += 8;
1336
+
1337
+ ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
1338
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1339
+ nRecordSize += 8;
1340
+
1341
+ for( i = 0; i < psObject->nVertices; i++ )
1342
+ {
1343
+ ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
1344
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1345
+ nRecordSize += 8;
1346
+ }
1347
+ }
1348
+ }
1349
+
1350
+ /* -------------------------------------------------------------------- */
1351
+ /* Extract vertices for a MultiPoint. */
1352
+ /* -------------------------------------------------------------------- */
1353
+ else if( psObject->nSHPType == SHPT_MULTIPOINT
1354
+ || psObject->nSHPType == SHPT_MULTIPOINTZ
1355
+ || psObject->nSHPType == SHPT_MULTIPOINTM )
1356
+ {
1357
+ int32 nPoints;
1358
+ int i;
1359
+
1360
+ nPoints = psObject->nVertices;
1361
+
1362
+ _SHPSetBounds( pabyRec + 12, psObject );
1363
+
1364
+ if( bBigEndian ) SwapWord( 4, &nPoints );
1365
+ ByteCopy( &nPoints, pabyRec + 44, 4 );
1366
+
1367
+ for( i = 0; i < psObject->nVertices; i++ )
1368
+ {
1369
+ ByteCopy( psObject->padfX + i, pabyRec + 48 + i*16, 8 );
1370
+ ByteCopy( psObject->padfY + i, pabyRec + 48 + i*16 + 8, 8 );
1371
+
1372
+ if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 );
1373
+ if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 + 8 );
1374
+ }
1375
+
1376
+ nRecordSize = 48 + 16 * psObject->nVertices;
1377
+
1378
+ if( psObject->nSHPType == SHPT_MULTIPOINTZ )
1379
+ {
1380
+ ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
1381
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1382
+ nRecordSize += 8;
1383
+
1384
+ ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
1385
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1386
+ nRecordSize += 8;
1387
+
1388
+ for( i = 0; i < psObject->nVertices; i++ )
1389
+ {
1390
+ ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
1391
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1392
+ nRecordSize += 8;
1393
+ }
1394
+ }
1395
+
1396
+ if( psObject->bMeasureIsUsed
1397
+ && (psObject->nSHPType == SHPT_MULTIPOINTZ
1398
+ || psObject->nSHPType == SHPT_MULTIPOINTM) )
1399
+ {
1400
+ ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
1401
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1402
+ nRecordSize += 8;
1403
+
1404
+ ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
1405
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1406
+ nRecordSize += 8;
1407
+
1408
+ for( i = 0; i < psObject->nVertices; i++ )
1409
+ {
1410
+ ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
1411
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1412
+ nRecordSize += 8;
1413
+ }
1414
+ }
1415
+ }
1416
+
1417
+ /* -------------------------------------------------------------------- */
1418
+ /* Write point. */
1419
+ /* -------------------------------------------------------------------- */
1420
+ else if( psObject->nSHPType == SHPT_POINT
1421
+ || psObject->nSHPType == SHPT_POINTZ
1422
+ || psObject->nSHPType == SHPT_POINTM )
1423
+ {
1424
+ ByteCopy( psObject->padfX, pabyRec + 12, 8 );
1425
+ ByteCopy( psObject->padfY, pabyRec + 20, 8 );
1426
+
1427
+ if( bBigEndian ) SwapWord( 8, pabyRec + 12 );
1428
+ if( bBigEndian ) SwapWord( 8, pabyRec + 20 );
1429
+
1430
+ nRecordSize = 28;
1431
+
1432
+ if( psObject->nSHPType == SHPT_POINTZ )
1433
+ {
1434
+ ByteCopy( psObject->padfZ, pabyRec + nRecordSize, 8 );
1435
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1436
+ nRecordSize += 8;
1437
+ }
1438
+
1439
+ if( psObject->bMeasureIsUsed
1440
+ && (psObject->nSHPType == SHPT_POINTZ
1441
+ || psObject->nSHPType == SHPT_POINTM) )
1442
+ {
1443
+ ByteCopy( psObject->padfM, pabyRec + nRecordSize, 8 );
1444
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1445
+ nRecordSize += 8;
1446
+ }
1447
+ }
1448
+
1449
+ /* -------------------------------------------------------------------- */
1450
+ /* Not much to do for null geometries. */
1451
+ /* -------------------------------------------------------------------- */
1452
+ else if( psObject->nSHPType == SHPT_NULL )
1453
+ {
1454
+ nRecordSize = 12;
1455
+ }
1456
+
1457
+ else
1458
+ {
1459
+ /* unknown type */
1460
+ assert( FALSE );
1461
+ }
1462
+
1463
+ /* -------------------------------------------------------------------- */
1464
+ /* Establish where we are going to put this record. If we are */
1465
+ /* rewriting and existing record, and it will fit, then put it */
1466
+ /* back where the original came from. Otherwise write at the end. */
1467
+ /* -------------------------------------------------------------------- */
1468
+ if( nShapeId == -1 || psSHP->panRecSize[nShapeId] < nRecordSize-8 )
1469
+ {
1470
+ unsigned int nExpectedSize = psSHP->nFileSize + nRecordSize;
1471
+ if( nExpectedSize < psSHP->nFileSize ) // due to unsigned int overflow
1472
+ {
1473
+ char str[128];
1474
+ sprintf( str, "Failed to write shape object. "
1475
+ "File size cannot reach %u + %u.",
1476
+ psSHP->nFileSize, nRecordSize );
1477
+ psSHP->sHooks.Error( str );
1478
+ free( pabyRec );
1479
+ return -1;
1480
+ }
1481
+
1482
+ if( nShapeId == -1 )
1483
+ nShapeId = psSHP->nRecords++;
1484
+
1485
+ psSHP->panRecOffset[nShapeId] = nRecordOffset = psSHP->nFileSize;
1486
+ psSHP->panRecSize[nShapeId] = nRecordSize-8;
1487
+ psSHP->nFileSize += nRecordSize;
1488
+ }
1489
+ else
1490
+ {
1491
+ nRecordOffset = psSHP->panRecOffset[nShapeId];
1492
+ psSHP->panRecSize[nShapeId] = nRecordSize-8;
1493
+ }
1494
+
1495
+ /* -------------------------------------------------------------------- */
1496
+ /* Set the shape type, record number, and record size. */
1497
+ /* -------------------------------------------------------------------- */
1498
+ i32 = nShapeId+1; /* record # */
1499
+ if( !bBigEndian ) SwapWord( 4, &i32 );
1500
+ ByteCopy( &i32, pabyRec, 4 );
1501
+
1502
+ i32 = (nRecordSize-8)/2; /* record size */
1503
+ if( !bBigEndian ) SwapWord( 4, &i32 );
1504
+ ByteCopy( &i32, pabyRec + 4, 4 );
1505
+
1506
+ i32 = psObject->nSHPType; /* shape type */
1507
+ if( bBigEndian ) SwapWord( 4, &i32 );
1508
+ ByteCopy( &i32, pabyRec + 8, 4 );
1509
+
1510
+ /* -------------------------------------------------------------------- */
1511
+ /* Write out record. */
1512
+ /* -------------------------------------------------------------------- */
1513
+ if( psSHP->sHooks.FSeek( psSHP->fpSHP, nRecordOffset, 0 ) != 0 )
1514
+ {
1515
+ psSHP->sHooks.Error( "Error in psSHP->sHooks.FSeek() while writing object to .shp file." );
1516
+ free( pabyRec );
1517
+ return -1;
1518
+ }
1519
+ if( psSHP->sHooks.FWrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 )
1520
+ {
1521
+ psSHP->sHooks.Error( "Error in psSHP->sHooks.Fwrite() while writing object to .shp file." );
1522
+ free( pabyRec );
1523
+ return -1;
1524
+ }
1525
+
1526
+ free( pabyRec );
1527
+
1528
+ /* -------------------------------------------------------------------- */
1529
+ /* Expand file wide bounds based on this shape. */
1530
+ /* -------------------------------------------------------------------- */
1531
+ if( psSHP->adBoundsMin[0] == 0.0
1532
+ && psSHP->adBoundsMax[0] == 0.0
1533
+ && psSHP->adBoundsMin[1] == 0.0
1534
+ && psSHP->adBoundsMax[1] == 0.0 )
1535
+ {
1536
+ if( psObject->nSHPType == SHPT_NULL || psObject->nVertices == 0 )
1537
+ {
1538
+ psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = 0.0;
1539
+ psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = 0.0;
1540
+ psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = 0.0;
1541
+ psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = 0.0;
1542
+ }
1543
+ else
1544
+ {
1545
+ psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = psObject->padfX[0];
1546
+ psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = psObject->padfY[0];
1547
+ psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ[0];
1548
+ psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM[0];
1549
+ }
1550
+ }
1551
+
1552
+ for( i = 0; i < psObject->nVertices; i++ )
1553
+ {
1554
+ psSHP->adBoundsMin[0] = MIN(psSHP->adBoundsMin[0],psObject->padfX[i]);
1555
+ psSHP->adBoundsMin[1] = MIN(psSHP->adBoundsMin[1],psObject->padfY[i]);
1556
+ psSHP->adBoundsMin[2] = MIN(psSHP->adBoundsMin[2],psObject->padfZ[i]);
1557
+ psSHP->adBoundsMin[3] = MIN(psSHP->adBoundsMin[3],psObject->padfM[i]);
1558
+ psSHP->adBoundsMax[0] = MAX(psSHP->adBoundsMax[0],psObject->padfX[i]);
1559
+ psSHP->adBoundsMax[1] = MAX(psSHP->adBoundsMax[1],psObject->padfY[i]);
1560
+ psSHP->adBoundsMax[2] = MAX(psSHP->adBoundsMax[2],psObject->padfZ[i]);
1561
+ psSHP->adBoundsMax[3] = MAX(psSHP->adBoundsMax[3],psObject->padfM[i]);
1562
+ }
1563
+
1564
+ return( nShapeId );
1565
+ }
1566
+
1567
+ /************************************************************************/
1568
+ /* SHPReadObject() */
1569
+ /* */
1570
+ /* Read the vertices, parts, and other non-attribute information */
1571
+ /* for one shape. */
1572
+ /************************************************************************/
1573
+
1574
+ SHPObject SHPAPI_CALL1(*)
1575
+ SHPReadObject( SHPHandle psSHP, int hEntity )
1576
+
1577
+ {
1578
+ int nEntitySize, nRequiredSize;
1579
+ SHPObject *psShape;
1580
+ char szErrorMsg[128];
1581
+
1582
+ /* -------------------------------------------------------------------- */
1583
+ /* Validate the record/entity number. */
1584
+ /* -------------------------------------------------------------------- */
1585
+ if( hEntity < 0 || hEntity >= psSHP->nRecords )
1586
+ return( NULL );
1587
+
1588
+ /* -------------------------------------------------------------------- */
1589
+ /* Ensure our record buffer is large enough. */
1590
+ /* -------------------------------------------------------------------- */
1591
+ nEntitySize = psSHP->panRecSize[hEntity]+8;
1592
+ if( nEntitySize > psSHP->nBufSize )
1593
+ {
1594
+ psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,nEntitySize);
1595
+ if (psSHP->pabyRec == NULL)
1596
+ {
1597
+ char szError[200];
1598
+
1599
+ /* Reallocate previous successfull size for following features */
1600
+ psSHP->pabyRec = (uchar *) malloc(psSHP->nBufSize);
1601
+
1602
+ sprintf( szError,
1603
+ "Not enough memory to allocate requested memory (nBufSize=%d). "
1604
+ "Probably broken SHP file", psSHP->nBufSize );
1605
+ psSHP->sHooks.Error( szError );
1606
+ return NULL;
1607
+ }
1608
+
1609
+ /* Only set new buffer size after successfull alloc */
1610
+ psSHP->nBufSize = nEntitySize;
1611
+ }
1612
+
1613
+ /* In case we were not able to reallocate the buffer on a previous step */
1614
+ if (psSHP->pabyRec == NULL)
1615
+ {
1616
+ return NULL;
1617
+ }
1618
+
1619
+ /* -------------------------------------------------------------------- */
1620
+ /* Read the record. */
1621
+ /* -------------------------------------------------------------------- */
1622
+ if( psSHP->sHooks.FSeek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 ) != 0 )
1623
+ {
1624
+ /*
1625
+ * TODO - mloskot: Consider detailed diagnostics of shape file,
1626
+ * for example to detect if file is truncated.
1627
+ */
1628
+ char str[128];
1629
+ sprintf( str,
1630
+ "Error in fseek() reading object from .shp file at offset %u",
1631
+ psSHP->panRecOffset[hEntity]);
1632
+
1633
+ psSHP->sHooks.Error( str );
1634
+ return NULL;
1635
+ }
1636
+
1637
+ if( psSHP->sHooks.FRead( psSHP->pabyRec, nEntitySize, 1, psSHP->fpSHP ) != 1 )
1638
+ {
1639
+ /*
1640
+ * TODO - mloskot: Consider detailed diagnostics of shape file,
1641
+ * for example to detect if file is truncated.
1642
+ */
1643
+ char str[128];
1644
+ sprintf( str,
1645
+ "Error in fread() reading object of size %u at offset %u from .shp file",
1646
+ nEntitySize, psSHP->panRecOffset[hEntity] );
1647
+
1648
+ psSHP->sHooks.Error( str );
1649
+ return NULL;
1650
+ }
1651
+
1652
+ /* -------------------------------------------------------------------- */
1653
+ /* Allocate and minimally initialize the object. */
1654
+ /* -------------------------------------------------------------------- */
1655
+ psShape = (SHPObject *) calloc(1,sizeof(SHPObject));
1656
+ psShape->nShapeId = hEntity;
1657
+ psShape->bMeasureIsUsed = FALSE;
1658
+
1659
+ if ( 8 + 4 > nEntitySize )
1660
+ {
1661
+ snprintf(szErrorMsg, sizeof(szErrorMsg),
1662
+ "Corrupted .shp file : shape %d : nEntitySize = %d",
1663
+ hEntity, nEntitySize);
1664
+ psSHP->sHooks.Error( szErrorMsg );
1665
+ SHPDestroyObject(psShape);
1666
+ return NULL;
1667
+ }
1668
+ memcpy( &psShape->nSHPType, psSHP->pabyRec + 8, 4 );
1669
+
1670
+ if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) );
1671
+
1672
+ /* ==================================================================== */
1673
+ /* Extract vertices for a Polygon or Arc. */
1674
+ /* ==================================================================== */
1675
+ if( psShape->nSHPType == SHPT_POLYGON || psShape->nSHPType == SHPT_ARC
1676
+ || psShape->nSHPType == SHPT_POLYGONZ
1677
+ || psShape->nSHPType == SHPT_POLYGONM
1678
+ || psShape->nSHPType == SHPT_ARCZ
1679
+ || psShape->nSHPType == SHPT_ARCM
1680
+ || psShape->nSHPType == SHPT_MULTIPATCH )
1681
+ {
1682
+ int32 nPoints, nParts;
1683
+ int i, nOffset;
1684
+
1685
+ if ( 40 + 8 + 4 > nEntitySize )
1686
+ {
1687
+ snprintf(szErrorMsg, sizeof(szErrorMsg),
1688
+ "Corrupted .shp file : shape %d : nEntitySize = %d",
1689
+ hEntity, nEntitySize);
1690
+ psSHP->sHooks.Error( szErrorMsg );
1691
+ SHPDestroyObject(psShape);
1692
+ return NULL;
1693
+ }
1694
+ /* -------------------------------------------------------------------- */
1695
+ /* Get the X/Y bounds. */
1696
+ /* -------------------------------------------------------------------- */
1697
+ memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 );
1698
+ memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );
1699
+ memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
1700
+ memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
1701
+
1702
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
1703
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
1704
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
1705
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
1706
+
1707
+ /* -------------------------------------------------------------------- */
1708
+ /* Extract part/point count, and build vertex and part arrays */
1709
+ /* to proper size. */
1710
+ /* -------------------------------------------------------------------- */
1711
+ memcpy( &nPoints, psSHP->pabyRec + 40 + 8, 4 );
1712
+ memcpy( &nParts, psSHP->pabyRec + 36 + 8, 4 );
1713
+
1714
+ if( bBigEndian ) SwapWord( 4, &nPoints );
1715
+ if( bBigEndian ) SwapWord( 4, &nParts );
1716
+
1717
+ if (nPoints < 0 || nParts < 0 ||
1718
+ nPoints > 50 * 1000 * 1000 || nParts > 10 * 1000 * 1000)
1719
+ {
1720
+ snprintf(szErrorMsg, sizeof(szErrorMsg),
1721
+ "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d.",
1722
+ hEntity, nPoints, nParts);
1723
+ psSHP->sHooks.Error( szErrorMsg );
1724
+ SHPDestroyObject(psShape);
1725
+ return NULL;
1726
+ }
1727
+
1728
+ /* With the previous checks on nPoints and nParts, */
1729
+ /* we should not overflow here and after */
1730
+ /* since 50 M * (16 + 8 + 8) = 1 600 MB */
1731
+ nRequiredSize = 44 + 8 + 4 * nParts + 16 * nPoints;
1732
+ if ( psShape->nSHPType == SHPT_POLYGONZ
1733
+ || psShape->nSHPType == SHPT_ARCZ
1734
+ || psShape->nSHPType == SHPT_MULTIPATCH )
1735
+ {
1736
+ nRequiredSize += 16 + 8 * nPoints;
1737
+ }
1738
+ if( psShape->nSHPType == SHPT_MULTIPATCH )
1739
+ {
1740
+ nRequiredSize += 4 * nParts;
1741
+ }
1742
+ if (nRequiredSize > nEntitySize)
1743
+ {
1744
+ snprintf(szErrorMsg, sizeof(szErrorMsg),
1745
+ "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d, nEntitySize=%d.",
1746
+ hEntity, nPoints, nParts, nEntitySize);
1747
+ psSHP->sHooks.Error( szErrorMsg );
1748
+ SHPDestroyObject(psShape);
1749
+ return NULL;
1750
+ }
1751
+
1752
+ psShape->nVertices = nPoints;
1753
+ psShape->padfX = (double *) calloc(nPoints,sizeof(double));
1754
+ psShape->padfY = (double *) calloc(nPoints,sizeof(double));
1755
+ psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
1756
+ psShape->padfM = (double *) calloc(nPoints,sizeof(double));
1757
+
1758
+ psShape->nParts = nParts;
1759
+ psShape->panPartStart = (int *) calloc(nParts,sizeof(int));
1760
+ psShape->panPartType = (int *) calloc(nParts,sizeof(int));
1761
+
1762
+ if (psShape->padfX == NULL ||
1763
+ psShape->padfY == NULL ||
1764
+ psShape->padfZ == NULL ||
1765
+ psShape->padfM == NULL ||
1766
+ psShape->panPartStart == NULL ||
1767
+ psShape->panPartType == NULL)
1768
+ {
1769
+ snprintf(szErrorMsg, sizeof(szErrorMsg),
1770
+ "Not enough memory to allocate requested memory (nPoints=%d, nParts=%d) for shape %d. "
1771
+ "Probably broken SHP file", hEntity, nPoints, nParts );
1772
+ psSHP->sHooks.Error( szErrorMsg );
1773
+ SHPDestroyObject(psShape);
1774
+ return NULL;
1775
+ }
1776
+
1777
+ for( i = 0; i < nParts; i++ )
1778
+ psShape->panPartType[i] = SHPP_RING;
1779
+
1780
+ /* -------------------------------------------------------------------- */
1781
+ /* Copy out the part array from the record. */
1782
+ /* -------------------------------------------------------------------- */
1783
+ memcpy( psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts );
1784
+ for( i = 0; i < nParts; i++ )
1785
+ {
1786
+ if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i );
1787
+
1788
+ /* We check that the offset is inside the vertex array */
1789
+ if (psShape->panPartStart[i] < 0
1790
+ || (psShape->panPartStart[i] >= psShape->nVertices
1791
+ && psShape->nVertices > 0) )
1792
+ {
1793
+ snprintf(szErrorMsg, sizeof(szErrorMsg),
1794
+ "Corrupted .shp file : shape %d : panPartStart[%d] = %d, nVertices = %d",
1795
+ hEntity, i, psShape->panPartStart[i], psShape->nVertices);
1796
+ psSHP->sHooks.Error( szErrorMsg );
1797
+ SHPDestroyObject(psShape);
1798
+ return NULL;
1799
+ }
1800
+ if (i > 0 && psShape->panPartStart[i] <= psShape->panPartStart[i-1])
1801
+ {
1802
+ snprintf(szErrorMsg, sizeof(szErrorMsg),
1803
+ "Corrupted .shp file : shape %d : panPartStart[%d] = %d, panPartStart[%d] = %d",
1804
+ hEntity, i, psShape->panPartStart[i], i - 1, psShape->panPartStart[i - 1]);
1805
+ psSHP->sHooks.Error( szErrorMsg );
1806
+ SHPDestroyObject(psShape);
1807
+ return NULL;
1808
+ }
1809
+ }
1810
+
1811
+ nOffset = 44 + 8 + 4*nParts;
1812
+
1813
+ /* -------------------------------------------------------------------- */
1814
+ /* If this is a multipatch, we will also have parts types. */
1815
+ /* -------------------------------------------------------------------- */
1816
+ if( psShape->nSHPType == SHPT_MULTIPATCH )
1817
+ {
1818
+ memcpy( psShape->panPartType, psSHP->pabyRec + nOffset, 4*nParts );
1819
+ for( i = 0; i < nParts; i++ )
1820
+ {
1821
+ if( bBigEndian ) SwapWord( 4, psShape->panPartType+i );
1822
+ }
1823
+
1824
+ nOffset += 4*nParts;
1825
+ }
1826
+
1827
+ /* -------------------------------------------------------------------- */
1828
+ /* Copy out the vertices from the record. */
1829
+ /* -------------------------------------------------------------------- */
1830
+ for( i = 0; i < nPoints; i++ )
1831
+ {
1832
+ memcpy(psShape->padfX + i,
1833
+ psSHP->pabyRec + nOffset + i * 16,
1834
+ 8 );
1835
+
1836
+ memcpy(psShape->padfY + i,
1837
+ psSHP->pabyRec + nOffset + i * 16 + 8,
1838
+ 8 );
1839
+
1840
+ if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
1841
+ if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
1842
+ }
1843
+
1844
+ nOffset += 16*nPoints;
1845
+
1846
+ /* -------------------------------------------------------------------- */
1847
+ /* If we have a Z coordinate, collect that now. */
1848
+ /* -------------------------------------------------------------------- */
1849
+ if( psShape->nSHPType == SHPT_POLYGONZ
1850
+ || psShape->nSHPType == SHPT_ARCZ
1851
+ || psShape->nSHPType == SHPT_MULTIPATCH )
1852
+ {
1853
+ memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
1854
+ memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
1855
+
1856
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
1857
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
1858
+
1859
+ for( i = 0; i < nPoints; i++ )
1860
+ {
1861
+ memcpy( psShape->padfZ + i,
1862
+ psSHP->pabyRec + nOffset + 16 + i*8, 8 );
1863
+ if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
1864
+ }
1865
+
1866
+ nOffset += 16 + 8*nPoints;
1867
+ }
1868
+
1869
+ /* -------------------------------------------------------------------- */
1870
+ /* If we have a M measure value, then read it now. We assume */
1871
+ /* that the measure can be present for any shape if the size is */
1872
+ /* big enough, but really it will only occur for the Z shapes */
1873
+ /* (options), and the M shapes. */
1874
+ /* -------------------------------------------------------------------- */
1875
+ if( nEntitySize >= nOffset + 16 + 8*nPoints )
1876
+ {
1877
+ memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
1878
+ memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
1879
+
1880
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
1881
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
1882
+
1883
+ for( i = 0; i < nPoints; i++ )
1884
+ {
1885
+ memcpy( psShape->padfM + i,
1886
+ psSHP->pabyRec + nOffset + 16 + i*8, 8 );
1887
+ if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
1888
+ }
1889
+ psShape->bMeasureIsUsed = TRUE;
1890
+ }
1891
+ }
1892
+
1893
+ /* ==================================================================== */
1894
+ /* Extract vertices for a MultiPoint. */
1895
+ /* ==================================================================== */
1896
+ else if( psShape->nSHPType == SHPT_MULTIPOINT
1897
+ || psShape->nSHPType == SHPT_MULTIPOINTM
1898
+ || psShape->nSHPType == SHPT_MULTIPOINTZ )
1899
+ {
1900
+ int32 nPoints;
1901
+ int i, nOffset;
1902
+
1903
+ if ( 44 + 4 > nEntitySize )
1904
+ {
1905
+ snprintf(szErrorMsg, sizeof(szErrorMsg),
1906
+ "Corrupted .shp file : shape %d : nEntitySize = %d",
1907
+ hEntity, nEntitySize);
1908
+ psSHP->sHooks.Error( szErrorMsg );
1909
+ SHPDestroyObject(psShape);
1910
+ return NULL;
1911
+ }
1912
+ memcpy( &nPoints, psSHP->pabyRec + 44, 4 );
1913
+
1914
+ if( bBigEndian ) SwapWord( 4, &nPoints );
1915
+
1916
+ if (nPoints < 0 || nPoints > 50 * 1000 * 1000)
1917
+ {
1918
+ snprintf(szErrorMsg, sizeof(szErrorMsg),
1919
+ "Corrupted .shp file : shape %d : nPoints = %d",
1920
+ hEntity, nPoints);
1921
+ psSHP->sHooks.Error( szErrorMsg );
1922
+ SHPDestroyObject(psShape);
1923
+ return NULL;
1924
+ }
1925
+
1926
+ nRequiredSize = 48 + nPoints * 16;
1927
+ if( psShape->nSHPType == SHPT_MULTIPOINTZ )
1928
+ {
1929
+ nRequiredSize += 16 + nPoints * 8;
1930
+ }
1931
+ if (nRequiredSize > nEntitySize)
1932
+ {
1933
+ snprintf(szErrorMsg, sizeof(szErrorMsg),
1934
+ "Corrupted .shp file : shape %d : nPoints = %d, nEntitySize = %d",
1935
+ hEntity, nPoints, nEntitySize);
1936
+ psSHP->sHooks.Error( szErrorMsg );
1937
+ SHPDestroyObject(psShape);
1938
+ return NULL;
1939
+ }
1940
+
1941
+ psShape->nVertices = nPoints;
1942
+ psShape->padfX = (double *) calloc(nPoints,sizeof(double));
1943
+ psShape->padfY = (double *) calloc(nPoints,sizeof(double));
1944
+ psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
1945
+ psShape->padfM = (double *) calloc(nPoints,sizeof(double));
1946
+
1947
+ if (psShape->padfX == NULL ||
1948
+ psShape->padfY == NULL ||
1949
+ psShape->padfZ == NULL ||
1950
+ psShape->padfM == NULL)
1951
+ {
1952
+ snprintf(szErrorMsg, sizeof(szErrorMsg),
1953
+ "Not enough memory to allocate requested memory (nPoints=%d) for shape %d. "
1954
+ "Probably broken SHP file", hEntity, nPoints );
1955
+ psSHP->sHooks.Error( szErrorMsg );
1956
+ SHPDestroyObject(psShape);
1957
+ return NULL;
1958
+ }
1959
+
1960
+ for( i = 0; i < nPoints; i++ )
1961
+ {
1962
+ memcpy(psShape->padfX+i, psSHP->pabyRec + 48 + 16 * i, 8 );
1963
+ memcpy(psShape->padfY+i, psSHP->pabyRec + 48 + 16 * i + 8, 8 );
1964
+
1965
+ if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
1966
+ if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
1967
+ }
1968
+
1969
+ nOffset = 48 + 16*nPoints;
1970
+
1971
+ /* -------------------------------------------------------------------- */
1972
+ /* Get the X/Y bounds. */
1973
+ /* -------------------------------------------------------------------- */
1974
+ memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 );
1975
+ memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );
1976
+ memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
1977
+ memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
1978
+
1979
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
1980
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
1981
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
1982
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
1983
+
1984
+ /* -------------------------------------------------------------------- */
1985
+ /* If we have a Z coordinate, collect that now. */
1986
+ /* -------------------------------------------------------------------- */
1987
+ if( psShape->nSHPType == SHPT_MULTIPOINTZ )
1988
+ {
1989
+ memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
1990
+ memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
1991
+
1992
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
1993
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
1994
+
1995
+ for( i = 0; i < nPoints; i++ )
1996
+ {
1997
+ memcpy( psShape->padfZ + i,
1998
+ psSHP->pabyRec + nOffset + 16 + i*8, 8 );
1999
+ if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
2000
+ }
2001
+
2002
+ nOffset += 16 + 8*nPoints;
2003
+ }
2004
+
2005
+ /* -------------------------------------------------------------------- */
2006
+ /* If we have a M measure value, then read it now. We assume */
2007
+ /* that the measure can be present for any shape if the size is */
2008
+ /* big enough, but really it will only occur for the Z shapes */
2009
+ /* (options), and the M shapes. */
2010
+ /* -------------------------------------------------------------------- */
2011
+ if( nEntitySize >= nOffset + 16 + 8*nPoints )
2012
+ {
2013
+ memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
2014
+ memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
2015
+
2016
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
2017
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
2018
+
2019
+ for( i = 0; i < nPoints; i++ )
2020
+ {
2021
+ memcpy( psShape->padfM + i,
2022
+ psSHP->pabyRec + nOffset + 16 + i*8, 8 );
2023
+ if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
2024
+ }
2025
+ psShape->bMeasureIsUsed = TRUE;
2026
+ }
2027
+ }
2028
+
2029
+ /* ==================================================================== */
2030
+ /* Extract vertices for a point. */
2031
+ /* ==================================================================== */
2032
+ else if( psShape->nSHPType == SHPT_POINT
2033
+ || psShape->nSHPType == SHPT_POINTM
2034
+ || psShape->nSHPType == SHPT_POINTZ )
2035
+ {
2036
+ int nOffset;
2037
+
2038
+ psShape->nVertices = 1;
2039
+ psShape->padfX = (double *) calloc(1,sizeof(double));
2040
+ psShape->padfY = (double *) calloc(1,sizeof(double));
2041
+ psShape->padfZ = (double *) calloc(1,sizeof(double));
2042
+ psShape->padfM = (double *) calloc(1,sizeof(double));
2043
+
2044
+ if (20 + 8 + (( psShape->nSHPType == SHPT_POINTZ ) ? 8 : 0)> nEntitySize)
2045
+ {
2046
+ snprintf(szErrorMsg, sizeof(szErrorMsg),
2047
+ "Corrupted .shp file : shape %d : nEntitySize = %d",
2048
+ hEntity, nEntitySize);
2049
+ psSHP->sHooks.Error( szErrorMsg );
2050
+ SHPDestroyObject(psShape);
2051
+ return NULL;
2052
+ }
2053
+ memcpy( psShape->padfX, psSHP->pabyRec + 12, 8 );
2054
+ memcpy( psShape->padfY, psSHP->pabyRec + 20, 8 );
2055
+
2056
+ if( bBigEndian ) SwapWord( 8, psShape->padfX );
2057
+ if( bBigEndian ) SwapWord( 8, psShape->padfY );
2058
+
2059
+ nOffset = 20 + 8;
2060
+
2061
+ /* -------------------------------------------------------------------- */
2062
+ /* If we have a Z coordinate, collect that now. */
2063
+ /* -------------------------------------------------------------------- */
2064
+ if( psShape->nSHPType == SHPT_POINTZ )
2065
+ {
2066
+ memcpy( psShape->padfZ, psSHP->pabyRec + nOffset, 8 );
2067
+
2068
+ if( bBigEndian ) SwapWord( 8, psShape->padfZ );
2069
+
2070
+ nOffset += 8;
2071
+ }
2072
+
2073
+ /* -------------------------------------------------------------------- */
2074
+ /* If we have a M measure value, then read it now. We assume */
2075
+ /* that the measure can be present for any shape if the size is */
2076
+ /* big enough, but really it will only occur for the Z shapes */
2077
+ /* (options), and the M shapes. */
2078
+ /* -------------------------------------------------------------------- */
2079
+ if( nEntitySize >= nOffset + 8 )
2080
+ {
2081
+ memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 );
2082
+
2083
+ if( bBigEndian ) SwapWord( 8, psShape->padfM );
2084
+ psShape->bMeasureIsUsed = TRUE;
2085
+ }
2086
+
2087
+ /* -------------------------------------------------------------------- */
2088
+ /* Since no extents are supplied in the record, we will apply */
2089
+ /* them from the single vertex. */
2090
+ /* -------------------------------------------------------------------- */
2091
+ psShape->dfXMin = psShape->dfXMax = psShape->padfX[0];
2092
+ psShape->dfYMin = psShape->dfYMax = psShape->padfY[0];
2093
+ psShape->dfZMin = psShape->dfZMax = psShape->padfZ[0];
2094
+ psShape->dfMMin = psShape->dfMMax = psShape->padfM[0];
2095
+ }
2096
+
2097
+ return( psShape );
2098
+ }
2099
+
2100
+ /************************************************************************/
2101
+ /* SHPTypeName() */
2102
+ /************************************************************************/
2103
+
2104
+ const char SHPAPI_CALL1(*)
2105
+ SHPTypeName( int nSHPType )
2106
+
2107
+ {
2108
+ switch( nSHPType )
2109
+ {
2110
+ case SHPT_NULL:
2111
+ return "NullShape";
2112
+
2113
+ case SHPT_POINT:
2114
+ return "Point";
2115
+
2116
+ case SHPT_ARC:
2117
+ return "Arc";
2118
+
2119
+ case SHPT_POLYGON:
2120
+ return "Polygon";
2121
+
2122
+ case SHPT_MULTIPOINT:
2123
+ return "MultiPoint";
2124
+
2125
+ case SHPT_POINTZ:
2126
+ return "PointZ";
2127
+
2128
+ case SHPT_ARCZ:
2129
+ return "ArcZ";
2130
+
2131
+ case SHPT_POLYGONZ:
2132
+ return "PolygonZ";
2133
+
2134
+ case SHPT_MULTIPOINTZ:
2135
+ return "MultiPointZ";
2136
+
2137
+ case SHPT_POINTM:
2138
+ return "PointM";
2139
+
2140
+ case SHPT_ARCM:
2141
+ return "ArcM";
2142
+
2143
+ case SHPT_POLYGONM:
2144
+ return "PolygonM";
2145
+
2146
+ case SHPT_MULTIPOINTM:
2147
+ return "MultiPointM";
2148
+
2149
+ case SHPT_MULTIPATCH:
2150
+ return "MultiPatch";
2151
+
2152
+ default:
2153
+ return "UnknownShapeType";
2154
+ }
2155
+ }
2156
+
2157
+ /************************************************************************/
2158
+ /* SHPPartTypeName() */
2159
+ /************************************************************************/
2160
+
2161
+ const char SHPAPI_CALL1(*)
2162
+ SHPPartTypeName( int nPartType )
2163
+
2164
+ {
2165
+ switch( nPartType )
2166
+ {
2167
+ case SHPP_TRISTRIP:
2168
+ return "TriangleStrip";
2169
+
2170
+ case SHPP_TRIFAN:
2171
+ return "TriangleFan";
2172
+
2173
+ case SHPP_OUTERRING:
2174
+ return "OuterRing";
2175
+
2176
+ case SHPP_INNERRING:
2177
+ return "InnerRing";
2178
+
2179
+ case SHPP_FIRSTRING:
2180
+ return "FirstRing";
2181
+
2182
+ case SHPP_RING:
2183
+ return "Ring";
2184
+
2185
+ default:
2186
+ return "UnknownPartType";
2187
+ }
2188
+ }
2189
+
2190
+ /************************************************************************/
2191
+ /* SHPDestroyObject() */
2192
+ /************************************************************************/
2193
+
2194
+ void SHPAPI_CALL
2195
+ SHPDestroyObject( SHPObject * psShape )
2196
+
2197
+ {
2198
+ if( psShape == NULL )
2199
+ return;
2200
+
2201
+ if( psShape->padfX != NULL )
2202
+ free( psShape->padfX );
2203
+ if( psShape->padfY != NULL )
2204
+ free( psShape->padfY );
2205
+ if( psShape->padfZ != NULL )
2206
+ free( psShape->padfZ );
2207
+ if( psShape->padfM != NULL )
2208
+ free( psShape->padfM );
2209
+
2210
+ if( psShape->panPartStart != NULL )
2211
+ free( psShape->panPartStart );
2212
+ if( psShape->panPartType != NULL )
2213
+ free( psShape->panPartType );
2214
+
2215
+ free( psShape );
2216
+ }
2217
+
2218
+ /************************************************************************/
2219
+ /* SHPRewindObject() */
2220
+ /* */
2221
+ /* Reset the winding of polygon objects to adhere to the */
2222
+ /* specification. */
2223
+ /************************************************************************/
2224
+
2225
+ int SHPAPI_CALL
2226
+ SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
2227
+
2228
+ {
2229
+ int iOpRing, bAltered = 0;
2230
+
2231
+ /* -------------------------------------------------------------------- */
2232
+ /* Do nothing if this is not a polygon object. */
2233
+ /* -------------------------------------------------------------------- */
2234
+ if( psObject->nSHPType != SHPT_POLYGON
2235
+ && psObject->nSHPType != SHPT_POLYGONZ
2236
+ && psObject->nSHPType != SHPT_POLYGONM )
2237
+ return 0;
2238
+
2239
+ if( psObject->nVertices == 0 || psObject->nParts == 0 )
2240
+ return 0;
2241
+
2242
+ /* -------------------------------------------------------------------- */
2243
+ /* Process each of the rings. */
2244
+ /* -------------------------------------------------------------------- */
2245
+ for( iOpRing = 0; iOpRing < psObject->nParts; iOpRing++ )
2246
+ {
2247
+ int bInner, iVert, nVertCount, nVertStart, iCheckRing;
2248
+ double dfSum, dfTestX, dfTestY;
2249
+
2250
+ /* -------------------------------------------------------------------- */
2251
+ /* Determine if this ring is an inner ring or an outer ring */
2252
+ /* relative to all the other rings. For now we assume the */
2253
+ /* first ring is outer and all others are inner, but eventually */
2254
+ /* we need to fix this to handle multiple island polygons and */
2255
+ /* unordered sets of rings. */
2256
+ /* */
2257
+ /* -------------------------------------------------------------------- */
2258
+
2259
+ /* Use point in the middle of segment to avoid testing
2260
+ * common points of rings.
2261
+ */
2262
+ dfTestX = ( psObject->padfX[psObject->panPartStart[iOpRing]]
2263
+ + psObject->padfX[psObject->panPartStart[iOpRing] + 1] ) / 2;
2264
+ dfTestY = ( psObject->padfY[psObject->panPartStart[iOpRing]]
2265
+ + psObject->padfY[psObject->panPartStart[iOpRing] + 1] ) / 2;
2266
+
2267
+ bInner = FALSE;
2268
+ for( iCheckRing = 0; iCheckRing < psObject->nParts; iCheckRing++ )
2269
+ {
2270
+ int iEdge;
2271
+
2272
+ if( iCheckRing == iOpRing )
2273
+ continue;
2274
+
2275
+ nVertStart = psObject->panPartStart[iCheckRing];
2276
+
2277
+ if( iCheckRing == psObject->nParts-1 )
2278
+ nVertCount = psObject->nVertices
2279
+ - psObject->panPartStart[iCheckRing];
2280
+ else
2281
+ nVertCount = psObject->panPartStart[iCheckRing+1]
2282
+ - psObject->panPartStart[iCheckRing];
2283
+
2284
+ for( iEdge = 0; iEdge < nVertCount; iEdge++ )
2285
+ {
2286
+ int iNext;
2287
+
2288
+ if( iEdge < nVertCount-1 )
2289
+ iNext = iEdge+1;
2290
+ else
2291
+ iNext = 0;
2292
+
2293
+ /* Rule #1:
2294
+ * Test whether the edge 'straddles' the horizontal ray from the test point (dfTestY,dfTestY)
2295
+ * The rule #1 also excludes edges collinear with the ray.
2296
+ */
2297
+ if ( ( psObject->padfY[iEdge+nVertStart] < dfTestY
2298
+ && dfTestY <= psObject->padfY[iNext+nVertStart] )
2299
+ || ( psObject->padfY[iNext+nVertStart] < dfTestY
2300
+ && dfTestY <= psObject->padfY[iEdge+nVertStart] ) )
2301
+ {
2302
+ /* Rule #2:
2303
+ * Test if edge-ray intersection is on the right from the test point (dfTestY,dfTestY)
2304
+ */
2305
+ double const intersect =
2306
+ ( psObject->padfX[iEdge+nVertStart]
2307
+ + ( dfTestY - psObject->padfY[iEdge+nVertStart] )
2308
+ / ( psObject->padfY[iNext+nVertStart] - psObject->padfY[iEdge+nVertStart] )
2309
+ * ( psObject->padfX[iNext+nVertStart] - psObject->padfX[iEdge+nVertStart] ) );
2310
+
2311
+ if (intersect < dfTestX)
2312
+ {
2313
+ bInner = !bInner;
2314
+ }
2315
+ }
2316
+ }
2317
+ } /* for iCheckRing */
2318
+
2319
+ /* -------------------------------------------------------------------- */
2320
+ /* Determine the current order of this ring so we will know if */
2321
+ /* it has to be reversed. */
2322
+ /* -------------------------------------------------------------------- */
2323
+ nVertStart = psObject->panPartStart[iOpRing];
2324
+
2325
+ if( iOpRing == psObject->nParts-1 )
2326
+ nVertCount = psObject->nVertices - psObject->panPartStart[iOpRing];
2327
+ else
2328
+ nVertCount = psObject->panPartStart[iOpRing+1]
2329
+ - psObject->panPartStart[iOpRing];
2330
+
2331
+ if (nVertCount < 2)
2332
+ continue;
2333
+
2334
+ dfSum = psObject->padfX[nVertStart] * (psObject->padfY[nVertStart+1] - psObject->padfY[nVertStart+nVertCount-1]);
2335
+ for( iVert = nVertStart + 1; iVert < nVertStart+nVertCount-1; iVert++ )
2336
+ {
2337
+ dfSum += psObject->padfX[iVert] * (psObject->padfY[iVert+1] - psObject->padfY[iVert-1]);
2338
+ }
2339
+
2340
+ dfSum += psObject->padfX[iVert] * (psObject->padfY[nVertStart] - psObject->padfY[iVert-1]);
2341
+
2342
+ /* -------------------------------------------------------------------- */
2343
+ /* Reverse if necessary. */
2344
+ /* -------------------------------------------------------------------- */
2345
+ if( (dfSum < 0.0 && bInner) || (dfSum > 0.0 && !bInner) )
2346
+ {
2347
+ int i;
2348
+
2349
+ bAltered++;
2350
+ for( i = 0; i < nVertCount/2; i++ )
2351
+ {
2352
+ double dfSaved;
2353
+
2354
+ /* Swap X */
2355
+ dfSaved = psObject->padfX[nVertStart+i];
2356
+ psObject->padfX[nVertStart+i] =
2357
+ psObject->padfX[nVertStart+nVertCount-i-1];
2358
+ psObject->padfX[nVertStart+nVertCount-i-1] = dfSaved;
2359
+
2360
+ /* Swap Y */
2361
+ dfSaved = psObject->padfY[nVertStart+i];
2362
+ psObject->padfY[nVertStart+i] =
2363
+ psObject->padfY[nVertStart+nVertCount-i-1];
2364
+ psObject->padfY[nVertStart+nVertCount-i-1] = dfSaved;
2365
+
2366
+ /* Swap Z */
2367
+ if( psObject->padfZ )
2368
+ {
2369
+ dfSaved = psObject->padfZ[nVertStart+i];
2370
+ psObject->padfZ[nVertStart+i] =
2371
+ psObject->padfZ[nVertStart+nVertCount-i-1];
2372
+ psObject->padfZ[nVertStart+nVertCount-i-1] = dfSaved;
2373
+ }
2374
+
2375
+ /* Swap M */
2376
+ if( psObject->padfM )
2377
+ {
2378
+ dfSaved = psObject->padfM[nVertStart+i];
2379
+ psObject->padfM[nVertStart+i] =
2380
+ psObject->padfM[nVertStart+nVertCount-i-1];
2381
+ psObject->padfM[nVertStart+nVertCount-i-1] = dfSaved;
2382
+ }
2383
+ }
2384
+ }
2385
+ }
2386
+
2387
+ return bAltered;
2388
+ }