LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/shape - shpopen.c (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 918 689 75.1 %
Date: 2010-01-09 Functions: 20 17 85.0 %

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

Generated by: LCOV version 1.7