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