LTP GCOV extension - code coverage report
Current view: directory - ogr/ogrsf_frmts/shape - shpopen.c
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 830
Code covered: 76.5 % Executed lines: 635

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

Generated by: LTP GCOV extension version 1.5