1 Star 1 Fork 0

xiyan-100/shapelib

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
dbfopen.c 87.24 KB
一键复制 编辑 原始数据 按行查看 历史
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435
/******************************************************************************
* $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 COPYING). 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$
* Revision 1.94 2018-08-16 15:39:07 erouault
* * shpopen.c, dbfopen.c, shptree.c, sbnsearch.c: resyc with GDAL
* internal shapelib. Mostly to allow building those files as C++
* without warning. Also add FTDate entry in DBFFieldType
* (see https://github.com/OSGeo/gdal/pull/308). And some other
* code cleanups
*
* Revision 1.93 2018-08-16 15:24:46 erouault
* * dbfopen.c: fix a bug where the end of file character was
* written on top of the first character of the first field name
* when deleting a field on a .dbf without records.
* Fixes https://github.com/OSGeo/gdal/issues/863
*
* Revision 1.92 2016-12-05 18:44:08 erouault
* * dbfopen.c, shapefil.h: write DBF end-of-file character 0x1A by default.
* This behaviour can be controlled with the DBFSetWriteEndOfFileChar()
* function.
*
* Revision 1.91 2016-12-05 12:44:05 erouault
* * Major overhaul of Makefile build system to use autoconf/automake.
*
* * Warning fixes in contrib/
*
* Revision 1.90 2016-12-04 15:30:15 erouault
* * shpopen.c, dbfopen.c, shptree.c, shapefil.h: resync with
* GDAL Shapefile driver. Mostly cleanups. SHPObject and DBFInfo
* structures extended with new members. New functions:
* DBFSetLastModifiedDate, SHPOpenLLEx, SHPRestoreSHX,
* SHPSetFastModeReadObject
*
* * sbnsearch.c: new file to implement original ESRI .sbn spatial
* index reading. (no write support). New functions:
* SBNOpenDiskTree, SBNCloseDiskTree, SBNSearchDiskTree,
* SBNSearchDiskTreeInteger, SBNSearchFreeIds
*
* * Makefile, makefile.vc, CMakeLists.txt, shapelib.def: updates
* with new file and symbols.
*
* * commit: helper script to cvs commit
*
* 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 "shapefil.h"
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#ifdef USE_CPL
#include "cpl_string.h"
#else
#if defined(WIN32) || defined(_WIN32)
# define STRCASECMP(a,b) (stricmp(a,b))
# else
#include <strings.h>
# define STRCASECMP(a,b) (strcasecmp(a,b))
#endif
#if defined(_MSC_VER)
# if _MSC_VER < 1900
# define snprintf _snprintf
# endif
#elif defined(WIN32) || defined(_WIN32)
# ifndef snprintf
# define snprintf _snprintf
# endif
#endif
#define CPLsprintf sprintf
#define CPLsnprintf snprintf
#endif
SHP_CVSID("$Id$")
#ifndef FALSE
# define FALSE 0
# define TRUE 1
#endif
/* File header size */
#define XBASE_FILEHDR_SZ 32
#define HEADER_RECORD_TERMINATOR 0x0D
/* See http://www.manmrk.net/tutorials/database/xbase/dbf.html */
#define END_OF_FILE_CHARACTER 0x1A
#ifdef USE_CPL
CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused) {}
#else
#define CPL_IGNORE_RET_VAL_INT(x) x
#endif
#ifdef __cplusplus
#define STATIC_CAST(type,x) static_cast<type>(x)
#define REINTERPRET_CAST(type,x) reinterpret_cast<type>(x)
#define CONST_CAST(type,x) const_cast<type>(x)
#define SHPLIB_NULLPTR nullptr
#else
#define STATIC_CAST(type,x) ((type)(x))
#define REINTERPRET_CAST(type,x) ((type)(x))
#define CONST_CAST(type,x) ((type)(x))
#define SHPLIB_NULLPTR NULL
#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 == SHPLIB_NULLPTR )
return malloc(nNewSize);
else
return 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_FILEHDR_SZ] = { 0 };
if( !psDBF->bNoHeader )
return;
psDBF->bNoHeader = FALSE;
/* -------------------------------------------------------------------- */
/* Initialize the file header information. */
/* -------------------------------------------------------------------- */
abyHeader[0] = 0x03; /* memo field? - just copying */
/* write out update date */
abyHeader[1] = STATIC_CAST(unsigned char, psDBF->nUpdateYearSince1900);
abyHeader[2] = STATIC_CAST(unsigned char, psDBF->nUpdateMonth);
abyHeader[3] = STATIC_CAST(unsigned char, psDBF->nUpdateDay);
/* record count preset at zero */
abyHeader[8] = STATIC_CAST(unsigned char, psDBF->nHeaderLength % 256);
abyHeader[9] = STATIC_CAST(unsigned char, psDBF->nHeaderLength / 256);
abyHeader[10] = STATIC_CAST(unsigned char, psDBF->nRecordLength % 256);
abyHeader[11] = STATIC_CAST(unsigned char, psDBF->nRecordLength / 256);
abyHeader[29] = STATIC_CAST(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_FILEHDR_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 > XBASE_FLDHDR_SZ*psDBF->nFields +
XBASE_FLDHDR_SZ )
{
char cNewline;
cNewline = HEADER_RECORD_TERMINATOR;
psDBF->sHooks.FWrite( &cNewline, 1, 1, psDBF->fp );
}
/* -------------------------------------------------------------------- */
/* If the file is new, add a EOF character. */
/* -------------------------------------------------------------------- */
if( psDBF->nRecords == 0 && psDBF->bWriteEndOfFileChar )
{
char ch = END_OF_FILE_CHARACTER;
psDBF->sHooks.FWrite( &ch, 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 * STATIC_CAST(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;
}
if( psDBF->nCurrentRecord == psDBF->nRecords - 1 )
{
if( psDBF->bWriteEndOfFileChar )
{
char ch = END_OF_FILE_CHARACTER;
psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
}
}
}
return TRUE;
}
/************************************************************************/
/* DBFLoadRecord() */
/************************************************************************/
static int DBFLoadRecord( DBFHandle psDBF, int iRecord )
{
if( psDBF->nCurrentRecord != iRecord )
{
SAOffset nRecordOffset;
if( !DBFFlushRecord( psDBF ) )
return FALSE;
nRecordOffset =
psDBF->nRecordLength * STATIC_CAST(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.",
STATIC_CAST(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.",
psDBF->nRecordLength );
psDBF->sHooks.Error( szMessage );
return FALSE;
}
psDBF->nCurrentRecord = iRecord;
}
return TRUE;
}
/************************************************************************/
/* DBFUpdateHeader() */
/************************************************************************/
void SHPAPI_CALL
DBFUpdateHeader( DBFHandle psDBF )
{
unsigned char abyFileHeader[XBASE_FILEHDR_SZ];
if( psDBF->bNoHeader )
DBFWriteHeader( psDBF );
if( !DBFFlushRecord( psDBF ) )
return;
psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
psDBF->sHooks.FRead( abyFileHeader, sizeof(abyFileHeader), 1, psDBF->fp );
abyFileHeader[1] = STATIC_CAST(unsigned char, psDBF->nUpdateYearSince1900);
abyFileHeader[2] = STATIC_CAST(unsigned char, psDBF->nUpdateMonth);
abyFileHeader[3] = STATIC_CAST(unsigned char, psDBF->nUpdateDay);
abyFileHeader[4] = STATIC_CAST(unsigned char, psDBF->nRecords & 0xFF);
abyFileHeader[5] = STATIC_CAST(unsigned char, (psDBF->nRecords>>8) & 0xFF);
abyFileHeader[6] = STATIC_CAST(unsigned char, (psDBF->nRecords>>16) & 0xFF);
abyFileHeader[7] = STATIC_CAST(unsigned char, (psDBF->nRecords>>24) & 0xFF);
psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
psDBF->sHooks.FWrite( abyFileHeader, sizeof(abyFileHeader), 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 );
}
/************************************************************************/
/* DBFGetLenWithoutExtension() */
/************************************************************************/
static int DBFGetLenWithoutExtension(const char* pszBasename)
{
int i;
int nLen = STATIC_CAST(int, strlen(pszBasename));
for( i = nLen-1;
i > 0 && pszBasename[i] != '/' && pszBasename[i] != '\\';
i-- )
{
if( pszBasename[i] == '.' )
{
return i;
}
}
return nLen;
}
/************************************************************************/
/* 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;
char *pszFullname;
int nBufSize = 500;
int nLenWithoutExtension;
/* -------------------------------------------------------------------- */
/* 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 SHPLIB_NULLPTR;
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. */
/* -------------------------------------------------------------------- */
nLenWithoutExtension = DBFGetLenWithoutExtension(pszFilename);
pszFullname = STATIC_CAST(char *, malloc(nLenWithoutExtension + 5));
memcpy(pszFullname, pszFilename, nLenWithoutExtension);
memcpy(pszFullname + nLenWithoutExtension, ".dbf", 5);
psDBF = STATIC_CAST(DBFHandle, calloc( 1, sizeof(DBFInfo) ));
psDBF->fp = psHooks->FOpen( pszFullname, pszAccess );
memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
if( psDBF->fp == SHPLIB_NULLPTR )
{
memcpy(pszFullname + nLenWithoutExtension, ".DBF", 5);
psDBF->fp = psDBF->sHooks.FOpen(pszFullname, pszAccess );
}
memcpy(pszFullname + nLenWithoutExtension, ".cpg", 5);
pfCPG = psHooks->FOpen( pszFullname, "r" );
if( pfCPG == SHPLIB_NULLPTR )
{
memcpy(pszFullname + nLenWithoutExtension, ".CPG", 5);
pfCPG = psHooks->FOpen( pszFullname, "r" );
}
free( pszFullname );
if( psDBF->fp == SHPLIB_NULLPTR )
{
free( psDBF );
if( pfCPG ) psHooks->FClose( pfCPG );
return SHPLIB_NULLPTR;
}
psDBF->bNoHeader = FALSE;
psDBF->nCurrentRecord = -1;
psDBF->bCurrentRecordModified = FALSE;
/* -------------------------------------------------------------------- */
/* Read Table Header info */
/* -------------------------------------------------------------------- */
pabyBuf = STATIC_CAST(unsigned char *, malloc(nBufSize));
if( psDBF->sHooks.FRead( pabyBuf, XBASE_FILEHDR_SZ, 1, psDBF->fp ) != 1 )
{
psDBF->sHooks.FClose( psDBF->fp );
if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
free( pabyBuf );
free( psDBF );
return SHPLIB_NULLPTR;
}
DBFSetLastModifiedDate(psDBF, pabyBuf[1], pabyBuf[2], pabyBuf[3]);
psDBF->nRecords =
pabyBuf[4]|(pabyBuf[5]<<8)|(pabyBuf[6]<<16)|((pabyBuf[7]&0x7f)<<24);
psDBF->nHeaderLength = nHeadLen = pabyBuf[8]|(pabyBuf[9]<<8);
psDBF->nRecordLength = pabyBuf[10]|(pabyBuf[11]<<8);
psDBF->iLanguageDriver = pabyBuf[29];
if (psDBF->nRecordLength == 0 || nHeadLen < XBASE_FILEHDR_SZ)
{
psDBF->sHooks.FClose( psDBF->fp );
if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
free( pabyBuf );
free( psDBF );
return SHPLIB_NULLPTR;
}
psDBF->nFields = nFields = (nHeadLen - XBASE_FILEHDR_SZ) / XBASE_FLDHDR_SZ;
/* coverity[tainted_data] */
psDBF->pszCurrentRecord = STATIC_CAST(char *, malloc(psDBF->nRecordLength));
/* -------------------------------------------------------------------- */
/* Figure out the code page from the LDID and CPG */
/* -------------------------------------------------------------------- */
psDBF->pszCodePage = SHPLIB_NULLPTR;
if( pfCPG )
{
size_t n;
memset( pabyBuf, 0, nBufSize);
psDBF->sHooks.FRead( pabyBuf, nBufSize - 1, 1, pfCPG );
n = strcspn( REINTERPRET_CAST(char *, pabyBuf), "\n\r" );
if( n > 0 )
{
pabyBuf[n] = '\0';
psDBF->pszCodePage = STATIC_CAST(char *, malloc(n + 1));
memcpy( psDBF->pszCodePage, pabyBuf, n + 1 );
}
psDBF->sHooks.FClose( pfCPG );
}
if( psDBF->pszCodePage == SHPLIB_NULLPTR && pabyBuf[29] != 0 )
{
snprintf( REINTERPRET_CAST(char *, pabyBuf), nBufSize, "LDID/%d", psDBF->iLanguageDriver );
psDBF->pszCodePage = STATIC_CAST(char *, malloc(strlen(REINTERPRET_CAST(char*, pabyBuf)) + 1));
strcpy( psDBF->pszCodePage, REINTERPRET_CAST(char *, pabyBuf) );
}
/* -------------------------------------------------------------------- */
/* Read in Field Definitions */
/* -------------------------------------------------------------------- */
pabyBuf = STATIC_CAST(unsigned char *, SfRealloc(pabyBuf,nHeadLen));
psDBF->pszHeader = REINTERPRET_CAST(char *, pabyBuf);
psDBF->sHooks.FSeek( psDBF->fp, XBASE_FILEHDR_SZ, 0 );
if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-XBASE_FILEHDR_SZ, 1,
psDBF->fp ) != 1 )
{
psDBF->sHooks.FClose( psDBF->fp );
free( pabyBuf );
free( psDBF->pszCurrentRecord );
free( psDBF->pszCodePage );
free( psDBF );
return SHPLIB_NULLPTR;
}
psDBF->panFieldOffset = STATIC_CAST(int *, malloc(sizeof(int) * nFields));
psDBF->panFieldSize = STATIC_CAST(int *, malloc(sizeof(int) * nFields));
psDBF->panFieldDecimals = STATIC_CAST(int *, malloc(sizeof(int) * nFields));
psDBF->pachFieldType = STATIC_CAST(char *, malloc(sizeof(char) * nFields));
for( iField = 0; iField < nFields; iField++ )
{
unsigned char *pabyFInfo;
pabyFInfo = pabyBuf+iField*XBASE_FLDHDR_SZ;
if( pabyFInfo[0] == HEADER_RECORD_TERMINATOR )
{
psDBF->nFields = iField;
break;
}
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] = STATIC_CAST(char, pabyFInfo[11]);
if( iField == 0 )
psDBF->panFieldOffset[iField] = 1;
else
psDBF->panFieldOffset[iField] =
psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
}
/* Check that the total width of fields does not exceed the record width */
if( psDBF->nFields > 0 &&
psDBF->panFieldOffset[psDBF->nFields-1] +
psDBF->panFieldSize[psDBF->nFields-1] > psDBF->nRecordLength )
{
DBFClose( psDBF );
return SHPLIB_NULLPTR;
}
DBFSetWriteEndOfFileChar( psDBF, TRUE );
return( psDBF );
}
/************************************************************************/
/* DBFClose() */
/************************************************************************/
void SHPAPI_CALL
DBFClose(DBFHandle psDBF)
{
if( psDBF == SHPLIB_NULLPTR )
return;
/* -------------------------------------------------------------------- */
/* Write out header if not already written. */
/* -------------------------------------------------------------------- */
if( psDBF->bNoHeader )
DBFWriteHeader( psDBF );
CPL_IGNORE_RET_VAL_INT(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 != SHPLIB_NULLPTR )
{
free( psDBF->panFieldOffset );
free( psDBF->panFieldSize );
free( psDBF->panFieldDecimals );
free( psDBF->pachFieldType );
}
if( psDBF->pszWorkField != SHPLIB_NULLPTR )
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;
int ldid = -1;
char chZero = '\0';
int nLenWithoutExtension;
/* -------------------------------------------------------------------- */
/* Compute the base (layer) name. If there is any extension */
/* on the passed in filename we will strip it off. */
/* -------------------------------------------------------------------- */
nLenWithoutExtension = DBFGetLenWithoutExtension(pszFilename);
pszFullname = STATIC_CAST(char *, malloc(nLenWithoutExtension + 5));
memcpy(pszFullname, pszFilename, nLenWithoutExtension);
memcpy(pszFullname + nLenWithoutExtension, ".dbf", 5);
/* -------------------------------------------------------------------- */
/* Create the file. */
/* -------------------------------------------------------------------- */
fp = psHooks->FOpen( pszFullname, "wb" );
if( fp == SHPLIB_NULLPTR )
{
free( pszFullname );
return SHPLIB_NULLPTR;
}
psHooks->FWrite( &chZero, 1, 1, fp );
psHooks->FClose( fp );
fp = psHooks->FOpen( pszFullname, "rb+" );
if( fp == SHPLIB_NULLPTR )
{
free( pszFullname );
return SHPLIB_NULLPTR;
}
memcpy(pszFullname + nLenWithoutExtension, ".cpg", 5);
if( pszCodePage != SHPLIB_NULLPTR )
{
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( CONST_CAST(void*, STATIC_CAST(const void*, pszCodePage)), strlen(pszCodePage), 1, fpCPG );
psHooks->FClose( fpCPG );
}
}
if( pszCodePage == SHPLIB_NULLPTR || ldid >= 0 )
{
psHooks->Remove( pszFullname );
}
free( pszFullname );
/* -------------------------------------------------------------------- */
/* Create the info structure. */
/* -------------------------------------------------------------------- */
psDBF = STATIC_CAST(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 = XBASE_FILEHDR_SZ + 1; /* + 1 for HEADER_RECORD_TERMINATOR */
psDBF->panFieldOffset = SHPLIB_NULLPTR;
psDBF->panFieldSize = SHPLIB_NULLPTR;
psDBF->panFieldDecimals = SHPLIB_NULLPTR;
psDBF->pachFieldType = SHPLIB_NULLPTR;
psDBF->pszHeader = SHPLIB_NULLPTR;
psDBF->nCurrentRecord = -1;
psDBF->bCurrentRecordModified = FALSE;
psDBF->pszCurrentRecord = SHPLIB_NULLPTR;
psDBF->bNoHeader = TRUE;
psDBF->iLanguageDriver = ldid > 0 ? ldid : 0;
psDBF->pszCodePage = SHPLIB_NULLPTR;
if( pszCodePage )
{
psDBF->pszCodePage = STATIC_CAST(char *, malloc( strlen(pszCodePage) + 1 ));
strcpy( psDBF->pszCodePage, pszCodePage );
}
DBFSetLastModifiedDate(psDBF, 95, 7, 26); /* dummy date */
DBFSetWriteEndOfFileChar(psDBF, TRUE);
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 == FTDate )
chNativeType = 'D';
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;
if( psDBF->nHeaderLength + XBASE_FLDHDR_SZ > 65535 )
{
char szMessage[128];
snprintf( szMessage, sizeof(szMessage),
"Cannot add field %s. Header length limit reached "
"(max 65535 bytes, 2046 fields).",
pszFieldName );
psDBF->sHooks.Error( szMessage );
return -1;
}
/* -------------------------------------------------------------------- */
/* Do some checking to ensure we can add records to this file. */
/* -------------------------------------------------------------------- */
if( nWidth < 1 )
return -1;
if( nWidth > XBASE_FLD_MAX_WIDTH )
nWidth = XBASE_FLD_MAX_WIDTH;
if( psDBF->nRecordLength + nWidth > 65535 )
{
char szMessage[128];
snprintf( szMessage, sizeof(szMessage),
"Cannot add field %s. Record length limit reached "
"(max 65535 bytes).",
pszFieldName );
psDBF->sHooks.Error( szMessage );
return -1;
}
nOldRecordLength = psDBF->nRecordLength;
nOldHeaderLength = psDBF->nHeaderLength;
/* -------------------------------------------------------------------- */
/* SfRealloc all the arrays larger to hold the additional field */
/* information. */
/* -------------------------------------------------------------------- */
psDBF->nFields++;
psDBF->panFieldOffset = STATIC_CAST(int *,
SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ));
psDBF->panFieldSize = STATIC_CAST(int *,
SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields ));
psDBF->panFieldDecimals = STATIC_CAST(int *,
SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ));
psDBF->pachFieldType = STATIC_CAST(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 += XBASE_FLDHDR_SZ;
psDBF->bUpdated = FALSE;
psDBF->pszHeader = STATIC_CAST(char *, SfRealloc(psDBF->pszHeader,
psDBF->nFields*XBASE_FLDHDR_SZ));
pszFInfo = psDBF->pszHeader + XBASE_FLDHDR_SZ * (psDBF->nFields-1);
for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
pszFInfo[i] = '\0';
strncpy( pszFInfo, pszFieldName, XBASE_FLDNAME_LEN_WRITE );
pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
if( chType == 'C' )
{
pszFInfo[16] = STATIC_CAST(unsigned char, nWidth % 256);
pszFInfo[17] = STATIC_CAST(unsigned char, nWidth / 256);
}
else
{
pszFInfo[16] = STATIC_CAST(unsigned char, nWidth);
pszFInfo[17] = STATIC_CAST(unsigned char, nDecimals);
}
/* -------------------------------------------------------------------- */
/* Make the current record buffer appropriately larger. */
/* -------------------------------------------------------------------- */
psDBF->pszCurrentRecord = STATIC_CAST(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 = STATIC_CAST(char *, malloc(sizeof(char) * psDBF->nRecordLength));
chFieldFill = DBFGetNullCharacter(chType);
for (i = psDBF->nRecords-1; i >= 0; --i)
{
nRecordOffset = nOldRecordLength * STATIC_CAST(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 * STATIC_CAST(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 );
}
if( psDBF->bWriteEndOfFileChar )
{
char ch = END_OF_FILE_CHARACTER;
nRecordOffset =
psDBF->nRecordLength * STATIC_CAST(SAOffset,psDBF->nRecords) + psDBF->nHeaderLength;
psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
psDBF->sHooks.FWrite( &ch, 1, 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 = SHPLIB_NULLPTR;
/* -------------------------------------------------------------------- */
/* Verify selection. */
/* -------------------------------------------------------------------- */
if( hEntity < 0 || hEntity >= psDBF->nRecords )
return SHPLIB_NULLPTR;
if( iField < 0 || iField >= psDBF->nFields )
return SHPLIB_NULLPTR;
/* -------------------------------------------------------------------- */
/* Have we read the record? */
/* -------------------------------------------------------------------- */
if( !DBFLoadRecord( psDBF, hEntity ) )
return SHPLIB_NULLPTR;
pabyRec = REINTERPRET_CAST(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 == SHPLIB_NULLPTR )
psDBF->pszWorkField = STATIC_CAST(char *, malloc(psDBF->nWorkFieldLength));
else
psDBF->pszWorkField = STATIC_CAST(char *, realloc(psDBF->pszWorkField,
psDBF->nWorkFieldLength));
}
/* -------------------------------------------------------------------- */
/* Extract the requested field. */
/* -------------------------------------------------------------------- */
memcpy( psDBF->pszWorkField,
REINTERPRET_CAST(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 = STATIC_CAST(int *, DBFReadAttribute( psDBF, iRecord, iField, 'I' ));
if( pnValue == SHPLIB_NULLPTR )
return 0;
else
return *pnValue;
}
/************************************************************************/
/* DBFReadDoubleAttribute() */
/* */
/* Read a double attribute. */
/************************************************************************/
double SHPAPI_CALL
DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
{
double *pdValue;
pdValue = STATIC_CAST(double *, DBFReadAttribute( psDBF, iRecord, iField, 'N' ));
if( pdValue == SHPLIB_NULLPTR )
return 0.0;
else
return *pdValue ;
}
/************************************************************************/
/* DBFReadStringAttribute() */
/* */
/* Read a string attribute. */
/************************************************************************/
const char SHPAPI_CALL1(*)
DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
{
return STATIC_CAST(const char *, DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
}
/************************************************************************/
/* DBFReadLogicalAttribute() */
/* */
/* Read a logical attribute. */
/************************************************************************/
const char SHPAPI_CALL1(*)
DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
{
return STATIC_CAST(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 == SHPLIB_NULLPTR )
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 == SHPLIB_NULLPTR )
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. */
/* pszFieldName must be at least XBASE_FLDNAME_LEN_READ+1 (=12) */
/* bytes long. */
/************************************************************************/
DBFFieldType SHPAPI_CALL
DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
int * pnWidth, int * pnDecimals )
{
if( iField < 0 || iField >= psDBF->nFields )
return( FTInvalid );
if( pnWidth != SHPLIB_NULLPTR )
*pnWidth = psDBF->panFieldSize[iField];
if( pnDecimals != SHPLIB_NULLPTR )
*pnDecimals = psDBF->panFieldDecimals[iField];
if( pszFieldName != SHPLIB_NULLPTR )
{
int i;
strncpy( pszFieldName, STATIC_CAST(char *,psDBF->pszHeader)+iField*XBASE_FLDHDR_SZ,
XBASE_FLDNAME_LEN_READ );
pszFieldName[XBASE_FLDNAME_LEN_READ] = '\0';
for( i = XBASE_FLDNAME_LEN_READ - 1; i > 0 && pszFieldName[i] == ' '; i-- )
pszFieldName[i] = '\0';
}
if ( psDBF->pachFieldType[iField] == 'L' )
return( FTLogical );
else if( psDBF->pachFieldType[iField] == 'D' )
return( FTDate );
else if( psDBF->pachFieldType[iField] == 'N'
|| psDBF->pachFieldType[iField] == 'F' )
{
if( psDBF->panFieldDecimals[iField] > 0
|| psDBF->panFieldSize[iField] >= 10 )
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[XBASE_FLD_MAX_WIDTH+1], 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 = REINTERPRET_CAST(unsigned char *,psDBF->pszCurrentRecord);
psDBF->bCurrentRecordModified = TRUE;
psDBF->bUpdated = TRUE;
/* -------------------------------------------------------------------- */
/* Translate NULL value to valid DBF file representation. */
/* */
/* Contributed by Jim Matthews. */
/* -------------------------------------------------------------------- */
if( pValue == SHPLIB_NULLPTR )
{
memset( 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( STATIC_CAST(int,sizeof(szSField))-2 < nWidth )
nWidth = sizeof(szSField)-2;
snprintf( szFormat, sizeof(szFormat), "%%%d.%df",
nWidth, psDBF->panFieldDecimals[iField] );
CPLsnprintf(szSField, sizeof(szSField), szFormat, *STATIC_CAST(double *, pValue) );
szSField[sizeof(szSField)-1] = '\0';
if( STATIC_CAST(int,strlen(szSField)) > psDBF->panFieldSize[iField] )
{
szSField[psDBF->panFieldSize[iField]] = '\0';
nRetResult = FALSE;
}
strncpy(REINTERPRET_CAST(char *, pabyRec+psDBF->panFieldOffset[iField]),
szSField, strlen(szSField) );
break;
}
case 'L':
if (psDBF->panFieldSize[iField] >= 1 &&
(*STATIC_CAST(char*,pValue) == 'F' || *STATIC_CAST(char*,pValue) == 'T'))
*(pabyRec+psDBF->panFieldOffset[iField]) = *STATIC_CAST(char*,pValue);
break;
default:
if( STATIC_CAST(int, strlen(STATIC_CAST(char *,pValue))) > psDBF->panFieldSize[iField] )
{
j = psDBF->panFieldSize[iField];
nRetResult = FALSE;
}
else
{
memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
psDBF->panFieldSize[iField] );
j = STATIC_CAST(int, strlen(STATIC_CAST(char *,pValue)));
}
strncpy(REINTERPRET_CAST(char *, pabyRec+psDBF->panFieldOffset[iField]),
STATIC_CAST(const 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 = REINTERPRET_CAST(unsigned char *, psDBF->pszCurrentRecord);
/* -------------------------------------------------------------------- */
/* Assign all the record fields. */
/* -------------------------------------------------------------------- */
if( STATIC_CAST(int, strlen(STATIC_CAST(char *, pValue))) > psDBF->panFieldSize[iField] )
j = psDBF->panFieldSize[iField];
else
{
memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
psDBF->panFieldSize[iField] );
j = STATIC_CAST(int, strlen(STATIC_CAST(char *, pValue)));
}
strncpy(REINTERPRET_CAST(char *, pabyRec+psDBF->panFieldOffset[iField]),
STATIC_CAST(const 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, STATIC_CAST(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, STATIC_CAST(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, STATIC_CAST(void *, CONST_CAST(char*, pszValue))) );
}
/************************************************************************/
/* DBFWriteNULLAttribute() */
/* */
/* Write a string attribute. */
/************************************************************************/
int SHPAPI_CALL
DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
{
return( DBFWriteAttribute( psDBF, iRecord, iField, SHPLIB_NULLPTR ) );
}
/************************************************************************/
/* DBFWriteLogicalAttribute() */
/* */
/* Write a logical attribute. */
/************************************************************************/
int SHPAPI_CALL
DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
const char lValue)
{
return( DBFWriteAttribute( psDBF, iRecord, iField, STATIC_CAST(void *, CONST_CAST(char*, &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 = REINTERPRET_CAST(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 SHPLIB_NULLPTR;
if( !DBFLoadRecord( psDBF, hEntity ) )
return SHPLIB_NULLPTR;
return STATIC_CAST(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 == SHPLIB_NULLPTR ) return SHPLIB_NULLPTR;
newDBF->nFields = psDBF->nFields;
newDBF->nRecordLength = psDBF->nRecordLength;
newDBF->nHeaderLength = psDBF->nHeaderLength;
if( psDBF->pszHeader )
{
newDBF->pszHeader = STATIC_CAST(char *, malloc ( XBASE_FLDHDR_SZ * psDBF->nFields ));
memcpy ( newDBF->pszHeader, psDBF->pszHeader, XBASE_FLDHDR_SZ * psDBF->nFields );
}
newDBF->panFieldOffset = STATIC_CAST(int *, malloc ( sizeof(int) * psDBF->nFields ));
memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
newDBF->panFieldSize = STATIC_CAST(int *, malloc ( sizeof(int) * psDBF->nFields ));
memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
newDBF->panFieldDecimals = STATIC_CAST(int *, malloc ( sizeof(int) * psDBF->nFields ));
memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
newDBF->pachFieldType = STATIC_CAST(char *, malloc ( sizeof(char) * psDBF->nFields ));
memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(char)*psDBF->nFields );
newDBF->bNoHeader = TRUE;
newDBF->bUpdated = TRUE;
newDBF->bWriteEndOfFileChar = psDBF->bWriteEndOfFileChar;
DBFWriteHeader ( newDBF );
DBFClose ( newDBF );
newDBF = DBFOpen ( pszFilename, "rb+" );
newDBF->bWriteEndOfFileChar = psDBF->bWriteEndOfFileChar;
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 ' ';
}
/************************************************************************/
/* 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[XBASE_FLDNAME_LEN_READ+1];
int i;
for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
{
DBFGetFieldInfo( psDBF, i, name, SHPLIB_NULLPTR, SHPLIB_NULLPTR );
if(!STRCASECMP(pszFieldName,name))
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 == SHPLIB_NULLPTR )
return SHPLIB_NULLPTR;
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 = STATIC_CAST(int *,
SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ));
psDBF->panFieldSize = STATIC_CAST(int *,
SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields ));
psDBF->panFieldDecimals = STATIC_CAST(int *,
SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ));
psDBF->pachFieldType = STATIC_CAST(char *,
SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields ));
/* update header information */
psDBF->nHeaderLength -= XBASE_FLDHDR_SZ;
psDBF->nRecordLength -= nDeletedFieldSize;
/* overwrite field information in header */
memmove(psDBF->pszHeader + iField*XBASE_FLDHDR_SZ,
psDBF->pszHeader + (iField+1)*XBASE_FLDHDR_SZ,
sizeof(char) * (psDBF->nFields - iField)*XBASE_FLDHDR_SZ);
psDBF->pszHeader = STATIC_CAST(char *, SfRealloc(psDBF->pszHeader,
psDBF->nFields*XBASE_FLDHDR_SZ));
/* update size of current record appropriately */
psDBF->pszCurrentRecord = STATIC_CAST(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 = STATIC_CAST(char *, malloc(sizeof(char) * nOldRecordLength));
/* shift records to their new positions */
for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
{
nRecordOffset =
nOldRecordLength * STATIC_CAST(SAOffset,iRecord) + nOldHeaderLength;
/* load record */
psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
nRecordOffset =
psDBF->nRecordLength * STATIC_CAST(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 );
}
if( psDBF->bWriteEndOfFileChar )
{
char ch = END_OF_FILE_CHARACTER;
SAOffset nEOFOffset =
psDBF->nRecordLength * STATIC_CAST(SAOffset,psDBF->nRecords) + psDBF->nHeaderLength;
psDBF->sHooks.FSeek( psDBF->fp, nEOFOffset, 0 );
psDBF->sHooks.FWrite( &ch, 1, 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 = STATIC_CAST(int *, calloc(sizeof(int), psDBF->nFields));
panFieldSizeNew = STATIC_CAST(int *, calloc(sizeof(int), psDBF->nFields));
panFieldDecimalsNew = STATIC_CAST(int *, calloc(sizeof(int), psDBF->nFields));
pachFieldTypeNew = STATIC_CAST(char *, calloc(sizeof(char), psDBF->nFields));
pszHeaderNew = STATIC_CAST(char*, malloc(sizeof(char) * XBASE_FLDHDR_SZ *
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 * XBASE_FLDHDR_SZ,
psDBF->pszHeader + panMap[i] * XBASE_FLDHDR_SZ, XBASE_FLDHDR_SZ);
}
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 = STATIC_CAST(char *, malloc(sizeof(char) * psDBF->nRecordLength));
pszRecordNew = STATIC_CAST(char *, malloc(sizeof(char) * psDBF->nRecordLength));
/* shuffle fields in records */
for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
{
nRecordOffset =
psDBF->nRecordLength * STATIC_CAST(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 > XBASE_FLD_MAX_WIDTH )
nWidth = XBASE_FLD_MAX_WIDTH;
/* -------------------------------------------------------------------- */
/* 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 + XBASE_FLDHDR_SZ * iField;
for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
pszFInfo[i] = '\0';
strncpy( pszFInfo, pszFieldName, XBASE_FLDNAME_LEN_WRITE );
pszFInfo[11] = psDBF->pachFieldType[iField];
if( chType == 'C' )
{
pszFInfo[16] = STATIC_CAST(unsigned char, nWidth % 256);
pszFInfo[17] = STATIC_CAST(unsigned char, nWidth / 256);
}
else
{
pszFInfo[16] = STATIC_CAST(unsigned char, nWidth);
pszFInfo[17] = STATIC_CAST(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 = STATIC_CAST(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 = STATIC_CAST(char *, malloc(sizeof(char) * nOldRecordLength));
char* pszOldField = STATIC_CAST(char *, malloc(sizeof(char) * (nOldWidth + 1)));
/* cppcheck-suppress uninitdata */
pszOldField[nOldWidth] = 0;
/* move records to their new positions */
for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
{
nRecordOffset =
nOldRecordLength * STATIC_CAST(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' || chOldType == 'D') && 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 * STATIC_CAST(SAOffset,iRecord) + psDBF->nHeaderLength;
/* write record */
psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
}
if( psDBF->bWriteEndOfFileChar )
{
char ch = END_OF_FILE_CHARACTER;
nRecordOffset =
psDBF->nRecordLength * STATIC_CAST(SAOffset,psDBF->nRecords) + psDBF->nHeaderLength;
psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
}
/* TODO: truncate file */
free(pszRecord);
free(pszOldField);
}
else if (nWidth > nOldWidth)
{
char* pszRecord = STATIC_CAST(char *, malloc(sizeof(char) * psDBF->nRecordLength));
char* pszOldField = STATIC_CAST(char *, malloc(sizeof(char) * (nOldWidth + 1)));
/* cppcheck-suppress uninitdata */
pszOldField[nOldWidth] = 0;
/* move records to their new positions */
for (iRecord = psDBF->nRecords - 1; iRecord >= 0; iRecord--)
{
nRecordOffset =
nOldRecordLength * STATIC_CAST(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 * STATIC_CAST(SAOffset,iRecord) + psDBF->nHeaderLength;
/* write record */
psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
}
if( psDBF->bWriteEndOfFileChar )
{
char ch = END_OF_FILE_CHARACTER;
nRecordOffset =
psDBF->nRecordLength * STATIC_CAST(SAOffset,psDBF->nRecords) + psDBF->nHeaderLength;
psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
}
free(pszRecord);
free(pszOldField);
}
psDBF->nCurrentRecord = -1;
psDBF->bCurrentRecordModified = FALSE;
psDBF->bUpdated = TRUE;
return TRUE;
}
/************************************************************************/
/* DBFSetWriteEndOfFileChar() */
/************************************************************************/
void SHPAPI_CALL DBFSetWriteEndOfFileChar( DBFHandle psDBF, int bWriteFlag )
{
psDBF->bWriteEndOfFileChar = bWriteFlag;
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/xiyan100/shapelib.git
git@gitee.com:xiyan100/shapelib.git
xiyan100
shapelib
shapelib
master

搜索帮助

23e8dbc6 1850385 7e0993f3 1850385