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