GRASS Programmer's Manual
6.4.2(2012)
|
00001 /****************************************************************************** 00002 * $Id: dbfopen.c 32581 2008-08-06 19:30:45Z neteler $ 00003 * 00004 * Project: Shapelib 00005 * Purpose: Implementation of .dbf access API documented in dbf_api.html. 00006 * Author: Frank Warmerdam, warmerdam@pobox.com 00007 * 00008 ****************************************************************************** 00009 * Copyright (c) 1999, Frank Warmerdam 00010 * 00011 * This software is available under the following "MIT Style" license, 00012 * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This 00013 * option is discussed in more detail in shapelib.html. 00014 * 00015 * -- 00016 * 00017 * Permission is hereby granted, free of charge, to any person obtaining a 00018 * copy of this software and associated documentation files (the "Software"), 00019 * to deal in the Software without restriction, including without limitation 00020 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00021 * and/or sell copies of the Software, and to permit persons to whom the 00022 * Software is furnished to do so, subject to the following conditions: 00023 * 00024 * The above copyright notice and this permission notice shall be included 00025 * in all copies or substantial portions of the Software. 00026 * 00027 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00028 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00029 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 00030 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00031 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 00032 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 00033 * DEALINGS IN THE SOFTWARE. 00034 ****************************************************************************** 00035 * 00036 * $Log: dbfopen.c,v $ 00037 * Revision 1.74 2007/12/06 07:00:25 fwarmerdam 00038 * dbfopen now using SAHooks for fileio 00039 * 00040 * Revision 1.73 2007/09/03 19:48:11 fwarmerdam 00041 * move DBFReadAttribute() static dDoubleField into dbfinfo 00042 * 00043 * Revision 1.72 2007/09/03 19:34:06 fwarmerdam 00044 * Avoid use of static tuple buffer in DBFReadTuple() 00045 * 00046 * Revision 1.71 2006/06/22 14:37:18 fwarmerdam 00047 * avoid memory leak if dbfopen fread fails 00048 * 00049 * Revision 1.70 2006/06/17 17:47:05 fwarmerdam 00050 * use calloc() for dbfinfo in DBFCreate 00051 * 00052 * Revision 1.69 2006/06/17 15:34:32 fwarmerdam 00053 * disallow creating fields wider than 255 00054 * 00055 * Revision 1.68 2006/06/17 15:12:40 fwarmerdam 00056 * Fixed C++ style comments. 00057 * 00058 * Revision 1.67 2006/06/17 00:24:53 fwarmerdam 00059 * Don't treat non-zero decimals values as high order byte for length 00060 * for strings. It causes serious corruption for some files. 00061 * http://bugzilla.remotesensing.org/show_bug.cgi?id=1202 00062 * 00063 * Revision 1.66 2006/03/29 18:26:20 fwarmerdam 00064 * fixed bug with size of pachfieldtype in dbfcloneempty 00065 * 00066 * Revision 1.65 2006/02/15 01:14:30 fwarmerdam 00067 * added DBFAddNativeFieldType 00068 * 00069 * Revision 1.64 2006/02/09 00:29:04 fwarmerdam 00070 * Changed to put spaces into string fields that are NULL as 00071 * per http://bugzilla.maptools.org/show_bug.cgi?id=316. 00072 * 00073 * Revision 1.63 2006/01/25 15:35:43 fwarmerdam 00074 * check success on DBFFlushRecord 00075 * 00076 * Revision 1.62 2006/01/10 16:28:03 fwarmerdam 00077 * Fixed typo in CPLError. 00078 * 00079 * Revision 1.61 2006/01/10 16:26:29 fwarmerdam 00080 * Push loading record buffer into DBFLoadRecord. 00081 * Implement CPL error reporting if USE_CPL defined. 00082 * 00083 * Revision 1.60 2006/01/05 01:27:27 fwarmerdam 00084 * added dbf deletion mark/fetch 00085 * 00086 * Revision 1.59 2005/03/14 15:20:28 fwarmerdam 00087 * Fixed last change. 00088 * 00089 * Revision 1.58 2005/03/14 15:18:54 fwarmerdam 00090 * Treat very wide fields with no decimals as double. This is 00091 * more than 32bit integer fields. 00092 * 00093 * Revision 1.57 2005/02/10 20:16:54 fwarmerdam 00094 * Make the pszStringField buffer for DBFReadAttribute() static char [256] 00095 * as per bug 306. 00096 * 00097 * Revision 1.56 2005/02/10 20:07:56 fwarmerdam 00098 * Fixed bug 305 in DBFCloneEmpty() - header length problem. 00099 * 00100 * Revision 1.55 2004/09/26 20:23:46 fwarmerdam 00101 * avoid warnings with rcsid and signed/unsigned stuff 00102 * 00103 * Revision 1.54 2004/09/15 16:26:10 fwarmerdam 00104 * Treat all blank numeric fields as null too. 00105 */ 00106 00107 #include <grass/shapefil.h> 00108 00109 #include <math.h> 00110 #include <stdlib.h> 00111 #include <ctype.h> 00112 #include <string.h> 00113 00114 SHP_CVSID("$Id: dbfopen.c 32581 2008-08-06 19:30:45Z neteler $") 00115 00116 #ifndef FALSE 00117 # define FALSE 0 00118 # define TRUE 1 00119 #endif 00120 00121 /************************************************************************/ 00122 /* SfRealloc() */ 00123 /* */ 00124 /* A realloc cover function that will access a NULL pointer as */ 00125 /* a valid input. */ 00126 /************************************************************************/ 00127 00128 static void * SfRealloc( void * pMem, int nNewSize ) 00129 00130 { 00131 if( pMem == NULL ) 00132 return( (void *) malloc(nNewSize) ); 00133 else 00134 return( (void *) realloc(pMem,nNewSize) ); 00135 } 00136 00137 /************************************************************************/ 00138 /* DBFWriteHeader() */ 00139 /* */ 00140 /* This is called to write out the file header, and field */ 00141 /* descriptions before writing any actual data records. This */ 00142 /* also computes all the DBFDataSet field offset/size/decimals */ 00143 /* and so forth values. */ 00144 /************************************************************************/ 00145 00146 static void DBFWriteHeader(DBFHandle psDBF) 00147 00148 { 00149 unsigned char abyHeader[XBASE_FLDHDR_SZ]; 00150 int i; 00151 00152 if( !psDBF->bNoHeader ) 00153 return; 00154 00155 psDBF->bNoHeader = FALSE; 00156 00157 /* -------------------------------------------------------------------- */ 00158 /* Initialize the file header information. */ 00159 /* -------------------------------------------------------------------- */ 00160 for( i = 0; i < XBASE_FLDHDR_SZ; i++ ) 00161 abyHeader[i] = 0; 00162 00163 abyHeader[0] = 0x03; /* memo field? - just copying */ 00164 00165 /* write out a dummy date */ 00166 abyHeader[1] = 95; /* YY */ 00167 abyHeader[2] = 7; /* MM */ 00168 abyHeader[3] = 26; /* DD */ 00169 00170 /* record count preset at zero */ 00171 00172 abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256); 00173 abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256); 00174 00175 abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256); 00176 abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256); 00177 00178 /* -------------------------------------------------------------------- */ 00179 /* Write the initial 32 byte file header, and all the field */ 00180 /* descriptions. */ 00181 /* -------------------------------------------------------------------- */ 00182 psDBF->sHooks.FSeek( psDBF->fp, 0, 0 ); 00183 psDBF->sHooks.FWrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp ); 00184 psDBF->sHooks.FWrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, 00185 psDBF->fp ); 00186 00187 /* -------------------------------------------------------------------- */ 00188 /* Write out the newline character if there is room for it. */ 00189 /* -------------------------------------------------------------------- */ 00190 if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 ) 00191 { 00192 char cNewline; 00193 00194 cNewline = 0x0d; 00195 psDBF->sHooks.FWrite( &cNewline, 1, 1, psDBF->fp ); 00196 } 00197 } 00198 00199 /************************************************************************/ 00200 /* DBFFlushRecord() */ 00201 /* */ 00202 /* Write out the current record if there is one. */ 00203 /************************************************************************/ 00204 00205 static int DBFFlushRecord( DBFHandle psDBF ) 00206 00207 { 00208 SAOffset nRecordOffset; 00209 00210 if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 ) 00211 { 00212 psDBF->bCurrentRecordModified = FALSE; 00213 00214 nRecordOffset = 00215 psDBF->nRecordLength * (SAOffset) psDBF->nCurrentRecord 00216 + psDBF->nHeaderLength; 00217 00218 if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ) != 0 00219 || psDBF->sHooks.FWrite( psDBF->pszCurrentRecord, 00220 psDBF->nRecordLength, 00221 1, psDBF->fp ) != 1 ) 00222 { 00223 #ifdef USE_CPL 00224 CPLError( CE_Failure, CPLE_FileIO, 00225 "Failure writing DBF record %d.", 00226 psDBF->nCurrentRecord ); 00227 #else 00228 fprintf( stderr, "Failure writing DBF record %d.", 00229 psDBF->nCurrentRecord ); 00230 #endif 00231 return FALSE; 00232 } 00233 } 00234 00235 return TRUE; 00236 } 00237 00238 /************************************************************************/ 00239 /* DBFLoadRecord() */ 00240 /************************************************************************/ 00241 00242 static int DBFLoadRecord( DBFHandle psDBF, int iRecord ) 00243 00244 { 00245 if( psDBF->nCurrentRecord != iRecord ) 00246 { 00247 SAOffset nRecordOffset; 00248 00249 if( !DBFFlushRecord( psDBF ) ) 00250 return FALSE; 00251 00252 nRecordOffset = 00253 psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength; 00254 00255 if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, SEEK_SET ) != 0 ) 00256 { 00257 #ifdef USE_CPL 00258 CPLError( CE_Failure, CPLE_FileIO, 00259 "fseek(%ld) failed on DBF file.\n", 00260 (long) nRecordOffset ); 00261 #else 00262 fprintf( stderr, "fseek(%ld) failed on DBF file.\n", 00263 (long) nRecordOffset ); 00264 #endif 00265 return FALSE; 00266 } 00267 00268 if( psDBF->sHooks.FRead( psDBF->pszCurrentRecord, 00269 psDBF->nRecordLength, 1, psDBF->fp ) != 1 ) 00270 { 00271 #ifdef USE_CPL 00272 CPLError( CE_Failure, CPLE_FileIO, 00273 "fread(%d) failed on DBF file.\n", 00274 psDBF->nRecordLength ); 00275 #else 00276 fprintf( stderr, "fread(%d) failed on DBF file.\n", 00277 psDBF->nRecordLength ); 00278 #endif 00279 return FALSE; 00280 } 00281 00282 psDBF->nCurrentRecord = iRecord; 00283 } 00284 00285 return TRUE; 00286 } 00287 00288 /************************************************************************/ 00289 /* DBFUpdateHeader() */ 00290 /************************************************************************/ 00291 00292 void SHPAPI_CALL 00293 DBFUpdateHeader( DBFHandle psDBF ) 00294 00295 { 00296 unsigned char abyFileHeader[32]; 00297 00298 if( psDBF->bNoHeader ) 00299 DBFWriteHeader( psDBF ); 00300 00301 DBFFlushRecord( psDBF ); 00302 00303 psDBF->sHooks.FSeek( psDBF->fp, 0, 0 ); 00304 psDBF->sHooks.FRead( abyFileHeader, 32, 1, psDBF->fp ); 00305 00306 abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256); 00307 abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256); 00308 abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256); 00309 abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256); 00310 00311 psDBF->sHooks.FSeek( psDBF->fp, 0, 0 ); 00312 psDBF->sHooks.FWrite( abyFileHeader, 32, 1, psDBF->fp ); 00313 00314 psDBF->sHooks.FFlush( psDBF->fp ); 00315 } 00316 00317 /************************************************************************/ 00318 /* DBFOpen() */ 00319 /* */ 00320 /* Open a .dbf file. */ 00321 /************************************************************************/ 00322 00323 DBFHandle SHPAPI_CALL 00324 DBFOpen( const char * pszFilename, const char * pszAccess ) 00325 00326 { 00327 SAHooks sHooks; 00328 00329 SASetupDefaultHooks( &sHooks ); 00330 00331 return DBFOpenLL( pszFilename, pszAccess, &sHooks ); 00332 } 00333 00334 /************************************************************************/ 00335 /* DBFOpen() */ 00336 /* */ 00337 /* Open a .dbf file. */ 00338 /************************************************************************/ 00339 00340 DBFHandle SHPAPI_CALL 00341 DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks ) 00342 00343 { 00344 DBFHandle psDBF; 00345 unsigned char *pabyBuf; 00346 int nFields, nHeadLen, iField, i; 00347 char *pszBasename, *pszFullname; 00348 00349 /* -------------------------------------------------------------------- */ 00350 /* We only allow the access strings "rb" and "r+". */ 00351 /* -------------------------------------------------------------------- */ 00352 if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0 00353 && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0 00354 && strcmp(pszAccess,"r+b") != 0 ) 00355 return( NULL ); 00356 00357 if( strcmp(pszAccess,"r") == 0 ) 00358 pszAccess = "rb"; 00359 00360 if( strcmp(pszAccess,"r+") == 0 ) 00361 pszAccess = "rb+"; 00362 00363 /* -------------------------------------------------------------------- */ 00364 /* Compute the base (layer) name. If there is any extension */ 00365 /* on the passed in filename we will strip it off. */ 00366 /* -------------------------------------------------------------------- */ 00367 pszBasename = (char *) malloc(strlen(pszFilename)+5); 00368 strcpy( pszBasename, pszFilename ); 00369 for( i = strlen(pszBasename)-1; 00370 i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' 00371 && pszBasename[i] != '\\'; 00372 i-- ) {} 00373 00374 if( pszBasename[i] == '.' ) 00375 pszBasename[i] = '\0'; 00376 00377 pszFullname = (char *) malloc(strlen(pszBasename) + 5); 00378 sprintf( pszFullname, "%s.dbf", pszBasename ); 00379 00380 psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) ); 00381 psDBF->fp = psHooks->FOpen( pszFullname, pszAccess ); 00382 memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) ); 00383 00384 if( psDBF->fp == NULL ) 00385 { 00386 sprintf( pszFullname, "%s.DBF", pszBasename ); 00387 psDBF->fp = psDBF->sHooks.FOpen(pszFullname, pszAccess ); 00388 } 00389 00390 free( pszBasename ); 00391 free( pszFullname ); 00392 00393 if( psDBF->fp == NULL ) 00394 { 00395 free( psDBF ); 00396 return( NULL ); 00397 } 00398 00399 psDBF->bNoHeader = FALSE; 00400 psDBF->nCurrentRecord = -1; 00401 psDBF->bCurrentRecordModified = FALSE; 00402 00403 /* -------------------------------------------------------------------- */ 00404 /* Read Table Header info */ 00405 /* -------------------------------------------------------------------- */ 00406 pabyBuf = (unsigned char *) malloc(500); 00407 if( psDBF->sHooks.FRead( pabyBuf, 32, 1, psDBF->fp ) != 1 ) 00408 { 00409 psDBF->sHooks.FClose( psDBF->fp ); 00410 free( pabyBuf ); 00411 free( psDBF ); 00412 return NULL; 00413 } 00414 00415 psDBF->nRecords = 00416 pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256; 00417 00418 psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256; 00419 psDBF->nRecordLength = pabyBuf[10] + pabyBuf[11]*256; 00420 00421 psDBF->nFields = nFields = (nHeadLen - 32) / 32; 00422 00423 psDBF->pszCurrentRecord = (char *) malloc(psDBF->nRecordLength); 00424 00425 /* -------------------------------------------------------------------- */ 00426 /* Read in Field Definitions */ 00427 /* -------------------------------------------------------------------- */ 00428 00429 pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen); 00430 psDBF->pszHeader = (char *) pabyBuf; 00431 00432 psDBF->sHooks.FSeek( psDBF->fp, 32, 0 ); 00433 if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 ) 00434 { 00435 psDBF->sHooks.FClose( psDBF->fp ); 00436 free( pabyBuf ); 00437 free( psDBF->pszCurrentRecord ); 00438 free( psDBF ); 00439 return NULL; 00440 } 00441 00442 psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields); 00443 psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields); 00444 psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields); 00445 psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields); 00446 00447 for( iField = 0; iField < nFields; iField++ ) 00448 { 00449 unsigned char *pabyFInfo; 00450 00451 pabyFInfo = pabyBuf+iField*32; 00452 00453 if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' ) 00454 { 00455 psDBF->panFieldSize[iField] = pabyFInfo[16]; 00456 psDBF->panFieldDecimals[iField] = pabyFInfo[17]; 00457 } 00458 else 00459 { 00460 psDBF->panFieldSize[iField] = pabyFInfo[16]; 00461 psDBF->panFieldDecimals[iField] = 0; 00462 00463 /* 00464 ** The following seemed to be used sometimes to handle files with long 00465 ** string fields, but in other cases (such as bug 1202) the decimals field 00466 ** just seems to indicate some sort of preferred formatting, not very 00467 ** wide fields. So I have disabled this code. FrankW. 00468 psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256; 00469 psDBF->panFieldDecimals[iField] = 0; 00470 */ 00471 } 00472 00473 psDBF->pachFieldType[iField] = (char) pabyFInfo[11]; 00474 if( iField == 0 ) 00475 psDBF->panFieldOffset[iField] = 1; 00476 else 00477 psDBF->panFieldOffset[iField] = 00478 psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1]; 00479 } 00480 00481 return( psDBF ); 00482 } 00483 00484 /************************************************************************/ 00485 /* DBFClose() */ 00486 /************************************************************************/ 00487 00488 void SHPAPI_CALL 00489 DBFClose(DBFHandle psDBF) 00490 { 00491 /* -------------------------------------------------------------------- */ 00492 /* Write out header if not already written. */ 00493 /* -------------------------------------------------------------------- */ 00494 if( psDBF->bNoHeader ) 00495 DBFWriteHeader( psDBF ); 00496 00497 DBFFlushRecord( psDBF ); 00498 00499 /* -------------------------------------------------------------------- */ 00500 /* Update last access date, and number of records if we have */ 00501 /* write access. */ 00502 /* -------------------------------------------------------------------- */ 00503 if( psDBF->bUpdated ) 00504 DBFUpdateHeader( psDBF ); 00505 00506 /* -------------------------------------------------------------------- */ 00507 /* Close, and free resources. */ 00508 /* -------------------------------------------------------------------- */ 00509 psDBF->sHooks.FClose( psDBF->fp ); 00510 00511 if( psDBF->panFieldOffset != NULL ) 00512 { 00513 free( psDBF->panFieldOffset ); 00514 free( psDBF->panFieldSize ); 00515 free( psDBF->panFieldDecimals ); 00516 free( psDBF->pachFieldType ); 00517 } 00518 00519 if( psDBF->pszWorkField != NULL ) 00520 free( psDBF->pszWorkField ); 00521 00522 free( psDBF->pszHeader ); 00523 free( psDBF->pszCurrentRecord ); 00524 00525 free( psDBF ); 00526 } 00527 00528 /************************************************************************/ 00529 /* DBFCreate() */ 00530 /* */ 00531 /* Create a new .dbf file. */ 00532 /************************************************************************/ 00533 00534 DBFHandle SHPAPI_CALL 00535 DBFCreate( const char * pszFilename ) 00536 00537 { 00538 SAHooks sHooks; 00539 00540 SASetupDefaultHooks( &sHooks ); 00541 00542 return DBFCreateLL( pszFilename, &sHooks ); 00543 } 00544 00545 /************************************************************************/ 00546 /* DBFCreate() */ 00547 /* */ 00548 /* Create a new .dbf file. */ 00549 /************************************************************************/ 00550 00551 DBFHandle SHPAPI_CALL 00552 DBFCreateLL( const char * pszFilename, SAHooks *psHooks ) 00553 00554 { 00555 DBFHandle psDBF; 00556 SAFile fp; 00557 char *pszFullname, *pszBasename; 00558 int i; 00559 char chZero = '\0'; 00560 00561 /* -------------------------------------------------------------------- */ 00562 /* Compute the base (layer) name. If there is any extension */ 00563 /* on the passed in filename we will strip it off. */ 00564 /* -------------------------------------------------------------------- */ 00565 pszBasename = (char *) malloc(strlen(pszFilename)+5); 00566 strcpy( pszBasename, pszFilename ); 00567 for( i = strlen(pszBasename)-1; 00568 i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' 00569 && pszBasename[i] != '\\'; 00570 i-- ) {} 00571 00572 if( pszBasename[i] == '.' ) 00573 pszBasename[i] = '\0'; 00574 00575 pszFullname = (char *) malloc(strlen(pszBasename) + 5); 00576 sprintf( pszFullname, "%s.dbf", pszBasename ); 00577 free( pszBasename ); 00578 00579 /* -------------------------------------------------------------------- */ 00580 /* Create the file. */ 00581 /* -------------------------------------------------------------------- */ 00582 fp = psHooks->FOpen( pszFullname, "wb" ); 00583 if( fp == NULL ) 00584 return( NULL ); 00585 00586 psHooks->FWrite( &chZero, 1, 1, fp ); 00587 psHooks->FClose( fp ); 00588 00589 fp = psHooks->FOpen( pszFullname, "rb+" ); 00590 if( fp == NULL ) 00591 return( NULL ); 00592 00593 free( pszFullname ); 00594 00595 /* -------------------------------------------------------------------- */ 00596 /* Create the info structure. */ 00597 /* -------------------------------------------------------------------- */ 00598 psDBF = (DBFHandle) calloc(1,sizeof(DBFInfo)); 00599 00600 memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) ); 00601 psDBF->fp = fp; 00602 psDBF->nRecords = 0; 00603 psDBF->nFields = 0; 00604 psDBF->nRecordLength = 1; 00605 psDBF->nHeaderLength = 33; 00606 00607 psDBF->panFieldOffset = NULL; 00608 psDBF->panFieldSize = NULL; 00609 psDBF->panFieldDecimals = NULL; 00610 psDBF->pachFieldType = NULL; 00611 psDBF->pszHeader = NULL; 00612 00613 psDBF->nCurrentRecord = -1; 00614 psDBF->bCurrentRecordModified = FALSE; 00615 psDBF->pszCurrentRecord = NULL; 00616 00617 psDBF->bNoHeader = TRUE; 00618 00619 return( psDBF ); 00620 } 00621 00622 /************************************************************************/ 00623 /* DBFAddField() */ 00624 /* */ 00625 /* Add a field to a newly created .dbf file before any records */ 00626 /* are written. */ 00627 /************************************************************************/ 00628 00629 int SHPAPI_CALL 00630 DBFAddField(DBFHandle psDBF, const char * pszFieldName, 00631 DBFFieldType eType, int nWidth, int nDecimals ) 00632 00633 { 00634 char chNativeType = 'C'; 00635 00636 if( eType == FTLogical ) 00637 chNativeType = 'L'; 00638 else if( eType == FTString ) 00639 chNativeType = 'C'; 00640 else 00641 chNativeType = 'N'; 00642 00643 return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType, 00644 nWidth, nDecimals ); 00645 } 00646 00647 /************************************************************************/ 00648 /* DBFAddField() */ 00649 /* */ 00650 /* Add a field to a newly created .dbf file before any records */ 00651 /* are written. */ 00652 /************************************************************************/ 00653 00654 int SHPAPI_CALL 00655 DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName, 00656 char chType, int nWidth, int nDecimals ) 00657 00658 { 00659 char *pszFInfo; 00660 int i; 00661 00662 /* -------------------------------------------------------------------- */ 00663 /* Do some checking to ensure we can add records to this file. */ 00664 /* -------------------------------------------------------------------- */ 00665 if( psDBF->nRecords > 0 ) 00666 return( -1 ); 00667 00668 if( !psDBF->bNoHeader ) 00669 return( -1 ); 00670 00671 if( nWidth < 1 ) 00672 return -1; 00673 00674 if( nWidth > 255 ) 00675 nWidth = 255; 00676 00677 /* -------------------------------------------------------------------- */ 00678 /* SfRealloc all the arrays larger to hold the additional field */ 00679 /* information. */ 00680 /* -------------------------------------------------------------------- */ 00681 psDBF->nFields++; 00682 00683 psDBF->panFieldOffset = (int *) 00684 SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ); 00685 00686 psDBF->panFieldSize = (int *) 00687 SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields ); 00688 00689 psDBF->panFieldDecimals = (int *) 00690 SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ); 00691 00692 psDBF->pachFieldType = (char *) 00693 SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields ); 00694 00695 /* -------------------------------------------------------------------- */ 00696 /* Assign the new field information fields. */ 00697 /* -------------------------------------------------------------------- */ 00698 psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength; 00699 psDBF->nRecordLength += nWidth; 00700 psDBF->panFieldSize[psDBF->nFields-1] = nWidth; 00701 psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals; 00702 psDBF->pachFieldType[psDBF->nFields-1] = chType; 00703 00704 /* -------------------------------------------------------------------- */ 00705 /* Extend the required header information. */ 00706 /* -------------------------------------------------------------------- */ 00707 psDBF->nHeaderLength += 32; 00708 psDBF->bUpdated = FALSE; 00709 00710 psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32); 00711 00712 pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1); 00713 00714 for( i = 0; i < 32; i++ ) 00715 pszFInfo[i] = '\0'; 00716 00717 if( (int) strlen(pszFieldName) < 10 ) 00718 strncpy( pszFInfo, pszFieldName, strlen(pszFieldName)); 00719 else 00720 strncpy( pszFInfo, pszFieldName, 10); 00721 00722 pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1]; 00723 00724 if( chType == 'C' ) 00725 { 00726 pszFInfo[16] = (unsigned char) (nWidth % 256); 00727 pszFInfo[17] = (unsigned char) (nWidth / 256); 00728 } 00729 else 00730 { 00731 pszFInfo[16] = (unsigned char) nWidth; 00732 pszFInfo[17] = (unsigned char) nDecimals; 00733 } 00734 00735 /* -------------------------------------------------------------------- */ 00736 /* Make the current record buffer appropriately larger. */ 00737 /* -------------------------------------------------------------------- */ 00738 psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord, 00739 psDBF->nRecordLength); 00740 00741 return( psDBF->nFields-1 ); 00742 } 00743 00744 /************************************************************************/ 00745 /* DBFReadAttribute() */ 00746 /* */ 00747 /* Read one of the attribute fields of a record. */ 00748 /************************************************************************/ 00749 00750 static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField, 00751 char chReqType ) 00752 00753 { 00754 unsigned char *pabyRec; 00755 void *pReturnField = NULL; 00756 00757 /* -------------------------------------------------------------------- */ 00758 /* Verify selection. */ 00759 /* -------------------------------------------------------------------- */ 00760 if( hEntity < 0 || hEntity >= psDBF->nRecords ) 00761 return( NULL ); 00762 00763 if( iField < 0 || iField >= psDBF->nFields ) 00764 return( NULL ); 00765 00766 /* -------------------------------------------------------------------- */ 00767 /* Have we read the record? */ 00768 /* -------------------------------------------------------------------- */ 00769 if( !DBFLoadRecord( psDBF, hEntity ) ) 00770 return NULL; 00771 00772 pabyRec = (unsigned char *) psDBF->pszCurrentRecord; 00773 00774 /* -------------------------------------------------------------------- */ 00775 /* Ensure we have room to extract the target field. */ 00776 /* -------------------------------------------------------------------- */ 00777 if( psDBF->panFieldSize[iField] >= psDBF->nWorkFieldLength ) 00778 { 00779 psDBF->nWorkFieldLength = psDBF->panFieldSize[iField] + 100; 00780 if( psDBF->pszWorkField == NULL ) 00781 psDBF->pszWorkField = (char *) malloc(psDBF->nWorkFieldLength); 00782 else 00783 psDBF->pszWorkField = (char *) realloc(psDBF->pszWorkField, 00784 psDBF->nWorkFieldLength); 00785 } 00786 00787 /* -------------------------------------------------------------------- */ 00788 /* Extract the requested field. */ 00789 /* -------------------------------------------------------------------- */ 00790 strncpy( psDBF->pszWorkField, 00791 ((const char *) pabyRec) + psDBF->panFieldOffset[iField], 00792 psDBF->panFieldSize[iField] ); 00793 psDBF->pszWorkField[psDBF->panFieldSize[iField]] = '\0'; 00794 00795 pReturnField = psDBF->pszWorkField; 00796 00797 /* -------------------------------------------------------------------- */ 00798 /* Decode the field. */ 00799 /* -------------------------------------------------------------------- */ 00800 if( chReqType == 'N' ) 00801 { 00802 psDBF->dfDoubleField = atof(psDBF->pszWorkField); 00803 00804 pReturnField = &(psDBF->dfDoubleField); 00805 } 00806 00807 /* -------------------------------------------------------------------- */ 00808 /* Should we trim white space off the string attribute value? */ 00809 /* -------------------------------------------------------------------- */ 00810 #ifdef TRIM_DBF_WHITESPACE 00811 else 00812 { 00813 char *pchSrc, *pchDst; 00814 00815 pchDst = pchSrc = psDBF->pszWorkField; 00816 while( *pchSrc == ' ' ) 00817 pchSrc++; 00818 00819 while( *pchSrc != '\0' ) 00820 *(pchDst++) = *(pchSrc++); 00821 *pchDst = '\0'; 00822 00823 while( pchDst != psDBF->pszWorkField && *(--pchDst) == ' ' ) 00824 *pchDst = '\0'; 00825 } 00826 #endif 00827 00828 return( pReturnField ); 00829 } 00830 00831 /************************************************************************/ 00832 /* DBFReadIntAttribute() */ 00833 /* */ 00834 /* Read an integer attribute. */ 00835 /************************************************************************/ 00836 00837 int SHPAPI_CALL 00838 DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField ) 00839 00840 { 00841 double *pdValue; 00842 00843 pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' ); 00844 00845 if( pdValue == NULL ) 00846 return 0; 00847 else 00848 return( (int) *pdValue ); 00849 } 00850 00851 /************************************************************************/ 00852 /* DBFReadDoubleAttribute() */ 00853 /* */ 00854 /* Read a double attribute. */ 00855 /************************************************************************/ 00856 00857 double SHPAPI_CALL 00858 DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField ) 00859 00860 { 00861 double *pdValue; 00862 00863 pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' ); 00864 00865 if( pdValue == NULL ) 00866 return 0.0; 00867 else 00868 return( *pdValue ); 00869 } 00870 00871 /************************************************************************/ 00872 /* DBFReadStringAttribute() */ 00873 /* */ 00874 /* Read a string attribute. */ 00875 /************************************************************************/ 00876 00877 const char SHPAPI_CALL1(*) 00878 DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField ) 00879 00880 { 00881 return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) ); 00882 } 00883 00884 /************************************************************************/ 00885 /* DBFReadLogicalAttribute() */ 00886 /* */ 00887 /* Read a logical attribute. */ 00888 /************************************************************************/ 00889 00890 const char SHPAPI_CALL1(*) 00891 DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField ) 00892 00893 { 00894 return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) ); 00895 } 00896 00897 /************************************************************************/ 00898 /* DBFIsAttributeNULL() */ 00899 /* */ 00900 /* Return TRUE if value for field is NULL. */ 00901 /* */ 00902 /* Contributed by Jim Matthews. */ 00903 /************************************************************************/ 00904 00905 int SHPAPI_CALL 00906 DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField ) 00907 00908 { 00909 const char *pszValue; 00910 int i; 00911 00912 pszValue = DBFReadStringAttribute( psDBF, iRecord, iField ); 00913 00914 if( pszValue == NULL ) 00915 return TRUE; 00916 00917 switch(psDBF->pachFieldType[iField]) 00918 { 00919 case 'N': 00920 case 'F': 00921 /* 00922 ** We accept all asterisks or all blanks as NULL 00923 ** though according to the spec I think it should be all 00924 ** asterisks. 00925 */ 00926 if( pszValue[0] == '*' ) 00927 return TRUE; 00928 00929 for( i = 0; pszValue[i] != '\0'; i++ ) 00930 { 00931 if( pszValue[i] != ' ' ) 00932 return FALSE; 00933 } 00934 return TRUE; 00935 00936 case 'D': 00937 /* NULL date fields have value "00000000" */ 00938 return strncmp(pszValue,"00000000",8) == 0; 00939 00940 case 'L': 00941 /* NULL boolean fields have value "?" */ 00942 return pszValue[0] == '?'; 00943 00944 default: 00945 /* empty string fields are considered NULL */ 00946 return strlen(pszValue) == 0; 00947 } 00948 } 00949 00950 /************************************************************************/ 00951 /* DBFGetFieldCount() */ 00952 /* */ 00953 /* Return the number of fields in this table. */ 00954 /************************************************************************/ 00955 00956 int SHPAPI_CALL 00957 DBFGetFieldCount( DBFHandle psDBF ) 00958 00959 { 00960 return( psDBF->nFields ); 00961 } 00962 00963 /************************************************************************/ 00964 /* DBFGetRecordCount() */ 00965 /* */ 00966 /* Return the number of records in this table. */ 00967 /************************************************************************/ 00968 00969 int SHPAPI_CALL 00970 DBFGetRecordCount( DBFHandle psDBF ) 00971 00972 { 00973 return( psDBF->nRecords ); 00974 } 00975 00976 /************************************************************************/ 00977 /* DBFGetFieldInfo() */ 00978 /* */ 00979 /* Return any requested information about the field. */ 00980 /************************************************************************/ 00981 00982 DBFFieldType SHPAPI_CALL 00983 DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName, 00984 int * pnWidth, int * pnDecimals ) 00985 00986 { 00987 if( iField < 0 || iField >= psDBF->nFields ) 00988 return( FTInvalid ); 00989 00990 if( pnWidth != NULL ) 00991 *pnWidth = psDBF->panFieldSize[iField]; 00992 00993 if( pnDecimals != NULL ) 00994 *pnDecimals = psDBF->panFieldDecimals[iField]; 00995 00996 if( pszFieldName != NULL ) 00997 { 00998 int i; 00999 01000 strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 ); 01001 pszFieldName[11] = '\0'; 01002 for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- ) 01003 pszFieldName[i] = '\0'; 01004 } 01005 01006 if ( psDBF->pachFieldType[iField] == 'L' ) 01007 return( FTLogical); 01008 01009 else if( psDBF->pachFieldType[iField] == 'N' 01010 || psDBF->pachFieldType[iField] == 'F' ) 01011 { 01012 if( psDBF->panFieldDecimals[iField] > 0 ) 01013 /* || psDBF->panFieldSize[iField] > 10 ) */ /* GDAL bug #809 */ 01014 return( FTDouble ); 01015 else 01016 return( FTInteger ); 01017 } 01018 else 01019 { 01020 return( FTString ); 01021 } 01022 } 01023 01024 /************************************************************************/ 01025 /* DBFWriteAttribute() */ 01026 /* */ 01027 /* Write an attribute record to the file. */ 01028 /************************************************************************/ 01029 01030 static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField, 01031 void * pValue ) 01032 01033 { 01034 int i, j, nRetResult = TRUE; 01035 unsigned char *pabyRec; 01036 char szSField[400], szFormat[20]; 01037 01038 /* -------------------------------------------------------------------- */ 01039 /* Is this a valid record? */ 01040 /* -------------------------------------------------------------------- */ 01041 if( hEntity < 0 || hEntity > psDBF->nRecords ) 01042 return( FALSE ); 01043 01044 if( psDBF->bNoHeader ) 01045 DBFWriteHeader(psDBF); 01046 01047 /* -------------------------------------------------------------------- */ 01048 /* Is this a brand new record? */ 01049 /* -------------------------------------------------------------------- */ 01050 if( hEntity == psDBF->nRecords ) 01051 { 01052 if( !DBFFlushRecord( psDBF ) ) 01053 return FALSE; 01054 01055 psDBF->nRecords++; 01056 for( i = 0; i < psDBF->nRecordLength; i++ ) 01057 psDBF->pszCurrentRecord[i] = ' '; 01058 01059 psDBF->nCurrentRecord = hEntity; 01060 } 01061 01062 /* -------------------------------------------------------------------- */ 01063 /* Is this an existing record, but different than the last one */ 01064 /* we accessed? */ 01065 /* -------------------------------------------------------------------- */ 01066 if( !DBFLoadRecord( psDBF, hEntity ) ) 01067 return FALSE; 01068 01069 pabyRec = (unsigned char *) psDBF->pszCurrentRecord; 01070 01071 psDBF->bCurrentRecordModified = TRUE; 01072 psDBF->bUpdated = TRUE; 01073 01074 /* -------------------------------------------------------------------- */ 01075 /* Translate NULL value to valid DBF file representation. */ 01076 /* */ 01077 /* Contributed by Jim Matthews. */ 01078 /* -------------------------------------------------------------------- */ 01079 if( pValue == NULL ) 01080 { 01081 switch(psDBF->pachFieldType[iField]) 01082 { 01083 case 'N': 01084 case 'F': 01085 /* NULL numeric fields have value "****************" */ 01086 memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*', 01087 psDBF->panFieldSize[iField] ); 01088 break; 01089 01090 case 'D': 01091 /* NULL date fields have value "00000000" */ 01092 memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0', 01093 psDBF->panFieldSize[iField] ); 01094 break; 01095 01096 case 'L': 01097 /* NULL boolean fields have value "?" */ 01098 memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?', 01099 psDBF->panFieldSize[iField] ); 01100 break; 01101 01102 default: 01103 /* empty string fields are considered NULL */ 01104 memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), ' ', 01105 psDBF->panFieldSize[iField] ); 01106 break; 01107 } 01108 return TRUE; 01109 } 01110 01111 /* -------------------------------------------------------------------- */ 01112 /* Assign all the record fields. */ 01113 /* -------------------------------------------------------------------- */ 01114 switch( psDBF->pachFieldType[iField] ) 01115 { 01116 case 'D': 01117 case 'N': 01118 case 'F': 01119 if( psDBF->panFieldDecimals[iField] == 0 ) 01120 { 01121 int nWidth = psDBF->panFieldSize[iField]; 01122 01123 if( (int) sizeof(szSField)-2 < nWidth ) 01124 nWidth = sizeof(szSField)-2; 01125 01126 sprintf( szFormat, "%%%dd", nWidth ); 01127 sprintf(szSField, szFormat, (int) *((double *) pValue) ); 01128 if( (int)strlen(szSField) > psDBF->panFieldSize[iField] ) 01129 { 01130 szSField[psDBF->panFieldSize[iField]] = '\0'; 01131 nRetResult = FALSE; 01132 } 01133 01134 strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), 01135 szSField, strlen(szSField) ); 01136 } 01137 else 01138 { 01139 int nWidth = psDBF->panFieldSize[iField]; 01140 01141 if( (int) sizeof(szSField)-2 < nWidth ) 01142 nWidth = sizeof(szSField)-2; 01143 01144 sprintf( szFormat, "%%%d.%df", 01145 nWidth, psDBF->panFieldDecimals[iField] ); 01146 sprintf(szSField, szFormat, *((double *) pValue) ); 01147 if( (int) strlen(szSField) > psDBF->panFieldSize[iField] ) 01148 { 01149 szSField[psDBF->panFieldSize[iField]] = '\0'; 01150 nRetResult = FALSE; 01151 } 01152 strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), 01153 szSField, strlen(szSField) ); 01154 } 01155 break; 01156 01157 case 'L': 01158 if (psDBF->panFieldSize[iField] >= 1 && 01159 (*(char*)pValue == 'F' || *(char*)pValue == 'T')) 01160 *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue; 01161 break; 01162 01163 default: 01164 if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] ) 01165 { 01166 j = psDBF->panFieldSize[iField]; 01167 nRetResult = FALSE; 01168 } 01169 else 01170 { 01171 memset( pabyRec+psDBF->panFieldOffset[iField], ' ', 01172 psDBF->panFieldSize[iField] ); 01173 j = strlen((char *) pValue); 01174 } 01175 01176 strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), 01177 (char *) pValue, j ); 01178 break; 01179 } 01180 01181 return( nRetResult ); 01182 } 01183 01184 /************************************************************************/ 01185 /* DBFWriteAttributeDirectly() */ 01186 /* */ 01187 /* Write an attribute record to the file, but without any */ 01188 /* reformatting based on type. The provided buffer is written */ 01189 /* as is to the field position in the record. */ 01190 /************************************************************************/ 01191 01192 int SHPAPI_CALL 01193 DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField, 01194 void * pValue ) 01195 01196 { 01197 int i, j; 01198 unsigned char *pabyRec; 01199 01200 /* -------------------------------------------------------------------- */ 01201 /* Is this a valid record? */ 01202 /* -------------------------------------------------------------------- */ 01203 if( hEntity < 0 || hEntity > psDBF->nRecords ) 01204 return( FALSE ); 01205 01206 if( psDBF->bNoHeader ) 01207 DBFWriteHeader(psDBF); 01208 01209 /* -------------------------------------------------------------------- */ 01210 /* Is this a brand new record? */ 01211 /* -------------------------------------------------------------------- */ 01212 if( hEntity == psDBF->nRecords ) 01213 { 01214 if( !DBFFlushRecord( psDBF ) ) 01215 return FALSE; 01216 01217 psDBF->nRecords++; 01218 for( i = 0; i < psDBF->nRecordLength; i++ ) 01219 psDBF->pszCurrentRecord[i] = ' '; 01220 01221 psDBF->nCurrentRecord = hEntity; 01222 } 01223 01224 /* -------------------------------------------------------------------- */ 01225 /* Is this an existing record, but different than the last one */ 01226 /* we accessed? */ 01227 /* -------------------------------------------------------------------- */ 01228 if( !DBFLoadRecord( psDBF, hEntity ) ) 01229 return FALSE; 01230 01231 pabyRec = (unsigned char *) psDBF->pszCurrentRecord; 01232 01233 /* -------------------------------------------------------------------- */ 01234 /* Assign all the record fields. */ 01235 /* -------------------------------------------------------------------- */ 01236 if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] ) 01237 j = psDBF->panFieldSize[iField]; 01238 else 01239 { 01240 memset( pabyRec+psDBF->panFieldOffset[iField], ' ', 01241 psDBF->panFieldSize[iField] ); 01242 j = strlen((char *) pValue); 01243 } 01244 01245 strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), 01246 (char *) pValue, j ); 01247 01248 psDBF->bCurrentRecordModified = TRUE; 01249 psDBF->bUpdated = TRUE; 01250 01251 return( TRUE ); 01252 } 01253 01254 /************************************************************************/ 01255 /* DBFWriteDoubleAttribute() */ 01256 /* */ 01257 /* Write a double attribute. */ 01258 /************************************************************************/ 01259 01260 int SHPAPI_CALL 01261 DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField, 01262 double dValue ) 01263 01264 { 01265 return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) ); 01266 } 01267 01268 /************************************************************************/ 01269 /* DBFWriteIntegerAttribute() */ 01270 /* */ 01271 /* Write a integer attribute. */ 01272 /************************************************************************/ 01273 01274 int SHPAPI_CALL 01275 DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField, 01276 int nValue ) 01277 01278 { 01279 double dValue = nValue; 01280 01281 return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) ); 01282 } 01283 01284 /************************************************************************/ 01285 /* DBFWriteStringAttribute() */ 01286 /* */ 01287 /* Write a string attribute. */ 01288 /************************************************************************/ 01289 01290 int SHPAPI_CALL 01291 DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField, 01292 const char * pszValue ) 01293 01294 { 01295 return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) ); 01296 } 01297 01298 /************************************************************************/ 01299 /* DBFWriteNULLAttribute() */ 01300 /* */ 01301 /* Write a string attribute. */ 01302 /************************************************************************/ 01303 01304 int SHPAPI_CALL 01305 DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField ) 01306 01307 { 01308 return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) ); 01309 } 01310 01311 /************************************************************************/ 01312 /* DBFWriteLogicalAttribute() */ 01313 /* */ 01314 /* Write a logical attribute. */ 01315 /************************************************************************/ 01316 01317 int SHPAPI_CALL 01318 DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField, 01319 const char lValue) 01320 01321 { 01322 return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) ); 01323 } 01324 01325 /************************************************************************/ 01326 /* DBFWriteTuple() */ 01327 /* */ 01328 /* Write an attribute record to the file. */ 01329 /************************************************************************/ 01330 01331 int SHPAPI_CALL 01332 DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple ) 01333 01334 { 01335 int i; 01336 unsigned char *pabyRec; 01337 01338 /* -------------------------------------------------------------------- */ 01339 /* Is this a valid record? */ 01340 /* -------------------------------------------------------------------- */ 01341 if( hEntity < 0 || hEntity > psDBF->nRecords ) 01342 return( FALSE ); 01343 01344 if( psDBF->bNoHeader ) 01345 DBFWriteHeader(psDBF); 01346 01347 /* -------------------------------------------------------------------- */ 01348 /* Is this a brand new record? */ 01349 /* -------------------------------------------------------------------- */ 01350 if( hEntity == psDBF->nRecords ) 01351 { 01352 if( !DBFFlushRecord( psDBF ) ) 01353 return FALSE; 01354 01355 psDBF->nRecords++; 01356 for( i = 0; i < psDBF->nRecordLength; i++ ) 01357 psDBF->pszCurrentRecord[i] = ' '; 01358 01359 psDBF->nCurrentRecord = hEntity; 01360 } 01361 01362 /* -------------------------------------------------------------------- */ 01363 /* Is this an existing record, but different than the last one */ 01364 /* we accessed? */ 01365 /* -------------------------------------------------------------------- */ 01366 if( !DBFLoadRecord( psDBF, hEntity ) ) 01367 return FALSE; 01368 01369 pabyRec = (unsigned char *) psDBF->pszCurrentRecord; 01370 01371 memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength ); 01372 01373 psDBF->bCurrentRecordModified = TRUE; 01374 psDBF->bUpdated = TRUE; 01375 01376 return( TRUE ); 01377 } 01378 01379 /************************************************************************/ 01380 /* DBFReadTuple() */ 01381 /* */ 01382 /* Read a complete record. Note that the result is only valid */ 01383 /* till the next record read for any reason. */ 01384 /************************************************************************/ 01385 01386 const char SHPAPI_CALL1(*) 01387 DBFReadTuple(DBFHandle psDBF, int hEntity ) 01388 01389 { 01390 if( hEntity < 0 || hEntity >= psDBF->nRecords ) 01391 return( NULL ); 01392 01393 if( !DBFLoadRecord( psDBF, hEntity ) ) 01394 return NULL; 01395 01396 return (const char *) psDBF->pszCurrentRecord; 01397 } 01398 01399 /************************************************************************/ 01400 /* DBFCloneEmpty() */ 01401 /* */ 01402 /* Read one of the attribute fields of a record. */ 01403 /************************************************************************/ 01404 01405 DBFHandle SHPAPI_CALL 01406 DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename ) 01407 { 01408 DBFHandle newDBF; 01409 01410 newDBF = DBFCreate ( pszFilename ); 01411 if ( newDBF == NULL ) return ( NULL ); 01412 01413 newDBF->nFields = psDBF->nFields; 01414 newDBF->nRecordLength = psDBF->nRecordLength; 01415 newDBF->nHeaderLength = psDBF->nHeaderLength; 01416 01417 newDBF->pszHeader = (char *) malloc ( newDBF->nHeaderLength ); 01418 memcpy ( newDBF->pszHeader, psDBF->pszHeader, newDBF->nHeaderLength ); 01419 01420 newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields ); 01421 memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ); 01422 newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields ); 01423 memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields ); 01424 newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields ); 01425 memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ); 01426 newDBF->pachFieldType = (char *) malloc ( sizeof(char) * psDBF->nFields ); 01427 memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(char)*psDBF->nFields ); 01428 01429 newDBF->bNoHeader = TRUE; 01430 newDBF->bUpdated = TRUE; 01431 01432 DBFWriteHeader ( newDBF ); 01433 DBFClose ( newDBF ); 01434 01435 newDBF = DBFOpen ( pszFilename, "rb+" ); 01436 01437 return ( newDBF ); 01438 } 01439 01440 /************************************************************************/ 01441 /* DBFGetNativeFieldType() */ 01442 /* */ 01443 /* Return the DBase field type for the specified field. */ 01444 /* */ 01445 /* Value can be one of: 'C' (String), 'D' (Date), 'F' (Float), */ 01446 /* 'N' (Numeric, with or without decimal), */ 01447 /* 'L' (Logical), */ 01448 /* 'M' (Memo: 10 digits .DBT block ptr) */ 01449 /************************************************************************/ 01450 01451 char SHPAPI_CALL 01452 DBFGetNativeFieldType( DBFHandle psDBF, int iField ) 01453 01454 { 01455 if( iField >=0 && iField < psDBF->nFields ) 01456 return psDBF->pachFieldType[iField]; 01457 01458 return ' '; 01459 } 01460 01461 /************************************************************************/ 01462 /* str_to_upper() */ 01463 /************************************************************************/ 01464 01465 static void str_to_upper (char *string) 01466 { 01467 int len; 01468 short i = -1; 01469 01470 len = strlen (string); 01471 01472 while (++i < len) 01473 if (isalpha(string[i]) && islower(string[i])) 01474 string[i] = (char) toupper ((int)string[i]); 01475 } 01476 01477 /************************************************************************/ 01478 /* DBFGetFieldIndex() */ 01479 /* */ 01480 /* Get the index number for a field in a .dbf file. */ 01481 /* */ 01482 /* Contributed by Jim Matthews. */ 01483 /************************************************************************/ 01484 01485 int SHPAPI_CALL 01486 DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName) 01487 01488 { 01489 char name[12], name1[12], name2[12]; 01490 int i; 01491 01492 strncpy(name1, pszFieldName,11); 01493 name1[11] = '\0'; 01494 str_to_upper(name1); 01495 01496 for( i = 0; i < DBFGetFieldCount(psDBF); i++ ) 01497 { 01498 DBFGetFieldInfo( psDBF, i, name, NULL, NULL ); 01499 strncpy(name2,name,11); 01500 str_to_upper(name2); 01501 01502 if(!strncmp(name1,name2,10)) 01503 return(i); 01504 } 01505 return(-1); 01506 } 01507 01508 /************************************************************************/ 01509 /* DBFIsRecordDeleted() */ 01510 /* */ 01511 /* Returns TRUE if the indicated record is deleted, otherwise */ 01512 /* it returns FALSE. */ 01513 /************************************************************************/ 01514 01515 int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape ) 01516 01517 { 01518 /* -------------------------------------------------------------------- */ 01519 /* Verify selection. */ 01520 /* -------------------------------------------------------------------- */ 01521 if( iShape < 0 || iShape >= psDBF->nRecords ) 01522 return TRUE; 01523 01524 /* -------------------------------------------------------------------- */ 01525 /* Have we read the record? */ 01526 /* -------------------------------------------------------------------- */ 01527 if( !DBFLoadRecord( psDBF, iShape ) ) 01528 return FALSE; 01529 01530 /* -------------------------------------------------------------------- */ 01531 /* '*' means deleted. */ 01532 /* -------------------------------------------------------------------- */ 01533 return psDBF->pszCurrentRecord[0] == '*'; 01534 } 01535 01536 /************************************************************************/ 01537 /* DBFMarkRecordDeleted() */ 01538 /************************************************************************/ 01539 01540 int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape, 01541 int bIsDeleted ) 01542 01543 { 01544 char chNewFlag; 01545 01546 /* -------------------------------------------------------------------- */ 01547 /* Verify selection. */ 01548 /* -------------------------------------------------------------------- */ 01549 if( iShape < 0 || iShape >= psDBF->nRecords ) 01550 return FALSE; 01551 01552 /* -------------------------------------------------------------------- */ 01553 /* Is this an existing record, but different than the last one */ 01554 /* we accessed? */ 01555 /* -------------------------------------------------------------------- */ 01556 if( !DBFLoadRecord( psDBF, iShape ) ) 01557 return FALSE; 01558 01559 /* -------------------------------------------------------------------- */ 01560 /* Assign value, marking record as dirty if it changes. */ 01561 /* -------------------------------------------------------------------- */ 01562 if( bIsDeleted ) 01563 chNewFlag = '*'; 01564 else 01565 chNewFlag = ' '; 01566 01567 if( psDBF->pszCurrentRecord[0] != chNewFlag ) 01568 { 01569 psDBF->bCurrentRecordModified = TRUE; 01570 psDBF->bUpdated = TRUE; 01571 psDBF->pszCurrentRecord[0] = chNewFlag; 01572 } 01573 01574 return TRUE; 01575 }