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