LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/shape - shpopen.c (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 932 719 77.1 %
Date: 2011-12-18 Functions: 19 17 89.5 %

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

Generated by: LCOV version 1.7