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.
- checksums.yaml +15 -0
- data/.gitignore +34 -0
- data/.travis.yml +4 -0
- data/Gemfile +3 -0
- data/LICENSE +28 -0
- data/README.md +30 -0
- data/Rakefile +23 -0
- data/ext/shp/base.hpp +113 -0
- data/ext/shp/dbf.cpp +381 -0
- data/ext/shp/dbf.hpp +44 -0
- data/ext/shp/extconf.rb +13 -0
- data/ext/shp/shape_object.cpp +58 -0
- data/ext/shp/shape_object.hpp +27 -0
- data/ext/shp/shapefile.cpp +299 -0
- data/ext/shp/shapefile.hpp +35 -0
- data/ext/shp/shapelib/.cvsignore +15 -0
- data/ext/shp/shapelib/ChangeLog +450 -0
- data/ext/shp/shapelib/HOWTO-RELEASE +16 -0
- data/ext/shp/shapelib/LICENSE.LGPL +483 -0
- data/ext/shp/shapelib/Makefile +113 -0
- data/ext/shp/shapelib/README +41 -0
- data/ext/shp/shapelib/README.tree +172 -0
- data/ext/shp/shapelib/contrib/.cvsignore +12 -0
- data/ext/shp/shapelib/contrib/Makefile +66 -0
- data/ext/shp/shapelib/contrib/ShapeFileII.pas +234 -0
- data/ext/shp/shapelib/contrib/Shape_PointInPoly.cpp +238 -0
- data/ext/shp/shapelib/contrib/Shape_PointInPoly_README.txt +59 -0
- data/ext/shp/shapelib/contrib/csv2shp.c +558 -0
- data/ext/shp/shapelib/contrib/dbfcat.c +166 -0
- data/ext/shp/shapelib/contrib/dbfinfo.c +106 -0
- data/ext/shp/shapelib/contrib/makefile.vc +34 -0
- data/ext/shp/shapelib/contrib/my_nan.h +46 -0
- data/ext/shp/shapelib/contrib/shpcat.c +100 -0
- data/ext/shp/shapelib/contrib/shpcentrd.c +159 -0
- data/ext/shp/shapelib/contrib/shpdata.c +129 -0
- data/ext/shp/shapelib/contrib/shpdxf.c +340 -0
- data/ext/shp/shapelib/contrib/shpfix.c +110 -0
- data/ext/shp/shapelib/contrib/shpgeo.c +1595 -0
- data/ext/shp/shapelib/contrib/shpgeo.h +154 -0
- data/ext/shp/shapelib/contrib/shpinfo.c +113 -0
- data/ext/shp/shapelib/contrib/shpproj.c +260 -0
- data/ext/shp/shapelib/contrib/shpsort.c +605 -0
- data/ext/shp/shapelib/contrib/shpsort.txt +44 -0
- data/ext/shp/shapelib/contrib/shpwkb.c +123 -0
- data/ext/shp/shapelib/contrib/tests/shpproj.sh +38 -0
- data/ext/shp/shapelib/dbfopen.c +2221 -0
- data/ext/shp/shapelib/makefile.vc +86 -0
- data/ext/shp/shapelib/makeshape.sh +21 -0
- data/ext/shp/shapelib/mkdist.sh +37 -0
- data/ext/shp/shapelib/mkinstalldirs +38 -0
- data/ext/shp/shapelib/mkrelease.sh +55 -0
- data/ext/shp/shapelib/safileio.c +286 -0
- data/ext/shp/shapelib/shapefil.h +647 -0
- data/ext/shp/shapelib/shapelib.def +46 -0
- data/ext/shp/shapelib/shpopen.c +2388 -0
- data/ext/shp/shapelib/shptree.c +1187 -0
- data/ext/shp/shapelib/shputils.c +1072 -0
- data/ext/shp/shapelib/stream1.out +1465 -0
- data/ext/shp/shapelib/stream1.sh +28 -0
- data/ext/shp/shapelib/stream2.out +530 -0
- data/ext/shp/shapelib/stream2.sh +11 -0
- data/ext/shp/shapelib/stream3.out +37 -0
- data/ext/shp/shapelib/web/.cvsignore +2 -0
- data/ext/shp/shapelib/web/codepage.html +403 -0
- data/ext/shp/shapelib/web/dbf_api.html +436 -0
- data/ext/shp/shapelib/web/index.html +235 -0
- data/ext/shp/shapelib/web/license.html +78 -0
- data/ext/shp/shapelib/web/manifest.html +87 -0
- data/ext/shp/shapelib/web/release.html +80 -0
- data/ext/shp/shapelib/web/shapelib-tools.html +352 -0
- data/ext/shp/shapelib/web/shp_api.html +376 -0
- data/ext/shp/shp.cpp +19 -0
- data/ext/shp/shp.hpp +47 -0
- data/lib/shp.rb +35 -0
- data/lib/shp/version.rb +3 -0
- data/shp.gemspec +23 -0
- data/spec/shp_spec.rb +127 -0
- 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
|
+
}
|