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