1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260 |
- /******************************************************************************
- * $Id$
- *
- * Project: Shapelib
- * Purpose: Implementation of .dbf access API documented in dbf_api.html.
- * Author: Frank Warmerdam, warmerdam@pobox.com
- *
- ******************************************************************************
- * Copyright (c) 1999, Frank Warmerdam
- * Copyright (c) 2012-2013, Even Rouault <even dot rouault at mines-paris dot org>
- *
- * This software is available under the following "MIT Style" license,
- * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
- * option is discussed in more detail in shapelib.html.
- *
- * --
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- ******************************************************************************
- *
- * $Log: dbfopen.c,v $
- * Revision 1.89 2011-07-24 05:59:25 fwarmerdam
- * minimize use of CPLError in favor of SAHooks.Error()
- *
- * Revision 1.88 2011-05-13 17:35:17 fwarmerdam
- * added DBFReorderFields() and DBFAlterFields() functions (from Even)
- *
- * Revision 1.87 2011-05-07 22:41:02 fwarmerdam
- * ensure pending record is flushed when adding a native field (GDAL #4073)
- *
- * Revision 1.86 2011-04-17 15:15:29 fwarmerdam
- * Removed unused variable.
- *
- * Revision 1.85 2010-12-06 16:09:34 fwarmerdam
- * fix buffer read overrun fetching code page (bug 2276)
- *
- * Revision 1.84 2009-10-29 19:59:48 fwarmerdam
- * avoid crash on truncated header (gdal #3093)
- *
- * Revision 1.83 2008/11/12 14:28:15 fwarmerdam
- * DBFCreateField() now works on files with records
- *
- * Revision 1.82 2008/11/11 17:47:09 fwarmerdam
- * added DBFDeleteField() function
- *
- * Revision 1.81 2008/01/03 17:48:13 bram
- * in DBFCreate, use default code page LDID/87 (= 0x57, ANSI)
- * instead of LDID/3. This seems to be the same as what ESRI
- * would be doing by default.
- *
- * Revision 1.80 2007/12/30 14:36:39 fwarmerdam
- * avoid syntax issue with last comment.
- *
- * Revision 1.79 2007/12/30 14:35:48 fwarmerdam
- * Avoid char* / unsigned char* warnings.
- *
- * Revision 1.78 2007/12/18 18:28:07 bram
- * - create hook for client specific atof (bugzilla ticket 1615)
- * - check for NULL handle before closing cpCPG file, and close after reading.
- *
- * Revision 1.77 2007/12/15 20:25:21 bram
- * dbfopen.c now reads the Code Page information from the DBF file, and exports
- * this information as a string through the DBFGetCodePage function. This is
- * either the number from the LDID header field ("LDID/<number>") or as the
- * content of an accompanying .CPG file. When creating a DBF file, the code can
- * be set using DBFCreateEx.
- *
- * Revision 1.76 2007/12/12 22:21:32 bram
- * DBFClose: check for NULL psDBF handle before trying to close it.
- *
- * Revision 1.75 2007/12/06 13:58:19 fwarmerdam
- * make sure file offset calculations are done in as SAOffset
- *
- * Revision 1.74 2007/12/06 07:00:25 fwarmerdam
- * dbfopen now using SAHooks for fileio
- *
- * Revision 1.73 2007/09/03 19:48:11 fwarmerdam
- * move DBFReadAttribute() static dDoubleField into dbfinfo
- *
- * Revision 1.72 2007/09/03 19:34:06 fwarmerdam
- * Avoid use of static tuple buffer in DBFReadTuple()
- *
- * Revision 1.71 2006/06/22 14:37:18 fwarmerdam
- * avoid memory leak if dbfopen fread fails
- *
- * Revision 1.70 2006/06/17 17:47:05 fwarmerdam
- * use calloc() for dbfinfo in DBFCreate
- *
- * Revision 1.69 2006/06/17 15:34:32 fwarmerdam
- * disallow creating fields wider than 255
- *
- * Revision 1.68 2006/06/17 15:12:40 fwarmerdam
- * Fixed C++ style comments.
- *
- * Revision 1.67 2006/06/17 00:24:53 fwarmerdam
- * Don't treat non-zero decimals values as high order byte for length
- * for strings. It causes serious corruption for some files.
- * http://bugzilla.remotesensing.org/show_bug.cgi?id=1202
- *
- * Revision 1.66 2006/03/29 18:26:20 fwarmerdam
- * fixed bug with size of pachfieldtype in dbfcloneempty
- *
- * Revision 1.65 2006/02/15 01:14:30 fwarmerdam
- * added DBFAddNativeFieldType
- *
- * Revision 1.64 2006/02/09 00:29:04 fwarmerdam
- * Changed to put spaces into string fields that are NULL as
- * per http://bugzilla.maptools.org/show_bug.cgi?id=316.
- *
- * Revision 1.63 2006/01/25 15:35:43 fwarmerdam
- * check success on DBFFlushRecord
- *
- * Revision 1.62 2006/01/10 16:28:03 fwarmerdam
- * Fixed typo in CPLError.
- *
- * Revision 1.61 2006/01/10 16:26:29 fwarmerdam
- * Push loading record buffer into DBFLoadRecord.
- * Implement CPL error reporting if USE_CPL defined.
- *
- * Revision 1.60 2006/01/05 01:27:27 fwarmerdam
- * added dbf deletion mark/fetch
- *
- * Revision 1.59 2005/03/14 15:20:28 fwarmerdam
- * Fixed last change.
- *
- * Revision 1.58 2005/03/14 15:18:54 fwarmerdam
- * Treat very wide fields with no decimals as double. This is
- * more than 32bit integer fields.
- *
- * Revision 1.57 2005/02/10 20:16:54 fwarmerdam
- * Make the pszStringField buffer for DBFReadAttribute() static char [256]
- * as per bug 306.
- *
- * Revision 1.56 2005/02/10 20:07:56 fwarmerdam
- * Fixed bug 305 in DBFCloneEmpty() - header length problem.
- *
- * Revision 1.55 2004/09/26 20:23:46 fwarmerdam
- * avoid warnings with rcsid and signed/unsigned stuff
- *
- * Revision 1.54 2004/09/15 16:26:10 fwarmerdam
- * Treat all blank numeric fields as null too.
- */
- #include <grass/shapefil.h>
- #include <math.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <string.h>
- #ifdef USE_CPL
- #include "cpl_string.h"
- #else
- #define CPLsprintf sprintf
- #endif
- #if defined(WIN32) || defined(_WIN32)
- # ifndef snprintf
- # define snprintf _snprintf
- # endif
- #endif
- SHP_CVSID("$Id$")
- #ifndef FALSE
- # define FALSE 0
- # define TRUE 1
- #endif
- /************************************************************************/
- /* SfRealloc() */
- /* */
- /* A realloc cover function that will access a NULL pointer as */
- /* a valid input. */
- /************************************************************************/
- static void * SfRealloc( void * pMem, int nNewSize )
- {
- if( pMem == NULL )
- return( (void *) malloc(nNewSize) );
- else
- return( (void *) realloc(pMem,nNewSize) );
- }
- /************************************************************************/
- /* DBFWriteHeader() */
- /* */
- /* This is called to write out the file header, and field */
- /* descriptions before writing any actual data records. This */
- /* also computes all the DBFDataSet field offset/size/decimals */
- /* and so forth values. */
- /************************************************************************/
- static void DBFWriteHeader(DBFHandle psDBF)
- {
- unsigned char abyHeader[XBASE_FLDHDR_SZ];
- int i;
- if( !psDBF->bNoHeader )
- return;
- psDBF->bNoHeader = FALSE;
- /* -------------------------------------------------------------------- */
- /* Initialize the file header information. */
- /* -------------------------------------------------------------------- */
- for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
- abyHeader[i] = 0;
- abyHeader[0] = 0x03; /* memo field? - just copying */
- /* write out update date */
- abyHeader[1] = (unsigned char) psDBF->nUpdateYearSince1900;
- abyHeader[2] = (unsigned char) psDBF->nUpdateMonth;
- abyHeader[3] = (unsigned char) psDBF->nUpdateDay;
- /* record count preset at zero */
- abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
- abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
- abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
- abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
- abyHeader[29] = (unsigned char) (psDBF->iLanguageDriver);
- /* -------------------------------------------------------------------- */
- /* Write the initial 32 byte file header, and all the field */
- /* descriptions. */
- /* -------------------------------------------------------------------- */
- psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
- psDBF->sHooks.FWrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
- psDBF->sHooks.FWrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields,
- psDBF->fp );
- /* -------------------------------------------------------------------- */
- /* Write out the newline character if there is room for it. */
- /* -------------------------------------------------------------------- */
- if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
- {
- char cNewline;
- cNewline = 0x0d;
- psDBF->sHooks.FWrite( &cNewline, 1, 1, psDBF->fp );
- }
- }
- /************************************************************************/
- /* DBFFlushRecord() */
- /* */
- /* Write out the current record if there is one. */
- /************************************************************************/
- static int DBFFlushRecord( DBFHandle psDBF )
- {
- SAOffset nRecordOffset;
- if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )
- {
- psDBF->bCurrentRecordModified = FALSE;
- nRecordOffset =
- psDBF->nRecordLength * (SAOffset) psDBF->nCurrentRecord
- + psDBF->nHeaderLength;
- if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ) != 0
- || psDBF->sHooks.FWrite( psDBF->pszCurrentRecord,
- psDBF->nRecordLength,
- 1, psDBF->fp ) != 1 )
- {
- char szMessage[128];
- snprintf( szMessage, sizeof(szMessage), "Failure writing DBF record %d.",
- psDBF->nCurrentRecord );
- psDBF->sHooks.Error( szMessage );
- return FALSE;
- }
- }
- return TRUE;
- }
- /************************************************************************/
- /* DBFLoadRecord() */
- /************************************************************************/
- static int DBFLoadRecord( DBFHandle psDBF, int iRecord )
- {
- if( psDBF->nCurrentRecord != iRecord )
- {
- SAOffset nRecordOffset;
- if( !DBFFlushRecord( psDBF ) )
- return FALSE;
- nRecordOffset =
- psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
- if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, SEEK_SET ) != 0 )
- {
- char szMessage[128];
- snprintf( szMessage, sizeof(szMessage), "fseek(%ld) failed on DBF file.\n",
- (long) nRecordOffset );
- psDBF->sHooks.Error( szMessage );
- return FALSE;
- }
- if( psDBF->sHooks.FRead( psDBF->pszCurrentRecord,
- psDBF->nRecordLength, 1, psDBF->fp ) != 1 )
- {
- char szMessage[128];
- snprintf( szMessage, sizeof(szMessage), "fread(%d) failed on DBF file.\n",
- psDBF->nRecordLength );
- psDBF->sHooks.Error( szMessage );
- return FALSE;
- }
- psDBF->nCurrentRecord = iRecord;
- }
- return TRUE;
- }
- /************************************************************************/
- /* DBFUpdateHeader() */
- /************************************************************************/
- void SHPAPI_CALL
- DBFUpdateHeader( DBFHandle psDBF )
- {
- unsigned char abyFileHeader[32];
- if( psDBF->bNoHeader )
- DBFWriteHeader( psDBF );
- if( !DBFFlushRecord( psDBF ) )
- return;
- psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
- psDBF->sHooks.FRead( abyFileHeader, 32, 1, psDBF->fp );
- abyFileHeader[1] = (unsigned char) psDBF->nUpdateYearSince1900;
- abyFileHeader[2] = (unsigned char) psDBF->nUpdateMonth;
- abyFileHeader[3] = (unsigned char) psDBF->nUpdateDay;
- abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256);
- abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256);
- abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256);
- abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256);
- psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
- psDBF->sHooks.FWrite( abyFileHeader, 32, 1, psDBF->fp );
- psDBF->sHooks.FFlush( psDBF->fp );
- }
- /************************************************************************/
- /* DBFSetLastModifiedDate() */
- /************************************************************************/
- void SHPAPI_CALL
- DBFSetLastModifiedDate( DBFHandle psDBF, int nYYSince1900, int nMM, int nDD )
- {
- psDBF->nUpdateYearSince1900 = nYYSince1900;
- psDBF->nUpdateMonth = nMM;
- psDBF->nUpdateDay = nDD;
- }
- /************************************************************************/
- /* DBFOpen() */
- /* */
- /* Open a .dbf file. */
- /************************************************************************/
- DBFHandle SHPAPI_CALL
- DBFOpen( const char * pszFilename, const char * pszAccess )
- {
- SAHooks sHooks;
- SASetupDefaultHooks( &sHooks );
- return DBFOpenLL( pszFilename, pszAccess, &sHooks );
- }
- /************************************************************************/
- /* DBFOpen() */
- /* */
- /* Open a .dbf file. */
- /************************************************************************/
- DBFHandle SHPAPI_CALL
- DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
- {
- DBFHandle psDBF;
- SAFile pfCPG;
- unsigned char *pabyBuf;
- int nFields, nHeadLen, iField, i;
- char *pszBasename, *pszFullname;
- int nBufSize = 500;
- size_t nFullnameLen;
- /* -------------------------------------------------------------------- */
- /* We only allow the access strings "rb" and "r+". */
- /* -------------------------------------------------------------------- */
- if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0
- && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
- && strcmp(pszAccess,"r+b") != 0 )
- return( NULL );
- if( strcmp(pszAccess,"r") == 0 )
- pszAccess = "rb";
- if( strcmp(pszAccess,"r+") == 0 )
- pszAccess = "rb+";
- /* -------------------------------------------------------------------- */
- /* Compute the base (layer) name. If there is any extension */
- /* on the passed in filename we will strip it off. */
- /* -------------------------------------------------------------------- */
- pszBasename = (char *) malloc(strlen(pszFilename)+5);
- strcpy( pszBasename, pszFilename );
- for( i = (int)strlen(pszBasename)-1;
- i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
- && pszBasename[i] != '\\';
- i-- ) {}
- if( pszBasename[i] == '.' )
- pszBasename[i] = '\0';
- nFullnameLen = strlen(pszBasename) + 5;
- pszFullname = (char *) malloc(nFullnameLen);
- snprintf( pszFullname, nFullnameLen, "%s.dbf", pszBasename );
- psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
- psDBF->fp = psHooks->FOpen( pszFullname, pszAccess );
- memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
- if( psDBF->fp == NULL )
- {
- snprintf( pszFullname, nFullnameLen, "%s.DBF", pszBasename );
- psDBF->fp = psDBF->sHooks.FOpen(pszFullname, pszAccess );
- }
- snprintf( pszFullname, nFullnameLen, "%s.cpg", pszBasename );
- pfCPG = psHooks->FOpen( pszFullname, "r" );
- if( pfCPG == NULL )
- {
- snprintf( pszFullname, nFullnameLen, "%s.CPG", pszBasename );
- pfCPG = psHooks->FOpen( pszFullname, "r" );
- }
- free( pszBasename );
- free( pszFullname );
- if( psDBF->fp == NULL )
- {
- free( psDBF );
- if( pfCPG ) psHooks->FClose( pfCPG );
- return( NULL );
- }
- psDBF->bNoHeader = FALSE;
- psDBF->nCurrentRecord = -1;
- psDBF->bCurrentRecordModified = FALSE;
- /* -------------------------------------------------------------------- */
- /* Read Table Header info */
- /* -------------------------------------------------------------------- */
- pabyBuf = (unsigned char *) malloc(nBufSize);
- if( psDBF->sHooks.FRead( pabyBuf, 32, 1, psDBF->fp ) != 1 )
- {
- psDBF->sHooks.FClose( psDBF->fp );
- if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
- free( pabyBuf );
- free( psDBF );
- return NULL;
- }
- DBFSetLastModifiedDate(psDBF, pabyBuf[1], pabyBuf[2], pabyBuf[3]);
- psDBF->nRecords =
- pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + (pabyBuf[7] & 0x7f) *256*256*256;
- psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
- psDBF->nRecordLength = pabyBuf[10] + pabyBuf[11]*256;
- psDBF->iLanguageDriver = pabyBuf[29];
- if (psDBF->nRecordLength == 0 || nHeadLen < 32)
- {
- psDBF->sHooks.FClose( psDBF->fp );
- if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
- free( pabyBuf );
- free( psDBF );
- return NULL;
- }
- psDBF->nFields = nFields = (nHeadLen - 32) / 32;
- psDBF->pszCurrentRecord = (char *) malloc(psDBF->nRecordLength);
- /* -------------------------------------------------------------------- */
- /* Figure out the code page from the LDID and CPG */
- /* -------------------------------------------------------------------- */
- psDBF->pszCodePage = NULL;
- if( pfCPG )
- {
- size_t n;
- memset( pabyBuf, 0, nBufSize);
- psDBF->sHooks.FRead( pabyBuf, nBufSize - 1, 1, pfCPG );
- n = strcspn( (char *) pabyBuf, "\n\r" );
- if( n > 0 )
- {
- pabyBuf[n] = '\0';
- psDBF->pszCodePage = (char *) malloc(n + 1);
- memcpy( psDBF->pszCodePage, pabyBuf, n + 1 );
- }
- psDBF->sHooks.FClose( pfCPG );
- }
- if( psDBF->pszCodePage == NULL && pabyBuf[29] != 0 )
- {
- snprintf( (char *) pabyBuf, nBufSize, "LDID/%d", psDBF->iLanguageDriver );
- psDBF->pszCodePage = (char *) malloc(strlen((char*)pabyBuf) + 1);
- strcpy( psDBF->pszCodePage, (char *) pabyBuf );
- }
- /* -------------------------------------------------------------------- */
- /* Read in Field Definitions */
- /* -------------------------------------------------------------------- */
- pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
- psDBF->pszHeader = (char *) pabyBuf;
- psDBF->sHooks.FSeek( psDBF->fp, 32, 0 );
- if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
- {
- psDBF->sHooks.FClose( psDBF->fp );
- free( pabyBuf );
- free( psDBF->pszCurrentRecord );
- free( psDBF );
- return NULL;
- }
- psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);
- psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);
- psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields);
- psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields);
- for( iField = 0; iField < nFields; iField++ )
- {
- unsigned char *pabyFInfo;
- pabyFInfo = pabyBuf+iField*32;
- if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
- {
- psDBF->panFieldSize[iField] = pabyFInfo[16];
- psDBF->panFieldDecimals[iField] = pabyFInfo[17];
- }
- else
- {
- psDBF->panFieldSize[iField] = pabyFInfo[16];
- psDBF->panFieldDecimals[iField] = 0;
- /*
- ** The following seemed to be used sometimes to handle files with long
- ** string fields, but in other cases (such as bug 1202) the decimals field
- ** just seems to indicate some sort of preferred formatting, not very
- ** wide fields. So I have disabled this code. FrankW.
- psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;
- psDBF->panFieldDecimals[iField] = 0;
- */
- }
- psDBF->pachFieldType[iField] = (char) pabyFInfo[11];
- if( iField == 0 )
- psDBF->panFieldOffset[iField] = 1;
- else
- psDBF->panFieldOffset[iField] =
- psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
- }
- return( psDBF );
- }
- /************************************************************************/
- /* DBFClose() */
- /************************************************************************/
- void SHPAPI_CALL
- DBFClose(DBFHandle psDBF)
- {
- if( psDBF == NULL )
- return;
- /* -------------------------------------------------------------------- */
- /* Write out header if not already written. */
- /* -------------------------------------------------------------------- */
- if( psDBF->bNoHeader )
- DBFWriteHeader( psDBF );
- DBFFlushRecord( psDBF );
- /* -------------------------------------------------------------------- */
- /* Update last access date, and number of records if we have */
- /* write access. */
- /* -------------------------------------------------------------------- */
- if( psDBF->bUpdated )
- DBFUpdateHeader( psDBF );
- /* -------------------------------------------------------------------- */
- /* Close, and free resources. */
- /* -------------------------------------------------------------------- */
- psDBF->sHooks.FClose( psDBF->fp );
- if( psDBF->panFieldOffset != NULL )
- {
- free( psDBF->panFieldOffset );
- free( psDBF->panFieldSize );
- free( psDBF->panFieldDecimals );
- free( psDBF->pachFieldType );
- }
- if( psDBF->pszWorkField != NULL )
- free( psDBF->pszWorkField );
- free( psDBF->pszHeader );
- free( psDBF->pszCurrentRecord );
- free( psDBF->pszCodePage );
- free( psDBF );
- }
- /************************************************************************/
- /* DBFCreate() */
- /* */
- /* Create a new .dbf file with default code page LDID/87 (0x57) */
- /************************************************************************/
- DBFHandle SHPAPI_CALL
- DBFCreate( const char * pszFilename )
- {
- return DBFCreateEx( pszFilename, "LDID/87" ); // 0x57
- }
- /************************************************************************/
- /* DBFCreateEx() */
- /* */
- /* Create a new .dbf file. */
- /************************************************************************/
- DBFHandle SHPAPI_CALL
- DBFCreateEx( const char * pszFilename, const char* pszCodePage )
- {
- SAHooks sHooks;
- SASetupDefaultHooks( &sHooks );
- return DBFCreateLL( pszFilename, pszCodePage , &sHooks );
- }
- /************************************************************************/
- /* DBFCreate() */
- /* */
- /* Create a new .dbf file. */
- /************************************************************************/
- DBFHandle SHPAPI_CALL
- DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHooks )
- {
- DBFHandle psDBF;
- SAFile fp;
- char *pszFullname, *pszBasename;
- int i, ldid = -1;
- char chZero = '\0';
- size_t nFullnameLen;
- /* -------------------------------------------------------------------- */
- /* Compute the base (layer) name. If there is any extension */
- /* on the passed in filename we will strip it off. */
- /* -------------------------------------------------------------------- */
- pszBasename = (char *) malloc(strlen(pszFilename)+5);
- strcpy( pszBasename, pszFilename );
- for( i = (int)strlen(pszBasename)-1;
- i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
- && pszBasename[i] != '\\';
- i-- ) {}
- if( pszBasename[i] == '.' )
- pszBasename[i] = '\0';
- nFullnameLen = strlen(pszBasename) + 5;
- pszFullname = (char *) malloc(nFullnameLen);
- snprintf( pszFullname, nFullnameLen, "%s.dbf", pszBasename );
- /* -------------------------------------------------------------------- */
- /* Create the file. */
- /* -------------------------------------------------------------------- */
- fp = psHooks->FOpen( pszFullname, "wb" );
- if( fp == NULL )
- {
- free( pszBasename );
- free( pszFullname );
- return( NULL );
- }
- psHooks->FWrite( &chZero, 1, 1, fp );
- psHooks->FClose( fp );
- fp = psHooks->FOpen( pszFullname, "rb+" );
- if( fp == NULL )
- {
- free( pszBasename );
- free( pszFullname );
- return( NULL );
- }
- snprintf( pszFullname, nFullnameLen, "%s.cpg", pszBasename );
- if( pszCodePage != NULL )
- {
- if( strncmp( pszCodePage, "LDID/", 5 ) == 0 )
- {
- ldid = atoi( pszCodePage + 5 );
- if( ldid > 255 )
- ldid = -1; // don't use 0 to indicate out of range as LDID/0 is a valid one
- }
- if( ldid < 0 )
- {
- SAFile fpCPG = psHooks->FOpen( pszFullname, "w" );
- psHooks->FWrite( (char*) pszCodePage, strlen(pszCodePage), 1, fpCPG );
- psHooks->FClose( fpCPG );
- }
- }
- if( pszCodePage == NULL || ldid >= 0 )
- {
- psHooks->Remove( pszFullname );
- }
- free( pszBasename );
- free( pszFullname );
- /* -------------------------------------------------------------------- */
- /* Create the info structure. */
- /* -------------------------------------------------------------------- */
- psDBF = (DBFHandle) calloc(1,sizeof(DBFInfo));
- memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
- psDBF->fp = fp;
- psDBF->nRecords = 0;
- psDBF->nFields = 0;
- psDBF->nRecordLength = 1;
- psDBF->nHeaderLength = 33;
- psDBF->panFieldOffset = NULL;
- psDBF->panFieldSize = NULL;
- psDBF->panFieldDecimals = NULL;
- psDBF->pachFieldType = NULL;
- psDBF->pszHeader = NULL;
- psDBF->nCurrentRecord = -1;
- psDBF->bCurrentRecordModified = FALSE;
- psDBF->pszCurrentRecord = NULL;
- psDBF->bNoHeader = TRUE;
- psDBF->iLanguageDriver = ldid > 0 ? ldid : 0;
- psDBF->pszCodePage = NULL;
- if( pszCodePage )
- {
- psDBF->pszCodePage = (char * ) malloc( strlen(pszCodePage) + 1 );
- strcpy( psDBF->pszCodePage, pszCodePage );
- }
- DBFSetLastModifiedDate(psDBF, 95, 7, 26); /* dummy date */
- return( psDBF );
- }
- /************************************************************************/
- /* DBFAddField() */
- /* */
- /* Add a field to a newly created .dbf or to an existing one */
- /************************************************************************/
- int SHPAPI_CALL
- DBFAddField(DBFHandle psDBF, const char * pszFieldName,
- DBFFieldType eType, int nWidth, int nDecimals )
- {
- char chNativeType = 'C';
- if( eType == FTLogical )
- chNativeType = 'L';
- else if( eType == FTString )
- chNativeType = 'C';
- else
- chNativeType = 'N';
- return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType,
- nWidth, nDecimals );
- }
- /************************************************************************/
- /* DBFGetNullCharacter() */
- /************************************************************************/
- static char DBFGetNullCharacter(char chType)
- {
- switch (chType)
- {
- case 'N':
- case 'F':
- return '*';
- case 'D':
- return '0';
- case 'L':
- return '?';
- default:
- return ' ';
- }
- }
- /************************************************************************/
- /* DBFAddField() */
- /* */
- /* Add a field to a newly created .dbf file before any records */
- /* are written. */
- /************************************************************************/
- int SHPAPI_CALL
- DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
- char chType, int nWidth, int nDecimals )
- {
- char *pszFInfo;
- int i;
- int nOldRecordLength, nOldHeaderLength;
- char *pszRecord;
- char chFieldFill;
- SAOffset nRecordOffset;
- /* make sure that everything is written in .dbf */
- if( !DBFFlushRecord( psDBF ) )
- return -1;
- /* -------------------------------------------------------------------- */
- /* Do some checking to ensure we can add records to this file. */
- /* -------------------------------------------------------------------- */
- if( nWidth < 1 )
- return -1;
- if( nWidth > 255 )
- nWidth = 255;
- nOldRecordLength = psDBF->nRecordLength;
- nOldHeaderLength = psDBF->nHeaderLength;
- /* -------------------------------------------------------------------- */
- /* SfRealloc all the arrays larger to hold the additional field */
- /* information. */
- /* -------------------------------------------------------------------- */
- psDBF->nFields++;
- psDBF->panFieldOffset = (int *)
- SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
- psDBF->panFieldSize = (int *)
- SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
- psDBF->panFieldDecimals = (int *)
- SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
- psDBF->pachFieldType = (char *)
- SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
- /* -------------------------------------------------------------------- */
- /* Assign the new field information fields. */
- /* -------------------------------------------------------------------- */
- psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
- psDBF->nRecordLength += nWidth;
- psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
- psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
- psDBF->pachFieldType[psDBF->nFields-1] = chType;
- /* -------------------------------------------------------------------- */
- /* Extend the required header information. */
- /* -------------------------------------------------------------------- */
- psDBF->nHeaderLength += 32;
- psDBF->bUpdated = FALSE;
- psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
- pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
- for( i = 0; i < 32; i++ )
- pszFInfo[i] = '\0';
- if( (int) strlen(pszFieldName) < 10 )
- strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
- else
- strncpy( pszFInfo, pszFieldName, 10);
- pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
- if( chType == 'C' )
- {
- pszFInfo[16] = (unsigned char) (nWidth % 256);
- pszFInfo[17] = (unsigned char) (nWidth / 256);
- }
- else
- {
- pszFInfo[16] = (unsigned char) nWidth;
- pszFInfo[17] = (unsigned char) nDecimals;
- }
- /* -------------------------------------------------------------------- */
- /* Make the current record buffer appropriately larger. */
- /* -------------------------------------------------------------------- */
- psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
- psDBF->nRecordLength);
- /* we're done if dealing with new .dbf */
- if( psDBF->bNoHeader )
- return( psDBF->nFields - 1 );
- /* -------------------------------------------------------------------- */
- /* For existing .dbf file, shift records */
- /* -------------------------------------------------------------------- */
- /* alloc record */
- pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
- chFieldFill = DBFGetNullCharacter(chType);
- for (i = psDBF->nRecords-1; i >= 0; --i)
- {
- nRecordOffset = nOldRecordLength * (SAOffset) i + nOldHeaderLength;
- /* load record */
- psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
- psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
- /* set new field's value to NULL */
- memset(pszRecord + nOldRecordLength, chFieldFill, nWidth);
- nRecordOffset = psDBF->nRecordLength * (SAOffset) i + psDBF->nHeaderLength;
- /* move record to the new place*/
- psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
- psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
- }
- /* free record */
- free(pszRecord);
- /* force update of header with new header, record length and new field */
- psDBF->bNoHeader = TRUE;
- DBFUpdateHeader( psDBF );
- psDBF->nCurrentRecord = -1;
- psDBF->bCurrentRecordModified = FALSE;
- psDBF->bUpdated = TRUE;
- return( psDBF->nFields-1 );
- }
- /************************************************************************/
- /* DBFReadAttribute() */
- /* */
- /* Read one of the attribute fields of a record. */
- /************************************************************************/
- static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
- char chReqType )
- {
- unsigned char *pabyRec;
- void *pReturnField = NULL;
- /* -------------------------------------------------------------------- */
- /* Verify selection. */
- /* -------------------------------------------------------------------- */
- if( hEntity < 0 || hEntity >= psDBF->nRecords )
- return( NULL );
- if( iField < 0 || iField >= psDBF->nFields )
- return( NULL );
- /* -------------------------------------------------------------------- */
- /* Have we read the record? */
- /* -------------------------------------------------------------------- */
- if( !DBFLoadRecord( psDBF, hEntity ) )
- return NULL;
- pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
- /* -------------------------------------------------------------------- */
- /* Ensure we have room to extract the target field. */
- /* -------------------------------------------------------------------- */
- if( psDBF->panFieldSize[iField] >= psDBF->nWorkFieldLength )
- {
- psDBF->nWorkFieldLength = psDBF->panFieldSize[iField] + 100;
- if( psDBF->pszWorkField == NULL )
- psDBF->pszWorkField = (char *) malloc(psDBF->nWorkFieldLength);
- else
- psDBF->pszWorkField = (char *) realloc(psDBF->pszWorkField,
- psDBF->nWorkFieldLength);
- }
- /* -------------------------------------------------------------------- */
- /* Extract the requested field. */
- /* -------------------------------------------------------------------- */
- memcpy( psDBF->pszWorkField,
- ((const char *) pabyRec) + psDBF->panFieldOffset[iField],
- psDBF->panFieldSize[iField] );
- psDBF->pszWorkField[psDBF->panFieldSize[iField]] = '\0';
- pReturnField = psDBF->pszWorkField;
- /* -------------------------------------------------------------------- */
- /* Decode the field. */
- /* -------------------------------------------------------------------- */
- if( chReqType == 'I' )
- {
- psDBF->fieldValue.nIntField = atoi(psDBF->pszWorkField);
- pReturnField = &(psDBF->fieldValue.nIntField);
- }
- else if( chReqType == 'N' )
- {
- psDBF->fieldValue.dfDoubleField = psDBF->sHooks.Atof(psDBF->pszWorkField);
- pReturnField = &(psDBF->fieldValue.dfDoubleField);
- }
- /* -------------------------------------------------------------------- */
- /* Should we trim white space off the string attribute value? */
- /* -------------------------------------------------------------------- */
- #ifdef TRIM_DBF_WHITESPACE
- else
- {
- char *pchSrc, *pchDst;
- pchDst = pchSrc = psDBF->pszWorkField;
- while( *pchSrc == ' ' )
- pchSrc++;
- while( *pchSrc != '\0' )
- *(pchDst++) = *(pchSrc++);
- *pchDst = '\0';
- while( pchDst != psDBF->pszWorkField && *(--pchDst) == ' ' )
- *pchDst = '\0';
- }
- #endif
- return( pReturnField );
- }
- /************************************************************************/
- /* DBFReadIntAttribute() */
- /* */
- /* Read an integer attribute. */
- /************************************************************************/
- int SHPAPI_CALL
- DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
- {
- int *pnValue;
- pnValue = (int *) DBFReadAttribute( psDBF, iRecord, iField, 'I' );
- if( pnValue == NULL )
- return 0;
- else
- return( *pnValue );
- }
- /************************************************************************/
- /* DBFReadDoubleAttribute() */
- /* */
- /* Read a double attribute. */
- /************************************************************************/
- double SHPAPI_CALL
- DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
- {
- double *pdValue;
- pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
- if( pdValue == NULL )
- return 0.0;
- else
- return( *pdValue );
- }
- /************************************************************************/
- /* DBFReadStringAttribute() */
- /* */
- /* Read a string attribute. */
- /************************************************************************/
- const char SHPAPI_CALL1(*)
- DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
- {
- return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
- }
- /************************************************************************/
- /* DBFReadLogicalAttribute() */
- /* */
- /* Read a logical attribute. */
- /************************************************************************/
- const char SHPAPI_CALL1(*)
- DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
- {
- return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
- }
- /************************************************************************/
- /* DBFIsValueNULL() */
- /* */
- /* Return TRUE if the passed string is NULL. */
- /************************************************************************/
- static int DBFIsValueNULL( char chType, const char* pszValue )
- {
- int i;
- if( pszValue == NULL )
- return TRUE;
- switch(chType)
- {
- case 'N':
- case 'F':
- /*
- ** We accept all asterisks or all blanks as NULL
- ** though according to the spec I think it should be all
- ** asterisks.
- */
- if( pszValue[0] == '*' )
- return TRUE;
- for( i = 0; pszValue[i] != '\0'; i++ )
- {
- if( pszValue[i] != ' ' )
- return FALSE;
- }
- return TRUE;
- case 'D':
- /* NULL date fields have value "00000000" */
- return strncmp(pszValue,"00000000",8) == 0;
- case 'L':
- /* NULL boolean fields have value "?" */
- return pszValue[0] == '?';
- default:
- /* empty string fields are considered NULL */
- return strlen(pszValue) == 0;
- }
- }
- /************************************************************************/
- /* DBFIsAttributeNULL() */
- /* */
- /* Return TRUE if value for field is NULL. */
- /* */
- /* Contributed by Jim Matthews. */
- /************************************************************************/
- int SHPAPI_CALL
- DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
- {
- const char *pszValue;
- pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
- if( pszValue == NULL )
- return TRUE;
- return DBFIsValueNULL( psDBF->pachFieldType[iField], pszValue );
- }
- /************************************************************************/
- /* DBFGetFieldCount() */
- /* */
- /* Return the number of fields in this table. */
- /************************************************************************/
- int SHPAPI_CALL
- DBFGetFieldCount( DBFHandle psDBF )
- {
- return( psDBF->nFields );
- }
- /************************************************************************/
- /* DBFGetRecordCount() */
- /* */
- /* Return the number of records in this table. */
- /************************************************************************/
- int SHPAPI_CALL
- DBFGetRecordCount( DBFHandle psDBF )
- {
- return( psDBF->nRecords );
- }
- /************************************************************************/
- /* DBFGetFieldInfo() */
- /* */
- /* Return any requested information about the field. */
- /************************************************************************/
- DBFFieldType SHPAPI_CALL
- DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
- int * pnWidth, int * pnDecimals )
- {
- if( iField < 0 || iField >= psDBF->nFields )
- return( FTInvalid );
- if( pnWidth != NULL )
- *pnWidth = psDBF->panFieldSize[iField];
- if( pnDecimals != NULL )
- *pnDecimals = psDBF->panFieldDecimals[iField];
- if( pszFieldName != NULL )
- {
- int i;
- strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
- pszFieldName[11] = '\0';
- for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
- pszFieldName[i] = '\0';
- }
- if ( psDBF->pachFieldType[iField] == 'L' )
- return( FTLogical);
- else if( psDBF->pachFieldType[iField] == 'N'
- || psDBF->pachFieldType[iField] == 'F' )
- {
- if( psDBF->panFieldDecimals[iField] > 0 )
- /* || psDBF->panFieldSize[iField] >= 10 ) */ /* GDAL bug #809 */
- return( FTDouble );
- else
- return( FTInteger );
- }
- else
- {
- return( FTString );
- }
- }
- /************************************************************************/
- /* DBFWriteAttribute() */
- /* */
- /* Write an attribute record to the file. */
- /************************************************************************/
- static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
- void * pValue )
- {
- int i, j, nRetResult = TRUE;
- unsigned char *pabyRec;
- char szSField[400], szFormat[20];
- /* -------------------------------------------------------------------- */
- /* Is this a valid record? */
- /* -------------------------------------------------------------------- */
- if( hEntity < 0 || hEntity > psDBF->nRecords )
- return( FALSE );
- if( psDBF->bNoHeader )
- DBFWriteHeader(psDBF);
- /* -------------------------------------------------------------------- */
- /* Is this a brand new record? */
- /* -------------------------------------------------------------------- */
- if( hEntity == psDBF->nRecords )
- {
- if( !DBFFlushRecord( psDBF ) )
- return FALSE;
- psDBF->nRecords++;
- for( i = 0; i < psDBF->nRecordLength; i++ )
- psDBF->pszCurrentRecord[i] = ' ';
- psDBF->nCurrentRecord = hEntity;
- }
- /* -------------------------------------------------------------------- */
- /* Is this an existing record, but different than the last one */
- /* we accessed? */
- /* -------------------------------------------------------------------- */
- if( !DBFLoadRecord( psDBF, hEntity ) )
- return FALSE;
- pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
- psDBF->bCurrentRecordModified = TRUE;
- psDBF->bUpdated = TRUE;
- /* -------------------------------------------------------------------- */
- /* Translate NULL value to valid DBF file representation. */
- /* */
- /* Contributed by Jim Matthews. */
- /* -------------------------------------------------------------------- */
- if( pValue == NULL )
- {
- memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]),
- DBFGetNullCharacter(psDBF->pachFieldType[iField]),
- psDBF->panFieldSize[iField] );
- return TRUE;
- }
- /* -------------------------------------------------------------------- */
- /* Assign all the record fields. */
- /* -------------------------------------------------------------------- */
- switch( psDBF->pachFieldType[iField] )
- {
- case 'D':
- case 'N':
- case 'F':
- {
- int nWidth = psDBF->panFieldSize[iField];
- if( (int) sizeof(szSField)-2 < nWidth )
- nWidth = sizeof(szSField)-2;
- snprintf( szFormat, sizeof(szFormat), "%%%d.%df",
- nWidth, psDBF->panFieldDecimals[iField] );
- snprintf(szSField, sizeof(szSField), szFormat, *((double *) pValue) );
- if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
- {
- szSField[psDBF->panFieldSize[iField]] = '\0';
- nRetResult = FALSE;
- }
- strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
- szSField, strlen(szSField) );
- break;
- }
- case 'L':
- if (psDBF->panFieldSize[iField] >= 1 &&
- (*(char*)pValue == 'F' || *(char*)pValue == 'T'))
- *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
- break;
- default:
- if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
- {
- j = psDBF->panFieldSize[iField];
- nRetResult = FALSE;
- }
- else
- {
- memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
- psDBF->panFieldSize[iField] );
- j = (int)strlen((char *) pValue);
- }
- strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
- (char *) pValue, j );
- break;
- }
- return( nRetResult );
- }
- /************************************************************************/
- /* DBFWriteAttributeDirectly() */
- /* */
- /* Write an attribute record to the file, but without any */
- /* reformatting based on type. The provided buffer is written */
- /* as is to the field position in the record. */
- /************************************************************************/
- int SHPAPI_CALL
- DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
- void * pValue )
- {
- int i, j;
- unsigned char *pabyRec;
- /* -------------------------------------------------------------------- */
- /* Is this a valid record? */
- /* -------------------------------------------------------------------- */
- if( hEntity < 0 || hEntity > psDBF->nRecords )
- return( FALSE );
- if( psDBF->bNoHeader )
- DBFWriteHeader(psDBF);
- /* -------------------------------------------------------------------- */
- /* Is this a brand new record? */
- /* -------------------------------------------------------------------- */
- if( hEntity == psDBF->nRecords )
- {
- if( !DBFFlushRecord( psDBF ) )
- return FALSE;
- psDBF->nRecords++;
- for( i = 0; i < psDBF->nRecordLength; i++ )
- psDBF->pszCurrentRecord[i] = ' ';
- psDBF->nCurrentRecord = hEntity;
- }
- /* -------------------------------------------------------------------- */
- /* Is this an existing record, but different than the last one */
- /* we accessed? */
- /* -------------------------------------------------------------------- */
- if( !DBFLoadRecord( psDBF, hEntity ) )
- return FALSE;
- pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
- /* -------------------------------------------------------------------- */
- /* Assign all the record fields. */
- /* -------------------------------------------------------------------- */
- if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] )
- j = psDBF->panFieldSize[iField];
- else
- {
- memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
- psDBF->panFieldSize[iField] );
- j = (int)strlen((char *) pValue);
- }
- strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
- (char *) pValue, j );
- psDBF->bCurrentRecordModified = TRUE;
- psDBF->bUpdated = TRUE;
- return( TRUE );
- }
- /************************************************************************/
- /* DBFWriteDoubleAttribute() */
- /* */
- /* Write a double attribute. */
- /************************************************************************/
- int SHPAPI_CALL
- DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
- double dValue )
- {
- return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
- }
- /************************************************************************/
- /* DBFWriteIntegerAttribute() */
- /* */
- /* Write a integer attribute. */
- /************************************************************************/
- int SHPAPI_CALL
- DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
- int nValue )
- {
- double dValue = nValue;
- return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
- }
- /************************************************************************/
- /* DBFWriteStringAttribute() */
- /* */
- /* Write a string attribute. */
- /************************************************************************/
- int SHPAPI_CALL
- DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
- const char * pszValue )
- {
- return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) );
- }
- /************************************************************************/
- /* DBFWriteNULLAttribute() */
- /* */
- /* Write a string attribute. */
- /************************************************************************/
- int SHPAPI_CALL
- DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
- {
- return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );
- }
- /************************************************************************/
- /* DBFWriteLogicalAttribute() */
- /* */
- /* Write a logical attribute. */
- /************************************************************************/
- int SHPAPI_CALL
- DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
- const char lValue)
- {
- return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );
- }
- /************************************************************************/
- /* DBFWriteTuple() */
- /* */
- /* Write an attribute record to the file. */
- /************************************************************************/
- int SHPAPI_CALL
- DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
- {
- int i;
- unsigned char *pabyRec;
- /* -------------------------------------------------------------------- */
- /* Is this a valid record? */
- /* -------------------------------------------------------------------- */
- if( hEntity < 0 || hEntity > psDBF->nRecords )
- return( FALSE );
- if( psDBF->bNoHeader )
- DBFWriteHeader(psDBF);
- /* -------------------------------------------------------------------- */
- /* Is this a brand new record? */
- /* -------------------------------------------------------------------- */
- if( hEntity == psDBF->nRecords )
- {
- if( !DBFFlushRecord( psDBF ) )
- return FALSE;
- psDBF->nRecords++;
- for( i = 0; i < psDBF->nRecordLength; i++ )
- psDBF->pszCurrentRecord[i] = ' ';
- psDBF->nCurrentRecord = hEntity;
- }
- /* -------------------------------------------------------------------- */
- /* Is this an existing record, but different than the last one */
- /* we accessed? */
- /* -------------------------------------------------------------------- */
- if( !DBFLoadRecord( psDBF, hEntity ) )
- return FALSE;
- pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
- memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength );
- psDBF->bCurrentRecordModified = TRUE;
- psDBF->bUpdated = TRUE;
- return( TRUE );
- }
- /************************************************************************/
- /* DBFReadTuple() */
- /* */
- /* Read a complete record. Note that the result is only valid */
- /* till the next record read for any reason. */
- /************************************************************************/
- const char SHPAPI_CALL1(*)
- DBFReadTuple(DBFHandle psDBF, int hEntity )
- {
- if( hEntity < 0 || hEntity >= psDBF->nRecords )
- return( NULL );
- if( !DBFLoadRecord( psDBF, hEntity ) )
- return NULL;
- return (const char *) psDBF->pszCurrentRecord;
- }
- /************************************************************************/
- /* DBFCloneEmpty() */
- /* */
- /* Read one of the attribute fields of a record. */
- /************************************************************************/
- DBFHandle SHPAPI_CALL
- DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
- {
- DBFHandle newDBF;
- newDBF = DBFCreateEx ( pszFilename, psDBF->pszCodePage );
- if ( newDBF == NULL ) return ( NULL );
- newDBF->nFields = psDBF->nFields;
- newDBF->nRecordLength = psDBF->nRecordLength;
- newDBF->nHeaderLength = psDBF->nHeaderLength;
- if( psDBF->pszHeader )
- {
- newDBF->pszHeader = (char *) malloc ( XBASE_FLDHDR_SZ * psDBF->nFields );
- memcpy ( newDBF->pszHeader, psDBF->pszHeader, XBASE_FLDHDR_SZ * psDBF->nFields );
- }
- newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields );
- memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
- newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
- memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
- newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
- memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
- newDBF->pachFieldType = (char *) malloc ( sizeof(char) * psDBF->nFields );
- memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(char)*psDBF->nFields );
- newDBF->bNoHeader = TRUE;
- newDBF->bUpdated = TRUE;
- DBFWriteHeader ( newDBF );
- DBFClose ( newDBF );
- newDBF = DBFOpen ( pszFilename, "rb+" );
- return ( newDBF );
- }
- /************************************************************************/
- /* DBFGetNativeFieldType() */
- /* */
- /* Return the DBase field type for the specified field. */
- /* */
- /* Value can be one of: 'C' (String), 'D' (Date), 'F' (Float), */
- /* 'N' (Numeric, with or without decimal), */
- /* 'L' (Logical), */
- /* 'M' (Memo: 10 digits .DBT block ptr) */
- /************************************************************************/
- char SHPAPI_CALL
- DBFGetNativeFieldType( DBFHandle psDBF, int iField )
- {
- if( iField >=0 && iField < psDBF->nFields )
- return psDBF->pachFieldType[iField];
- return ' ';
- }
- /************************************************************************/
- /* str_to_upper() */
- /************************************************************************/
- static void str_to_upper (char *string)
- {
- int len;
- int i = -1;
- len = (int)strlen (string);
- while (++i < len)
- if (isalpha(string[i]) && islower(string[i]))
- string[i] = (char) toupper ((int)string[i]);
- }
- /************************************************************************/
- /* DBFGetFieldIndex() */
- /* */
- /* Get the index number for a field in a .dbf file. */
- /* */
- /* Contributed by Jim Matthews. */
- /************************************************************************/
- int SHPAPI_CALL
- DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
- {
- char name[12], name1[12], name2[12];
- int i;
- strncpy(name1, pszFieldName,11);
- name1[11] = '\0';
- str_to_upper(name1);
- for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
- {
- DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
- strncpy(name2,name,11);
- str_to_upper(name2);
- if(!strncmp(name1,name2,10))
- return(i);
- }
- return(-1);
- }
- /************************************************************************/
- /* DBFIsRecordDeleted() */
- /* */
- /* Returns TRUE if the indicated record is deleted, otherwise */
- /* it returns FALSE. */
- /************************************************************************/
- int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape )
- {
- /* -------------------------------------------------------------------- */
- /* Verify selection. */
- /* -------------------------------------------------------------------- */
- if( iShape < 0 || iShape >= psDBF->nRecords )
- return TRUE;
- /* -------------------------------------------------------------------- */
- /* Have we read the record? */
- /* -------------------------------------------------------------------- */
- if( !DBFLoadRecord( psDBF, iShape ) )
- return FALSE;
- /* -------------------------------------------------------------------- */
- /* '*' means deleted. */
- /* -------------------------------------------------------------------- */
- return psDBF->pszCurrentRecord[0] == '*';
- }
- /************************************************************************/
- /* DBFMarkRecordDeleted() */
- /************************************************************************/
- int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape,
- int bIsDeleted )
- {
- char chNewFlag;
- /* -------------------------------------------------------------------- */
- /* Verify selection. */
- /* -------------------------------------------------------------------- */
- if( iShape < 0 || iShape >= psDBF->nRecords )
- return FALSE;
- /* -------------------------------------------------------------------- */
- /* Is this an existing record, but different than the last one */
- /* we accessed? */
- /* -------------------------------------------------------------------- */
- if( !DBFLoadRecord( psDBF, iShape ) )
- return FALSE;
- /* -------------------------------------------------------------------- */
- /* Assign value, marking record as dirty if it changes. */
- /* -------------------------------------------------------------------- */
- if( bIsDeleted )
- chNewFlag = '*';
- else
- chNewFlag = ' ';
- if( psDBF->pszCurrentRecord[0] != chNewFlag )
- {
- psDBF->bCurrentRecordModified = TRUE;
- psDBF->bUpdated = TRUE;
- psDBF->pszCurrentRecord[0] = chNewFlag;
- }
- return TRUE;
- }
- /************************************************************************/
- /* DBFGetCodePage */
- /************************************************************************/
- const char SHPAPI_CALL1(*)
- DBFGetCodePage(DBFHandle psDBF )
- {
- if( psDBF == NULL )
- return NULL;
- return psDBF->pszCodePage;
- }
- /************************************************************************/
- /* DBFDeleteField() */
- /* */
- /* Remove a field from a .dbf file */
- /************************************************************************/
- int SHPAPI_CALL
- DBFDeleteField(DBFHandle psDBF, int iField)
- {
- int nOldRecordLength, nOldHeaderLength;
- int nDeletedFieldOffset, nDeletedFieldSize;
- SAOffset nRecordOffset;
- char* pszRecord;
- int i, iRecord;
- if (iField < 0 || iField >= psDBF->nFields)
- return FALSE;
- /* make sure that everything is written in .dbf */
- if( !DBFFlushRecord( psDBF ) )
- return FALSE;
- /* get information about field to be deleted */
- nOldRecordLength = psDBF->nRecordLength;
- nOldHeaderLength = psDBF->nHeaderLength;
- nDeletedFieldOffset = psDBF->panFieldOffset[iField];
- nDeletedFieldSize = psDBF->panFieldSize[iField];
- /* update fields info */
- for (i = iField + 1; i < psDBF->nFields; i++)
- {
- psDBF->panFieldOffset[i-1] = psDBF->panFieldOffset[i] - nDeletedFieldSize;
- psDBF->panFieldSize[i-1] = psDBF->panFieldSize[i];
- psDBF->panFieldDecimals[i-1] = psDBF->panFieldDecimals[i];
- psDBF->pachFieldType[i-1] = psDBF->pachFieldType[i];
- }
- /* resize fields arrays */
- psDBF->nFields--;
- psDBF->panFieldOffset = (int *)
- SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
- psDBF->panFieldSize = (int *)
- SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
- psDBF->panFieldDecimals = (int *)
- SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
- psDBF->pachFieldType = (char *)
- SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
- /* update header information */
- psDBF->nHeaderLength -= 32;
- psDBF->nRecordLength -= nDeletedFieldSize;
- /* overwrite field information in header */
- memmove(psDBF->pszHeader + iField*32,
- psDBF->pszHeader + (iField+1)*32,
- sizeof(char) * (psDBF->nFields - iField)*32);
- psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
- /* update size of current record appropriately */
- psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
- psDBF->nRecordLength);
- /* we're done if we're dealing with not yet created .dbf */
- if ( psDBF->bNoHeader && psDBF->nRecords == 0 )
- return TRUE;
- /* force update of header with new header and record length */
- psDBF->bNoHeader = TRUE;
- DBFUpdateHeader( psDBF );
- /* alloc record */
- pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength);
- /* shift records to their new positions */
- for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
- {
- nRecordOffset =
- nOldRecordLength * (SAOffset) iRecord + nOldHeaderLength;
- /* load record */
- psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
- psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
- nRecordOffset =
- psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
- /* move record in two steps */
- psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
- psDBF->sHooks.FWrite( pszRecord, nDeletedFieldOffset, 1, psDBF->fp );
- psDBF->sHooks.FWrite( pszRecord + nDeletedFieldOffset + nDeletedFieldSize,
- nOldRecordLength - nDeletedFieldOffset - nDeletedFieldSize,
- 1, psDBF->fp );
- }
- /* TODO: truncate file */
- /* free record */
- free(pszRecord);
- psDBF->nCurrentRecord = -1;
- psDBF->bCurrentRecordModified = FALSE;
- psDBF->bUpdated = TRUE;
- return TRUE;
- }
- /************************************************************************/
- /* DBFReorderFields() */
- /* */
- /* Reorder the fields of a .dbf file */
- /* */
- /* panMap must be exactly psDBF->nFields long and be a permutation */
- /* of [0, psDBF->nFields-1]. This assumption will not be asserted in the*/
- /* code of DBFReorderFields. */
- /************************************************************************/
- int SHPAPI_CALL
- DBFReorderFields( DBFHandle psDBF, int* panMap )
- {
- SAOffset nRecordOffset;
- int i, iRecord;
- int *panFieldOffsetNew;
- int *panFieldSizeNew;
- int *panFieldDecimalsNew;
- char *pachFieldTypeNew;
- char *pszHeaderNew;
- char *pszRecord;
- char *pszRecordNew;
- if ( psDBF->nFields == 0 )
- return TRUE;
- /* make sure that everything is written in .dbf */
- if( !DBFFlushRecord( psDBF ) )
- return FALSE;
- /* a simple malloc() would be enough, but calloc() helps clang static analyzer */
- panFieldOffsetNew = (int *) calloc(sizeof(int), psDBF->nFields);
- panFieldSizeNew = (int *) malloc(sizeof(int) * psDBF->nFields);
- panFieldDecimalsNew = (int *) malloc(sizeof(int) * psDBF->nFields);
- pachFieldTypeNew = (char *) malloc(sizeof(char) * psDBF->nFields);
- pszHeaderNew = (char*) malloc(sizeof(char) * 32 * psDBF->nFields);
- /* shuffle fields definitions */
- for(i=0; i < psDBF->nFields; i++)
- {
- panFieldSizeNew[i] = psDBF->panFieldSize[panMap[i]];
- panFieldDecimalsNew[i] = psDBF->panFieldDecimals[panMap[i]];
- pachFieldTypeNew[i] = psDBF->pachFieldType[panMap[i]];
- memcpy(pszHeaderNew + i * 32,
- psDBF->pszHeader + panMap[i] * 32, 32);
- }
- panFieldOffsetNew[0] = 1;
- for(i=1; i < psDBF->nFields; i++)
- {
- panFieldOffsetNew[i] = panFieldOffsetNew[i - 1] + panFieldSizeNew[i - 1];
- }
- free(psDBF->pszHeader);
- psDBF->pszHeader = pszHeaderNew;
- /* we're done if we're dealing with not yet created .dbf */
- if ( !(psDBF->bNoHeader && psDBF->nRecords == 0) )
- {
- /* force update of header with new header and record length */
- psDBF->bNoHeader = TRUE;
- DBFUpdateHeader( psDBF );
- /* alloc record */
- pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
- pszRecordNew = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
- /* shuffle fields in records */
- for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
- {
- nRecordOffset =
- psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
- /* load record */
- psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
- psDBF->sHooks.FRead( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
- pszRecordNew[0] = pszRecord[0];
- for(i=0; i < psDBF->nFields; i++)
- {
- memcpy(pszRecordNew + panFieldOffsetNew[i],
- pszRecord + psDBF->panFieldOffset[panMap[i]],
- psDBF->panFieldSize[panMap[i]]);
- }
- /* write record */
- psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
- psDBF->sHooks.FWrite( pszRecordNew, psDBF->nRecordLength, 1, psDBF->fp );
- }
- /* free record */
- free(pszRecord);
- free(pszRecordNew);
- }
- free(psDBF->panFieldOffset);
- free(psDBF->panFieldSize);
- free(psDBF->panFieldDecimals);
- free(psDBF->pachFieldType);
- psDBF->panFieldOffset = panFieldOffsetNew;
- psDBF->panFieldSize = panFieldSizeNew;
- psDBF->panFieldDecimals =panFieldDecimalsNew;
- psDBF->pachFieldType = pachFieldTypeNew;
- psDBF->nCurrentRecord = -1;
- psDBF->bCurrentRecordModified = FALSE;
- psDBF->bUpdated = TRUE;
- return TRUE;
- }
- /************************************************************************/
- /* DBFAlterFieldDefn() */
- /* */
- /* Alter a field definition in a .dbf file */
- /************************************************************************/
- int SHPAPI_CALL
- DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
- char chType, int nWidth, int nDecimals )
- {
- int i;
- int iRecord;
- int nOffset;
- int nOldWidth;
- int nOldRecordLength;
- SAOffset nRecordOffset;
- char* pszFInfo;
- char chOldType;
- int bIsNULL;
- char chFieldFill;
- if (iField < 0 || iField >= psDBF->nFields)
- return FALSE;
- /* make sure that everything is written in .dbf */
- if( !DBFFlushRecord( psDBF ) )
- return FALSE;
- chFieldFill = DBFGetNullCharacter(chType);
- chOldType = psDBF->pachFieldType[iField];
- nOffset = psDBF->panFieldOffset[iField];
- nOldWidth = psDBF->panFieldSize[iField];
- nOldRecordLength = psDBF->nRecordLength;
- /* -------------------------------------------------------------------- */
- /* Do some checking to ensure we can add records to this file. */
- /* -------------------------------------------------------------------- */
- if( nWidth < 1 )
- return -1;
- if( nWidth > 255 )
- nWidth = 255;
- /* -------------------------------------------------------------------- */
- /* Assign the new field information fields. */
- /* -------------------------------------------------------------------- */
- psDBF->panFieldSize[iField] = nWidth;
- psDBF->panFieldDecimals[iField] = nDecimals;
- psDBF->pachFieldType[iField] = chType;
- /* -------------------------------------------------------------------- */
- /* Update the header information. */
- /* -------------------------------------------------------------------- */
- pszFInfo = psDBF->pszHeader + 32 * iField;
- for( i = 0; i < 32; i++ )
- pszFInfo[i] = '\0';
- if( (int) strlen(pszFieldName) < 10 )
- strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
- else
- strncpy( pszFInfo, pszFieldName, 10);
- pszFInfo[11] = psDBF->pachFieldType[iField];
- if( chType == 'C' )
- {
- pszFInfo[16] = (unsigned char) (nWidth % 256);
- pszFInfo[17] = (unsigned char) (nWidth / 256);
- }
- else
- {
- pszFInfo[16] = (unsigned char) nWidth;
- pszFInfo[17] = (unsigned char) nDecimals;
- }
- /* -------------------------------------------------------------------- */
- /* Update offsets */
- /* -------------------------------------------------------------------- */
- if (nWidth != nOldWidth)
- {
- for (i = iField + 1; i < psDBF->nFields; i++)
- psDBF->panFieldOffset[i] += nWidth - nOldWidth;
- psDBF->nRecordLength += nWidth - nOldWidth;
- psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
- psDBF->nRecordLength);
- }
- /* we're done if we're dealing with not yet created .dbf */
- if ( psDBF->bNoHeader && psDBF->nRecords == 0 )
- return TRUE;
- /* force update of header with new header and record length */
- psDBF->bNoHeader = TRUE;
- DBFUpdateHeader( psDBF );
- if (nWidth < nOldWidth || (nWidth == nOldWidth && chType != chOldType))
- {
- char* pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength);
- char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
- pszOldField[nOldWidth] = 0;
- /* move records to their new positions */
- for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
- {
- nRecordOffset =
- nOldRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
- /* load record */
- psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
- psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
- memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
- bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
- if (nWidth != nOldWidth)
- {
- if ((chOldType == 'N' || chOldType == 'F') && pszOldField[0] == ' ')
- {
- /* Strip leading spaces when truncating a numeric field */
- memmove( pszRecord + nOffset,
- pszRecord + nOffset + nOldWidth - nWidth,
- nWidth );
- }
- if (nOffset + nOldWidth < nOldRecordLength)
- {
- memmove( pszRecord + nOffset + nWidth,
- pszRecord + nOffset + nOldWidth,
- nOldRecordLength - (nOffset + nOldWidth));
- }
- }
- /* Convert null value to the appropriate value of the new type */
- if (bIsNULL)
- {
- memset( pszRecord + nOffset, chFieldFill, nWidth);
- }
- nRecordOffset =
- psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
- /* write record */
- psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
- psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
- }
- free(pszRecord);
- free(pszOldField);
- }
- else if (nWidth > nOldWidth)
- {
- char* pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
- char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
- pszOldField[nOldWidth] = 0;
- /* move records to their new positions */
- for (iRecord = psDBF->nRecords - 1; iRecord >= 0; iRecord--)
- {
- nRecordOffset =
- nOldRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
- /* load record */
- psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
- psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
- memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
- bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
- if (nOffset + nOldWidth < nOldRecordLength)
- {
- memmove( pszRecord + nOffset + nWidth,
- pszRecord + nOffset + nOldWidth,
- nOldRecordLength - (nOffset + nOldWidth));
- }
- /* Convert null value to the appropriate value of the new type */
- if (bIsNULL)
- {
- memset( pszRecord + nOffset, chFieldFill, nWidth);
- }
- else
- {
- if ((chOldType == 'N' || chOldType == 'F'))
- {
- /* Add leading spaces when expanding a numeric field */
- memmove( pszRecord + nOffset + nWidth - nOldWidth,
- pszRecord + nOffset, nOldWidth );
- memset( pszRecord + nOffset, ' ', nWidth - nOldWidth );
- }
- else
- {
- /* Add trailing spaces */
- memset(pszRecord + nOffset + nOldWidth, ' ', nWidth - nOldWidth);
- }
- }
- nRecordOffset =
- psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
- /* write record */
- psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
- psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
- }
- free(pszRecord);
- free(pszOldField);
- }
- psDBF->nCurrentRecord = -1;
- psDBF->bCurrentRecordModified = FALSE;
- psDBF->bUpdated = TRUE;
- return TRUE;
- }
|