dbfopen.c 79 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260
  1. /******************************************************************************
  2. * $Id$
  3. *
  4. * Project: Shapelib
  5. * Purpose: Implementation of .dbf access API documented in dbf_api.html.
  6. * Author: Frank Warmerdam, warmerdam@pobox.com
  7. *
  8. ******************************************************************************
  9. * Copyright (c) 1999, Frank Warmerdam
  10. * Copyright (c) 2012-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: dbfopen.c,v $
  38. * Revision 1.89 2011-07-24 05:59:25 fwarmerdam
  39. * minimize use of CPLError in favor of SAHooks.Error()
  40. *
  41. * Revision 1.88 2011-05-13 17:35:17 fwarmerdam
  42. * added DBFReorderFields() and DBFAlterFields() functions (from Even)
  43. *
  44. * Revision 1.87 2011-05-07 22:41:02 fwarmerdam
  45. * ensure pending record is flushed when adding a native field (GDAL #4073)
  46. *
  47. * Revision 1.86 2011-04-17 15:15:29 fwarmerdam
  48. * Removed unused variable.
  49. *
  50. * Revision 1.85 2010-12-06 16:09:34 fwarmerdam
  51. * fix buffer read overrun fetching code page (bug 2276)
  52. *
  53. * Revision 1.84 2009-10-29 19:59:48 fwarmerdam
  54. * avoid crash on truncated header (gdal #3093)
  55. *
  56. * Revision 1.83 2008/11/12 14:28:15 fwarmerdam
  57. * DBFCreateField() now works on files with records
  58. *
  59. * Revision 1.82 2008/11/11 17:47:09 fwarmerdam
  60. * added DBFDeleteField() function
  61. *
  62. * Revision 1.81 2008/01/03 17:48:13 bram
  63. * in DBFCreate, use default code page LDID/87 (= 0x57, ANSI)
  64. * instead of LDID/3. This seems to be the same as what ESRI
  65. * would be doing by default.
  66. *
  67. * Revision 1.80 2007/12/30 14:36:39 fwarmerdam
  68. * avoid syntax issue with last comment.
  69. *
  70. * Revision 1.79 2007/12/30 14:35:48 fwarmerdam
  71. * Avoid char* / unsigned char* warnings.
  72. *
  73. * Revision 1.78 2007/12/18 18:28:07 bram
  74. * - create hook for client specific atof (bugzilla ticket 1615)
  75. * - check for NULL handle before closing cpCPG file, and close after reading.
  76. *
  77. * Revision 1.77 2007/12/15 20:25:21 bram
  78. * dbfopen.c now reads the Code Page information from the DBF file, and exports
  79. * this information as a string through the DBFGetCodePage function. This is
  80. * either the number from the LDID header field ("LDID/<number>") or as the
  81. * content of an accompanying .CPG file. When creating a DBF file, the code can
  82. * be set using DBFCreateEx.
  83. *
  84. * Revision 1.76 2007/12/12 22:21:32 bram
  85. * DBFClose: check for NULL psDBF handle before trying to close it.
  86. *
  87. * Revision 1.75 2007/12/06 13:58:19 fwarmerdam
  88. * make sure file offset calculations are done in as SAOffset
  89. *
  90. * Revision 1.74 2007/12/06 07:00:25 fwarmerdam
  91. * dbfopen now using SAHooks for fileio
  92. *
  93. * Revision 1.73 2007/09/03 19:48:11 fwarmerdam
  94. * move DBFReadAttribute() static dDoubleField into dbfinfo
  95. *
  96. * Revision 1.72 2007/09/03 19:34:06 fwarmerdam
  97. * Avoid use of static tuple buffer in DBFReadTuple()
  98. *
  99. * Revision 1.71 2006/06/22 14:37:18 fwarmerdam
  100. * avoid memory leak if dbfopen fread fails
  101. *
  102. * Revision 1.70 2006/06/17 17:47:05 fwarmerdam
  103. * use calloc() for dbfinfo in DBFCreate
  104. *
  105. * Revision 1.69 2006/06/17 15:34:32 fwarmerdam
  106. * disallow creating fields wider than 255
  107. *
  108. * Revision 1.68 2006/06/17 15:12:40 fwarmerdam
  109. * Fixed C++ style comments.
  110. *
  111. * Revision 1.67 2006/06/17 00:24:53 fwarmerdam
  112. * Don't treat non-zero decimals values as high order byte for length
  113. * for strings. It causes serious corruption for some files.
  114. * http://bugzilla.remotesensing.org/show_bug.cgi?id=1202
  115. *
  116. * Revision 1.66 2006/03/29 18:26:20 fwarmerdam
  117. * fixed bug with size of pachfieldtype in dbfcloneempty
  118. *
  119. * Revision 1.65 2006/02/15 01:14:30 fwarmerdam
  120. * added DBFAddNativeFieldType
  121. *
  122. * Revision 1.64 2006/02/09 00:29:04 fwarmerdam
  123. * Changed to put spaces into string fields that are NULL as
  124. * per http://bugzilla.maptools.org/show_bug.cgi?id=316.
  125. *
  126. * Revision 1.63 2006/01/25 15:35:43 fwarmerdam
  127. * check success on DBFFlushRecord
  128. *
  129. * Revision 1.62 2006/01/10 16:28:03 fwarmerdam
  130. * Fixed typo in CPLError.
  131. *
  132. * Revision 1.61 2006/01/10 16:26:29 fwarmerdam
  133. * Push loading record buffer into DBFLoadRecord.
  134. * Implement CPL error reporting if USE_CPL defined.
  135. *
  136. * Revision 1.60 2006/01/05 01:27:27 fwarmerdam
  137. * added dbf deletion mark/fetch
  138. *
  139. * Revision 1.59 2005/03/14 15:20:28 fwarmerdam
  140. * Fixed last change.
  141. *
  142. * Revision 1.58 2005/03/14 15:18:54 fwarmerdam
  143. * Treat very wide fields with no decimals as double. This is
  144. * more than 32bit integer fields.
  145. *
  146. * Revision 1.57 2005/02/10 20:16:54 fwarmerdam
  147. * Make the pszStringField buffer for DBFReadAttribute() static char [256]
  148. * as per bug 306.
  149. *
  150. * Revision 1.56 2005/02/10 20:07:56 fwarmerdam
  151. * Fixed bug 305 in DBFCloneEmpty() - header length problem.
  152. *
  153. * Revision 1.55 2004/09/26 20:23:46 fwarmerdam
  154. * avoid warnings with rcsid and signed/unsigned stuff
  155. *
  156. * Revision 1.54 2004/09/15 16:26:10 fwarmerdam
  157. * Treat all blank numeric fields as null too.
  158. */
  159. #include <grass/shapefil.h>
  160. #include <math.h>
  161. #include <stdlib.h>
  162. #include <ctype.h>
  163. #include <string.h>
  164. #ifdef USE_CPL
  165. #include "cpl_string.h"
  166. #else
  167. #define CPLsprintf sprintf
  168. #endif
  169. #if defined(WIN32) || defined(_WIN32)
  170. # ifndef snprintf
  171. # define snprintf _snprintf
  172. # endif
  173. #endif
  174. SHP_CVSID("$Id$")
  175. #ifndef FALSE
  176. # define FALSE 0
  177. # define TRUE 1
  178. #endif
  179. /************************************************************************/
  180. /* SfRealloc() */
  181. /* */
  182. /* A realloc cover function that will access a NULL pointer as */
  183. /* a valid input. */
  184. /************************************************************************/
  185. static void * SfRealloc( void * pMem, int nNewSize )
  186. {
  187. if( pMem == NULL )
  188. return( (void *) malloc(nNewSize) );
  189. else
  190. return( (void *) realloc(pMem,nNewSize) );
  191. }
  192. /************************************************************************/
  193. /* DBFWriteHeader() */
  194. /* */
  195. /* This is called to write out the file header, and field */
  196. /* descriptions before writing any actual data records. This */
  197. /* also computes all the DBFDataSet field offset/size/decimals */
  198. /* and so forth values. */
  199. /************************************************************************/
  200. static void DBFWriteHeader(DBFHandle psDBF)
  201. {
  202. unsigned char abyHeader[XBASE_FLDHDR_SZ];
  203. int i;
  204. if( !psDBF->bNoHeader )
  205. return;
  206. psDBF->bNoHeader = FALSE;
  207. /* -------------------------------------------------------------------- */
  208. /* Initialize the file header information. */
  209. /* -------------------------------------------------------------------- */
  210. for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
  211. abyHeader[i] = 0;
  212. abyHeader[0] = 0x03; /* memo field? - just copying */
  213. /* write out update date */
  214. abyHeader[1] = (unsigned char) psDBF->nUpdateYearSince1900;
  215. abyHeader[2] = (unsigned char) psDBF->nUpdateMonth;
  216. abyHeader[3] = (unsigned char) psDBF->nUpdateDay;
  217. /* record count preset at zero */
  218. abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
  219. abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
  220. abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
  221. abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
  222. abyHeader[29] = (unsigned char) (psDBF->iLanguageDriver);
  223. /* -------------------------------------------------------------------- */
  224. /* Write the initial 32 byte file header, and all the field */
  225. /* descriptions. */
  226. /* -------------------------------------------------------------------- */
  227. psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
  228. psDBF->sHooks.FWrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
  229. psDBF->sHooks.FWrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields,
  230. psDBF->fp );
  231. /* -------------------------------------------------------------------- */
  232. /* Write out the newline character if there is room for it. */
  233. /* -------------------------------------------------------------------- */
  234. if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
  235. {
  236. char cNewline;
  237. cNewline = 0x0d;
  238. psDBF->sHooks.FWrite( &cNewline, 1, 1, psDBF->fp );
  239. }
  240. }
  241. /************************************************************************/
  242. /* DBFFlushRecord() */
  243. /* */
  244. /* Write out the current record if there is one. */
  245. /************************************************************************/
  246. static int DBFFlushRecord( DBFHandle psDBF )
  247. {
  248. SAOffset nRecordOffset;
  249. if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )
  250. {
  251. psDBF->bCurrentRecordModified = FALSE;
  252. nRecordOffset =
  253. psDBF->nRecordLength * (SAOffset) psDBF->nCurrentRecord
  254. + psDBF->nHeaderLength;
  255. if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ) != 0
  256. || psDBF->sHooks.FWrite( psDBF->pszCurrentRecord,
  257. psDBF->nRecordLength,
  258. 1, psDBF->fp ) != 1 )
  259. {
  260. char szMessage[128];
  261. snprintf( szMessage, sizeof(szMessage), "Failure writing DBF record %d.",
  262. psDBF->nCurrentRecord );
  263. psDBF->sHooks.Error( szMessage );
  264. return FALSE;
  265. }
  266. }
  267. return TRUE;
  268. }
  269. /************************************************************************/
  270. /* DBFLoadRecord() */
  271. /************************************************************************/
  272. static int DBFLoadRecord( DBFHandle psDBF, int iRecord )
  273. {
  274. if( psDBF->nCurrentRecord != iRecord )
  275. {
  276. SAOffset nRecordOffset;
  277. if( !DBFFlushRecord( psDBF ) )
  278. return FALSE;
  279. nRecordOffset =
  280. psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
  281. if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, SEEK_SET ) != 0 )
  282. {
  283. char szMessage[128];
  284. snprintf( szMessage, sizeof(szMessage), "fseek(%ld) failed on DBF file.\n",
  285. (long) nRecordOffset );
  286. psDBF->sHooks.Error( szMessage );
  287. return FALSE;
  288. }
  289. if( psDBF->sHooks.FRead( psDBF->pszCurrentRecord,
  290. psDBF->nRecordLength, 1, psDBF->fp ) != 1 )
  291. {
  292. char szMessage[128];
  293. snprintf( szMessage, sizeof(szMessage), "fread(%d) failed on DBF file.\n",
  294. psDBF->nRecordLength );
  295. psDBF->sHooks.Error( szMessage );
  296. return FALSE;
  297. }
  298. psDBF->nCurrentRecord = iRecord;
  299. }
  300. return TRUE;
  301. }
  302. /************************************************************************/
  303. /* DBFUpdateHeader() */
  304. /************************************************************************/
  305. void SHPAPI_CALL
  306. DBFUpdateHeader( DBFHandle psDBF )
  307. {
  308. unsigned char abyFileHeader[32];
  309. if( psDBF->bNoHeader )
  310. DBFWriteHeader( psDBF );
  311. if( !DBFFlushRecord( psDBF ) )
  312. return;
  313. psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
  314. psDBF->sHooks.FRead( abyFileHeader, 32, 1, psDBF->fp );
  315. abyFileHeader[1] = (unsigned char) psDBF->nUpdateYearSince1900;
  316. abyFileHeader[2] = (unsigned char) psDBF->nUpdateMonth;
  317. abyFileHeader[3] = (unsigned char) psDBF->nUpdateDay;
  318. abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256);
  319. abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256);
  320. abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256);
  321. abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256);
  322. psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
  323. psDBF->sHooks.FWrite( abyFileHeader, 32, 1, psDBF->fp );
  324. psDBF->sHooks.FFlush( psDBF->fp );
  325. }
  326. /************************************************************************/
  327. /* DBFSetLastModifiedDate() */
  328. /************************************************************************/
  329. void SHPAPI_CALL
  330. DBFSetLastModifiedDate( DBFHandle psDBF, int nYYSince1900, int nMM, int nDD )
  331. {
  332. psDBF->nUpdateYearSince1900 = nYYSince1900;
  333. psDBF->nUpdateMonth = nMM;
  334. psDBF->nUpdateDay = nDD;
  335. }
  336. /************************************************************************/
  337. /* DBFOpen() */
  338. /* */
  339. /* Open a .dbf file. */
  340. /************************************************************************/
  341. DBFHandle SHPAPI_CALL
  342. DBFOpen( const char * pszFilename, const char * pszAccess )
  343. {
  344. SAHooks sHooks;
  345. SASetupDefaultHooks( &sHooks );
  346. return DBFOpenLL( pszFilename, pszAccess, &sHooks );
  347. }
  348. /************************************************************************/
  349. /* DBFOpen() */
  350. /* */
  351. /* Open a .dbf file. */
  352. /************************************************************************/
  353. DBFHandle SHPAPI_CALL
  354. DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
  355. {
  356. DBFHandle psDBF;
  357. SAFile pfCPG;
  358. unsigned char *pabyBuf;
  359. int nFields, nHeadLen, iField, i;
  360. char *pszBasename, *pszFullname;
  361. int nBufSize = 500;
  362. size_t nFullnameLen;
  363. /* -------------------------------------------------------------------- */
  364. /* We only allow the access strings "rb" and "r+". */
  365. /* -------------------------------------------------------------------- */
  366. if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0
  367. && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
  368. && strcmp(pszAccess,"r+b") != 0 )
  369. return( NULL );
  370. if( strcmp(pszAccess,"r") == 0 )
  371. pszAccess = "rb";
  372. if( strcmp(pszAccess,"r+") == 0 )
  373. pszAccess = "rb+";
  374. /* -------------------------------------------------------------------- */
  375. /* Compute the base (layer) name. If there is any extension */
  376. /* on the passed in filename we will strip it off. */
  377. /* -------------------------------------------------------------------- */
  378. pszBasename = (char *) malloc(strlen(pszFilename)+5);
  379. strcpy( pszBasename, pszFilename );
  380. for( i = (int)strlen(pszBasename)-1;
  381. i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
  382. && pszBasename[i] != '\\';
  383. i-- ) {}
  384. if( pszBasename[i] == '.' )
  385. pszBasename[i] = '\0';
  386. nFullnameLen = strlen(pszBasename) + 5;
  387. pszFullname = (char *) malloc(nFullnameLen);
  388. snprintf( pszFullname, nFullnameLen, "%s.dbf", pszBasename );
  389. psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
  390. psDBF->fp = psHooks->FOpen( pszFullname, pszAccess );
  391. memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
  392. if( psDBF->fp == NULL )
  393. {
  394. snprintf( pszFullname, nFullnameLen, "%s.DBF", pszBasename );
  395. psDBF->fp = psDBF->sHooks.FOpen(pszFullname, pszAccess );
  396. }
  397. snprintf( pszFullname, nFullnameLen, "%s.cpg", pszBasename );
  398. pfCPG = psHooks->FOpen( pszFullname, "r" );
  399. if( pfCPG == NULL )
  400. {
  401. snprintf( pszFullname, nFullnameLen, "%s.CPG", pszBasename );
  402. pfCPG = psHooks->FOpen( pszFullname, "r" );
  403. }
  404. free( pszBasename );
  405. free( pszFullname );
  406. if( psDBF->fp == NULL )
  407. {
  408. free( psDBF );
  409. if( pfCPG ) psHooks->FClose( pfCPG );
  410. return( NULL );
  411. }
  412. psDBF->bNoHeader = FALSE;
  413. psDBF->nCurrentRecord = -1;
  414. psDBF->bCurrentRecordModified = FALSE;
  415. /* -------------------------------------------------------------------- */
  416. /* Read Table Header info */
  417. /* -------------------------------------------------------------------- */
  418. pabyBuf = (unsigned char *) malloc(nBufSize);
  419. if( psDBF->sHooks.FRead( pabyBuf, 32, 1, psDBF->fp ) != 1 )
  420. {
  421. psDBF->sHooks.FClose( psDBF->fp );
  422. if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
  423. free( pabyBuf );
  424. free( psDBF );
  425. return NULL;
  426. }
  427. DBFSetLastModifiedDate(psDBF, pabyBuf[1], pabyBuf[2], pabyBuf[3]);
  428. psDBF->nRecords =
  429. pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + (pabyBuf[7] & 0x7f) *256*256*256;
  430. psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
  431. psDBF->nRecordLength = pabyBuf[10] + pabyBuf[11]*256;
  432. psDBF->iLanguageDriver = pabyBuf[29];
  433. if (psDBF->nRecordLength == 0 || nHeadLen < 32)
  434. {
  435. psDBF->sHooks.FClose( psDBF->fp );
  436. if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
  437. free( pabyBuf );
  438. free( psDBF );
  439. return NULL;
  440. }
  441. psDBF->nFields = nFields = (nHeadLen - 32) / 32;
  442. psDBF->pszCurrentRecord = (char *) malloc(psDBF->nRecordLength);
  443. /* -------------------------------------------------------------------- */
  444. /* Figure out the code page from the LDID and CPG */
  445. /* -------------------------------------------------------------------- */
  446. psDBF->pszCodePage = NULL;
  447. if( pfCPG )
  448. {
  449. size_t n;
  450. memset( pabyBuf, 0, nBufSize);
  451. psDBF->sHooks.FRead( pabyBuf, nBufSize - 1, 1, pfCPG );
  452. n = strcspn( (char *) pabyBuf, "\n\r" );
  453. if( n > 0 )
  454. {
  455. pabyBuf[n] = '\0';
  456. psDBF->pszCodePage = (char *) malloc(n + 1);
  457. memcpy( psDBF->pszCodePage, pabyBuf, n + 1 );
  458. }
  459. psDBF->sHooks.FClose( pfCPG );
  460. }
  461. if( psDBF->pszCodePage == NULL && pabyBuf[29] != 0 )
  462. {
  463. snprintf( (char *) pabyBuf, nBufSize, "LDID/%d", psDBF->iLanguageDriver );
  464. psDBF->pszCodePage = (char *) malloc(strlen((char*)pabyBuf) + 1);
  465. strcpy( psDBF->pszCodePage, (char *) pabyBuf );
  466. }
  467. /* -------------------------------------------------------------------- */
  468. /* Read in Field Definitions */
  469. /* -------------------------------------------------------------------- */
  470. pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
  471. psDBF->pszHeader = (char *) pabyBuf;
  472. psDBF->sHooks.FSeek( psDBF->fp, 32, 0 );
  473. if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
  474. {
  475. psDBF->sHooks.FClose( psDBF->fp );
  476. free( pabyBuf );
  477. free( psDBF->pszCurrentRecord );
  478. free( psDBF );
  479. return NULL;
  480. }
  481. psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);
  482. psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);
  483. psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields);
  484. psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields);
  485. for( iField = 0; iField < nFields; iField++ )
  486. {
  487. unsigned char *pabyFInfo;
  488. pabyFInfo = pabyBuf+iField*32;
  489. if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
  490. {
  491. psDBF->panFieldSize[iField] = pabyFInfo[16];
  492. psDBF->panFieldDecimals[iField] = pabyFInfo[17];
  493. }
  494. else
  495. {
  496. psDBF->panFieldSize[iField] = pabyFInfo[16];
  497. psDBF->panFieldDecimals[iField] = 0;
  498. /*
  499. ** The following seemed to be used sometimes to handle files with long
  500. ** string fields, but in other cases (such as bug 1202) the decimals field
  501. ** just seems to indicate some sort of preferred formatting, not very
  502. ** wide fields. So I have disabled this code. FrankW.
  503. psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;
  504. psDBF->panFieldDecimals[iField] = 0;
  505. */
  506. }
  507. psDBF->pachFieldType[iField] = (char) pabyFInfo[11];
  508. if( iField == 0 )
  509. psDBF->panFieldOffset[iField] = 1;
  510. else
  511. psDBF->panFieldOffset[iField] =
  512. psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
  513. }
  514. return( psDBF );
  515. }
  516. /************************************************************************/
  517. /* DBFClose() */
  518. /************************************************************************/
  519. void SHPAPI_CALL
  520. DBFClose(DBFHandle psDBF)
  521. {
  522. if( psDBF == NULL )
  523. return;
  524. /* -------------------------------------------------------------------- */
  525. /* Write out header if not already written. */
  526. /* -------------------------------------------------------------------- */
  527. if( psDBF->bNoHeader )
  528. DBFWriteHeader( psDBF );
  529. DBFFlushRecord( psDBF );
  530. /* -------------------------------------------------------------------- */
  531. /* Update last access date, and number of records if we have */
  532. /* write access. */
  533. /* -------------------------------------------------------------------- */
  534. if( psDBF->bUpdated )
  535. DBFUpdateHeader( psDBF );
  536. /* -------------------------------------------------------------------- */
  537. /* Close, and free resources. */
  538. /* -------------------------------------------------------------------- */
  539. psDBF->sHooks.FClose( psDBF->fp );
  540. if( psDBF->panFieldOffset != NULL )
  541. {
  542. free( psDBF->panFieldOffset );
  543. free( psDBF->panFieldSize );
  544. free( psDBF->panFieldDecimals );
  545. free( psDBF->pachFieldType );
  546. }
  547. if( psDBF->pszWorkField != NULL )
  548. free( psDBF->pszWorkField );
  549. free( psDBF->pszHeader );
  550. free( psDBF->pszCurrentRecord );
  551. free( psDBF->pszCodePage );
  552. free( psDBF );
  553. }
  554. /************************************************************************/
  555. /* DBFCreate() */
  556. /* */
  557. /* Create a new .dbf file with default code page LDID/87 (0x57) */
  558. /************************************************************************/
  559. DBFHandle SHPAPI_CALL
  560. DBFCreate( const char * pszFilename )
  561. {
  562. return DBFCreateEx( pszFilename, "LDID/87" ); // 0x57
  563. }
  564. /************************************************************************/
  565. /* DBFCreateEx() */
  566. /* */
  567. /* Create a new .dbf file. */
  568. /************************************************************************/
  569. DBFHandle SHPAPI_CALL
  570. DBFCreateEx( const char * pszFilename, const char* pszCodePage )
  571. {
  572. SAHooks sHooks;
  573. SASetupDefaultHooks( &sHooks );
  574. return DBFCreateLL( pszFilename, pszCodePage , &sHooks );
  575. }
  576. /************************************************************************/
  577. /* DBFCreate() */
  578. /* */
  579. /* Create a new .dbf file. */
  580. /************************************************************************/
  581. DBFHandle SHPAPI_CALL
  582. DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHooks )
  583. {
  584. DBFHandle psDBF;
  585. SAFile fp;
  586. char *pszFullname, *pszBasename;
  587. int i, ldid = -1;
  588. char chZero = '\0';
  589. size_t nFullnameLen;
  590. /* -------------------------------------------------------------------- */
  591. /* Compute the base (layer) name. If there is any extension */
  592. /* on the passed in filename we will strip it off. */
  593. /* -------------------------------------------------------------------- */
  594. pszBasename = (char *) malloc(strlen(pszFilename)+5);
  595. strcpy( pszBasename, pszFilename );
  596. for( i = (int)strlen(pszBasename)-1;
  597. i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
  598. && pszBasename[i] != '\\';
  599. i-- ) {}
  600. if( pszBasename[i] == '.' )
  601. pszBasename[i] = '\0';
  602. nFullnameLen = strlen(pszBasename) + 5;
  603. pszFullname = (char *) malloc(nFullnameLen);
  604. snprintf( pszFullname, nFullnameLen, "%s.dbf", pszBasename );
  605. /* -------------------------------------------------------------------- */
  606. /* Create the file. */
  607. /* -------------------------------------------------------------------- */
  608. fp = psHooks->FOpen( pszFullname, "wb" );
  609. if( fp == NULL )
  610. {
  611. free( pszBasename );
  612. free( pszFullname );
  613. return( NULL );
  614. }
  615. psHooks->FWrite( &chZero, 1, 1, fp );
  616. psHooks->FClose( fp );
  617. fp = psHooks->FOpen( pszFullname, "rb+" );
  618. if( fp == NULL )
  619. {
  620. free( pszBasename );
  621. free( pszFullname );
  622. return( NULL );
  623. }
  624. snprintf( pszFullname, nFullnameLen, "%s.cpg", pszBasename );
  625. if( pszCodePage != NULL )
  626. {
  627. if( strncmp( pszCodePage, "LDID/", 5 ) == 0 )
  628. {
  629. ldid = atoi( pszCodePage + 5 );
  630. if( ldid > 255 )
  631. ldid = -1; // don't use 0 to indicate out of range as LDID/0 is a valid one
  632. }
  633. if( ldid < 0 )
  634. {
  635. SAFile fpCPG = psHooks->FOpen( pszFullname, "w" );
  636. psHooks->FWrite( (char*) pszCodePage, strlen(pszCodePage), 1, fpCPG );
  637. psHooks->FClose( fpCPG );
  638. }
  639. }
  640. if( pszCodePage == NULL || ldid >= 0 )
  641. {
  642. psHooks->Remove( pszFullname );
  643. }
  644. free( pszBasename );
  645. free( pszFullname );
  646. /* -------------------------------------------------------------------- */
  647. /* Create the info structure. */
  648. /* -------------------------------------------------------------------- */
  649. psDBF = (DBFHandle) calloc(1,sizeof(DBFInfo));
  650. memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
  651. psDBF->fp = fp;
  652. psDBF->nRecords = 0;
  653. psDBF->nFields = 0;
  654. psDBF->nRecordLength = 1;
  655. psDBF->nHeaderLength = 33;
  656. psDBF->panFieldOffset = NULL;
  657. psDBF->panFieldSize = NULL;
  658. psDBF->panFieldDecimals = NULL;
  659. psDBF->pachFieldType = NULL;
  660. psDBF->pszHeader = NULL;
  661. psDBF->nCurrentRecord = -1;
  662. psDBF->bCurrentRecordModified = FALSE;
  663. psDBF->pszCurrentRecord = NULL;
  664. psDBF->bNoHeader = TRUE;
  665. psDBF->iLanguageDriver = ldid > 0 ? ldid : 0;
  666. psDBF->pszCodePage = NULL;
  667. if( pszCodePage )
  668. {
  669. psDBF->pszCodePage = (char * ) malloc( strlen(pszCodePage) + 1 );
  670. strcpy( psDBF->pszCodePage, pszCodePage );
  671. }
  672. DBFSetLastModifiedDate(psDBF, 95, 7, 26); /* dummy date */
  673. return( psDBF );
  674. }
  675. /************************************************************************/
  676. /* DBFAddField() */
  677. /* */
  678. /* Add a field to a newly created .dbf or to an existing one */
  679. /************************************************************************/
  680. int SHPAPI_CALL
  681. DBFAddField(DBFHandle psDBF, const char * pszFieldName,
  682. DBFFieldType eType, int nWidth, int nDecimals )
  683. {
  684. char chNativeType = 'C';
  685. if( eType == FTLogical )
  686. chNativeType = 'L';
  687. else if( eType == FTString )
  688. chNativeType = 'C';
  689. else
  690. chNativeType = 'N';
  691. return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType,
  692. nWidth, nDecimals );
  693. }
  694. /************************************************************************/
  695. /* DBFGetNullCharacter() */
  696. /************************************************************************/
  697. static char DBFGetNullCharacter(char chType)
  698. {
  699. switch (chType)
  700. {
  701. case 'N':
  702. case 'F':
  703. return '*';
  704. case 'D':
  705. return '0';
  706. case 'L':
  707. return '?';
  708. default:
  709. return ' ';
  710. }
  711. }
  712. /************************************************************************/
  713. /* DBFAddField() */
  714. /* */
  715. /* Add a field to a newly created .dbf file before any records */
  716. /* are written. */
  717. /************************************************************************/
  718. int SHPAPI_CALL
  719. DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
  720. char chType, int nWidth, int nDecimals )
  721. {
  722. char *pszFInfo;
  723. int i;
  724. int nOldRecordLength, nOldHeaderLength;
  725. char *pszRecord;
  726. char chFieldFill;
  727. SAOffset nRecordOffset;
  728. /* make sure that everything is written in .dbf */
  729. if( !DBFFlushRecord( psDBF ) )
  730. return -1;
  731. /* -------------------------------------------------------------------- */
  732. /* Do some checking to ensure we can add records to this file. */
  733. /* -------------------------------------------------------------------- */
  734. if( nWidth < 1 )
  735. return -1;
  736. if( nWidth > 255 )
  737. nWidth = 255;
  738. nOldRecordLength = psDBF->nRecordLength;
  739. nOldHeaderLength = psDBF->nHeaderLength;
  740. /* -------------------------------------------------------------------- */
  741. /* SfRealloc all the arrays larger to hold the additional field */
  742. /* information. */
  743. /* -------------------------------------------------------------------- */
  744. psDBF->nFields++;
  745. psDBF->panFieldOffset = (int *)
  746. SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
  747. psDBF->panFieldSize = (int *)
  748. SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
  749. psDBF->panFieldDecimals = (int *)
  750. SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
  751. psDBF->pachFieldType = (char *)
  752. SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
  753. /* -------------------------------------------------------------------- */
  754. /* Assign the new field information fields. */
  755. /* -------------------------------------------------------------------- */
  756. psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
  757. psDBF->nRecordLength += nWidth;
  758. psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
  759. psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
  760. psDBF->pachFieldType[psDBF->nFields-1] = chType;
  761. /* -------------------------------------------------------------------- */
  762. /* Extend the required header information. */
  763. /* -------------------------------------------------------------------- */
  764. psDBF->nHeaderLength += 32;
  765. psDBF->bUpdated = FALSE;
  766. psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
  767. pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
  768. for( i = 0; i < 32; i++ )
  769. pszFInfo[i] = '\0';
  770. if( (int) strlen(pszFieldName) < 10 )
  771. strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
  772. else
  773. strncpy( pszFInfo, pszFieldName, 10);
  774. pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
  775. if( chType == 'C' )
  776. {
  777. pszFInfo[16] = (unsigned char) (nWidth % 256);
  778. pszFInfo[17] = (unsigned char) (nWidth / 256);
  779. }
  780. else
  781. {
  782. pszFInfo[16] = (unsigned char) nWidth;
  783. pszFInfo[17] = (unsigned char) nDecimals;
  784. }
  785. /* -------------------------------------------------------------------- */
  786. /* Make the current record buffer appropriately larger. */
  787. /* -------------------------------------------------------------------- */
  788. psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
  789. psDBF->nRecordLength);
  790. /* we're done if dealing with new .dbf */
  791. if( psDBF->bNoHeader )
  792. return( psDBF->nFields - 1 );
  793. /* -------------------------------------------------------------------- */
  794. /* For existing .dbf file, shift records */
  795. /* -------------------------------------------------------------------- */
  796. /* alloc record */
  797. pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
  798. chFieldFill = DBFGetNullCharacter(chType);
  799. for (i = psDBF->nRecords-1; i >= 0; --i)
  800. {
  801. nRecordOffset = nOldRecordLength * (SAOffset) i + nOldHeaderLength;
  802. /* load record */
  803. psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
  804. psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
  805. /* set new field's value to NULL */
  806. memset(pszRecord + nOldRecordLength, chFieldFill, nWidth);
  807. nRecordOffset = psDBF->nRecordLength * (SAOffset) i + psDBF->nHeaderLength;
  808. /* move record to the new place*/
  809. psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
  810. psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
  811. }
  812. /* free record */
  813. free(pszRecord);
  814. /* force update of header with new header, record length and new field */
  815. psDBF->bNoHeader = TRUE;
  816. DBFUpdateHeader( psDBF );
  817. psDBF->nCurrentRecord = -1;
  818. psDBF->bCurrentRecordModified = FALSE;
  819. psDBF->bUpdated = TRUE;
  820. return( psDBF->nFields-1 );
  821. }
  822. /************************************************************************/
  823. /* DBFReadAttribute() */
  824. /* */
  825. /* Read one of the attribute fields of a record. */
  826. /************************************************************************/
  827. static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
  828. char chReqType )
  829. {
  830. unsigned char *pabyRec;
  831. void *pReturnField = NULL;
  832. /* -------------------------------------------------------------------- */
  833. /* Verify selection. */
  834. /* -------------------------------------------------------------------- */
  835. if( hEntity < 0 || hEntity >= psDBF->nRecords )
  836. return( NULL );
  837. if( iField < 0 || iField >= psDBF->nFields )
  838. return( NULL );
  839. /* -------------------------------------------------------------------- */
  840. /* Have we read the record? */
  841. /* -------------------------------------------------------------------- */
  842. if( !DBFLoadRecord( psDBF, hEntity ) )
  843. return NULL;
  844. pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
  845. /* -------------------------------------------------------------------- */
  846. /* Ensure we have room to extract the target field. */
  847. /* -------------------------------------------------------------------- */
  848. if( psDBF->panFieldSize[iField] >= psDBF->nWorkFieldLength )
  849. {
  850. psDBF->nWorkFieldLength = psDBF->panFieldSize[iField] + 100;
  851. if( psDBF->pszWorkField == NULL )
  852. psDBF->pszWorkField = (char *) malloc(psDBF->nWorkFieldLength);
  853. else
  854. psDBF->pszWorkField = (char *) realloc(psDBF->pszWorkField,
  855. psDBF->nWorkFieldLength);
  856. }
  857. /* -------------------------------------------------------------------- */
  858. /* Extract the requested field. */
  859. /* -------------------------------------------------------------------- */
  860. memcpy( psDBF->pszWorkField,
  861. ((const char *) pabyRec) + psDBF->panFieldOffset[iField],
  862. psDBF->panFieldSize[iField] );
  863. psDBF->pszWorkField[psDBF->panFieldSize[iField]] = '\0';
  864. pReturnField = psDBF->pszWorkField;
  865. /* -------------------------------------------------------------------- */
  866. /* Decode the field. */
  867. /* -------------------------------------------------------------------- */
  868. if( chReqType == 'I' )
  869. {
  870. psDBF->fieldValue.nIntField = atoi(psDBF->pszWorkField);
  871. pReturnField = &(psDBF->fieldValue.nIntField);
  872. }
  873. else if( chReqType == 'N' )
  874. {
  875. psDBF->fieldValue.dfDoubleField = psDBF->sHooks.Atof(psDBF->pszWorkField);
  876. pReturnField = &(psDBF->fieldValue.dfDoubleField);
  877. }
  878. /* -------------------------------------------------------------------- */
  879. /* Should we trim white space off the string attribute value? */
  880. /* -------------------------------------------------------------------- */
  881. #ifdef TRIM_DBF_WHITESPACE
  882. else
  883. {
  884. char *pchSrc, *pchDst;
  885. pchDst = pchSrc = psDBF->pszWorkField;
  886. while( *pchSrc == ' ' )
  887. pchSrc++;
  888. while( *pchSrc != '\0' )
  889. *(pchDst++) = *(pchSrc++);
  890. *pchDst = '\0';
  891. while( pchDst != psDBF->pszWorkField && *(--pchDst) == ' ' )
  892. *pchDst = '\0';
  893. }
  894. #endif
  895. return( pReturnField );
  896. }
  897. /************************************************************************/
  898. /* DBFReadIntAttribute() */
  899. /* */
  900. /* Read an integer attribute. */
  901. /************************************************************************/
  902. int SHPAPI_CALL
  903. DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
  904. {
  905. int *pnValue;
  906. pnValue = (int *) DBFReadAttribute( psDBF, iRecord, iField, 'I' );
  907. if( pnValue == NULL )
  908. return 0;
  909. else
  910. return( *pnValue );
  911. }
  912. /************************************************************************/
  913. /* DBFReadDoubleAttribute() */
  914. /* */
  915. /* Read a double attribute. */
  916. /************************************************************************/
  917. double SHPAPI_CALL
  918. DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
  919. {
  920. double *pdValue;
  921. pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
  922. if( pdValue == NULL )
  923. return 0.0;
  924. else
  925. return( *pdValue );
  926. }
  927. /************************************************************************/
  928. /* DBFReadStringAttribute() */
  929. /* */
  930. /* Read a string attribute. */
  931. /************************************************************************/
  932. const char SHPAPI_CALL1(*)
  933. DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
  934. {
  935. return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
  936. }
  937. /************************************************************************/
  938. /* DBFReadLogicalAttribute() */
  939. /* */
  940. /* Read a logical attribute. */
  941. /************************************************************************/
  942. const char SHPAPI_CALL1(*)
  943. DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
  944. {
  945. return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
  946. }
  947. /************************************************************************/
  948. /* DBFIsValueNULL() */
  949. /* */
  950. /* Return TRUE if the passed string is NULL. */
  951. /************************************************************************/
  952. static int DBFIsValueNULL( char chType, const char* pszValue )
  953. {
  954. int i;
  955. if( pszValue == NULL )
  956. return TRUE;
  957. switch(chType)
  958. {
  959. case 'N':
  960. case 'F':
  961. /*
  962. ** We accept all asterisks or all blanks as NULL
  963. ** though according to the spec I think it should be all
  964. ** asterisks.
  965. */
  966. if( pszValue[0] == '*' )
  967. return TRUE;
  968. for( i = 0; pszValue[i] != '\0'; i++ )
  969. {
  970. if( pszValue[i] != ' ' )
  971. return FALSE;
  972. }
  973. return TRUE;
  974. case 'D':
  975. /* NULL date fields have value "00000000" */
  976. return strncmp(pszValue,"00000000",8) == 0;
  977. case 'L':
  978. /* NULL boolean fields have value "?" */
  979. return pszValue[0] == '?';
  980. default:
  981. /* empty string fields are considered NULL */
  982. return strlen(pszValue) == 0;
  983. }
  984. }
  985. /************************************************************************/
  986. /* DBFIsAttributeNULL() */
  987. /* */
  988. /* Return TRUE if value for field is NULL. */
  989. /* */
  990. /* Contributed by Jim Matthews. */
  991. /************************************************************************/
  992. int SHPAPI_CALL
  993. DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
  994. {
  995. const char *pszValue;
  996. pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
  997. if( pszValue == NULL )
  998. return TRUE;
  999. return DBFIsValueNULL( psDBF->pachFieldType[iField], pszValue );
  1000. }
  1001. /************************************************************************/
  1002. /* DBFGetFieldCount() */
  1003. /* */
  1004. /* Return the number of fields in this table. */
  1005. /************************************************************************/
  1006. int SHPAPI_CALL
  1007. DBFGetFieldCount( DBFHandle psDBF )
  1008. {
  1009. return( psDBF->nFields );
  1010. }
  1011. /************************************************************************/
  1012. /* DBFGetRecordCount() */
  1013. /* */
  1014. /* Return the number of records in this table. */
  1015. /************************************************************************/
  1016. int SHPAPI_CALL
  1017. DBFGetRecordCount( DBFHandle psDBF )
  1018. {
  1019. return( psDBF->nRecords );
  1020. }
  1021. /************************************************************************/
  1022. /* DBFGetFieldInfo() */
  1023. /* */
  1024. /* Return any requested information about the field. */
  1025. /************************************************************************/
  1026. DBFFieldType SHPAPI_CALL
  1027. DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
  1028. int * pnWidth, int * pnDecimals )
  1029. {
  1030. if( iField < 0 || iField >= psDBF->nFields )
  1031. return( FTInvalid );
  1032. if( pnWidth != NULL )
  1033. *pnWidth = psDBF->panFieldSize[iField];
  1034. if( pnDecimals != NULL )
  1035. *pnDecimals = psDBF->panFieldDecimals[iField];
  1036. if( pszFieldName != NULL )
  1037. {
  1038. int i;
  1039. strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
  1040. pszFieldName[11] = '\0';
  1041. for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
  1042. pszFieldName[i] = '\0';
  1043. }
  1044. if ( psDBF->pachFieldType[iField] == 'L' )
  1045. return( FTLogical);
  1046. else if( psDBF->pachFieldType[iField] == 'N'
  1047. || psDBF->pachFieldType[iField] == 'F' )
  1048. {
  1049. if( psDBF->panFieldDecimals[iField] > 0 )
  1050. /* || psDBF->panFieldSize[iField] >= 10 ) */ /* GDAL bug #809 */
  1051. return( FTDouble );
  1052. else
  1053. return( FTInteger );
  1054. }
  1055. else
  1056. {
  1057. return( FTString );
  1058. }
  1059. }
  1060. /************************************************************************/
  1061. /* DBFWriteAttribute() */
  1062. /* */
  1063. /* Write an attribute record to the file. */
  1064. /************************************************************************/
  1065. static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
  1066. void * pValue )
  1067. {
  1068. int i, j, nRetResult = TRUE;
  1069. unsigned char *pabyRec;
  1070. char szSField[400], szFormat[20];
  1071. /* -------------------------------------------------------------------- */
  1072. /* Is this a valid record? */
  1073. /* -------------------------------------------------------------------- */
  1074. if( hEntity < 0 || hEntity > psDBF->nRecords )
  1075. return( FALSE );
  1076. if( psDBF->bNoHeader )
  1077. DBFWriteHeader(psDBF);
  1078. /* -------------------------------------------------------------------- */
  1079. /* Is this a brand new record? */
  1080. /* -------------------------------------------------------------------- */
  1081. if( hEntity == psDBF->nRecords )
  1082. {
  1083. if( !DBFFlushRecord( psDBF ) )
  1084. return FALSE;
  1085. psDBF->nRecords++;
  1086. for( i = 0; i < psDBF->nRecordLength; i++ )
  1087. psDBF->pszCurrentRecord[i] = ' ';
  1088. psDBF->nCurrentRecord = hEntity;
  1089. }
  1090. /* -------------------------------------------------------------------- */
  1091. /* Is this an existing record, but different than the last one */
  1092. /* we accessed? */
  1093. /* -------------------------------------------------------------------- */
  1094. if( !DBFLoadRecord( psDBF, hEntity ) )
  1095. return FALSE;
  1096. pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
  1097. psDBF->bCurrentRecordModified = TRUE;
  1098. psDBF->bUpdated = TRUE;
  1099. /* -------------------------------------------------------------------- */
  1100. /* Translate NULL value to valid DBF file representation. */
  1101. /* */
  1102. /* Contributed by Jim Matthews. */
  1103. /* -------------------------------------------------------------------- */
  1104. if( pValue == NULL )
  1105. {
  1106. memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]),
  1107. DBFGetNullCharacter(psDBF->pachFieldType[iField]),
  1108. psDBF->panFieldSize[iField] );
  1109. return TRUE;
  1110. }
  1111. /* -------------------------------------------------------------------- */
  1112. /* Assign all the record fields. */
  1113. /* -------------------------------------------------------------------- */
  1114. switch( psDBF->pachFieldType[iField] )
  1115. {
  1116. case 'D':
  1117. case 'N':
  1118. case 'F':
  1119. {
  1120. int nWidth = psDBF->panFieldSize[iField];
  1121. if( (int) sizeof(szSField)-2 < nWidth )
  1122. nWidth = sizeof(szSField)-2;
  1123. snprintf( szFormat, sizeof(szFormat), "%%%d.%df",
  1124. nWidth, psDBF->panFieldDecimals[iField] );
  1125. snprintf(szSField, sizeof(szSField), szFormat, *((double *) pValue) );
  1126. if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
  1127. {
  1128. szSField[psDBF->panFieldSize[iField]] = '\0';
  1129. nRetResult = FALSE;
  1130. }
  1131. strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
  1132. szSField, strlen(szSField) );
  1133. break;
  1134. }
  1135. case 'L':
  1136. if (psDBF->panFieldSize[iField] >= 1 &&
  1137. (*(char*)pValue == 'F' || *(char*)pValue == 'T'))
  1138. *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
  1139. break;
  1140. default:
  1141. if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
  1142. {
  1143. j = psDBF->panFieldSize[iField];
  1144. nRetResult = FALSE;
  1145. }
  1146. else
  1147. {
  1148. memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
  1149. psDBF->panFieldSize[iField] );
  1150. j = (int)strlen((char *) pValue);
  1151. }
  1152. strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
  1153. (char *) pValue, j );
  1154. break;
  1155. }
  1156. return( nRetResult );
  1157. }
  1158. /************************************************************************/
  1159. /* DBFWriteAttributeDirectly() */
  1160. /* */
  1161. /* Write an attribute record to the file, but without any */
  1162. /* reformatting based on type. The provided buffer is written */
  1163. /* as is to the field position in the record. */
  1164. /************************************************************************/
  1165. int SHPAPI_CALL
  1166. DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
  1167. void * pValue )
  1168. {
  1169. int i, j;
  1170. unsigned char *pabyRec;
  1171. /* -------------------------------------------------------------------- */
  1172. /* Is this a valid record? */
  1173. /* -------------------------------------------------------------------- */
  1174. if( hEntity < 0 || hEntity > psDBF->nRecords )
  1175. return( FALSE );
  1176. if( psDBF->bNoHeader )
  1177. DBFWriteHeader(psDBF);
  1178. /* -------------------------------------------------------------------- */
  1179. /* Is this a brand new record? */
  1180. /* -------------------------------------------------------------------- */
  1181. if( hEntity == psDBF->nRecords )
  1182. {
  1183. if( !DBFFlushRecord( psDBF ) )
  1184. return FALSE;
  1185. psDBF->nRecords++;
  1186. for( i = 0; i < psDBF->nRecordLength; i++ )
  1187. psDBF->pszCurrentRecord[i] = ' ';
  1188. psDBF->nCurrentRecord = hEntity;
  1189. }
  1190. /* -------------------------------------------------------------------- */
  1191. /* Is this an existing record, but different than the last one */
  1192. /* we accessed? */
  1193. /* -------------------------------------------------------------------- */
  1194. if( !DBFLoadRecord( psDBF, hEntity ) )
  1195. return FALSE;
  1196. pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
  1197. /* -------------------------------------------------------------------- */
  1198. /* Assign all the record fields. */
  1199. /* -------------------------------------------------------------------- */
  1200. if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] )
  1201. j = psDBF->panFieldSize[iField];
  1202. else
  1203. {
  1204. memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
  1205. psDBF->panFieldSize[iField] );
  1206. j = (int)strlen((char *) pValue);
  1207. }
  1208. strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
  1209. (char *) pValue, j );
  1210. psDBF->bCurrentRecordModified = TRUE;
  1211. psDBF->bUpdated = TRUE;
  1212. return( TRUE );
  1213. }
  1214. /************************************************************************/
  1215. /* DBFWriteDoubleAttribute() */
  1216. /* */
  1217. /* Write a double attribute. */
  1218. /************************************************************************/
  1219. int SHPAPI_CALL
  1220. DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
  1221. double dValue )
  1222. {
  1223. return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
  1224. }
  1225. /************************************************************************/
  1226. /* DBFWriteIntegerAttribute() */
  1227. /* */
  1228. /* Write a integer attribute. */
  1229. /************************************************************************/
  1230. int SHPAPI_CALL
  1231. DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
  1232. int nValue )
  1233. {
  1234. double dValue = nValue;
  1235. return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
  1236. }
  1237. /************************************************************************/
  1238. /* DBFWriteStringAttribute() */
  1239. /* */
  1240. /* Write a string attribute. */
  1241. /************************************************************************/
  1242. int SHPAPI_CALL
  1243. DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
  1244. const char * pszValue )
  1245. {
  1246. return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) );
  1247. }
  1248. /************************************************************************/
  1249. /* DBFWriteNULLAttribute() */
  1250. /* */
  1251. /* Write a string attribute. */
  1252. /************************************************************************/
  1253. int SHPAPI_CALL
  1254. DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
  1255. {
  1256. return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );
  1257. }
  1258. /************************************************************************/
  1259. /* DBFWriteLogicalAttribute() */
  1260. /* */
  1261. /* Write a logical attribute. */
  1262. /************************************************************************/
  1263. int SHPAPI_CALL
  1264. DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
  1265. const char lValue)
  1266. {
  1267. return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );
  1268. }
  1269. /************************************************************************/
  1270. /* DBFWriteTuple() */
  1271. /* */
  1272. /* Write an attribute record to the file. */
  1273. /************************************************************************/
  1274. int SHPAPI_CALL
  1275. DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
  1276. {
  1277. int i;
  1278. unsigned char *pabyRec;
  1279. /* -------------------------------------------------------------------- */
  1280. /* Is this a valid record? */
  1281. /* -------------------------------------------------------------------- */
  1282. if( hEntity < 0 || hEntity > psDBF->nRecords )
  1283. return( FALSE );
  1284. if( psDBF->bNoHeader )
  1285. DBFWriteHeader(psDBF);
  1286. /* -------------------------------------------------------------------- */
  1287. /* Is this a brand new record? */
  1288. /* -------------------------------------------------------------------- */
  1289. if( hEntity == psDBF->nRecords )
  1290. {
  1291. if( !DBFFlushRecord( psDBF ) )
  1292. return FALSE;
  1293. psDBF->nRecords++;
  1294. for( i = 0; i < psDBF->nRecordLength; i++ )
  1295. psDBF->pszCurrentRecord[i] = ' ';
  1296. psDBF->nCurrentRecord = hEntity;
  1297. }
  1298. /* -------------------------------------------------------------------- */
  1299. /* Is this an existing record, but different than the last one */
  1300. /* we accessed? */
  1301. /* -------------------------------------------------------------------- */
  1302. if( !DBFLoadRecord( psDBF, hEntity ) )
  1303. return FALSE;
  1304. pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
  1305. memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength );
  1306. psDBF->bCurrentRecordModified = TRUE;
  1307. psDBF->bUpdated = TRUE;
  1308. return( TRUE );
  1309. }
  1310. /************************************************************************/
  1311. /* DBFReadTuple() */
  1312. /* */
  1313. /* Read a complete record. Note that the result is only valid */
  1314. /* till the next record read for any reason. */
  1315. /************************************************************************/
  1316. const char SHPAPI_CALL1(*)
  1317. DBFReadTuple(DBFHandle psDBF, int hEntity )
  1318. {
  1319. if( hEntity < 0 || hEntity >= psDBF->nRecords )
  1320. return( NULL );
  1321. if( !DBFLoadRecord( psDBF, hEntity ) )
  1322. return NULL;
  1323. return (const char *) psDBF->pszCurrentRecord;
  1324. }
  1325. /************************************************************************/
  1326. /* DBFCloneEmpty() */
  1327. /* */
  1328. /* Read one of the attribute fields of a record. */
  1329. /************************************************************************/
  1330. DBFHandle SHPAPI_CALL
  1331. DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
  1332. {
  1333. DBFHandle newDBF;
  1334. newDBF = DBFCreateEx ( pszFilename, psDBF->pszCodePage );
  1335. if ( newDBF == NULL ) return ( NULL );
  1336. newDBF->nFields = psDBF->nFields;
  1337. newDBF->nRecordLength = psDBF->nRecordLength;
  1338. newDBF->nHeaderLength = psDBF->nHeaderLength;
  1339. if( psDBF->pszHeader )
  1340. {
  1341. newDBF->pszHeader = (char *) malloc ( XBASE_FLDHDR_SZ * psDBF->nFields );
  1342. memcpy ( newDBF->pszHeader, psDBF->pszHeader, XBASE_FLDHDR_SZ * psDBF->nFields );
  1343. }
  1344. newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields );
  1345. memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
  1346. newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
  1347. memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
  1348. newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
  1349. memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
  1350. newDBF->pachFieldType = (char *) malloc ( sizeof(char) * psDBF->nFields );
  1351. memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(char)*psDBF->nFields );
  1352. newDBF->bNoHeader = TRUE;
  1353. newDBF->bUpdated = TRUE;
  1354. DBFWriteHeader ( newDBF );
  1355. DBFClose ( newDBF );
  1356. newDBF = DBFOpen ( pszFilename, "rb+" );
  1357. return ( newDBF );
  1358. }
  1359. /************************************************************************/
  1360. /* DBFGetNativeFieldType() */
  1361. /* */
  1362. /* Return the DBase field type for the specified field. */
  1363. /* */
  1364. /* Value can be one of: 'C' (String), 'D' (Date), 'F' (Float), */
  1365. /* 'N' (Numeric, with or without decimal), */
  1366. /* 'L' (Logical), */
  1367. /* 'M' (Memo: 10 digits .DBT block ptr) */
  1368. /************************************************************************/
  1369. char SHPAPI_CALL
  1370. DBFGetNativeFieldType( DBFHandle psDBF, int iField )
  1371. {
  1372. if( iField >=0 && iField < psDBF->nFields )
  1373. return psDBF->pachFieldType[iField];
  1374. return ' ';
  1375. }
  1376. /************************************************************************/
  1377. /* str_to_upper() */
  1378. /************************************************************************/
  1379. static void str_to_upper (char *string)
  1380. {
  1381. int len;
  1382. int i = -1;
  1383. len = (int)strlen (string);
  1384. while (++i < len)
  1385. if (isalpha(string[i]) && islower(string[i]))
  1386. string[i] = (char) toupper ((int)string[i]);
  1387. }
  1388. /************************************************************************/
  1389. /* DBFGetFieldIndex() */
  1390. /* */
  1391. /* Get the index number for a field in a .dbf file. */
  1392. /* */
  1393. /* Contributed by Jim Matthews. */
  1394. /************************************************************************/
  1395. int SHPAPI_CALL
  1396. DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
  1397. {
  1398. char name[12], name1[12], name2[12];
  1399. int i;
  1400. strncpy(name1, pszFieldName,11);
  1401. name1[11] = '\0';
  1402. str_to_upper(name1);
  1403. for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
  1404. {
  1405. DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
  1406. strncpy(name2,name,11);
  1407. str_to_upper(name2);
  1408. if(!strncmp(name1,name2,10))
  1409. return(i);
  1410. }
  1411. return(-1);
  1412. }
  1413. /************************************************************************/
  1414. /* DBFIsRecordDeleted() */
  1415. /* */
  1416. /* Returns TRUE if the indicated record is deleted, otherwise */
  1417. /* it returns FALSE. */
  1418. /************************************************************************/
  1419. int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape )
  1420. {
  1421. /* -------------------------------------------------------------------- */
  1422. /* Verify selection. */
  1423. /* -------------------------------------------------------------------- */
  1424. if( iShape < 0 || iShape >= psDBF->nRecords )
  1425. return TRUE;
  1426. /* -------------------------------------------------------------------- */
  1427. /* Have we read the record? */
  1428. /* -------------------------------------------------------------------- */
  1429. if( !DBFLoadRecord( psDBF, iShape ) )
  1430. return FALSE;
  1431. /* -------------------------------------------------------------------- */
  1432. /* '*' means deleted. */
  1433. /* -------------------------------------------------------------------- */
  1434. return psDBF->pszCurrentRecord[0] == '*';
  1435. }
  1436. /************************************************************************/
  1437. /* DBFMarkRecordDeleted() */
  1438. /************************************************************************/
  1439. int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape,
  1440. int bIsDeleted )
  1441. {
  1442. char chNewFlag;
  1443. /* -------------------------------------------------------------------- */
  1444. /* Verify selection. */
  1445. /* -------------------------------------------------------------------- */
  1446. if( iShape < 0 || iShape >= psDBF->nRecords )
  1447. return FALSE;
  1448. /* -------------------------------------------------------------------- */
  1449. /* Is this an existing record, but different than the last one */
  1450. /* we accessed? */
  1451. /* -------------------------------------------------------------------- */
  1452. if( !DBFLoadRecord( psDBF, iShape ) )
  1453. return FALSE;
  1454. /* -------------------------------------------------------------------- */
  1455. /* Assign value, marking record as dirty if it changes. */
  1456. /* -------------------------------------------------------------------- */
  1457. if( bIsDeleted )
  1458. chNewFlag = '*';
  1459. else
  1460. chNewFlag = ' ';
  1461. if( psDBF->pszCurrentRecord[0] != chNewFlag )
  1462. {
  1463. psDBF->bCurrentRecordModified = TRUE;
  1464. psDBF->bUpdated = TRUE;
  1465. psDBF->pszCurrentRecord[0] = chNewFlag;
  1466. }
  1467. return TRUE;
  1468. }
  1469. /************************************************************************/
  1470. /* DBFGetCodePage */
  1471. /************************************************************************/
  1472. const char SHPAPI_CALL1(*)
  1473. DBFGetCodePage(DBFHandle psDBF )
  1474. {
  1475. if( psDBF == NULL )
  1476. return NULL;
  1477. return psDBF->pszCodePage;
  1478. }
  1479. /************************************************************************/
  1480. /* DBFDeleteField() */
  1481. /* */
  1482. /* Remove a field from a .dbf file */
  1483. /************************************************************************/
  1484. int SHPAPI_CALL
  1485. DBFDeleteField(DBFHandle psDBF, int iField)
  1486. {
  1487. int nOldRecordLength, nOldHeaderLength;
  1488. int nDeletedFieldOffset, nDeletedFieldSize;
  1489. SAOffset nRecordOffset;
  1490. char* pszRecord;
  1491. int i, iRecord;
  1492. if (iField < 0 || iField >= psDBF->nFields)
  1493. return FALSE;
  1494. /* make sure that everything is written in .dbf */
  1495. if( !DBFFlushRecord( psDBF ) )
  1496. return FALSE;
  1497. /* get information about field to be deleted */
  1498. nOldRecordLength = psDBF->nRecordLength;
  1499. nOldHeaderLength = psDBF->nHeaderLength;
  1500. nDeletedFieldOffset = psDBF->panFieldOffset[iField];
  1501. nDeletedFieldSize = psDBF->panFieldSize[iField];
  1502. /* update fields info */
  1503. for (i = iField + 1; i < psDBF->nFields; i++)
  1504. {
  1505. psDBF->panFieldOffset[i-1] = psDBF->panFieldOffset[i] - nDeletedFieldSize;
  1506. psDBF->panFieldSize[i-1] = psDBF->panFieldSize[i];
  1507. psDBF->panFieldDecimals[i-1] = psDBF->panFieldDecimals[i];
  1508. psDBF->pachFieldType[i-1] = psDBF->pachFieldType[i];
  1509. }
  1510. /* resize fields arrays */
  1511. psDBF->nFields--;
  1512. psDBF->panFieldOffset = (int *)
  1513. SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
  1514. psDBF->panFieldSize = (int *)
  1515. SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
  1516. psDBF->panFieldDecimals = (int *)
  1517. SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
  1518. psDBF->pachFieldType = (char *)
  1519. SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
  1520. /* update header information */
  1521. psDBF->nHeaderLength -= 32;
  1522. psDBF->nRecordLength -= nDeletedFieldSize;
  1523. /* overwrite field information in header */
  1524. memmove(psDBF->pszHeader + iField*32,
  1525. psDBF->pszHeader + (iField+1)*32,
  1526. sizeof(char) * (psDBF->nFields - iField)*32);
  1527. psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
  1528. /* update size of current record appropriately */
  1529. psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
  1530. psDBF->nRecordLength);
  1531. /* we're done if we're dealing with not yet created .dbf */
  1532. if ( psDBF->bNoHeader && psDBF->nRecords == 0 )
  1533. return TRUE;
  1534. /* force update of header with new header and record length */
  1535. psDBF->bNoHeader = TRUE;
  1536. DBFUpdateHeader( psDBF );
  1537. /* alloc record */
  1538. pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength);
  1539. /* shift records to their new positions */
  1540. for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
  1541. {
  1542. nRecordOffset =
  1543. nOldRecordLength * (SAOffset) iRecord + nOldHeaderLength;
  1544. /* load record */
  1545. psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
  1546. psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
  1547. nRecordOffset =
  1548. psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
  1549. /* move record in two steps */
  1550. psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
  1551. psDBF->sHooks.FWrite( pszRecord, nDeletedFieldOffset, 1, psDBF->fp );
  1552. psDBF->sHooks.FWrite( pszRecord + nDeletedFieldOffset + nDeletedFieldSize,
  1553. nOldRecordLength - nDeletedFieldOffset - nDeletedFieldSize,
  1554. 1, psDBF->fp );
  1555. }
  1556. /* TODO: truncate file */
  1557. /* free record */
  1558. free(pszRecord);
  1559. psDBF->nCurrentRecord = -1;
  1560. psDBF->bCurrentRecordModified = FALSE;
  1561. psDBF->bUpdated = TRUE;
  1562. return TRUE;
  1563. }
  1564. /************************************************************************/
  1565. /* DBFReorderFields() */
  1566. /* */
  1567. /* Reorder the fields of a .dbf file */
  1568. /* */
  1569. /* panMap must be exactly psDBF->nFields long and be a permutation */
  1570. /* of [0, psDBF->nFields-1]. This assumption will not be asserted in the*/
  1571. /* code of DBFReorderFields. */
  1572. /************************************************************************/
  1573. int SHPAPI_CALL
  1574. DBFReorderFields( DBFHandle psDBF, int* panMap )
  1575. {
  1576. SAOffset nRecordOffset;
  1577. int i, iRecord;
  1578. int *panFieldOffsetNew;
  1579. int *panFieldSizeNew;
  1580. int *panFieldDecimalsNew;
  1581. char *pachFieldTypeNew;
  1582. char *pszHeaderNew;
  1583. char *pszRecord;
  1584. char *pszRecordNew;
  1585. if ( psDBF->nFields == 0 )
  1586. return TRUE;
  1587. /* make sure that everything is written in .dbf */
  1588. if( !DBFFlushRecord( psDBF ) )
  1589. return FALSE;
  1590. /* a simple malloc() would be enough, but calloc() helps clang static analyzer */
  1591. panFieldOffsetNew = (int *) calloc(sizeof(int), psDBF->nFields);
  1592. panFieldSizeNew = (int *) malloc(sizeof(int) * psDBF->nFields);
  1593. panFieldDecimalsNew = (int *) malloc(sizeof(int) * psDBF->nFields);
  1594. pachFieldTypeNew = (char *) malloc(sizeof(char) * psDBF->nFields);
  1595. pszHeaderNew = (char*) malloc(sizeof(char) * 32 * psDBF->nFields);
  1596. /* shuffle fields definitions */
  1597. for(i=0; i < psDBF->nFields; i++)
  1598. {
  1599. panFieldSizeNew[i] = psDBF->panFieldSize[panMap[i]];
  1600. panFieldDecimalsNew[i] = psDBF->panFieldDecimals[panMap[i]];
  1601. pachFieldTypeNew[i] = psDBF->pachFieldType[panMap[i]];
  1602. memcpy(pszHeaderNew + i * 32,
  1603. psDBF->pszHeader + panMap[i] * 32, 32);
  1604. }
  1605. panFieldOffsetNew[0] = 1;
  1606. for(i=1; i < psDBF->nFields; i++)
  1607. {
  1608. panFieldOffsetNew[i] = panFieldOffsetNew[i - 1] + panFieldSizeNew[i - 1];
  1609. }
  1610. free(psDBF->pszHeader);
  1611. psDBF->pszHeader = pszHeaderNew;
  1612. /* we're done if we're dealing with not yet created .dbf */
  1613. if ( !(psDBF->bNoHeader && psDBF->nRecords == 0) )
  1614. {
  1615. /* force update of header with new header and record length */
  1616. psDBF->bNoHeader = TRUE;
  1617. DBFUpdateHeader( psDBF );
  1618. /* alloc record */
  1619. pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
  1620. pszRecordNew = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
  1621. /* shuffle fields in records */
  1622. for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
  1623. {
  1624. nRecordOffset =
  1625. psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
  1626. /* load record */
  1627. psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
  1628. psDBF->sHooks.FRead( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
  1629. pszRecordNew[0] = pszRecord[0];
  1630. for(i=0; i < psDBF->nFields; i++)
  1631. {
  1632. memcpy(pszRecordNew + panFieldOffsetNew[i],
  1633. pszRecord + psDBF->panFieldOffset[panMap[i]],
  1634. psDBF->panFieldSize[panMap[i]]);
  1635. }
  1636. /* write record */
  1637. psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
  1638. psDBF->sHooks.FWrite( pszRecordNew, psDBF->nRecordLength, 1, psDBF->fp );
  1639. }
  1640. /* free record */
  1641. free(pszRecord);
  1642. free(pszRecordNew);
  1643. }
  1644. free(psDBF->panFieldOffset);
  1645. free(psDBF->panFieldSize);
  1646. free(psDBF->panFieldDecimals);
  1647. free(psDBF->pachFieldType);
  1648. psDBF->panFieldOffset = panFieldOffsetNew;
  1649. psDBF->panFieldSize = panFieldSizeNew;
  1650. psDBF->panFieldDecimals =panFieldDecimalsNew;
  1651. psDBF->pachFieldType = pachFieldTypeNew;
  1652. psDBF->nCurrentRecord = -1;
  1653. psDBF->bCurrentRecordModified = FALSE;
  1654. psDBF->bUpdated = TRUE;
  1655. return TRUE;
  1656. }
  1657. /************************************************************************/
  1658. /* DBFAlterFieldDefn() */
  1659. /* */
  1660. /* Alter a field definition in a .dbf file */
  1661. /************************************************************************/
  1662. int SHPAPI_CALL
  1663. DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
  1664. char chType, int nWidth, int nDecimals )
  1665. {
  1666. int i;
  1667. int iRecord;
  1668. int nOffset;
  1669. int nOldWidth;
  1670. int nOldRecordLength;
  1671. SAOffset nRecordOffset;
  1672. char* pszFInfo;
  1673. char chOldType;
  1674. int bIsNULL;
  1675. char chFieldFill;
  1676. if (iField < 0 || iField >= psDBF->nFields)
  1677. return FALSE;
  1678. /* make sure that everything is written in .dbf */
  1679. if( !DBFFlushRecord( psDBF ) )
  1680. return FALSE;
  1681. chFieldFill = DBFGetNullCharacter(chType);
  1682. chOldType = psDBF->pachFieldType[iField];
  1683. nOffset = psDBF->panFieldOffset[iField];
  1684. nOldWidth = psDBF->panFieldSize[iField];
  1685. nOldRecordLength = psDBF->nRecordLength;
  1686. /* -------------------------------------------------------------------- */
  1687. /* Do some checking to ensure we can add records to this file. */
  1688. /* -------------------------------------------------------------------- */
  1689. if( nWidth < 1 )
  1690. return -1;
  1691. if( nWidth > 255 )
  1692. nWidth = 255;
  1693. /* -------------------------------------------------------------------- */
  1694. /* Assign the new field information fields. */
  1695. /* -------------------------------------------------------------------- */
  1696. psDBF->panFieldSize[iField] = nWidth;
  1697. psDBF->panFieldDecimals[iField] = nDecimals;
  1698. psDBF->pachFieldType[iField] = chType;
  1699. /* -------------------------------------------------------------------- */
  1700. /* Update the header information. */
  1701. /* -------------------------------------------------------------------- */
  1702. pszFInfo = psDBF->pszHeader + 32 * iField;
  1703. for( i = 0; i < 32; i++ )
  1704. pszFInfo[i] = '\0';
  1705. if( (int) strlen(pszFieldName) < 10 )
  1706. strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
  1707. else
  1708. strncpy( pszFInfo, pszFieldName, 10);
  1709. pszFInfo[11] = psDBF->pachFieldType[iField];
  1710. if( chType == 'C' )
  1711. {
  1712. pszFInfo[16] = (unsigned char) (nWidth % 256);
  1713. pszFInfo[17] = (unsigned char) (nWidth / 256);
  1714. }
  1715. else
  1716. {
  1717. pszFInfo[16] = (unsigned char) nWidth;
  1718. pszFInfo[17] = (unsigned char) nDecimals;
  1719. }
  1720. /* -------------------------------------------------------------------- */
  1721. /* Update offsets */
  1722. /* -------------------------------------------------------------------- */
  1723. if (nWidth != nOldWidth)
  1724. {
  1725. for (i = iField + 1; i < psDBF->nFields; i++)
  1726. psDBF->panFieldOffset[i] += nWidth - nOldWidth;
  1727. psDBF->nRecordLength += nWidth - nOldWidth;
  1728. psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
  1729. psDBF->nRecordLength);
  1730. }
  1731. /* we're done if we're dealing with not yet created .dbf */
  1732. if ( psDBF->bNoHeader && psDBF->nRecords == 0 )
  1733. return TRUE;
  1734. /* force update of header with new header and record length */
  1735. psDBF->bNoHeader = TRUE;
  1736. DBFUpdateHeader( psDBF );
  1737. if (nWidth < nOldWidth || (nWidth == nOldWidth && chType != chOldType))
  1738. {
  1739. char* pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength);
  1740. char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
  1741. pszOldField[nOldWidth] = 0;
  1742. /* move records to their new positions */
  1743. for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
  1744. {
  1745. nRecordOffset =
  1746. nOldRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
  1747. /* load record */
  1748. psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
  1749. psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
  1750. memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
  1751. bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
  1752. if (nWidth != nOldWidth)
  1753. {
  1754. if ((chOldType == 'N' || chOldType == 'F') && pszOldField[0] == ' ')
  1755. {
  1756. /* Strip leading spaces when truncating a numeric field */
  1757. memmove( pszRecord + nOffset,
  1758. pszRecord + nOffset + nOldWidth - nWidth,
  1759. nWidth );
  1760. }
  1761. if (nOffset + nOldWidth < nOldRecordLength)
  1762. {
  1763. memmove( pszRecord + nOffset + nWidth,
  1764. pszRecord + nOffset + nOldWidth,
  1765. nOldRecordLength - (nOffset + nOldWidth));
  1766. }
  1767. }
  1768. /* Convert null value to the appropriate value of the new type */
  1769. if (bIsNULL)
  1770. {
  1771. memset( pszRecord + nOffset, chFieldFill, nWidth);
  1772. }
  1773. nRecordOffset =
  1774. psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
  1775. /* write record */
  1776. psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
  1777. psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
  1778. }
  1779. free(pszRecord);
  1780. free(pszOldField);
  1781. }
  1782. else if (nWidth > nOldWidth)
  1783. {
  1784. char* pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
  1785. char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
  1786. pszOldField[nOldWidth] = 0;
  1787. /* move records to their new positions */
  1788. for (iRecord = psDBF->nRecords - 1; iRecord >= 0; iRecord--)
  1789. {
  1790. nRecordOffset =
  1791. nOldRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
  1792. /* load record */
  1793. psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
  1794. psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
  1795. memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
  1796. bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
  1797. if (nOffset + nOldWidth < nOldRecordLength)
  1798. {
  1799. memmove( pszRecord + nOffset + nWidth,
  1800. pszRecord + nOffset + nOldWidth,
  1801. nOldRecordLength - (nOffset + nOldWidth));
  1802. }
  1803. /* Convert null value to the appropriate value of the new type */
  1804. if (bIsNULL)
  1805. {
  1806. memset( pszRecord + nOffset, chFieldFill, nWidth);
  1807. }
  1808. else
  1809. {
  1810. if ((chOldType == 'N' || chOldType == 'F'))
  1811. {
  1812. /* Add leading spaces when expanding a numeric field */
  1813. memmove( pszRecord + nOffset + nWidth - nOldWidth,
  1814. pszRecord + nOffset, nOldWidth );
  1815. memset( pszRecord + nOffset, ' ', nWidth - nOldWidth );
  1816. }
  1817. else
  1818. {
  1819. /* Add trailing spaces */
  1820. memset(pszRecord + nOffset + nOldWidth, ' ', nWidth - nOldWidth);
  1821. }
  1822. }
  1823. nRecordOffset =
  1824. psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
  1825. /* write record */
  1826. psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
  1827. psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
  1828. }
  1829. free(pszRecord);
  1830. free(pszOldField);
  1831. }
  1832. psDBF->nCurrentRecord = -1;
  1833. psDBF->bCurrentRecordModified = FALSE;
  1834. psDBF->bUpdated = TRUE;
  1835. return TRUE;
  1836. }