LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/shape - shpopen.c (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 935 733 78.4 %
Date: 2012-12-26 Functions: 19 17 89.5 %

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

Generated by: LCOV version 1.7