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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1612 - (hide annotations)
Tue Aug 19 21:29:25 2003 UTC (21 years, 6 months ago) by jan
Original Path: trunk/thuban/libraries/shapelib/shpopen.c
File MIME type: text/plain
File size: 62287 byte(s)
These files have been moved here from thuban/extensions/shapelib/
See there in the Attic for the older history.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26