dbfopen.c 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576
  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. *
  11. * This software is available under the following "MIT Style" license,
  12. * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
  13. * option is discussed in more detail in shapelib.html.
  14. *
  15. * --
  16. *
  17. * Permission is hereby granted, free of charge, to any person obtaining a
  18. * copy of this software and associated documentation files (the "Software"),
  19. * to deal in the Software without restriction, including without limitation
  20. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  21. * and/or sell copies of the Software, and to permit persons to whom the
  22. * Software is furnished to do so, subject to the following conditions:
  23. *
  24. * The above copyright notice and this permission notice shall be included
  25. * in all copies or substantial portions of the Software.
  26. *
  27. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  28. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  29. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  30. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  31. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  32. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  33. * DEALINGS IN THE SOFTWARE.
  34. ******************************************************************************
  35. *
  36. * $Log: dbfopen.c,v $
  37. * Revision 1.74 2007/12/06 07:00:25 fwarmerdam
  38. * dbfopen now using SAHooks for fileio
  39. *
  40. * Revision 1.73 2007/09/03 19:48:11 fwarmerdam
  41. * move DBFReadAttribute() static dDoubleField into dbfinfo
  42. *
  43. * Revision 1.72 2007/09/03 19:34:06 fwarmerdam
  44. * Avoid use of static tuple buffer in DBFReadTuple()
  45. *
  46. * Revision 1.71 2006/06/22 14:37:18 fwarmerdam
  47. * avoid memory leak if dbfopen fread fails
  48. *
  49. * Revision 1.70 2006/06/17 17:47:05 fwarmerdam
  50. * use calloc() for dbfinfo in DBFCreate
  51. *
  52. * Revision 1.69 2006/06/17 15:34:32 fwarmerdam
  53. * disallow creating fields wider than 255
  54. *
  55. * Revision 1.68 2006/06/17 15:12:40 fwarmerdam
  56. * Fixed C++ style comments.
  57. *
  58. * Revision 1.67 2006/06/17 00:24:53 fwarmerdam
  59. * Don't treat non-zero decimals values as high order byte for length
  60. * for strings. It causes serious corruption for some files.
  61. * http://bugzilla.remotesensing.org/show_bug.cgi?id=1202
  62. *
  63. * Revision 1.66 2006/03/29 18:26:20 fwarmerdam
  64. * fixed bug with size of pachfieldtype in dbfcloneempty
  65. *
  66. * Revision 1.65 2006/02/15 01:14:30 fwarmerdam
  67. * added DBFAddNativeFieldType
  68. *
  69. * Revision 1.64 2006/02/09 00:29:04 fwarmerdam
  70. * Changed to put spaces into string fields that are NULL as
  71. * per http://bugzilla.maptools.org/show_bug.cgi?id=316.
  72. *
  73. * Revision 1.63 2006/01/25 15:35:43 fwarmerdam
  74. * check success on DBFFlushRecord
  75. *
  76. * Revision 1.62 2006/01/10 16:28:03 fwarmerdam
  77. * Fixed typo in CPLError.
  78. *
  79. * Revision 1.61 2006/01/10 16:26:29 fwarmerdam
  80. * Push loading record buffer into DBFLoadRecord.
  81. * Implement CPL error reporting if USE_CPL defined.
  82. *
  83. * Revision 1.60 2006/01/05 01:27:27 fwarmerdam
  84. * added dbf deletion mark/fetch
  85. *
  86. * Revision 1.59 2005/03/14 15:20:28 fwarmerdam
  87. * Fixed last change.
  88. *
  89. * Revision 1.58 2005/03/14 15:18:54 fwarmerdam
  90. * Treat very wide fields with no decimals as double. This is
  91. * more than 32bit integer fields.
  92. *
  93. * Revision 1.57 2005/02/10 20:16:54 fwarmerdam
  94. * Make the pszStringField buffer for DBFReadAttribute() static char [256]
  95. * as per bug 306.
  96. *
  97. * Revision 1.56 2005/02/10 20:07:56 fwarmerdam
  98. * Fixed bug 305 in DBFCloneEmpty() - header length problem.
  99. *
  100. * Revision 1.55 2004/09/26 20:23:46 fwarmerdam
  101. * avoid warnings with rcsid and signed/unsigned stuff
  102. *
  103. * Revision 1.54 2004/09/15 16:26:10 fwarmerdam
  104. * Treat all blank numeric fields as null too.
  105. */
  106. #include <grass/shapefil.h>
  107. #include <math.h>
  108. #include <stdlib.h>
  109. #include <ctype.h>
  110. #include <string.h>
  111. SHP_CVSID("$Id$")
  112. #ifndef FALSE
  113. # define FALSE 0
  114. # define TRUE 1
  115. #endif
  116. /************************************************************************/
  117. /* SfRealloc() */
  118. /* */
  119. /* A realloc cover function that will access a NULL pointer as */
  120. /* a valid input. */
  121. /************************************************************************/
  122. static void * SfRealloc( void * pMem, int nNewSize )
  123. {
  124. if( pMem == NULL )
  125. return( (void *) malloc(nNewSize) );
  126. else
  127. return( (void *) realloc(pMem,nNewSize) );
  128. }
  129. /************************************************************************/
  130. /* DBFWriteHeader() */
  131. /* */
  132. /* This is called to write out the file header, and field */
  133. /* descriptions before writing any actual data records. This */
  134. /* also computes all the DBFDataSet field offset/size/decimals */
  135. /* and so forth values. */
  136. /************************************************************************/
  137. static void DBFWriteHeader(DBFHandle psDBF)
  138. {
  139. unsigned char abyHeader[XBASE_FLDHDR_SZ];
  140. int i;
  141. if( !psDBF->bNoHeader )
  142. return;
  143. psDBF->bNoHeader = FALSE;
  144. /* -------------------------------------------------------------------- */
  145. /* Initialize the file header information. */
  146. /* -------------------------------------------------------------------- */
  147. for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
  148. abyHeader[i] = 0;
  149. abyHeader[0] = 0x03; /* memo field? - just copying */
  150. /* write out a dummy date */
  151. abyHeader[1] = 95; /* YY */
  152. abyHeader[2] = 7; /* MM */
  153. abyHeader[3] = 26; /* DD */
  154. /* record count preset at zero */
  155. abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
  156. abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
  157. abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
  158. abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
  159. /* -------------------------------------------------------------------- */
  160. /* Write the initial 32 byte file header, and all the field */
  161. /* descriptions. */
  162. /* -------------------------------------------------------------------- */
  163. psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
  164. psDBF->sHooks.FWrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
  165. psDBF->sHooks.FWrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields,
  166. psDBF->fp );
  167. /* -------------------------------------------------------------------- */
  168. /* Write out the newline character if there is room for it. */
  169. /* -------------------------------------------------------------------- */
  170. if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
  171. {
  172. char cNewline;
  173. cNewline = 0x0d;
  174. psDBF->sHooks.FWrite( &cNewline, 1, 1, psDBF->fp );
  175. }
  176. }
  177. /************************************************************************/
  178. /* DBFFlushRecord() */
  179. /* */
  180. /* Write out the current record if there is one. */
  181. /************************************************************************/
  182. static int DBFFlushRecord( DBFHandle psDBF )
  183. {
  184. SAOffset nRecordOffset;
  185. if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )
  186. {
  187. psDBF->bCurrentRecordModified = FALSE;
  188. nRecordOffset =
  189. psDBF->nRecordLength * (SAOffset) psDBF->nCurrentRecord
  190. + psDBF->nHeaderLength;
  191. if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ) != 0
  192. || psDBF->sHooks.FWrite( psDBF->pszCurrentRecord,
  193. psDBF->nRecordLength,
  194. 1, psDBF->fp ) != 1 )
  195. {
  196. #ifdef USE_CPL
  197. CPLError( CE_Failure, CPLE_FileIO,
  198. "Failure writing DBF record %d.",
  199. psDBF->nCurrentRecord );
  200. #else
  201. fprintf( stderr, "Failure writing DBF record %d.",
  202. psDBF->nCurrentRecord );
  203. #endif
  204. return FALSE;
  205. }
  206. }
  207. return TRUE;
  208. }
  209. /************************************************************************/
  210. /* DBFLoadRecord() */
  211. /************************************************************************/
  212. static int DBFLoadRecord( DBFHandle psDBF, int iRecord )
  213. {
  214. if( psDBF->nCurrentRecord != iRecord )
  215. {
  216. SAOffset nRecordOffset;
  217. if( !DBFFlushRecord( psDBF ) )
  218. return FALSE;
  219. nRecordOffset =
  220. psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
  221. if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, SEEK_SET ) != 0 )
  222. {
  223. #ifdef USE_CPL
  224. CPLError( CE_Failure, CPLE_FileIO,
  225. "fseek(%ld) failed on DBF file.\n",
  226. (long) nRecordOffset );
  227. #else
  228. fprintf( stderr, "fseek(%ld) failed on DBF file.\n",
  229. (long) nRecordOffset );
  230. #endif
  231. return FALSE;
  232. }
  233. if( psDBF->sHooks.FRead( psDBF->pszCurrentRecord,
  234. psDBF->nRecordLength, 1, psDBF->fp ) != 1 )
  235. {
  236. #ifdef USE_CPL
  237. CPLError( CE_Failure, CPLE_FileIO,
  238. "fread(%d) failed on DBF file.\n",
  239. psDBF->nRecordLength );
  240. #else
  241. fprintf( stderr, "fread(%d) failed on DBF file.\n",
  242. psDBF->nRecordLength );
  243. #endif
  244. return FALSE;
  245. }
  246. psDBF->nCurrentRecord = iRecord;
  247. }
  248. return TRUE;
  249. }
  250. /************************************************************************/
  251. /* DBFUpdateHeader() */
  252. /************************************************************************/
  253. void SHPAPI_CALL
  254. DBFUpdateHeader( DBFHandle psDBF )
  255. {
  256. unsigned char abyFileHeader[32];
  257. if( psDBF->bNoHeader )
  258. DBFWriteHeader( psDBF );
  259. DBFFlushRecord( psDBF );
  260. psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
  261. psDBF->sHooks.FRead( abyFileHeader, 32, 1, psDBF->fp );
  262. abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256);
  263. abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256);
  264. abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256);
  265. abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256);
  266. psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
  267. psDBF->sHooks.FWrite( abyFileHeader, 32, 1, psDBF->fp );
  268. psDBF->sHooks.FFlush( psDBF->fp );
  269. }
  270. /************************************************************************/
  271. /* DBFOpen() */
  272. /* */
  273. /* Open a .dbf file. */
  274. /************************************************************************/
  275. DBFHandle SHPAPI_CALL
  276. DBFOpen( const char * pszFilename, const char * pszAccess )
  277. {
  278. SAHooks sHooks;
  279. SASetupDefaultHooks( &sHooks );
  280. return DBFOpenLL( pszFilename, pszAccess, &sHooks );
  281. }
  282. /************************************************************************/
  283. /* DBFOpen() */
  284. /* */
  285. /* Open a .dbf file. */
  286. /************************************************************************/
  287. DBFHandle SHPAPI_CALL
  288. DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
  289. {
  290. DBFHandle psDBF;
  291. unsigned char *pabyBuf;
  292. int nFields, nHeadLen, iField, i;
  293. char *pszBasename, *pszFullname;
  294. /* -------------------------------------------------------------------- */
  295. /* We only allow the access strings "rb" and "r+". */
  296. /* -------------------------------------------------------------------- */
  297. if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0
  298. && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
  299. && strcmp(pszAccess,"r+b") != 0 )
  300. return( NULL );
  301. if( strcmp(pszAccess,"r") == 0 )
  302. pszAccess = "rb";
  303. if( strcmp(pszAccess,"r+") == 0 )
  304. pszAccess = "rb+";
  305. /* -------------------------------------------------------------------- */
  306. /* Compute the base (layer) name. If there is any extension */
  307. /* on the passed in filename we will strip it off. */
  308. /* -------------------------------------------------------------------- */
  309. pszBasename = (char *) malloc(strlen(pszFilename)+5);
  310. strcpy( pszBasename, pszFilename );
  311. for( i = strlen(pszBasename)-1;
  312. i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
  313. && pszBasename[i] != '\\';
  314. i-- ) {}
  315. if( pszBasename[i] == '.' )
  316. pszBasename[i] = '\0';
  317. pszFullname = (char *) malloc(strlen(pszBasename) + 5);
  318. sprintf( pszFullname, "%s.dbf", pszBasename );
  319. psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
  320. psDBF->fp = psHooks->FOpen( pszFullname, pszAccess );
  321. memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
  322. if( psDBF->fp == NULL )
  323. {
  324. sprintf( pszFullname, "%s.DBF", pszBasename );
  325. psDBF->fp = psDBF->sHooks.FOpen(pszFullname, pszAccess );
  326. }
  327. free( pszBasename );
  328. free( pszFullname );
  329. if( psDBF->fp == NULL )
  330. {
  331. free( psDBF );
  332. return( NULL );
  333. }
  334. psDBF->bNoHeader = FALSE;
  335. psDBF->nCurrentRecord = -1;
  336. psDBF->bCurrentRecordModified = FALSE;
  337. /* -------------------------------------------------------------------- */
  338. /* Read Table Header info */
  339. /* -------------------------------------------------------------------- */
  340. pabyBuf = (unsigned char *) malloc(500);
  341. if( psDBF->sHooks.FRead( pabyBuf, 32, 1, psDBF->fp ) != 1 )
  342. {
  343. psDBF->sHooks.FClose( psDBF->fp );
  344. free( pabyBuf );
  345. free( psDBF );
  346. return NULL;
  347. }
  348. psDBF->nRecords =
  349. pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
  350. psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
  351. psDBF->nRecordLength = pabyBuf[10] + pabyBuf[11]*256;
  352. psDBF->nFields = nFields = (nHeadLen - 32) / 32;
  353. psDBF->pszCurrentRecord = (char *) malloc(psDBF->nRecordLength);
  354. /* -------------------------------------------------------------------- */
  355. /* Read in Field Definitions */
  356. /* -------------------------------------------------------------------- */
  357. pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
  358. psDBF->pszHeader = (char *) pabyBuf;
  359. psDBF->sHooks.FSeek( psDBF->fp, 32, 0 );
  360. if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
  361. {
  362. psDBF->sHooks.FClose( psDBF->fp );
  363. free( pabyBuf );
  364. free( psDBF->pszCurrentRecord );
  365. free( psDBF );
  366. return NULL;
  367. }
  368. psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);
  369. psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);
  370. psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields);
  371. psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields);
  372. for( iField = 0; iField < nFields; iField++ )
  373. {
  374. unsigned char *pabyFInfo;
  375. pabyFInfo = pabyBuf+iField*32;
  376. if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
  377. {
  378. psDBF->panFieldSize[iField] = pabyFInfo[16];
  379. psDBF->panFieldDecimals[iField] = pabyFInfo[17];
  380. }
  381. else
  382. {
  383. psDBF->panFieldSize[iField] = pabyFInfo[16];
  384. psDBF->panFieldDecimals[iField] = 0;
  385. /*
  386. ** The following seemed to be used sometimes to handle files with long
  387. ** string fields, but in other cases (such as bug 1202) the decimals field
  388. ** just seems to indicate some sort of preferred formatting, not very
  389. ** wide fields. So I have disabled this code. FrankW.
  390. psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;
  391. psDBF->panFieldDecimals[iField] = 0;
  392. */
  393. }
  394. psDBF->pachFieldType[iField] = (char) pabyFInfo[11];
  395. if( iField == 0 )
  396. psDBF->panFieldOffset[iField] = 1;
  397. else
  398. psDBF->panFieldOffset[iField] =
  399. psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
  400. }
  401. return( psDBF );
  402. }
  403. /************************************************************************/
  404. /* DBFClose() */
  405. /************************************************************************/
  406. void SHPAPI_CALL
  407. DBFClose(DBFHandle psDBF)
  408. {
  409. /* -------------------------------------------------------------------- */
  410. /* Write out header if not already written. */
  411. /* -------------------------------------------------------------------- */
  412. if( psDBF->bNoHeader )
  413. DBFWriteHeader( psDBF );
  414. DBFFlushRecord( psDBF );
  415. /* -------------------------------------------------------------------- */
  416. /* Update last access date, and number of records if we have */
  417. /* write access. */
  418. /* -------------------------------------------------------------------- */
  419. if( psDBF->bUpdated )
  420. DBFUpdateHeader( psDBF );
  421. /* -------------------------------------------------------------------- */
  422. /* Close, and free resources. */
  423. /* -------------------------------------------------------------------- */
  424. psDBF->sHooks.FClose( psDBF->fp );
  425. if( psDBF->panFieldOffset != NULL )
  426. {
  427. free( psDBF->panFieldOffset );
  428. free( psDBF->panFieldSize );
  429. free( psDBF->panFieldDecimals );
  430. free( psDBF->pachFieldType );
  431. }
  432. if( psDBF->pszWorkField != NULL )
  433. free( psDBF->pszWorkField );
  434. free( psDBF->pszHeader );
  435. free( psDBF->pszCurrentRecord );
  436. free( psDBF );
  437. }
  438. /************************************************************************/
  439. /* DBFCreate() */
  440. /* */
  441. /* Create a new .dbf file. */
  442. /************************************************************************/
  443. DBFHandle SHPAPI_CALL
  444. DBFCreate( const char * pszFilename )
  445. {
  446. SAHooks sHooks;
  447. SASetupDefaultHooks( &sHooks );
  448. return DBFCreateLL( pszFilename, &sHooks );
  449. }
  450. /************************************************************************/
  451. /* DBFCreate() */
  452. /* */
  453. /* Create a new .dbf file. */
  454. /************************************************************************/
  455. DBFHandle SHPAPI_CALL
  456. DBFCreateLL( const char * pszFilename, SAHooks *psHooks )
  457. {
  458. DBFHandle psDBF;
  459. SAFile fp;
  460. char *pszFullname, *pszBasename;
  461. int i;
  462. char chZero = '\0';
  463. /* -------------------------------------------------------------------- */
  464. /* Compute the base (layer) name. If there is any extension */
  465. /* on the passed in filename we will strip it off. */
  466. /* -------------------------------------------------------------------- */
  467. pszBasename = (char *) malloc(strlen(pszFilename)+5);
  468. strcpy( pszBasename, pszFilename );
  469. for( i = strlen(pszBasename)-1;
  470. i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
  471. && pszBasename[i] != '\\';
  472. i-- ) {}
  473. if( pszBasename[i] == '.' )
  474. pszBasename[i] = '\0';
  475. pszFullname = (char *) malloc(strlen(pszBasename) + 5);
  476. sprintf( pszFullname, "%s.dbf", pszBasename );
  477. free( pszBasename );
  478. /* -------------------------------------------------------------------- */
  479. /* Create the file. */
  480. /* -------------------------------------------------------------------- */
  481. fp = psHooks->FOpen( pszFullname, "wb" );
  482. if( fp == NULL )
  483. return( NULL );
  484. psHooks->FWrite( &chZero, 1, 1, fp );
  485. psHooks->FClose( fp );
  486. fp = psHooks->FOpen( pszFullname, "rb+" );
  487. if( fp == NULL )
  488. return( NULL );
  489. free( pszFullname );
  490. /* -------------------------------------------------------------------- */
  491. /* Create the info structure. */
  492. /* -------------------------------------------------------------------- */
  493. psDBF = (DBFHandle) calloc(1,sizeof(DBFInfo));
  494. memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
  495. psDBF->fp = fp;
  496. psDBF->nRecords = 0;
  497. psDBF->nFields = 0;
  498. psDBF->nRecordLength = 1;
  499. psDBF->nHeaderLength = 33;
  500. psDBF->panFieldOffset = NULL;
  501. psDBF->panFieldSize = NULL;
  502. psDBF->panFieldDecimals = NULL;
  503. psDBF->pachFieldType = NULL;
  504. psDBF->pszHeader = NULL;
  505. psDBF->nCurrentRecord = -1;
  506. psDBF->bCurrentRecordModified = FALSE;
  507. psDBF->pszCurrentRecord = NULL;
  508. psDBF->bNoHeader = TRUE;
  509. return( psDBF );
  510. }
  511. /************************************************************************/
  512. /* DBFAddField() */
  513. /* */
  514. /* Add a field to a newly created .dbf file before any records */
  515. /* are written. */
  516. /************************************************************************/
  517. int SHPAPI_CALL
  518. DBFAddField(DBFHandle psDBF, const char * pszFieldName,
  519. DBFFieldType eType, int nWidth, int nDecimals )
  520. {
  521. char chNativeType = 'C';
  522. if( eType == FTLogical )
  523. chNativeType = 'L';
  524. else if( eType == FTString )
  525. chNativeType = 'C';
  526. else
  527. chNativeType = 'N';
  528. return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType,
  529. nWidth, nDecimals );
  530. }
  531. /************************************************************************/
  532. /* DBFAddField() */
  533. /* */
  534. /* Add a field to a newly created .dbf file before any records */
  535. /* are written. */
  536. /************************************************************************/
  537. int SHPAPI_CALL
  538. DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
  539. char chType, int nWidth, int nDecimals )
  540. {
  541. char *pszFInfo;
  542. int i;
  543. /* -------------------------------------------------------------------- */
  544. /* Do some checking to ensure we can add records to this file. */
  545. /* -------------------------------------------------------------------- */
  546. if( psDBF->nRecords > 0 )
  547. return( -1 );
  548. if( !psDBF->bNoHeader )
  549. return( -1 );
  550. if( nWidth < 1 )
  551. return -1;
  552. if( nWidth > 255 )
  553. nWidth = 255;
  554. /* -------------------------------------------------------------------- */
  555. /* SfRealloc all the arrays larger to hold the additional field */
  556. /* information. */
  557. /* -------------------------------------------------------------------- */
  558. psDBF->nFields++;
  559. psDBF->panFieldOffset = (int *)
  560. SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
  561. psDBF->panFieldSize = (int *)
  562. SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
  563. psDBF->panFieldDecimals = (int *)
  564. SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
  565. psDBF->pachFieldType = (char *)
  566. SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
  567. /* -------------------------------------------------------------------- */
  568. /* Assign the new field information fields. */
  569. /* -------------------------------------------------------------------- */
  570. psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
  571. psDBF->nRecordLength += nWidth;
  572. psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
  573. psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
  574. psDBF->pachFieldType[psDBF->nFields-1] = chType;
  575. /* -------------------------------------------------------------------- */
  576. /* Extend the required header information. */
  577. /* -------------------------------------------------------------------- */
  578. psDBF->nHeaderLength += 32;
  579. psDBF->bUpdated = FALSE;
  580. psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
  581. pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
  582. for( i = 0; i < 32; i++ )
  583. pszFInfo[i] = '\0';
  584. if( (int) strlen(pszFieldName) < 10 )
  585. strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
  586. else
  587. strncpy( pszFInfo, pszFieldName, 10);
  588. pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
  589. if( chType == 'C' )
  590. {
  591. pszFInfo[16] = (unsigned char) (nWidth % 256);
  592. pszFInfo[17] = (unsigned char) (nWidth / 256);
  593. }
  594. else
  595. {
  596. pszFInfo[16] = (unsigned char) nWidth;
  597. pszFInfo[17] = (unsigned char) nDecimals;
  598. }
  599. /* -------------------------------------------------------------------- */
  600. /* Make the current record buffer appropriately larger. */
  601. /* -------------------------------------------------------------------- */
  602. psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
  603. psDBF->nRecordLength);
  604. return( psDBF->nFields-1 );
  605. }
  606. /************************************************************************/
  607. /* DBFReadAttribute() */
  608. /* */
  609. /* Read one of the attribute fields of a record. */
  610. /************************************************************************/
  611. static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
  612. char chReqType )
  613. {
  614. unsigned char *pabyRec;
  615. void *pReturnField = NULL;
  616. /* -------------------------------------------------------------------- */
  617. /* Verify selection. */
  618. /* -------------------------------------------------------------------- */
  619. if( hEntity < 0 || hEntity >= psDBF->nRecords )
  620. return( NULL );
  621. if( iField < 0 || iField >= psDBF->nFields )
  622. return( NULL );
  623. /* -------------------------------------------------------------------- */
  624. /* Have we read the record? */
  625. /* -------------------------------------------------------------------- */
  626. if( !DBFLoadRecord( psDBF, hEntity ) )
  627. return NULL;
  628. pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
  629. /* -------------------------------------------------------------------- */
  630. /* Ensure we have room to extract the target field. */
  631. /* -------------------------------------------------------------------- */
  632. if( psDBF->panFieldSize[iField] >= psDBF->nWorkFieldLength )
  633. {
  634. psDBF->nWorkFieldLength = psDBF->panFieldSize[iField] + 100;
  635. if( psDBF->pszWorkField == NULL )
  636. psDBF->pszWorkField = (char *) malloc(psDBF->nWorkFieldLength);
  637. else
  638. psDBF->pszWorkField = (char *) realloc(psDBF->pszWorkField,
  639. psDBF->nWorkFieldLength);
  640. }
  641. /* -------------------------------------------------------------------- */
  642. /* Extract the requested field. */
  643. /* -------------------------------------------------------------------- */
  644. strncpy( psDBF->pszWorkField,
  645. ((const char *) pabyRec) + psDBF->panFieldOffset[iField],
  646. psDBF->panFieldSize[iField] );
  647. psDBF->pszWorkField[psDBF->panFieldSize[iField]] = '\0';
  648. pReturnField = psDBF->pszWorkField;
  649. /* -------------------------------------------------------------------- */
  650. /* Decode the field. */
  651. /* -------------------------------------------------------------------- */
  652. if( chReqType == 'N' )
  653. {
  654. psDBF->dfDoubleField = atof(psDBF->pszWorkField);
  655. pReturnField = &(psDBF->dfDoubleField);
  656. }
  657. /* -------------------------------------------------------------------- */
  658. /* Should we trim white space off the string attribute value? */
  659. /* -------------------------------------------------------------------- */
  660. #ifdef TRIM_DBF_WHITESPACE
  661. else
  662. {
  663. char *pchSrc, *pchDst;
  664. pchDst = pchSrc = psDBF->pszWorkField;
  665. while( *pchSrc == ' ' )
  666. pchSrc++;
  667. while( *pchSrc != '\0' )
  668. *(pchDst++) = *(pchSrc++);
  669. *pchDst = '\0';
  670. while( pchDst != psDBF->pszWorkField && *(--pchDst) == ' ' )
  671. *pchDst = '\0';
  672. }
  673. #endif
  674. return( pReturnField );
  675. }
  676. /************************************************************************/
  677. /* DBFReadIntAttribute() */
  678. /* */
  679. /* Read an integer attribute. */
  680. /************************************************************************/
  681. int SHPAPI_CALL
  682. DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
  683. {
  684. double *pdValue;
  685. pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
  686. if( pdValue == NULL )
  687. return 0;
  688. else
  689. return( (int) *pdValue );
  690. }
  691. /************************************************************************/
  692. /* DBFReadDoubleAttribute() */
  693. /* */
  694. /* Read a double attribute. */
  695. /************************************************************************/
  696. double SHPAPI_CALL
  697. DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
  698. {
  699. double *pdValue;
  700. pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
  701. if( pdValue == NULL )
  702. return 0.0;
  703. else
  704. return( *pdValue );
  705. }
  706. /************************************************************************/
  707. /* DBFReadStringAttribute() */
  708. /* */
  709. /* Read a string attribute. */
  710. /************************************************************************/
  711. const char SHPAPI_CALL1(*)
  712. DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
  713. {
  714. return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
  715. }
  716. /************************************************************************/
  717. /* DBFReadLogicalAttribute() */
  718. /* */
  719. /* Read a logical attribute. */
  720. /************************************************************************/
  721. const char SHPAPI_CALL1(*)
  722. DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
  723. {
  724. return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
  725. }
  726. /************************************************************************/
  727. /* DBFIsAttributeNULL() */
  728. /* */
  729. /* Return TRUE if value for field is NULL. */
  730. /* */
  731. /* Contributed by Jim Matthews. */
  732. /************************************************************************/
  733. int SHPAPI_CALL
  734. DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
  735. {
  736. const char *pszValue;
  737. int i;
  738. pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
  739. if( pszValue == NULL )
  740. return TRUE;
  741. switch(psDBF->pachFieldType[iField])
  742. {
  743. case 'N':
  744. case 'F':
  745. /*
  746. ** We accept all asterisks or all blanks as NULL
  747. ** though according to the spec I think it should be all
  748. ** asterisks.
  749. */
  750. if( pszValue[0] == '*' )
  751. return TRUE;
  752. for( i = 0; pszValue[i] != '\0'; i++ )
  753. {
  754. if( pszValue[i] != ' ' )
  755. return FALSE;
  756. }
  757. return TRUE;
  758. case 'D':
  759. /* NULL date fields have value "00000000" */
  760. return strncmp(pszValue,"00000000",8) == 0;
  761. case 'L':
  762. /* NULL boolean fields have value "?" */
  763. return pszValue[0] == '?';
  764. default:
  765. /* empty string fields are considered NULL */
  766. return strlen(pszValue) == 0;
  767. }
  768. }
  769. /************************************************************************/
  770. /* DBFGetFieldCount() */
  771. /* */
  772. /* Return the number of fields in this table. */
  773. /************************************************************************/
  774. int SHPAPI_CALL
  775. DBFGetFieldCount( DBFHandle psDBF )
  776. {
  777. return( psDBF->nFields );
  778. }
  779. /************************************************************************/
  780. /* DBFGetRecordCount() */
  781. /* */
  782. /* Return the number of records in this table. */
  783. /************************************************************************/
  784. int SHPAPI_CALL
  785. DBFGetRecordCount( DBFHandle psDBF )
  786. {
  787. return( psDBF->nRecords );
  788. }
  789. /************************************************************************/
  790. /* DBFGetFieldInfo() */
  791. /* */
  792. /* Return any requested information about the field. */
  793. /************************************************************************/
  794. DBFFieldType SHPAPI_CALL
  795. DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
  796. int * pnWidth, int * pnDecimals )
  797. {
  798. if( iField < 0 || iField >= psDBF->nFields )
  799. return( FTInvalid );
  800. if( pnWidth != NULL )
  801. *pnWidth = psDBF->panFieldSize[iField];
  802. if( pnDecimals != NULL )
  803. *pnDecimals = psDBF->panFieldDecimals[iField];
  804. if( pszFieldName != NULL )
  805. {
  806. int i;
  807. strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
  808. pszFieldName[11] = '\0';
  809. for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
  810. pszFieldName[i] = '\0';
  811. }
  812. if ( psDBF->pachFieldType[iField] == 'L' )
  813. return( FTLogical);
  814. else if( psDBF->pachFieldType[iField] == 'N'
  815. || psDBF->pachFieldType[iField] == 'F' )
  816. {
  817. if( psDBF->panFieldDecimals[iField] > 0 )
  818. /* || psDBF->panFieldSize[iField] > 10 ) */ /* GDAL bug #809 */
  819. return( FTDouble );
  820. else
  821. return( FTInteger );
  822. }
  823. else
  824. {
  825. return( FTString );
  826. }
  827. }
  828. /************************************************************************/
  829. /* DBFWriteAttribute() */
  830. /* */
  831. /* Write an attribute record to the file. */
  832. /************************************************************************/
  833. static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
  834. void * pValue )
  835. {
  836. int i, j, nRetResult = TRUE;
  837. unsigned char *pabyRec;
  838. char szSField[400], szFormat[20];
  839. /* -------------------------------------------------------------------- */
  840. /* Is this a valid record? */
  841. /* -------------------------------------------------------------------- */
  842. if( hEntity < 0 || hEntity > psDBF->nRecords )
  843. return( FALSE );
  844. if( psDBF->bNoHeader )
  845. DBFWriteHeader(psDBF);
  846. /* -------------------------------------------------------------------- */
  847. /* Is this a brand new record? */
  848. /* -------------------------------------------------------------------- */
  849. if( hEntity == psDBF->nRecords )
  850. {
  851. if( !DBFFlushRecord( psDBF ) )
  852. return FALSE;
  853. psDBF->nRecords++;
  854. for( i = 0; i < psDBF->nRecordLength; i++ )
  855. psDBF->pszCurrentRecord[i] = ' ';
  856. psDBF->nCurrentRecord = hEntity;
  857. }
  858. /* -------------------------------------------------------------------- */
  859. /* Is this an existing record, but different than the last one */
  860. /* we accessed? */
  861. /* -------------------------------------------------------------------- */
  862. if( !DBFLoadRecord( psDBF, hEntity ) )
  863. return FALSE;
  864. pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
  865. psDBF->bCurrentRecordModified = TRUE;
  866. psDBF->bUpdated = TRUE;
  867. /* -------------------------------------------------------------------- */
  868. /* Translate NULL value to valid DBF file representation. */
  869. /* */
  870. /* Contributed by Jim Matthews. */
  871. /* -------------------------------------------------------------------- */
  872. if( pValue == NULL )
  873. {
  874. switch(psDBF->pachFieldType[iField])
  875. {
  876. case 'N':
  877. case 'F':
  878. /* NULL numeric fields have value "****************" */
  879. memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*',
  880. psDBF->panFieldSize[iField] );
  881. break;
  882. case 'D':
  883. /* NULL date fields have value "00000000" */
  884. memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0',
  885. psDBF->panFieldSize[iField] );
  886. break;
  887. case 'L':
  888. /* NULL boolean fields have value "?" */
  889. memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?',
  890. psDBF->panFieldSize[iField] );
  891. break;
  892. default:
  893. /* empty string fields are considered NULL */
  894. memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), ' ',
  895. psDBF->panFieldSize[iField] );
  896. break;
  897. }
  898. return TRUE;
  899. }
  900. /* -------------------------------------------------------------------- */
  901. /* Assign all the record fields. */
  902. /* -------------------------------------------------------------------- */
  903. switch( psDBF->pachFieldType[iField] )
  904. {
  905. case 'D':
  906. case 'N':
  907. case 'F':
  908. if( psDBF->panFieldDecimals[iField] == 0 )
  909. {
  910. int nWidth = psDBF->panFieldSize[iField];
  911. if( (int) sizeof(szSField)-2 < nWidth )
  912. nWidth = sizeof(szSField)-2;
  913. sprintf( szFormat, "%%%dd", nWidth );
  914. sprintf(szSField, szFormat, (int) *((double *) pValue) );
  915. if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
  916. {
  917. szSField[psDBF->panFieldSize[iField]] = '\0';
  918. nRetResult = FALSE;
  919. }
  920. strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
  921. szSField, strlen(szSField) );
  922. }
  923. else
  924. {
  925. int nWidth = psDBF->panFieldSize[iField];
  926. if( (int) sizeof(szSField)-2 < nWidth )
  927. nWidth = sizeof(szSField)-2;
  928. sprintf( szFormat, "%%%d.%df",
  929. nWidth, psDBF->panFieldDecimals[iField] );
  930. sprintf(szSField, szFormat, *((double *) pValue) );
  931. if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
  932. {
  933. szSField[psDBF->panFieldSize[iField]] = '\0';
  934. nRetResult = FALSE;
  935. }
  936. strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
  937. szSField, strlen(szSField) );
  938. }
  939. break;
  940. case 'L':
  941. if (psDBF->panFieldSize[iField] >= 1 &&
  942. (*(char*)pValue == 'F' || *(char*)pValue == 'T'))
  943. *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
  944. break;
  945. default:
  946. if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
  947. {
  948. j = psDBF->panFieldSize[iField];
  949. nRetResult = FALSE;
  950. }
  951. else
  952. {
  953. memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
  954. psDBF->panFieldSize[iField] );
  955. j = strlen((char *) pValue);
  956. }
  957. strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
  958. (char *) pValue, j );
  959. break;
  960. }
  961. return( nRetResult );
  962. }
  963. /************************************************************************/
  964. /* DBFWriteAttributeDirectly() */
  965. /* */
  966. /* Write an attribute record to the file, but without any */
  967. /* reformatting based on type. The provided buffer is written */
  968. /* as is to the field position in the record. */
  969. /************************************************************************/
  970. int SHPAPI_CALL
  971. DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
  972. void * pValue )
  973. {
  974. int i, j;
  975. unsigned char *pabyRec;
  976. /* -------------------------------------------------------------------- */
  977. /* Is this a valid record? */
  978. /* -------------------------------------------------------------------- */
  979. if( hEntity < 0 || hEntity > psDBF->nRecords )
  980. return( FALSE );
  981. if( psDBF->bNoHeader )
  982. DBFWriteHeader(psDBF);
  983. /* -------------------------------------------------------------------- */
  984. /* Is this a brand new record? */
  985. /* -------------------------------------------------------------------- */
  986. if( hEntity == psDBF->nRecords )
  987. {
  988. if( !DBFFlushRecord( psDBF ) )
  989. return FALSE;
  990. psDBF->nRecords++;
  991. for( i = 0; i < psDBF->nRecordLength; i++ )
  992. psDBF->pszCurrentRecord[i] = ' ';
  993. psDBF->nCurrentRecord = hEntity;
  994. }
  995. /* -------------------------------------------------------------------- */
  996. /* Is this an existing record, but different than the last one */
  997. /* we accessed? */
  998. /* -------------------------------------------------------------------- */
  999. if( !DBFLoadRecord( psDBF, hEntity ) )
  1000. return FALSE;
  1001. pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
  1002. /* -------------------------------------------------------------------- */
  1003. /* Assign all the record fields. */
  1004. /* -------------------------------------------------------------------- */
  1005. if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] )
  1006. j = psDBF->panFieldSize[iField];
  1007. else
  1008. {
  1009. memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
  1010. psDBF->panFieldSize[iField] );
  1011. j = strlen((char *) pValue);
  1012. }
  1013. strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
  1014. (char *) pValue, j );
  1015. psDBF->bCurrentRecordModified = TRUE;
  1016. psDBF->bUpdated = TRUE;
  1017. return( TRUE );
  1018. }
  1019. /************************************************************************/
  1020. /* DBFWriteDoubleAttribute() */
  1021. /* */
  1022. /* Write a double attribute. */
  1023. /************************************************************************/
  1024. int SHPAPI_CALL
  1025. DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
  1026. double dValue )
  1027. {
  1028. return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
  1029. }
  1030. /************************************************************************/
  1031. /* DBFWriteIntegerAttribute() */
  1032. /* */
  1033. /* Write a integer attribute. */
  1034. /************************************************************************/
  1035. int SHPAPI_CALL
  1036. DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
  1037. int nValue )
  1038. {
  1039. double dValue = nValue;
  1040. return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
  1041. }
  1042. /************************************************************************/
  1043. /* DBFWriteStringAttribute() */
  1044. /* */
  1045. /* Write a string attribute. */
  1046. /************************************************************************/
  1047. int SHPAPI_CALL
  1048. DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
  1049. const char * pszValue )
  1050. {
  1051. return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) );
  1052. }
  1053. /************************************************************************/
  1054. /* DBFWriteNULLAttribute() */
  1055. /* */
  1056. /* Write a string attribute. */
  1057. /************************************************************************/
  1058. int SHPAPI_CALL
  1059. DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
  1060. {
  1061. return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );
  1062. }
  1063. /************************************************************************/
  1064. /* DBFWriteLogicalAttribute() */
  1065. /* */
  1066. /* Write a logical attribute. */
  1067. /************************************************************************/
  1068. int SHPAPI_CALL
  1069. DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
  1070. const char lValue)
  1071. {
  1072. return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );
  1073. }
  1074. /************************************************************************/
  1075. /* DBFWriteTuple() */
  1076. /* */
  1077. /* Write an attribute record to the file. */
  1078. /************************************************************************/
  1079. int SHPAPI_CALL
  1080. DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
  1081. {
  1082. int i;
  1083. unsigned char *pabyRec;
  1084. /* -------------------------------------------------------------------- */
  1085. /* Is this a valid record? */
  1086. /* -------------------------------------------------------------------- */
  1087. if( hEntity < 0 || hEntity > psDBF->nRecords )
  1088. return( FALSE );
  1089. if( psDBF->bNoHeader )
  1090. DBFWriteHeader(psDBF);
  1091. /* -------------------------------------------------------------------- */
  1092. /* Is this a brand new record? */
  1093. /* -------------------------------------------------------------------- */
  1094. if( hEntity == psDBF->nRecords )
  1095. {
  1096. if( !DBFFlushRecord( psDBF ) )
  1097. return FALSE;
  1098. psDBF->nRecords++;
  1099. for( i = 0; i < psDBF->nRecordLength; i++ )
  1100. psDBF->pszCurrentRecord[i] = ' ';
  1101. psDBF->nCurrentRecord = hEntity;
  1102. }
  1103. /* -------------------------------------------------------------------- */
  1104. /* Is this an existing record, but different than the last one */
  1105. /* we accessed? */
  1106. /* -------------------------------------------------------------------- */
  1107. if( !DBFLoadRecord( psDBF, hEntity ) )
  1108. return FALSE;
  1109. pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
  1110. memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength );
  1111. psDBF->bCurrentRecordModified = TRUE;
  1112. psDBF->bUpdated = TRUE;
  1113. return( TRUE );
  1114. }
  1115. /************************************************************************/
  1116. /* DBFReadTuple() */
  1117. /* */
  1118. /* Read a complete record. Note that the result is only valid */
  1119. /* till the next record read for any reason. */
  1120. /************************************************************************/
  1121. const char SHPAPI_CALL1(*)
  1122. DBFReadTuple(DBFHandle psDBF, int hEntity )
  1123. {
  1124. if( hEntity < 0 || hEntity >= psDBF->nRecords )
  1125. return( NULL );
  1126. if( !DBFLoadRecord( psDBF, hEntity ) )
  1127. return NULL;
  1128. return (const char *) psDBF->pszCurrentRecord;
  1129. }
  1130. /************************************************************************/
  1131. /* DBFCloneEmpty() */
  1132. /* */
  1133. /* Read one of the attribute fields of a record. */
  1134. /************************************************************************/
  1135. DBFHandle SHPAPI_CALL
  1136. DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
  1137. {
  1138. DBFHandle newDBF;
  1139. newDBF = DBFCreate ( pszFilename );
  1140. if ( newDBF == NULL ) return ( NULL );
  1141. newDBF->nFields = psDBF->nFields;
  1142. newDBF->nRecordLength = psDBF->nRecordLength;
  1143. newDBF->nHeaderLength = psDBF->nHeaderLength;
  1144. newDBF->pszHeader = (char *) malloc ( newDBF->nHeaderLength );
  1145. memcpy ( newDBF->pszHeader, psDBF->pszHeader, newDBF->nHeaderLength );
  1146. newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields );
  1147. memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
  1148. newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
  1149. memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
  1150. newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
  1151. memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
  1152. newDBF->pachFieldType = (char *) malloc ( sizeof(char) * psDBF->nFields );
  1153. memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(char)*psDBF->nFields );
  1154. newDBF->bNoHeader = TRUE;
  1155. newDBF->bUpdated = TRUE;
  1156. DBFWriteHeader ( newDBF );
  1157. DBFClose ( newDBF );
  1158. newDBF = DBFOpen ( pszFilename, "rb+" );
  1159. return ( newDBF );
  1160. }
  1161. /************************************************************************/
  1162. /* DBFGetNativeFieldType() */
  1163. /* */
  1164. /* Return the DBase field type for the specified field. */
  1165. /* */
  1166. /* Value can be one of: 'C' (String), 'D' (Date), 'F' (Float), */
  1167. /* 'N' (Numeric, with or without decimal), */
  1168. /* 'L' (Logical), */
  1169. /* 'M' (Memo: 10 digits .DBT block ptr) */
  1170. /************************************************************************/
  1171. char SHPAPI_CALL
  1172. DBFGetNativeFieldType( DBFHandle psDBF, int iField )
  1173. {
  1174. if( iField >=0 && iField < psDBF->nFields )
  1175. return psDBF->pachFieldType[iField];
  1176. return ' ';
  1177. }
  1178. /************************************************************************/
  1179. /* str_to_upper() */
  1180. /************************************************************************/
  1181. static void str_to_upper (char *string)
  1182. {
  1183. int len;
  1184. short i = -1;
  1185. len = strlen (string);
  1186. while (++i < len)
  1187. if (isalpha(string[i]) && islower(string[i]))
  1188. string[i] = (char) toupper ((int)string[i]);
  1189. }
  1190. /************************************************************************/
  1191. /* DBFGetFieldIndex() */
  1192. /* */
  1193. /* Get the index number for a field in a .dbf file. */
  1194. /* */
  1195. /* Contributed by Jim Matthews. */
  1196. /************************************************************************/
  1197. int SHPAPI_CALL
  1198. DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
  1199. {
  1200. char name[12], name1[12], name2[12];
  1201. int i;
  1202. strncpy(name1, pszFieldName,11);
  1203. name1[11] = '\0';
  1204. str_to_upper(name1);
  1205. for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
  1206. {
  1207. DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
  1208. strncpy(name2,name,11);
  1209. str_to_upper(name2);
  1210. if(!strncmp(name1,name2,10))
  1211. return(i);
  1212. }
  1213. return(-1);
  1214. }
  1215. /************************************************************************/
  1216. /* DBFIsRecordDeleted() */
  1217. /* */
  1218. /* Returns TRUE if the indicated record is deleted, otherwise */
  1219. /* it returns FALSE. */
  1220. /************************************************************************/
  1221. int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape )
  1222. {
  1223. /* -------------------------------------------------------------------- */
  1224. /* Verify selection. */
  1225. /* -------------------------------------------------------------------- */
  1226. if( iShape < 0 || iShape >= psDBF->nRecords )
  1227. return TRUE;
  1228. /* -------------------------------------------------------------------- */
  1229. /* Have we read the record? */
  1230. /* -------------------------------------------------------------------- */
  1231. if( !DBFLoadRecord( psDBF, iShape ) )
  1232. return FALSE;
  1233. /* -------------------------------------------------------------------- */
  1234. /* '*' means deleted. */
  1235. /* -------------------------------------------------------------------- */
  1236. return psDBF->pszCurrentRecord[0] == '*';
  1237. }
  1238. /************************************************************************/
  1239. /* DBFMarkRecordDeleted() */
  1240. /************************************************************************/
  1241. int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape,
  1242. int bIsDeleted )
  1243. {
  1244. char chNewFlag;
  1245. /* -------------------------------------------------------------------- */
  1246. /* Verify selection. */
  1247. /* -------------------------------------------------------------------- */
  1248. if( iShape < 0 || iShape >= psDBF->nRecords )
  1249. return FALSE;
  1250. /* -------------------------------------------------------------------- */
  1251. /* Is this an existing record, but different than the last one */
  1252. /* we accessed? */
  1253. /* -------------------------------------------------------------------- */
  1254. if( !DBFLoadRecord( psDBF, iShape ) )
  1255. return FALSE;
  1256. /* -------------------------------------------------------------------- */
  1257. /* Assign value, marking record as dirty if it changes. */
  1258. /* -------------------------------------------------------------------- */
  1259. if( bIsDeleted )
  1260. chNewFlag = '*';
  1261. else
  1262. chNewFlag = ' ';
  1263. if( psDBF->pszCurrentRecord[0] != chNewFlag )
  1264. {
  1265. psDBF->bCurrentRecordModified = TRUE;
  1266. psDBF->bUpdated = TRUE;
  1267. psDBF->pszCurrentRecord[0] = chNewFlag;
  1268. }
  1269. return TRUE;
  1270. }