shpopen.c 107 KB

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