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