PostGIS  2.4.9dev-r@@SVN_REVISION@@
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 
266 SHP_CVSID("$Id: shpopen.c 15750 2017-09-17 20:59:20Z strk $")
267 
268 typedef unsigned char uchar;
269 
270 #if UINT_MAX == 65535
271 typedef unsigned long int32;
272 #else
273 typedef 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 
293 static int bBigEndian;
294 
295 
296 /************************************************************************/
297 /* SwapWord() */
298 /* */
299 /* Swap a 2, 4 or 8 byte word. */
300 /************************************************************************/
301 
302 static 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 
323 static 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 
464 SHPOpen( 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 
482 SHPOpenLL( 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 )
508  bBigEndian = FALSE;
509  else
510  bBigEndian = TRUE;
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 
758 void 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 
795 void SHPAPI_CALL
796 SHPGetInfo(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 
828 SHPCreate( 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 
846 SHPCreateLL( 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 )
861  bBigEndian = FALSE;
862  else
863  bBigEndian = TRUE;
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 
959 error:
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 
974 static 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 
998 void 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 
1037 SHPCreateObject( 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;
1049  psObject->bMeasureIsUsed = FALSE;
1050 
1051 /* -------------------------------------------------------------------- */
1052 /* Establish whether this shape type has M, and Z values. */
1053 /* -------------------------------------------------------------------- */
1054  if( nSHPType == SHPT_ARCM
1055  || nSHPType == SHPT_POINTM
1056  || nSHPType == SHPT_POLYGONM
1057  || nSHPType == SHPT_MULTIPOINTM )
1058  {
1059  bHasM = TRUE;
1060  bHasZ = FALSE;
1061  }
1062  else if( nSHPType == SHPT_ARCZ
1063  || nSHPType == SHPT_POINTZ
1064  || nSHPType == SHPT_POLYGONZ
1065  || nSHPType == SHPT_MULTIPOINTZ
1066  || nSHPType == SHPT_MULTIPATCH )
1067  {
1068  bHasM = TRUE;
1069  bHasZ = TRUE;
1070  }
1071  else
1072  {
1073  bHasM = FALSE;
1074  bHasZ = FALSE;
1075  }
1076 
1077 /* -------------------------------------------------------------------- */
1078 /* Capture parts. Note that part type is optional, and */
1079 /* defaults to ring. */
1080 /* -------------------------------------------------------------------- */
1081  if( nSHPType == SHPT_ARC || nSHPType == SHPT_POLYGON
1082  || nSHPType == SHPT_ARCM || nSHPType == SHPT_POLYGONM
1083  || nSHPType == SHPT_ARCZ || nSHPType == SHPT_POLYGONZ
1084  || nSHPType == SHPT_MULTIPATCH )
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 /* -------------------------------------------------------------------- */
1139  psObject->nVertices = nVertices;
1140  SHPComputeExtents( psObject );
1141 
1142  return( psObject );
1143 }
1144 
1145 /************************************************************************/
1146 /* SHPCreateSimpleObject() */
1147 /* */
1148 /* Create a simple (common) shape object. Destroy with */
1149 /* SHPDestroyObject(). */
1150 /************************************************************************/
1151 
1153 SHPCreateSimpleObject( int nSHPType, int nVertices,
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 
1169 int SHPAPI_CALL
1170 SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
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 
1563 SHPReadObject( SHPHandle psSHP, int hEntity )
1564 
1565 {
1566  int nEntitySize, nRequiredSize;
1567  SHPObject *psShape;
1568  char szErrorMsg[128];
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 > 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 );
1653  SHPDestroyObject(psShape);
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  int 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 );
1679  SHPDestroyObject(psShape);
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 );
1711  SHPDestroyObject(psShape);
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 );
1735  SHPDestroyObject(psShape);
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 );
1760  SHPDestroyObject(psShape);
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 );
1784  SHPDestroyObject(psShape);
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 );
1793  SHPDestroyObject(psShape);
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  int 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 );
1896  SHPDestroyObject(psShape);
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 );
1909  SHPDestroyObject(psShape);
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 );
1924  SHPDestroyObject(psShape);
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 );
1943  SHPDestroyObject(psShape);
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  int 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 );
2037  SHPDestroyObject(psShape);
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 
2091 const char SHPAPI_CALL1(*)
2092 SHPTypeName( 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 
2148 const char SHPAPI_CALL1(*)
2149 SHPPartTypeName( 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 
2181 void 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 
2212 int 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 SHPT_MULTIPATCH
Definition: shapefil.h:319
#define SHPP_TRIFAN
Definition: shapefil.h:328
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)
SHPInfo * SHPHandle
Definition: shapefil.h:301
#define SHPT_ARCM
Definition: shapefil.h:316
unsigned int int32
Definition: shpopen.c:273
double adBoundsMin[4]
Definition: shapefil.h:292
void SHPAPI_CALL SHPGetInfo(SHPHandle psSHP, int *pnEntities, int *pnShapeType, double *padfMinBound, double *padfMaxBound)
Definition: shpopen.c:796
unsigned int nFileSize
Definition: shapefil.h:285
int * panPartStart
Definition: shapefil.h:345
static void * SfRealloc(void *pMem, int nNewSize)
Definition: shpopen.c:323
#define SHPT_POLYGONM
Definition: shapefil.h:317
void SHPAPI_CALL SHPDestroyObject(SHPObject *psShape)
Definition: shpopen.c:2182
int nVertices
Definition: shapefil.h:348
int(* FFlush)(SAFile file)
Definition: shapefil.h:260
const char SHPAPI_CALL1 * SHPPartTypeName(int nPartType){ switch(nPartType
Definition: shpopen.c:2149
#define ByteCopy(a, b, c)
Definition: shpopen.c:281
double dfZMax
Definition: shapefil.h:361
double dfZMin
Definition: shapefil.h:356
#define DISABLE_MULTIPATCH_MEASURE
Definition: shapefil.h:166
double * padfX
Definition: shapefil.h:349
SHPHandle SHPAPI_CALL SHPCreate(const char *pszLayer, int nShapeType)
Definition: shpopen.c:828
#define SHPT_MULTIPOINT
Definition: shapefil.h:310
#define SHPT_POLYGON
Definition: shapefil.h:309
#define SHPT_MULTIPOINTZ
Definition: shapefil.h:314
#define SHPP_RING
Definition: shapefil.h:332
int(* FClose)(SAFile file)
Definition: shapefil.h:261
psShape
Definition: shpopen.c:1643
#define MIN(a, b)
Definition: shpopen.c:283
double * padfY
Definition: shapefil.h:350
int nRecords
Definition: shapefil.h:287
double dfYMin
Definition: shapefil.h:355
#define SHP_CVSID(string)
Definition: shapefil.h:223
#define SHPT_ARCZ
Definition: shapefil.h:312
double dfXMax
Definition: shapefil.h:359
SAOffset(* FWrite)(void *p, SAOffset size, SAOffset nmemb, SAFile file)
Definition: shapefil.h:257
double dfXMin
Definition: shapefil.h:354
int nShapeId
Definition: shapefil.h:342
#define FALSE
Definition: shpopen.c:277
#define SHPP_INNERRING
Definition: shapefil.h:330
const char SHPAPI_CALL1 * SHPTypeName(int nSHPType){ switch(nSHPType
Definition: shpopen.c:2092
unsigned int * panRecOffset
Definition: shapefil.h:289
static int bBigEndian
Definition: shpopen.c:293
SAHooks sHooks
Definition: shapefil.h:278
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)
bHasZ
Definition: shpopen.c:1074
void SHPAPI_CALL SHPComputeExtents(SHPObject *psObject)
Definition: shpopen.c:999
#define MAX(a, b)
Definition: shpopen.c:284
#define SHPAPI_CALL1(x)
Definition: shapefil.h:212
SAFile fpSHX
Definition: shapefil.h:281
psObject nSHPType
Definition: shpopen.c:1047
int bMeasureIsUsed
Definition: shapefil.h:364
int nParts
Definition: shapefil.h:344
int nMaxRecords
Definition: shapefil.h:288
psObject nVertices
Definition: shpopen.c:1139
#define SHPT_MULTIPOINTM
Definition: shapefil.h:318
nEntitySize
Definition: shpopen.c:1579
double adBoundsMax[4]
Definition: shapefil.h:293
int SHPAPI_CALL SHPRewindObject(SHPHandle hSHP, SHPObject *psObject)
Definition: shpopen.c:2213
#define SHPT_POINTZ
Definition: shapefil.h:311
#define SHPT_POINTM
Definition: shapefil.h:315
#define SHPT_POLYGONZ
Definition: shapefil.h:313
#define SHPP_FIRSTRING
Definition: shapefil.h:331
#define SHPT_POINT
Definition: shapefil.h:307
int nBufSize
Definition: shapefil.h:298
#define SHPT_NULL
Definition: shapefil.h:306
int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject *psObject)
Definition: shpopen.c:1170
#define SHPAPI_CALL
Definition: shapefil.h:207
unsigned int * panRecSize
Definition: shapefil.h:290
static void _SHPSetBounds(uchar *pabyRec, SHPObject *psShape)
Definition: shpopen.c:974
psObject nShapeId
Definition: shpopen.c:1048
SAOffset(* FSeek)(SAFile file, SAOffset offset, int whence)
Definition: shapefil.h:258
double * padfZ
Definition: shapefil.h:351
void SHPAPI_CALL SHPWriteHeader(SHPHandle psSHP)
Definition: shpopen.c:339
#define SHPP_OUTERRING
Definition: shapefil.h:329
void free(void *)
void * malloc(YYSIZE_T)
double dfMMax
Definition: shapefil.h:362
SHPHandle SHPAPI_CALL SHPOpen(const char *pszLayer, const char *pszAccess)
Definition: shpopen.c:464
int * SAFile
Definition: shapefil.h:242
unsigned char * pabyRec
Definition: shapefil.h:297
double dfYMax
Definition: shapefil.h:360
int nSHPType
Definition: shapefil.h:340
int bUpdated
Definition: shapefil.h:295
SHPHandle SHPAPI_CALL SHPOpenLL(const char *pszLayer, const char *pszAccess, SAHooks *psHooks)
Definition: shpopen.c:482
#define SHPT_ARC
Definition: shapefil.h:308
double * padfM
Definition: shapefil.h:352
SAFile(* FOpen)(const char *filename, const char *access)
Definition: shapefil.h:255
SHPObject SHPAPI_CALL1 * SHPReadObject(SHPHandle psSHP, int hEntity){ int nEntitySize, nRequiredSize;SHPObject *psShape;char szErrorMsg[128];if(hEntity< 0||hEntity >=psSHP->nRecords) return(NULL
SHPHandle SHPAPI_CALL SHPCreateLL(const char *pszLayer, int nShapeType, SAHooks *psHooks)
Definition: shpopen.c:846
double dfMMin
Definition: shapefil.h:357
#define TRUE
Definition: shpopen.c:278
static void SwapWord(int length, void *wordP)
Definition: shpopen.c:302
unsigned char uchar
Definition: shpopen.c:268
void(* Error)(const char *message)
Definition: shapefil.h:264
#define SHPP_TRISTRIP
Definition: shapefil.h:327
SAOffset(* FRead)(void *p, SAOffset size, SAOffset nmemb, SAFile file)
Definition: shapefil.h:256
void SASetupDefaultHooks(SAHooks *psHooks)
Definition: safileio.c:195
int nShapeType
Definition: shapefil.h:283
SAFile fpSHP
Definition: shapefil.h:280
void SHPAPI_CALL SHPClose(SHPHandle psSHP)
Definition: shpopen.c:759
int * panPartType
Definition: shapefil.h:346