/[thuban]/branches/WIP-pyshapelib-bramz/libraries/shapelib/shpopen.c
ViewVC logotype

Contents of /branches/WIP-pyshapelib-bramz/libraries/shapelib/shpopen.c

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26