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