shp 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +34 -0
  3. data/.travis.yml +4 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE +28 -0
  6. data/README.md +30 -0
  7. data/Rakefile +23 -0
  8. data/ext/shp/base.hpp +113 -0
  9. data/ext/shp/dbf.cpp +381 -0
  10. data/ext/shp/dbf.hpp +44 -0
  11. data/ext/shp/extconf.rb +13 -0
  12. data/ext/shp/shape_object.cpp +58 -0
  13. data/ext/shp/shape_object.hpp +27 -0
  14. data/ext/shp/shapefile.cpp +299 -0
  15. data/ext/shp/shapefile.hpp +35 -0
  16. data/ext/shp/shapelib/.cvsignore +15 -0
  17. data/ext/shp/shapelib/ChangeLog +450 -0
  18. data/ext/shp/shapelib/HOWTO-RELEASE +16 -0
  19. data/ext/shp/shapelib/LICENSE.LGPL +483 -0
  20. data/ext/shp/shapelib/Makefile +113 -0
  21. data/ext/shp/shapelib/README +41 -0
  22. data/ext/shp/shapelib/README.tree +172 -0
  23. data/ext/shp/shapelib/contrib/.cvsignore +12 -0
  24. data/ext/shp/shapelib/contrib/Makefile +66 -0
  25. data/ext/shp/shapelib/contrib/ShapeFileII.pas +234 -0
  26. data/ext/shp/shapelib/contrib/Shape_PointInPoly.cpp +238 -0
  27. data/ext/shp/shapelib/contrib/Shape_PointInPoly_README.txt +59 -0
  28. data/ext/shp/shapelib/contrib/csv2shp.c +558 -0
  29. data/ext/shp/shapelib/contrib/dbfcat.c +166 -0
  30. data/ext/shp/shapelib/contrib/dbfinfo.c +106 -0
  31. data/ext/shp/shapelib/contrib/makefile.vc +34 -0
  32. data/ext/shp/shapelib/contrib/my_nan.h +46 -0
  33. data/ext/shp/shapelib/contrib/shpcat.c +100 -0
  34. data/ext/shp/shapelib/contrib/shpcentrd.c +159 -0
  35. data/ext/shp/shapelib/contrib/shpdata.c +129 -0
  36. data/ext/shp/shapelib/contrib/shpdxf.c +340 -0
  37. data/ext/shp/shapelib/contrib/shpfix.c +110 -0
  38. data/ext/shp/shapelib/contrib/shpgeo.c +1595 -0
  39. data/ext/shp/shapelib/contrib/shpgeo.h +154 -0
  40. data/ext/shp/shapelib/contrib/shpinfo.c +113 -0
  41. data/ext/shp/shapelib/contrib/shpproj.c +260 -0
  42. data/ext/shp/shapelib/contrib/shpsort.c +605 -0
  43. data/ext/shp/shapelib/contrib/shpsort.txt +44 -0
  44. data/ext/shp/shapelib/contrib/shpwkb.c +123 -0
  45. data/ext/shp/shapelib/contrib/tests/shpproj.sh +38 -0
  46. data/ext/shp/shapelib/dbfopen.c +2221 -0
  47. data/ext/shp/shapelib/makefile.vc +86 -0
  48. data/ext/shp/shapelib/makeshape.sh +21 -0
  49. data/ext/shp/shapelib/mkdist.sh +37 -0
  50. data/ext/shp/shapelib/mkinstalldirs +38 -0
  51. data/ext/shp/shapelib/mkrelease.sh +55 -0
  52. data/ext/shp/shapelib/safileio.c +286 -0
  53. data/ext/shp/shapelib/shapefil.h +647 -0
  54. data/ext/shp/shapelib/shapelib.def +46 -0
  55. data/ext/shp/shapelib/shpopen.c +2388 -0
  56. data/ext/shp/shapelib/shptree.c +1187 -0
  57. data/ext/shp/shapelib/shputils.c +1072 -0
  58. data/ext/shp/shapelib/stream1.out +1465 -0
  59. data/ext/shp/shapelib/stream1.sh +28 -0
  60. data/ext/shp/shapelib/stream2.out +530 -0
  61. data/ext/shp/shapelib/stream2.sh +11 -0
  62. data/ext/shp/shapelib/stream3.out +37 -0
  63. data/ext/shp/shapelib/web/.cvsignore +2 -0
  64. data/ext/shp/shapelib/web/codepage.html +403 -0
  65. data/ext/shp/shapelib/web/dbf_api.html +436 -0
  66. data/ext/shp/shapelib/web/index.html +235 -0
  67. data/ext/shp/shapelib/web/license.html +78 -0
  68. data/ext/shp/shapelib/web/manifest.html +87 -0
  69. data/ext/shp/shapelib/web/release.html +80 -0
  70. data/ext/shp/shapelib/web/shapelib-tools.html +352 -0
  71. data/ext/shp/shapelib/web/shp_api.html +376 -0
  72. data/ext/shp/shp.cpp +19 -0
  73. data/ext/shp/shp.hpp +47 -0
  74. data/lib/shp.rb +35 -0
  75. data/lib/shp/version.rb +3 -0
  76. data/shp.gemspec +23 -0
  77. data/spec/shp_spec.rb +127 -0
  78. metadata +176 -0
@@ -0,0 +1,46 @@
1
+ LIBRARY shapelib
2
+ EXPORTS SHPOpen
3
+ SHPCreate
4
+ SHPGetInfo
5
+ SHPReadObject
6
+ SHPWriteObject
7
+ SHPDestroyObject
8
+ SHPComputeExtents
9
+ SHPCreateObject
10
+ SHPCreateSimpleObject
11
+ SHPClose
12
+ SHPWriteHeader
13
+ SHPTypeName
14
+ SHPPartTypeName
15
+ SHPCreateTree
16
+ SHPDestroyTree
17
+ SHPTreeAddShapeId
18
+ SHPTreeTrimExtraNodes
19
+ SHPTreeFindLikelyShapes
20
+ SHPCheckBoundsOverlap
21
+ DBFOpen
22
+ DBFCreate
23
+ DBFGetFieldCount
24
+ DBFGetRecordCount
25
+ DBFAddField
26
+ DBFGetFieldInfo
27
+ DBFReadIntegerAttribute
28
+ DBFReadDoubleAttribute
29
+ DBFReadStringAttribute
30
+ DBFWriteIntegerAttribute
31
+ DBFWriteDoubleAttribute
32
+ DBFWriteStringAttribute
33
+ DBFReadTuple
34
+ DBFWriteTuple
35
+ DBFCloneEmpty
36
+ DBFClose
37
+ DBFWriteNULLAttribute
38
+ DBFGetFieldIndex
39
+ DBFIsAttributeNULL
40
+ DBFWriteLogicalAttribute
41
+ DBFReadLogicalAttribute
42
+ DBFUpdateHeader
43
+ DBFGetNativeFieldType
44
+ SHPRewindObject
45
+ DBFIsRecordDeleted
46
+ DBFMarkRecordDeleted
@@ -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
+ }