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