123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289 |
- /******************************************************************************
- * $Id$
- *
- * Project: Shapelib
- * Purpose: Implementation of core Shapefile read/write functions.
- * Author: Frank Warmerdam, warmerdam@pobox.com
- *
- ******************************************************************************
- * Copyright (c) 1999, 2001, Frank Warmerdam
- *
- * This software is available under the following "MIT Style" license,
- * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
- * option is discussed in more detail in shapelib.html.
- *
- * --
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- ******************************************************************************
- *
- * $Log: shpopen.c,v $
- * Revision 1.59 2008/03/14 05:25:31 fwarmerdam
- * Correct crash on buggy geometries (gdal #2218)
- *
- * Revision 1.58 2008/01/08 23:28:26 bram
- * on line 2095, use a float instead of a double to avoid a compiler warning
- *
- * Revision 1.57 2007/12/06 07:00:25 fwarmerdam
- * dbfopen now using SAHooks for fileio
- *
- * Revision 1.56 2007/12/04 20:37:56 fwarmerdam
- * preliminary implementation of hooks api for io and errors
- *
- * Revision 1.55 2007/11/21 22:39:56 fwarmerdam
- * close shx file in readonly mode (GDAL #1956)
- *
- * Revision 1.54 2007/11/15 00:12:47 mloskot
- * Backported recent changes from GDAL (Ticket #1415) to Shapelib.
- *
- * Revision 1.53 2007/11/14 22:31:08 fwarmerdam
- * checks after mallocs to detect for corrupted/voluntary broken shapefiles.
- * http://trac.osgeo.org/gdal/ticket/1991
- *
- * Revision 1.52 2007/06/21 15:58:33 fwarmerdam
- * fix for SHPRewindObject when rings touch at one vertex (gdal #976)
- *
- * Revision 1.51 2006/09/04 15:24:01 fwarmerdam
- * Fixed up log message for 1.49.
- *
- * Revision 1.50 2006/09/04 15:21:39 fwarmerdam
- * fix of last fix
- *
- * Revision 1.49 2006/09/04 15:21:00 fwarmerdam
- * MLoskot: Added stronger test of Shapefile reading failures, e.g. truncated
- * files. The problem was discovered by Tim Sutton and reported here
- * https://svn.qgis.org/trac/ticket/200
- *
- * Revision 1.48 2006/01/26 15:07:32 fwarmerdam
- * add bMeasureIsUsed flag from Craig Bruce: Bug 1249
- *
- * Revision 1.47 2006/01/04 20:07:23 fwarmerdam
- * In SHPWriteObject() make sure that the record length is updated
- * when rewriting an existing record.
- *
- * Revision 1.46 2005/02/11 17:17:46 fwarmerdam
- * added panPartStart[0] validation
- *
- * Revision 1.45 2004/09/26 20:09:48 fwarmerdam
- * const correctness changes
- *
- * Revision 1.44 2003/12/29 00:18:39 fwarmerdam
- * added error checking for failed IO and optional CPL error reporting
- *
- * Revision 1.43 2003/12/01 16:20:08 warmerda
- * be careful of zero vertex shapes
- *
- * Revision 1.42 2003/12/01 14:58:27 warmerda
- * added degenerate object check in SHPRewindObject()
- *
- * Revision 1.41 2003/07/08 15:22:43 warmerda
- * avoid warning
- *
- * Revision 1.40 2003/04/21 18:30:37 warmerda
- * added header write/update public methods
- *
- * Revision 1.39 2002/08/26 06:46:56 warmerda
- * avoid c++ comments
- *
- * Revision 1.38 2002/05/07 16:43:39 warmerda
- * Removed debugging printf.
- *
- * Revision 1.37 2002/04/10 17:35:22 warmerda
- * fixed bug in ring reversal code
- *
- * Revision 1.36 2002/04/10 16:59:54 warmerda
- * added SHPRewindObject
- *
- * Revision 1.35 2001/12/07 15:10:44 warmerda
- * fix if .shx fails to open
- *
- * Revision 1.34 2001/11/01 16:29:55 warmerda
- * move pabyRec into SHPInfo for thread safety
- *
- * Revision 1.33 2001/07/03 12:18:15 warmerda
- * Improved cleanup if SHX not found, provied by Riccardo Cohen.
- *
- * Revision 1.32 2001/06/22 01:58:07 warmerda
- * be more careful about establishing initial bounds in face of NULL shapes
- *
- * Revision 1.31 2001/05/31 19:35:29 warmerda
- * added support for writing null shapes
- *
- * Revision 1.30 2001/05/28 12:46:29 warmerda
- * Add some checking on reasonableness of record count when opening.
- *
- * Revision 1.29 2001/05/23 13:36:52 warmerda
- * added use of SHPAPI_CALL
- *
- * Revision 1.28 2001/02/06 22:25:06 warmerda
- * fixed memory leaks when SHPOpen() fails
- *
- * Revision 1.27 2000/07/18 15:21:33 warmerda
- * added better enforcement of -1 for append in SHPWriteObject
- *
- * Revision 1.26 2000/02/16 16:03:51 warmerda
- * added null shape support
- *
- * Revision 1.25 1999/12/15 13:47:07 warmerda
- * Fixed record size settings in .shp file (was 4 words too long)
- * Added stdlib.h.
- *
- * Revision 1.24 1999/11/05 14:12:04 warmerda
- * updated license terms
- *
- * Revision 1.23 1999/07/27 00:53:46 warmerda
- * added support for rewriting shapes
- *
- * Revision 1.22 1999/06/11 19:19:11 warmerda
- * Cleanup pabyRec static buffer on SHPClose().
- *
- * Revision 1.21 1999/06/02 14:57:56 kshih
- * Remove unused variables
- *
- * Revision 1.20 1999/04/19 21:04:17 warmerda
- * Fixed syntax error.
- *
- * Revision 1.19 1999/04/19 21:01:57 warmerda
- * Force access string to binary in SHPOpen().
- *
- * Revision 1.18 1999/04/01 18:48:07 warmerda
- * Try upper case extensions if lower case doesn't work.
- *
- * Revision 1.17 1998/12/31 15:29:39 warmerda
- * Disable writing measure values to multipatch objects if
- * DISABLE_MULTIPATCH_MEASURE is defined.
- *
- * Revision 1.16 1998/12/16 05:14:33 warmerda
- * Added support to write MULTIPATCH. Fixed reading Z coordinate of
- * MULTIPATCH. Fixed record size written for all feature types.
- *
- * Revision 1.15 1998/12/03 16:35:29 warmerda
- * r+b is proper binary access string, not rb+.
- *
- * Revision 1.14 1998/12/03 15:47:56 warmerda
- * Fixed setting of nVertices in SHPCreateObject().
- *
- * Revision 1.13 1998/12/03 15:33:54 warmerda
- * Made SHPCalculateExtents() separately callable.
- *
- * Revision 1.12 1998/11/11 20:01:50 warmerda
- * Fixed bug writing ArcM/Z, and PolygonM/Z for big endian machines.
- *
- * Revision 1.11 1998/11/09 20:56:44 warmerda
- * Fixed up handling of file wide bounds.
- *
- * Revision 1.10 1998/11/09 20:18:51 warmerda
- * Converted to support 3D shapefiles, and use of SHPObject.
- *
- * Revision 1.9 1998/02/24 15:09:05 warmerda
- * Fixed memory leak.
- *
- * Revision 1.8 1997/12/04 15:40:29 warmerda
- * Fixed byte swapping of record number, and record length fields in the
- * .shp file.
- *
- * Revision 1.7 1995/10/21 03:15:58 warmerda
- * Added support for binary file access, the magic cookie 9997
- * and tried to improve the int32 selection logic for 16bit systems.
- *
- * Revision 1.6 1995/09/04 04:19:41 warmerda
- * Added fix for file bounds.
- *
- * Revision 1.5 1995/08/25 15:16:44 warmerda
- * Fixed a couple of problems with big endian systems ... one with bounds
- * and the other with multipart polygons.
- *
- * Revision 1.4 1995/08/24 18:10:17 warmerda
- * Switch to use SfRealloc() to avoid problems with pre-ANSI realloc()
- * functions (such as on the Sun).
- *
- * Revision 1.3 1995/08/23 02:23:15 warmerda
- * Added support for reading bounds, and fixed up problems in setting the
- * file wide bounds.
- *
- * Revision 1.2 1995/08/04 03:16:57 warmerda
- * Added header.
- *
- */
- #include <grass/shapefil.h>
- #include <math.h>
- #include <limits.h>
- #include <assert.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- SHP_CVSID("$Id$")
- typedef unsigned char uchar;
- #if UINT_MAX == 65535
- typedef long int32;
- #else
- typedef int int32;
- #endif
- #ifndef FALSE
- # define FALSE 0
- # define TRUE 1
- #endif
- #define ByteCopy( a, b, c ) memcpy( b, a, c )
- #ifndef MAX
- # define MIN(a,b) ((a<b) ? a : b)
- # define MAX(a,b) ((a>b) ? a : b)
- #endif
- static int bBigEndian;
- /************************************************************************/
- /* SwapWord() */
- /* */
- /* Swap a 2, 4 or 8 byte word. */
- /************************************************************************/
- static void SwapWord( int length, void * wordP )
- {
- int i;
- uchar temp;
- for( i=0; i < length/2; i++ )
- {
- temp = ((uchar *) wordP)[i];
- ((uchar *)wordP)[i] = ((uchar *) wordP)[length-i-1];
- ((uchar *) wordP)[length-i-1] = temp;
- }
- }
- /************************************************************************/
- /* SfRealloc() */
- /* */
- /* A realloc cover function that will access a NULL pointer as */
- /* a valid input. */
- /************************************************************************/
- static void * SfRealloc( void * pMem, int nNewSize )
- {
- if( pMem == NULL )
- return( (void *) malloc(nNewSize) );
- else
- return( (void *) realloc(pMem,nNewSize) );
- }
- /************************************************************************/
- /* SHPWriteHeader() */
- /* */
- /* Write out a header for the .shp and .shx files as well as the */
- /* contents of the index (.shx) file. */
- /************************************************************************/
- void SHPWriteHeader( SHPHandle psSHP )
- {
- uchar abyHeader[100];
- int i;
- int32 i32;
- double dValue;
- int32 *panSHX;
-
- if (psSHP->fpSHX == NULL)
- {
- psSHP->sHooks.Error( "SHPWriteHeader failed : SHX file is closed");
- return;
- }
- /* -------------------------------------------------------------------- */
- /* Prepare header block for .shp file. */
- /* -------------------------------------------------------------------- */
- for( i = 0; i < 100; i++ )
- abyHeader[i] = 0;
- abyHeader[2] = 0x27; /* magic cookie */
- abyHeader[3] = 0x0a;
- i32 = psSHP->nFileSize/2; /* file size */
- ByteCopy( &i32, abyHeader+24, 4 );
- if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
-
- i32 = 1000; /* version */
- ByteCopy( &i32, abyHeader+28, 4 );
- if( bBigEndian ) SwapWord( 4, abyHeader+28 );
-
- i32 = psSHP->nShapeType; /* shape type */
- ByteCopy( &i32, abyHeader+32, 4 );
- if( bBigEndian ) SwapWord( 4, abyHeader+32 );
- dValue = psSHP->adBoundsMin[0]; /* set bounds */
- ByteCopy( &dValue, abyHeader+36, 8 );
- if( bBigEndian ) SwapWord( 8, abyHeader+36 );
- dValue = psSHP->adBoundsMin[1];
- ByteCopy( &dValue, abyHeader+44, 8 );
- if( bBigEndian ) SwapWord( 8, abyHeader+44 );
- dValue = psSHP->adBoundsMax[0];
- ByteCopy( &dValue, abyHeader+52, 8 );
- if( bBigEndian ) SwapWord( 8, abyHeader+52 );
- dValue = psSHP->adBoundsMax[1];
- ByteCopy( &dValue, abyHeader+60, 8 );
- if( bBigEndian ) SwapWord( 8, abyHeader+60 );
- dValue = psSHP->adBoundsMin[2]; /* z */
- ByteCopy( &dValue, abyHeader+68, 8 );
- if( bBigEndian ) SwapWord( 8, abyHeader+68 );
- dValue = psSHP->adBoundsMax[2];
- ByteCopy( &dValue, abyHeader+76, 8 );
- if( bBigEndian ) SwapWord( 8, abyHeader+76 );
- dValue = psSHP->adBoundsMin[3]; /* m */
- ByteCopy( &dValue, abyHeader+84, 8 );
- if( bBigEndian ) SwapWord( 8, abyHeader+84 );
- dValue = psSHP->adBoundsMax[3];
- ByteCopy( &dValue, abyHeader+92, 8 );
- if( bBigEndian ) SwapWord( 8, abyHeader+92 );
- /* -------------------------------------------------------------------- */
- /* Write .shp file header. */
- /* -------------------------------------------------------------------- */
- if( psSHP->sHooks.FSeek( psSHP->fpSHP, 0, 0 ) != 0
- || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHP ) != 1 )
- {
- psSHP->sHooks.Error( "Failure writing .shp header" );
- return;
- }
- /* -------------------------------------------------------------------- */
- /* Prepare, and write .shx file header. */
- /* -------------------------------------------------------------------- */
- i32 = (psSHP->nRecords * 2 * sizeof(int32) + 100)/2; /* file size */
- ByteCopy( &i32, abyHeader+24, 4 );
- if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
-
- if( psSHP->sHooks.FSeek( psSHP->fpSHX, 0, 0 ) != 0
- || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHX ) != 1 )
- {
- psSHP->sHooks.Error( "Failure writing .shx header" );
- return;
- }
- /* -------------------------------------------------------------------- */
- /* Write out the .shx contents. */
- /* -------------------------------------------------------------------- */
- panSHX = (int32 *) malloc(sizeof(int32) * 2 * psSHP->nRecords);
- for( i = 0; i < psSHP->nRecords; i++ )
- {
- panSHX[i*2 ] = psSHP->panRecOffset[i]/2;
- panSHX[i*2+1] = psSHP->panRecSize[i]/2;
- if( !bBigEndian ) SwapWord( 4, panSHX+i*2 );
- if( !bBigEndian ) SwapWord( 4, panSHX+i*2+1 );
- }
- if( (int)psSHP->sHooks.FWrite( panSHX, sizeof(int32)*2, psSHP->nRecords, psSHP->fpSHX )
- != psSHP->nRecords )
- {
- psSHP->sHooks.Error( "Failure writing .shx contents" );
- }
- free( panSHX );
- /* -------------------------------------------------------------------- */
- /* Flush to disk. */
- /* -------------------------------------------------------------------- */
- psSHP->sHooks.FFlush( psSHP->fpSHP );
- psSHP->sHooks.FFlush( psSHP->fpSHX );
- }
- /************************************************************************/
- /* SHPOpen() */
- /************************************************************************/
- SHPHandle SHPAPI_CALL
- SHPOpen( const char * pszLayer, const char * pszAccess )
- {
- SAHooks sHooks;
- SASetupDefaultHooks( &sHooks );
- return SHPOpenLL( pszLayer, pszAccess, &sHooks );
- }
- /************************************************************************/
- /* SHPOpen() */
- /* */
- /* Open the .shp and .shx files based on the basename of the */
- /* files or either file name. */
- /************************************************************************/
-
- SHPHandle SHPAPI_CALL
- SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
- {
- char *pszFullname, *pszBasename;
- SHPHandle psSHP;
-
- uchar *pabyBuf;
- int i;
- double dValue;
-
- /* -------------------------------------------------------------------- */
- /* Ensure the access string is one of the legal ones. We */
- /* ensure the result string indicates binary to avoid common */
- /* problems on Windows. */
- /* -------------------------------------------------------------------- */
- if( strcmp(pszAccess,"rb+") == 0 || strcmp(pszAccess,"r+b") == 0
- || strcmp(pszAccess,"r+") == 0 )
- pszAccess = "r+b";
- else
- pszAccess = "rb";
-
- /* -------------------------------------------------------------------- */
- /* Establish the byte order on this machine. */
- /* -------------------------------------------------------------------- */
- i = 1;
- if( *((uchar *) &i) == 1 )
- bBigEndian = FALSE;
- else
- bBigEndian = TRUE;
- /* -------------------------------------------------------------------- */
- /* Initialize the info structure. */
- /* -------------------------------------------------------------------- */
- psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1);
- psSHP->bUpdated = FALSE;
- memcpy( &(psSHP->sHooks), psHooks, sizeof(SAHooks) );
- /* -------------------------------------------------------------------- */
- /* Compute the base (layer) name. If there is any extension */
- /* on the passed in filename we will strip it off. */
- /* -------------------------------------------------------------------- */
- pszBasename = (char *) malloc(strlen(pszLayer)+5);
- strcpy( pszBasename, pszLayer );
- for( i = strlen(pszBasename)-1;
- i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
- && pszBasename[i] != '\\';
- i-- ) {}
- if( pszBasename[i] == '.' )
- pszBasename[i] = '\0';
- /* -------------------------------------------------------------------- */
- /* Open the .shp and .shx files. Note that files pulled from */
- /* a PC to Unix with upper case filenames won't work! */
- /* -------------------------------------------------------------------- */
- pszFullname = (char *) malloc(strlen(pszBasename) + 5);
- sprintf( pszFullname, "%s.shp", pszBasename ) ;
- psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
- if( psSHP->fpSHP == NULL )
- {
- sprintf( pszFullname, "%s.SHP", pszBasename );
- psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
- }
-
- if( psSHP->fpSHP == NULL )
- {
- #ifdef USE_CPL
- CPLError( CE_Failure, CPLE_OpenFailed,
- "Unable to open %s.shp or %s.SHP.",
- pszBasename, pszBasename );
- #endif
- free( psSHP );
- free( pszBasename );
- free( pszFullname );
- return( NULL );
- }
- sprintf( pszFullname, "%s.shx", pszBasename );
- psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess );
- if( psSHP->fpSHX == NULL )
- {
- sprintf( pszFullname, "%s.SHX", pszBasename );
- psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess );
- }
-
- if( psSHP->fpSHX == NULL )
- {
- #ifdef USE_CPL
- CPLError( CE_Failure, CPLE_OpenFailed,
- "Unable to open %s.shx or %s.SHX.",
- pszBasename, pszBasename );
- #endif
- psSHP->sHooks.FClose( psSHP->fpSHP );
- free( psSHP );
- free( pszBasename );
- free( pszFullname );
- return( NULL );
- }
- free( pszFullname );
- free( pszBasename );
- /* -------------------------------------------------------------------- */
- /* Read the file size from the SHP file. */
- /* -------------------------------------------------------------------- */
- pabyBuf = (uchar *) malloc(100);
- psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHP );
- psSHP->nFileSize = (pabyBuf[24] * 256 * 256 * 256
- + pabyBuf[25] * 256 * 256
- + pabyBuf[26] * 256
- + pabyBuf[27]) * 2;
- /* -------------------------------------------------------------------- */
- /* Read SHX file Header info */
- /* -------------------------------------------------------------------- */
- if( psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHX ) != 1
- || pabyBuf[0] != 0
- || pabyBuf[1] != 0
- || pabyBuf[2] != 0x27
- || (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d) )
- {
- psSHP->sHooks.Error( ".shx file is unreadable, or corrupt." );
- psSHP->sHooks.FClose( psSHP->fpSHP );
- psSHP->sHooks.FClose( psSHP->fpSHX );
- free( psSHP );
- return( NULL );
- }
- psSHP->nRecords = pabyBuf[27] + pabyBuf[26] * 256
- + pabyBuf[25] * 256 * 256 + pabyBuf[24] * 256 * 256 * 256;
- psSHP->nRecords = (psSHP->nRecords*2 - 100) / 8;
- psSHP->nShapeType = pabyBuf[32];
- if( psSHP->nRecords < 0 || psSHP->nRecords > 256000000 )
- {
- char szError[200];
-
- sprintf( szError,
- "Record count in .shp header is %d, which seems\n"
- "unreasonable. Assuming header is corrupt.",
- psSHP->nRecords );
- psSHP->sHooks.Error( szError );
- psSHP->sHooks.FClose( psSHP->fpSHP );
- psSHP->sHooks.FClose( psSHP->fpSHX );
- free( psSHP );
- free(pabyBuf);
- return( NULL );
- }
- /* -------------------------------------------------------------------- */
- /* Read the bounds. */
- /* -------------------------------------------------------------------- */
- if( bBigEndian ) SwapWord( 8, pabyBuf+36 );
- memcpy( &dValue, pabyBuf+36, 8 );
- psSHP->adBoundsMin[0] = dValue;
- if( bBigEndian ) SwapWord( 8, pabyBuf+44 );
- memcpy( &dValue, pabyBuf+44, 8 );
- psSHP->adBoundsMin[1] = dValue;
- if( bBigEndian ) SwapWord( 8, pabyBuf+52 );
- memcpy( &dValue, pabyBuf+52, 8 );
- psSHP->adBoundsMax[0] = dValue;
- if( bBigEndian ) SwapWord( 8, pabyBuf+60 );
- memcpy( &dValue, pabyBuf+60, 8 );
- psSHP->adBoundsMax[1] = dValue;
- if( bBigEndian ) SwapWord( 8, pabyBuf+68 ); /* z */
- memcpy( &dValue, pabyBuf+68, 8 );
- psSHP->adBoundsMin[2] = dValue;
-
- if( bBigEndian ) SwapWord( 8, pabyBuf+76 );
- memcpy( &dValue, pabyBuf+76, 8 );
- psSHP->adBoundsMax[2] = dValue;
-
- if( bBigEndian ) SwapWord( 8, pabyBuf+84 ); /* z */
- memcpy( &dValue, pabyBuf+84, 8 );
- psSHP->adBoundsMin[3] = dValue;
- if( bBigEndian ) SwapWord( 8, pabyBuf+92 );
- memcpy( &dValue, pabyBuf+92, 8 );
- psSHP->adBoundsMax[3] = dValue;
- free( pabyBuf );
- /* -------------------------------------------------------------------- */
- /* Read the .shx file to get the offsets to each record in */
- /* the .shp file. */
- /* -------------------------------------------------------------------- */
- psSHP->nMaxRecords = psSHP->nRecords;
- psSHP->panRecOffset =
- (int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) );
- psSHP->panRecSize =
- (int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) );
- pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) );
- if (psSHP->panRecOffset == NULL ||
- psSHP->panRecSize == NULL ||
- pabyBuf == NULL)
- {
- char szError[200];
- sprintf(szError,
- "Not enough memory to allocate requested memory (nRecords=%d).\n"
- "Probably broken SHP file",
- psSHP->nRecords );
- psSHP->sHooks.Error( szError );
- psSHP->sHooks.FClose( psSHP->fpSHP );
- psSHP->sHooks.FClose( psSHP->fpSHX );
- if (psSHP->panRecOffset) free( psSHP->panRecOffset );
- if (psSHP->panRecSize) free( psSHP->panRecSize );
- if (pabyBuf) free( pabyBuf );
- free( psSHP );
- return( NULL );
- }
- if( (int) psSHP->sHooks.FRead( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX )
- != psSHP->nRecords )
- {
- char szError[200];
- sprintf( szError,
- "Failed to read all values for %d records in .shx file.",
- psSHP->nRecords );
- psSHP->sHooks.Error( szError );
- /* SHX is short or unreadable for some reason. */
- psSHP->sHooks.FClose( psSHP->fpSHP );
- psSHP->sHooks.FClose( psSHP->fpSHX );
- free( psSHP->panRecOffset );
- free( psSHP->panRecSize );
- free( pabyBuf );
- free( psSHP );
- return( NULL );
- }
-
- /* In read-only mode, we can close the SHX now */
- if (strcmp(pszAccess, "rb") == 0)
- {
- psSHP->sHooks.FClose( psSHP->fpSHX );
- psSHP->fpSHX = NULL;
- }
- for( i = 0; i < psSHP->nRecords; i++ )
- {
- int32 nOffset, nLength;
- memcpy( &nOffset, pabyBuf + i * 8, 4 );
- if( !bBigEndian ) SwapWord( 4, &nOffset );
- memcpy( &nLength, pabyBuf + i * 8 + 4, 4 );
- if( !bBigEndian ) SwapWord( 4, &nLength );
- psSHP->panRecOffset[i] = nOffset*2;
- psSHP->panRecSize[i] = nLength*2;
- }
- free( pabyBuf );
- return( psSHP );
- }
- /************************************************************************/
- /* SHPClose() */
- /* */
- /* Close the .shp and .shx files. */
- /************************************************************************/
- void SHPAPI_CALL
- SHPClose(SHPHandle psSHP )
- {
- if( psSHP == NULL )
- return;
- /* -------------------------------------------------------------------- */
- /* Update the header if we have modified anything. */
- /* -------------------------------------------------------------------- */
- if( psSHP->bUpdated )
- SHPWriteHeader( psSHP );
- /* -------------------------------------------------------------------- */
- /* Free all resources, and close files. */
- /* -------------------------------------------------------------------- */
- free( psSHP->panRecOffset );
- free( psSHP->panRecSize );
- if ( psSHP->fpSHX != NULL)
- psSHP->sHooks.FClose( psSHP->fpSHX );
- psSHP->sHooks.FClose( psSHP->fpSHP );
- if( psSHP->pabyRec != NULL )
- {
- free( psSHP->pabyRec );
- }
-
- free( psSHP );
- }
- /************************************************************************/
- /* SHPGetInfo() */
- /* */
- /* Fetch general information about the shape file. */
- /************************************************************************/
- void SHPAPI_CALL
- SHPGetInfo(SHPHandle psSHP, int * pnEntities, int * pnShapeType,
- double * padfMinBound, double * padfMaxBound )
- {
- int i;
- if( psSHP == NULL )
- return;
-
- if( pnEntities != NULL )
- *pnEntities = psSHP->nRecords;
- if( pnShapeType != NULL )
- *pnShapeType = psSHP->nShapeType;
- for( i = 0; i < 4; i++ )
- {
- if( padfMinBound != NULL )
- padfMinBound[i] = psSHP->adBoundsMin[i];
- if( padfMaxBound != NULL )
- padfMaxBound[i] = psSHP->adBoundsMax[i];
- }
- }
- /************************************************************************/
- /* SHPCreate() */
- /* */
- /* Create a new shape file and return a handle to the open */
- /* shape file with read/write access. */
- /************************************************************************/
- SHPHandle SHPAPI_CALL
- SHPCreate( const char * pszLayer, int nShapeType )
- {
- SAHooks sHooks;
- SASetupDefaultHooks( &sHooks );
- return SHPCreateLL( pszLayer, nShapeType, &sHooks );
- }
- /************************************************************************/
- /* SHPCreate() */
- /* */
- /* Create a new shape file and return a handle to the open */
- /* shape file with read/write access. */
- /************************************************************************/
- SHPHandle SHPAPI_CALL
- SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
- {
- char *pszBasename, *pszFullname;
- int i;
- SAFile fpSHP, fpSHX;
- uchar abyHeader[100];
- int32 i32;
- double dValue;
-
- /* -------------------------------------------------------------------- */
- /* Establish the byte order on this system. */
- /* -------------------------------------------------------------------- */
- i = 1;
- if( *((uchar *) &i) == 1 )
- bBigEndian = FALSE;
- else
- bBigEndian = TRUE;
- /* -------------------------------------------------------------------- */
- /* Compute the base (layer) name. If there is any extension */
- /* on the passed in filename we will strip it off. */
- /* -------------------------------------------------------------------- */
- pszBasename = (char *) malloc(strlen(pszLayer)+5);
- strcpy( pszBasename, pszLayer );
- for( i = strlen(pszBasename)-1;
- i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
- && pszBasename[i] != '\\';
- i-- ) {}
- if( pszBasename[i] == '.' )
- pszBasename[i] = '\0';
- /* -------------------------------------------------------------------- */
- /* Open the two files so we can write their headers. */
- /* -------------------------------------------------------------------- */
- pszFullname = (char *) malloc(strlen(pszBasename) + 5);
- sprintf( pszFullname, "%s.shp", pszBasename );
- fpSHP = psHooks->FOpen(pszFullname, "wb" );
- if( fpSHP == NULL )
- {
- psHooks->Error( "Failed to create file .shp file." );
- free( pszFullname );
- free( pszBasename );
- return( NULL );
- }
- sprintf( pszFullname, "%s.shx", pszBasename );
- fpSHX = psHooks->FOpen(pszFullname, "wb" );
- if( fpSHX == NULL )
- {
- psHooks->Error( "Failed to create file .shx file." );
- free( pszFullname );
- free( pszBasename );
- return( NULL );
- }
- free( pszFullname );
- free( pszBasename );
- /* -------------------------------------------------------------------- */
- /* Prepare header block for .shp file. */
- /* -------------------------------------------------------------------- */
- for( i = 0; i < 100; i++ )
- abyHeader[i] = 0;
- abyHeader[2] = 0x27; /* magic cookie */
- abyHeader[3] = 0x0a;
- i32 = 50; /* file size */
- ByteCopy( &i32, abyHeader+24, 4 );
- if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
-
- i32 = 1000; /* version */
- ByteCopy( &i32, abyHeader+28, 4 );
- if( bBigEndian ) SwapWord( 4, abyHeader+28 );
-
- i32 = nShapeType; /* shape type */
- ByteCopy( &i32, abyHeader+32, 4 );
- if( bBigEndian ) SwapWord( 4, abyHeader+32 );
- dValue = 0.0; /* set bounds */
- ByteCopy( &dValue, abyHeader+36, 8 );
- ByteCopy( &dValue, abyHeader+44, 8 );
- ByteCopy( &dValue, abyHeader+52, 8 );
- ByteCopy( &dValue, abyHeader+60, 8 );
- /* -------------------------------------------------------------------- */
- /* Write .shp file header. */
- /* -------------------------------------------------------------------- */
- if( psHooks->FWrite( abyHeader, 100, 1, fpSHP ) != 1 )
- {
- psHooks->Error( "Failed to write .shp header." );
- return NULL;
- }
- /* -------------------------------------------------------------------- */
- /* Prepare, and write .shx file header. */
- /* -------------------------------------------------------------------- */
- i32 = 50; /* file size */
- ByteCopy( &i32, abyHeader+24, 4 );
- if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
-
- if( psHooks->FWrite( abyHeader, 100, 1, fpSHX ) != 1 )
- {
- psHooks->Error( "Failed to write .shx header." );
- return NULL;
- }
- /* -------------------------------------------------------------------- */
- /* Close the files, and then open them as regular existing files. */
- /* -------------------------------------------------------------------- */
- psHooks->FClose( fpSHP );
- psHooks->FClose( fpSHX );
- return( SHPOpenLL( pszLayer, "r+b", psHooks ) );
- }
- /************************************************************************/
- /* _SHPSetBounds() */
- /* */
- /* Compute a bounds rectangle for a shape, and set it into the */
- /* indicated location in the record. */
- /************************************************************************/
- static void _SHPSetBounds( uchar * pabyRec, SHPObject * psShape )
- {
- ByteCopy( &(psShape->dfXMin), pabyRec + 0, 8 );
- ByteCopy( &(psShape->dfYMin), pabyRec + 8, 8 );
- ByteCopy( &(psShape->dfXMax), pabyRec + 16, 8 );
- ByteCopy( &(psShape->dfYMax), pabyRec + 24, 8 );
- if( bBigEndian )
- {
- SwapWord( 8, pabyRec + 0 );
- SwapWord( 8, pabyRec + 8 );
- SwapWord( 8, pabyRec + 16 );
- SwapWord( 8, pabyRec + 24 );
- }
- }
- /************************************************************************/
- /* SHPComputeExtents() */
- /* */
- /* Recompute the extents of a shape. Automatically done by */
- /* SHPCreateObject(). */
- /************************************************************************/
- void SHPAPI_CALL
- SHPComputeExtents( SHPObject * psObject )
- {
- int i;
-
- /* -------------------------------------------------------------------- */
- /* Build extents for this object. */
- /* -------------------------------------------------------------------- */
- if( psObject->nVertices > 0 )
- {
- psObject->dfXMin = psObject->dfXMax = psObject->padfX[0];
- psObject->dfYMin = psObject->dfYMax = psObject->padfY[0];
- psObject->dfZMin = psObject->dfZMax = psObject->padfZ[0];
- psObject->dfMMin = psObject->dfMMax = psObject->padfM[0];
- }
-
- for( i = 0; i < psObject->nVertices; i++ )
- {
- psObject->dfXMin = MIN(psObject->dfXMin, psObject->padfX[i]);
- psObject->dfYMin = MIN(psObject->dfYMin, psObject->padfY[i]);
- psObject->dfZMin = MIN(psObject->dfZMin, psObject->padfZ[i]);
- psObject->dfMMin = MIN(psObject->dfMMin, psObject->padfM[i]);
- psObject->dfXMax = MAX(psObject->dfXMax, psObject->padfX[i]);
- psObject->dfYMax = MAX(psObject->dfYMax, psObject->padfY[i]);
- psObject->dfZMax = MAX(psObject->dfZMax, psObject->padfZ[i]);
- psObject->dfMMax = MAX(psObject->dfMMax, psObject->padfM[i]);
- }
- }
- /************************************************************************/
- /* SHPCreateObject() */
- /* */
- /* Create a shape object. It should be freed with */
- /* SHPDestroyObject(). */
- /************************************************************************/
- SHPObject SHPAPI_CALL1(*)
- SHPCreateObject( int nSHPType, int nShapeId, int nParts,
- const int * panPartStart, const int * panPartType,
- int nVertices, const double *padfX, const double *padfY,
- const double * padfZ, const double * padfM )
- {
- SHPObject *psObject;
- int i, bHasM, bHasZ;
- psObject = (SHPObject *) calloc(1,sizeof(SHPObject));
- psObject->nSHPType = nSHPType;
- psObject->nShapeId = nShapeId;
- psObject->bMeasureIsUsed = FALSE;
- /* -------------------------------------------------------------------- */
- /* Establish whether this shape type has M, and Z values. */
- /* -------------------------------------------------------------------- */
- if( nSHPType == SHPT_ARCM
- || nSHPType == SHPT_POINTM
- || nSHPType == SHPT_POLYGONM
- || nSHPType == SHPT_MULTIPOINTM )
- {
- bHasM = TRUE;
- bHasZ = FALSE;
- }
- else if( nSHPType == SHPT_ARCZ
- || nSHPType == SHPT_POINTZ
- || nSHPType == SHPT_POLYGONZ
- || nSHPType == SHPT_MULTIPOINTZ
- || nSHPType == SHPT_MULTIPATCH )
- {
- bHasM = TRUE;
- bHasZ = TRUE;
- }
- else
- {
- bHasM = FALSE;
- bHasZ = FALSE;
- }
- /* -------------------------------------------------------------------- */
- /* Capture parts. Note that part type is optional, and */
- /* defaults to ring. */
- /* -------------------------------------------------------------------- */
- if( nSHPType == SHPT_ARC || nSHPType == SHPT_POLYGON
- || nSHPType == SHPT_ARCM || nSHPType == SHPT_POLYGONM
- || nSHPType == SHPT_ARCZ || nSHPType == SHPT_POLYGONZ
- || nSHPType == SHPT_MULTIPATCH )
- {
- psObject->nParts = MAX(1,nParts);
- psObject->panPartStart = (int *)
- malloc(sizeof(int) * psObject->nParts);
- psObject->panPartType = (int *)
- malloc(sizeof(int) * psObject->nParts);
- psObject->panPartStart[0] = 0;
- psObject->panPartType[0] = SHPP_RING;
-
- for( i = 0; i < nParts; i++ )
- {
- psObject->panPartStart[i] = panPartStart[i];
- if( panPartType != NULL )
- psObject->panPartType[i] = panPartType[i];
- else
- psObject->panPartType[i] = SHPP_RING;
- }
- if( psObject->panPartStart[0] != 0 )
- psObject->panPartStart[0] = 0;
- }
- /* -------------------------------------------------------------------- */
- /* Capture vertices. Note that Z and M are optional, but X and */
- /* Y are not. */
- /* -------------------------------------------------------------------- */
- if( nVertices > 0 )
- {
- psObject->padfX = (double *) calloc(sizeof(double),nVertices);
- psObject->padfY = (double *) calloc(sizeof(double),nVertices);
- psObject->padfZ = (double *) calloc(sizeof(double),nVertices);
- psObject->padfM = (double *) calloc(sizeof(double),nVertices);
- assert( padfX != NULL );
- assert( padfY != NULL );
-
- for( i = 0; i < nVertices; i++ )
- {
- psObject->padfX[i] = padfX[i];
- psObject->padfY[i] = padfY[i];
- if( padfZ != NULL && bHasZ )
- psObject->padfZ[i] = padfZ[i];
- if( padfM != NULL && bHasM )
- psObject->padfM[i] = padfM[i];
- }
- if( padfM != NULL && bHasM )
- psObject->bMeasureIsUsed = TRUE;
- }
- /* -------------------------------------------------------------------- */
- /* Compute the extents. */
- /* -------------------------------------------------------------------- */
- psObject->nVertices = nVertices;
- SHPComputeExtents( psObject );
- return( psObject );
- }
- /************************************************************************/
- /* SHPCreateSimpleObject() */
- /* */
- /* Create a simple (common) shape object. Destroy with */
- /* SHPDestroyObject(). */
- /************************************************************************/
- SHPObject SHPAPI_CALL1(*)
- SHPCreateSimpleObject( int nSHPType, int nVertices,
- const double * padfX, const double * padfY,
- const double * padfZ )
- {
- return( SHPCreateObject( nSHPType, -1, 0, NULL, NULL,
- nVertices, padfX, padfY, padfZ, NULL ) );
- }
-
- /************************************************************************/
- /* SHPWriteObject() */
- /* */
- /* Write out the vertices of a new structure. Note that it is */
- /* only possible to write vertices at the end of the file. */
- /************************************************************************/
- int SHPAPI_CALL
- SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
-
- {
- int nRecordOffset, i, nRecordSize=0;
- uchar *pabyRec;
- int32 i32;
- psSHP->bUpdated = TRUE;
- /* -------------------------------------------------------------------- */
- /* Ensure that shape object matches the type of the file it is */
- /* being written to. */
- /* -------------------------------------------------------------------- */
- assert( psObject->nSHPType == psSHP->nShapeType
- || psObject->nSHPType == SHPT_NULL );
- /* -------------------------------------------------------------------- */
- /* Ensure that -1 is used for appends. Either blow an */
- /* assertion, or if they are disabled, set the shapeid to -1 */
- /* for appends. */
- /* -------------------------------------------------------------------- */
- assert( nShapeId == -1
- || (nShapeId >= 0 && nShapeId < psSHP->nRecords) );
- if( nShapeId != -1 && nShapeId >= psSHP->nRecords )
- nShapeId = -1;
- /* -------------------------------------------------------------------- */
- /* Add the new entity to the in memory index. */
- /* -------------------------------------------------------------------- */
- if( nShapeId == -1 && psSHP->nRecords+1 > psSHP->nMaxRecords )
- {
- psSHP->nMaxRecords =(int) ( psSHP->nMaxRecords * 1.3 + 100);
- psSHP->panRecOffset = (int *)
- SfRealloc(psSHP->panRecOffset,sizeof(int) * psSHP->nMaxRecords );
- psSHP->panRecSize = (int *)
- SfRealloc(psSHP->panRecSize,sizeof(int) * psSHP->nMaxRecords );
- }
- /* -------------------------------------------------------------------- */
- /* Initialize record. */
- /* -------------------------------------------------------------------- */
- pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double)
- + psObject->nParts * 8 + 128);
-
- /* -------------------------------------------------------------------- */
- /* Extract vertices for a Polygon or Arc. */
- /* -------------------------------------------------------------------- */
- if( psObject->nSHPType == SHPT_POLYGON
- || psObject->nSHPType == SHPT_POLYGONZ
- || psObject->nSHPType == SHPT_POLYGONM
- || psObject->nSHPType == SHPT_ARC
- || psObject->nSHPType == SHPT_ARCZ
- || psObject->nSHPType == SHPT_ARCM
- || psObject->nSHPType == SHPT_MULTIPATCH )
- {
- int32 nPoints, nParts;
- int i;
- nPoints = psObject->nVertices;
- nParts = psObject->nParts;
- _SHPSetBounds( pabyRec + 12, psObject );
- if( bBigEndian ) SwapWord( 4, &nPoints );
- if( bBigEndian ) SwapWord( 4, &nParts );
- ByteCopy( &nPoints, pabyRec + 40 + 8, 4 );
- ByteCopy( &nParts, pabyRec + 36 + 8, 4 );
- nRecordSize = 52;
- /*
- * Write part start positions.
- */
- ByteCopy( psObject->panPartStart, pabyRec + 44 + 8,
- 4 * psObject->nParts );
- for( i = 0; i < psObject->nParts; i++ )
- {
- if( bBigEndian ) SwapWord( 4, pabyRec + 44 + 8 + 4*i );
- nRecordSize += 4;
- }
- /*
- * Write multipatch part types if needed.
- */
- if( psObject->nSHPType == SHPT_MULTIPATCH )
- {
- memcpy( pabyRec + nRecordSize, psObject->panPartType,
- 4*psObject->nParts );
- for( i = 0; i < psObject->nParts; i++ )
- {
- if( bBigEndian ) SwapWord( 4, pabyRec + nRecordSize );
- nRecordSize += 4;
- }
- }
- /*
- * Write the (x,y) vertex values.
- */
- for( i = 0; i < psObject->nVertices; i++ )
- {
- ByteCopy( psObject->padfX + i, pabyRec + nRecordSize, 8 );
- ByteCopy( psObject->padfY + i, pabyRec + nRecordSize + 8, 8 );
- if( bBigEndian )
- SwapWord( 8, pabyRec + nRecordSize );
-
- if( bBigEndian )
- SwapWord( 8, pabyRec + nRecordSize + 8 );
- nRecordSize += 2 * 8;
- }
- /*
- * Write the Z coordinates (if any).
- */
- if( psObject->nSHPType == SHPT_POLYGONZ
- || psObject->nSHPType == SHPT_ARCZ
- || psObject->nSHPType == SHPT_MULTIPATCH )
- {
- ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
- if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
- nRecordSize += 8;
-
- ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
- if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
- nRecordSize += 8;
- for( i = 0; i < psObject->nVertices; i++ )
- {
- ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
- if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
- nRecordSize += 8;
- }
- }
- /*
- * Write the M values, if any.
- */
- if( psObject->bMeasureIsUsed
- && (psObject->nSHPType == SHPT_POLYGONM
- || psObject->nSHPType == SHPT_ARCM
- #ifndef DISABLE_MULTIPATCH_MEASURE
- || psObject->nSHPType == SHPT_MULTIPATCH
- #endif
- || psObject->nSHPType == SHPT_POLYGONZ
- || psObject->nSHPType == SHPT_ARCZ) )
- {
- ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
- if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
- nRecordSize += 8;
-
- ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
- if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
- nRecordSize += 8;
- for( i = 0; i < psObject->nVertices; i++ )
- {
- ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
- if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
- nRecordSize += 8;
- }
- }
- }
- /* -------------------------------------------------------------------- */
- /* Extract vertices for a MultiPoint. */
- /* -------------------------------------------------------------------- */
- else if( psObject->nSHPType == SHPT_MULTIPOINT
- || psObject->nSHPType == SHPT_MULTIPOINTZ
- || psObject->nSHPType == SHPT_MULTIPOINTM )
- {
- int32 nPoints;
- int i;
- nPoints = psObject->nVertices;
- _SHPSetBounds( pabyRec + 12, psObject );
- if( bBigEndian ) SwapWord( 4, &nPoints );
- ByteCopy( &nPoints, pabyRec + 44, 4 );
-
- for( i = 0; i < psObject->nVertices; i++ )
- {
- ByteCopy( psObject->padfX + i, pabyRec + 48 + i*16, 8 );
- ByteCopy( psObject->padfY + i, pabyRec + 48 + i*16 + 8, 8 );
- if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 );
- if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 + 8 );
- }
- nRecordSize = 48 + 16 * psObject->nVertices;
- if( psObject->nSHPType == SHPT_MULTIPOINTZ )
- {
- ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
- if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
- nRecordSize += 8;
- ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
- if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
- nRecordSize += 8;
-
- for( i = 0; i < psObject->nVertices; i++ )
- {
- ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
- if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
- nRecordSize += 8;
- }
- }
- if( psObject->bMeasureIsUsed
- && (psObject->nSHPType == SHPT_MULTIPOINTZ
- || psObject->nSHPType == SHPT_MULTIPOINTM) )
- {
- ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
- if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
- nRecordSize += 8;
- ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
- if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
- nRecordSize += 8;
-
- for( i = 0; i < psObject->nVertices; i++ )
- {
- ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
- if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
- nRecordSize += 8;
- }
- }
- }
- /* -------------------------------------------------------------------- */
- /* Write point. */
- /* -------------------------------------------------------------------- */
- else if( psObject->nSHPType == SHPT_POINT
- || psObject->nSHPType == SHPT_POINTZ
- || psObject->nSHPType == SHPT_POINTM )
- {
- ByteCopy( psObject->padfX, pabyRec + 12, 8 );
- ByteCopy( psObject->padfY, pabyRec + 20, 8 );
- if( bBigEndian ) SwapWord( 8, pabyRec + 12 );
- if( bBigEndian ) SwapWord( 8, pabyRec + 20 );
- nRecordSize = 28;
-
- if( psObject->nSHPType == SHPT_POINTZ )
- {
- ByteCopy( psObject->padfZ, pabyRec + nRecordSize, 8 );
- if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
- nRecordSize += 8;
- }
-
- if( psObject->bMeasureIsUsed
- && (psObject->nSHPType == SHPT_POINTZ
- || psObject->nSHPType == SHPT_POINTM) )
- {
- ByteCopy( psObject->padfM, pabyRec + nRecordSize, 8 );
- if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
- nRecordSize += 8;
- }
- }
- /* -------------------------------------------------------------------- */
- /* Not much to do for null geometries. */
- /* -------------------------------------------------------------------- */
- else if( psObject->nSHPType == SHPT_NULL )
- {
- nRecordSize = 12;
- }
- else
- {
- /* unknown type */
- assert( FALSE );
- }
- /* -------------------------------------------------------------------- */
- /* Establish where we are going to put this record. If we are */
- /* rewriting and existing record, and it will fit, then put it */
- /* back where the original came from. Otherwise write at the end. */
- /* -------------------------------------------------------------------- */
- if( nShapeId == -1 || psSHP->panRecSize[nShapeId] < nRecordSize-8 )
- {
- if( nShapeId == -1 )
- nShapeId = psSHP->nRecords++;
- psSHP->panRecOffset[nShapeId] = nRecordOffset = psSHP->nFileSize;
- psSHP->panRecSize[nShapeId] = nRecordSize-8;
- psSHP->nFileSize += nRecordSize;
- }
- else
- {
- nRecordOffset = psSHP->panRecOffset[nShapeId];
- psSHP->panRecSize[nShapeId] = nRecordSize-8;
- }
-
- /* -------------------------------------------------------------------- */
- /* Set the shape type, record number, and record size. */
- /* -------------------------------------------------------------------- */
- i32 = nShapeId+1; /* record # */
- if( !bBigEndian ) SwapWord( 4, &i32 );
- ByteCopy( &i32, pabyRec, 4 );
- i32 = (nRecordSize-8)/2; /* record size */
- if( !bBigEndian ) SwapWord( 4, &i32 );
- ByteCopy( &i32, pabyRec + 4, 4 );
- i32 = psObject->nSHPType; /* shape type */
- if( bBigEndian ) SwapWord( 4, &i32 );
- ByteCopy( &i32, pabyRec + 8, 4 );
- /* -------------------------------------------------------------------- */
- /* Write out record. */
- /* -------------------------------------------------------------------- */
- if( psSHP->sHooks.FSeek( psSHP->fpSHP, nRecordOffset, 0 ) != 0
- || psSHP->sHooks.FWrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 )
- {
- psSHP->sHooks.Error( "Error in psSHP->sHooks.FSeek() or fwrite() writing object to .shp file." );
- free( pabyRec );
- return -1;
- }
-
- free( pabyRec );
- /* -------------------------------------------------------------------- */
- /* Expand file wide bounds based on this shape. */
- /* -------------------------------------------------------------------- */
- if( psSHP->adBoundsMin[0] == 0.0
- && psSHP->adBoundsMax[0] == 0.0
- && psSHP->adBoundsMin[1] == 0.0
- && psSHP->adBoundsMax[1] == 0.0 )
- {
- if( psObject->nSHPType == SHPT_NULL || psObject->nVertices == 0 )
- {
- psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = 0.0;
- psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = 0.0;
- psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = 0.0;
- psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = 0.0;
- }
- else
- {
- psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = psObject->padfX[0];
- psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = psObject->padfY[0];
- psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ[0];
- psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM[0];
- }
- }
- for( i = 0; i < psObject->nVertices; i++ )
- {
- psSHP->adBoundsMin[0] = MIN(psSHP->adBoundsMin[0],psObject->padfX[i]);
- psSHP->adBoundsMin[1] = MIN(psSHP->adBoundsMin[1],psObject->padfY[i]);
- psSHP->adBoundsMin[2] = MIN(psSHP->adBoundsMin[2],psObject->padfZ[i]);
- psSHP->adBoundsMin[3] = MIN(psSHP->adBoundsMin[3],psObject->padfM[i]);
- psSHP->adBoundsMax[0] = MAX(psSHP->adBoundsMax[0],psObject->padfX[i]);
- psSHP->adBoundsMax[1] = MAX(psSHP->adBoundsMax[1],psObject->padfY[i]);
- psSHP->adBoundsMax[2] = MAX(psSHP->adBoundsMax[2],psObject->padfZ[i]);
- psSHP->adBoundsMax[3] = MAX(psSHP->adBoundsMax[3],psObject->padfM[i]);
- }
- return( nShapeId );
- }
- /************************************************************************/
- /* SHPReadObject() */
- /* */
- /* Read the vertices, parts, and other non-attribute information */
- /* for one shape. */
- /************************************************************************/
- SHPObject SHPAPI_CALL1(*)
- SHPReadObject( SHPHandle psSHP, int hEntity )
- {
- int nEntitySize, nRequiredSize;
- SHPObject *psShape;
- char pszErrorMsg[128];
- /* -------------------------------------------------------------------- */
- /* Validate the record/entity number. */
- /* -------------------------------------------------------------------- */
- if( hEntity < 0 || hEntity >= psSHP->nRecords )
- return( NULL );
- /* -------------------------------------------------------------------- */
- /* Ensure our record buffer is large enough. */
- /* -------------------------------------------------------------------- */
- nEntitySize = psSHP->panRecSize[hEntity]+8;
- if( nEntitySize > psSHP->nBufSize )
- {
- psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,nEntitySize);
- if (psSHP->pabyRec == NULL)
- {
- char szError[200];
- /* Reallocate previous successfull size for following features */
- psSHP->pabyRec = malloc(psSHP->nBufSize);
- sprintf( szError,
- "Not enough memory to allocate requested memory (nBufSize=%d). "
- "Probably broken SHP file", psSHP->nBufSize );
- psSHP->sHooks.Error( szError );
- return NULL;
- }
- /* Only set new buffer size after successfull alloc */
- psSHP->nBufSize = nEntitySize;
- }
- /* In case we were not able to reallocate the buffer on a previous step */
- if (psSHP->pabyRec == NULL)
- {
- return NULL;
- }
- /* -------------------------------------------------------------------- */
- /* Read the record. */
- /* -------------------------------------------------------------------- */
- if( psSHP->sHooks.FSeek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 ) != 0
- || psSHP->sHooks.FRead( psSHP->pabyRec, nEntitySize, 1,
- psSHP->fpSHP ) != 1 )
- {
- /*
- * TODO - mloskot: Consider detailed diagnostics of shape file,
- * for example to detect if file is truncated.
- */
- psSHP->sHooks.Error( "Error in fseek() or fread() reading object from .shp file." );
- return NULL;
- }
- /* -------------------------------------------------------------------- */
- /* Allocate and minimally initialize the object. */
- /* -------------------------------------------------------------------- */
- psShape = (SHPObject *) calloc(1,sizeof(SHPObject));
- psShape->nShapeId = hEntity;
- psShape->bMeasureIsUsed = FALSE;
- if ( 8 + 4 > nEntitySize )
- {
- snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d",
- hEntity, nEntitySize);
- psSHP->sHooks.Error( pszErrorMsg );
- SHPDestroyObject(psShape);
- return NULL;
- }
- memcpy( &psShape->nSHPType, psSHP->pabyRec + 8, 4 );
- if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) );
- /* ==================================================================== */
- /* Extract vertices for a Polygon or Arc. */
- /* ==================================================================== */
- if( psShape->nSHPType == SHPT_POLYGON || psShape->nSHPType == SHPT_ARC
- || psShape->nSHPType == SHPT_POLYGONZ
- || psShape->nSHPType == SHPT_POLYGONM
- || psShape->nSHPType == SHPT_ARCZ
- || psShape->nSHPType == SHPT_ARCM
- || psShape->nSHPType == SHPT_MULTIPATCH )
- {
- int32 nPoints, nParts;
- int i, nOffset;
- if ( 40 + 8 + 4 > nEntitySize )
- {
- snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d",
- hEntity, nEntitySize);
- psSHP->sHooks.Error( pszErrorMsg );
- SHPDestroyObject(psShape);
- return NULL;
- }
- /* -------------------------------------------------------------------- */
- /* Get the X/Y bounds. */
- /* -------------------------------------------------------------------- */
- memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 );
- memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );
- memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
- memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
- if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
- if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
- if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
- if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
- /* -------------------------------------------------------------------- */
- /* Extract part/point count, and build vertex and part arrays */
- /* to proper size. */
- /* -------------------------------------------------------------------- */
- memcpy( &nPoints, psSHP->pabyRec + 40 + 8, 4 );
- memcpy( &nParts, psSHP->pabyRec + 36 + 8, 4 );
- if( bBigEndian ) SwapWord( 4, &nPoints );
- if( bBigEndian ) SwapWord( 4, &nParts );
- if (nPoints < 0 || nParts < 0 ||
- nPoints > 50 * 1000 * 1000 || nParts > 10 * 1000 * 1000)
- {
- snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d.",
- hEntity, nPoints, nParts);
- psSHP->sHooks.Error( pszErrorMsg );
- SHPDestroyObject(psShape);
- return NULL;
- }
-
- /* With the previous checks on nPoints and nParts, */
- /* we should not overflow here and after */
- /* since 50 M * (16 + 8 + 8) = 1 600 MB */
- nRequiredSize = 44 + 8 + 4 * nParts + 16 * nPoints;
- if ( psShape->nSHPType == SHPT_POLYGONZ
- || psShape->nSHPType == SHPT_ARCZ
- || psShape->nSHPType == SHPT_MULTIPATCH )
- {
- nRequiredSize += 16 + 8 * nPoints;
- }
- if( psShape->nSHPType == SHPT_MULTIPATCH )
- {
- nRequiredSize += 4 * nParts;
- }
- if (nRequiredSize > nEntitySize)
- {
- snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d, nEntitySize=%d.",
- hEntity, nPoints, nParts, nEntitySize);
- psSHP->sHooks.Error( pszErrorMsg );
- SHPDestroyObject(psShape);
- return NULL;
- }
- psShape->nVertices = nPoints;
- psShape->padfX = (double *) calloc(nPoints,sizeof(double));
- psShape->padfY = (double *) calloc(nPoints,sizeof(double));
- psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
- psShape->padfM = (double *) calloc(nPoints,sizeof(double));
- psShape->nParts = nParts;
- psShape->panPartStart = (int *) calloc(nParts,sizeof(int));
- psShape->panPartType = (int *) calloc(nParts,sizeof(int));
-
- if (psShape->padfX == NULL ||
- psShape->padfY == NULL ||
- psShape->padfZ == NULL ||
- psShape->padfM == NULL ||
- psShape->panPartStart == NULL ||
- psShape->panPartType == NULL)
- {
- snprintf(pszErrorMsg, 128,
- "Not enough memory to allocate requested memory (nPoints=%d, nParts=%d) for shape %d. "
- "Probably broken SHP file", hEntity, nPoints, nParts );
- psSHP->sHooks.Error( pszErrorMsg );
- SHPDestroyObject(psShape);
- return NULL;
- }
- for( i = 0; i < nParts; i++ )
- psShape->panPartType[i] = SHPP_RING;
- /* -------------------------------------------------------------------- */
- /* Copy out the part array from the record. */
- /* -------------------------------------------------------------------- */
- memcpy( psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts );
- for( i = 0; i < nParts; i++ )
- {
- if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i );
- /* We check that the offset is inside the vertex array */
- if (psShape->panPartStart[i] < 0 ||
- psShape->panPartStart[i] >= psShape->nVertices)
- {
- snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : panPartStart[%d] = %d, nVertices = %d",
- hEntity, i, psShape->panPartStart[i], psShape->nVertices);
- psSHP->sHooks.Error( pszErrorMsg );
- SHPDestroyObject(psShape);
- return NULL;
- }
- if (i > 0 && psShape->panPartStart[i] <= psShape->panPartStart[i-1])
- {
- snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : panPartStart[%d] = %d, panPartStart[%d] = %d",
- hEntity, i, psShape->panPartStart[i], i - 1, psShape->panPartStart[i - 1]);
- psSHP->sHooks.Error( pszErrorMsg );
- SHPDestroyObject(psShape);
- return NULL;
- }
- }
- nOffset = 44 + 8 + 4*nParts;
- /* -------------------------------------------------------------------- */
- /* If this is a multipatch, we will also have parts types. */
- /* -------------------------------------------------------------------- */
- if( psShape->nSHPType == SHPT_MULTIPATCH )
- {
- memcpy( psShape->panPartType, psSHP->pabyRec + nOffset, 4*nParts );
- for( i = 0; i < nParts; i++ )
- {
- if( bBigEndian ) SwapWord( 4, psShape->panPartType+i );
- }
- nOffset += 4*nParts;
- }
-
- /* -------------------------------------------------------------------- */
- /* Copy out the vertices from the record. */
- /* -------------------------------------------------------------------- */
- for( i = 0; i < nPoints; i++ )
- {
- memcpy(psShape->padfX + i,
- psSHP->pabyRec + nOffset + i * 16,
- 8 );
- memcpy(psShape->padfY + i,
- psSHP->pabyRec + nOffset + i * 16 + 8,
- 8 );
- if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
- if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
- }
- nOffset += 16*nPoints;
-
- /* -------------------------------------------------------------------- */
- /* If we have a Z coordinate, collect that now. */
- /* -------------------------------------------------------------------- */
- if( psShape->nSHPType == SHPT_POLYGONZ
- || psShape->nSHPType == SHPT_ARCZ
- || psShape->nSHPType == SHPT_MULTIPATCH )
- {
- memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
- memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
-
- if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
- if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
-
- for( i = 0; i < nPoints; i++ )
- {
- memcpy( psShape->padfZ + i,
- psSHP->pabyRec + nOffset + 16 + i*8, 8 );
- if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
- }
- nOffset += 16 + 8*nPoints;
- }
- /* -------------------------------------------------------------------- */
- /* If we have a M measure value, then read it now. We assume */
- /* that the measure can be present for any shape if the size is */
- /* big enough, but really it will only occur for the Z shapes */
- /* (options), and the M shapes. */
- /* -------------------------------------------------------------------- */
- if( nEntitySize >= nOffset + 16 + 8*nPoints )
- {
- memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
- memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
-
- if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
- if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
-
- for( i = 0; i < nPoints; i++ )
- {
- memcpy( psShape->padfM + i,
- psSHP->pabyRec + nOffset + 16 + i*8, 8 );
- if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
- }
- psShape->bMeasureIsUsed = TRUE;
- }
- }
- /* ==================================================================== */
- /* Extract vertices for a MultiPoint. */
- /* ==================================================================== */
- else if( psShape->nSHPType == SHPT_MULTIPOINT
- || psShape->nSHPType == SHPT_MULTIPOINTM
- || psShape->nSHPType == SHPT_MULTIPOINTZ )
- {
- int32 nPoints;
- int i, nOffset;
- if ( 44 + 4 > nEntitySize )
- {
- snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d",
- hEntity, nEntitySize);
- psSHP->sHooks.Error( pszErrorMsg );
- SHPDestroyObject(psShape);
- return NULL;
- }
- memcpy( &nPoints, psSHP->pabyRec + 44, 4 );
- if( bBigEndian ) SwapWord( 4, &nPoints );
- if (nPoints < 0 || nPoints > 50 * 1000 * 1000)
- {
- snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nPoints = %d",
- hEntity, nPoints);
- psSHP->sHooks.Error( pszErrorMsg );
- SHPDestroyObject(psShape);
- return NULL;
- }
- nRequiredSize = 48 + nPoints * 16;
- if( psShape->nSHPType == SHPT_MULTIPOINTZ )
- {
- nRequiredSize += 16 + nPoints * 8;
- }
- if (nRequiredSize > nEntitySize)
- {
- snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nPoints = %d, nEntitySize = %d",
- hEntity, nPoints, nEntitySize);
- psSHP->sHooks.Error( pszErrorMsg );
- SHPDestroyObject(psShape);
- return NULL;
- }
-
- psShape->nVertices = nPoints;
- psShape->padfX = (double *) calloc(nPoints,sizeof(double));
- psShape->padfY = (double *) calloc(nPoints,sizeof(double));
- psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
- psShape->padfM = (double *) calloc(nPoints,sizeof(double));
- if (psShape->padfX == NULL ||
- psShape->padfY == NULL ||
- psShape->padfZ == NULL ||
- psShape->padfM == NULL)
- {
- snprintf(pszErrorMsg, 128,
- "Not enough memory to allocate requested memory (nPoints=%d) for shape %d. "
- "Probably broken SHP file", hEntity, nPoints );
- psSHP->sHooks.Error( pszErrorMsg );
- SHPDestroyObject(psShape);
- return NULL;
- }
- for( i = 0; i < nPoints; i++ )
- {
- memcpy(psShape->padfX+i, psSHP->pabyRec + 48 + 16 * i, 8 );
- memcpy(psShape->padfY+i, psSHP->pabyRec + 48 + 16 * i + 8, 8 );
- if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
- if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
- }
- nOffset = 48 + 16*nPoints;
-
- /* -------------------------------------------------------------------- */
- /* Get the X/Y bounds. */
- /* -------------------------------------------------------------------- */
- memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 );
- memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );
- memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
- memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
- if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
- if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
- if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
- if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
- /* -------------------------------------------------------------------- */
- /* If we have a Z coordinate, collect that now. */
- /* -------------------------------------------------------------------- */
- if( psShape->nSHPType == SHPT_MULTIPOINTZ )
- {
- memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
- memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
-
- if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
- if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
-
- for( i = 0; i < nPoints; i++ )
- {
- memcpy( psShape->padfZ + i,
- psSHP->pabyRec + nOffset + 16 + i*8, 8 );
- if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
- }
- nOffset += 16 + 8*nPoints;
- }
- /* -------------------------------------------------------------------- */
- /* If we have a M measure value, then read it now. We assume */
- /* that the measure can be present for any shape if the size is */
- /* big enough, but really it will only occur for the Z shapes */
- /* (options), and the M shapes. */
- /* -------------------------------------------------------------------- */
- if( nEntitySize >= nOffset + 16 + 8*nPoints )
- {
- memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
- memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
-
- if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
- if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
-
- for( i = 0; i < nPoints; i++ )
- {
- memcpy( psShape->padfM + i,
- psSHP->pabyRec + nOffset + 16 + i*8, 8 );
- if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
- }
- psShape->bMeasureIsUsed = TRUE;
- }
- }
- /* ==================================================================== */
- /* Extract vertices for a point. */
- /* ==================================================================== */
- else if( psShape->nSHPType == SHPT_POINT
- || psShape->nSHPType == SHPT_POINTM
- || psShape->nSHPType == SHPT_POINTZ )
- {
- int nOffset;
-
- psShape->nVertices = 1;
- psShape->padfX = (double *) calloc(1,sizeof(double));
- psShape->padfY = (double *) calloc(1,sizeof(double));
- psShape->padfZ = (double *) calloc(1,sizeof(double));
- psShape->padfM = (double *) calloc(1,sizeof(double));
- if (20 + 8 + (( psShape->nSHPType == SHPT_POINTZ ) ? 8 : 0)> nEntitySize)
- {
- snprintf(pszErrorMsg, 128, "Corrupted .shp file : shape %d : nEntitySize = %d",
- hEntity, nEntitySize);
- psSHP->sHooks.Error( pszErrorMsg );
- SHPDestroyObject(psShape);
- return NULL;
- }
- memcpy( psShape->padfX, psSHP->pabyRec + 12, 8 );
- memcpy( psShape->padfY, psSHP->pabyRec + 20, 8 );
- if( bBigEndian ) SwapWord( 8, psShape->padfX );
- if( bBigEndian ) SwapWord( 8, psShape->padfY );
- nOffset = 20 + 8;
-
- /* -------------------------------------------------------------------- */
- /* If we have a Z coordinate, collect that now. */
- /* -------------------------------------------------------------------- */
- if( psShape->nSHPType == SHPT_POINTZ )
- {
- memcpy( psShape->padfZ, psSHP->pabyRec + nOffset, 8 );
-
- if( bBigEndian ) SwapWord( 8, psShape->padfZ );
-
- nOffset += 8;
- }
- /* -------------------------------------------------------------------- */
- /* If we have a M measure value, then read it now. We assume */
- /* that the measure can be present for any shape if the size is */
- /* big enough, but really it will only occur for the Z shapes */
- /* (options), and the M shapes. */
- /* -------------------------------------------------------------------- */
- if( nEntitySize >= nOffset + 8 )
- {
- memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 );
-
- if( bBigEndian ) SwapWord( 8, psShape->padfM );
- psShape->bMeasureIsUsed = TRUE;
- }
- /* -------------------------------------------------------------------- */
- /* Since no extents are supplied in the record, we will apply */
- /* them from the single vertex. */
- /* -------------------------------------------------------------------- */
- psShape->dfXMin = psShape->dfXMax = psShape->padfX[0];
- psShape->dfYMin = psShape->dfYMax = psShape->padfY[0];
- psShape->dfZMin = psShape->dfZMax = psShape->padfZ[0];
- psShape->dfMMin = psShape->dfMMax = psShape->padfM[0];
- }
- return( psShape );
- }
- /************************************************************************/
- /* SHPTypeName() */
- /************************************************************************/
- const char SHPAPI_CALL1(*)
- SHPTypeName( int nSHPType )
- {
- switch( nSHPType )
- {
- case SHPT_NULL:
- return "NullShape";
- case SHPT_POINT:
- return "Point";
- case SHPT_ARC:
- return "Arc";
- case SHPT_POLYGON:
- return "Polygon";
- case SHPT_MULTIPOINT:
- return "MultiPoint";
-
- case SHPT_POINTZ:
- return "PointZ";
- case SHPT_ARCZ:
- return "ArcZ";
- case SHPT_POLYGONZ:
- return "PolygonZ";
- case SHPT_MULTIPOINTZ:
- return "MultiPointZ";
-
- case SHPT_POINTM:
- return "PointM";
- case SHPT_ARCM:
- return "ArcM";
- case SHPT_POLYGONM:
- return "PolygonM";
- case SHPT_MULTIPOINTM:
- return "MultiPointM";
- case SHPT_MULTIPATCH:
- return "MultiPatch";
- default:
- return "UnknownShapeType";
- }
- }
- /************************************************************************/
- /* SHPPartTypeName() */
- /************************************************************************/
- const char SHPAPI_CALL1(*)
- SHPPartTypeName( int nPartType )
- {
- switch( nPartType )
- {
- case SHPP_TRISTRIP:
- return "TriangleStrip";
-
- case SHPP_TRIFAN:
- return "TriangleFan";
- case SHPP_OUTERRING:
- return "OuterRing";
- case SHPP_INNERRING:
- return "InnerRing";
- case SHPP_FIRSTRING:
- return "FirstRing";
- case SHPP_RING:
- return "Ring";
- default:
- return "UnknownPartType";
- }
- }
- /************************************************************************/
- /* SHPDestroyObject() */
- /************************************************************************/
- void SHPAPI_CALL
- SHPDestroyObject( SHPObject * psShape )
- {
- if( psShape == NULL )
- return;
-
- if( psShape->padfX != NULL )
- free( psShape->padfX );
- if( psShape->padfY != NULL )
- free( psShape->padfY );
- if( psShape->padfZ != NULL )
- free( psShape->padfZ );
- if( psShape->padfM != NULL )
- free( psShape->padfM );
- if( psShape->panPartStart != NULL )
- free( psShape->panPartStart );
- if( psShape->panPartType != NULL )
- free( psShape->panPartType );
- free( psShape );
- }
- /************************************************************************/
- /* SHPRewindObject() */
- /* */
- /* Reset the winding of polygon objects to adhere to the */
- /* specification. */
- /************************************************************************/
- int SHPAPI_CALL
- SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
- {
- int iOpRing, bAltered = 0;
- /* -------------------------------------------------------------------- */
- /* Do nothing if this is not a polygon object. */
- /* -------------------------------------------------------------------- */
- if( psObject->nSHPType != SHPT_POLYGON
- && psObject->nSHPType != SHPT_POLYGONZ
- && psObject->nSHPType != SHPT_POLYGONM )
- return 0;
- if( psObject->nVertices == 0 || psObject->nParts == 0 )
- return 0;
- /* -------------------------------------------------------------------- */
- /* Process each of the rings. */
- /* -------------------------------------------------------------------- */
- for( iOpRing = 0; iOpRing < psObject->nParts; iOpRing++ )
- {
- int bInner, iVert, nVertCount, nVertStart, iCheckRing;
- double dfSum, dfTestX, dfTestY;
- /* -------------------------------------------------------------------- */
- /* Determine if this ring is an inner ring or an outer ring */
- /* relative to all the other rings. For now we assume the */
- /* first ring is outer and all others are inner, but eventually */
- /* we need to fix this to handle multiple island polygons and */
- /* unordered sets of rings. */
- /* */
- /* -------------------------------------------------------------------- */
- /* Use point in the middle of segment to avoid testing
- * common points of rings.
- */
- dfTestX = ( psObject->padfX[psObject->panPartStart[iOpRing]]
- + psObject->padfX[psObject->panPartStart[iOpRing] + 1] ) / 2;
- dfTestY = ( psObject->padfY[psObject->panPartStart[iOpRing]]
- + psObject->padfY[psObject->panPartStart[iOpRing] + 1] ) / 2;
- bInner = FALSE;
- for( iCheckRing = 0; iCheckRing < psObject->nParts; iCheckRing++ )
- {
- int iEdge;
- if( iCheckRing == iOpRing )
- continue;
-
- nVertStart = psObject->panPartStart[iCheckRing];
- if( iCheckRing == psObject->nParts-1 )
- nVertCount = psObject->nVertices
- - psObject->panPartStart[iCheckRing];
- else
- nVertCount = psObject->panPartStart[iCheckRing+1]
- - psObject->panPartStart[iCheckRing];
- for( iEdge = 0; iEdge < nVertCount; iEdge++ )
- {
- int iNext;
- if( iEdge < nVertCount-1 )
- iNext = iEdge+1;
- else
- iNext = 0;
- /* Rule #1:
- * Test whether the edge 'straddles' the horizontal ray from the test point (dfTestY,dfTestY)
- * The rule #1 also excludes edges collinear with the ray.
- */
- if ( ( psObject->padfY[iEdge+nVertStart] < dfTestY
- && dfTestY <= psObject->padfY[iNext+nVertStart] )
- || ( psObject->padfY[iNext+nVertStart] < dfTestY
- && dfTestY <= psObject->padfY[iEdge+nVertStart] ) )
- {
- /* Rule #2:
- * Test if edge-ray intersection is on the right from the test point (dfTestY,dfTestY)
- */
- double const intersect =
- ( psObject->padfX[iEdge+nVertStart]
- + ( dfTestY - psObject->padfY[iEdge+nVertStart] )
- / ( psObject->padfY[iNext+nVertStart] - psObject->padfY[iEdge+nVertStart] )
- * ( psObject->padfX[iNext+nVertStart] - psObject->padfX[iEdge+nVertStart] ) );
- if (intersect < dfTestX)
- {
- bInner = !bInner;
- }
- }
- }
- } /* for iCheckRing */
- /* -------------------------------------------------------------------- */
- /* Determine the current order of this ring so we will know if */
- /* it has to be reversed. */
- /* -------------------------------------------------------------------- */
- nVertStart = psObject->panPartStart[iOpRing];
- if( iOpRing == psObject->nParts-1 )
- nVertCount = psObject->nVertices - psObject->panPartStart[iOpRing];
- else
- nVertCount = psObject->panPartStart[iOpRing+1]
- - psObject->panPartStart[iOpRing];
- dfSum = 0.0;
- for( iVert = nVertStart; iVert < nVertStart+nVertCount-1; iVert++ )
- {
- dfSum += psObject->padfX[iVert] * psObject->padfY[iVert+1]
- - psObject->padfY[iVert] * psObject->padfX[iVert+1];
- }
- dfSum += psObject->padfX[iVert] * psObject->padfY[nVertStart]
- - psObject->padfY[iVert] * psObject->padfX[nVertStart];
- /* -------------------------------------------------------------------- */
- /* Reverse if necessary. */
- /* -------------------------------------------------------------------- */
- if( (dfSum < 0.0 && bInner) || (dfSum > 0.0 && !bInner) )
- {
- int i;
- bAltered++;
- for( i = 0; i < nVertCount/2; i++ )
- {
- double dfSaved;
- /* Swap X */
- dfSaved = psObject->padfX[nVertStart+i];
- psObject->padfX[nVertStart+i] =
- psObject->padfX[nVertStart+nVertCount-i-1];
- psObject->padfX[nVertStart+nVertCount-i-1] = dfSaved;
- /* Swap Y */
- dfSaved = psObject->padfY[nVertStart+i];
- psObject->padfY[nVertStart+i] =
- psObject->padfY[nVertStart+nVertCount-i-1];
- psObject->padfY[nVertStart+nVertCount-i-1] = dfSaved;
- /* Swap Z */
- if( psObject->padfZ )
- {
- dfSaved = psObject->padfZ[nVertStart+i];
- psObject->padfZ[nVertStart+i] =
- psObject->padfZ[nVertStart+nVertCount-i-1];
- psObject->padfZ[nVertStart+nVertCount-i-1] = dfSaved;
- }
- /* Swap M */
- if( psObject->padfM )
- {
- dfSaved = psObject->padfM[nVertStart+i];
- psObject->padfM[nVertStart+i] =
- psObject->padfM[nVertStart+nVertCount-i-1];
- psObject->padfM[nVertStart+nVertCount-i-1] = dfSaved;
- }
- }
- }
- }
- return bAltered;
- }
|