Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

.dbf file header. (FoxPro)

655 views
Skip to first unread message

Colin Bompas

unread,
Dec 22, 2002, 3:25:15 PM12/22/02
to
My client has corrupt data on a .dbf data base table. I
have identified it to be the header that has been
trashed. Has any one knowledge of a tool that I could get
hold of to set this right. (Client last backed up in
January!!)
Thanks
Colin

Eric den Doop

unread,
Dec 22, 2002, 6:24:33 PM12/22/02
to
Check the download area of www.universalthread.com. You should be able to
find some DBF fixers. For a commercial product: try
http://www.stonefield.com/
--
Eric den Doop
www.foxite.com - The Home Of The Visual FoxPro Experts - Powered By VFP7

"Colin Bompas" <colin...@ascii.co.za> wrote in message
news:037601c2a9f8$3c76aff0$8df82ecf@TK2MSFTNGXA02...

CindyWinegarden

unread,
Dec 22, 2002, 10:22:42 PM12/22/02
to
Colin Bompas <colin...@ascii.co.za> scribbled in
news:037601c2a9f8$3c76aff0$8df82ecf@TK2MSFTNGXA02 ...

> My client has corrupt data on a .dbf data base table. I
> have identified it to be the header ....

Colin, a description of the header is "Table File Structure (.dbc, .dbf,
..frx, .lbx, .mnx, .pjx, .scx, .vcx)" in Help. If you've got a mismatched
number of records you can fix that using directions at
http://fox.wikis.com/wc.dll?Wiki~NotATable~VFP. In any case you've got a Hex
editor already in the Tools directory.

--
Cindy Winegarden MCSD, Microsoft Visual FoxPro MVP
cindy.wi...@mvps.org http://cindywinegarden.adsl.duke.edu
http://mdsn.microsoft.com/vfoxpro http://foxcentral.net


Tom Bellmer

unread,
Dec 23, 2002, 8:10:22 PM12/23/02
to
Try this, it will fix corrupted record count values:

**********************************************************
************
* Program Name: FIXRECNT.PRG
* Purpose: Rewrite correct RECCOUNT() value to
DBF header
* Written by: Tom Bellmer
* Date Written: 06/28/93
* Modified: 08/11/93
* Usage: If dbf name = TEMP.DBF
* DO fixrecnt WITH "temp.dbf" OR
=fixrecnt("temp.dbf")
**********************************************************
***********
PARAMETERS lcfname
PRIVATE ALL LIKE l*

IF AT('.',lcfname) = 0
? CHR(7)
WAIT WINDOW "File name with extension is
required..."
RETURN
ENDIF

lnhandle =FOPEN(lcfname,12) && Open
w/unbuffered read/write
IF lnhandle = -1
&& Test for error
WAIT WINDOW "Error: "+STR(FERROR(),2)
RETURN
ENDIF
lchdrinfo =FREAD(lnhandle,12) && Read first 12
characters

* Calculate the header length
lnhdrsize = INT(ASC(SUBSTR(lchdrinfo,09,01)) ;
+ ASC(SUBSTR(lchdrinfo,10,01))
* 256)
* Calculate the record length
lnreclngth = INT(ASC(SUBSTR(lchdrinfo,11,01)) ;
+ ASC(SUBSTR(lchdrinfo,12,01)) * 256)

**********************************************************
**************
* ADIR returns file statistics into the array
named 'lafsize'. The
* variable 'lnreccnt' calculates the record count by
subtracting the
* header length from the file size and dividing the
result by the
* record length.
**********************************************************
**************
=ADIR(lafsize,lcfname)
lnreccnt = INT((lafsize[2] - lnhdrsize) / lnreclngth)

**********************************************************
**************
* Modulus division is used to return the remainder of
division by 256
* taken to a decreasing exponent power.
**********************************************************
**************
lcfirst8 = LEFT(lchdrinfo,4) + SPACE(4)
FOR lni = 3 TO 0 STEP -1
lcfirst8 = STUFF(lcfirst8,lni+5,1,CHR(INT
(lnreccnt / 256^lni)))
lnreccnt = lnreccnt % 256^lni
ENDFOR

=FSEEK(lnhandle,0,0) && Go to the top
of the file
=FWRITE(lnhandle,m.lcfirst8) && Write 1st 4 positions
& RECCOUNT() val
=FCLOSE(lnhandle) && Close
the file

RETURN
* EOF fixrecnt.prg

>.
>

Darrell

unread,
Dec 25, 2002, 10:37:29 PM12/25/02
to
Tom:

I might add that, users/newbies should be extremely
careful when running 'offered' code to fix tables.

If the table is in a DBC or has memos of a whole host of
other possibilities, they can make matters worse if they
don't know what they are doing.

I've found that, although the file structure isn't that hard
to grasp after you've spent the requisite time studying it,
the average user won't appreciate the subtleties involved.

It's typically better to go with a commercial grade application
that will detect all the types possible.

By the way - decent code.

Darrell

"Tom Bellmer" <tbel...@kc.rr.com> wrote in message
news:03bd01c2aae9$3b86d830$d2f82ecf@TK2MSFTNGXA09...

CindyWinegarden

unread,
Dec 25, 2002, 11:39:21 PM12/25/02
to
Darrell <som...@somewhere.com> scribbled in
news:ZPuO9.91$jn3.7...@newssvr15.news.prodigy.com ...

> I might add that, users/newbies should be extremely
> careful when running 'offered' code to fix tables.

Let me add, do all the experimenting you want - on a backup copy!

josepe

unread,
Dec 26, 2002, 5:20:50 PM12/26/02
to Colin Bompas
** Try run this under Foxpro 2.x for DOS. Work nice to solve
several issues.
*****************************************************************************

* FIXDBFLT.PRG (FIXDBF Lite) v1.00, July 1995
* by Lowell Fishman Š Copyright 1995
* All Rights Reserved
* DESCRIPTION:
*
* FIXDBFLT repairs damaged FoxPro dbf headers unless extreme damage
* has destroyed vital information.
*
* Associated fpt (memo file) FIXDBF will be correctly repaired too,
unlike
* FILEFIX, which is reported to destroy FoxPro memo files. As
implemented,
* FIXDBFLT should only be used on FoxPro (not dBase or FoxBase) dbfs. It

* should be trivial to modify the code for these other Xbase
implementations,
* if needed. However, I have no plans to do so, so it's up to you.
Before
* doing a repair, FIXDBFLT asks first, and if you want to proceed it
backs up
* the damaged file with its extension reversed. (.DBF ==> .FBD, .FPT ==>
..TPF)
*
* FIXDBFLT was developed under FoxPro 2.5 Mac, but should operate
equally
* well on other platforms, as it has no platform-specific code that I am

* aware of. It works well under FoxPro 2.6 Windows, but I have not tried

* it on any other versions or platforms.
*
* HOW TO USE FIXDBFLT:
*
* To use, just issue DO FIXDBFLT. A file selection dialogue will be
presented
* repeatedly. Locate the dbf you wish to repair and click 'OK'.
* When you have no more dbfs to fix, click 'Cancel'. That's all there
* is to it. If the fpt memo blocksize appears to be in error, you will
be asked
* to enter the value to use. The FoxPro default is 64. Your installation

* convention may be different. Also, different fpts may have different
* blocksizes, so you have to know what's what here. If you have no
reason
* to assume otherwise, accept the suggested value of 64. The enhanced
version,
* FIXDBF, which comes with the DICT4FP package, bypasses this step as
long
* as the dbf is in the DICT4FP database dictionary.
*
* FIXDBFLT is SHAREWARE, it is *not* free. If you find it useful, please
send
* the $10 (Ten dollar) shareware fee (a bargain!) to me at the address
below.
* Please help support the shareware system (and me too!) by *actually
sending
* it*, not just thinking about it!
*
* If you find FIXDBFLT useful, might I suggest that you consider
* purchasing the DICT4FP package (which I offer for sale at $25 to
registered
* users of FIXDBLT, $35 otherwise). DICT4FP (Dictionary for FoxPro), not
being
* shareware, is available by mail-order only. Once your check is
received, I
* will be glad to send either a 3 1/2" diskette (state Mac or DOS
format) or
* email you the source, if you prefer.
*
* DICT4FP maintains and prints a complete site database and index
dictionary,
* prints the dictionary for documentation purposes, recreates damaged
indexes,
* database headers and/or structures, or memo file (fpt) headers but
not, of
* course, data. It permits automatic dictionary updating to be
performed. It
* may be used either as a 'stand-alone' program or called as a
subroutine.
* This is useful in building initialization routines. It can also scan
all dbfs
* in the dictionary and automatically determine which indexes are
out-of-date
* or in need of repair, and update or repair them. DICT4FP uses the
full-
* featured version of FIXDBF which automatically rebuilds dbf and fpt
headers
* from dictionary information if they would otherwise be beyond repair.
*
* Also, please remember that I am available for FoxPro design and
* development consulting. :) (Information on how to reach me is below.)
*
*
* TERMS AND CONDITIONS:
*
*
* 1) FIXDBF is shareware. If you keep it for more than thirty (30) days,
you
* owe me ten bucks ($10.00, U.S.currency). More lavish voluntary
donations
* to the author will not, however, be refused. Checks drawn on U.S.
banks only,
* please. Foreign purchasers please send U.S. currency.
*
* 2) FIXDBF is Š copyright 1995 by Lowell Fishman. All rights reserved.
* You may use FIXDBF on your own personal or business computer.
* You may freely distribute unmodified copies of this program, with all
* comments (including this legalese section) but you may not charge
money for
* it or include it as part of any sale of, promotion for, or offering
of,
* any product or service for which money is charged, other than as a
normal
* inclusion in the shareware libraries of online services.
*
* You may modify this program for your own use, but you may not
distribute
* such modified copies. Any other use of this program including, but not

* limited to commercial duplication and distribution is expressly
forbidden.
* Inquiries from commercial distributors of shareware, such as
publishers
* of CD-ROMS or floppy-disk shareware collections, regarding licenses,
are
* not only invited, but devoutly hoped for. :)
*
* 3) You agree to use FIXDBF entirely at your own risk. The author is
not
* liable for any damages, direct or consequential, resulting from any
use
* of this program, or for any errors it may contain.
*
* 4) Please feel free to report any problems with this program to the
author.
* I will probably attempt to remedy them. However, this program comes
with
* absolutely no warranty, or guarantee of support of any kind.
*
* 5) The author may be reached by email or by telephone, fax, or snail
mail at:
*
* Lowell Fishman
* 69 Bayview Avenue
* Portsmouth, RI 02871
* Tel: (401) 683-6288
* Fax: (401) 683-0368
* Email: <pin...@aol.com>
*
*****************************************************************************

set echo off
home = sys(5) + curdir() && get the directory we're operating from

* save the environment for when we're done
vfn = sys(3)
create view (home + vfn +'.VUE')
set talk off
clear
close all
close data

* Loop as long as the user has a dbf to fix
do while .T.
close all && in case something is open from last loop

* get file name and path information
longname = getfile('DBF','Find the dbf to be repaired')
if empty(longname)
exit
endif
thePath = left(longname, rat('\',longname))
dbname = right(longname, len(longname) - rat('\', longname))
fptname = left(dbname, rat('.', dbname)) + 'fpt'
set default to (thePath)

* Is there an .fpt file?
hasfpt = file(fptname) && .t. if it has a memo file


* get file header and extract existing info
dbhandle = fopen(dbname, 12) && unbuffered is slower but safer
if ferror() # 0
wait window timeout 5 "Can't open dbf! Repair not made!"
loop
else
wait window nowait "Analyzing dbf . . ."
endif

fsize = fseek(dbhandle,0,2) && get file size
= fseek(dbhandle,0,0) && point to beginning
hdr = fread(dbhandle,32) && get header
if ferror() # 0
wait window timeout 5 "Can't read dbf! Repair not made!"
loop
endif

xhdrtype = left(hdr,1) &&existing header type flag
memotype = .F. && assume no memo fields until proven otherwise

* If you opt to repair a non-FoxPro dbf, it will end up looking like
* a FoxPro dbf

do case
case xhdrtype = chr(3) && x'03'
memotype = .F.
case xhdrtype = chr(245) && x'F5'
memotype = .T.
case xhdtype = chr(131) && x'83'
if !attention("Just Checking . . .", ;
"This may be a FoxBase+ or dBaseIII Plus dbf with memo file." ;
+ chr(13) + "Fix it anyway?")
loop
endif
case xhdrtype = chr(139) && x'8B'
if !attention("Just Checking . . .", ;
"This may be a dBaseIV dbf with memo file." ;
+ chr(13) + "Fix it anyway?")
loop
endif
endcase

xpof = unintel(substr(hdr, 9, 2)) && where the hdr delimiter should be
xnrecs = unintel(substr(hdr, 5,4)) && what the number of records should
be
xldata = unintel(substr(hdr, 11, 2)) && what the record length should
be

* convert date from header
tdte = right('0' + alltrim(str(unintel(substr(hdr, 3, 1)))),2) + '/' ;
+ right('0' + alltrim(str(unintel(substr(hdr, 4, 1)))),2) + '/' ;
+ right('0' + alltrim(str(unintel(substr(hdr, 2, 1)))),2)

* test if it's valid, if not, don't make an issue of it, just fix it
baddate = .F.
if empty(ctod(tdte))
tdte = dtoc(date()) && if not, use today's date
baddate = .T.
endif
xdate = chr(val(right(tdte,2))) + + chr(val(left(tdte,2))) + ;
chr(val(substr(tdte,4,2))) && ymd


* compute header info for comparison
nflds = 0
ldata = 1 && 1 byte for the delete flag
=fseek(dbhandle, 32) && position past header
pof = 0
hasmemo = .F.
maxlen = 0 && computed max length of record
do while !feof(dbhandle)
nflds = nflds + 1
fldrec = fread(dbhandle,32)
if left(fldrec,1) = chr(13)
pof = 32*nflds + 1
exit
else
* verify the field rec
if frok(fldrec, @maxlen, @hasmemo)
ldata = ldata + unintel(substr(fldrec, 17, 1)) && accum data rec
length
else
* if it's garbage, there's nothing left to do.
=attention("Fatal Error", ;
"Invalid field record. Dbf is not repairable", .T.)
loop
endif
endif
enddo

* if little (<32 bytes) or no data, or premature eof
if feof(dbhandle)
if pof = 0
=attention("Fatal Error", ;
"No header delimiter found. Dbf is not repairable", .T.)
loop
else && probably empty dbf
if len(fldrec) <= 1 && no data after delimiter
dbfempty = .T.
else
dbfempty = .F. && less than 32 bytes of data, so check
if ldata > 31 && inconsistency we can fix
wait window timeout 5 "Hdr/Data Length Inconsistency"
endif
endif
endif
else
dbfempty = .F. && normal case
endif

* compute how many records there actually are
nrecs = int((fsize - pof - 1)/ldata)


if maxlen + 1 # ldata && we'll fix this
wait window timeout 5 "Data Length inconsistency"
endif

if !hasmemo and hasfpt && very odd . . .
=attention("For your information . . .", ;
"There is an .fpt file with the same name as this dbf," + chr(13) + ;
"although this dbf does not have any memo fields.", .T.)
endif

if hasmemo and !hasfpt && missing fpt file, but fix whatever else we
can
=attention("For your information . . .", ;
"There is no .fpt file for this dbf!" + chr(13) + ;
"To salvage data, make a copy without the memo fields!", .T.)
endif

wait clear

* if there is anything wrong with the header, make a new one
if xpof # pof or xnrecs # nrecs or xldata # ldata or ;
xdate # substr(hdr, 2, 3) ;
or memotype # hasmemo or hasmemo and xhdrtype#chr(245) ;
or !hasmemo and xhdrtype # chr(3) or baddate

if attention("Please tell me . . .", "This dbf has a bad header." +
chr(13) + ;
"Should I repair it?")
wait window nowait "Repairing dbf . . ."
=backup(dbname, @dbhandle)
=fseek(dbhandle,0) && position at beginning of header
* construct valid header and write it
newhdr = iif(hasmemo, chr(245), chr(3)) ;
+ xdate + intel(nrecs,4) + intel(pof,2) + intel(ldata,2) ;
+ substr(hdr,13,20) && take the rest including code page, as is
=fwrite(dbhandle, newhdr)
if ferror() = 0
wait window timeout 3 "dbf Repair successful!"
else
wait window timeout 3 "New dbf header not written. Repair not done!"


endif
endif
else

=attention("For your information . . .", "This dbf is OK!", .T.)

endif

wait clear

* dbf part is all done
* Now see if there is an fpt to repair

if hasmemo and hasfpt

envblksz = set('BLOCKSIZE') && the environment blocksize, default 64
fpthandle = fopen(fptname, 12)
if ferror() # 0
wait window timeout 5 "Can't open fpt! Repair not made!"
loop
else
wait window nowait "Analyzing fpt"
endif

fpthdr = fread(fpthandle, 8) && get fpt header
if ferror() # 0
wait window timeout 5 "Can't read fpt! Repair not made!"
loop
endif

size = fseek(fpthandle, 0, 2) && file size
fptblksz = unltor(substr(fpthdr, 7, 2)) && the block size shown in the
fpt
fptptr = unltor(substr(fpthdr, 1, 4)) &&fpt ptr to next available
block

* pointer to next available memo block times blocksize
* should equal filesize, since pointer starts counting at 0

if fptptr # int(size/fptblksz)
valok = .F.

* This version requires manual input of correct blocksize

do while !valok
y = attention2("Possible Blocksize Error", ;
+ "fpt file shows a blocksize of " + alltrim(str(fptblksz)) ;
+ ". Default is " + alltrim(str(envblksz)) + ". Value to use:", ;
envblksz)

if y > 0 and y = int(y) && must be a positive integer
valok = .T.
else
if y = 0
exit
else
wait window nowait ;
"Blocksize must be a positive integer!"
endif
endif
enddo
if y = 0 && if no value was supplied, assume user wants to cancel
wait window timeout 3 "fpt repair cancelled"
loop
else && easy to fix it, now that all the work is done
wait window nowait "Repairing fpt . . ."
=backup(fptname, @fpthandle)
fptblksz = y
* if blocksize < 33 it represents a multiple of 512
fptblksz = iif(fptblksz < 33, fptblksz*512, fptblksz)
fptptr = int(size/fptblksz)
newhdr = ltor(fptptr,4) + chr(0) + chr(0) + ltor(fptblksz, 2)
=fseek(fpthandle, 0)
=fwrite(fpthandle, newhdr)
if ferror() = 0
wait window timeout 3 "fpt Repair successful!"
else
wait window timeout 3 "New fpt header not written. Repair not
done!"

endif

endif
else
wait window timeout 3 'fpt is OK!'
endif

endif
close all
wait clear
enddo
close all
wait clear

* restore the environment
set view to (home + vfn +'.VUE')
delete file (home + vfn + '.VUE')

return

*******************************************************************
*
* User defined functions
*
* Note: FoxPro uses both Intel style and normal (=sane) numbers
*
*******************************************************************

function unintel && convert from intel 8086 format numbers
parameters x
private all
res = 0
for i = len(x) to 1 step - 1
res = res * 256 + asc(substr(x, i, 1))
endfor
return res

function intel && convert to intel 8086 format numbers
parameters num, digs
private all
res = ''
for i = 1 to digs
res = res + chr(mod(num, 256))
num = int(num/256)
endfor
return res

function unltor && convert from l -> r format #s
parameters x
private all
res = 0
for i = 1 to len(x)
res = res *256 + asc(substr(x, i, 1))
endfor
return res

function ltor && convert to l -> r format #s
parameters num, digs
res = ''
for i = 1 to digs && for the desired number of digits
res = chr(mod(num, 256)) + res
num = int(num/256)
endfor
return res

function frok && check the validity of a field record in the dbf header
parameters fr, maxlen, hasmemo
private all
*check name
nameok = .T. && assume good until proven bad

for i = 10 to 1 step - 1 && count nulls, if any, at end of name
if substr(fr, i, 1) = chr(0)
loop
else
exit
endif
endfor

if !isalpha(left(fr,1)) && make sure name begins with an alpha
nameok = .F.
endif

for j = 2 to i && validate characters 2 ==> end
x = substr(fr, i, 1)
if !(isalpha(x) or isdigit(x) or x='_')
nameok = .F.
exit
endif
endfor

* Type has to be one of these characters
typeok = iif(substr(fr, 12, 1)$'CNLMGDFP', .T., .F.)

hasmemo = hasmemo or substr(fr, 12, 1)$'MGP' && is there a memo type
field?

* accumulate record length in maxlen
fl = asc(substr(fr, 17, 1)) && field length
* find max of field displacement + length - 1
maxlen = max(maxlen, unintel(substr(fr, 13, 4)) + fl - 1)

* validate decimal places
decok = iif(asc(substr(fr, 18, 1)) < fl, .T., .F.)
return nameok and typeok and decok && .T. if everything's good

* *********************************************************
* * attention() -- Puts up a 1 or 2-button dialog box
* * Should be pretty non-platform-specific
* *********************************************************

function attention
parameter titletxt, msg, ok && if 'ok' is present, only use "OK" button,
return .T.
private tmsg

tmsg = alltrim(msg)
SET BORDER TO PANEL
DEFINE WINDOW chat ;
AT 5, 9 ;
SIZE 10,66 ;
TITLE titletxt ;
NOCLOSE ;
SYSTEM
MOVE WINDOW chat CENTER

ACTIVATE WINDOW chat
@ 2,MAX(0,(3+max(0,0.5*(60-LEN(tmsg))))) SAY tmsg ;
SIZE 2,60

if parameters() = 3 && it's information only
@ 6,28 GET mresponse ;
PICTURE "@*HT3 \!OK" ;
SIZE 2,8,1 ;
DEFAULT 1
else
@ 6,23 GET mresponse ;
PICTURE "@*HT3 \!OK;\?No" ;
SIZE 2,8,1 ;
DEFAULT 1
endif

READ MODAL
RELEASE WINDOW chat

if parameters() = 3 && Information only case
return .T.
else
if mresponse = 1
return .T.
else
return .F.
endif
endif


* *********************************************************
* * attention2() -- Puts up a 2-button dialog box and gets a
value
* *********************************************************

function attention2
parameter titletxt, msg, val
private tmsg
set readborder on
tmsg = alltrim(msg)
SET BORDER TO PANEL
DEFINE WINDOW chat ;
AT 5, 9 ;
SIZE 10,66 ;
TITLE titletxt ;
NOCLOSE ;
SYSTEM
MOVE WINDOW chat CENTER

ACTIVATE WINDOW chat
@ 2,MAX(0,(3+max(0,0.5*(60-LEN(tmsg))))) SAY tmsg ;
SIZE 2,60

@ 3, 23 GET value ;
PICTURE "99999" ;
SIZE 1,5 ;
DEFAULT val

@ 6,23 GET mresponse ;
PICTURE "@*HT3 \!OK;\?No" ;
SIZE 2,8,1 ;
DEFAULT 1

READ MODAL
RELEASE WINDOW chat
set readborder off
if mresponse = 1
return value
else
return 0
endif


* ******************************************************
* *
* * Create a backup of file being repaired, with
* * extension reversed.
* *
* ******************************************************

function backup
parameters fname, fhandle
private all

* get the extension
bext = trim(right(fname, len(fname) - rat('.', fname)))
* and the name
bname = left(fname, at('.', fname))

* reverse the extension
revext = ''
for i = 1 to len(bext)
revext = revext + substr(bext, len(bext) + 1 - i, 1)
endfor

* If an old backup file exists, delete it
if file(bname + revext)
delete file (bname + revext)
endif

* close the handle so we won't get a 'file in use'
=fclose(fhandle)

* make the backup copy
copy file (bname + bext) to (bname + revext)

* re-open the file
fhandle = fopen(fname, 12)
return

******** END FIXDBFLT.PRG


bonma...@gmail.com

unread,
Jul 4, 2012, 2:08:37 AM7/4/12
to
Foxpro, Dbase and Foxbase are very popular database management programs, used by the individuals to store structured information. Database records are maintained by these programs in DBF files. Likewise another files, DBF files often become corrupt due to several factors like intrusion of malicious virus, crash of window server, hard disk errors and errors in portable storage media. The Kernel recovery for DBF should be used to retrieve data from the inaccessible or damaged DBF files. The utility performs deep scan of the system to find the all DBF files. To know more about utility visit: http://www.repairdbf.net/


0 new messages