GRASS GIS 8 Programmer's Manual 8.2.1(2023)-exported
shpopen.c
Go to the documentation of this file.
1/******************************************************************************
2 * $Id$
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 * Copyright (c) 2011-2013, Even Rouault <even dot rouault at mines-paris dot org>
11 *
12 * This software is available under the following "MIT Style" license,
13 * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
14 * option is discussed in more detail in shapelib.html.
15 *
16 * --
17 *
18 * Permission is hereby granted, free of charge, to any person obtaining a
19 * copy of this software and associated documentation files (the "Software"),
20 * to deal in the Software without restriction, including without limitation
21 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
22 * and/or sell copies of the Software, and to permit persons to whom the
23 * Software is furnished to do so, subject to the following conditions:
24 *
25 * The above copyright notice and this permission notice shall be included
26 * in all copies or substantial portions of the Software.
27 *
28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
29 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
31 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
33 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
34 * DEALINGS IN THE SOFTWARE.
35 ******************************************************************************
36 *
37 * $Log: shpopen.c,v $
38 * Revision 1.73 2012-01-24 22:33:01 fwarmerdam
39 * fix memory leak on failure to open .shp (gdal #4410)
40 *
41 * Revision 1.72 2011-12-11 22:45:28 fwarmerdam
42 * fix failure return from SHPOpenLL.
43 *
44 * Revision 1.71 2011-09-15 03:33:58 fwarmerdam
45 * fix missing cast (#2344)
46 *
47 * Revision 1.70 2011-07-24 05:59:25 fwarmerdam
48 * minimize use of CPLError in favor of SAHooks.Error()
49 *
50 * Revision 1.69 2011-07-24 03:24:22 fwarmerdam
51 * fix memory leaks in error cases creating shapefiles (#2061)
52 *
53 * Revision 1.68 2010-08-27 23:42:52 fwarmerdam
54 * add SHPAPI_CALL attribute in code
55 *
56 * Revision 1.67 2010-07-01 08:15:48 fwarmerdam
57 * do not error out on an object with zero vertices
58 *
59 * Revision 1.66 2010-07-01 07:58:57 fwarmerdam
60 * minor cleanup of error handling
61 *
62 * Revision 1.65 2010-07-01 07:27:13 fwarmerdam
63 * white space formatting adjustments
64 *
65 * Revision 1.64 2010-01-28 11:34:34 fwarmerdam
66 * handle the shape file length limits more gracefully (#3236)
67 *
68 * Revision 1.63 2010-01-28 04:04:40 fwarmerdam
69 * improve numerical accuracy of SHPRewind() algs (gdal #3363)
70 *
71 * Revision 1.62 2010-01-17 05:34:13 fwarmerdam
72 * Remove asserts on x/y being null (#2148).
73 *
74 * Revision 1.61 2010-01-16 05:07:42 fwarmerdam
75 * allow 0/nulls in shpcreateobject (#2148)
76 *
77 * Revision 1.60 2009-09-17 20:50:02 bram
78 * on Win32, define snprintf as alias to _snprintf
79 *
80 * Revision 1.59 2008-03-14 05:25:31 fwarmerdam
81 * Correct crash on buggy geometries (gdal #2218)
82 *
83 * Revision 1.58 2008/01/08 23:28:26 bram
84 * on line 2095, use a float instead of a double to avoid a compiler warning
85 *
86 * Revision 1.57 2007/12/06 07:00:25 fwarmerdam
87 * dbfopen now using SAHooks for fileio
88 *
89 * Revision 1.56 2007/12/04 20:37:56 fwarmerdam
90 * preliminary implementation of hooks api for io and errors
91 *
92 * Revision 1.55 2007/11/21 22:39:56 fwarmerdam
93 * close shx file in readonly mode (GDAL #1956)
94 *
95 * Revision 1.54 2007/11/15 00:12:47 mloskot
96 * Backported recent changes from GDAL (Ticket #1415) to Shapelib.
97 *
98 * Revision 1.53 2007/11/14 22:31:08 fwarmerdam
99 * checks after mallocs to detect for corrupted/voluntary broken shapefiles.
100 * http://trac.osgeo.org/gdal/ticket/1991
101 *
102 * Revision 1.52 2007/06/21 15:58:33 fwarmerdam
103 * fix for SHPRewindObject when rings touch at one vertex (gdal #976)
104 *
105 * Revision 1.51 2006/09/04 15:24:01 fwarmerdam
106 * Fixed up log message for 1.49.
107 *
108 * Revision 1.50 2006/09/04 15:21:39 fwarmerdam
109 * fix of last fix
110 *
111 * Revision 1.49 2006/09/04 15:21:00 fwarmerdam
112 * MLoskot: Added stronger test of Shapefile reading failures, e.g. truncated
113 * files. The problem was discovered by Tim Sutton and reported here
114 * https://svn.qgis.org/trac/ticket/200
115 *
116 * Revision 1.48 2006/01/26 15:07:32 fwarmerdam
117 * add bMeasureIsUsed flag from Craig Bruce: Bug 1249
118 *
119 * Revision 1.47 2006/01/04 20:07:23 fwarmerdam
120 * In SHPWriteObject() make sure that the record length is updated
121 * when rewriting an existing record.
122 *
123 * Revision 1.46 2005/02/11 17:17:46 fwarmerdam
124 * added panPartStart[0] validation
125 *
126 * Revision 1.45 2004/09/26 20:09:48 fwarmerdam
127 * const correctness changes
128 *
129 * Revision 1.44 2003/12/29 00:18:39 fwarmerdam
130 * added error checking for failed IO and optional CPL error reporting
131 *
132 * Revision 1.43 2003/12/01 16:20:08 warmerda
133 * be careful of zero vertex shapes
134 *
135 * Revision 1.42 2003/12/01 14:58:27 warmerda
136 * added degenerate object check in SHPRewindObject()
137 *
138 * Revision 1.41 2003/07/08 15:22:43 warmerda
139 * avoid warning
140 *
141 * Revision 1.40 2003/04/21 18:30:37 warmerda
142 * added header write/update public methods
143 *
144 * Revision 1.39 2002/08/26 06:46:56 warmerda
145 * avoid c++ comments
146 *
147 * Revision 1.38 2002/05/07 16:43:39 warmerda
148 * Removed debugging printf.
149 *
150 * Revision 1.37 2002/04/10 17:35:22 warmerda
151 * fixed bug in ring reversal code
152 *
153 * Revision 1.36 2002/04/10 16:59:54 warmerda
154 * added SHPRewindObject
155 *
156 * Revision 1.35 2001/12/07 15:10:44 warmerda
157 * fix if .shx fails to open
158 *
159 * Revision 1.34 2001/11/01 16:29:55 warmerda
160 * move pabyRec into SHPInfo for thread safety
161 *
162 * Revision 1.33 2001/07/03 12:18:15 warmerda
163 * Improved cleanup if SHX not found, provided by Riccardo Cohen.
164 *
165 * Revision 1.32 2001/06/22 01:58:07 warmerda
166 * be more careful about establishing initial bounds in face of NULL shapes
167 *
168 * Revision 1.31 2001/05/31 19:35:29 warmerda
169 * added support for writing null shapes
170 *
171 * Revision 1.30 2001/05/28 12:46:29 warmerda
172 * Add some checking on reasonableness of record count when opening.
173 *
174 * Revision 1.29 2001/05/23 13:36:52 warmerda
175 * added use of SHPAPI_CALL
176 *
177 * Revision 1.28 2001/02/06 22:25:06 warmerda
178 * fixed memory leaks when SHPOpen() fails
179 *
180 * Revision 1.27 2000/07/18 15:21:33 warmerda
181 * added better enforcement of -1 for append in SHPWriteObject
182 *
183 * Revision 1.26 2000/02/16 16:03:51 warmerda
184 * added null shape support
185 *
186 * Revision 1.25 1999/12/15 13:47:07 warmerda
187 * Fixed record size settings in .shp file (was 4 words too long)
188 * Added stdlib.h.
189 *
190 * Revision 1.24 1999/11/05 14:12:04 warmerda
191 * updated license terms
192 *
193 * Revision 1.23 1999/07/27 00:53:46 warmerda
194 * added support for rewriting shapes
195 *
196 * Revision 1.22 1999/06/11 19:19:11 warmerda
197 * Cleanup pabyRec static buffer on SHPClose().
198 *
199 * Revision 1.21 1999/06/02 14:57:56 kshih
200 * Remove unused variables
201 *
202 * Revision 1.20 1999/04/19 21:04:17 warmerda
203 * Fixed syntax error.
204 *
205 * Revision 1.19 1999/04/19 21:01:57 warmerda
206 * Force access string to binary in SHPOpen().
207 *
208 * Revision 1.18 1999/04/01 18:48:07 warmerda
209 * Try upper case extensions if lower case doesn't work.
210 *
211 * Revision 1.17 1998/12/31 15:29:39 warmerda
212 * Disable writing measure values to multipatch objects if
213 * DISABLE_MULTIPATCH_MEASURE is defined.
214 *
215 * Revision 1.16 1998/12/16 05:14:33 warmerda
216 * Added support to write MULTIPATCH. Fixed reading Z coordinate of
217 * MULTIPATCH. Fixed record size written for all feature types.
218 *
219 * Revision 1.15 1998/12/03 16:35:29 warmerda
220 * r+b is proper binary access string, not rb+.
221 *
222 * Revision 1.14 1998/12/03 15:47:56 warmerda
223 * Fixed setting of nVertices in SHPCreateObject().
224 *
225 * Revision 1.13 1998/12/03 15:33:54 warmerda
226 * Made SHPCalculateExtents() separately callable.
227 *
228 * Revision 1.12 1998/11/11 20:01:50 warmerda
229 * Fixed bug writing ArcM/Z, and PolygonM/Z for big endian machines.
230 *
231 * Revision 1.11 1998/11/09 20:56:44 warmerda
232 * Fixed up handling of file wide bounds.
233 *
234 * Revision 1.10 1998/11/09 20:18:51 warmerda
235 * Converted to support 3D shapefiles, and use of SHPObject.
236 *
237 * Revision 1.9 1998/02/24 15:09:05 warmerda
238 * Fixed memory leak.
239 *
240 * Revision 1.8 1997/12/04 15:40:29 warmerda
241 * Fixed byte swapping of record number, and record length fields in the
242 * .shp file.
243 *
244 * Revision 1.7 1995/10/21 03:15:58 warmerda
245 * Added support for binary file access, the magic cookie 9997
246 * and tried to improve the int32 selection logic for 16bit systems.
247 *
248 * Revision 1.6 1995/09/04 04:19:41 warmerda
249 * Added fix for file bounds.
250 *
251 * Revision 1.5 1995/08/25 15:16:44 warmerda
252 * Fixed a couple of problems with big endian systems ... one with bounds
253 * and the other with multipart polygons.
254 *
255 * Revision 1.4 1995/08/24 18:10:17 warmerda
256 * Switch to use SfRealloc() to avoid problems with pre-ANSI realloc()
257 * functions (such as on the Sun).
258 *
259 * Revision 1.3 1995/08/23 02:23:15 warmerda
260 * Added support for reading bounds, and fixed up problems in setting the
261 * file wide bounds.
262 *
263 * Revision 1.2 1995/08/04 03:16:57 warmerda
264 * Added header.
265 *
266 */
267
268#include <grass/shapefil.h>
269
270#include <math.h>
271#include <limits.h>
272#include <assert.h>
273#include <stdlib.h>
274#include <string.h>
275#include <stdio.h>
276
277SHP_CVSID("$Id$")
278
279#ifndef CPL_UNUSED
280#define CPL_UNUSED
281#endif
282
283typedef unsigned char uchar;
284
285#if UINT_MAX == 65535
286typedef unsigned long int32;
287#else
288typedef unsigned int int32;
289#endif
290
291#ifndef FALSE
292# define FALSE 0
293# define TRUE 1
294#endif
295
296#define ByteCopy( a, b, c ) memcpy( b, a, c )
297#ifndef MAX
298# define MIN(a,b) ((a<b) ? a : b)
299# define MAX(a,b) ((a>b) ? a : b)
300#endif
301
302#if defined(WIN32) || defined(_WIN32)
303# ifndef snprintf
304# define snprintf _snprintf
305# endif
306#endif
307
308#if defined(CPL_LSB)
309#define bBigEndian FALSE
310#elif defined(CPL_MSB)
311#define bBigEndian TRUE
312#else
313static int bBigEndian;
314#endif
315
316/************************************************************************/
317/* SwapWord() */
318/* */
319/* Swap a 2, 4 or 8 byte word. */
320/************************************************************************/
321
322static void SwapWord( int length, void * wordP )
323
324{
325 int i;
326 uchar temp;
327
328 for( i=0; i < length/2; i++ )
329 {
330 temp = ((uchar *) wordP)[i];
331 ((uchar *)wordP)[i] = ((uchar *) wordP)[length-i-1];
332 ((uchar *) wordP)[length-i-1] = temp;
333 }
334}
335
336/************************************************************************/
337/* SfRealloc() */
338/* */
339/* A realloc cover function that will access a NULL pointer as */
340/* a valid input. */
341/************************************************************************/
342
343static void * SfRealloc( void * pMem, int nNewSize )
344
345{
346 if( pMem == NULL )
347 return( (void *) malloc(nNewSize) );
348 else
349 return( (void *) realloc(pMem,nNewSize) );
350}
351
352/************************************************************************/
353/* SHPWriteHeader() */
354/* */
355/* Write out a header for the .shp and .shx files as well as the */
356/* contents of the index (.shx) file. */
357/************************************************************************/
358
360
361{
362 uchar abyHeader[100];
363 int i;
364 int32 i32;
365 double dValue;
366 int32 *panSHX;
367
368 if (psSHP->fpSHX == NULL)
369 {
370 psSHP->sHooks.Error( "SHPWriteHeader failed : SHX file is closed");
371 return;
372 }
373
374/* -------------------------------------------------------------------- */
375/* Prepare header block for .shp file. */
376/* -------------------------------------------------------------------- */
377 for( i = 0; i < 100; i++ )
378 abyHeader[i] = 0;
379
380 abyHeader[2] = 0x27; /* magic cookie */
381 abyHeader[3] = 0x0a;
382
383 i32 = psSHP->nFileSize/2; /* file size */
384 ByteCopy( &i32, abyHeader+24, 4 );
385 if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
386
387 i32 = 1000; /* version */
388 ByteCopy( &i32, abyHeader+28, 4 );
389 if( bBigEndian ) SwapWord( 4, abyHeader+28 );
390
391 i32 = psSHP->nShapeType; /* shape type */
392 ByteCopy( &i32, abyHeader+32, 4 );
393 if( bBigEndian ) SwapWord( 4, abyHeader+32 );
394
395 dValue = psSHP->adBoundsMin[0]; /* set bounds */
396 ByteCopy( &dValue, abyHeader+36, 8 );
397 if( bBigEndian ) SwapWord( 8, abyHeader+36 );
398
399 dValue = psSHP->adBoundsMin[1];
400 ByteCopy( &dValue, abyHeader+44, 8 );
401 if( bBigEndian ) SwapWord( 8, abyHeader+44 );
402
403 dValue = psSHP->adBoundsMax[0];
404 ByteCopy( &dValue, abyHeader+52, 8 );
405 if( bBigEndian ) SwapWord( 8, abyHeader+52 );
406
407 dValue = psSHP->adBoundsMax[1];
408 ByteCopy( &dValue, abyHeader+60, 8 );
409 if( bBigEndian ) SwapWord( 8, abyHeader+60 );
410
411 dValue = psSHP->adBoundsMin[2]; /* z */
412 ByteCopy( &dValue, abyHeader+68, 8 );
413 if( bBigEndian ) SwapWord( 8, abyHeader+68 );
414
415 dValue = psSHP->adBoundsMax[2];
416 ByteCopy( &dValue, abyHeader+76, 8 );
417 if( bBigEndian ) SwapWord( 8, abyHeader+76 );
418
419 dValue = psSHP->adBoundsMin[3]; /* m */
420 ByteCopy( &dValue, abyHeader+84, 8 );
421 if( bBigEndian ) SwapWord( 8, abyHeader+84 );
422
423 dValue = psSHP->adBoundsMax[3];
424 ByteCopy( &dValue, abyHeader+92, 8 );
425 if( bBigEndian ) SwapWord( 8, abyHeader+92 );
426
427/* -------------------------------------------------------------------- */
428/* Write .shp file header. */
429/* -------------------------------------------------------------------- */
430 if( psSHP->sHooks.FSeek( psSHP->fpSHP, 0, 0 ) != 0
431 || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHP ) != 1 )
432 {
433 psSHP->sHooks.Error( "Failure writing .shp header" );
434 return;
435 }
436
437/* -------------------------------------------------------------------- */
438/* Prepare, and write .shx file header. */
439/* -------------------------------------------------------------------- */
440 i32 = (psSHP->nRecords * 2 * sizeof(int32) + 100)/2; /* file size */
441 ByteCopy( &i32, abyHeader+24, 4 );
442 if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
443
444 if( psSHP->sHooks.FSeek( psSHP->fpSHX, 0, 0 ) != 0
445 || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHX ) != 1 )
446 {
447 psSHP->sHooks.Error( "Failure writing .shx header" );
448 return;
449 }
450
451/* -------------------------------------------------------------------- */
452/* Write out the .shx contents. */
453/* -------------------------------------------------------------------- */
454 panSHX = (int32 *) malloc(sizeof(int32) * 2 * psSHP->nRecords);
455 if( panSHX == NULL )
456 {
457 psSHP->sHooks.Error( "Failure allocatin panSHX" );
458 return;
459 }
460
461 for( i = 0; i < psSHP->nRecords; i++ )
462 {
463 panSHX[i*2 ] = psSHP->panRecOffset[i]/2;
464 panSHX[i*2+1] = psSHP->panRecSize[i]/2;
465 if( !bBigEndian ) SwapWord( 4, panSHX+i*2 );
466 if( !bBigEndian ) SwapWord( 4, panSHX+i*2+1 );
467 }
468
469 if( (int)psSHP->sHooks.FWrite( panSHX, sizeof(int32)*2, psSHP->nRecords, psSHP->fpSHX )
470 != psSHP->nRecords )
471 {
472 psSHP->sHooks.Error( "Failure writing .shx contents" );
473 }
474
475 free( panSHX );
476
477/* -------------------------------------------------------------------- */
478/* Flush to disk. */
479/* -------------------------------------------------------------------- */
480 psSHP->sHooks.FFlush( psSHP->fpSHP );
481 psSHP->sHooks.FFlush( psSHP->fpSHX );
482}
483
484/************************************************************************/
485/* SHPOpen() */
486/************************************************************************/
487
489SHPOpen( const char * pszLayer, const char * pszAccess )
490
491{
492 SAHooks sHooks;
493
494 SASetupDefaultHooks( &sHooks );
495
496 return SHPOpenLL( pszLayer, pszAccess, &sHooks );
497}
498
499/************************************************************************/
500/* SHPOpen() */
501/* */
502/* Open the .shp and .shx files based on the basename of the */
503/* files or either file name. */
504/************************************************************************/
505
507SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
508
509{
510 char *pszFullname, *pszBasename;
511 SHPHandle psSHP;
512
513 uchar *pabyBuf;
514 int i;
515 double dValue;
516 int bLazySHXLoading = FALSE;
517 size_t nFullnameLen;
518
519/* -------------------------------------------------------------------- */
520/* Ensure the access string is one of the legal ones. We */
521/* ensure the result string indicates binary to avoid common */
522/* problems on Windows. */
523/* -------------------------------------------------------------------- */
524 if( strcmp(pszAccess,"rb+") == 0 || strcmp(pszAccess,"r+b") == 0
525 || strcmp(pszAccess,"r+") == 0 )
526 pszAccess = "r+b";
527 else
528 {
529 bLazySHXLoading = strchr(pszAccess, 'l') != NULL;
530 pszAccess = "rb";
531 }
532
533/* -------------------------------------------------------------------- */
534/* Establish the byte order on this machine. */
535/* -------------------------------------------------------------------- */
536#if !defined(bBigEndian)
537 i = 1;
538 if( *((uchar *) &i) == 1 )
539 bBigEndian = FALSE;
540 else
541 bBigEndian = TRUE;
542#endif
543
544/* -------------------------------------------------------------------- */
545/* Initialize the info structure. */
546/* -------------------------------------------------------------------- */
547 psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1);
548
549 psSHP->bUpdated = FALSE;
550 memcpy( &(psSHP->sHooks), psHooks, sizeof(SAHooks) );
551
552/* -------------------------------------------------------------------- */
553/* Compute the base (layer) name. If there is any extension */
554/* on the passed in filename we will strip it off. */
555/* -------------------------------------------------------------------- */
556 pszBasename = (char *) malloc(strlen(pszLayer)+5);
557 strcpy( pszBasename, pszLayer );
558 for( i = (int)strlen(pszBasename)-1;
559 i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
560 && pszBasename[i] != '\\';
561 i-- ) {}
562
563 if( pszBasename[i] == '.' )
564 pszBasename[i] = '\0';
565
566/* -------------------------------------------------------------------- */
567/* Open the .shp and .shx files. Note that files pulled from */
568/* a PC to Unix with upper case filenames won't work! */
569/* -------------------------------------------------------------------- */
570 nFullnameLen = strlen(pszBasename) + 5;
571 pszFullname = (char *) malloc(nFullnameLen);
572 snprintf( pszFullname, nFullnameLen, "%s.shp", pszBasename ) ;
573 psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
574 if( psSHP->fpSHP == NULL )
575 {
576 snprintf( pszFullname, nFullnameLen, "%s.SHP", pszBasename );
577 psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
578 }
579
580 if( psSHP->fpSHP == NULL )
581 {
582 size_t nMessageLen = strlen(pszBasename)*2+256;
583 char *pszMessage = (char *) malloc(nMessageLen);
584 snprintf( pszMessage, nMessageLen, "Unable to open %s.shp or %s.SHP.",
585 pszBasename, pszBasename );
586 psHooks->Error( pszMessage );
587 free( pszMessage );
588
589 free( psSHP );
590 free( pszBasename );
591 free( pszFullname );
592
593 return NULL;
594 }
595
596 snprintf( pszFullname, nFullnameLen, "%s.shx", pszBasename );
597 psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess );
598 if( psSHP->fpSHX == NULL )
599 {
600 snprintf( pszFullname, nFullnameLen, "%s.SHX", pszBasename );
601 psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess );
602 }
603
604 if( psSHP->fpSHX == NULL )
605 {
606 size_t nMessageLen = strlen(pszBasename)*2+256;
607 char *pszMessage = (char *) malloc(nMessageLen);
608 snprintf( pszMessage, nMessageLen, "Unable to open %s.shx or %s.SHX."
609 "Try --config SHAPE_RESTORE_SHX true to restore or create it",
610 pszBasename, pszBasename );
611 psHooks->Error( pszMessage );
612 free( pszMessage );
613
614 psSHP->sHooks.FClose( psSHP->fpSHP );
615 free( psSHP );
616 free( pszBasename );
617 free( pszFullname );
618 return( NULL );
619 }
620
621 free( pszFullname );
622 free( pszBasename );
623
624/* -------------------------------------------------------------------- */
625/* Read the file size from the SHP file. */
626/* -------------------------------------------------------------------- */
627 pabyBuf = (uchar *) malloc(100);
628 psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHP );
629
630 psSHP->nFileSize = ((unsigned int)pabyBuf[24] * 256 * 256 * 256
631 + (unsigned int)pabyBuf[25] * 256 * 256
632 + (unsigned int)pabyBuf[26] * 256
633 + (unsigned int)pabyBuf[27]);
634 if( psSHP->nFileSize < 0xFFFFFFFFU / 2 )
635 psSHP->nFileSize *= 2;
636 else
637 psSHP->nFileSize = 0xFFFFFFFEU;
638
639/* -------------------------------------------------------------------- */
640/* Read SHX file Header info */
641/* -------------------------------------------------------------------- */
642 if( psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHX ) != 1
643 || pabyBuf[0] != 0
644 || pabyBuf[1] != 0
645 || pabyBuf[2] != 0x27
646 || (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d) )
647 {
648 psSHP->sHooks.Error( ".shx file is unreadable, or corrupt." );
649 psSHP->sHooks.FClose( psSHP->fpSHP );
650 psSHP->sHooks.FClose( psSHP->fpSHX );
651 free( psSHP );
652
653 return( NULL );
654 }
655
656 psSHP->nRecords = pabyBuf[27] + pabyBuf[26] * 256
657 + pabyBuf[25] * 256 * 256 + (pabyBuf[24] & 0x7F) * 256 * 256 * 256;
658 psSHP->nRecords = (psSHP->nRecords - 50) / 4;
659
660 psSHP->nShapeType = pabyBuf[32];
661
662 if( psSHP->nRecords < 0 || psSHP->nRecords > 256000000 )
663 {
664 char szError[200];
665
666 snprintf( szError, sizeof(szError),
667 "Record count in .shp header is %d, which seems\n"
668 "unreasonable. Assuming header is corrupt.",
669 psSHP->nRecords );
670 psSHP->sHooks.Error( szError );
671 psSHP->sHooks.FClose( psSHP->fpSHP );
672 psSHP->sHooks.FClose( psSHP->fpSHX );
673 free( psSHP );
674 free(pabyBuf);
675
676 return( NULL );
677 }
678
679 /* If a lot of records are advertized, check that the file is big enough */
680 /* to hold them */
681 if( psSHP->nRecords >= 1024 * 1024 )
682 {
683 SAOffset nFileSize;
684 psSHP->sHooks.FSeek( psSHP->fpSHX, 0, 2 );
685 nFileSize = psSHP->sHooks.FTell( psSHP->fpSHX );
686 if( nFileSize > 100 &&
687 nFileSize/2 < (SAOffset)(psSHP->nRecords * 4 + 50) )
688 {
689 psSHP->nRecords = (int)((nFileSize - 100) / 8);
690 }
691 psSHP->sHooks.FSeek( psSHP->fpSHX, 100, 0 );
692 }
693
694/* -------------------------------------------------------------------- */
695/* Read the bounds. */
696/* -------------------------------------------------------------------- */
697 if( bBigEndian ) SwapWord( 8, pabyBuf+36 );
698 memcpy( &dValue, pabyBuf+36, 8 );
699 psSHP->adBoundsMin[0] = dValue;
700
701 if( bBigEndian ) SwapWord( 8, pabyBuf+44 );
702 memcpy( &dValue, pabyBuf+44, 8 );
703 psSHP->adBoundsMin[1] = dValue;
704
705 if( bBigEndian ) SwapWord( 8, pabyBuf+52 );
706 memcpy( &dValue, pabyBuf+52, 8 );
707 psSHP->adBoundsMax[0] = dValue;
708
709 if( bBigEndian ) SwapWord( 8, pabyBuf+60 );
710 memcpy( &dValue, pabyBuf+60, 8 );
711 psSHP->adBoundsMax[1] = dValue;
712
713 if( bBigEndian ) SwapWord( 8, pabyBuf+68 ); /* z */
714 memcpy( &dValue, pabyBuf+68, 8 );
715 psSHP->adBoundsMin[2] = dValue;
716
717 if( bBigEndian ) SwapWord( 8, pabyBuf+76 );
718 memcpy( &dValue, pabyBuf+76, 8 );
719 psSHP->adBoundsMax[2] = dValue;
720
721 if( bBigEndian ) SwapWord( 8, pabyBuf+84 ); /* z */
722 memcpy( &dValue, pabyBuf+84, 8 );
723 psSHP->adBoundsMin[3] = dValue;
724
725 if( bBigEndian ) SwapWord( 8, pabyBuf+92 );
726 memcpy( &dValue, pabyBuf+92, 8 );
727 psSHP->adBoundsMax[3] = dValue;
728
729 free( pabyBuf );
730
731/* -------------------------------------------------------------------- */
732/* Read the .shx file to get the offsets to each record in */
733/* the .shp file. */
734/* -------------------------------------------------------------------- */
735 psSHP->nMaxRecords = psSHP->nRecords;
736
737 psSHP->panRecOffset = (unsigned int *)
738 malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
739 psSHP->panRecSize = (unsigned int *)
740 malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
741 if( bLazySHXLoading )
742 pabyBuf = NULL;
743 else
744 pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) );
745
746 if (psSHP->panRecOffset == NULL ||
747 psSHP->panRecSize == NULL ||
748 (!bLazySHXLoading && pabyBuf == NULL))
749 {
750 char szError[200];
751
752 snprintf( szError, sizeof(szError),
753 "Not enough memory to allocate requested memory (nRecords=%d).\n"
754 "Probably broken SHP file",
755 psSHP->nRecords );
756 psSHP->sHooks.Error( szError );
757 psSHP->sHooks.FClose( psSHP->fpSHP );
758 psSHP->sHooks.FClose( psSHP->fpSHX );
759 if (psSHP->panRecOffset) free( psSHP->panRecOffset );
760 if (psSHP->panRecSize) free( psSHP->panRecSize );
761 if (pabyBuf) free( pabyBuf );
762 free( psSHP );
763 return( NULL );
764 }
765
766 if( bLazySHXLoading )
767 {
768 memset(psSHP->panRecOffset, 0, sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
769 memset(psSHP->panRecSize, 0, sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
770 return( psSHP );
771 }
772
773 if( (int) psSHP->sHooks.FRead( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX )
774 != psSHP->nRecords )
775 {
776 char szError[200];
777
778 snprintf( szError, sizeof(szError),
779 "Failed to read all values for %d records in .shx file.",
780 psSHP->nRecords );
781 psSHP->sHooks.Error( szError );
782
783 /* SHX is short or unreadable for some reason. */
784 psSHP->sHooks.FClose( psSHP->fpSHP );
785 psSHP->sHooks.FClose( psSHP->fpSHX );
786 free( psSHP->panRecOffset );
787 free( psSHP->panRecSize );
788 free( pabyBuf );
789 free( psSHP );
790
791 return( NULL );
792 }
793
794 /* In read-only mode, we can close the SHX now */
795 if (strcmp(pszAccess, "rb") == 0)
796 {
797 psSHP->sHooks.FClose( psSHP->fpSHX );
798 psSHP->fpSHX = NULL;
799 }
800
801 for( i = 0; i < psSHP->nRecords; i++ )
802 {
803 unsigned int nOffset, nLength;
804
805 memcpy( &nOffset, pabyBuf + i * 8, 4 );
806 if( !bBigEndian ) SwapWord( 4, &nOffset );
807
808 memcpy( &nLength, pabyBuf + i * 8 + 4, 4 );
809 if( !bBigEndian ) SwapWord( 4, &nLength );
810
811 if( nOffset > (unsigned int)INT_MAX )
812 {
813 char str[128];
814 snprintf( str, sizeof(str),
815 "Invalid offset for entity %d", i);
816
817 psSHP->sHooks.Error( str );
818 SHPClose(psSHP);
819 free( pabyBuf );
820 return NULL;
821 }
822 if( nLength > (unsigned int)(INT_MAX / 2 - 4) )
823 {
824 char str[128];
825 snprintf( str, sizeof(str),
826 "Invalid length for entity %d", i);
827
828 psSHP->sHooks.Error( str );
829 SHPClose(psSHP);
830 free( pabyBuf );
831 return NULL;
832 }
833 psSHP->panRecOffset[i] = nOffset*2;
834 psSHP->panRecSize[i] = nLength*2;
835 }
836 free( pabyBuf );
837
838 return( psSHP );
839}
840
841/************************************************************************/
842/* SHPOpenLLEx() */
843/* */
844/* Open the .shp and .shx files based on the basename of the */
845/* files or either file name. It generally invokes SHPRestoreSHX() */
846/* in case when bRestoreSHX equals true. */
847/************************************************************************/
848
850SHPOpenLLEx( const char * pszLayer, const char * pszAccess, SAHooks *psHooks,
851 int bRestoreSHX )
852
853{
854 if ( !bRestoreSHX ) return SHPOpenLL ( pszLayer, pszAccess, psHooks );
855 else
856 {
857 if ( SHPRestoreSHX ( pszLayer, pszAccess, psHooks ) )
858 {
859 return SHPOpenLL ( pszLayer, pszAccess, psHooks );
860 }
861 }
862
863 return( NULL );
864}
865
866/************************************************************************/
867/* SHPRestoreSHX() */
868/* */
869/* Restore .SHX file using associated .SHP file. */
870/* */
871/************************************************************************/
872
873int SHPAPI_CALL
874SHPRestoreSHX ( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
875
876{
877 char *pszFullname, *pszBasename;
878 SAFile fpSHP, fpSHX;
879
880
881 uchar *pabyBuf;
882 int i;
883 size_t nFullnameLen;
884 unsigned int nSHPFilesize;
885
886 size_t nMessageLen;
887 char *pszMessage;
888
889 unsigned int nCurrentRecordOffset = 0;
890 unsigned int nCurrentSHPOffset = 100;
891 size_t nRealSHXContentSize = 100;
892
893 const char pszSHXAccess[] = "w+b";
894 char *pabySHXHeader;
895 char abyReadedRecord[8];
896 unsigned int niRecord = 0;
897 unsigned int nRecordLength = 0;
898 unsigned int nRecordOffset = 50;
899
900/* -------------------------------------------------------------------- */
901/* Ensure the access string is one of the legal ones. We */
902/* ensure the result string indicates binary to avoid common */
903/* problems on Windows. */
904/* -------------------------------------------------------------------- */
905 if( strcmp(pszAccess,"rb+") == 0 || strcmp(pszAccess,"r+b") == 0
906 || strcmp(pszAccess,"r+") == 0 )
907 pszAccess = "r+b";
908 else
909 {
910 pszAccess = "rb";
911 }
912
913/* -------------------------------------------------------------------- */
914/* Establish the byte order on this machine. */
915/* -------------------------------------------------------------------- */
916#if !defined(bBigEndian)
917 i = 1;
918 if( *((uchar *) &i) == 1 )
919 bBigEndian = FALSE;
920 else
921 bBigEndian = TRUE;
922#endif
923
924/* -------------------------------------------------------------------- */
925/* Compute the base (layer) name. If there is any extension */
926/* on the passed in filename we will strip it off. */
927/* -------------------------------------------------------------------- */
928 pszBasename = (char *) malloc(strlen(pszLayer)+5);
929 strcpy( pszBasename, pszLayer );
930 for( i = (int)strlen(pszBasename)-1;
931 i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
932 && pszBasename[i] != '\\';
933 i-- ) {}
934
935 if( pszBasename[i] == '.' )
936 pszBasename[i] = '\0';
937
938/* -------------------------------------------------------------------- */
939/* Open the .shp file. Note that files pulled from */
940/* a PC to Unix with upper case filenames won't work! */
941/* -------------------------------------------------------------------- */
942 nFullnameLen = strlen(pszBasename) + 5;
943 pszFullname = (char *) malloc(nFullnameLen);
944 snprintf( pszFullname, nFullnameLen, "%s.shp", pszBasename ) ;
945 fpSHP = psHooks->FOpen(pszFullname, pszAccess );
946 if( fpSHP == NULL )
947 {
948 snprintf( pszFullname, nFullnameLen, "%s.SHP", pszBasename );
949 fpSHP = psHooks->FOpen(pszFullname, pszAccess );
950 }
951
952 if( fpSHP == NULL )
953 {
954 nMessageLen = strlen(pszBasename)*2+256;
955 pszMessage = (char *) malloc(nMessageLen);
956 snprintf( pszMessage, nMessageLen, "Unable to open %s.shp or %s.SHP.",
957 pszBasename, pszBasename );
958 psHooks->Error( pszMessage );
959 free( pszMessage );
960
961 free( pszBasename );
962 free( pszFullname );
963
964 return( 0 );
965 }
966
967/* -------------------------------------------------------------------- */
968/* Read the file size from the SHP file. */
969/* -------------------------------------------------------------------- */
970 pabyBuf = (uchar *) malloc(100);
971 psHooks->FRead( pabyBuf, 100, 1, fpSHP );
972
973 nSHPFilesize = ((unsigned int)pabyBuf[24] * 256 * 256 * 256
974 + (unsigned int)pabyBuf[25] * 256 * 256
975 + (unsigned int)pabyBuf[26] * 256
976 + (unsigned int)pabyBuf[27]);
977 if( nSHPFilesize < 0xFFFFFFFFU / 2 )
978 nSHPFilesize *= 2;
979 else
980 nSHPFilesize = 0xFFFFFFFEU;
981
982 snprintf( pszFullname, nFullnameLen, "%s.shx", pszBasename );
983 fpSHX = psHooks->FOpen( pszFullname, pszSHXAccess );
984
985 if( fpSHX == NULL )
986 {
987 nMessageLen = strlen( pszBasename ) * 2 + 256;
988 pszMessage = (char *) malloc( nMessageLen );
989 snprintf( pszMessage, nMessageLen, "Error opening file %s.shx for writing",
990 pszBasename );
991 psHooks->Error( pszMessage );
992 free( pszMessage );
993
994 psHooks->FClose( fpSHX );
995
996 free( pabyBuf );
997 free( pszBasename );
998 free( pszFullname );
999
1000 return( 0 );
1001 }
1002
1003/* -------------------------------------------------------------------- */
1004/* Open SHX and create it using SHP file content. */
1005/* -------------------------------------------------------------------- */
1006 psHooks->FSeek( fpSHP, 100, 0 );
1007 pabySHXHeader = (char *) malloc ( 100 );
1008 memcpy( pabySHXHeader, pabyBuf, 100 );
1009 psHooks->FWrite( pabySHXHeader, 100, 1, fpSHX );
1010
1011 while( nCurrentSHPOffset < nSHPFilesize )
1012 {
1013 if( psHooks->FRead( &niRecord, 4, 1, fpSHP ) == 1 &&
1014 psHooks->FRead( &nRecordLength, 4, 1, fpSHP ) == 1)
1015 {
1016 if( !bBigEndian ) SwapWord( 4, &nRecordOffset );
1017 memcpy( abyReadedRecord, &nRecordOffset, 4 );
1018 memcpy( abyReadedRecord + 4, &nRecordLength, 4 );
1019
1020 psHooks->FWrite( abyReadedRecord, 8, 1, fpSHX );
1021
1022 if ( !bBigEndian ) SwapWord( 4, &nRecordOffset );
1023 if ( !bBigEndian ) SwapWord( 4, &nRecordLength );
1024 nRecordOffset += nRecordLength + 4;
1025 nCurrentRecordOffset += 8;
1026 nCurrentSHPOffset += 8 + nRecordLength * 2;
1027
1028 psHooks->FSeek( fpSHP, nCurrentSHPOffset, 0 );
1029 nRealSHXContentSize += 8;
1030 }
1031 else
1032 {
1033 nMessageLen = strlen( pszBasename ) * 2 + 256;
1034 pszMessage = (char *) malloc( nMessageLen );
1035 snprintf( pszMessage, nMessageLen, "Error parsing .shp to restore .shx" );
1036 psHooks->Error( pszMessage );
1037 free( pszMessage );
1038
1039 psHooks->FClose( fpSHX );
1040 psHooks->FClose( fpSHP );
1041
1042 free( pabySHXHeader );
1043 free( pszBasename );
1044 free( pszFullname );
1045
1046 return( 0 );
1047 }
1048 }
1049
1050 nRealSHXContentSize /= 2; // Bytes counted -> WORDs
1051 if( !bBigEndian ) SwapWord( 4, &nRealSHXContentSize );
1052 psHooks->FSeek( fpSHX, 24, 0 );
1053 psHooks->FWrite( &nRealSHXContentSize, 4, 1, fpSHX );
1054
1055 psHooks->FClose( fpSHP );
1056 psHooks->FClose( fpSHX );
1057
1058 free ( pabyBuf );
1059 free ( pszFullname );
1060 free ( pszBasename );
1061 free ( pabySHXHeader );
1062
1063 return( 1 );
1064}
1065
1066/************************************************************************/
1067/* SHPClose() */
1068/* */
1069/* Close the .shp and .shx files. */
1070/************************************************************************/
1071
1072void SHPAPI_CALL
1074
1075{
1076 if( psSHP == NULL )
1077 return;
1078
1079/* -------------------------------------------------------------------- */
1080/* Update the header if we have modified anything. */
1081/* -------------------------------------------------------------------- */
1082 if( psSHP->bUpdated )
1083 SHPWriteHeader( psSHP );
1084
1085/* -------------------------------------------------------------------- */
1086/* Free all resources, and close files. */
1087/* -------------------------------------------------------------------- */
1088 free( psSHP->panRecOffset );
1089 free( psSHP->panRecSize );
1090
1091 if ( psSHP->fpSHX != NULL)
1092 psSHP->sHooks.FClose( psSHP->fpSHX );
1093 psSHP->sHooks.FClose( psSHP->fpSHP );
1094
1095 if( psSHP->pabyRec != NULL )
1096 {
1097 free( psSHP->pabyRec );
1098 }
1099
1100 if( psSHP->pabyObjectBuf != NULL )
1101 {
1102 free( psSHP->pabyObjectBuf );
1103 }
1104 if( psSHP->psCachedObject != NULL )
1105 {
1106 free( psSHP->psCachedObject );
1107 }
1108
1109 free( psSHP );
1110}
1111
1112/************************************************************************/
1113/* SHPSetFastModeReadObject() */
1114/************************************************************************/
1115
1116/* If setting bFastMode = TRUE, the content of SHPReadObject() is owned by the SHPHandle. */
1117/* So you cannot have 2 valid instances of SHPReadObject() simultaneously. */
1118/* The SHPObject padfZ and padfM members may be NULL depending on the geometry */
1119/* type. It is illegal to free at hand any of the pointer members of the SHPObject structure */
1121{
1122 if( bFastMode )
1123 {
1124 if( hSHP->psCachedObject == NULL )
1125 {
1126 hSHP->psCachedObject = (SHPObject*) calloc(1, sizeof(SHPObject));
1127 assert( hSHP->psCachedObject != NULL );
1128 }
1129 }
1130
1131 hSHP->bFastModeReadObject = bFastMode;
1132}
1133
1134/************************************************************************/
1135/* SHPGetInfo() */
1136/* */
1137/* Fetch general information about the shape file. */
1138/************************************************************************/
1139
1140void SHPAPI_CALL
1141SHPGetInfo(SHPHandle psSHP, int * pnEntities, int * pnShapeType,
1142 double * padfMinBound, double * padfMaxBound )
1143
1144{
1145 int i;
1146
1147 if( psSHP == NULL )
1148 return;
1149
1150 if( pnEntities != NULL )
1151 *pnEntities = psSHP->nRecords;
1152
1153 if( pnShapeType != NULL )
1154 *pnShapeType = psSHP->nShapeType;
1155
1156 for( i = 0; i < 4; i++ )
1157 {
1158 if( padfMinBound != NULL )
1159 padfMinBound[i] = psSHP->adBoundsMin[i];
1160 if( padfMaxBound != NULL )
1161 padfMaxBound[i] = psSHP->adBoundsMax[i];
1162 }
1163}
1164
1165/************************************************************************/
1166/* SHPCreate() */
1167/* */
1168/* Create a new shape file and return a handle to the open */
1169/* shape file with read/write access. */
1170/************************************************************************/
1171
1173SHPCreate( const char * pszLayer, int nShapeType )
1174
1175{
1176 SAHooks sHooks;
1177
1178 SASetupDefaultHooks( &sHooks );
1179
1180 return SHPCreateLL( pszLayer, nShapeType, &sHooks );
1181}
1182
1183/************************************************************************/
1184/* SHPCreate() */
1185/* */
1186/* Create a new shape file and return a handle to the open */
1187/* shape file with read/write access. */
1188/************************************************************************/
1189
1191SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
1192
1193{
1194 char *pszBasename = NULL, *pszFullname = NULL;
1195 int i;
1196 SAFile fpSHP = NULL, fpSHX = NULL;
1197 uchar abyHeader[100];
1198 int32 i32;
1199 double dValue;
1200 size_t nFullnameLen;
1201
1202/* -------------------------------------------------------------------- */
1203/* Establish the byte order on this system. */
1204/* -------------------------------------------------------------------- */
1205#if !defined(bBigEndian)
1206 i = 1;
1207 if( *((uchar *) &i) == 1 )
1208 bBigEndian = FALSE;
1209 else
1210 bBigEndian = TRUE;
1211#endif
1212
1213/* -------------------------------------------------------------------- */
1214/* Compute the base (layer) name. If there is any extension */
1215/* on the passed in filename we will strip it off. */
1216/* -------------------------------------------------------------------- */
1217 pszBasename = (char *) malloc(strlen(pszLayer)+5);
1218 strcpy( pszBasename, pszLayer );
1219 for( i = (int)strlen(pszBasename)-1;
1220 i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
1221 && pszBasename[i] != '\\';
1222 i-- ) {}
1223
1224 if( pszBasename[i] == '.' )
1225 pszBasename[i] = '\0';
1226
1227/* -------------------------------------------------------------------- */
1228/* Open the two files so we can write their headers. */
1229/* -------------------------------------------------------------------- */
1230 nFullnameLen = strlen(pszBasename) + 5;
1231 pszFullname = (char *) malloc(nFullnameLen);
1232 snprintf( pszFullname, nFullnameLen, "%s.shp", pszBasename );
1233 fpSHP = psHooks->FOpen(pszFullname, "wb" );
1234 if( fpSHP == NULL )
1235 {
1236 psHooks->Error( "Failed to create file .shp file." );
1237 goto error;
1238 }
1239
1240 snprintf( pszFullname, nFullnameLen, "%s.shx", pszBasename );
1241 fpSHX = psHooks->FOpen(pszFullname, "wb" );
1242 if( fpSHX == NULL )
1243 {
1244 psHooks->Error( "Failed to create file .shx file." );
1245 goto error;
1246 }
1247
1248 free( pszFullname ); pszFullname = NULL;
1249 free( pszBasename ); pszBasename = NULL;
1250
1251/* -------------------------------------------------------------------- */
1252/* Prepare header block for .shp file. */
1253/* -------------------------------------------------------------------- */
1254 for( i = 0; i < 100; i++ )
1255 abyHeader[i] = 0;
1256
1257 abyHeader[2] = 0x27; /* magic cookie */
1258 abyHeader[3] = 0x0a;
1259
1260 i32 = 50; /* file size */
1261 ByteCopy( &i32, abyHeader+24, 4 );
1262 if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
1263
1264 i32 = 1000; /* version */
1265 ByteCopy( &i32, abyHeader+28, 4 );
1266 if( bBigEndian ) SwapWord( 4, abyHeader+28 );
1267
1268 i32 = nShapeType; /* shape type */
1269 ByteCopy( &i32, abyHeader+32, 4 );
1270 if( bBigEndian ) SwapWord( 4, abyHeader+32 );
1271
1272 dValue = 0.0; /* set bounds */
1273 ByteCopy( &dValue, abyHeader+36, 8 );
1274 ByteCopy( &dValue, abyHeader+44, 8 );
1275 ByteCopy( &dValue, abyHeader+52, 8 );
1276 ByteCopy( &dValue, abyHeader+60, 8 );
1277
1278/* -------------------------------------------------------------------- */
1279/* Write .shp file header. */
1280/* -------------------------------------------------------------------- */
1281 if( psHooks->FWrite( abyHeader, 100, 1, fpSHP ) != 1 )
1282 {
1283 psHooks->Error( "Failed to write .shp header." );
1284 goto error;
1285 }
1286
1287/* -------------------------------------------------------------------- */
1288/* Prepare, and write .shx file header. */
1289/* -------------------------------------------------------------------- */
1290 i32 = 50; /* file size */
1291 ByteCopy( &i32, abyHeader+24, 4 );
1292 if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
1293
1294 if( psHooks->FWrite( abyHeader, 100, 1, fpSHX ) != 1 )
1295 {
1296 psHooks->Error( "Failed to write .shx header." );
1297 goto error;
1298 }
1299
1300/* -------------------------------------------------------------------- */
1301/* Close the files, and then open them as regular existing files. */
1302/* -------------------------------------------------------------------- */
1303 psHooks->FClose( fpSHP );
1304 psHooks->FClose( fpSHX );
1305
1306 return( SHPOpenLL( pszLayer, "r+b", psHooks ) );
1307
1308error:
1309 if (pszFullname) free(pszFullname);
1310 if (pszBasename) free(pszBasename);
1311 if (fpSHP) psHooks->FClose( fpSHP );
1312 if (fpSHX) psHooks->FClose( fpSHX );
1313 return NULL;
1314}
1315
1316/************************************************************************/
1317/* _SHPSetBounds() */
1318/* */
1319/* Compute a bounds rectangle for a shape, and set it into the */
1320/* indicated location in the record. */
1321/************************************************************************/
1322
1323static void _SHPSetBounds( uchar * pabyRec, SHPObject * psShape )
1324
1325{
1326 ByteCopy( &(psShape->dfXMin), pabyRec + 0, 8 );
1327 ByteCopy( &(psShape->dfYMin), pabyRec + 8, 8 );
1328 ByteCopy( &(psShape->dfXMax), pabyRec + 16, 8 );
1329 ByteCopy( &(psShape->dfYMax), pabyRec + 24, 8 );
1330
1331 if( bBigEndian )
1332 {
1333 SwapWord( 8, pabyRec + 0 );
1334 SwapWord( 8, pabyRec + 8 );
1335 SwapWord( 8, pabyRec + 16 );
1336 SwapWord( 8, pabyRec + 24 );
1337 }
1338}
1339
1340/************************************************************************/
1341/* SHPComputeExtents() */
1342/* */
1343/* Recompute the extents of a shape. Automatically done by */
1344/* SHPCreateObject(). */
1345/************************************************************************/
1346
1347void SHPAPI_CALL
1349
1350{
1351 int i;
1352
1353/* -------------------------------------------------------------------- */
1354/* Build extents for this object. */
1355/* -------------------------------------------------------------------- */
1356 if( psObject->nVertices > 0 )
1357 {
1358 psObject->dfXMin = psObject->dfXMax = psObject->padfX[0];
1359 psObject->dfYMin = psObject->dfYMax = psObject->padfY[0];
1360 psObject->dfZMin = psObject->dfZMax = psObject->padfZ[0];
1361 psObject->dfMMin = psObject->dfMMax = psObject->padfM[0];
1362 }
1363
1364 for( i = 0; i < psObject->nVertices; i++ )
1365 {
1366 psObject->dfXMin = MIN(psObject->dfXMin, psObject->padfX[i]);
1367 psObject->dfYMin = MIN(psObject->dfYMin, psObject->padfY[i]);
1368 psObject->dfZMin = MIN(psObject->dfZMin, psObject->padfZ[i]);
1369 psObject->dfMMin = MIN(psObject->dfMMin, psObject->padfM[i]);
1370
1371 psObject->dfXMax = MAX(psObject->dfXMax, psObject->padfX[i]);
1372 psObject->dfYMax = MAX(psObject->dfYMax, psObject->padfY[i]);
1373 psObject->dfZMax = MAX(psObject->dfZMax, psObject->padfZ[i]);
1374 psObject->dfMMax = MAX(psObject->dfMMax, psObject->padfM[i]);
1375 }
1376}
1377
1378/************************************************************************/
1379/* SHPCreateObject() */
1380/* */
1381/* Create a shape object. It should be freed with */
1382/* SHPDestroyObject(). */
1383/************************************************************************/
1384
1386SHPCreateObject( int nSHPType, int nShapeId, int nParts,
1387 const int * panPartStart, const int * panPartType,
1388 int nVertices, const double *padfX, const double *padfY,
1389 const double * padfZ, const double * padfM )
1390
1391{
1392 SHPObject *psObject;
1393 int i, bHasM, bHasZ;
1394
1395 psObject = (SHPObject *) calloc(1,sizeof(SHPObject));
1396 psObject->nSHPType = nSHPType;
1397 psObject->nShapeId = nShapeId;
1399
1400/* -------------------------------------------------------------------- */
1401/* Establish whether this shape type has M, and Z values. */
1402/* -------------------------------------------------------------------- */
1404 || nSHPType == SHPT_POINTM
1407 {
1408 bHasM = TRUE;
1409 bHasZ = FALSE;
1410 }
1411 else if( nSHPType == SHPT_ARCZ
1412 || nSHPType == SHPT_POINTZ
1416 {
1417 bHasM = TRUE;
1418 bHasZ = TRUE;
1419 }
1420 else
1421 {
1422 bHasM = FALSE;
1424 }
1425
1426/* -------------------------------------------------------------------- */
1427/* Capture parts. Note that part type is optional, and */
1428/* defaults to ring. */
1429/* -------------------------------------------------------------------- */
1434 {
1435 psObject->nParts = MAX(1,nParts);
1436
1437 psObject->panPartStart = (int *)
1438 calloc(sizeof(int), psObject->nParts);
1439 psObject->panPartType = (int *)
1440 malloc(sizeof(int) * psObject->nParts);
1441
1442 psObject->panPartStart[0] = 0;
1443 psObject->panPartType[0] = SHPP_RING;
1444
1445 for( i = 0; i < nParts; i++ )
1446 {
1447 if( panPartStart != NULL )
1448 psObject->panPartStart[i] = panPartStart[i];
1449
1450 if( panPartType != NULL )
1451 psObject->panPartType[i] = panPartType[i];
1452 else
1453 psObject->panPartType[i] = SHPP_RING;
1454 }
1455
1456 if( psObject->panPartStart[0] != 0 )
1457 psObject->panPartStart[0] = 0;
1458 }
1459
1460/* -------------------------------------------------------------------- */
1461/* Capture vertices. Note that X, Y, Z and M are optional. */
1462/* -------------------------------------------------------------------- */
1463 if( nVertices > 0 )
1464 {
1465 psObject->padfX = (double *) calloc(sizeof(double),nVertices);
1466 psObject->padfY = (double *) calloc(sizeof(double),nVertices);
1467 psObject->padfZ = (double *) calloc(sizeof(double),nVertices);
1468 psObject->padfM = (double *) calloc(sizeof(double),nVertices);
1469
1470 for( i = 0; i < nVertices; i++ )
1471 {
1472 if( padfX != NULL )
1473 psObject->padfX[i] = padfX[i];
1474 if( padfY != NULL )
1475 psObject->padfY[i] = padfY[i];
1476 if( padfZ != NULL && bHasZ )
1477 psObject->padfZ[i] = padfZ[i];
1478 if( padfM != NULL && bHasM )
1479 psObject->padfM[i] = padfM[i];
1480 }
1481 if( padfM != NULL && bHasM )
1482 psObject->bMeasureIsUsed = TRUE;
1483 }
1484
1485/* -------------------------------------------------------------------- */
1486/* Compute the extents. */
1487/* -------------------------------------------------------------------- */
1490
1491 return( psObject );
1492}
1493
1494/************************************************************************/
1495/* SHPCreateSimpleObject() */
1496/* */
1497/* Create a simple (common) shape object. Destroy with */
1498/* SHPDestroyObject(). */
1499/************************************************************************/
1500
1503 const double * padfX, const double * padfY,
1504 const double * padfZ )
1505
1506{
1507 return( SHPCreateObject( nSHPType, -1, 0, NULL, NULL,
1508 nVertices, padfX, padfY, padfZ, NULL ) );
1509}
1510
1511/************************************************************************/
1512/* SHPWriteObject() */
1513/* */
1514/* Write out the vertices of a new structure. Note that it is */
1515/* only possible to write vertices at the end of the file. */
1516/************************************************************************/
1517
1518int SHPAPI_CALL
1520
1521{
1522 unsigned int nRecordOffset, nRecordSize=0;
1523 int i;
1524 uchar *pabyRec;
1525 int32 i32;
1526 int bExtendFile = FALSE;
1527
1528 psSHP->bUpdated = TRUE;
1529
1530/* -------------------------------------------------------------------- */
1531/* Ensure that shape object matches the type of the file it is */
1532/* being written to. */
1533/* -------------------------------------------------------------------- */
1534 assert( psObject->nSHPType == psSHP->nShapeType
1535 || psObject->nSHPType == SHPT_NULL );
1536
1537/* -------------------------------------------------------------------- */
1538/* Ensure that -1 is used for appends. Either blow an */
1539/* assertion, or if they are disabled, set the shapeid to -1 */
1540/* for appends. */
1541/* -------------------------------------------------------------------- */
1542 assert( nShapeId == -1
1543 || (nShapeId >= 0 && nShapeId < psSHP->nRecords) );
1544
1545 if( nShapeId != -1 && nShapeId >= psSHP->nRecords )
1546 nShapeId = -1;
1547
1548/* -------------------------------------------------------------------- */
1549/* Add the new entity to the in memory index. */
1550/* -------------------------------------------------------------------- */
1551 if( nShapeId == -1 && psSHP->nRecords+1 > psSHP->nMaxRecords )
1552 {
1553 int nNewMaxRecords = psSHP->nMaxRecords + psSHP->nMaxRecords / 3 + 100;
1554 unsigned int* panRecOffsetNew;
1555 unsigned int* panRecSizeNew;
1556
1557 panRecOffsetNew = (unsigned int *)
1558 SfRealloc(psSHP->panRecOffset,sizeof(unsigned int) * nNewMaxRecords );
1559 if( panRecOffsetNew == NULL )
1560 return -1;
1561 psSHP->panRecOffset = panRecOffsetNew;
1562
1563 panRecSizeNew = (unsigned int *)
1564 SfRealloc(psSHP->panRecSize,sizeof(unsigned int) * nNewMaxRecords );
1565 if( panRecSizeNew == NULL )
1566 return -1;
1567 psSHP->panRecSize = panRecSizeNew;
1568
1569 psSHP->nMaxRecords = nNewMaxRecords;
1570 }
1571
1572/* -------------------------------------------------------------------- */
1573/* Initialize record. */
1574/* -------------------------------------------------------------------- */
1575 pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double)
1576 + psObject->nParts * 8 + 128);
1577 if( pabyRec == NULL )
1578 return -1;
1579
1580/* -------------------------------------------------------------------- */
1581/* Extract vertices for a Polygon or Arc. */
1582/* -------------------------------------------------------------------- */
1583 if( psObject->nSHPType == SHPT_POLYGON
1584 || psObject->nSHPType == SHPT_POLYGONZ
1585 || psObject->nSHPType == SHPT_POLYGONM
1586 || psObject->nSHPType == SHPT_ARC
1587 || psObject->nSHPType == SHPT_ARCZ
1588 || psObject->nSHPType == SHPT_ARCM
1589 || psObject->nSHPType == SHPT_MULTIPATCH )
1590 {
1591 int32 nPoints, nParts;
1592
1593 nPoints = psObject->nVertices;
1594 nParts = psObject->nParts;
1595
1596 _SHPSetBounds( pabyRec + 12, psObject );
1597
1598 if( bBigEndian ) SwapWord( 4, &nPoints );
1599 if( bBigEndian ) SwapWord( 4, &nParts );
1600
1601 ByteCopy( &nPoints, pabyRec + 40 + 8, 4 );
1602 ByteCopy( &nParts, pabyRec + 36 + 8, 4 );
1603
1604 nRecordSize = 52;
1605
1606 /*
1607 * Write part start positions.
1608 */
1609 ByteCopy( psObject->panPartStart, pabyRec + 44 + 8,
1610 4 * psObject->nParts );
1611 for( i = 0; i < psObject->nParts; i++ )
1612 {
1613 if( bBigEndian ) SwapWord( 4, pabyRec + 44 + 8 + 4*i );
1614 nRecordSize += 4;
1615 }
1616
1617 /*
1618 * Write multipatch part types if needed.
1619 */
1620 if( psObject->nSHPType == SHPT_MULTIPATCH )
1621 {
1622 memcpy( pabyRec + nRecordSize, psObject->panPartType,
1623 4*psObject->nParts );
1624 for( i = 0; i < psObject->nParts; i++ )
1625 {
1626 if( bBigEndian ) SwapWord( 4, pabyRec + nRecordSize );
1627 nRecordSize += 4;
1628 }
1629 }
1630
1631 /*
1632 * Write the (x,y) vertex values.
1633 */
1634 for( i = 0; i < psObject->nVertices; i++ )
1635 {
1636 ByteCopy( psObject->padfX + i, pabyRec + nRecordSize, 8 );
1637 ByteCopy( psObject->padfY + i, pabyRec + nRecordSize + 8, 8 );
1638
1639 if( bBigEndian )
1640 SwapWord( 8, pabyRec + nRecordSize );
1641
1642 if( bBigEndian )
1643 SwapWord( 8, pabyRec + nRecordSize + 8 );
1644
1645 nRecordSize += 2 * 8;
1646 }
1647
1648 /*
1649 * Write the Z coordinates (if any).
1650 */
1651 if( psObject->nSHPType == SHPT_POLYGONZ
1652 || psObject->nSHPType == SHPT_ARCZ
1653 || psObject->nSHPType == SHPT_MULTIPATCH )
1654 {
1655 ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
1656 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1657 nRecordSize += 8;
1658
1659 ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
1660 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1661 nRecordSize += 8;
1662
1663 for( i = 0; i < psObject->nVertices; i++ )
1664 {
1665 ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
1666 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1667 nRecordSize += 8;
1668 }
1669 }
1670
1671 /*
1672 * Write the M values, if any.
1673 */
1674 if( psObject->bMeasureIsUsed
1675 && (psObject->nSHPType == SHPT_POLYGONM
1676 || psObject->nSHPType == SHPT_ARCM
1678 || psObject->nSHPType == SHPT_MULTIPATCH
1679#endif
1680 || psObject->nSHPType == SHPT_POLYGONZ
1681 || psObject->nSHPType == SHPT_ARCZ) )
1682 {
1683 ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
1684 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1685 nRecordSize += 8;
1686
1687 ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
1688 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1689 nRecordSize += 8;
1690
1691 for( i = 0; i < psObject->nVertices; i++ )
1692 {
1693 ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
1694 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1695 nRecordSize += 8;
1696 }
1697 }
1698 }
1699
1700/* -------------------------------------------------------------------- */
1701/* Extract vertices for a MultiPoint. */
1702/* -------------------------------------------------------------------- */
1703 else if( psObject->nSHPType == SHPT_MULTIPOINT
1704 || psObject->nSHPType == SHPT_MULTIPOINTZ
1705 || psObject->nSHPType == SHPT_MULTIPOINTM )
1706 {
1707 int32 nPoints;
1708
1709 nPoints = psObject->nVertices;
1710
1711 _SHPSetBounds( pabyRec + 12, psObject );
1712
1713 if( bBigEndian ) SwapWord( 4, &nPoints );
1714 ByteCopy( &nPoints, pabyRec + 44, 4 );
1715
1716 for( i = 0; i < psObject->nVertices; i++ )
1717 {
1718 ByteCopy( psObject->padfX + i, pabyRec + 48 + i*16, 8 );
1719 ByteCopy( psObject->padfY + i, pabyRec + 48 + i*16 + 8, 8 );
1720
1721 if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 );
1722 if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 + 8 );
1723 }
1724
1725 nRecordSize = 48 + 16 * psObject->nVertices;
1726
1727 if( psObject->nSHPType == SHPT_MULTIPOINTZ )
1728 {
1729 ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
1730 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1731 nRecordSize += 8;
1732
1733 ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
1734 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1735 nRecordSize += 8;
1736
1737 for( i = 0; i < psObject->nVertices; i++ )
1738 {
1739 ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
1740 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1741 nRecordSize += 8;
1742 }
1743 }
1744
1745 if( psObject->bMeasureIsUsed
1746 && (psObject->nSHPType == SHPT_MULTIPOINTZ
1747 || psObject->nSHPType == SHPT_MULTIPOINTM) )
1748 {
1749 ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
1750 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1751 nRecordSize += 8;
1752
1753 ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
1754 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1755 nRecordSize += 8;
1756
1757 for( i = 0; i < psObject->nVertices; i++ )
1758 {
1759 ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
1760 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1761 nRecordSize += 8;
1762 }
1763 }
1764 }
1765
1766/* -------------------------------------------------------------------- */
1767/* Write point. */
1768/* -------------------------------------------------------------------- */
1769 else if( psObject->nSHPType == SHPT_POINT
1770 || psObject->nSHPType == SHPT_POINTZ
1771 || psObject->nSHPType == SHPT_POINTM )
1772 {
1773 ByteCopy( psObject->padfX, pabyRec + 12, 8 );
1774 ByteCopy( psObject->padfY, pabyRec + 20, 8 );
1775
1776 if( bBigEndian ) SwapWord( 8, pabyRec + 12 );
1777 if( bBigEndian ) SwapWord( 8, pabyRec + 20 );
1778
1779 nRecordSize = 28;
1780
1781 if( psObject->nSHPType == SHPT_POINTZ )
1782 {
1783 ByteCopy( psObject->padfZ, pabyRec + nRecordSize, 8 );
1784 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1785 nRecordSize += 8;
1786 }
1787
1788 if( psObject->bMeasureIsUsed
1789 && (psObject->nSHPType == SHPT_POINTZ
1790 || psObject->nSHPType == SHPT_POINTM) )
1791 {
1792 ByteCopy( psObject->padfM, pabyRec + nRecordSize, 8 );
1793 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
1794 nRecordSize += 8;
1795 }
1796 }
1797
1798/* -------------------------------------------------------------------- */
1799/* Not much to do for null geometries. */
1800/* -------------------------------------------------------------------- */
1801 else if( psObject->nSHPType == SHPT_NULL )
1802 {
1803 nRecordSize = 12;
1804 }
1805
1806 else
1807 {
1808 /* unknown type */
1809 assert( FALSE );
1810 }
1811
1812/* -------------------------------------------------------------------- */
1813/* Establish where we are going to put this record. If we are */
1814/* rewriting and existing record, and it will fit, then put it */
1815/* back where the original came from. Otherwise write at the end. */
1816/* -------------------------------------------------------------------- */
1817 if( nShapeId == -1 || psSHP->panRecSize[nShapeId] < nRecordSize-8 )
1818 {
1819 unsigned int nExpectedSize = psSHP->nFileSize + nRecordSize;
1820 if( nExpectedSize < psSHP->nFileSize ) // due to unsigned int overflow
1821 {
1822 char str[128];
1823 snprintf( str, sizeof(str), "Failed to write shape object. "
1824 "File size cannot reach %u + %u.",
1825 psSHP->nFileSize, nRecordSize );
1826 psSHP->sHooks.Error( str );
1827 free( pabyRec );
1828 return -1;
1829 }
1830
1831 bExtendFile = TRUE;
1832 nRecordOffset = psSHP->nFileSize;
1833 }
1834 else
1835 {
1836 nRecordOffset = psSHP->panRecOffset[nShapeId];
1837 }
1838
1839/* -------------------------------------------------------------------- */
1840/* Set the shape type, record number, and record size. */
1841/* -------------------------------------------------------------------- */
1842 i32 = (nShapeId < 0) ? psSHP->nRecords+1 : nShapeId+1; /* record # */
1843 if( !bBigEndian ) SwapWord( 4, &i32 );
1844 ByteCopy( &i32, pabyRec, 4 );
1845
1846 i32 = (nRecordSize-8)/2; /* record size */
1847 if( !bBigEndian ) SwapWord( 4, &i32 );
1848 ByteCopy( &i32, pabyRec + 4, 4 );
1849
1850 i32 = psObject->nSHPType; /* shape type */
1851 if( bBigEndian ) SwapWord( 4, &i32 );
1852 ByteCopy( &i32, pabyRec + 8, 4 );
1853
1854/* -------------------------------------------------------------------- */
1855/* Write out record. */
1856/* -------------------------------------------------------------------- */
1857 if( psSHP->sHooks.FSeek( psSHP->fpSHP, nRecordOffset, 0 ) != 0 )
1858 {
1859 psSHP->sHooks.Error( "Error in psSHP->sHooks.FSeek() while writing object to .shp file." );
1860 free( pabyRec );
1861 return -1;
1862 }
1863 if( psSHP->sHooks.FWrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 )
1864 {
1865 psSHP->sHooks.Error( "Error in psSHP->sHooks.Fwrite() while writing object to .shp file." );
1866 free( pabyRec );
1867 return -1;
1868 }
1869
1870 free( pabyRec );
1871
1872 if( bExtendFile )
1873 {
1874 if( nShapeId == -1 )
1875 nShapeId = psSHP->nRecords++;
1876
1877 psSHP->panRecOffset[nShapeId] = psSHP->nFileSize;
1878 psSHP->nFileSize += nRecordSize;
1879 }
1880 psSHP->panRecSize[nShapeId] = nRecordSize-8;
1881
1882/* -------------------------------------------------------------------- */
1883/* Expand file wide bounds based on this shape. */
1884/* -------------------------------------------------------------------- */
1885 if( psSHP->adBoundsMin[0] == 0.0
1886 && psSHP->adBoundsMax[0] == 0.0
1887 && psSHP->adBoundsMin[1] == 0.0
1888 && psSHP->adBoundsMax[1] == 0.0 )
1889 {
1890 if( psObject->nSHPType == SHPT_NULL || psObject->nVertices == 0 )
1891 {
1892 psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = 0.0;
1893 psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = 0.0;
1894 psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = 0.0;
1895 psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = 0.0;
1896 }
1897 else
1898 {
1899 psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = psObject->padfX[0];
1900 psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = psObject->padfY[0];
1901 psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ ? psObject->padfZ[0] : 0.0;
1902 psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM ? psObject->padfM[0] : 0.0;
1903 }
1904 }
1905
1906 for( i = 0; i < psObject->nVertices; i++ )
1907 {
1908 psSHP->adBoundsMin[0] = MIN(psSHP->adBoundsMin[0],psObject->padfX[i]);
1909 psSHP->adBoundsMin[1] = MIN(psSHP->adBoundsMin[1],psObject->padfY[i]);
1910 psSHP->adBoundsMax[0] = MAX(psSHP->adBoundsMax[0],psObject->padfX[i]);
1911 psSHP->adBoundsMax[1] = MAX(psSHP->adBoundsMax[1],psObject->padfY[i]);
1912 if( psObject->padfZ )
1913 {
1914 psSHP->adBoundsMin[2] = MIN(psSHP->adBoundsMin[2],psObject->padfZ[i]);
1915 psSHP->adBoundsMax[2] = MAX(psSHP->adBoundsMax[2],psObject->padfZ[i]);
1916 }
1917 if( psObject->padfM )
1918 {
1919 psSHP->adBoundsMin[3] = MIN(psSHP->adBoundsMin[3],psObject->padfM[i]);
1920 psSHP->adBoundsMax[3] = MAX(psSHP->adBoundsMax[3],psObject->padfM[i]);
1921 }
1922 }
1923
1924 return( nShapeId );
1925}
1926
1927/************************************************************************/
1928/* SHPAllocBuffer() */
1929/************************************************************************/
1930
1931static void* SHPAllocBuffer(unsigned char** pBuffer, int nSize)
1932{
1933 unsigned char* pRet;
1934
1935 if( pBuffer == NULL )
1936 return calloc(1, nSize);
1937
1938 pRet = *pBuffer;
1939 if( pRet == NULL )
1940 return NULL;
1941
1942 (*pBuffer) += nSize;
1943 return pRet;
1944}
1945
1946/************************************************************************/
1947/* SHPReallocObjectBufIfNecessary() */
1948/************************************************************************/
1949
1950static unsigned char* SHPReallocObjectBufIfNecessary ( SHPHandle psSHP,
1951 int nObjectBufSize )
1952{
1953 unsigned char* pBuffer;
1954 if( nObjectBufSize == 0 )
1955 {
1956 nObjectBufSize = 4 * sizeof(double);
1957 }
1958 if( nObjectBufSize > psSHP->nObjectBufSize )
1959 {
1960 pBuffer = (unsigned char*) realloc( psSHP->pabyObjectBuf, nObjectBufSize );
1961 if( pBuffer != NULL )
1962 {
1963 psSHP->pabyObjectBuf = pBuffer;
1964 psSHP->nObjectBufSize = nObjectBufSize;
1965 }
1966 }
1967 else
1968 pBuffer = psSHP->pabyObjectBuf;
1969 return pBuffer;
1970}
1971
1972/************************************************************************/
1973/* SHPReadObject() */
1974/* */
1975/* Read the vertices, parts, and other non-attribute information */
1976/* for one shape. */
1977/************************************************************************/
1978
1980SHPReadObject( SHPHandle psSHP, int hEntity )
1981
1982{
1983 int nEntitySize, nRequiredSize;
1985 char szErrorMsg[128];
1986 int nSHPType;
1987 int nBytesRead;
1988
1989/* -------------------------------------------------------------------- */
1990/* Validate the record/entity number. */
1991/* -------------------------------------------------------------------- */
1992 if( hEntity < 0 || hEntity >= psSHP->nRecords )
1993 return( NULL );
1994
1995/* -------------------------------------------------------------------- */
1996/* Read offset/length from SHX loading if necessary. */
1997/* -------------------------------------------------------------------- */
1998 if( psSHP->panRecOffset[hEntity] == 0 && psSHP->fpSHX != NULL )
1999 {
2000 unsigned int nOffset, nLength;
2001
2002 if( psSHP->sHooks.FSeek( psSHP->fpSHX, 100 + 8 * hEntity, 0 ) != 0 ||
2003 psSHP->sHooks.FRead( &nOffset, 1, 4, psSHP->fpSHX ) != 4 ||
2004 psSHP->sHooks.FRead( &nLength, 1, 4, psSHP->fpSHX ) != 4 )
2005 {
2006 char str[128];
2007 snprintf( str, sizeof(str),
2008 "Error in fseek()/fread() reading object from .shx file at offset %d",
2009 100 + 8 * hEntity);
2010
2011 psSHP->sHooks.Error( str );
2012 return NULL;
2013 }
2014 if( !bBigEndian ) SwapWord( 4, &nOffset );
2015 if( !bBigEndian ) SwapWord( 4, &nLength );
2016
2017 if( nOffset > (unsigned int)INT_MAX )
2018 {
2019 char str[128];
2020 snprintf( str, sizeof(str),
2021 "Invalid offset for entity %d", hEntity);
2022
2023 psSHP->sHooks.Error( str );
2024 return NULL;
2025 }
2026 if( nLength > (unsigned int)(INT_MAX / 2 - 4) )
2027 {
2028 char str[128];
2029 snprintf( str, sizeof(str),
2030 "Invalid length for entity %d", hEntity);
2031
2032 psSHP->sHooks.Error( str );
2033 return NULL;
2034 }
2035
2036 psSHP->panRecOffset[hEntity] = nOffset*2;
2037 psSHP->panRecSize[hEntity] = nLength*2;
2038 }
2039
2040/* -------------------------------------------------------------------- */
2041/* Ensure our record buffer is large enough. */
2042/* -------------------------------------------------------------------- */
2043 nEntitySize = psSHP->panRecSize[hEntity]+8;
2044 if( nEntitySize > psSHP->nBufSize )
2045 {
2046 uchar* pabyRecNew;
2047 int nNewBufSize = nEntitySize;
2048 if( nNewBufSize < INT_MAX - nNewBufSize / 3 )
2049 nNewBufSize += nNewBufSize / 3;
2050 else
2051 nNewBufSize = INT_MAX;
2052
2053 /* Before allocating too much memory, check that the file is big enough */
2054 if( nEntitySize >= 10 * 1024 * 1024 &&
2055 (psSHP->panRecOffset[hEntity] >= psSHP->nFileSize ||
2056 (unsigned int)nEntitySize > psSHP->nFileSize - psSHP->panRecOffset[hEntity]) )
2057 {
2058 /* We do as is we didn't trust the file size in the header */
2059 SAOffset nFileSize;
2060 psSHP->sHooks.FSeek( psSHP->fpSHP, 0, 2 );
2061 nFileSize = psSHP->sHooks.FTell(psSHP->fpSHP);
2062 if( nFileSize >= 0xFFFFFFFFU )
2063 psSHP->nFileSize = 0xFFFFFFFFU;
2064 else
2065 psSHP->nFileSize = (unsigned int)nFileSize;
2066
2067 if( psSHP->panRecOffset[hEntity] >= psSHP->nFileSize ||
2068 (unsigned int)nEntitySize > psSHP->nFileSize - psSHP->panRecOffset[hEntity] )
2069 {
2070 char str[128];
2071 snprintf( str, sizeof(str),
2072 "Error in fread() reading object of size %u at offset %u from .shp file",
2073 nEntitySize, psSHP->panRecOffset[hEntity] );
2074
2075 psSHP->sHooks.Error( str );
2076 return NULL;
2077 }
2078 }
2079
2080 pabyRecNew = (uchar *) SfRealloc(psSHP->pabyRec,nNewBufSize);
2081 if (pabyRecNew == NULL)
2082 {
2083 char szError[200];
2084
2085 snprintf( szError, sizeof(szError),
2086 "Not enough memory to allocate requested memory (nNewBufSize=%d). "
2087 "Probably broken SHP file", nNewBufSize);
2088 psSHP->sHooks.Error( szError );
2089 return NULL;
2090 }
2091
2092 /* Only set new buffer size after successful alloc */
2093 psSHP->pabyRec = pabyRecNew;
2094 psSHP->nBufSize = nNewBufSize;
2095 }
2096
2097 /* In case we were not able to reallocate the buffer on a previous step */
2098 if (psSHP->pabyRec == NULL)
2099 {
2100 return NULL;
2101 }
2102
2103/* -------------------------------------------------------------------- */
2104/* Read the record. */
2105/* -------------------------------------------------------------------- */
2106 if( psSHP->sHooks.FSeek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 ) != 0 )
2107 {
2108 /*
2109 * TODO - mloskot: Consider detailed diagnostics of shape file,
2110 * for example to detect if file is truncated.
2111 */
2112 char str[128];
2113 snprintf( str, sizeof(str),
2114 "Error in fseek() reading object from .shp file at offset %u",
2115 psSHP->panRecOffset[hEntity]);
2116
2117 psSHP->sHooks.Error( str );
2118 return NULL;
2119 }
2120
2121 nBytesRead = (int)psSHP->sHooks.FRead( psSHP->pabyRec, 1, nEntitySize, psSHP->fpSHP );
2122
2123 /* Special case for a shapefile whose .shx content length field is not equal */
2124 /* to the content length field of the .shp, which is a violation of "The */
2125 /* content length stored in the index record is the same as the value stored in the main */
2126 /* file record header." (http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf, page 24) */
2127 /* Actually in that case the .shx content length is equal to the .shp content length + */
2128 /* 4 (16 bit words), representing the 8 bytes of the record header... */
2129 if( nBytesRead >= 8 && nBytesRead == nEntitySize - 8 )
2130 {
2131 /* Do a sanity check */
2132 int nSHPContentLength;
2133 memcpy( &nSHPContentLength, psSHP->pabyRec + 4, 4 );
2134 if( !bBigEndian ) SwapWord( 4, &(nSHPContentLength) );
2135 if( nSHPContentLength < 0 ||
2136 nSHPContentLength > INT_MAX / 2 - 4 ||
2137 2 * nSHPContentLength + 8 != nBytesRead )
2138 {
2139 char str[128];
2140 snprintf( str, sizeof(str),
2141 "Sanity check failed when trying to recover from inconsistent .shx/.shp with shape %d",
2142 hEntity );
2143
2144 psSHP->sHooks.Error( str );
2145 return NULL;
2146 }
2147 }
2149 {
2150 /*
2151 * TODO - mloskot: Consider detailed diagnostics of shape file,
2152 * for example to detect if file is truncated.
2153 */
2154 char str[128];
2155 snprintf( str, sizeof(str),
2156 "Error in fread() reading object of size %u at offset %u from .shp file",
2157 nEntitySize, psSHP->panRecOffset[hEntity] );
2158
2159 psSHP->sHooks.Error( str );
2160 return NULL;
2161 }
2162
2163 if ( 8 + 4 > nEntitySize )
2164 {
2165 snprintf(szErrorMsg, sizeof(szErrorMsg),
2166 "Corrupted .shp file : shape %d : nEntitySize = %d",
2167 hEntity, nEntitySize);
2168 psSHP->sHooks.Error( szErrorMsg );
2169 return NULL;
2170 }
2171 memcpy( &nSHPType, psSHP->pabyRec + 8, 4 );
2172
2173 if( bBigEndian ) SwapWord( 4, &(nSHPType) );
2174
2175/* -------------------------------------------------------------------- */
2176/* Allocate and minimally initialize the object. */
2177/* -------------------------------------------------------------------- */
2178 if( psSHP->bFastModeReadObject )
2179 {
2180 if( psSHP->psCachedObject->bFastModeReadObject )
2181 {
2182 psSHP->sHooks.Error( "Invalid read pattern in fast read mode. "
2183 "SHPDestroyObject() should be called." );
2184 return NULL;
2185 }
2186
2187 psShape = psSHP->psCachedObject;
2188 memset(psShape, 0, sizeof(SHPObject));
2189 }
2190 else
2191 psShape = (SHPObject *) calloc(1,sizeof(SHPObject));
2192 psShape->nShapeId = hEntity;
2193 psShape->nSHPType = nSHPType;
2194 psShape->bMeasureIsUsed = FALSE;
2195 psShape->bFastModeReadObject = psSHP->bFastModeReadObject;
2196
2197/* ==================================================================== */
2198/* Extract vertices for a Polygon or Arc. */
2199/* ==================================================================== */
2200 if( psShape->nSHPType == SHPT_POLYGON || psShape->nSHPType == SHPT_ARC
2201 || psShape->nSHPType == SHPT_POLYGONZ
2202 || psShape->nSHPType == SHPT_POLYGONM
2203 || psShape->nSHPType == SHPT_ARCZ
2204 || psShape->nSHPType == SHPT_ARCM
2205 || psShape->nSHPType == SHPT_MULTIPATCH )
2206 {
2207 int32 nPoints, nParts;
2208 int i, nOffset;
2209 unsigned char* pBuffer = NULL;
2210 unsigned char** ppBuffer = NULL;
2211
2212 if ( 40 + 8 + 4 > nEntitySize )
2213 {
2214 snprintf(szErrorMsg, sizeof(szErrorMsg),
2215 "Corrupted .shp file : shape %d : nEntitySize = %d",
2216 hEntity, nEntitySize);
2217 psSHP->sHooks.Error( szErrorMsg );
2219 return NULL;
2220 }
2221/* -------------------------------------------------------------------- */
2222/* Get the X/Y bounds. */
2223/* -------------------------------------------------------------------- */
2224 memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 );
2225 memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );
2226 memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
2227 memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
2228
2229 if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
2230 if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
2231 if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
2232 if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
2233
2234/* -------------------------------------------------------------------- */
2235/* Extract part/point count, and build vertex and part arrays */
2236/* to proper size. */
2237/* -------------------------------------------------------------------- */
2238 memcpy( &nPoints, psSHP->pabyRec + 40 + 8, 4 );
2239 memcpy( &nParts, psSHP->pabyRec + 36 + 8, 4 );
2240
2241 if( bBigEndian ) SwapWord( 4, &nPoints );
2242 if( bBigEndian ) SwapWord( 4, &nParts );
2243
2244 /* nPoints and nParts are unsigned */
2245 if (/* nPoints < 0 || nParts < 0 || */
2246 nPoints > 50 * 1000 * 1000 || nParts > 10 * 1000 * 1000)
2247 {
2248 snprintf(szErrorMsg, sizeof(szErrorMsg),
2249 "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d.",
2250 hEntity, nPoints, nParts);
2251 psSHP->sHooks.Error( szErrorMsg );
2253 return NULL;
2254 }
2255
2256 /* With the previous checks on nPoints and nParts, */
2257 /* we should not overflow here and after */
2258 /* since 50 M * (16 + 8 + 8) = 1 600 MB */
2259 nRequiredSize = 44 + 8 + 4 * nParts + 16 * nPoints;
2260 if ( psShape->nSHPType == SHPT_POLYGONZ
2261 || psShape->nSHPType == SHPT_ARCZ
2262 || psShape->nSHPType == SHPT_MULTIPATCH )
2263 {
2264 nRequiredSize += 16 + 8 * nPoints;
2265 }
2266 if( psShape->nSHPType == SHPT_MULTIPATCH )
2267 {
2268 nRequiredSize += 4 * nParts;
2269 }
2270 if (nRequiredSize > nEntitySize)
2271 {
2272 snprintf(szErrorMsg, sizeof(szErrorMsg),
2273 "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d, nEntitySize=%d.",
2274 hEntity, nPoints, nParts, nEntitySize);
2275 psSHP->sHooks.Error( szErrorMsg );
2277 return NULL;
2278 }
2279
2280 if( psShape->bFastModeReadObject )
2281 {
2282 int nObjectBufSize = 4 * sizeof(double) * nPoints + 2 * sizeof(int) * nParts;
2283 pBuffer = SHPReallocObjectBufIfNecessary(psSHP, nObjectBufSize);
2284 ppBuffer = &pBuffer;
2285 }
2286
2287 psShape->nVertices = nPoints;
2288 psShape->padfX = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
2289 psShape->padfY = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
2290 psShape->padfZ = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
2291 psShape->padfM = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
2292
2293 psShape->nParts = nParts;
2294 psShape->panPartStart = (int *) SHPAllocBuffer(ppBuffer, nParts * sizeof(int));
2295 psShape->panPartType = (int *) SHPAllocBuffer(ppBuffer, nParts * sizeof(int));
2296
2297 if (psShape->padfX == NULL ||
2298 psShape->padfY == NULL ||
2299 psShape->padfZ == NULL ||
2300 psShape->padfM == NULL ||
2301 psShape->panPartStart == NULL ||
2302 psShape->panPartType == NULL)
2303 {
2304 snprintf(szErrorMsg, sizeof(szErrorMsg),
2305 "Not enough memory to allocate requested memory (nPoints=%d, nParts=%d) for shape %d. "
2306 "Probably broken SHP file", hEntity, nPoints, nParts );
2307 psSHP->sHooks.Error( szErrorMsg );
2309 return NULL;
2310 }
2311
2312 for( i = 0; (int32)i < nParts; i++ )
2313 psShape->panPartType[i] = SHPP_RING;
2314
2315/* -------------------------------------------------------------------- */
2316/* Copy out the part array from the record. */
2317/* -------------------------------------------------------------------- */
2318 memcpy( psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts );
2319 for( i = 0; (int32)i < nParts; i++ )
2320 {
2321 if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i );
2322
2323 /* We check that the offset is inside the vertex array */
2324 if (psShape->panPartStart[i] < 0
2325 || (psShape->panPartStart[i] >= psShape->nVertices
2326 && psShape->nVertices > 0)
2327 || (psShape->panPartStart[i] > 0 && psShape->nVertices == 0) )
2328 {
2329 snprintf(szErrorMsg, sizeof(szErrorMsg),
2330 "Corrupted .shp file : shape %d : panPartStart[%d] = %d, nVertices = %d",
2331 hEntity, i, psShape->panPartStart[i], psShape->nVertices);
2332 psSHP->sHooks.Error( szErrorMsg );
2334 return NULL;
2335 }
2336 if (i > 0 && psShape->panPartStart[i] <= psShape->panPartStart[i-1])
2337 {
2338 snprintf(szErrorMsg, sizeof(szErrorMsg),
2339 "Corrupted .shp file : shape %d : panPartStart[%d] = %d, panPartStart[%d] = %d",
2340 hEntity, i, psShape->panPartStart[i], i - 1, psShape->panPartStart[i - 1]);
2341 psSHP->sHooks.Error( szErrorMsg );
2343 return NULL;
2344 }
2345 }
2346
2347 nOffset = 44 + 8 + 4*nParts;
2348
2349/* -------------------------------------------------------------------- */
2350/* If this is a multipatch, we will also have parts types. */
2351/* -------------------------------------------------------------------- */
2352 if( psShape->nSHPType == SHPT_MULTIPATCH )
2353 {
2354 memcpy( psShape->panPartType, psSHP->pabyRec + nOffset, 4*nParts );
2355 for( i = 0; (int32)i < nParts; i++ )
2356 {
2357 if( bBigEndian ) SwapWord( 4, psShape->panPartType+i );
2358 }
2359
2360 nOffset += 4*nParts;
2361 }
2362
2363/* -------------------------------------------------------------------- */
2364/* Copy out the vertices from the record. */
2365/* -------------------------------------------------------------------- */
2366 for( i = 0; (int32)i < nPoints; i++ )
2367 {
2368 memcpy(psShape->padfX + i,
2369 psSHP->pabyRec + nOffset + i * 16,
2370 8 );
2371
2372 memcpy(psShape->padfY + i,
2373 psSHP->pabyRec + nOffset + i * 16 + 8,
2374 8 );
2375
2376 if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
2377 if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
2378 }
2379
2380 nOffset += 16*nPoints;
2381
2382/* -------------------------------------------------------------------- */
2383/* If we have a Z coordinate, collect that now. */
2384/* -------------------------------------------------------------------- */
2385 if( psShape->nSHPType == SHPT_POLYGONZ
2386 || psShape->nSHPType == SHPT_ARCZ
2387 || psShape->nSHPType == SHPT_MULTIPATCH )
2388 {
2389 memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
2390 memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
2391
2392 if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
2393 if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
2394
2395 for( i = 0; (int32)i < nPoints; i++ )
2396 {
2397 memcpy( psShape->padfZ + i,
2398 psSHP->pabyRec + nOffset + 16 + i*8, 8 );
2399 if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
2400 }
2401
2402 nOffset += 16 + 8*nPoints;
2403 }
2404 else if( psShape->bFastModeReadObject )
2405 {
2406 psShape->padfZ = NULL;
2407 }
2408
2409/* -------------------------------------------------------------------- */
2410/* If we have a M measure value, then read it now. We assume */
2411/* that the measure can be present for any shape if the size is */
2412/* big enough, but really it will only occur for the Z shapes */
2413/* (options), and the M shapes. */
2414/* -------------------------------------------------------------------- */
2415 if( nEntitySize >= (int)(nOffset + 16 + 8*nPoints) )
2416 {
2417 memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
2418 memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
2419
2420 if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
2421 if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
2422
2423 for( i = 0; (int32)i < nPoints; i++ )
2424 {
2425 memcpy( psShape->padfM + i,
2426 psSHP->pabyRec + nOffset + 16 + i*8, 8 );
2427 if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
2428 }
2429 psShape->bMeasureIsUsed = TRUE;
2430 }
2431 else if( psShape->bFastModeReadObject )
2432 {
2433 psShape->padfM = NULL;
2434 }
2435 }
2436
2437/* ==================================================================== */
2438/* Extract vertices for a MultiPoint. */
2439/* ==================================================================== */
2440 else if( psShape->nSHPType == SHPT_MULTIPOINT
2441 || psShape->nSHPType == SHPT_MULTIPOINTM
2442 || psShape->nSHPType == SHPT_MULTIPOINTZ )
2443 {
2444 int32 nPoints;
2445 int i, nOffset;
2446 unsigned char* pBuffer = NULL;
2447 unsigned char** ppBuffer = NULL;
2448
2449 if ( 44 + 4 > nEntitySize )
2450 {
2451 snprintf(szErrorMsg, sizeof(szErrorMsg),
2452 "Corrupted .shp file : shape %d : nEntitySize = %d",
2453 hEntity, nEntitySize);
2454 psSHP->sHooks.Error( szErrorMsg );
2456 return NULL;
2457 }
2458 memcpy( &nPoints, psSHP->pabyRec + 44, 4 );
2459
2460 if( bBigEndian ) SwapWord( 4, &nPoints );
2461
2462 /* nPoints is unsigned */
2463 if (/* nPoints < 0 || */ nPoints > 50 * 1000 * 1000)
2464 {
2465 snprintf(szErrorMsg, sizeof(szErrorMsg),
2466 "Corrupted .shp file : shape %d : nPoints = %d",
2467 hEntity, nPoints);
2468 psSHP->sHooks.Error( szErrorMsg );
2470 return NULL;
2471 }
2472
2473 nRequiredSize = 48 + nPoints * 16;
2474 if( psShape->nSHPType == SHPT_MULTIPOINTZ )
2475 {
2476 nRequiredSize += 16 + nPoints * 8;
2477 }
2478 if (nRequiredSize > nEntitySize)
2479 {
2480 snprintf(szErrorMsg, sizeof(szErrorMsg),
2481 "Corrupted .shp file : shape %d : nPoints = %d, nEntitySize = %d",
2482 hEntity, nPoints, nEntitySize);
2483 psSHP->sHooks.Error( szErrorMsg );
2485 return NULL;
2486 }
2487
2488 if( psShape->bFastModeReadObject )
2489 {
2490 int nObjectBufSize = 4 * sizeof(double) * nPoints;
2491 pBuffer = SHPReallocObjectBufIfNecessary(psSHP, nObjectBufSize);
2492 ppBuffer = &pBuffer;
2493 }
2494
2495 psShape->nVertices = nPoints;
2496
2497 psShape->padfX = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
2498 psShape->padfY = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
2499 psShape->padfZ = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
2500 psShape->padfM = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
2501
2502 if (psShape->padfX == NULL ||
2503 psShape->padfY == NULL ||
2504 psShape->padfZ == NULL ||
2505 psShape->padfM == NULL)
2506 {
2507 snprintf(szErrorMsg, sizeof(szErrorMsg),
2508 "Not enough memory to allocate requested memory (nPoints=%d) for shape %d. "
2509 "Probably broken SHP file", hEntity, nPoints );
2510 psSHP->sHooks.Error( szErrorMsg );
2512 return NULL;
2513 }
2514
2515 for( i = 0; (int32)i < nPoints; i++ )
2516 {
2517 memcpy(psShape->padfX+i, psSHP->pabyRec + 48 + 16 * i, 8 );
2518 memcpy(psShape->padfY+i, psSHP->pabyRec + 48 + 16 * i + 8, 8 );
2519
2520 if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
2521 if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
2522 }
2523
2524 nOffset = 48 + 16*nPoints;
2525
2526/* -------------------------------------------------------------------- */
2527/* Get the X/Y bounds. */
2528/* -------------------------------------------------------------------- */
2529 memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 );
2530 memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );
2531 memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
2532 memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
2533
2534 if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
2535 if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
2536 if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
2537 if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
2538
2539/* -------------------------------------------------------------------- */
2540/* If we have a Z coordinate, collect that now. */
2541/* -------------------------------------------------------------------- */
2542 if( psShape->nSHPType == SHPT_MULTIPOINTZ )
2543 {
2544 memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
2545 memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
2546
2547 if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
2548 if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
2549
2550 for( i = 0; (int32)i < nPoints; i++ )
2551 {
2552 memcpy( psShape->padfZ + i,
2553 psSHP->pabyRec + nOffset + 16 + i*8, 8 );
2554 if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
2555 }
2556
2557 nOffset += 16 + 8*nPoints;
2558 }
2559 else if( psShape->bFastModeReadObject )
2560 psShape->padfZ = NULL;
2561
2562/* -------------------------------------------------------------------- */
2563/* If we have a M measure value, then read it now. We assume */
2564/* that the measure can be present for any shape if the size is */
2565/* big enough, but really it will only occur for the Z shapes */
2566/* (options), and the M shapes. */
2567/* -------------------------------------------------------------------- */
2568 if( nEntitySize >= (int)(nOffset + 16 + 8*nPoints) )
2569 {
2570 memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
2571 memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
2572
2573 if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
2574 if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
2575
2576 for( i = 0; (int32)i < nPoints; i++ )
2577 {
2578 memcpy( psShape->padfM + i,
2579 psSHP->pabyRec + nOffset + 16 + i*8, 8 );
2580 if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
2581 }
2582 psShape->bMeasureIsUsed = TRUE;
2583 }
2584 else if( psShape->bFastModeReadObject )
2585 psShape->padfM = NULL;
2586 }
2587
2588/* ==================================================================== */
2589/* Extract vertices for a point. */
2590/* ==================================================================== */
2591 else if( psShape->nSHPType == SHPT_POINT
2592 || psShape->nSHPType == SHPT_POINTM
2593 || psShape->nSHPType == SHPT_POINTZ )
2594 {
2595 int nOffset;
2596
2597 psShape->nVertices = 1;
2598 if( psShape->bFastModeReadObject )
2599 {
2600 psShape->padfX = &(psShape->dfXMin);
2601 psShape->padfY = &(psShape->dfYMin);
2602 psShape->padfZ = &(psShape->dfZMin);
2603 psShape->padfM = &(psShape->dfMMin);
2604 psShape->padfZ[0] = 0.0;
2605 psShape->padfM[0] = 0.0;
2606 }
2607 else
2608 {
2609 psShape->padfX = (double *) calloc(1,sizeof(double));
2610 psShape->padfY = (double *) calloc(1,sizeof(double));
2611 psShape->padfZ = (double *) calloc(1,sizeof(double));
2612 psShape->padfM = (double *) calloc(1,sizeof(double));
2613 }
2614
2615 if (20 + 8 + (( psShape->nSHPType == SHPT_POINTZ ) ? 8 : 0)> nEntitySize)
2616 {
2617 snprintf(szErrorMsg, sizeof(szErrorMsg),
2618 "Corrupted .shp file : shape %d : nEntitySize = %d",
2619 hEntity, nEntitySize);
2620 psSHP->sHooks.Error( szErrorMsg );
2622 return NULL;
2623 }
2624 memcpy( psShape->padfX, psSHP->pabyRec + 12, 8 );
2625 memcpy( psShape->padfY, psSHP->pabyRec + 20, 8 );
2626
2627 if( bBigEndian ) SwapWord( 8, psShape->padfX );
2628 if( bBigEndian ) SwapWord( 8, psShape->padfY );
2629
2630 nOffset = 20 + 8;
2631
2632/* -------------------------------------------------------------------- */
2633/* If we have a Z coordinate, collect that now. */
2634/* -------------------------------------------------------------------- */
2635 if( psShape->nSHPType == SHPT_POINTZ )
2636 {
2637 memcpy( psShape->padfZ, psSHP->pabyRec + nOffset, 8 );
2638
2639 if( bBigEndian ) SwapWord( 8, psShape->padfZ );
2640
2641 nOffset += 8;
2642 }
2643
2644/* -------------------------------------------------------------------- */
2645/* If we have a M measure value, then read it now. We assume */
2646/* that the measure can be present for any shape if the size is */
2647/* big enough, but really it will only occur for the Z shapes */
2648/* (options), and the M shapes. */
2649/* -------------------------------------------------------------------- */
2650 if( nEntitySize >= nOffset + 8 )
2651 {
2652 memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 );
2653
2654 if( bBigEndian ) SwapWord( 8, psShape->padfM );
2655 psShape->bMeasureIsUsed = TRUE;
2656 }
2657
2658/* -------------------------------------------------------------------- */
2659/* Since no extents are supplied in the record, we will apply */
2660/* them from the single vertex. */
2661/* -------------------------------------------------------------------- */
2662 psShape->dfXMin = psShape->dfXMax = psShape->padfX[0];
2663 psShape->dfYMin = psShape->dfYMax = psShape->padfY[0];
2664 psShape->dfZMin = psShape->dfZMax = psShape->padfZ[0];
2665 psShape->dfMMin = psShape->dfMMax = psShape->padfM[0];
2666 }
2667
2668 return( psShape );
2669}
2670
2671/************************************************************************/
2672/* SHPTypeName() */
2673/************************************************************************/
2674
2675const char SHPAPI_CALL1(*)
2676SHPTypeName( int nSHPType )
2677
2678{
2679 switch( nSHPType )
2680 {
2681 case SHPT_NULL:
2682 return "NullShape";
2683
2684 case SHPT_POINT:
2685 return "Point";
2686
2687 case SHPT_ARC:
2688 return "Arc";
2689
2690 case SHPT_POLYGON:
2691 return "Polygon";
2692
2693 case SHPT_MULTIPOINT:
2694 return "MultiPoint";
2695
2696 case SHPT_POINTZ:
2697 return "PointZ";
2698
2699 case SHPT_ARCZ:
2700 return "ArcZ";
2701
2702 case SHPT_POLYGONZ:
2703 return "PolygonZ";
2704
2705 case SHPT_MULTIPOINTZ:
2706 return "MultiPointZ";
2707
2708 case SHPT_POINTM:
2709 return "PointM";
2710
2711 case SHPT_ARCM:
2712 return "ArcM";
2713
2714 case SHPT_POLYGONM:
2715 return "PolygonM";
2716
2717 case SHPT_MULTIPOINTM:
2718 return "MultiPointM";
2719
2720 case SHPT_MULTIPATCH:
2721 return "MultiPatch";
2722
2723 default:
2724 return "UnknownShapeType";
2725 }
2726}
2727
2728/************************************************************************/
2729/* SHPPartTypeName() */
2730/************************************************************************/
2731
2732const char SHPAPI_CALL1(*)
2733SHPPartTypeName( int nPartType )
2734
2735{
2736 switch( nPartType )
2737 {
2738 case SHPP_TRISTRIP:
2739 return "TriangleStrip";
2740
2741 case SHPP_TRIFAN:
2742 return "TriangleFan";
2743
2744 case SHPP_OUTERRING:
2745 return "OuterRing";
2746
2747 case SHPP_INNERRING:
2748 return "InnerRing";
2749
2750 case SHPP_FIRSTRING:
2751 return "FirstRing";
2752
2753 case SHPP_RING:
2754 return "Ring";
2755
2756 default:
2757 return "UnknownPartType";
2758 }
2759}
2760
2761/************************************************************************/
2762/* SHPDestroyObject() */
2763/************************************************************************/
2764
2765void SHPAPI_CALL
2767
2768{
2769 if( psShape == NULL )
2770 return;
2771
2772 if( psShape->bFastModeReadObject )
2773 {
2774 psShape->bFastModeReadObject = FALSE;
2775 return;
2776 }
2777
2778 if( psShape->padfX != NULL )
2779 free( psShape->padfX );
2780 if( psShape->padfY != NULL )
2781 free( psShape->padfY );
2782 if( psShape->padfZ != NULL )
2783 free( psShape->padfZ );
2784 if( psShape->padfM != NULL )
2785 free( psShape->padfM );
2786
2787 if( psShape->panPartStart != NULL )
2788 free( psShape->panPartStart );
2789 if( psShape->panPartType != NULL )
2790 free( psShape->panPartType );
2791
2792 free( psShape );
2793}
2794
2795/************************************************************************/
2796/* SHPRewindObject() */
2797/* */
2798/* Reset the winding of polygon objects to adhere to the */
2799/* specification. */
2800/************************************************************************/
2801
2802int SHPAPI_CALL
2804 SHPObject * psObject )
2805{
2806 int iOpRing, bAltered = 0;
2807
2808/* -------------------------------------------------------------------- */
2809/* Do nothing if this is not a polygon object. */
2810/* -------------------------------------------------------------------- */
2811 if( psObject->nSHPType != SHPT_POLYGON
2812 && psObject->nSHPType != SHPT_POLYGONZ
2813 && psObject->nSHPType != SHPT_POLYGONM )
2814 return 0;
2815
2816 if( psObject->nVertices == 0 || psObject->nParts == 0 )
2817 return 0;
2818
2819/* -------------------------------------------------------------------- */
2820/* Process each of the rings. */
2821/* -------------------------------------------------------------------- */
2822 for( iOpRing = 0; iOpRing < psObject->nParts; iOpRing++ )
2823 {
2824 int bInner, iVert, nVertCount, nVertStart, iCheckRing;
2825 double dfSum, dfTestX, dfTestY;
2826
2827/* -------------------------------------------------------------------- */
2828/* Determine if this ring is an inner ring or an outer ring */
2829/* relative to all the other rings. For now we assume the */
2830/* first ring is outer and all others are inner, but eventually */
2831/* we need to fix this to handle multiple island polygons and */
2832/* unordered sets of rings. */
2833/* */
2834/* -------------------------------------------------------------------- */
2835
2836 /* Use point in the middle of segment to avoid testing
2837 * common points of rings.
2838 */
2839 dfTestX = ( psObject->padfX[psObject->panPartStart[iOpRing]]
2840 + psObject->padfX[psObject->panPartStart[iOpRing] + 1] ) / 2;
2841 dfTestY = ( psObject->padfY[psObject->panPartStart[iOpRing]]
2842 + psObject->padfY[psObject->panPartStart[iOpRing] + 1] ) / 2;
2843
2844 bInner = FALSE;
2845 for( iCheckRing = 0; iCheckRing < psObject->nParts; iCheckRing++ )
2846 {
2847 int iEdge;
2848
2849 if( iCheckRing == iOpRing )
2850 continue;
2851
2852 nVertStart = psObject->panPartStart[iCheckRing];
2853
2854 if( iCheckRing == psObject->nParts-1 )
2855 nVertCount = psObject->nVertices
2856 - psObject->panPartStart[iCheckRing];
2857 else
2858 nVertCount = psObject->panPartStart[iCheckRing+1]
2859 - psObject->panPartStart[iCheckRing];
2860
2861 for( iEdge = 0; iEdge < nVertCount; iEdge++ )
2862 {
2863 int iNext;
2864
2865 if( iEdge < nVertCount-1 )
2866 iNext = iEdge+1;
2867 else
2868 iNext = 0;
2869
2870 /* Rule #1:
2871 * Test whether the edge 'straddles' the horizontal ray from the test point (dfTestY,dfTestY)
2872 * The rule #1 also excludes edges colinear with the ray.
2873 */
2874 if ( ( psObject->padfY[iEdge+nVertStart] < dfTestY
2875 && dfTestY <= psObject->padfY[iNext+nVertStart] )
2876 || ( psObject->padfY[iNext+nVertStart] < dfTestY
2877 && dfTestY <= psObject->padfY[iEdge+nVertStart] ) )
2878 {
2879 /* Rule #2:
2880 * Test if edge-ray intersection is on the right from the test point (dfTestY,dfTestY)
2881 */
2882 double const intersect =
2883 ( psObject->padfX[iEdge+nVertStart]
2884 + ( dfTestY - psObject->padfY[iEdge+nVertStart] )
2885 / ( psObject->padfY[iNext+nVertStart] - psObject->padfY[iEdge+nVertStart] )
2886 * ( psObject->padfX[iNext+nVertStart] - psObject->padfX[iEdge+nVertStart] ) );
2887
2888 if (intersect < dfTestX)
2889 {
2890 bInner = !bInner;
2891 }
2892 }
2893 }
2894 } /* for iCheckRing */
2895
2896/* -------------------------------------------------------------------- */
2897/* Determine the current order of this ring so we will know if */
2898/* it has to be reversed. */
2899/* -------------------------------------------------------------------- */
2900 nVertStart = psObject->panPartStart[iOpRing];
2901
2902 if( iOpRing == psObject->nParts-1 )
2903 nVertCount = psObject->nVertices - psObject->panPartStart[iOpRing];
2904 else
2905 nVertCount = psObject->panPartStart[iOpRing+1]
2906 - psObject->panPartStart[iOpRing];
2907
2908 if (nVertCount < 2)
2909 continue;
2910
2911 dfSum = psObject->padfX[nVertStart] * (psObject->padfY[nVertStart+1] - psObject->padfY[nVertStart+nVertCount-1]);
2912 for( iVert = nVertStart + 1; iVert < nVertStart+nVertCount-1; iVert++ )
2913 {
2914 dfSum += psObject->padfX[iVert] * (psObject->padfY[iVert+1] - psObject->padfY[iVert-1]);
2915 }
2916
2917 dfSum += psObject->padfX[iVert] * (psObject->padfY[nVertStart] - psObject->padfY[iVert-1]);
2918
2919/* -------------------------------------------------------------------- */
2920/* Reverse if necessary. */
2921/* -------------------------------------------------------------------- */
2922 if( (dfSum < 0.0 && bInner) || (dfSum > 0.0 && !bInner) )
2923 {
2924 int i;
2925
2926 bAltered++;
2927 for( i = 0; i < nVertCount/2; i++ )
2928 {
2929 double dfSaved;
2930
2931 /* Swap X */
2932 dfSaved = psObject->padfX[nVertStart+i];
2933 psObject->padfX[nVertStart+i] =
2934 psObject->padfX[nVertStart+nVertCount-i-1];
2935 psObject->padfX[nVertStart+nVertCount-i-1] = dfSaved;
2936
2937 /* Swap Y */
2938 dfSaved = psObject->padfY[nVertStart+i];
2939 psObject->padfY[nVertStart+i] =
2940 psObject->padfY[nVertStart+nVertCount-i-1];
2941 psObject->padfY[nVertStart+nVertCount-i-1] = dfSaved;
2942
2943 /* Swap Z */
2944 if( psObject->padfZ )
2945 {
2946 dfSaved = psObject->padfZ[nVertStart+i];
2947 psObject->padfZ[nVertStart+i] =
2948 psObject->padfZ[nVertStart+nVertCount-i-1];
2949 psObject->padfZ[nVertStart+nVertCount-i-1] = dfSaved;
2950 }
2951
2952 /* Swap M */
2953 if( psObject->padfM )
2954 {
2955 dfSaved = psObject->padfM[nVertStart+i];
2956 psObject->padfM[nVertStart+i] =
2957 psObject->padfM[nVertStart+nVertCount-i-1];
2958 psObject->padfM[nVertStart+nVertCount-i-1] = dfSaved;
2959 }
2960 }
2961 }
2962 }
2963
2964 return bAltered;
2965}
#define NULL
Definition: ccmath.h:32
#define assert(condition)
Definition: lz4.c:324
void SASetupDefaultHooks(SAHooks *psHooks)
Definition: safileio.c:175
#define SHPT_ARCZ
Definition: shapefil.h:320
#define SHPT_MULTIPATCH
Definition: shapefil.h:327
#define SHPP_OUTERRING
Definition: shapefil.h:337
#define SHPT_NULL
Definition: shapefil.h:314
#define SHPP_FIRSTRING
Definition: shapefil.h:339
#define SHPT_ARCM
Definition: shapefil.h:324
#define SHPT_POLYGONM
Definition: shapefil.h:325
#define SHP_CVSID(string)
Definition: shapefil.h:230
#define SHPT_ARC
Definition: shapefil.h:316
#define SHPT_POLYGON
Definition: shapefil.h:317
#define SHPP_RING
Definition: shapefil.h:340
#define DISABLE_MULTIPATCH_MEASURE
Definition: shapefil.h:173
#define SHPP_TRIFAN
Definition: shapefil.h:336
#define SHPT_MULTIPOINT
Definition: shapefil.h:318
SHPInfo * SHPHandle
Definition: shapefil.h:309
int * SAFile
Definition: shapefil.h:249
#define SHPT_POINTZ
Definition: shapefil.h:319
#define SHPT_MULTIPOINTZ
Definition: shapefil.h:322
#define SHPAPI_CALL
Definition: shapefil.h:214
#define SHPAPI_CALL1(x)
Definition: shapefil.h:219
#define SHPP_TRISTRIP
Definition: shapefil.h:335
#define SHPT_MULTIPOINTM
Definition: shapefil.h:326
#define SHPT_POINTM
Definition: shapefil.h:323
#define SHPT_POINT
Definition: shapefil.h:315
#define SHPT_POLYGONZ
Definition: shapefil.h:321
#define SHPP_INNERRING
Definition: shapefil.h:338
unsigned long SAOffset
Definition: shapefil.h:252
SHPObject SHPAPI_CALL1 * SHPCreateObject(int nSHPType, int nShapeId, int nParts, const int *panPartStart, const int *panPartType, int nVertices, const double *padfX, const double *padfY, const double *padfZ, const double *padfM){ SHPObject *psObject;int i, bHasM, bHasZ;psObject=(SHPObject *) calloc(1, sizeof(SHPObject)
SHPHandle SHPAPI_CALL SHPOpen(const char *pszLayer, const char *pszAccess)
Definition: shpopen.c:489
SHPHandle SHPAPI_CALL SHPOpenLL(const char *pszLayer, const char *pszAccess, SAHooks *psHooks)
Definition: shpopen.c:507
psObject nShapeId
Definition: shpopen.c:1397
psObject nVertices
Definition: shpopen.c:1488
unsigned int int32
Definition: shpopen.c:288
SHPHandle SHPAPI_CALL SHPCreate(const char *pszLayer, int nShapeType)
Definition: shpopen.c:1173
SHPObject SHPAPI_CALL1 * SHPReadObject(SHPHandle psSHP, int hEntity){ int nEntitySize, nRequiredSize;SHPObject *psShape;char szErrorMsg[128];int nSHPType;int nBytesRead;if(hEntity< 0||hEntity >=psSHP->nRecords) return(NULL
#define MIN(a, b)
Definition: shpopen.c:298
else psShape
Definition: shpopen.c:2191
void SHPAPI_CALL SHPSetFastModeReadObject(SHPHandle hSHP, int bFastMode)
Definition: shpopen.c:1120
psObject nSHPType
Definition: shpopen.c:1396
SHPHandle SHPAPI_CALL SHPCreateLL(const char *pszLayer, int nShapeType, SAHooks *psHooks)
Definition: shpopen.c:1191
#define CPL_UNUSED
Definition: shpopen.c:280
nEntitySize
Definition: shpopen.c:2043
void SHPAPI_CALL SHPComputeExtents(SHPObject *psObject)
Definition: shpopen.c:1348
unsigned char uchar
Definition: shpopen.c:283
const char SHPAPI_CALL1 * SHPPartTypeName(int nPartType){ switch(nPartType
Definition: shpopen.c:2733
void SHPAPI_CALL SHPWriteHeader(SHPHandle psSHP)
Definition: shpopen.c:359
SHPObject SHPAPI_CALL1 * SHPCreateSimpleObject(int nSHPType, int nVertices, const double *padfX, const double *padfY, const double *padfZ){ return(SHPCreateObject(nSHPType, -1, 0, NULL, NULL, nVertices, padfX, padfY, padfZ, NULL)
void SHPAPI_CALL SHPClose(SHPHandle psSHP)
Definition: shpopen.c:1073
void SHPAPI_CALL SHPGetInfo(SHPHandle psSHP, int *pnEntities, int *pnShapeType, double *padfMinBound, double *padfMaxBound)
Definition: shpopen.c:1141
int SHPAPI_CALL SHPRestoreSHX(const char *pszLayer, const char *pszAccess, SAHooks *psHooks)
Definition: shpopen.c:874
bHasZ
Definition: shpopen.c:1423
int SHPAPI_CALL SHPRewindObject(CPL_UNUSED SHPHandle hSHP, SHPObject *psObject)
Definition: shpopen.c:2803
nBytesRead
Definition: shpopen.c:2121
#define TRUE
Definition: shpopen.c:293
#define FALSE
Definition: shpopen.c:292
const char SHPAPI_CALL1 * SHPTypeName(int nSHPType){ switch(nSHPType
Definition: shpopen.c:2676
void SHPAPI_CALL SHPDestroyObject(SHPObject *psShape)
Definition: shpopen.c:2766
int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject *psObject)
Definition: shpopen.c:1519
#define ByteCopy(a, b, c)
Definition: shpopen.c:296
SHPHandle SHPAPI_CALL SHPOpenLLEx(const char *pszLayer, const char *pszAccess, SAHooks *psHooks, int bRestoreSHX)
Definition: shpopen.c:850
#define MAX(a, b)
Definition: shpopen.c:299
void(* Error)(const char *message)
Definition: shapefil.h:265
SAFile(* FOpen)(const char *filename, const char *access)
Definition: shapefil.h:256
SAOffset(* FTell)(SAFile file)
Definition: shapefil.h:260
int(* FFlush)(SAFile file)
Definition: shapefil.h:261
SAOffset(* FWrite)(void *p, SAOffset size, SAOffset nmemb, SAFile file)
Definition: shapefil.h:258
int(* FClose)(SAFile file)
Definition: shapefil.h:262
SAOffset(* FRead)(void *p, SAOffset size, SAOffset nmemb, SAFile file)
Definition: shapefil.h:257
SAOffset(* FSeek)(SAFile file, SAOffset offset, int whence)
Definition: shapefil.h:259
SAFile fpSHX
Definition: shapefil.h:284
int nShapeType
Definition: shapefil.h:286
SAFile fpSHP
Definition: shapefil.h:283
int nMaxRecords
Definition: shapefil.h:291
SHPObject * psCachedObject
Definition: shapefil.h:306
unsigned int * panRecSize
Definition: shapefil.h:293
SAHooks sHooks
Definition: shapefil.h:281
double adBoundsMin[4]
Definition: shapefil.h:295
int nRecords
Definition: shapefil.h:290
unsigned char * pabyObjectBuf
Definition: shapefil.h:304
int bUpdated
Definition: shapefil.h:298
int nObjectBufSize
Definition: shapefil.h:305
unsigned int nFileSize
Definition: shapefil.h:288
unsigned int * panRecOffset
Definition: shapefil.h:292
int bFastModeReadObject
Definition: shapefil.h:303
unsigned char * pabyRec
Definition: shapefil.h:300
double adBoundsMax[4]
Definition: shapefil.h:296
double dfYMax
Definition: shapefil.h:368
double * padfX
Definition: shapefil.h:357
double dfXMin
Definition: shapefil.h:362
int * panPartType
Definition: shapefil.h:354
int nVertices
Definition: shapefil.h:356
int nShapeId
Definition: shapefil.h:350
double dfYMin
Definition: shapefil.h:363
double * padfY
Definition: shapefil.h:358
int nSHPType
Definition: shapefil.h:348
double dfMMax
Definition: shapefil.h:370
double * padfZ
Definition: shapefil.h:359
double dfZMax
Definition: shapefil.h:369
double dfXMax
Definition: shapefil.h:367
int * panPartStart
Definition: shapefil.h:353
double * padfM
Definition: shapefil.h:360
double dfMMin
Definition: shapefil.h:365
double dfZMin
Definition: shapefil.h:364
int bMeasureIsUsed
Definition: shapefil.h:372