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 256340 : static void SwapWord( int length, void * wordP )
313 :
314 : {
315 : int i;
316 : uchar temp;
317 :
318 769020 : for( i=0; i < length/2; i++ )
319 : {
320 512680 : temp = ((uchar *) wordP)[i];
321 512680 : ((uchar *)wordP)[i] = ((uchar *) wordP)[length-i-1];
322 512680 : ((uchar *) wordP)[length-i-1] = temp;
323 : }
324 256340 : }
325 :
326 : /************************************************************************/
327 : /* SfRealloc() */
328 : /* */
329 : /* A realloc cover function that will access a NULL pointer as */
330 : /* a valid input. */
331 : /************************************************************************/
332 :
333 4455 : static void * SfRealloc( void * pMem, int nNewSize )
334 :
335 : {
336 4455 : if( pMem == NULL )
337 1435 : return( (void *) malloc(nNewSize) );
338 : else
339 3020 : 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 1252 : 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 1252 : if (psSHP->fpSHX == NULL)
359 : {
360 0 : psSHP->sHooks.Error( "SHPWriteHeader failed : SHX file is closed");
361 0 : return;
362 : }
363 :
364 : /* -------------------------------------------------------------------- */
365 : /* Prepare header block for .shp file. */
366 : /* -------------------------------------------------------------------- */
367 126452 : for( i = 0; i < 100; i++ )
368 125200 : abyHeader[i] = 0;
369 :
370 1252 : abyHeader[2] = 0x27; /* magic cookie */
371 1252 : abyHeader[3] = 0x0a;
372 :
373 1252 : i32 = psSHP->nFileSize/2; /* file size */
374 1252 : ByteCopy( &i32, abyHeader+24, 4 );
375 1252 : if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
376 :
377 1252 : i32 = 1000; /* version */
378 1252 : ByteCopy( &i32, abyHeader+28, 4 );
379 1252 : if( bBigEndian ) SwapWord( 4, abyHeader+28 );
380 :
381 1252 : i32 = psSHP->nShapeType; /* shape type */
382 1252 : ByteCopy( &i32, abyHeader+32, 4 );
383 1252 : if( bBigEndian ) SwapWord( 4, abyHeader+32 );
384 :
385 1252 : dValue = psSHP->adBoundsMin[0]; /* set bounds */
386 1252 : ByteCopy( &dValue, abyHeader+36, 8 );
387 1252 : if( bBigEndian ) SwapWord( 8, abyHeader+36 );
388 :
389 1252 : dValue = psSHP->adBoundsMin[1];
390 1252 : ByteCopy( &dValue, abyHeader+44, 8 );
391 1252 : if( bBigEndian ) SwapWord( 8, abyHeader+44 );
392 :
393 1252 : dValue = psSHP->adBoundsMax[0];
394 1252 : ByteCopy( &dValue, abyHeader+52, 8 );
395 1252 : if( bBigEndian ) SwapWord( 8, abyHeader+52 );
396 :
397 1252 : dValue = psSHP->adBoundsMax[1];
398 1252 : ByteCopy( &dValue, abyHeader+60, 8 );
399 1252 : if( bBigEndian ) SwapWord( 8, abyHeader+60 );
400 :
401 1252 : dValue = psSHP->adBoundsMin[2]; /* z */
402 1252 : ByteCopy( &dValue, abyHeader+68, 8 );
403 1252 : if( bBigEndian ) SwapWord( 8, abyHeader+68 );
404 :
405 1252 : dValue = psSHP->adBoundsMax[2];
406 1252 : ByteCopy( &dValue, abyHeader+76, 8 );
407 1252 : if( bBigEndian ) SwapWord( 8, abyHeader+76 );
408 :
409 1252 : dValue = psSHP->adBoundsMin[3]; /* m */
410 1252 : ByteCopy( &dValue, abyHeader+84, 8 );
411 1252 : if( bBigEndian ) SwapWord( 8, abyHeader+84 );
412 :
413 1252 : dValue = psSHP->adBoundsMax[3];
414 1252 : ByteCopy( &dValue, abyHeader+92, 8 );
415 1252 : if( bBigEndian ) SwapWord( 8, abyHeader+92 );
416 :
417 : /* -------------------------------------------------------------------- */
418 : /* Write .shp file header. */
419 : /* -------------------------------------------------------------------- */
420 2504 : if( psSHP->sHooks.FSeek( psSHP->fpSHP, 0, 0 ) != 0
421 2504 : || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHP ) != 1 )
422 : {
423 0 : psSHP->sHooks.Error( "Failure writing .shp header" );
424 0 : return;
425 : }
426 :
427 : /* -------------------------------------------------------------------- */
428 : /* Prepare, and write .shx file header. */
429 : /* -------------------------------------------------------------------- */
430 1252 : i32 = (psSHP->nRecords * 2 * sizeof(int32) + 100)/2; /* file size */
431 1252 : ByteCopy( &i32, abyHeader+24, 4 );
432 1252 : if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
433 :
434 2504 : if( psSHP->sHooks.FSeek( psSHP->fpSHX, 0, 0 ) != 0
435 2504 : || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHX ) != 1 )
436 : {
437 0 : psSHP->sHooks.Error( "Failure writing .shx header" );
438 0 : return;
439 : }
440 :
441 : /* -------------------------------------------------------------------- */
442 : /* Write out the .shx contents. */
443 : /* -------------------------------------------------------------------- */
444 1252 : panSHX = (int32 *) malloc(sizeof(int32) * 2 * psSHP->nRecords);
445 :
446 58220 : for( i = 0; i < psSHP->nRecords; i++ )
447 : {
448 56968 : panSHX[i*2 ] = psSHP->panRecOffset[i]/2;
449 56968 : panSHX[i*2+1] = psSHP->panRecSize[i]/2;
450 56968 : if( !bBigEndian ) SwapWord( 4, panSHX+i*2 );
451 56968 : if( !bBigEndian ) SwapWord( 4, panSHX+i*2+1 );
452 : }
453 :
454 1252 : if( (int)psSHP->sHooks.FWrite( panSHX, sizeof(int32)*2, psSHP->nRecords, psSHP->fpSHX )
455 : != psSHP->nRecords )
456 : {
457 0 : psSHP->sHooks.Error( "Failure writing .shx contents" );
458 : }
459 :
460 1252 : free( panSHX );
461 :
462 : /* -------------------------------------------------------------------- */
463 : /* Flush to disk. */
464 : /* -------------------------------------------------------------------- */
465 1252 : psSHP->sHooks.FFlush( psSHP->fpSHP );
466 1252 : psSHP->sHooks.FFlush( psSHP->fpSHX );
467 : }
468 :
469 : /************************************************************************/
470 : /* SHPOpen() */
471 : /************************************************************************/
472 :
473 : SHPHandle SHPAPI_CALL
474 2699 : SHPOpen( const char * pszLayer, const char * pszAccess )
475 :
476 : {
477 : SAHooks sHooks;
478 :
479 2699 : SASetupDefaultHooks( &sHooks );
480 :
481 2699 : 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 3916 : 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 13462 : if( strcmp(pszAccess,"rb+") == 0 || strcmp(pszAccess,"r+b") == 0
508 6615 : || strcmp(pszAccess,"r+") == 0 )
509 2931 : pszAccess = "r+b";
510 : else
511 985 : pszAccess = "rb";
512 :
513 : /* -------------------------------------------------------------------- */
514 : /* Establish the byte order on this machine. */
515 : /* -------------------------------------------------------------------- */
516 3916 : i = 1;
517 3916 : if( *((uchar *) &i) == 1 )
518 3916 : bBigEndian = FALSE;
519 : else
520 0 : bBigEndian = TRUE;
521 :
522 : /* -------------------------------------------------------------------- */
523 : /* Initialize the info structure. */
524 : /* -------------------------------------------------------------------- */
525 3916 : psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1);
526 :
527 3916 : psSHP->bUpdated = FALSE;
528 3916 : 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 3916 : pszBasename = (char *) malloc(strlen(pszLayer)+5);
535 3916 : strcpy( pszBasename, pszLayer );
536 58740 : for( i = strlen(pszBasename)-1;
537 43076 : i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
538 11748 : && pszBasename[i] != '\\';
539 11748 : i-- ) {}
540 :
541 3916 : if( pszBasename[i] == '.' )
542 3916 : 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 3916 : pszFullname = (char *) malloc(strlen(pszBasename) + 5);
549 3916 : sprintf( pszFullname, "%s.shp", pszBasename ) ;
550 3916 : psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
551 3916 : if( psSHP->fpSHP == NULL )
552 : {
553 37 : sprintf( pszFullname, "%s.SHP", pszBasename );
554 37 : psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
555 : }
556 :
557 3916 : if( psSHP->fpSHP == NULL )
558 : {
559 35 : char *pszMessage = (char *) malloc(strlen(pszBasename)*2+256);
560 35 : sprintf( pszMessage, "Unable to open %s.shp or %s.SHP.",
561 : pszBasename, pszBasename );
562 35 : psHooks->Error( pszMessage );
563 35 : free( pszMessage );
564 :
565 35 : free( psSHP );
566 35 : free( pszBasename );
567 35 : free( pszFullname );
568 :
569 35 : return NULL;
570 : }
571 :
572 3881 : sprintf( pszFullname, "%s.shx", pszBasename );
573 3881 : psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess );
574 3881 : if( psSHP->fpSHX == NULL )
575 : {
576 2 : sprintf( pszFullname, "%s.SHX", pszBasename );
577 2 : psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess );
578 : }
579 :
580 3881 : if( psSHP->fpSHX == NULL )
581 : {
582 0 : char *pszMessage = (char *) malloc(strlen(pszBasename)*2+256);
583 0 : sprintf( pszMessage, "Unable to open %s.shx or %s.SHX.",
584 : pszBasename, pszBasename );
585 0 : psHooks->Error( pszMessage );
586 0 : free( pszMessage );
587 :
588 0 : psSHP->sHooks.FClose( psSHP->fpSHP );
589 0 : free( psSHP );
590 0 : free( pszBasename );
591 0 : free( pszFullname );
592 0 : return( NULL );
593 : }
594 :
595 3881 : free( pszFullname );
596 3881 : free( pszBasename );
597 :
598 : /* -------------------------------------------------------------------- */
599 : /* Read the file size from the SHP file. */
600 : /* -------------------------------------------------------------------- */
601 3881 : pabyBuf = (uchar *) malloc(100);
602 3881 : psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHP );
603 :
604 7762 : psSHP->nFileSize = ((unsigned int)pabyBuf[24] * 256 * 256 * 256
605 3881 : + (unsigned int)pabyBuf[25] * 256 * 256
606 3881 : + (unsigned int)pabyBuf[26] * 256
607 11643 : + (unsigned int)pabyBuf[27]) * 2;
608 :
609 : /* -------------------------------------------------------------------- */
610 : /* Read SHX file Header info */
611 : /* -------------------------------------------------------------------- */
612 19405 : if( psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHX ) != 1
613 7762 : || pabyBuf[0] != 0
614 3881 : || pabyBuf[1] != 0
615 3881 : || pabyBuf[2] != 0x27
616 3881 : || (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d) )
617 : {
618 0 : psSHP->sHooks.Error( ".shx file is unreadable, or corrupt." );
619 0 : psSHP->sHooks.FClose( psSHP->fpSHP );
620 0 : psSHP->sHooks.FClose( psSHP->fpSHX );
621 0 : free( psSHP );
622 :
623 0 : return( NULL );
624 : }
625 :
626 11643 : psSHP->nRecords = pabyBuf[27] + pabyBuf[26] * 256
627 7762 : + pabyBuf[25] * 256 * 256 + pabyBuf[24] * 256 * 256 * 256;
628 3881 : psSHP->nRecords = (psSHP->nRecords*2 - 100) / 8;
629 :
630 3881 : psSHP->nShapeType = pabyBuf[32];
631 :
632 3881 : if( psSHP->nRecords < 0 || psSHP->nRecords > 256000000 )
633 : {
634 : char szError[200];
635 :
636 0 : sprintf( szError,
637 : "Record count in .shp header is %d, which seems\n"
638 : "unreasonable. Assuming header is corrupt.",
639 : psSHP->nRecords );
640 0 : psSHP->sHooks.Error( szError );
641 0 : psSHP->sHooks.FClose( psSHP->fpSHP );
642 0 : psSHP->sHooks.FClose( psSHP->fpSHX );
643 0 : free( psSHP );
644 0 : free(pabyBuf);
645 :
646 0 : return( NULL );
647 : }
648 :
649 : /* -------------------------------------------------------------------- */
650 : /* Read the bounds. */
651 : /* -------------------------------------------------------------------- */
652 3881 : if( bBigEndian ) SwapWord( 8, pabyBuf+36 );
653 3881 : memcpy( &dValue, pabyBuf+36, 8 );
654 3881 : psSHP->adBoundsMin[0] = dValue;
655 :
656 3881 : if( bBigEndian ) SwapWord( 8, pabyBuf+44 );
657 3881 : memcpy( &dValue, pabyBuf+44, 8 );
658 3881 : psSHP->adBoundsMin[1] = dValue;
659 :
660 3881 : if( bBigEndian ) SwapWord( 8, pabyBuf+52 );
661 3881 : memcpy( &dValue, pabyBuf+52, 8 );
662 3881 : psSHP->adBoundsMax[0] = dValue;
663 :
664 3881 : if( bBigEndian ) SwapWord( 8, pabyBuf+60 );
665 3881 : memcpy( &dValue, pabyBuf+60, 8 );
666 3881 : psSHP->adBoundsMax[1] = dValue;
667 :
668 3881 : if( bBigEndian ) SwapWord( 8, pabyBuf+68 ); /* z */
669 3881 : memcpy( &dValue, pabyBuf+68, 8 );
670 3881 : psSHP->adBoundsMin[2] = dValue;
671 :
672 3881 : if( bBigEndian ) SwapWord( 8, pabyBuf+76 );
673 3881 : memcpy( &dValue, pabyBuf+76, 8 );
674 3881 : psSHP->adBoundsMax[2] = dValue;
675 :
676 3881 : if( bBigEndian ) SwapWord( 8, pabyBuf+84 ); /* z */
677 3881 : memcpy( &dValue, pabyBuf+84, 8 );
678 3881 : psSHP->adBoundsMin[3] = dValue;
679 :
680 3881 : if( bBigEndian ) SwapWord( 8, pabyBuf+92 );
681 3881 : memcpy( &dValue, pabyBuf+92, 8 );
682 3881 : psSHP->adBoundsMax[3] = dValue;
683 :
684 3881 : free( pabyBuf );
685 :
686 : /* -------------------------------------------------------------------- */
687 : /* Read the .shx file to get the offsets to each record in */
688 : /* the .shp file. */
689 : /* -------------------------------------------------------------------- */
690 3881 : psSHP->nMaxRecords = psSHP->nRecords;
691 :
692 3881 : psSHP->panRecOffset = (unsigned int *)
693 : malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
694 3881 : psSHP->panRecSize = (unsigned int *)
695 : malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
696 3881 : pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) );
697 :
698 7762 : if (psSHP->panRecOffset == NULL ||
699 3881 : psSHP->panRecSize == NULL ||
700 : pabyBuf == NULL)
701 : {
702 : char szError[200];
703 :
704 0 : sprintf(szError,
705 : "Not enough memory to allocate requested memory (nRecords=%d).\n"
706 : "Probably broken SHP file",
707 : psSHP->nRecords );
708 0 : psSHP->sHooks.Error( szError );
709 0 : psSHP->sHooks.FClose( psSHP->fpSHP );
710 0 : psSHP->sHooks.FClose( psSHP->fpSHX );
711 0 : if (psSHP->panRecOffset) free( psSHP->panRecOffset );
712 0 : if (psSHP->panRecSize) free( psSHP->panRecSize );
713 0 : if (pabyBuf) free( pabyBuf );
714 0 : free( psSHP );
715 0 : return( NULL );
716 : }
717 :
718 3881 : if( (int) psSHP->sHooks.FRead( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX )
719 : != psSHP->nRecords )
720 : {
721 : char szError[200];
722 :
723 0 : sprintf( szError,
724 : "Failed to read all values for %d records in .shx file.",
725 : psSHP->nRecords );
726 0 : psSHP->sHooks.Error( szError );
727 :
728 : /* SHX is short or unreadable for some reason. */
729 0 : psSHP->sHooks.FClose( psSHP->fpSHP );
730 0 : psSHP->sHooks.FClose( psSHP->fpSHX );
731 0 : free( psSHP->panRecOffset );
732 0 : free( psSHP->panRecSize );
733 0 : free( pabyBuf );
734 0 : free( psSHP );
735 :
736 0 : return( NULL );
737 : }
738 :
739 : /* In read-only mode, we can close the SHX now */
740 3881 : if (strcmp(pszAccess, "rb") == 0)
741 : {
742 955 : psSHP->sHooks.FClose( psSHP->fpSHX );
743 955 : psSHP->fpSHX = NULL;
744 : }
745 :
746 42926 : for( i = 0; i < psSHP->nRecords; i++ )
747 : {
748 : int32 nOffset, nLength;
749 :
750 39045 : memcpy( &nOffset, pabyBuf + i * 8, 4 );
751 39045 : if( !bBigEndian ) SwapWord( 4, &nOffset );
752 :
753 39045 : memcpy( &nLength, pabyBuf + i * 8 + 4, 4 );
754 39045 : if( !bBigEndian ) SwapWord( 4, &nLength );
755 :
756 39045 : psSHP->panRecOffset[i] = nOffset*2;
757 39045 : psSHP->panRecSize[i] = nLength*2;
758 : }
759 3881 : free( pabyBuf );
760 :
761 3881 : return( psSHP );
762 : }
763 :
764 : /************************************************************************/
765 : /* SHPClose() */
766 : /* */
767 : /* Close the .shp and .shx files. */
768 : /************************************************************************/
769 :
770 : void SHPAPI_CALL
771 3882 : SHPClose(SHPHandle psSHP )
772 :
773 : {
774 3882 : if( psSHP == NULL )
775 1 : return;
776 :
777 : /* -------------------------------------------------------------------- */
778 : /* Update the header if we have modified anything. */
779 : /* -------------------------------------------------------------------- */
780 3881 : if( psSHP->bUpdated )
781 1229 : SHPWriteHeader( psSHP );
782 :
783 : /* -------------------------------------------------------------------- */
784 : /* Free all resources, and close files. */
785 : /* -------------------------------------------------------------------- */
786 3881 : free( psSHP->panRecOffset );
787 3881 : free( psSHP->panRecSize );
788 :
789 3881 : if ( psSHP->fpSHX != NULL)
790 2926 : psSHP->sHooks.FClose( psSHP->fpSHX );
791 3881 : psSHP->sHooks.FClose( psSHP->fpSHP );
792 :
793 3881 : if( psSHP->pabyRec != NULL )
794 : {
795 1435 : free( psSHP->pabyRec );
796 : }
797 :
798 3881 : free( psSHP );
799 : }
800 :
801 : /************************************************************************/
802 : /* SHPGetInfo() */
803 : /* */
804 : /* Fetch general information about the shape file. */
805 : /************************************************************************/
806 :
807 : void SHPAPI_CALL
808 17699 : SHPGetInfo(SHPHandle psSHP, int * pnEntities, int * pnShapeType,
809 : double * padfMinBound, double * padfMaxBound )
810 :
811 : {
812 : int i;
813 :
814 17699 : if( psSHP == NULL )
815 0 : return;
816 :
817 17699 : if( pnEntities != NULL )
818 28 : *pnEntities = psSHP->nRecords;
819 :
820 17699 : if( pnShapeType != NULL )
821 0 : *pnShapeType = psSHP->nShapeType;
822 :
823 88495 : for( i = 0; i < 4; i++ )
824 : {
825 70796 : if( padfMinBound != NULL )
826 70684 : padfMinBound[i] = psSHP->adBoundsMin[i];
827 70796 : if( padfMaxBound != NULL )
828 70684 : 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 1218 : SHPCreate( const char * pszLayer, int nShapeType )
841 :
842 : {
843 : SAHooks sHooks;
844 :
845 1218 : SASetupDefaultHooks( &sHooks );
846 :
847 1218 : 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 1218 : SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
859 :
860 : {
861 1218 : char *pszBasename = NULL, *pszFullname = NULL;
862 : int i;
863 1218 : 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 1218 : i = 1;
872 1218 : if( *((uchar *) &i) == 1 )
873 1218 : bBigEndian = FALSE;
874 : else
875 0 : 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 1218 : pszBasename = (char *) malloc(strlen(pszLayer)+5);
882 1218 : strcpy( pszBasename, pszLayer );
883 18270 : for( i = strlen(pszBasename)-1;
884 13398 : i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
885 3654 : && pszBasename[i] != '\\';
886 3654 : i-- ) {}
887 :
888 1218 : if( pszBasename[i] == '.' )
889 1218 : pszBasename[i] = '\0';
890 :
891 : /* -------------------------------------------------------------------- */
892 : /* Open the two files so we can write their headers. */
893 : /* -------------------------------------------------------------------- */
894 1218 : pszFullname = (char *) malloc(strlen(pszBasename) + 5);
895 1218 : sprintf( pszFullname, "%s.shp", pszBasename );
896 1218 : fpSHP = psHooks->FOpen(pszFullname, "wb" );
897 1218 : if( fpSHP == NULL )
898 : {
899 1 : psHooks->Error( "Failed to create file .shp file." );
900 1 : goto error;
901 : }
902 :
903 1217 : sprintf( pszFullname, "%s.shx", pszBasename );
904 1217 : fpSHX = psHooks->FOpen(pszFullname, "wb" );
905 1217 : if( fpSHX == NULL )
906 : {
907 0 : psHooks->Error( "Failed to create file .shx file." );
908 0 : goto error;
909 : }
910 :
911 1217 : free( pszFullname ); pszFullname = NULL;
912 1217 : free( pszBasename ); pszBasename = NULL;
913 :
914 : /* -------------------------------------------------------------------- */
915 : /* Prepare header block for .shp file. */
916 : /* -------------------------------------------------------------------- */
917 122917 : for( i = 0; i < 100; i++ )
918 121700 : abyHeader[i] = 0;
919 :
920 1217 : abyHeader[2] = 0x27; /* magic cookie */
921 1217 : abyHeader[3] = 0x0a;
922 :
923 1217 : i32 = 50; /* file size */
924 1217 : ByteCopy( &i32, abyHeader+24, 4 );
925 1217 : if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
926 :
927 1217 : i32 = 1000; /* version */
928 1217 : ByteCopy( &i32, abyHeader+28, 4 );
929 1217 : if( bBigEndian ) SwapWord( 4, abyHeader+28 );
930 :
931 1217 : i32 = nShapeType; /* shape type */
932 1217 : ByteCopy( &i32, abyHeader+32, 4 );
933 1217 : if( bBigEndian ) SwapWord( 4, abyHeader+32 );
934 :
935 1217 : dValue = 0.0; /* set bounds */
936 1217 : ByteCopy( &dValue, abyHeader+36, 8 );
937 1217 : ByteCopy( &dValue, abyHeader+44, 8 );
938 1217 : ByteCopy( &dValue, abyHeader+52, 8 );
939 1217 : ByteCopy( &dValue, abyHeader+60, 8 );
940 :
941 : /* -------------------------------------------------------------------- */
942 : /* Write .shp file header. */
943 : /* -------------------------------------------------------------------- */
944 1217 : if( psHooks->FWrite( abyHeader, 100, 1, fpSHP ) != 1 )
945 : {
946 0 : psHooks->Error( "Failed to write .shp header." );
947 0 : goto error;
948 : }
949 :
950 : /* -------------------------------------------------------------------- */
951 : /* Prepare, and write .shx file header. */
952 : /* -------------------------------------------------------------------- */
953 1217 : i32 = 50; /* file size */
954 1217 : ByteCopy( &i32, abyHeader+24, 4 );
955 1217 : if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
956 :
957 1217 : if( psHooks->FWrite( abyHeader, 100, 1, fpSHX ) != 1 )
958 : {
959 0 : psHooks->Error( "Failed to write .shx header." );
960 0 : goto error;
961 : }
962 :
963 : /* -------------------------------------------------------------------- */
964 : /* Close the files, and then open them as regular existing files. */
965 : /* -------------------------------------------------------------------- */
966 1217 : psHooks->FClose( fpSHP );
967 1217 : psHooks->FClose( fpSHX );
968 :
969 1217 : return( SHPOpenLL( pszLayer, "r+b", psHooks ) );
970 :
971 : error:
972 1 : if (pszFullname) free(pszFullname);
973 1 : if (pszBasename) free(pszBasename);
974 1 : if (fpSHP) psHooks->FClose( fpSHP );
975 1 : if (fpSHX) psHooks->FClose( fpSHX );
976 1 : 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 13881 : static void _SHPSetBounds( uchar * pabyRec, SHPObject * psShape )
987 :
988 : {
989 13881 : ByteCopy( &(psShape->dfXMin), pabyRec + 0, 8 );
990 13881 : ByteCopy( &(psShape->dfYMin), pabyRec + 8, 8 );
991 13881 : ByteCopy( &(psShape->dfXMax), pabyRec + 16, 8 );
992 13881 : ByteCopy( &(psShape->dfYMax), pabyRec + 24, 8 );
993 :
994 13881 : if( bBigEndian )
995 : {
996 0 : SwapWord( 8, pabyRec + 0 );
997 0 : SwapWord( 8, pabyRec + 8 );
998 0 : SwapWord( 8, pabyRec + 16 );
999 0 : SwapWord( 8, pabyRec + 24 );
1000 : }
1001 13881 : }
1002 :
1003 : /************************************************************************/
1004 : /* SHPComputeExtents() */
1005 : /* */
1006 : /* Recompute the extents of a shape. Automatically done by */
1007 : /* SHPCreateObject(). */
1008 : /************************************************************************/
1009 :
1010 : void SHPAPI_CALL
1011 29660 : SHPComputeExtents( SHPObject * psObject )
1012 :
1013 : {
1014 : int i;
1015 :
1016 : /* -------------------------------------------------------------------- */
1017 : /* Build extents for this object. */
1018 : /* -------------------------------------------------------------------- */
1019 29660 : if( psObject->nVertices > 0 )
1020 : {
1021 29118 : psObject->dfXMin = psObject->dfXMax = psObject->padfX[0];
1022 29118 : psObject->dfYMin = psObject->dfYMax = psObject->padfY[0];
1023 29118 : psObject->dfZMin = psObject->dfZMax = psObject->padfZ[0];
1024 29118 : psObject->dfMMin = psObject->dfMMax = psObject->padfM[0];
1025 : }
1026 :
1027 144109 : for( i = 0; i < psObject->nVertices; i++ )
1028 : {
1029 114449 : psObject->dfXMin = MIN(psObject->dfXMin, psObject->padfX[i]);
1030 114449 : psObject->dfYMin = MIN(psObject->dfYMin, psObject->padfY[i]);
1031 114449 : psObject->dfZMin = MIN(psObject->dfZMin, psObject->padfZ[i]);
1032 114449 : psObject->dfMMin = MIN(psObject->dfMMin, psObject->padfM[i]);
1033 :
1034 114449 : psObject->dfXMax = MAX(psObject->dfXMax, psObject->padfX[i]);
1035 114449 : psObject->dfYMax = MAX(psObject->dfYMax, psObject->padfY[i]);
1036 114449 : psObject->dfZMax = MAX(psObject->dfZMax, psObject->padfZ[i]);
1037 114449 : psObject->dfMMax = MAX(psObject->dfMMax, psObject->padfM[i]);
1038 : }
1039 29660 : }
1040 :
1041 : /************************************************************************/
1042 : /* SHPCreateObject() */
1043 : /* */
1044 : /* Create a shape object. It should be freed with */
1045 : /* SHPDestroyObject(). */
1046 : /************************************************************************/
1047 :
1048 : SHPObject SHPAPI_CALL1(*)
1049 29660 : 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 29660 : psObject = (SHPObject *) calloc(1,sizeof(SHPObject));
1059 29660 : psObject->nSHPType = nSHPType;
1060 29660 : psObject->nShapeId = nShapeId;
1061 29660 : psObject->bMeasureIsUsed = FALSE;
1062 :
1063 : /* -------------------------------------------------------------------- */
1064 : /* Establish whether this shape type has M, and Z values. */
1065 : /* -------------------------------------------------------------------- */
1066 29660 : if( nSHPType == SHPT_ARCM
1067 : || nSHPType == SHPT_POINTM
1068 : || nSHPType == SHPT_POLYGONM
1069 : || nSHPType == SHPT_MULTIPOINTM )
1070 : {
1071 0 : bHasM = TRUE;
1072 0 : bHasZ = FALSE;
1073 : }
1074 45025 : else if( nSHPType == SHPT_ARCZ
1075 : || nSHPType == SHPT_POINTZ
1076 : || nSHPType == SHPT_POLYGONZ
1077 : || nSHPType == SHPT_MULTIPOINTZ
1078 : || nSHPType == SHPT_MULTIPATCH )
1079 : {
1080 15365 : bHasM = TRUE;
1081 15365 : bHasZ = TRUE;
1082 : }
1083 : else
1084 : {
1085 14295 : bHasM = FALSE;
1086 14295 : bHasZ = FALSE;
1087 : }
1088 :
1089 : /* -------------------------------------------------------------------- */
1090 : /* Capture parts. Note that part type is optional, and */
1091 : /* defaults to ring. */
1092 : /* -------------------------------------------------------------------- */
1093 29660 : 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 13847 : psObject->nParts = MAX(1,nParts);
1099 :
1100 13847 : psObject->panPartStart = (int *)
1101 13847 : calloc(sizeof(int), psObject->nParts);
1102 13847 : psObject->panPartType = (int *)
1103 : malloc(sizeof(int) * psObject->nParts);
1104 :
1105 13847 : psObject->panPartStart[0] = 0;
1106 13847 : psObject->panPartType[0] = SHPP_RING;
1107 :
1108 26982 : for( i = 0; i < nParts; i++ )
1109 : {
1110 13135 : if( psObject->panPartStart != NULL )
1111 13135 : psObject->panPartStart[i] = panPartStart[i];
1112 :
1113 13135 : if( panPartType != NULL )
1114 0 : psObject->panPartType[i] = panPartType[i];
1115 : else
1116 13135 : psObject->panPartType[i] = SHPP_RING;
1117 : }
1118 :
1119 13847 : if( psObject->panPartStart[0] != 0 )
1120 0 : psObject->panPartStart[0] = 0;
1121 : }
1122 :
1123 : /* -------------------------------------------------------------------- */
1124 : /* Capture vertices. Note that X, Y, Z and M are optional. */
1125 : /* -------------------------------------------------------------------- */
1126 29660 : if( nVertices > 0 )
1127 : {
1128 29118 : psObject->padfX = (double *) calloc(sizeof(double),nVertices);
1129 29118 : psObject->padfY = (double *) calloc(sizeof(double),nVertices);
1130 29118 : psObject->padfZ = (double *) calloc(sizeof(double),nVertices);
1131 29118 : psObject->padfM = (double *) calloc(sizeof(double),nVertices);
1132 :
1133 143567 : for( i = 0; i < nVertices; i++ )
1134 : {
1135 114449 : if( padfX != NULL )
1136 114449 : psObject->padfX[i] = padfX[i];
1137 114449 : if( padfY != NULL )
1138 114449 : psObject->padfY[i] = padfY[i];
1139 114449 : if( padfZ != NULL && bHasZ )
1140 34422 : psObject->padfZ[i] = padfZ[i];
1141 114449 : if( padfM != NULL && bHasM )
1142 0 : psObject->padfM[i] = padfM[i];
1143 : }
1144 29118 : if( padfM != NULL && bHasM )
1145 0 : psObject->bMeasureIsUsed = TRUE;
1146 : }
1147 :
1148 : /* -------------------------------------------------------------------- */
1149 : /* Compute the extents. */
1150 : /* -------------------------------------------------------------------- */
1151 29660 : psObject->nVertices = nVertices;
1152 29660 : SHPComputeExtents( psObject );
1153 :
1154 29660 : 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 16584 : SHPCreateSimpleObject( int nSHPType, int nVertices,
1166 : const double * padfX, const double * padfY,
1167 : const double * padfZ )
1168 :
1169 : {
1170 16584 : 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 29688 : SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
1183 :
1184 : {
1185 29688 : unsigned int nRecordOffset, nRecordSize=0;
1186 : int i;
1187 : uchar *pabyRec;
1188 : int32 i32;
1189 :
1190 29688 : psSHP->bUpdated = TRUE;
1191 :
1192 : /* -------------------------------------------------------------------- */
1193 : /* Ensure that shape object matches the type of the file it is */
1194 : /* being written to. */
1195 : /* -------------------------------------------------------------------- */
1196 29688 : 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 29688 : assert( nShapeId == -1
1205 : || (nShapeId >= 0 && nShapeId < psSHP->nRecords) );
1206 :
1207 29688 : if( nShapeId != -1 && nShapeId >= psSHP->nRecords )
1208 0 : nShapeId = -1;
1209 :
1210 : /* -------------------------------------------------------------------- */
1211 : /* Add the new entity to the in memory index. */
1212 : /* -------------------------------------------------------------------- */
1213 29688 : if( nShapeId == -1 && psSHP->nRecords+1 > psSHP->nMaxRecords )
1214 : {
1215 1262 : psSHP->nMaxRecords =(int) ( psSHP->nMaxRecords * 1.3 + 100);
1216 :
1217 2524 : psSHP->panRecOffset = (unsigned int *)
1218 1262 : SfRealloc(psSHP->panRecOffset,sizeof(unsigned int) * psSHP->nMaxRecords );
1219 2524 : psSHP->panRecSize = (unsigned int *)
1220 1262 : SfRealloc(psSHP->panRecSize,sizeof(unsigned int) * psSHP->nMaxRecords );
1221 : }
1222 :
1223 : /* -------------------------------------------------------------------- */
1224 : /* Initialize record. */
1225 : /* -------------------------------------------------------------------- */
1226 29688 : pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double)
1227 29688 : + psObject->nParts * 8 + 128);
1228 :
1229 : /* -------------------------------------------------------------------- */
1230 : /* Extract vertices for a Polygon or Arc. */
1231 : /* -------------------------------------------------------------------- */
1232 141513 : if( psObject->nSHPType == SHPT_POLYGON
1233 29688 : || psObject->nSHPType == SHPT_POLYGONZ
1234 16683 : || psObject->nSHPType == SHPT_POLYGONM
1235 16597 : || psObject->nSHPType == SHPT_ARC
1236 16597 : || psObject->nSHPType == SHPT_ARCZ
1237 16446 : || psObject->nSHPType == SHPT_ARCM
1238 31628 : || psObject->nSHPType == SHPT_MULTIPATCH )
1239 : {
1240 : int32 nPoints, nParts;
1241 : int i;
1242 :
1243 13874 : nPoints = psObject->nVertices;
1244 13874 : nParts = psObject->nParts;
1245 :
1246 13874 : _SHPSetBounds( pabyRec + 12, psObject );
1247 :
1248 13874 : if( bBigEndian ) SwapWord( 4, &nPoints );
1249 13874 : if( bBigEndian ) SwapWord( 4, &nParts );
1250 :
1251 13874 : ByteCopy( &nPoints, pabyRec + 40 + 8, 4 );
1252 13874 : ByteCopy( &nParts, pabyRec + 36 + 8, 4 );
1253 :
1254 13874 : nRecordSize = 52;
1255 :
1256 : /*
1257 : * Write part start positions.
1258 : */
1259 13874 : ByteCopy( psObject->panPartStart, pabyRec + 44 + 8,
1260 : 4 * psObject->nParts );
1261 27807 : for( i = 0; i < psObject->nParts; i++ )
1262 : {
1263 13933 : if( bBigEndian ) SwapWord( 4, pabyRec + 44 + 8 + 4*i );
1264 13933 : nRecordSize += 4;
1265 : }
1266 :
1267 : /*
1268 : * Write multipatch part types if needed.
1269 : */
1270 13874 : if( psObject->nSHPType == SHPT_MULTIPATCH )
1271 : {
1272 0 : memcpy( pabyRec + nRecordSize, psObject->panPartType,
1273 0 : 4*psObject->nParts );
1274 0 : for( i = 0; i < psObject->nParts; i++ )
1275 : {
1276 0 : if( bBigEndian ) SwapWord( 4, pabyRec + nRecordSize );
1277 0 : nRecordSize += 4;
1278 : }
1279 : }
1280 :
1281 : /*
1282 : * Write the (x,y) vertex values.
1283 : */
1284 113714 : for( i = 0; i < psObject->nVertices; i++ )
1285 : {
1286 99840 : ByteCopy( psObject->padfX + i, pabyRec + nRecordSize, 8 );
1287 99840 : ByteCopy( psObject->padfY + i, pabyRec + nRecordSize + 8, 8 );
1288 :
1289 99840 : if( bBigEndian )
1290 0 : SwapWord( 8, pabyRec + nRecordSize );
1291 :
1292 99840 : if( bBigEndian )
1293 0 : SwapWord( 8, pabyRec + nRecordSize + 8 );
1294 :
1295 99840 : nRecordSize += 2 * 8;
1296 : }
1297 :
1298 : /*
1299 : * Write the Z coordinates (if any).
1300 : */
1301 40818 : if( psObject->nSHPType == SHPT_POLYGONZ
1302 13874 : || psObject->nSHPType == SHPT_ARCZ
1303 26944 : || psObject->nSHPType == SHPT_MULTIPATCH )
1304 : {
1305 718 : ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
1306 718 : if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1307 718 : nRecordSize += 8;
1308 :
1309 718 : ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
1310 718 : if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1311 718 : nRecordSize += 8;
1312 :
1313 20490 : for( i = 0; i < psObject->nVertices; i++ )
1314 : {
1315 19772 : ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
1316 19772 : if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1317 19772 : nRecordSize += 8;
1318 : }
1319 : }
1320 :
1321 : /*
1322 : * Write the M values, if any.
1323 : */
1324 13874 : if( psObject->bMeasureIsUsed
1325 13874 : && (psObject->nSHPType == SHPT_POLYGONM
1326 0 : || psObject->nSHPType == SHPT_ARCM
1327 : #ifndef DISABLE_MULTIPATCH_MEASURE
1328 : || psObject->nSHPType == SHPT_MULTIPATCH
1329 : #endif
1330 0 : || psObject->nSHPType == SHPT_POLYGONZ
1331 0 : || psObject->nSHPType == SHPT_ARCZ) )
1332 : {
1333 0 : ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
1334 0 : if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1335 0 : nRecordSize += 8;
1336 :
1337 0 : ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
1338 0 : if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1339 0 : nRecordSize += 8;
1340 :
1341 0 : for( i = 0; i < psObject->nVertices; i++ )
1342 : {
1343 0 : ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
1344 0 : if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1345 0 : nRecordSize += 8;
1346 : }
1347 : }
1348 : }
1349 :
1350 : /* -------------------------------------------------------------------- */
1351 : /* Extract vertices for a MultiPoint. */
1352 : /* -------------------------------------------------------------------- */
1353 47438 : else if( psObject->nSHPType == SHPT_MULTIPOINT
1354 15814 : || psObject->nSHPType == SHPT_MULTIPOINTZ
1355 31617 : || psObject->nSHPType == SHPT_MULTIPOINTM )
1356 : {
1357 : int32 nPoints;
1358 : int i;
1359 :
1360 7 : nPoints = psObject->nVertices;
1361 :
1362 7 : _SHPSetBounds( pabyRec + 12, psObject );
1363 :
1364 7 : if( bBigEndian ) SwapWord( 4, &nPoints );
1365 7 : ByteCopy( &nPoints, pabyRec + 44, 4 );
1366 :
1367 20 : for( i = 0; i < psObject->nVertices; i++ )
1368 : {
1369 13 : ByteCopy( psObject->padfX + i, pabyRec + 48 + i*16, 8 );
1370 13 : ByteCopy( psObject->padfY + i, pabyRec + 48 + i*16 + 8, 8 );
1371 :
1372 13 : if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 );
1373 13 : if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 + 8 );
1374 : }
1375 :
1376 7 : nRecordSize = 48 + 16 * psObject->nVertices;
1377 :
1378 7 : if( psObject->nSHPType == SHPT_MULTIPOINTZ )
1379 : {
1380 3 : ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
1381 3 : if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1382 3 : nRecordSize += 8;
1383 :
1384 3 : ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
1385 3 : if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1386 3 : nRecordSize += 8;
1387 :
1388 9 : for( i = 0; i < psObject->nVertices; i++ )
1389 : {
1390 6 : ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
1391 6 : if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1392 6 : nRecordSize += 8;
1393 : }
1394 : }
1395 :
1396 7 : if( psObject->bMeasureIsUsed
1397 7 : && (psObject->nSHPType == SHPT_MULTIPOINTZ
1398 0 : || psObject->nSHPType == SHPT_MULTIPOINTM) )
1399 : {
1400 0 : ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
1401 0 : if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1402 0 : nRecordSize += 8;
1403 :
1404 0 : ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
1405 0 : if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1406 0 : nRecordSize += 8;
1407 :
1408 0 : for( i = 0; i < psObject->nVertices; i++ )
1409 : {
1410 0 : ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
1411 0 : if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1412 0 : nRecordSize += 8;
1413 : }
1414 : }
1415 : }
1416 :
1417 : /* -------------------------------------------------------------------- */
1418 : /* Write point. */
1419 : /* -------------------------------------------------------------------- */
1420 46801 : else if( psObject->nSHPType == SHPT_POINT
1421 15807 : || psObject->nSHPType == SHPT_POINTZ
1422 15730 : || psObject->nSHPType == SHPT_POINTM )
1423 : {
1424 15264 : ByteCopy( psObject->padfX, pabyRec + 12, 8 );
1425 15264 : ByteCopy( psObject->padfY, pabyRec + 20, 8 );
1426 :
1427 15264 : if( bBigEndian ) SwapWord( 8, pabyRec + 12 );
1428 15264 : if( bBigEndian ) SwapWord( 8, pabyRec + 20 );
1429 :
1430 15264 : nRecordSize = 28;
1431 :
1432 15264 : if( psObject->nSHPType == SHPT_POINTZ )
1433 : {
1434 14644 : ByteCopy( psObject->padfZ, pabyRec + nRecordSize, 8 );
1435 14644 : if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1436 14644 : nRecordSize += 8;
1437 : }
1438 :
1439 15264 : if( psObject->bMeasureIsUsed
1440 15264 : && (psObject->nSHPType == SHPT_POINTZ
1441 0 : || psObject->nSHPType == SHPT_POINTM) )
1442 : {
1443 0 : ByteCopy( psObject->padfM, pabyRec + nRecordSize, 8 );
1444 0 : if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1445 0 : nRecordSize += 8;
1446 : }
1447 : }
1448 :
1449 : /* -------------------------------------------------------------------- */
1450 : /* Not much to do for null geometries. */
1451 : /* -------------------------------------------------------------------- */
1452 543 : else if( psObject->nSHPType == SHPT_NULL )
1453 : {
1454 543 : nRecordSize = 12;
1455 : }
1456 :
1457 : else
1458 : {
1459 : /* unknown type */
1460 0 : 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 59353 : if( nShapeId == -1 || psSHP->panRecSize[nShapeId] < nRecordSize-8 )
1469 : {
1470 29665 : unsigned int nExpectedSize = psSHP->nFileSize + nRecordSize;
1471 29665 : if( nExpectedSize < psSHP->nFileSize ) // due to unsigned int overflow
1472 : {
1473 : char str[128];
1474 0 : sprintf( str, "Failed to write shape object. "
1475 : "File size cannot reach %u + %u.",
1476 : psSHP->nFileSize, nRecordSize );
1477 0 : psSHP->sHooks.Error( str );
1478 0 : free( pabyRec );
1479 0 : return -1;
1480 : }
1481 :
1482 29665 : if( nShapeId == -1 )
1483 29662 : nShapeId = psSHP->nRecords++;
1484 :
1485 29665 : psSHP->panRecOffset[nShapeId] = nRecordOffset = psSHP->nFileSize;
1486 29665 : psSHP->panRecSize[nShapeId] = nRecordSize-8;
1487 29665 : psSHP->nFileSize += nRecordSize;
1488 : }
1489 : else
1490 : {
1491 23 : nRecordOffset = psSHP->panRecOffset[nShapeId];
1492 23 : psSHP->panRecSize[nShapeId] = nRecordSize-8;
1493 : }
1494 :
1495 : /* -------------------------------------------------------------------- */
1496 : /* Set the shape type, record number, and record size. */
1497 : /* -------------------------------------------------------------------- */
1498 29688 : i32 = nShapeId+1; /* record # */
1499 29688 : if( !bBigEndian ) SwapWord( 4, &i32 );
1500 29688 : ByteCopy( &i32, pabyRec, 4 );
1501 :
1502 29688 : i32 = (nRecordSize-8)/2; /* record size */
1503 29688 : if( !bBigEndian ) SwapWord( 4, &i32 );
1504 29688 : ByteCopy( &i32, pabyRec + 4, 4 );
1505 :
1506 29688 : i32 = psObject->nSHPType; /* shape type */
1507 29688 : if( bBigEndian ) SwapWord( 4, &i32 );
1508 29688 : ByteCopy( &i32, pabyRec + 8, 4 );
1509 :
1510 : /* -------------------------------------------------------------------- */
1511 : /* Write out record. */
1512 : /* -------------------------------------------------------------------- */
1513 29688 : if( psSHP->sHooks.FSeek( psSHP->fpSHP, nRecordOffset, 0 ) != 0 )
1514 : {
1515 0 : psSHP->sHooks.Error( "Error in psSHP->sHooks.FSeek() while writing object to .shp file." );
1516 0 : free( pabyRec );
1517 0 : return -1;
1518 : }
1519 29688 : if( psSHP->sHooks.FWrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 )
1520 : {
1521 0 : psSHP->sHooks.Error( "Error in psSHP->sHooks.Fwrite() while writing object to .shp file." );
1522 0 : free( pabyRec );
1523 0 : return -1;
1524 : }
1525 :
1526 29688 : free( pabyRec );
1527 :
1528 : /* -------------------------------------------------------------------- */
1529 : /* Expand file wide bounds based on this shape. */
1530 : /* -------------------------------------------------------------------- */
1531 35297 : if( psSHP->adBoundsMin[0] == 0.0
1532 3165 : && psSHP->adBoundsMax[0] == 0.0
1533 1222 : && psSHP->adBoundsMin[1] == 0.0
1534 1222 : && psSHP->adBoundsMax[1] == 0.0 )
1535 : {
1536 1760 : if( psObject->nSHPType == SHPT_NULL || psObject->nVertices == 0 )
1537 : {
1538 538 : psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = 0.0;
1539 538 : psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = 0.0;
1540 538 : psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = 0.0;
1541 538 : psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = 0.0;
1542 : }
1543 : else
1544 : {
1545 684 : psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = psObject->padfX[0];
1546 684 : psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = psObject->padfY[0];
1547 684 : psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ[0];
1548 684 : psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM[0];
1549 : }
1550 : }
1551 :
1552 144805 : for( i = 0; i < psObject->nVertices; i++ )
1553 : {
1554 115117 : psSHP->adBoundsMin[0] = MIN(psSHP->adBoundsMin[0],psObject->padfX[i]);
1555 115117 : psSHP->adBoundsMin[1] = MIN(psSHP->adBoundsMin[1],psObject->padfY[i]);
1556 115117 : psSHP->adBoundsMin[2] = MIN(psSHP->adBoundsMin[2],psObject->padfZ[i]);
1557 115117 : psSHP->adBoundsMin[3] = MIN(psSHP->adBoundsMin[3],psObject->padfM[i]);
1558 115117 : psSHP->adBoundsMax[0] = MAX(psSHP->adBoundsMax[0],psObject->padfX[i]);
1559 115117 : psSHP->adBoundsMax[1] = MAX(psSHP->adBoundsMax[1],psObject->padfY[i]);
1560 115117 : psSHP->adBoundsMax[2] = MAX(psSHP->adBoundsMax[2],psObject->padfZ[i]);
1561 115117 : psSHP->adBoundsMax[3] = MAX(psSHP->adBoundsMax[3],psObject->padfM[i]);
1562 : }
1563 :
1564 29688 : 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 195742 : 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 195742 : if( hEntity < 0 || hEntity >= psSHP->nRecords )
1586 0 : return( NULL );
1587 :
1588 : /* -------------------------------------------------------------------- */
1589 : /* Ensure our record buffer is large enough. */
1590 : /* -------------------------------------------------------------------- */
1591 195742 : nEntitySize = psSHP->panRecSize[hEntity]+8;
1592 195742 : if( nEntitySize > psSHP->nBufSize )
1593 : {
1594 1931 : psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,nEntitySize);
1595 1931 : if (psSHP->pabyRec == NULL)
1596 : {
1597 : char szError[200];
1598 :
1599 : /* Reallocate previous successfull size for following features */
1600 0 : psSHP->pabyRec = (uchar *) malloc(psSHP->nBufSize);
1601 :
1602 0 : sprintf( szError,
1603 : "Not enough memory to allocate requested memory (nBufSize=%d). "
1604 : "Probably broken SHP file", psSHP->nBufSize );
1605 0 : psSHP->sHooks.Error( szError );
1606 0 : return NULL;
1607 : }
1608 :
1609 : /* Only set new buffer size after successfull alloc */
1610 1931 : psSHP->nBufSize = nEntitySize;
1611 : }
1612 :
1613 : /* In case we were not able to reallocate the buffer on a previous step */
1614 195742 : if (psSHP->pabyRec == NULL)
1615 : {
1616 0 : return NULL;
1617 : }
1618 :
1619 : /* -------------------------------------------------------------------- */
1620 : /* Read the record. */
1621 : /* -------------------------------------------------------------------- */
1622 195742 : 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 0 : sprintf( str,
1630 : "Error in fseek() reading object from .shp file at offset %u",
1631 0 : psSHP->panRecOffset[hEntity]);
1632 :
1633 0 : psSHP->sHooks.Error( str );
1634 0 : return NULL;
1635 : }
1636 :
1637 195742 : 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 0 : sprintf( str,
1645 : "Error in fread() reading object of size %u at offset %u from .shp file",
1646 0 : nEntitySize, psSHP->panRecOffset[hEntity] );
1647 :
1648 0 : psSHP->sHooks.Error( str );
1649 0 : return NULL;
1650 : }
1651 :
1652 : /* -------------------------------------------------------------------- */
1653 : /* Allocate and minimally initialize the object. */
1654 : /* -------------------------------------------------------------------- */
1655 195742 : psShape = (SHPObject *) calloc(1,sizeof(SHPObject));
1656 195742 : psShape->nShapeId = hEntity;
1657 195742 : psShape->bMeasureIsUsed = FALSE;
1658 :
1659 195742 : if ( 8 + 4 > nEntitySize )
1660 : {
1661 0 : snprintf(szErrorMsg, sizeof(szErrorMsg),
1662 : "Corrupted .shp file : shape %d : nEntitySize = %d",
1663 : hEntity, nEntitySize);
1664 0 : psSHP->sHooks.Error( szErrorMsg );
1665 0 : SHPDestroyObject(psShape);
1666 0 : return NULL;
1667 : }
1668 195742 : memcpy( &psShape->nSHPType, psSHP->pabyRec + 8, 4 );
1669 :
1670 195742 : if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) );
1671 :
1672 : /* ==================================================================== */
1673 : /* Extract vertices for a Polygon or Arc. */
1674 : /* ==================================================================== */
1675 595214 : if( psShape->nSHPType == SHPT_POLYGON || psShape->nSHPType == SHPT_ARC
1676 57956 : || psShape->nSHPType == SHPT_POLYGONZ
1677 36781 : || psShape->nSHPType == SHPT_POLYGONM
1678 36753 : || psShape->nSHPType == SHPT_ARCZ
1679 36753 : || psShape->nSHPType == SHPT_ARCM
1680 70990 : || psShape->nSHPType == SHPT_MULTIPATCH )
1681 : {
1682 : int32 nPoints, nParts;
1683 : int i, nOffset;
1684 :
1685 160248 : if ( 40 + 8 + 4 > nEntitySize )
1686 : {
1687 0 : snprintf(szErrorMsg, sizeof(szErrorMsg),
1688 : "Corrupted .shp file : shape %d : nEntitySize = %d",
1689 : hEntity, nEntitySize);
1690 0 : psSHP->sHooks.Error( szErrorMsg );
1691 0 : SHPDestroyObject(psShape);
1692 0 : return NULL;
1693 : }
1694 : /* -------------------------------------------------------------------- */
1695 : /* Get the X/Y bounds. */
1696 : /* -------------------------------------------------------------------- */
1697 160248 : memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 );
1698 160248 : memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );
1699 160248 : memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
1700 160248 : memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
1701 :
1702 160248 : if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
1703 160248 : if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
1704 160248 : if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
1705 160248 : 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 160248 : memcpy( &nPoints, psSHP->pabyRec + 40 + 8, 4 );
1712 160248 : memcpy( &nParts, psSHP->pabyRec + 36 + 8, 4 );
1713 :
1714 160248 : if( bBigEndian ) SwapWord( 4, &nPoints );
1715 160248 : if( bBigEndian ) SwapWord( 4, &nParts );
1716 :
1717 320496 : if (nPoints < 0 || nParts < 0 ||
1718 320496 : nPoints > 50 * 1000 * 1000 || nParts > 10 * 1000 * 1000)
1719 : {
1720 0 : snprintf(szErrorMsg, sizeof(szErrorMsg),
1721 : "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d.",
1722 : hEntity, nPoints, nParts);
1723 0 : psSHP->sHooks.Error( szErrorMsg );
1724 0 : SHPDestroyObject(psShape);
1725 0 : 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 160248 : nRequiredSize = 44 + 8 + 4 * nParts + 16 * nPoints;
1732 479430 : if ( psShape->nSHPType == SHPT_POLYGONZ
1733 160248 : || psShape->nSHPType == SHPT_ARCZ
1734 319182 : || psShape->nSHPType == SHPT_MULTIPATCH )
1735 : {
1736 1287 : nRequiredSize += 16 + 8 * nPoints;
1737 : }
1738 160248 : if( psShape->nSHPType == SHPT_MULTIPATCH )
1739 : {
1740 1 : nRequiredSize += 4 * nParts;
1741 : }
1742 160248 : if (nRequiredSize > nEntitySize)
1743 : {
1744 6 : snprintf(szErrorMsg, sizeof(szErrorMsg),
1745 : "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d, nEntitySize=%d.",
1746 : hEntity, nPoints, nParts, nEntitySize);
1747 6 : psSHP->sHooks.Error( szErrorMsg );
1748 6 : SHPDestroyObject(psShape);
1749 6 : return NULL;
1750 : }
1751 :
1752 160242 : psShape->nVertices = nPoints;
1753 160242 : psShape->padfX = (double *) calloc(nPoints,sizeof(double));
1754 160242 : psShape->padfY = (double *) calloc(nPoints,sizeof(double));
1755 160242 : psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
1756 160242 : psShape->padfM = (double *) calloc(nPoints,sizeof(double));
1757 :
1758 160242 : psShape->nParts = nParts;
1759 160242 : psShape->panPartStart = (int *) calloc(nParts,sizeof(int));
1760 160242 : psShape->panPartType = (int *) calloc(nParts,sizeof(int));
1761 :
1762 961452 : if (psShape->padfX == NULL ||
1763 160242 : psShape->padfY == NULL ||
1764 160242 : psShape->padfZ == NULL ||
1765 160242 : psShape->padfM == NULL ||
1766 160242 : psShape->panPartStart == NULL ||
1767 160242 : psShape->panPartType == NULL)
1768 : {
1769 0 : 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 0 : psSHP->sHooks.Error( szErrorMsg );
1773 0 : SHPDestroyObject(psShape);
1774 0 : return NULL;
1775 : }
1776 :
1777 321558 : for( i = 0; i < nParts; i++ )
1778 161316 : psShape->panPartType[i] = SHPP_RING;
1779 :
1780 : /* -------------------------------------------------------------------- */
1781 : /* Copy out the part array from the record. */
1782 : /* -------------------------------------------------------------------- */
1783 160242 : memcpy( psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts );
1784 321552 : for( i = 0; i < nParts; i++ )
1785 : {
1786 161313 : if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i );
1787 :
1788 : /* We check that the offset is inside the vertex array */
1789 322626 : if (psShape->panPartStart[i] < 0
1790 161313 : || (psShape->panPartStart[i] >= psShape->nVertices
1791 161313 : && psShape->nVertices > 0) )
1792 : {
1793 0 : snprintf(szErrorMsg, sizeof(szErrorMsg),
1794 : "Corrupted .shp file : shape %d : panPartStart[%d] = %d, nVertices = %d",
1795 0 : hEntity, i, psShape->panPartStart[i], psShape->nVertices);
1796 0 : psSHP->sHooks.Error( szErrorMsg );
1797 0 : SHPDestroyObject(psShape);
1798 0 : return NULL;
1799 : }
1800 161313 : if (i > 0 && psShape->panPartStart[i] <= psShape->panPartStart[i-1])
1801 : {
1802 6 : snprintf(szErrorMsg, sizeof(szErrorMsg),
1803 : "Corrupted .shp file : shape %d : panPartStart[%d] = %d, panPartStart[%d] = %d",
1804 6 : hEntity, i, psShape->panPartStart[i], i - 1, psShape->panPartStart[i - 1]);
1805 3 : psSHP->sHooks.Error( szErrorMsg );
1806 3 : SHPDestroyObject(psShape);
1807 3 : return NULL;
1808 : }
1809 : }
1810 :
1811 160239 : nOffset = 44 + 8 + 4*nParts;
1812 :
1813 : /* -------------------------------------------------------------------- */
1814 : /* If this is a multipatch, we will also have parts types. */
1815 : /* -------------------------------------------------------------------- */
1816 160239 : if( psShape->nSHPType == SHPT_MULTIPATCH )
1817 : {
1818 1 : memcpy( psShape->panPartType, psSHP->pabyRec + nOffset, 4*nParts );
1819 6 : for( i = 0; i < nParts; i++ )
1820 : {
1821 5 : if( bBigEndian ) SwapWord( 4, psShape->panPartType+i );
1822 : }
1823 :
1824 1 : nOffset += 4*nParts;
1825 : }
1826 :
1827 : /* -------------------------------------------------------------------- */
1828 : /* Copy out the vertices from the record. */
1829 : /* -------------------------------------------------------------------- */
1830 3034223 : for( i = 0; i < nPoints; i++ )
1831 : {
1832 8621952 : memcpy(psShape->padfX + i,
1833 5747968 : psSHP->pabyRec + nOffset + i * 16,
1834 : 8 );
1835 :
1836 8621952 : memcpy(psShape->padfY + i,
1837 5747968 : psSHP->pabyRec + nOffset + i * 16 + 8,
1838 : 8 );
1839 :
1840 2873984 : if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
1841 2873984 : if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
1842 : }
1843 :
1844 160239 : nOffset += 16*nPoints;
1845 :
1846 : /* -------------------------------------------------------------------- */
1847 : /* If we have a Z coordinate, collect that now. */
1848 : /* -------------------------------------------------------------------- */
1849 479403 : if( psShape->nSHPType == SHPT_POLYGONZ
1850 160239 : || psShape->nSHPType == SHPT_ARCZ
1851 319164 : || psShape->nSHPType == SHPT_MULTIPATCH )
1852 : {
1853 1287 : memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
1854 1287 : memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
1855 :
1856 1287 : if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
1857 1287 : if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
1858 :
1859 37389 : for( i = 0; i < nPoints; i++ )
1860 : {
1861 108306 : memcpy( psShape->padfZ + i,
1862 72204 : psSHP->pabyRec + nOffset + 16 + i*8, 8 );
1863 36102 : if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
1864 : }
1865 :
1866 1287 : 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 160239 : if( nEntitySize >= nOffset + 16 + 8*nPoints )
1876 : {
1877 0 : memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
1878 0 : memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
1879 :
1880 0 : if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
1881 0 : if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
1882 :
1883 0 : for( i = 0; i < nPoints; i++ )
1884 : {
1885 0 : memcpy( psShape->padfM + i,
1886 0 : psSHP->pabyRec + nOffset + 16 + i*8, 8 );
1887 0 : if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
1888 : }
1889 0 : psShape->bMeasureIsUsed = TRUE;
1890 : }
1891 : }
1892 :
1893 : /* ==================================================================== */
1894 : /* Extract vertices for a MultiPoint. */
1895 : /* ==================================================================== */
1896 106472 : else if( psShape->nSHPType == SHPT_MULTIPOINT
1897 35494 : || psShape->nSHPType == SHPT_MULTIPOINTM
1898 70968 : || psShape->nSHPType == SHPT_MULTIPOINTZ )
1899 : {
1900 : int32 nPoints;
1901 : int i, nOffset;
1902 :
1903 13 : if ( 44 + 4 > nEntitySize )
1904 : {
1905 0 : snprintf(szErrorMsg, sizeof(szErrorMsg),
1906 : "Corrupted .shp file : shape %d : nEntitySize = %d",
1907 : hEntity, nEntitySize);
1908 0 : psSHP->sHooks.Error( szErrorMsg );
1909 0 : SHPDestroyObject(psShape);
1910 0 : return NULL;
1911 : }
1912 13 : memcpy( &nPoints, psSHP->pabyRec + 44, 4 );
1913 :
1914 13 : if( bBigEndian ) SwapWord( 4, &nPoints );
1915 :
1916 13 : if (nPoints < 0 || nPoints > 50 * 1000 * 1000)
1917 : {
1918 0 : snprintf(szErrorMsg, sizeof(szErrorMsg),
1919 : "Corrupted .shp file : shape %d : nPoints = %d",
1920 : hEntity, nPoints);
1921 0 : psSHP->sHooks.Error( szErrorMsg );
1922 0 : SHPDestroyObject(psShape);
1923 0 : return NULL;
1924 : }
1925 :
1926 13 : nRequiredSize = 48 + nPoints * 16;
1927 13 : if( psShape->nSHPType == SHPT_MULTIPOINTZ )
1928 : {
1929 3 : nRequiredSize += 16 + nPoints * 8;
1930 : }
1931 13 : if (nRequiredSize > nEntitySize)
1932 : {
1933 3 : snprintf(szErrorMsg, sizeof(szErrorMsg),
1934 : "Corrupted .shp file : shape %d : nPoints = %d, nEntitySize = %d",
1935 : hEntity, nPoints, nEntitySize);
1936 3 : psSHP->sHooks.Error( szErrorMsg );
1937 3 : SHPDestroyObject(psShape);
1938 3 : return NULL;
1939 : }
1940 :
1941 10 : psShape->nVertices = nPoints;
1942 10 : psShape->padfX = (double *) calloc(nPoints,sizeof(double));
1943 10 : psShape->padfY = (double *) calloc(nPoints,sizeof(double));
1944 10 : psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
1945 10 : psShape->padfM = (double *) calloc(nPoints,sizeof(double));
1946 :
1947 40 : if (psShape->padfX == NULL ||
1948 10 : psShape->padfY == NULL ||
1949 10 : psShape->padfZ == NULL ||
1950 10 : psShape->padfM == NULL)
1951 : {
1952 0 : 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 0 : psSHP->sHooks.Error( szErrorMsg );
1956 0 : SHPDestroyObject(psShape);
1957 0 : return NULL;
1958 : }
1959 :
1960 27 : for( i = 0; i < nPoints; i++ )
1961 : {
1962 17 : memcpy(psShape->padfX+i, psSHP->pabyRec + 48 + 16 * i, 8 );
1963 17 : memcpy(psShape->padfY+i, psSHP->pabyRec + 48 + 16 * i + 8, 8 );
1964 :
1965 17 : if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
1966 17 : if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
1967 : }
1968 :
1969 10 : nOffset = 48 + 16*nPoints;
1970 :
1971 : /* -------------------------------------------------------------------- */
1972 : /* Get the X/Y bounds. */
1973 : /* -------------------------------------------------------------------- */
1974 10 : memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 );
1975 10 : memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );
1976 10 : memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
1977 10 : memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
1978 :
1979 10 : if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
1980 10 : if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
1981 10 : if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
1982 10 : if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
1983 :
1984 : /* -------------------------------------------------------------------- */
1985 : /* If we have a Z coordinate, collect that now. */
1986 : /* -------------------------------------------------------------------- */
1987 10 : if( psShape->nSHPType == SHPT_MULTIPOINTZ )
1988 : {
1989 3 : memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
1990 3 : memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
1991 :
1992 3 : if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
1993 3 : if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
1994 :
1995 9 : for( i = 0; i < nPoints; i++ )
1996 : {
1997 18 : memcpy( psShape->padfZ + i,
1998 12 : psSHP->pabyRec + nOffset + 16 + i*8, 8 );
1999 6 : if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
2000 : }
2001 :
2002 3 : 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 10 : if( nEntitySize >= nOffset + 16 + 8*nPoints )
2012 : {
2013 1 : memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
2014 1 : memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
2015 :
2016 1 : if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
2017 1 : if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
2018 :
2019 1 : for( i = 0; i < nPoints; i++ )
2020 : {
2021 0 : memcpy( psShape->padfM + i,
2022 0 : psSHP->pabyRec + nOffset + 16 + i*8, 8 );
2023 0 : if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
2024 : }
2025 1 : psShape->bMeasureIsUsed = TRUE;
2026 : }
2027 : }
2028 :
2029 : /* ==================================================================== */
2030 : /* Extract vertices for a point. */
2031 : /* ==================================================================== */
2032 95438 : else if( psShape->nSHPType == SHPT_POINT
2033 35481 : || psShape->nSHPType == SHPT_POINTM
2034 59957 : || psShape->nSHPType == SHPT_POINTZ )
2035 : {
2036 : int nOffset;
2037 :
2038 34789 : psShape->nVertices = 1;
2039 34789 : psShape->padfX = (double *) calloc(1,sizeof(double));
2040 34789 : psShape->padfY = (double *) calloc(1,sizeof(double));
2041 34789 : psShape->padfZ = (double *) calloc(1,sizeof(double));
2042 34789 : psShape->padfM = (double *) calloc(1,sizeof(double));
2043 :
2044 34789 : if (20 + 8 + (( psShape->nSHPType == SHPT_POINTZ ) ? 8 : 0)> nEntitySize)
2045 : {
2046 3 : snprintf(szErrorMsg, sizeof(szErrorMsg),
2047 : "Corrupted .shp file : shape %d : nEntitySize = %d",
2048 : hEntity, nEntitySize);
2049 3 : psSHP->sHooks.Error( szErrorMsg );
2050 3 : SHPDestroyObject(psShape);
2051 3 : return NULL;
2052 : }
2053 34786 : memcpy( psShape->padfX, psSHP->pabyRec + 12, 8 );
2054 34786 : memcpy( psShape->padfY, psSHP->pabyRec + 20, 8 );
2055 :
2056 34786 : if( bBigEndian ) SwapWord( 8, psShape->padfX );
2057 34786 : if( bBigEndian ) SwapWord( 8, psShape->padfY );
2058 :
2059 34786 : nOffset = 20 + 8;
2060 :
2061 : /* -------------------------------------------------------------------- */
2062 : /* If we have a Z coordinate, collect that now. */
2063 : /* -------------------------------------------------------------------- */
2064 34786 : if( psShape->nSHPType == SHPT_POINTZ )
2065 : {
2066 29286 : memcpy( psShape->padfZ, psSHP->pabyRec + nOffset, 8 );
2067 :
2068 29286 : if( bBigEndian ) SwapWord( 8, psShape->padfZ );
2069 :
2070 29286 : 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 34786 : if( nEntitySize >= nOffset + 8 )
2080 : {
2081 2 : memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 );
2082 :
2083 2 : if( bBigEndian ) SwapWord( 8, psShape->padfM );
2084 2 : 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 34786 : psShape->dfXMin = psShape->dfXMax = psShape->padfX[0];
2092 34786 : psShape->dfYMin = psShape->dfYMax = psShape->padfY[0];
2093 34786 : psShape->dfZMin = psShape->dfZMax = psShape->padfZ[0];
2094 34786 : psShape->dfMMin = psShape->dfMMax = psShape->padfM[0];
2095 : }
2096 :
2097 195727 : return( psShape );
2098 : }
2099 :
2100 : /************************************************************************/
2101 : /* SHPTypeName() */
2102 : /************************************************************************/
2103 :
2104 : const char SHPAPI_CALL1(*)
2105 0 : SHPTypeName( int nSHPType )
2106 :
2107 : {
2108 0 : switch( nSHPType )
2109 : {
2110 : case SHPT_NULL:
2111 0 : return "NullShape";
2112 :
2113 : case SHPT_POINT:
2114 0 : return "Point";
2115 :
2116 : case SHPT_ARC:
2117 0 : return "Arc";
2118 :
2119 : case SHPT_POLYGON:
2120 0 : return "Polygon";
2121 :
2122 : case SHPT_MULTIPOINT:
2123 0 : return "MultiPoint";
2124 :
2125 : case SHPT_POINTZ:
2126 0 : return "PointZ";
2127 :
2128 : case SHPT_ARCZ:
2129 0 : return "ArcZ";
2130 :
2131 : case SHPT_POLYGONZ:
2132 0 : return "PolygonZ";
2133 :
2134 : case SHPT_MULTIPOINTZ:
2135 0 : return "MultiPointZ";
2136 :
2137 : case SHPT_POINTM:
2138 0 : return "PointM";
2139 :
2140 : case SHPT_ARCM:
2141 0 : return "ArcM";
2142 :
2143 : case SHPT_POLYGONM:
2144 0 : return "PolygonM";
2145 :
2146 : case SHPT_MULTIPOINTM:
2147 0 : return "MultiPointM";
2148 :
2149 : case SHPT_MULTIPATCH:
2150 0 : return "MultiPatch";
2151 :
2152 : default:
2153 0 : return "UnknownShapeType";
2154 : }
2155 : }
2156 :
2157 : /************************************************************************/
2158 : /* SHPPartTypeName() */
2159 : /************************************************************************/
2160 :
2161 : const char SHPAPI_CALL1(*)
2162 0 : SHPPartTypeName( int nPartType )
2163 :
2164 : {
2165 0 : switch( nPartType )
2166 : {
2167 : case SHPP_TRISTRIP:
2168 0 : return "TriangleStrip";
2169 :
2170 : case SHPP_TRIFAN:
2171 0 : return "TriangleFan";
2172 :
2173 : case SHPP_OUTERRING:
2174 0 : return "OuterRing";
2175 :
2176 : case SHPP_INNERRING:
2177 0 : return "InnerRing";
2178 :
2179 : case SHPP_FIRSTRING:
2180 0 : return "FirstRing";
2181 :
2182 : case SHPP_RING:
2183 0 : return "Ring";
2184 :
2185 : default:
2186 0 : return "UnknownPartType";
2187 : }
2188 : }
2189 :
2190 : /************************************************************************/
2191 : /* SHPDestroyObject() */
2192 : /************************************************************************/
2193 :
2194 : void SHPAPI_CALL
2195 225402 : SHPDestroyObject( SHPObject * psShape )
2196 :
2197 : {
2198 225402 : if( psShape == NULL )
2199 0 : return;
2200 :
2201 225402 : if( psShape->padfX != NULL )
2202 224159 : free( psShape->padfX );
2203 225402 : if( psShape->padfY != NULL )
2204 224159 : free( psShape->padfY );
2205 225402 : if( psShape->padfZ != NULL )
2206 224159 : free( psShape->padfZ );
2207 225402 : if( psShape->padfM != NULL )
2208 224159 : free( psShape->padfM );
2209 :
2210 225402 : if( psShape->panPartStart != NULL )
2211 174089 : free( psShape->panPartStart );
2212 225402 : if( psShape->panPartType != NULL )
2213 174089 : free( psShape->panPartType );
2214 :
2215 225402 : 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 13064 : SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
2227 :
2228 : {
2229 13064 : int iOpRing, bAltered = 0;
2230 :
2231 : /* -------------------------------------------------------------------- */
2232 : /* Do nothing if this is not a polygon object. */
2233 : /* -------------------------------------------------------------------- */
2234 13150 : if( psObject->nSHPType != SHPT_POLYGON
2235 13064 : && psObject->nSHPType != SHPT_POLYGONZ
2236 86 : && psObject->nSHPType != SHPT_POLYGONM )
2237 0 : return 0;
2238 :
2239 13064 : if( psObject->nVertices == 0 || psObject->nParts == 0 )
2240 0 : return 0;
2241 :
2242 : /* -------------------------------------------------------------------- */
2243 : /* Process each of the rings. */
2244 : /* -------------------------------------------------------------------- */
2245 26177 : 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 26226 : dfTestX = ( psObject->padfX[psObject->panPartStart[iOpRing]]
2263 13113 : + psObject->padfX[psObject->panPartStart[iOpRing] + 1] ) / 2;
2264 26226 : dfTestY = ( psObject->padfY[psObject->panPartStart[iOpRing]]
2265 13113 : + psObject->padfY[psObject->panPartStart[iOpRing] + 1] ) / 2;
2266 :
2267 13113 : bInner = FALSE;
2268 26364 : for( iCheckRing = 0; iCheckRing < psObject->nParts; iCheckRing++ )
2269 : {
2270 : int iEdge;
2271 :
2272 13251 : if( iCheckRing == iOpRing )
2273 13113 : continue;
2274 :
2275 138 : nVertStart = psObject->panPartStart[iCheckRing];
2276 :
2277 138 : if( iCheckRing == psObject->nParts-1 )
2278 98 : nVertCount = psObject->nVertices
2279 49 : - psObject->panPartStart[iCheckRing];
2280 : else
2281 178 : nVertCount = psObject->panPartStart[iCheckRing+1]
2282 89 : - psObject->panPartStart[iCheckRing];
2283 :
2284 871 : for( iEdge = 0; iEdge < nVertCount; iEdge++ )
2285 : {
2286 : int iNext;
2287 :
2288 733 : if( iEdge < nVertCount-1 )
2289 595 : iNext = iEdge+1;
2290 : else
2291 138 : 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 2851 : if ( ( psObject->padfY[iEdge+nVertStart] < dfTestY
2298 1101 : && dfTestY <= psObject->padfY[iNext+nVertStart] )
2299 649 : || ( psObject->padfY[iNext+nVertStart] < dfTestY
2300 1017 : && 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 168 : ( psObject->padfX[iEdge+nVertStart]
2307 168 : + ( dfTestY - psObject->padfY[iEdge+nVertStart] )
2308 168 : / ( psObject->padfY[iNext+nVertStart] - psObject->padfY[iEdge+nVertStart] )
2309 168 : * ( psObject->padfX[iNext+nVertStart] - psObject->padfX[iEdge+nVertStart] ) );
2310 :
2311 168 : if (intersect < dfTestX)
2312 : {
2313 69 : 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 13113 : nVertStart = psObject->panPartStart[iOpRing];
2324 :
2325 13113 : if( iOpRing == psObject->nParts-1 )
2326 13064 : nVertCount = psObject->nVertices - psObject->panPartStart[iOpRing];
2327 : else
2328 98 : nVertCount = psObject->panPartStart[iOpRing+1]
2329 49 : - psObject->panPartStart[iOpRing];
2330 :
2331 13113 : if (nVertCount < 2)
2332 0 : continue;
2333 :
2334 13113 : dfSum = psObject->padfX[nVertStart] * (psObject->padfY[nVertStart+1] - psObject->padfY[nVertStart+nVertCount-1]);
2335 64411 : for( iVert = nVertStart + 1; iVert < nVertStart+nVertCount-1; iVert++ )
2336 : {
2337 51298 : dfSum += psObject->padfX[iVert] * (psObject->padfY[iVert+1] - psObject->padfY[iVert-1]);
2338 : }
2339 :
2340 13113 : dfSum += psObject->padfX[iVert] * (psObject->padfY[nVertStart] - psObject->padfY[iVert-1]);
2341 :
2342 : /* -------------------------------------------------------------------- */
2343 : /* Reverse if necessary. */
2344 : /* -------------------------------------------------------------------- */
2345 13113 : if( (dfSum < 0.0 && bInner) || (dfSum > 0.0 && !bInner) )
2346 : {
2347 : int i;
2348 :
2349 76 : bAltered++;
2350 248 : for( i = 0; i < nVertCount/2; i++ )
2351 : {
2352 : double dfSaved;
2353 :
2354 : /* Swap X */
2355 172 : dfSaved = psObject->padfX[nVertStart+i];
2356 344 : psObject->padfX[nVertStart+i] =
2357 172 : psObject->padfX[nVertStart+nVertCount-i-1];
2358 172 : psObject->padfX[nVertStart+nVertCount-i-1] = dfSaved;
2359 :
2360 : /* Swap Y */
2361 172 : dfSaved = psObject->padfY[nVertStart+i];
2362 344 : psObject->padfY[nVertStart+i] =
2363 172 : psObject->padfY[nVertStart+nVertCount-i-1];
2364 172 : psObject->padfY[nVertStart+nVertCount-i-1] = dfSaved;
2365 :
2366 : /* Swap Z */
2367 172 : if( psObject->padfZ )
2368 : {
2369 172 : dfSaved = psObject->padfZ[nVertStart+i];
2370 344 : psObject->padfZ[nVertStart+i] =
2371 172 : psObject->padfZ[nVertStart+nVertCount-i-1];
2372 172 : psObject->padfZ[nVertStart+nVertCount-i-1] = dfSaved;
2373 : }
2374 :
2375 : /* Swap M */
2376 172 : if( psObject->padfM )
2377 : {
2378 172 : dfSaved = psObject->padfM[nVertStart+i];
2379 344 : psObject->padfM[nVertStart+i] =
2380 172 : psObject->padfM[nVertStart+nVertCount-i-1];
2381 172 : psObject->padfM[nVertStart+nVertCount-i-1] = dfSaved;
2382 : }
2383 : }
2384 : }
2385 : }
2386 :
2387 13064 : return bAltered;
2388 : }
|