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