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