GRASS Programmer's Manual  6.4.2(2012)
shpopen.c
Go to the documentation of this file.
00001 /******************************************************************************
00002  * $Id: shpopen.c 32581 2008-08-06 19:30:45Z neteler $
00003  *
00004  * Project:  Shapelib
00005  * Purpose:  Implementation of core Shapefile read/write functions.
00006  * Author:   Frank Warmerdam, warmerdam@pobox.com
00007  *
00008  ******************************************************************************
00009  * Copyright (c) 1999, 2001, Frank Warmerdam
00010  *
00011  * This software is available under the following "MIT Style" license,
00012  * or at the option of the licensee under the LGPL (see LICENSE.LGPL).  This
00013  * option is discussed in more detail in shapelib.html.
00014  *
00015  * --
00016  * 
00017  * Permission is hereby granted, free of charge, to any person obtaining a
00018  * copy of this software and associated documentation files (the "Software"),
00019  * to deal in the Software without restriction, including without limitation
00020  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00021  * and/or sell copies of the Software, and to permit persons to whom the
00022  * Software is furnished to do so, subject to the following conditions:
00023  *
00024  * The above copyright notice and this permission notice shall be included
00025  * in all copies or substantial portions of the Software.
00026  *
00027  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00028  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00029  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00030  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00031  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00032  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00033  * DEALINGS IN THE SOFTWARE.
00034  ******************************************************************************
00035  *
00036  * $Log: shpopen.c,v $
00037  * Revision 1.59  2008/03/14 05:25:31  fwarmerdam
00038  * Correct crash on buggy geometries (gdal #2218)
00039  *
00040  * Revision 1.58  2008/01/08 23:28:26  bram
00041  * on line 2095, use a float instead of a double to avoid a compiler warning
00042  *
00043  * Revision 1.57  2007/12/06 07:00:25  fwarmerdam
00044  * dbfopen now using SAHooks for fileio
00045  *
00046  * Revision 1.56  2007/12/04 20:37:56  fwarmerdam
00047  * preliminary implementation of hooks api for io and errors
00048  *
00049  * Revision 1.55  2007/11/21 22:39:56  fwarmerdam
00050  * close shx file in readonly mode (GDAL #1956)
00051  *
00052  * Revision 1.54  2007/11/15 00:12:47  mloskot
00053  * Backported recent changes from GDAL (Ticket #1415) to Shapelib.
00054  *
00055  * Revision 1.53  2007/11/14 22:31:08  fwarmerdam
00056  * checks after mallocs to detect for corrupted/voluntary broken shapefiles.
00057  * http://trac.osgeo.org/gdal/ticket/1991
00058  *
00059  * Revision 1.52  2007/06/21 15:58:33  fwarmerdam
00060  * fix for SHPRewindObject when rings touch at one vertex (gdal #976)
00061  *
00062  * Revision 1.51  2006/09/04 15:24:01  fwarmerdam
00063  * Fixed up log message for 1.49.
00064  *
00065  * Revision 1.50  2006/09/04 15:21:39  fwarmerdam
00066  * fix of last fix
00067  *
00068  * Revision 1.49  2006/09/04 15:21:00  fwarmerdam
00069  * MLoskot: Added stronger test of Shapefile reading failures, e.g. truncated
00070  * files.  The problem was discovered by Tim Sutton and reported here
00071  *   https://svn.qgis.org/trac/ticket/200
00072  *
00073  * Revision 1.48  2006/01/26 15:07:32  fwarmerdam
00074  * add bMeasureIsUsed flag from Craig Bruce: Bug 1249
00075  *
00076  * Revision 1.47  2006/01/04 20:07:23  fwarmerdam
00077  * In SHPWriteObject() make sure that the record length is updated
00078  * when rewriting an existing record.
00079  *
00080  * Revision 1.46  2005/02/11 17:17:46  fwarmerdam
00081  * added panPartStart[0] validation
00082  *
00083  * Revision 1.45  2004/09/26 20:09:48  fwarmerdam
00084  * const correctness changes
00085  *
00086  * Revision 1.44  2003/12/29 00:18:39  fwarmerdam
00087  * added error checking for failed IO and optional CPL error reporting
00088  *
00089  * Revision 1.43  2003/12/01 16:20:08  warmerda
00090  * be careful of zero vertex shapes
00091  *
00092  * Revision 1.42  2003/12/01 14:58:27  warmerda
00093  * added degenerate object check in SHPRewindObject()
00094  *
00095  * Revision 1.41  2003/07/08 15:22:43  warmerda
00096  * avoid warning
00097  *
00098  * Revision 1.40  2003/04/21 18:30:37  warmerda
00099  * added header write/update public methods
00100  *
00101  * Revision 1.39  2002/08/26 06:46:56  warmerda
00102  * avoid c++ comments
00103  *
00104  * Revision 1.38  2002/05/07 16:43:39  warmerda
00105  * Removed debugging printf.
00106  *
00107  * Revision 1.37  2002/04/10 17:35:22  warmerda
00108  * fixed bug in ring reversal code
00109  *
00110  * Revision 1.36  2002/04/10 16:59:54  warmerda
00111  * added SHPRewindObject
00112  *
00113  * Revision 1.35  2001/12/07 15:10:44  warmerda
00114  * fix if .shx fails to open
00115  *
00116  * Revision 1.34  2001/11/01 16:29:55  warmerda
00117  * move pabyRec into SHPInfo for thread safety
00118  *
00119  * Revision 1.33  2001/07/03 12:18:15  warmerda
00120  * Improved cleanup if SHX not found, provied by Riccardo Cohen.
00121  *
00122  * Revision 1.32  2001/06/22 01:58:07  warmerda
00123  * be more careful about establishing initial bounds in face of NULL shapes
00124  *
00125  * Revision 1.31  2001/05/31 19:35:29  warmerda
00126  * added support for writing null shapes
00127  *
00128  * Revision 1.30  2001/05/28 12:46:29  warmerda
00129  * Add some checking on reasonableness of record count when opening.
00130  *
00131  * Revision 1.29  2001/05/23 13:36:52  warmerda
00132  * added use of SHPAPI_CALL
00133  *
00134  * Revision 1.28  2001/02/06 22:25:06  warmerda
00135  * fixed memory leaks when SHPOpen() fails
00136  *
00137  * Revision 1.27  2000/07/18 15:21:33  warmerda
00138  * added better enforcement of -1 for append in SHPWriteObject
00139  *
00140  * Revision 1.26  2000/02/16 16:03:51  warmerda
00141  * added null shape support
00142  *
00143  * Revision 1.25  1999/12/15 13:47:07  warmerda
00144  * Fixed record size settings in .shp file (was 4 words too long)
00145  * Added stdlib.h.
00146  *
00147  * Revision 1.24  1999/11/05 14:12:04  warmerda
00148  * updated license terms
00149  *
00150  * Revision 1.23  1999/07/27 00:53:46  warmerda
00151  * added support for rewriting shapes
00152  *
00153  * Revision 1.22  1999/06/11 19:19:11  warmerda
00154  * Cleanup pabyRec static buffer on SHPClose().
00155  *
00156  * Revision 1.21  1999/06/02 14:57:56  kshih
00157  * Remove unused variables
00158  *
00159  * Revision 1.20  1999/04/19 21:04:17  warmerda
00160  * Fixed syntax error.
00161  *
00162  * Revision 1.19  1999/04/19 21:01:57  warmerda
00163  * Force access string to binary in SHPOpen().
00164  *
00165  * Revision 1.18  1999/04/01 18:48:07  warmerda
00166  * Try upper case extensions if lower case doesn't work.
00167  *
00168  * Revision 1.17  1998/12/31 15:29:39  warmerda
00169  * Disable writing measure values to multipatch objects if
00170  * DISABLE_MULTIPATCH_MEASURE is defined.
00171  *
00172  * Revision 1.16  1998/12/16 05:14:33  warmerda
00173  * Added support to write MULTIPATCH.  Fixed reading Z coordinate of
00174  * MULTIPATCH. Fixed record size written for all feature types.
00175  *
00176  * Revision 1.15  1998/12/03 16:35:29  warmerda
00177  * r+b is proper binary access string, not rb+.
00178  *
00179  * Revision 1.14  1998/12/03 15:47:56  warmerda
00180  * Fixed setting of nVertices in SHPCreateObject().
00181  *
00182  * Revision 1.13  1998/12/03 15:33:54  warmerda
00183  * Made SHPCalculateExtents() separately callable.
00184  *
00185  * Revision 1.12  1998/11/11 20:01:50  warmerda
00186  * Fixed bug writing ArcM/Z, and PolygonM/Z for big endian machines.
00187  *
00188  * Revision 1.11  1998/11/09 20:56:44  warmerda
00189  * Fixed up handling of file wide bounds.
00190  *
00191  * Revision 1.10  1998/11/09 20:18:51  warmerda
00192  * Converted to support 3D shapefiles, and use of SHPObject.
00193  *
00194  * Revision 1.9  1998/02/24 15:09:05  warmerda
00195  * Fixed memory leak.
00196  *
00197  * Revision 1.8  1997/12/04 15:40:29  warmerda
00198  * Fixed byte swapping of record number, and record length fields in the
00199  * .shp file.
00200  *
00201  * Revision 1.7  1995/10/21 03:15:58  warmerda
00202  * Added support for binary file access, the magic cookie 9997
00203  * and tried to improve the int32 selection logic for 16bit systems.
00204  *
00205  * Revision 1.6  1995/09/04  04:19:41  warmerda
00206  * Added fix for file bounds.
00207  *
00208  * Revision 1.5  1995/08/25  15:16:44  warmerda
00209  * Fixed a couple of problems with big endian systems ... one with bounds
00210  * and the other with multipart polygons.
00211  *
00212  * Revision 1.4  1995/08/24  18:10:17  warmerda
00213  * Switch to use SfRealloc() to avoid problems with pre-ANSI realloc()
00214  * functions (such as on the Sun).
00215  *
00216  * Revision 1.3  1995/08/23  02:23:15  warmerda
00217  * Added support for reading bounds, and fixed up problems in setting the
00218  * file wide bounds.
00219  *
00220  * Revision 1.2  1995/08/04  03:16:57  warmerda
00221  * Added header.
00222  *
00223  */
00224 
00225 #include <grass/shapefil.h>
00226 
00227 #include <math.h>
00228 #include <limits.h>
00229 #include <assert.h>
00230 #include <stdlib.h>
00231 #include <string.h>
00232 #include <stdio.h>
00233 
00234 SHP_CVSID("$Id: shpopen.c 32581 2008-08-06 19:30:45Z neteler $")
00235 
00236 typedef unsigned char uchar;
00237 
00238 #if UINT_MAX == 65535
00239 typedef long          int32;
00240 #else
00241 typedef int           int32;
00242 #endif
00243 
00244 #ifndef FALSE
00245 #  define FALSE         0
00246 #  define TRUE          1
00247 #endif
00248 
00249 #define ByteCopy( a, b, c )     memcpy( b, a, c )
00250 #ifndef MAX
00251 #  define MIN(a,b)      ((a<b) ? a : b)
00252 #  define MAX(a,b)      ((a>b) ? a : b)
00253 #endif
00254 
00255 static int      bBigEndian;
00256 
00257 
00258 /************************************************************************/
00259 /*                              SwapWord()                              */
00260 /*                                                                      */
00261 /*      Swap a 2, 4 or 8 byte word.                                     */
00262 /************************************************************************/
00263 
00264 static void     SwapWord( int length, void * wordP )
00265 
00266 {
00267     int         i;
00268     uchar       temp;
00269 
00270     for( i=0; i < length/2; i++ )
00271     {
00272         temp = ((uchar *) wordP)[i];
00273         ((uchar *)wordP)[i] = ((uchar *) wordP)[length-i-1];
00274         ((uchar *) wordP)[length-i-1] = temp;
00275     }
00276 }
00277 
00278 /************************************************************************/
00279 /*                             SfRealloc()                              */
00280 /*                                                                      */
00281 /*      A realloc cover function that will access a NULL pointer as     */
00282 /*      a valid input.                                                  */
00283 /************************************************************************/
00284 
00285 static void * SfRealloc( void * pMem, int nNewSize )
00286 
00287 {
00288     if( pMem == NULL )
00289         return( (void *) malloc(nNewSize) );
00290     else
00291         return( (void *) realloc(pMem,nNewSize) );
00292 }
00293 
00294 /************************************************************************/
00295 /*                          SHPWriteHeader()                            */
00296 /*                                                                      */
00297 /*      Write out a header for the .shp and .shx files as well as the   */
00298 /*      contents of the index (.shx) file.                              */
00299 /************************************************************************/
00300 
00301 void SHPWriteHeader( SHPHandle psSHP )
00302 
00303 {
00304     uchar       abyHeader[100];
00305     int         i;
00306     int32       i32;
00307     double      dValue;
00308     int32       *panSHX;
00309     
00310     if (psSHP->fpSHX == NULL)
00311     {
00312         psSHP->sHooks.Error( "SHPWriteHeader failed : SHX file is closed");
00313         return;
00314     }
00315 
00316 /* -------------------------------------------------------------------- */
00317 /*      Prepare header block for .shp file.                             */
00318 /* -------------------------------------------------------------------- */
00319     for( i = 0; i < 100; i++ )
00320       abyHeader[i] = 0;
00321 
00322     abyHeader[2] = 0x27;                                /* magic cookie */
00323     abyHeader[3] = 0x0a;
00324 
00325     i32 = psSHP->nFileSize/2;                           /* file size */
00326     ByteCopy( &i32, abyHeader+24, 4 );
00327     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
00328     
00329     i32 = 1000;                                         /* version */
00330     ByteCopy( &i32, abyHeader+28, 4 );
00331     if( bBigEndian ) SwapWord( 4, abyHeader+28 );
00332     
00333     i32 = psSHP->nShapeType;                            /* shape type */
00334     ByteCopy( &i32, abyHeader+32, 4 );
00335     if( bBigEndian ) SwapWord( 4, abyHeader+32 );
00336 
00337     dValue = psSHP->adBoundsMin[0];                     /* set bounds */
00338     ByteCopy( &dValue, abyHeader+36, 8 );
00339     if( bBigEndian ) SwapWord( 8, abyHeader+36 );
00340 
00341     dValue = psSHP->adBoundsMin[1];
00342     ByteCopy( &dValue, abyHeader+44, 8 );
00343     if( bBigEndian ) SwapWord( 8, abyHeader+44 );
00344 
00345     dValue = psSHP->adBoundsMax[0];
00346     ByteCopy( &dValue, abyHeader+52, 8 );
00347     if( bBigEndian ) SwapWord( 8, abyHeader+52 );
00348 
00349     dValue = psSHP->adBoundsMax[1];
00350     ByteCopy( &dValue, abyHeader+60, 8 );
00351     if( bBigEndian ) SwapWord( 8, abyHeader+60 );
00352 
00353     dValue = psSHP->adBoundsMin[2];                     /* z */
00354     ByteCopy( &dValue, abyHeader+68, 8 );
00355     if( bBigEndian ) SwapWord( 8, abyHeader+68 );
00356 
00357     dValue = psSHP->adBoundsMax[2];
00358     ByteCopy( &dValue, abyHeader+76, 8 );
00359     if( bBigEndian ) SwapWord( 8, abyHeader+76 );
00360 
00361     dValue = psSHP->adBoundsMin[3];                     /* m */
00362     ByteCopy( &dValue, abyHeader+84, 8 );
00363     if( bBigEndian ) SwapWord( 8, abyHeader+84 );
00364 
00365     dValue = psSHP->adBoundsMax[3];
00366     ByteCopy( &dValue, abyHeader+92, 8 );
00367     if( bBigEndian ) SwapWord( 8, abyHeader+92 );
00368 
00369 /* -------------------------------------------------------------------- */
00370 /*      Write .shp file header.                                         */
00371 /* -------------------------------------------------------------------- */
00372     if( psSHP->sHooks.FSeek( psSHP->fpSHP, 0, 0 ) != 0 
00373         || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHP ) != 1 )
00374     {
00375         psSHP->sHooks.Error( "Failure writing .shp header" );
00376         return;
00377     }
00378 
00379 /* -------------------------------------------------------------------- */
00380 /*      Prepare, and write .shx file header.                            */
00381 /* -------------------------------------------------------------------- */
00382     i32 = (psSHP->nRecords * 2 * sizeof(int32) + 100)/2;   /* file size */
00383     ByteCopy( &i32, abyHeader+24, 4 );
00384     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
00385     
00386     if( psSHP->sHooks.FSeek( psSHP->fpSHX, 0, 0 ) != 0 
00387         || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHX ) != 1 )
00388     {
00389         psSHP->sHooks.Error( "Failure writing .shx header" );
00390         return;
00391     }
00392 
00393 /* -------------------------------------------------------------------- */
00394 /*      Write out the .shx contents.                                    */
00395 /* -------------------------------------------------------------------- */
00396     panSHX = (int32 *) malloc(sizeof(int32) * 2 * psSHP->nRecords);
00397 
00398     for( i = 0; i < psSHP->nRecords; i++ )
00399     {
00400         panSHX[i*2  ] = psSHP->panRecOffset[i]/2;
00401         panSHX[i*2+1] = psSHP->panRecSize[i]/2;
00402         if( !bBigEndian ) SwapWord( 4, panSHX+i*2 );
00403         if( !bBigEndian ) SwapWord( 4, panSHX+i*2+1 );
00404     }
00405 
00406     if( (int)psSHP->sHooks.FWrite( panSHX, sizeof(int32)*2, psSHP->nRecords, psSHP->fpSHX ) 
00407         != psSHP->nRecords )
00408     {
00409         psSHP->sHooks.Error( "Failure writing .shx contents" );
00410     }
00411 
00412     free( panSHX );
00413 
00414 /* -------------------------------------------------------------------- */
00415 /*      Flush to disk.                                                  */
00416 /* -------------------------------------------------------------------- */
00417     psSHP->sHooks.FFlush( psSHP->fpSHP );
00418     psSHP->sHooks.FFlush( psSHP->fpSHX );
00419 }
00420 
00421 /************************************************************************/
00422 /*                              SHPOpen()                               */
00423 /************************************************************************/
00424 
00425 SHPHandle SHPAPI_CALL
00426 SHPOpen( const char * pszLayer, const char * pszAccess )
00427 
00428 {
00429     SAHooks sHooks;
00430 
00431     SASetupDefaultHooks( &sHooks );
00432 
00433     return SHPOpenLL( pszLayer, pszAccess, &sHooks );
00434 }
00435 
00436 /************************************************************************/
00437 /*                              SHPOpen()                               */
00438 /*                                                                      */
00439 /*      Open the .shp and .shx files based on the basename of the       */
00440 /*      files or either file name.                                      */
00441 /************************************************************************/
00442    
00443 SHPHandle SHPAPI_CALL
00444 SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
00445 
00446 {
00447     char                *pszFullname, *pszBasename;
00448     SHPHandle           psSHP;
00449     
00450     uchar               *pabyBuf;
00451     int                 i;
00452     double              dValue;
00453     
00454 /* -------------------------------------------------------------------- */
00455 /*      Ensure the access string is one of the legal ones.  We          */
00456 /*      ensure the result string indicates binary to avoid common       */
00457 /*      problems on Windows.                                            */
00458 /* -------------------------------------------------------------------- */
00459     if( strcmp(pszAccess,"rb+") == 0 || strcmp(pszAccess,"r+b") == 0
00460         || strcmp(pszAccess,"r+") == 0 )
00461         pszAccess = "r+b";
00462     else
00463         pszAccess = "rb";
00464     
00465 /* -------------------------------------------------------------------- */
00466 /*      Establish the byte order on this machine.                       */
00467 /* -------------------------------------------------------------------- */
00468     i = 1;
00469     if( *((uchar *) &i) == 1 )
00470         bBigEndian = FALSE;
00471     else
00472         bBigEndian = TRUE;
00473 
00474 /* -------------------------------------------------------------------- */
00475 /*      Initialize the info structure.                                  */
00476 /* -------------------------------------------------------------------- */
00477     psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1);
00478 
00479     psSHP->bUpdated = FALSE;
00480     memcpy( &(psSHP->sHooks), psHooks, sizeof(SAHooks) );
00481 
00482 /* -------------------------------------------------------------------- */
00483 /*      Compute the base (layer) name.  If there is any extension       */
00484 /*      on the passed in filename we will strip it off.                 */
00485 /* -------------------------------------------------------------------- */
00486     pszBasename = (char *) malloc(strlen(pszLayer)+5);
00487     strcpy( pszBasename, pszLayer );
00488     for( i = strlen(pszBasename)-1; 
00489          i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
00490                && pszBasename[i] != '\\';
00491          i-- ) {}
00492 
00493     if( pszBasename[i] == '.' )
00494         pszBasename[i] = '\0';
00495 
00496 /* -------------------------------------------------------------------- */
00497 /*      Open the .shp and .shx files.  Note that files pulled from      */
00498 /*      a PC to Unix with upper case filenames won't work!              */
00499 /* -------------------------------------------------------------------- */
00500     pszFullname = (char *) malloc(strlen(pszBasename) + 5);
00501     sprintf( pszFullname, "%s.shp", pszBasename ) ;
00502     psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
00503     if( psSHP->fpSHP == NULL )
00504     {
00505         sprintf( pszFullname, "%s.SHP", pszBasename );
00506         psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
00507     }
00508     
00509     if( psSHP->fpSHP == NULL )
00510     {
00511 #ifdef USE_CPL
00512         CPLError( CE_Failure, CPLE_OpenFailed, 
00513                   "Unable to open %s.shp or %s.SHP.", 
00514                   pszBasename, pszBasename );
00515 #endif
00516         free( psSHP );
00517         free( pszBasename );
00518         free( pszFullname );
00519         return( NULL );
00520     }
00521 
00522     sprintf( pszFullname, "%s.shx", pszBasename );
00523     psSHP->fpSHX =  psSHP->sHooks.FOpen(pszFullname, pszAccess );
00524     if( psSHP->fpSHX == NULL )
00525     {
00526         sprintf( pszFullname, "%s.SHX", pszBasename );
00527         psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess );
00528     }
00529     
00530     if( psSHP->fpSHX == NULL )
00531     {
00532 #ifdef USE_CPL
00533         CPLError( CE_Failure, CPLE_OpenFailed, 
00534                   "Unable to open %s.shx or %s.SHX.", 
00535                   pszBasename, pszBasename );
00536 #endif
00537         psSHP->sHooks.FClose( psSHP->fpSHP );
00538         free( psSHP );
00539         free( pszBasename );
00540         free( pszFullname );
00541         return( NULL );
00542     }
00543 
00544     free( pszFullname );
00545     free( pszBasename );
00546 
00547 /* -------------------------------------------------------------------- */
00548 /*  Read the file size from the SHP file.                               */
00549 /* -------------------------------------------------------------------- */
00550     pabyBuf = (uchar *) malloc(100);
00551     psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHP );
00552 
00553     psSHP->nFileSize = (pabyBuf[24] * 256 * 256 * 256
00554                         + pabyBuf[25] * 256 * 256
00555                         + pabyBuf[26] * 256
00556                         + pabyBuf[27]) * 2;
00557 
00558 /* -------------------------------------------------------------------- */
00559 /*  Read SHX file Header info                                           */
00560 /* -------------------------------------------------------------------- */
00561     if( psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHX ) != 1 
00562         || pabyBuf[0] != 0 
00563         || pabyBuf[1] != 0 
00564         || pabyBuf[2] != 0x27 
00565         || (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d) )
00566     {
00567         psSHP->sHooks.Error( ".shx file is unreadable, or corrupt." );
00568         psSHP->sHooks.FClose( psSHP->fpSHP );
00569         psSHP->sHooks.FClose( psSHP->fpSHX );
00570         free( psSHP );
00571 
00572         return( NULL );
00573     }
00574 
00575     psSHP->nRecords = pabyBuf[27] + pabyBuf[26] * 256
00576       + pabyBuf[25] * 256 * 256 + pabyBuf[24] * 256 * 256 * 256;
00577     psSHP->nRecords = (psSHP->nRecords*2 - 100) / 8;
00578 
00579     psSHP->nShapeType = pabyBuf[32];
00580 
00581     if( psSHP->nRecords < 0 || psSHP->nRecords > 256000000 )
00582     {
00583         char szError[200];
00584         
00585         sprintf( szError, 
00586                  "Record count in .shp header is %d, which seems\n"
00587                  "unreasonable.  Assuming header is corrupt.",
00588                   psSHP->nRecords );
00589         psSHP->sHooks.Error( szError );                                
00590         psSHP->sHooks.FClose( psSHP->fpSHP );
00591         psSHP->sHooks.FClose( psSHP->fpSHX );
00592         free( psSHP );
00593         free(pabyBuf);
00594 
00595         return( NULL );
00596     }
00597 
00598 /* -------------------------------------------------------------------- */
00599 /*      Read the bounds.                                                */
00600 /* -------------------------------------------------------------------- */
00601     if( bBigEndian ) SwapWord( 8, pabyBuf+36 );
00602     memcpy( &dValue, pabyBuf+36, 8 );
00603     psSHP->adBoundsMin[0] = dValue;
00604 
00605     if( bBigEndian ) SwapWord( 8, pabyBuf+44 );
00606     memcpy( &dValue, pabyBuf+44, 8 );
00607     psSHP->adBoundsMin[1] = dValue;
00608 
00609     if( bBigEndian ) SwapWord( 8, pabyBuf+52 );
00610     memcpy( &dValue, pabyBuf+52, 8 );
00611     psSHP->adBoundsMax[0] = dValue;
00612 
00613     if( bBigEndian ) SwapWord( 8, pabyBuf+60 );
00614     memcpy( &dValue, pabyBuf+60, 8 );
00615     psSHP->adBoundsMax[1] = dValue;
00616 
00617     if( bBigEndian ) SwapWord( 8, pabyBuf+68 );         /* z */
00618     memcpy( &dValue, pabyBuf+68, 8 );
00619     psSHP->adBoundsMin[2] = dValue;
00620     
00621     if( bBigEndian ) SwapWord( 8, pabyBuf+76 );
00622     memcpy( &dValue, pabyBuf+76, 8 );
00623     psSHP->adBoundsMax[2] = dValue;
00624     
00625     if( bBigEndian ) SwapWord( 8, pabyBuf+84 );         /* z */
00626     memcpy( &dValue, pabyBuf+84, 8 );
00627     psSHP->adBoundsMin[3] = dValue;
00628 
00629     if( bBigEndian ) SwapWord( 8, pabyBuf+92 );
00630     memcpy( &dValue, pabyBuf+92, 8 );
00631     psSHP->adBoundsMax[3] = dValue;
00632 
00633     free( pabyBuf );
00634 
00635 /* -------------------------------------------------------------------- */
00636 /*      Read the .shx file to get the offsets to each record in         */
00637 /*      the .shp file.                                                  */
00638 /* -------------------------------------------------------------------- */
00639     psSHP->nMaxRecords = psSHP->nRecords;
00640 
00641     psSHP->panRecOffset =
00642         (int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) );
00643     psSHP->panRecSize =
00644         (int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) );
00645     pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) );
00646 
00647     if (psSHP->panRecOffset == NULL ||
00648         psSHP->panRecSize == NULL ||
00649         pabyBuf == NULL)
00650     {
00651         char szError[200];
00652 
00653         sprintf(szError, 
00654                 "Not enough memory to allocate requested memory (nRecords=%d).\n"
00655                 "Probably broken SHP file", 
00656                 psSHP->nRecords );
00657         psSHP->sHooks.Error( szError );
00658         psSHP->sHooks.FClose( psSHP->fpSHP );
00659         psSHP->sHooks.FClose( psSHP->fpSHX );
00660         if (psSHP->panRecOffset) free( psSHP->panRecOffset );
00661         if (psSHP->panRecSize) free( psSHP->panRecSize );
00662         if (pabyBuf) free( pabyBuf );
00663         free( psSHP );
00664         return( NULL );
00665     }
00666 
00667     if( (int) psSHP->sHooks.FRead( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX ) 
00668                         != psSHP->nRecords )
00669     {
00670         char szError[200];
00671 
00672         sprintf( szError, 
00673                  "Failed to read all values for %d records in .shx file.",
00674                  psSHP->nRecords );
00675         psSHP->sHooks.Error( szError );
00676 
00677         /* SHX is short or unreadable for some reason. */
00678         psSHP->sHooks.FClose( psSHP->fpSHP );
00679         psSHP->sHooks.FClose( psSHP->fpSHX );
00680         free( psSHP->panRecOffset );
00681         free( psSHP->panRecSize );
00682         free( pabyBuf );
00683         free( psSHP );
00684 
00685         return( NULL );
00686     }
00687     
00688     /* In read-only mode, we can close the SHX now */
00689     if (strcmp(pszAccess, "rb") == 0)
00690     {
00691         psSHP->sHooks.FClose( psSHP->fpSHX );
00692         psSHP->fpSHX = NULL;
00693     }
00694 
00695     for( i = 0; i < psSHP->nRecords; i++ )
00696     {
00697         int32           nOffset, nLength;
00698 
00699         memcpy( &nOffset, pabyBuf + i * 8, 4 );
00700         if( !bBigEndian ) SwapWord( 4, &nOffset );
00701 
00702         memcpy( &nLength, pabyBuf + i * 8 + 4, 4 );
00703         if( !bBigEndian ) SwapWord( 4, &nLength );
00704 
00705         psSHP->panRecOffset[i] = nOffset*2;
00706         psSHP->panRecSize[i] = nLength*2;
00707     }
00708     free( pabyBuf );
00709 
00710     return( psSHP );
00711 }
00712 
00713 /************************************************************************/
00714 /*                              SHPClose()                              */
00715 /*                                                                      */
00716 /*      Close the .shp and .shx files.                                  */
00717 /************************************************************************/
00718 
00719 void SHPAPI_CALL
00720 SHPClose(SHPHandle psSHP )
00721 
00722 {
00723     if( psSHP == NULL )
00724         return;
00725 
00726 /* -------------------------------------------------------------------- */
00727 /*      Update the header if we have modified anything.                 */
00728 /* -------------------------------------------------------------------- */
00729     if( psSHP->bUpdated )
00730         SHPWriteHeader( psSHP );
00731 
00732 /* -------------------------------------------------------------------- */
00733 /*      Free all resources, and close files.                            */
00734 /* -------------------------------------------------------------------- */
00735     free( psSHP->panRecOffset );
00736     free( psSHP->panRecSize );
00737 
00738     if ( psSHP->fpSHX != NULL)
00739         psSHP->sHooks.FClose( psSHP->fpSHX );
00740     psSHP->sHooks.FClose( psSHP->fpSHP );
00741 
00742     if( psSHP->pabyRec != NULL )
00743     {
00744         free( psSHP->pabyRec );
00745     }
00746     
00747     free( psSHP );
00748 }
00749 
00750 /************************************************************************/
00751 /*                             SHPGetInfo()                             */
00752 /*                                                                      */
00753 /*      Fetch general information about the shape file.                 */
00754 /************************************************************************/
00755 
00756 void SHPAPI_CALL
00757 SHPGetInfo(SHPHandle psSHP, int * pnEntities, int * pnShapeType,
00758            double * padfMinBound, double * padfMaxBound )
00759 
00760 {
00761     int         i;
00762 
00763     if( psSHP == NULL )
00764         return;
00765     
00766     if( pnEntities != NULL )
00767         *pnEntities = psSHP->nRecords;
00768 
00769     if( pnShapeType != NULL )
00770         *pnShapeType = psSHP->nShapeType;
00771 
00772     for( i = 0; i < 4; i++ )
00773     {
00774         if( padfMinBound != NULL )
00775             padfMinBound[i] = psSHP->adBoundsMin[i];
00776         if( padfMaxBound != NULL )
00777             padfMaxBound[i] = psSHP->adBoundsMax[i];
00778     }
00779 }
00780 
00781 /************************************************************************/
00782 /*                             SHPCreate()                              */
00783 /*                                                                      */
00784 /*      Create a new shape file and return a handle to the open         */
00785 /*      shape file with read/write access.                              */
00786 /************************************************************************/
00787 
00788 SHPHandle SHPAPI_CALL
00789 SHPCreate( const char * pszLayer, int nShapeType )
00790 
00791 {
00792     SAHooks sHooks;
00793 
00794     SASetupDefaultHooks( &sHooks );
00795 
00796     return SHPCreateLL( pszLayer, nShapeType, &sHooks );
00797 }
00798 
00799 /************************************************************************/
00800 /*                             SHPCreate()                              */
00801 /*                                                                      */
00802 /*      Create a new shape file and return a handle to the open         */
00803 /*      shape file with read/write access.                              */
00804 /************************************************************************/
00805 
00806 SHPHandle SHPAPI_CALL
00807 SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
00808 
00809 {
00810     char        *pszBasename, *pszFullname;
00811     int         i;
00812     SAFile      fpSHP, fpSHX;
00813     uchar       abyHeader[100];
00814     int32       i32;
00815     double      dValue;
00816     
00817 /* -------------------------------------------------------------------- */
00818 /*      Establish the byte order on this system.                        */
00819 /* -------------------------------------------------------------------- */
00820     i = 1;
00821     if( *((uchar *) &i) == 1 )
00822         bBigEndian = FALSE;
00823     else
00824         bBigEndian = TRUE;
00825 
00826 /* -------------------------------------------------------------------- */
00827 /*      Compute the base (layer) name.  If there is any extension       */
00828 /*      on the passed in filename we will strip it off.                 */
00829 /* -------------------------------------------------------------------- */
00830     pszBasename = (char *) malloc(strlen(pszLayer)+5);
00831     strcpy( pszBasename, pszLayer );
00832     for( i = strlen(pszBasename)-1; 
00833          i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
00834                && pszBasename[i] != '\\';
00835          i-- ) {}
00836 
00837     if( pszBasename[i] == '.' )
00838         pszBasename[i] = '\0';
00839 
00840 /* -------------------------------------------------------------------- */
00841 /*      Open the two files so we can write their headers.               */
00842 /* -------------------------------------------------------------------- */
00843     pszFullname = (char *) malloc(strlen(pszBasename) + 5);
00844     sprintf( pszFullname, "%s.shp", pszBasename );
00845     fpSHP = psHooks->FOpen(pszFullname, "wb" );
00846     if( fpSHP == NULL )
00847     {
00848         psHooks->Error( "Failed to create file .shp file." );
00849         return( NULL );
00850     }
00851 
00852     sprintf( pszFullname, "%s.shx", pszBasename );
00853     fpSHX = psHooks->FOpen(pszFullname, "wb" );
00854     if( fpSHX == NULL )
00855     {
00856         psHooks->Error( "Failed to create file .shx file." );
00857         return( NULL );
00858     }
00859 
00860     free( pszFullname );
00861     free( pszBasename );
00862 
00863 /* -------------------------------------------------------------------- */
00864 /*      Prepare header block for .shp file.                             */
00865 /* -------------------------------------------------------------------- */
00866     for( i = 0; i < 100; i++ )
00867       abyHeader[i] = 0;
00868 
00869     abyHeader[2] = 0x27;                                /* magic cookie */
00870     abyHeader[3] = 0x0a;
00871 
00872     i32 = 50;                                           /* file size */
00873     ByteCopy( &i32, abyHeader+24, 4 );
00874     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
00875     
00876     i32 = 1000;                                         /* version */
00877     ByteCopy( &i32, abyHeader+28, 4 );
00878     if( bBigEndian ) SwapWord( 4, abyHeader+28 );
00879     
00880     i32 = nShapeType;                                   /* shape type */
00881     ByteCopy( &i32, abyHeader+32, 4 );
00882     if( bBigEndian ) SwapWord( 4, abyHeader+32 );
00883 
00884     dValue = 0.0;                                       /* set bounds */
00885     ByteCopy( &dValue, abyHeader+36, 8 );
00886     ByteCopy( &dValue, abyHeader+44, 8 );
00887     ByteCopy( &dValue, abyHeader+52, 8 );
00888     ByteCopy( &dValue, abyHeader+60, 8 );
00889 
00890 /* -------------------------------------------------------------------- */
00891 /*      Write .shp file header.                                         */
00892 /* -------------------------------------------------------------------- */
00893     if( psHooks->FWrite( abyHeader, 100, 1, fpSHP ) != 1 )
00894     {
00895         psHooks->Error( "Failed to write .shp header." );
00896         return NULL;
00897     }
00898 
00899 /* -------------------------------------------------------------------- */
00900 /*      Prepare, and write .shx file header.                            */
00901 /* -------------------------------------------------------------------- */
00902     i32 = 50;                                           /* file size */
00903     ByteCopy( &i32, abyHeader+24, 4 );
00904     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
00905     
00906     if( psHooks->FWrite( abyHeader, 100, 1, fpSHX ) != 1 )
00907     {
00908         psHooks->Error( "Failed to write .shx header." );
00909         return NULL;
00910     }
00911 
00912 /* -------------------------------------------------------------------- */
00913 /*      Close the files, and then open them as regular existing files.  */
00914 /* -------------------------------------------------------------------- */
00915     psHooks->FClose( fpSHP );
00916     psHooks->FClose( fpSHX );
00917 
00918     return( SHPOpenLL( pszLayer, "r+b", psHooks ) );
00919 }
00920 
00921 /************************************************************************/
00922 /*                           _SHPSetBounds()                            */
00923 /*                                                                      */
00924 /*      Compute a bounds rectangle for a shape, and set it into the     */
00925 /*      indicated location in the record.                               */
00926 /************************************************************************/
00927 
00928 static void     _SHPSetBounds( uchar * pabyRec, SHPObject * psShape )
00929 
00930 {
00931     ByteCopy( &(psShape->dfXMin), pabyRec +  0, 8 );
00932     ByteCopy( &(psShape->dfYMin), pabyRec +  8, 8 );
00933     ByteCopy( &(psShape->dfXMax), pabyRec + 16, 8 );
00934     ByteCopy( &(psShape->dfYMax), pabyRec + 24, 8 );
00935 
00936     if( bBigEndian )
00937     {
00938         SwapWord( 8, pabyRec + 0 );
00939         SwapWord( 8, pabyRec + 8 );
00940         SwapWord( 8, pabyRec + 16 );
00941         SwapWord( 8, pabyRec + 24 );
00942     }
00943 }
00944 
00945 /************************************************************************/
00946 /*                         SHPComputeExtents()                          */
00947 /*                                                                      */
00948 /*      Recompute the extents of a shape.  Automatically done by        */
00949 /*      SHPCreateObject().                                              */
00950 /************************************************************************/
00951 
00952 void SHPAPI_CALL
00953 SHPComputeExtents( SHPObject * psObject )
00954 
00955 {
00956     int         i;
00957     
00958 /* -------------------------------------------------------------------- */
00959 /*      Build extents for this object.                                  */
00960 /* -------------------------------------------------------------------- */
00961     if( psObject->nVertices > 0 )
00962     {
00963         psObject->dfXMin = psObject->dfXMax = psObject->padfX[0];
00964         psObject->dfYMin = psObject->dfYMax = psObject->padfY[0];
00965         psObject->dfZMin = psObject->dfZMax = psObject->padfZ[0];
00966         psObject->dfMMin = psObject->dfMMax = psObject->padfM[0];
00967     }
00968     
00969     for( i = 0; i < psObject->nVertices; i++ )
00970     {
00971         psObject->dfXMin = MIN(psObject->dfXMin, psObject->padfX[i]);
00972         psObject->dfYMin = MIN(psObject->dfYMin, psObject->padfY[i]);
00973         psObject->dfZMin = MIN(psObject->dfZMin, psObject->padfZ[i]);
00974         psObject->dfMMin = MIN(psObject->dfMMin, psObject->padfM[i]);
00975 
00976         psObject->dfXMax = MAX(psObject->dfXMax, psObject->padfX[i]);
00977         psObject->dfYMax = MAX(psObject->dfYMax, psObject->padfY[i]);
00978         psObject->dfZMax = MAX(psObject->dfZMax, psObject->padfZ[i]);
00979         psObject->dfMMax = MAX(psObject->dfMMax, psObject->padfM[i]);
00980     }
00981 }
00982 
00983 /************************************************************************/
00984 /*                          SHPCreateObject()                           */
00985 /*                                                                      */
00986 /*      Create a shape object.  It should be freed with                 */
00987 /*      SHPDestroyObject().                                             */
00988 /************************************************************************/
00989 
00990 SHPObject SHPAPI_CALL1(*)
00991 SHPCreateObject( int nSHPType, int nShapeId, int nParts,
00992                  const int * panPartStart, const int * panPartType,
00993                  int nVertices, const double *padfX, const double *padfY,
00994                  const double * padfZ, const double * padfM )
00995 
00996 {
00997     SHPObject   *psObject;
00998     int         i, bHasM, bHasZ;
00999 
01000     psObject = (SHPObject *) calloc(1,sizeof(SHPObject));
01001     psObject->nSHPType = nSHPType;
01002     psObject->nShapeId = nShapeId;
01003     psObject->bMeasureIsUsed = FALSE;
01004 
01005 /* -------------------------------------------------------------------- */
01006 /*      Establish whether this shape type has M, and Z values.          */
01007 /* -------------------------------------------------------------------- */
01008     if( nSHPType == SHPT_ARCM
01009         || nSHPType == SHPT_POINTM
01010         || nSHPType == SHPT_POLYGONM
01011         || nSHPType == SHPT_MULTIPOINTM )
01012     {
01013         bHasM = TRUE;
01014         bHasZ = FALSE;
01015     }
01016     else if( nSHPType == SHPT_ARCZ
01017              || nSHPType == SHPT_POINTZ
01018              || nSHPType == SHPT_POLYGONZ
01019              || nSHPType == SHPT_MULTIPOINTZ
01020              || nSHPType == SHPT_MULTIPATCH )
01021     {
01022         bHasM = TRUE;
01023         bHasZ = TRUE;
01024     }
01025     else
01026     {
01027         bHasM = FALSE;
01028         bHasZ = FALSE;
01029     }
01030 
01031 /* -------------------------------------------------------------------- */
01032 /*      Capture parts.  Note that part type is optional, and            */
01033 /*      defaults to ring.                                               */
01034 /* -------------------------------------------------------------------- */
01035     if( nSHPType == SHPT_ARC || nSHPType == SHPT_POLYGON
01036         || nSHPType == SHPT_ARCM || nSHPType == SHPT_POLYGONM
01037         || nSHPType == SHPT_ARCZ || nSHPType == SHPT_POLYGONZ
01038         || nSHPType == SHPT_MULTIPATCH )
01039     {
01040         psObject->nParts = MAX(1,nParts);
01041 
01042         psObject->panPartStart = (int *)
01043             malloc(sizeof(int) * psObject->nParts);
01044         psObject->panPartType = (int *)
01045             malloc(sizeof(int) * psObject->nParts);
01046 
01047         psObject->panPartStart[0] = 0;
01048         psObject->panPartType[0] = SHPP_RING;
01049         
01050         for( i = 0; i < nParts; i++ )
01051         {
01052             psObject->panPartStart[i] = panPartStart[i];
01053 
01054             if( panPartType != NULL )
01055                 psObject->panPartType[i] = panPartType[i];
01056             else
01057                 psObject->panPartType[i] = SHPP_RING;
01058         }
01059 
01060         if( psObject->panPartStart[0] != 0 )
01061             psObject->panPartStart[0] = 0;
01062     }
01063 
01064 /* -------------------------------------------------------------------- */
01065 /*      Capture vertices.  Note that Z and M are optional, but X and    */
01066 /*      Y are not.                                                      */
01067 /* -------------------------------------------------------------------- */
01068     if( nVertices > 0 )
01069     {
01070         psObject->padfX = (double *) calloc(sizeof(double),nVertices);
01071         psObject->padfY = (double *) calloc(sizeof(double),nVertices);
01072         psObject->padfZ = (double *) calloc(sizeof(double),nVertices);
01073         psObject->padfM = (double *) calloc(sizeof(double),nVertices);
01074 
01075         assert( padfX != NULL );
01076         assert( padfY != NULL );
01077     
01078         for( i = 0; i < nVertices; i++ )
01079         {
01080             psObject->padfX[i] = padfX[i];
01081             psObject->padfY[i] = padfY[i];
01082             if( padfZ != NULL && bHasZ )
01083                 psObject->padfZ[i] = padfZ[i];
01084             if( padfM != NULL && bHasM )
01085                 psObject->padfM[i] = padfM[i];
01086         }
01087         if( padfM != NULL && bHasM )
01088             psObject->bMeasureIsUsed = TRUE;
01089     }
01090 
01091 /* -------------------------------------------------------------------- */
01092 /*      Compute the extents.                                            */
01093 /* -------------------------------------------------------------------- */
01094     psObject->nVertices = nVertices;
01095     SHPComputeExtents( psObject );
01096 
01097     return( psObject );
01098 }
01099 
01100 /************************************************************************/
01101 /*                       SHPCreateSimpleObject()                        */
01102 /*                                                                      */
01103 /*      Create a simple (common) shape object.  Destroy with            */
01104 /*      SHPDestroyObject().                                             */
01105 /************************************************************************/
01106 
01107 SHPObject SHPAPI_CALL1(*)
01108 SHPCreateSimpleObject( int nSHPType, int nVertices,
01109                        const double * padfX, const double * padfY,
01110                        const double * padfZ )
01111 
01112 {
01113     return( SHPCreateObject( nSHPType, -1, 0, NULL, NULL,
01114                              nVertices, padfX, padfY, padfZ, NULL ) );
01115 }
01116                                   
01117 /************************************************************************/
01118 /*                           SHPWriteObject()                           */
01119 /*                                                                      */
01120 /*      Write out the vertices of a new structure.  Note that it is     */
01121 /*      only possible to write vertices at the end of the file.         */
01122 /************************************************************************/
01123 
01124 int SHPAPI_CALL
01125 SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
01126                       
01127 {
01128     int         nRecordOffset, i, nRecordSize=0;
01129     uchar       *pabyRec;
01130     int32       i32;
01131 
01132     psSHP->bUpdated = TRUE;
01133 
01134 /* -------------------------------------------------------------------- */
01135 /*      Ensure that shape object matches the type of the file it is     */
01136 /*      being written to.                                               */
01137 /* -------------------------------------------------------------------- */
01138     assert( psObject->nSHPType == psSHP->nShapeType 
01139             || psObject->nSHPType == SHPT_NULL );
01140 
01141 /* -------------------------------------------------------------------- */
01142 /*      Ensure that -1 is used for appends.  Either blow an             */
01143 /*      assertion, or if they are disabled, set the shapeid to -1       */
01144 /*      for appends.                                                    */
01145 /* -------------------------------------------------------------------- */
01146     assert( nShapeId == -1 
01147             || (nShapeId >= 0 && nShapeId < psSHP->nRecords) );
01148 
01149     if( nShapeId != -1 && nShapeId >= psSHP->nRecords )
01150         nShapeId = -1;
01151 
01152 /* -------------------------------------------------------------------- */
01153 /*      Add the new entity to the in memory index.                      */
01154 /* -------------------------------------------------------------------- */
01155     if( nShapeId == -1 && psSHP->nRecords+1 > psSHP->nMaxRecords )
01156     {
01157         psSHP->nMaxRecords =(int) ( psSHP->nMaxRecords * 1.3 + 100);
01158 
01159         psSHP->panRecOffset = (int *) 
01160             SfRealloc(psSHP->panRecOffset,sizeof(int) * psSHP->nMaxRecords );
01161         psSHP->panRecSize = (int *) 
01162             SfRealloc(psSHP->panRecSize,sizeof(int) * psSHP->nMaxRecords );
01163     }
01164 
01165 /* -------------------------------------------------------------------- */
01166 /*      Initialize record.                                              */
01167 /* -------------------------------------------------------------------- */
01168     pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double) 
01169                                + psObject->nParts * 8 + 128);
01170     
01171 /* -------------------------------------------------------------------- */
01172 /*  Extract vertices for a Polygon or Arc.                              */
01173 /* -------------------------------------------------------------------- */
01174     if( psObject->nSHPType == SHPT_POLYGON
01175         || psObject->nSHPType == SHPT_POLYGONZ
01176         || psObject->nSHPType == SHPT_POLYGONM
01177         || psObject->nSHPType == SHPT_ARC 
01178         || psObject->nSHPType == SHPT_ARCZ
01179         || psObject->nSHPType == SHPT_ARCM
01180         || psObject->nSHPType == SHPT_MULTIPATCH )
01181     {
01182         int32           nPoints, nParts;
01183         int             i;
01184 
01185         nPoints = psObject->nVertices;
01186         nParts = psObject->nParts;
01187 
01188         _SHPSetBounds( pabyRec + 12, psObject );
01189 
01190         if( bBigEndian ) SwapWord( 4, &nPoints );
01191         if( bBigEndian ) SwapWord( 4, &nParts );
01192 
01193         ByteCopy( &nPoints, pabyRec + 40 + 8, 4 );
01194         ByteCopy( &nParts, pabyRec + 36 + 8, 4 );
01195 
01196         nRecordSize = 52;
01197 
01198         /*
01199          * Write part start positions.
01200          */
01201         ByteCopy( psObject->panPartStart, pabyRec + 44 + 8,
01202                   4 * psObject->nParts );
01203         for( i = 0; i < psObject->nParts; i++ )
01204         {
01205             if( bBigEndian ) SwapWord( 4, pabyRec + 44 + 8 + 4*i );
01206             nRecordSize += 4;
01207         }
01208 
01209         /*
01210          * Write multipatch part types if needed.
01211          */
01212         if( psObject->nSHPType == SHPT_MULTIPATCH )
01213         {
01214             memcpy( pabyRec + nRecordSize, psObject->panPartType,
01215                     4*psObject->nParts );
01216             for( i = 0; i < psObject->nParts; i++ )
01217             {
01218                 if( bBigEndian ) SwapWord( 4, pabyRec + nRecordSize );
01219                 nRecordSize += 4;
01220             }
01221         }
01222 
01223         /*
01224          * Write the (x,y) vertex values.
01225          */
01226         for( i = 0; i < psObject->nVertices; i++ )
01227         {
01228             ByteCopy( psObject->padfX + i, pabyRec + nRecordSize, 8 );
01229             ByteCopy( psObject->padfY + i, pabyRec + nRecordSize + 8, 8 );
01230 
01231             if( bBigEndian )
01232                 SwapWord( 8, pabyRec + nRecordSize );
01233             
01234             if( bBigEndian )
01235                 SwapWord( 8, pabyRec + nRecordSize + 8 );
01236 
01237             nRecordSize += 2 * 8;
01238         }
01239 
01240         /*
01241          * Write the Z coordinates (if any).
01242          */
01243         if( psObject->nSHPType == SHPT_POLYGONZ
01244             || psObject->nSHPType == SHPT_ARCZ
01245             || psObject->nSHPType == SHPT_MULTIPATCH )
01246         {
01247             ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
01248             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01249             nRecordSize += 8;
01250             
01251             ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
01252             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01253             nRecordSize += 8;
01254 
01255             for( i = 0; i < psObject->nVertices; i++ )
01256             {
01257                 ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
01258                 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01259                 nRecordSize += 8;
01260             }
01261         }
01262 
01263         /*
01264          * Write the M values, if any.
01265          */
01266         if( psObject->bMeasureIsUsed
01267             && (psObject->nSHPType == SHPT_POLYGONM
01268             || psObject->nSHPType == SHPT_ARCM
01269 #ifndef DISABLE_MULTIPATCH_MEASURE            
01270             || psObject->nSHPType == SHPT_MULTIPATCH
01271 #endif            
01272             || psObject->nSHPType == SHPT_POLYGONZ
01273             || psObject->nSHPType == SHPT_ARCZ) )
01274         {
01275             ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
01276             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01277             nRecordSize += 8;
01278             
01279             ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
01280             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01281             nRecordSize += 8;
01282 
01283             for( i = 0; i < psObject->nVertices; i++ )
01284             {
01285                 ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
01286                 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01287                 nRecordSize += 8;
01288             }
01289         }
01290     }
01291 
01292 /* -------------------------------------------------------------------- */
01293 /*  Extract vertices for a MultiPoint.                                  */
01294 /* -------------------------------------------------------------------- */
01295     else if( psObject->nSHPType == SHPT_MULTIPOINT
01296              || psObject->nSHPType == SHPT_MULTIPOINTZ
01297              || psObject->nSHPType == SHPT_MULTIPOINTM )
01298     {
01299         int32           nPoints;
01300         int             i;
01301 
01302         nPoints = psObject->nVertices;
01303 
01304         _SHPSetBounds( pabyRec + 12, psObject );
01305 
01306         if( bBigEndian ) SwapWord( 4, &nPoints );
01307         ByteCopy( &nPoints, pabyRec + 44, 4 );
01308         
01309         for( i = 0; i < psObject->nVertices; i++ )
01310         {
01311             ByteCopy( psObject->padfX + i, pabyRec + 48 + i*16, 8 );
01312             ByteCopy( psObject->padfY + i, pabyRec + 48 + i*16 + 8, 8 );
01313 
01314             if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 );
01315             if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 + 8 );
01316         }
01317 
01318         nRecordSize = 48 + 16 * psObject->nVertices;
01319 
01320         if( psObject->nSHPType == SHPT_MULTIPOINTZ )
01321         {
01322             ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
01323             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01324             nRecordSize += 8;
01325 
01326             ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
01327             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01328             nRecordSize += 8;
01329             
01330             for( i = 0; i < psObject->nVertices; i++ )
01331             {
01332                 ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
01333                 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01334                 nRecordSize += 8;
01335             }
01336         }
01337 
01338         if( psObject->bMeasureIsUsed
01339             && (psObject->nSHPType == SHPT_MULTIPOINTZ
01340             || psObject->nSHPType == SHPT_MULTIPOINTM) )
01341         {
01342             ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
01343             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01344             nRecordSize += 8;
01345 
01346             ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
01347             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01348             nRecordSize += 8;
01349             
01350             for( i = 0; i < psObject->nVertices; i++ )
01351             {
01352                 ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
01353                 if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01354                 nRecordSize += 8;
01355             }
01356         }
01357     }
01358 
01359 /* -------------------------------------------------------------------- */
01360 /*      Write point.                                                    */
01361 /* -------------------------------------------------------------------- */
01362     else if( psObject->nSHPType == SHPT_POINT
01363              || psObject->nSHPType == SHPT_POINTZ
01364              || psObject->nSHPType == SHPT_POINTM )
01365     {
01366         ByteCopy( psObject->padfX, pabyRec + 12, 8 );
01367         ByteCopy( psObject->padfY, pabyRec + 20, 8 );
01368 
01369         if( bBigEndian ) SwapWord( 8, pabyRec + 12 );
01370         if( bBigEndian ) SwapWord( 8, pabyRec + 20 );
01371 
01372         nRecordSize = 28;
01373         
01374         if( psObject->nSHPType == SHPT_POINTZ )
01375         {
01376             ByteCopy( psObject->padfZ, pabyRec + nRecordSize, 8 );
01377             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01378             nRecordSize += 8;
01379         }
01380         
01381         if( psObject->bMeasureIsUsed
01382             && (psObject->nSHPType == SHPT_POINTZ
01383             || psObject->nSHPType == SHPT_POINTM) )
01384         {
01385             ByteCopy( psObject->padfM, pabyRec + nRecordSize, 8 );
01386             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
01387             nRecordSize += 8;
01388         }
01389     }
01390 
01391 /* -------------------------------------------------------------------- */
01392 /*      Not much to do for null geometries.                             */
01393 /* -------------------------------------------------------------------- */
01394     else if( psObject->nSHPType == SHPT_NULL )
01395     {
01396         nRecordSize = 12;
01397     }
01398 
01399     else
01400     {
01401         /* unknown type */
01402         assert( FALSE );
01403     }
01404 
01405 /* -------------------------------------------------------------------- */
01406 /*      Establish where we are going to put this record. If we are      */
01407 /*      rewriting and existing record, and it will fit, then put it     */
01408 /*      back where the original came from.  Otherwise write at the end. */
01409 /* -------------------------------------------------------------------- */
01410     if( nShapeId == -1 || psSHP->panRecSize[nShapeId] < nRecordSize-8 )
01411     {
01412         if( nShapeId == -1 )
01413             nShapeId = psSHP->nRecords++;
01414 
01415         psSHP->panRecOffset[nShapeId] = nRecordOffset = psSHP->nFileSize;
01416         psSHP->panRecSize[nShapeId] = nRecordSize-8;
01417         psSHP->nFileSize += nRecordSize;
01418     }
01419     else
01420     {
01421         nRecordOffset = psSHP->panRecOffset[nShapeId];
01422         psSHP->panRecSize[nShapeId] = nRecordSize-8;
01423     }
01424     
01425 /* -------------------------------------------------------------------- */
01426 /*      Set the shape type, record number, and record size.             */
01427 /* -------------------------------------------------------------------- */
01428     i32 = nShapeId+1;                                   /* record # */
01429     if( !bBigEndian ) SwapWord( 4, &i32 );
01430     ByteCopy( &i32, pabyRec, 4 );
01431 
01432     i32 = (nRecordSize-8)/2;                            /* record size */
01433     if( !bBigEndian ) SwapWord( 4, &i32 );
01434     ByteCopy( &i32, pabyRec + 4, 4 );
01435 
01436     i32 = psObject->nSHPType;                           /* shape type */
01437     if( bBigEndian ) SwapWord( 4, &i32 );
01438     ByteCopy( &i32, pabyRec + 8, 4 );
01439 
01440 /* -------------------------------------------------------------------- */
01441 /*      Write out record.                                               */
01442 /* -------------------------------------------------------------------- */
01443     if( psSHP->sHooks.FSeek( psSHP->fpSHP, nRecordOffset, 0 ) != 0
01444         || psSHP->sHooks.FWrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 )
01445     {
01446         psSHP->sHooks.Error( "Error in psSHP->sHooks.FSeek() or fwrite() writing object to .shp file." );
01447         free( pabyRec );
01448         return -1;
01449     }
01450     
01451     free( pabyRec );
01452 
01453 /* -------------------------------------------------------------------- */
01454 /*      Expand file wide bounds based on this shape.                    */
01455 /* -------------------------------------------------------------------- */
01456     if( psSHP->adBoundsMin[0] == 0.0
01457         && psSHP->adBoundsMax[0] == 0.0
01458         && psSHP->adBoundsMin[1] == 0.0
01459         && psSHP->adBoundsMax[1] == 0.0 )
01460     {
01461         if( psObject->nSHPType == SHPT_NULL || psObject->nVertices == 0 )
01462         {
01463             psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = 0.0;
01464             psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = 0.0;
01465             psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = 0.0;
01466             psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = 0.0;
01467         }
01468         else
01469         {
01470             psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = psObject->padfX[0];
01471             psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = psObject->padfY[0];
01472             psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ[0];
01473             psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM[0];
01474         }
01475     }
01476 
01477     for( i = 0; i < psObject->nVertices; i++ )
01478     {
01479         psSHP->adBoundsMin[0] = MIN(psSHP->adBoundsMin[0],psObject->padfX[i]);
01480         psSHP->adBoundsMin[1] = MIN(psSHP->adBoundsMin[1],psObject->padfY[i]);
01481         psSHP->adBoundsMin[2] = MIN(psSHP->adBoundsMin[2],psObject->padfZ[i]);
01482         psSHP->adBoundsMin[3] = MIN(psSHP->adBoundsMin[3],psObject->padfM[i]);
01483         psSHP->adBoundsMax[0] = MAX(psSHP->adBoundsMax[0],psObject->padfX[i]);
01484         psSHP->adBoundsMax[1] = MAX(psSHP->adBoundsMax[1],psObject->padfY[i]);
01485         psSHP->adBoundsMax[2] = MAX(psSHP->adBoundsMax[2],psObject->padfZ[i]);
01486         psSHP->adBoundsMax[3] = MAX(psSHP->adBoundsMax[3],psObject->padfM[i]);
01487     }
01488 
01489     return( nShapeId  );
01490 }
01491 
01492 /************************************************************************/
01493 /*                          SHPReadObject()                             */
01494 /*                                                                      */
01495 /*      Read the vertices, parts, and other non-attribute information   */
01496 /*      for one shape.                                                  */
01497 /************************************************************************/
01498 
01499 SHPObject SHPAPI_CALL1(*)
01500 SHPReadObject( SHPHandle psSHP, int hEntity )
01501 
01502 {
01503     int                  nEntitySize, nRequiredSize;
01504     SHPObject           *psShape;
01505     char                 pszErrorMsg[128];
01506 
01507 /* -------------------------------------------------------------------- */
01508 /*      Validate the record/entity number.                              */
01509 /* -------------------------------------------------------------------- */
01510     if( hEntity < 0 || hEntity >= psSHP->nRecords )
01511         return( NULL );
01512 
01513 /* -------------------------------------------------------------------- */
01514 /*      Ensure our record buffer is large enough.                       */
01515 /* -------------------------------------------------------------------- */
01516     nEntitySize = psSHP->panRecSize[hEntity]+8;
01517     if( nEntitySize > psSHP->nBufSize )
01518     {
01519         psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,nEntitySize);
01520         if (psSHP->pabyRec == NULL)
01521         {
01522             char szError[200];
01523 
01524             /* Reallocate previous successfull size for following features */
01525             psSHP->pabyRec = malloc(psSHP->nBufSize);
01526 
01527             sprintf( szError, 
01528                      "Not enough memory to allocate requested memory (nBufSize=%d). "
01529                      "Probably broken SHP file", psSHP->nBufSize );
01530             psSHP->sHooks.Error( szError );
01531             return NULL;
01532         }
01533 
01534         /* Only set new buffer size after successfull alloc */
01535         psSHP->nBufSize = nEntitySize;
01536     }
01537 
01538     /* In case we were not able to reallocate the buffer on a previous step */
01539     if (psSHP->pabyRec == NULL)
01540     {
01541         return NULL;
01542     }
01543 
01544 /* -------------------------------------------------------------------- */
01545 /*      Read the record.                                                */
01546 /* -------------------------------------------------------------------- */
01547     if( psSHP->sHooks.FSeek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 ) != 0 
01548         || psSHP->sHooks.FRead( psSHP->pabyRec, nEntitySize, 1, 
01549                   psSHP->fpSHP ) != 1 )
01550     {
01551         /*
01552          * TODO - mloskot: Consider detailed diagnostics of shape file,
01553          * for example to detect if file is truncated.
01554          */
01555 
01556         psSHP->sHooks.Error( "Error in fseek() or fread() reading object from .shp file." );
01557         return NULL;
01558     }
01559 
01560 /* -------------------------------------------------------------------- */
01561 /*      Allocate and minimally initialize the object.                   */
01562 /* -------------------------------------------------------------------- */
01563     psShape = (SHPObject *) calloc(1,sizeof(SHPObject));
01564     psShape->nShapeId = hEntity;
01565     psShape->bMeasureIsUsed = FALSE;
01566 
01567     if ( 8 + 4 > nEntitySize )
01568     {
01569         snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d",
01570                     hEntity, nEntitySize); 
01571         psSHP->sHooks.Error( pszErrorMsg );
01572         SHPDestroyObject(psShape);
01573         return NULL;
01574     }
01575     memcpy( &psShape->nSHPType, psSHP->pabyRec + 8, 4 );
01576 
01577     if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) );
01578 
01579 /* ==================================================================== */
01580 /*  Extract vertices for a Polygon or Arc.                              */
01581 /* ==================================================================== */
01582     if( psShape->nSHPType == SHPT_POLYGON || psShape->nSHPType == SHPT_ARC
01583         || psShape->nSHPType == SHPT_POLYGONZ
01584         || psShape->nSHPType == SHPT_POLYGONM
01585         || psShape->nSHPType == SHPT_ARCZ
01586         || psShape->nSHPType == SHPT_ARCM
01587         || psShape->nSHPType == SHPT_MULTIPATCH )
01588     {
01589         int32           nPoints, nParts;
01590         int             i, nOffset;
01591 
01592         if ( 40 + 8 + 4 > nEntitySize )
01593         {
01594             snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d",
01595                      hEntity, nEntitySize); 
01596             psSHP->sHooks.Error( pszErrorMsg );
01597             SHPDestroyObject(psShape);
01598             return NULL;
01599         }
01600 /* -------------------------------------------------------------------- */
01601 /*      Get the X/Y bounds.                                             */
01602 /* -------------------------------------------------------------------- */
01603         memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 +  4, 8 );
01604         memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );
01605         memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
01606         memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
01607 
01608         if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
01609         if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
01610         if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
01611         if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
01612 
01613 /* -------------------------------------------------------------------- */
01614 /*      Extract part/point count, and build vertex and part arrays      */
01615 /*      to proper size.                                                 */
01616 /* -------------------------------------------------------------------- */
01617         memcpy( &nPoints, psSHP->pabyRec + 40 + 8, 4 );
01618         memcpy( &nParts, psSHP->pabyRec + 36 + 8, 4 );
01619 
01620         if( bBigEndian ) SwapWord( 4, &nPoints );
01621         if( bBigEndian ) SwapWord( 4, &nParts );
01622 
01623         if (nPoints < 0 || nParts < 0 ||
01624             nPoints > 50 * 1000 * 1000 || nParts > 10 * 1000 * 1000)
01625         {
01626             snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d.",
01627                         hEntity, nPoints, nParts);
01628             psSHP->sHooks.Error( pszErrorMsg );
01629             SHPDestroyObject(psShape);
01630             return NULL;
01631         }
01632         
01633         /* With the previous checks on nPoints and nParts, */
01634         /* we should not overflow here and after */
01635         /* since 50 M * (16 + 8 + 8) = 1 600 MB */
01636         nRequiredSize = 44 + 8 + 4 * nParts + 16 * nPoints;
01637         if ( psShape->nSHPType == SHPT_POLYGONZ
01638             || psShape->nSHPType == SHPT_ARCZ
01639             || psShape->nSHPType == SHPT_MULTIPATCH )
01640         {
01641             nRequiredSize += 16 + 8 * nPoints;
01642         }
01643         if( psShape->nSHPType == SHPT_MULTIPATCH )
01644         {
01645             nRequiredSize += 4 * nParts;
01646         }
01647         if (nRequiredSize > nEntitySize)
01648         {
01649             snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d, nEntitySize=%d.",
01650                         hEntity, nPoints, nParts, nEntitySize);
01651             psSHP->sHooks.Error( pszErrorMsg );
01652             SHPDestroyObject(psShape);
01653             return NULL;
01654         }
01655 
01656         psShape->nVertices = nPoints;
01657         psShape->padfX = (double *) calloc(nPoints,sizeof(double));
01658         psShape->padfY = (double *) calloc(nPoints,sizeof(double));
01659         psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
01660         psShape->padfM = (double *) calloc(nPoints,sizeof(double));
01661 
01662         psShape->nParts = nParts;
01663         psShape->panPartStart = (int *) calloc(nParts,sizeof(int));
01664         psShape->panPartType = (int *) calloc(nParts,sizeof(int));
01665         
01666         if (psShape->padfX == NULL ||
01667             psShape->padfY == NULL ||
01668             psShape->padfZ == NULL ||
01669             psShape->padfM == NULL ||
01670             psShape->panPartStart == NULL ||
01671             psShape->panPartType == NULL)
01672         {
01673             snprintf(pszErrorMsg, 128,
01674                      "Not enough memory to allocate requested memory (nPoints=%d, nParts=%d) for shape %d. "
01675                      "Probably broken SHP file", hEntity, nPoints, nParts );
01676             psSHP->sHooks.Error( pszErrorMsg );
01677             SHPDestroyObject(psShape);
01678             return NULL;
01679         }
01680 
01681         for( i = 0; i < nParts; i++ )
01682             psShape->panPartType[i] = SHPP_RING;
01683 
01684 /* -------------------------------------------------------------------- */
01685 /*      Copy out the part array from the record.                        */
01686 /* -------------------------------------------------------------------- */
01687         memcpy( psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts );
01688         for( i = 0; i < nParts; i++ )
01689         {
01690             if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i );
01691 
01692             /* We check that the offset is inside the vertex array */
01693             if (psShape->panPartStart[i] < 0 ||
01694                 psShape->panPartStart[i] >= psShape->nVertices)
01695             {
01696                 snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : panPartStart[%d] = %d, nVertices = %d",
01697                          hEntity, i, psShape->panPartStart[i], psShape->nVertices); 
01698                 psSHP->sHooks.Error( pszErrorMsg );
01699                 SHPDestroyObject(psShape);
01700                 return NULL;
01701             }
01702             if (i > 0 && psShape->panPartStart[i] <= psShape->panPartStart[i-1])
01703             {
01704                 snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : panPartStart[%d] = %d, panPartStart[%d] = %d",
01705                          hEntity, i, psShape->panPartStart[i], i - 1, psShape->panPartStart[i - 1]); 
01706                 psSHP->sHooks.Error( pszErrorMsg );
01707                 SHPDestroyObject(psShape);
01708                 return NULL;
01709             }
01710         }
01711 
01712         nOffset = 44 + 8 + 4*nParts;
01713 
01714 /* -------------------------------------------------------------------- */
01715 /*      If this is a multipatch, we will also have parts types.         */
01716 /* -------------------------------------------------------------------- */
01717         if( psShape->nSHPType == SHPT_MULTIPATCH )
01718         {
01719             memcpy( psShape->panPartType, psSHP->pabyRec + nOffset, 4*nParts );
01720             for( i = 0; i < nParts; i++ )
01721             {
01722                 if( bBigEndian ) SwapWord( 4, psShape->panPartType+i );
01723             }
01724 
01725             nOffset += 4*nParts;
01726         }
01727         
01728 /* -------------------------------------------------------------------- */
01729 /*      Copy out the vertices from the record.                          */
01730 /* -------------------------------------------------------------------- */
01731         for( i = 0; i < nPoints; i++ )
01732         {
01733             memcpy(psShape->padfX + i,
01734                    psSHP->pabyRec + nOffset + i * 16,
01735                    8 );
01736 
01737             memcpy(psShape->padfY + i,
01738                    psSHP->pabyRec + nOffset + i * 16 + 8,
01739                    8 );
01740 
01741             if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
01742             if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
01743         }
01744 
01745         nOffset += 16*nPoints;
01746         
01747 /* -------------------------------------------------------------------- */
01748 /*      If we have a Z coordinate, collect that now.                    */
01749 /* -------------------------------------------------------------------- */
01750         if( psShape->nSHPType == SHPT_POLYGONZ
01751             || psShape->nSHPType == SHPT_ARCZ
01752             || psShape->nSHPType == SHPT_MULTIPATCH )
01753         {
01754             memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
01755             memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
01756             
01757             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
01758             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
01759             
01760             for( i = 0; i < nPoints; i++ )
01761             {
01762                 memcpy( psShape->padfZ + i,
01763                         psSHP->pabyRec + nOffset + 16 + i*8, 8 );
01764                 if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
01765             }
01766 
01767             nOffset += 16 + 8*nPoints;
01768         }
01769 
01770 /* -------------------------------------------------------------------- */
01771 /*      If we have a M measure value, then read it now.  We assume      */
01772 /*      that the measure can be present for any shape if the size is    */
01773 /*      big enough, but really it will only occur for the Z shapes      */
01774 /*      (options), and the M shapes.                                    */
01775 /* -------------------------------------------------------------------- */
01776         if( nEntitySize >= nOffset + 16 + 8*nPoints )
01777         {
01778             memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
01779             memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
01780             
01781             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
01782             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
01783             
01784             for( i = 0; i < nPoints; i++ )
01785             {
01786                 memcpy( psShape->padfM + i,
01787                         psSHP->pabyRec + nOffset + 16 + i*8, 8 );
01788                 if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
01789             }
01790             psShape->bMeasureIsUsed = TRUE;
01791         }
01792     }
01793 
01794 /* ==================================================================== */
01795 /*  Extract vertices for a MultiPoint.                                  */
01796 /* ==================================================================== */
01797     else if( psShape->nSHPType == SHPT_MULTIPOINT
01798              || psShape->nSHPType == SHPT_MULTIPOINTM
01799              || psShape->nSHPType == SHPT_MULTIPOINTZ )
01800     {
01801         int32           nPoints;
01802         int             i, nOffset;
01803 
01804         if ( 44 + 4 > nEntitySize )
01805         {
01806             snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d",
01807                      hEntity, nEntitySize); 
01808             psSHP->sHooks.Error( pszErrorMsg );
01809             SHPDestroyObject(psShape);
01810             return NULL;
01811         }
01812         memcpy( &nPoints, psSHP->pabyRec + 44, 4 );
01813 
01814         if( bBigEndian ) SwapWord( 4, &nPoints );
01815 
01816         if (nPoints < 0 || nPoints > 50 * 1000 * 1000)
01817         {
01818             snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nPoints = %d",
01819                      hEntity, nPoints); 
01820             psSHP->sHooks.Error( pszErrorMsg );
01821             SHPDestroyObject(psShape);
01822             return NULL;
01823         }
01824 
01825         nRequiredSize = 48 + nPoints * 16;
01826         if( psShape->nSHPType == SHPT_MULTIPOINTZ )
01827         {
01828             nRequiredSize += 16 + nPoints * 8;
01829         }
01830         if (nRequiredSize > nEntitySize)
01831         {
01832             snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nPoints = %d, nEntitySize = %d",
01833                      hEntity, nPoints, nEntitySize); 
01834             psSHP->sHooks.Error( pszErrorMsg );
01835             SHPDestroyObject(psShape);
01836             return NULL;
01837         }
01838         
01839         psShape->nVertices = nPoints;
01840         psShape->padfX = (double *) calloc(nPoints,sizeof(double));
01841         psShape->padfY = (double *) calloc(nPoints,sizeof(double));
01842         psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
01843         psShape->padfM = (double *) calloc(nPoints,sizeof(double));
01844 
01845         if (psShape->padfX == NULL ||
01846             psShape->padfY == NULL ||
01847             psShape->padfZ == NULL ||
01848             psShape->padfM == NULL)
01849         {
01850             snprintf(pszErrorMsg, 128,
01851                      "Not enough memory to allocate requested memory (nPoints=%d) for shape %d. "
01852                      "Probably broken SHP file", hEntity, nPoints );
01853             psSHP->sHooks.Error( pszErrorMsg );
01854             SHPDestroyObject(psShape);
01855             return NULL;
01856         }
01857 
01858         for( i = 0; i < nPoints; i++ )
01859         {
01860             memcpy(psShape->padfX+i, psSHP->pabyRec + 48 + 16 * i, 8 );
01861             memcpy(psShape->padfY+i, psSHP->pabyRec + 48 + 16 * i + 8, 8 );
01862 
01863             if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
01864             if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
01865         }
01866 
01867         nOffset = 48 + 16*nPoints;
01868         
01869 /* -------------------------------------------------------------------- */
01870 /*      Get the X/Y bounds.                                             */
01871 /* -------------------------------------------------------------------- */
01872         memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 +  4, 8 );
01873         memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );
01874         memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
01875         memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
01876 
01877         if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
01878         if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
01879         if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
01880         if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
01881 
01882 /* -------------------------------------------------------------------- */
01883 /*      If we have a Z coordinate, collect that now.                    */
01884 /* -------------------------------------------------------------------- */
01885         if( psShape->nSHPType == SHPT_MULTIPOINTZ )
01886         {
01887             memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
01888             memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
01889             
01890             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
01891             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
01892             
01893             for( i = 0; i < nPoints; i++ )
01894             {
01895                 memcpy( psShape->padfZ + i,
01896                         psSHP->pabyRec + nOffset + 16 + i*8, 8 );
01897                 if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
01898             }
01899 
01900             nOffset += 16 + 8*nPoints;
01901         }
01902 
01903 /* -------------------------------------------------------------------- */
01904 /*      If we have a M measure value, then read it now.  We assume      */
01905 /*      that the measure can be present for any shape if the size is    */
01906 /*      big enough, but really it will only occur for the Z shapes      */
01907 /*      (options), and the M shapes.                                    */
01908 /* -------------------------------------------------------------------- */
01909         if( nEntitySize >= nOffset + 16 + 8*nPoints )
01910         {
01911             memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
01912             memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
01913             
01914             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
01915             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
01916             
01917             for( i = 0; i < nPoints; i++ )
01918             {
01919                 memcpy( psShape->padfM + i,
01920                         psSHP->pabyRec + nOffset + 16 + i*8, 8 );
01921                 if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
01922             }
01923             psShape->bMeasureIsUsed = TRUE;
01924         }
01925     }
01926 
01927 /* ==================================================================== */
01928 /*      Extract vertices for a point.                                   */
01929 /* ==================================================================== */
01930     else if( psShape->nSHPType == SHPT_POINT
01931              || psShape->nSHPType == SHPT_POINTM
01932              || psShape->nSHPType == SHPT_POINTZ )
01933     {
01934         int     nOffset;
01935         
01936         psShape->nVertices = 1;
01937         psShape->padfX = (double *) calloc(1,sizeof(double));
01938         psShape->padfY = (double *) calloc(1,sizeof(double));
01939         psShape->padfZ = (double *) calloc(1,sizeof(double));
01940         psShape->padfM = (double *) calloc(1,sizeof(double));
01941 
01942         if (20 + 8 + (( psShape->nSHPType == SHPT_POINTZ ) ? 8 : 0)> nEntitySize)
01943         {
01944             snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d",
01945                      hEntity, nEntitySize); 
01946             psSHP->sHooks.Error( pszErrorMsg );
01947             SHPDestroyObject(psShape);
01948             return NULL;
01949         }
01950         memcpy( psShape->padfX, psSHP->pabyRec + 12, 8 );
01951         memcpy( psShape->padfY, psSHP->pabyRec + 20, 8 );
01952 
01953         if( bBigEndian ) SwapWord( 8, psShape->padfX );
01954         if( bBigEndian ) SwapWord( 8, psShape->padfY );
01955 
01956         nOffset = 20 + 8;
01957         
01958 /* -------------------------------------------------------------------- */
01959 /*      If we have a Z coordinate, collect that now.                    */
01960 /* -------------------------------------------------------------------- */
01961         if( psShape->nSHPType == SHPT_POINTZ )
01962         {
01963             memcpy( psShape->padfZ, psSHP->pabyRec + nOffset, 8 );
01964         
01965             if( bBigEndian ) SwapWord( 8, psShape->padfZ );
01966             
01967             nOffset += 8;
01968         }
01969 
01970 /* -------------------------------------------------------------------- */
01971 /*      If we have a M measure value, then read it now.  We assume      */
01972 /*      that the measure can be present for any shape if the size is    */
01973 /*      big enough, but really it will only occur for the Z shapes      */
01974 /*      (options), and the M shapes.                                    */
01975 /* -------------------------------------------------------------------- */
01976         if( nEntitySize >= nOffset + 8 )
01977         {
01978             memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 );
01979         
01980             if( bBigEndian ) SwapWord( 8, psShape->padfM );
01981             psShape->bMeasureIsUsed = TRUE;
01982         }
01983 
01984 /* -------------------------------------------------------------------- */
01985 /*      Since no extents are supplied in the record, we will apply      */
01986 /*      them from the single vertex.                                    */
01987 /* -------------------------------------------------------------------- */
01988         psShape->dfXMin = psShape->dfXMax = psShape->padfX[0];
01989         psShape->dfYMin = psShape->dfYMax = psShape->padfY[0];
01990         psShape->dfZMin = psShape->dfZMax = psShape->padfZ[0];
01991         psShape->dfMMin = psShape->dfMMax = psShape->padfM[0];
01992     }
01993 
01994     return( psShape );
01995 }
01996 
01997 /************************************************************************/
01998 /*                            SHPTypeName()                             */
01999 /************************************************************************/
02000 
02001 const char SHPAPI_CALL1(*)
02002 SHPTypeName( int nSHPType )
02003 
02004 {
02005     switch( nSHPType )
02006     {
02007       case SHPT_NULL:
02008         return "NullShape";
02009 
02010       case SHPT_POINT:
02011         return "Point";
02012 
02013       case SHPT_ARC:
02014         return "Arc";
02015 
02016       case SHPT_POLYGON:
02017         return "Polygon";
02018 
02019       case SHPT_MULTIPOINT:
02020         return "MultiPoint";
02021         
02022       case SHPT_POINTZ:
02023         return "PointZ";
02024 
02025       case SHPT_ARCZ:
02026         return "ArcZ";
02027 
02028       case SHPT_POLYGONZ:
02029         return "PolygonZ";
02030 
02031       case SHPT_MULTIPOINTZ:
02032         return "MultiPointZ";
02033         
02034       case SHPT_POINTM:
02035         return "PointM";
02036 
02037       case SHPT_ARCM:
02038         return "ArcM";
02039 
02040       case SHPT_POLYGONM:
02041         return "PolygonM";
02042 
02043       case SHPT_MULTIPOINTM:
02044         return "MultiPointM";
02045 
02046       case SHPT_MULTIPATCH:
02047         return "MultiPatch";
02048 
02049       default:
02050         return "UnknownShapeType";
02051     }
02052 }
02053 
02054 /************************************************************************/
02055 /*                          SHPPartTypeName()                           */
02056 /************************************************************************/
02057 
02058 const char SHPAPI_CALL1(*)
02059 SHPPartTypeName( int nPartType )
02060 
02061 {
02062     switch( nPartType )
02063     {
02064       case SHPP_TRISTRIP:
02065         return "TriangleStrip";
02066         
02067       case SHPP_TRIFAN:
02068         return "TriangleFan";
02069 
02070       case SHPP_OUTERRING:
02071         return "OuterRing";
02072 
02073       case SHPP_INNERRING:
02074         return "InnerRing";
02075 
02076       case SHPP_FIRSTRING:
02077         return "FirstRing";
02078 
02079       case SHPP_RING:
02080         return "Ring";
02081 
02082       default:
02083         return "UnknownPartType";
02084     }
02085 }
02086 
02087 /************************************************************************/
02088 /*                          SHPDestroyObject()                          */
02089 /************************************************************************/
02090 
02091 void SHPAPI_CALL
02092 SHPDestroyObject( SHPObject * psShape )
02093 
02094 {
02095     if( psShape == NULL )
02096         return;
02097     
02098     if( psShape->padfX != NULL )
02099         free( psShape->padfX );
02100     if( psShape->padfY != NULL )
02101         free( psShape->padfY );
02102     if( psShape->padfZ != NULL )
02103         free( psShape->padfZ );
02104     if( psShape->padfM != NULL )
02105         free( psShape->padfM );
02106 
02107     if( psShape->panPartStart != NULL )
02108         free( psShape->panPartStart );
02109     if( psShape->panPartType != NULL )
02110         free( psShape->panPartType );
02111 
02112     free( psShape );
02113 }
02114 
02115 /************************************************************************/
02116 /*                          SHPRewindObject()                           */
02117 /*                                                                      */
02118 /*      Reset the winding of polygon objects to adhere to the           */
02119 /*      specification.                                                  */
02120 /************************************************************************/
02121 
02122 int SHPAPI_CALL
02123 SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
02124 
02125 {
02126     int  iOpRing, bAltered = 0;
02127 
02128 /* -------------------------------------------------------------------- */
02129 /*      Do nothing if this is not a polygon object.                     */
02130 /* -------------------------------------------------------------------- */
02131     if( psObject->nSHPType != SHPT_POLYGON
02132         && psObject->nSHPType != SHPT_POLYGONZ
02133         && psObject->nSHPType != SHPT_POLYGONM )
02134         return 0;
02135 
02136     if( psObject->nVertices == 0 || psObject->nParts == 0 )
02137         return 0;
02138 
02139 /* -------------------------------------------------------------------- */
02140 /*      Process each of the rings.                                      */
02141 /* -------------------------------------------------------------------- */
02142     for( iOpRing = 0; iOpRing < psObject->nParts; iOpRing++ )
02143     {
02144         int      bInner, iVert, nVertCount, nVertStart, iCheckRing;
02145         double   dfSum, dfTestX, dfTestY;
02146 
02147 /* -------------------------------------------------------------------- */
02148 /*      Determine if this ring is an inner ring or an outer ring        */
02149 /*      relative to all the other rings.  For now we assume the         */
02150 /*      first ring is outer and all others are inner, but eventually    */
02151 /*      we need to fix this to handle multiple island polygons and      */
02152 /*      unordered sets of rings.                                        */
02153 /*                                                                      */
02154 /* -------------------------------------------------------------------- */
02155 
02156         /* Use point in the middle of segment to avoid testing
02157          * common points of rings.
02158          */
02159         dfTestX = ( psObject->padfX[psObject->panPartStart[iOpRing]]
02160                     + psObject->padfX[psObject->panPartStart[iOpRing] + 1] ) / 2;
02161         dfTestY = ( psObject->padfY[psObject->panPartStart[iOpRing]]
02162                     + psObject->padfY[psObject->panPartStart[iOpRing] + 1] ) / 2;
02163 
02164         bInner = FALSE;
02165         for( iCheckRing = 0; iCheckRing < psObject->nParts; iCheckRing++ )
02166         {
02167             int iEdge;
02168 
02169             if( iCheckRing == iOpRing )
02170                 continue;
02171             
02172             nVertStart = psObject->panPartStart[iCheckRing];
02173 
02174             if( iCheckRing == psObject->nParts-1 )
02175                 nVertCount = psObject->nVertices 
02176                     - psObject->panPartStart[iCheckRing];
02177             else
02178                 nVertCount = psObject->panPartStart[iCheckRing+1] 
02179                     - psObject->panPartStart[iCheckRing];
02180 
02181             for( iEdge = 0; iEdge < nVertCount; iEdge++ )
02182             {
02183                 int iNext;
02184 
02185                 if( iEdge < nVertCount-1 )
02186                     iNext = iEdge+1;
02187                 else
02188                     iNext = 0;
02189 
02190                 /* Rule #1:
02191                  * Test whether the edge 'straddles' the horizontal ray from the test point (dfTestY,dfTestY)
02192                  * The rule #1 also excludes edges collinear with the ray.
02193                  */
02194                 if ( ( psObject->padfY[iEdge+nVertStart] < dfTestY
02195                        && dfTestY <= psObject->padfY[iNext+nVertStart] )
02196                     || ( psObject->padfY[iNext+nVertStart] < dfTestY
02197                          && dfTestY <= psObject->padfY[iEdge+nVertStart] ) )
02198                 {
02199                     /* Rule #2:
02200                     * Test if edge-ray intersection is on the right from the test point (dfTestY,dfTestY)
02201                     */
02202                     double const intersect = 
02203                         ( psObject->padfX[iEdge+nVertStart]
02204                           + ( dfTestY - psObject->padfY[iEdge+nVertStart] ) 
02205                           / ( psObject->padfY[iNext+nVertStart] - psObject->padfY[iEdge+nVertStart] )
02206                           * ( psObject->padfX[iNext+nVertStart] - psObject->padfX[iEdge+nVertStart] ) );
02207 
02208                     if (intersect  < dfTestX)
02209                     {
02210                         bInner = !bInner;
02211                     }
02212                 }    
02213             }
02214         } /* for iCheckRing */
02215 
02216 /* -------------------------------------------------------------------- */
02217 /*      Determine the current order of this ring so we will know if     */
02218 /*      it has to be reversed.                                          */
02219 /* -------------------------------------------------------------------- */
02220         nVertStart = psObject->panPartStart[iOpRing];
02221 
02222         if( iOpRing == psObject->nParts-1 )
02223             nVertCount = psObject->nVertices - psObject->panPartStart[iOpRing];
02224         else
02225             nVertCount = psObject->panPartStart[iOpRing+1] 
02226                 - psObject->panPartStart[iOpRing];
02227 
02228         dfSum = 0.0;
02229         for( iVert = nVertStart; iVert < nVertStart+nVertCount-1; iVert++ )
02230         {
02231             dfSum += psObject->padfX[iVert] * psObject->padfY[iVert+1]
02232                 - psObject->padfY[iVert] * psObject->padfX[iVert+1];
02233         }
02234 
02235         dfSum += psObject->padfX[iVert] * psObject->padfY[nVertStart]
02236                - psObject->padfY[iVert] * psObject->padfX[nVertStart];
02237 
02238 /* -------------------------------------------------------------------- */
02239 /*      Reverse if necessary.                                           */
02240 /* -------------------------------------------------------------------- */
02241         if( (dfSum < 0.0 && bInner) || (dfSum > 0.0 && !bInner) )
02242         {
02243             int   i;
02244 
02245             bAltered++;
02246             for( i = 0; i < nVertCount/2; i++ )
02247             {
02248                 double dfSaved;
02249 
02250                 /* Swap X */
02251                 dfSaved = psObject->padfX[nVertStart+i];
02252                 psObject->padfX[nVertStart+i] = 
02253                     psObject->padfX[nVertStart+nVertCount-i-1];
02254                 psObject->padfX[nVertStart+nVertCount-i-1] = dfSaved;
02255 
02256                 /* Swap Y */
02257                 dfSaved = psObject->padfY[nVertStart+i];
02258                 psObject->padfY[nVertStart+i] = 
02259                     psObject->padfY[nVertStart+nVertCount-i-1];
02260                 psObject->padfY[nVertStart+nVertCount-i-1] = dfSaved;
02261 
02262                 /* Swap Z */
02263                 if( psObject->padfZ )
02264                 {
02265                     dfSaved = psObject->padfZ[nVertStart+i];
02266                     psObject->padfZ[nVertStart+i] = 
02267                         psObject->padfZ[nVertStart+nVertCount-i-1];
02268                     psObject->padfZ[nVertStart+nVertCount-i-1] = dfSaved;
02269                 }
02270 
02271                 /* Swap M */
02272                 if( psObject->padfM )
02273                 {
02274                     dfSaved = psObject->padfM[nVertStart+i];
02275                     psObject->padfM[nVertStart+i] = 
02276                         psObject->padfM[nVertStart+nVertCount-i-1];
02277                     psObject->padfM[nVertStart+nVertCount-i-1] = dfSaved;
02278                 }
02279             }
02280         }
02281     }
02282 
02283     return bAltered;
02284 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines