The record count could be wrong or the last byte of the file at HEADER()+RECSIZE()*RECCOUNT()+1 which should be a CHR(26) ^Z may be changed or missing.
The referenced utilities had no source code and the code posted in this thread was a bit confusing because it was a sample and not a utility. I decided I've needed a DBFFIX for a long time and just for fun, I wrote it in FOX. As a FOX source, you can include DBF fixing in your runtime projects if necessary. This code was created and tested for a couple of hours today so it may not be as full featured as other DBF recovery products. Unfortunately, it is so rare that I run into a damaged DBF, my ability to test it further will be limited. Let me know if there are problems.
DO DBFFIX WITH "BAD.DBF",.t.,.t.,.t.
* DBFFIX.PRG by severach
3/23/2005
* Written & Tested under FOXPRO-DOS 2.5
*To test, find a DBF, use HIEW.EXE (Hex-Edit) and Truncate the last record.
* 1) Truncate only the ^Z
* 2) Truncate partway into a record
* 3) Truncate all but the DELE() column
* 4) Truncate a few records
* 5) Adjust RECCOUNT() down
*do dbffix1 with "a2.dbf",.t.,.f.,.t.
*This programs assumes that the header length and record length are correct.
*xin, file to fix
*xfix, true to fix, false to show results only
*xpad, true to pad last damaged record instead of truncate
*xreco, true to recover extra records found at the end
*proc dbffix1
parameter xin,xfix,xpad,xreco
clos data
clos all
set talk off
?
?iif(xfix,"Examining","Fixing")+" file "+xin
fi=fopen(xin,iif(xfix,12,10))
if fi>=0 then
hdr=fread(fi,12)
nr=asc(substr(hdr,5,1))+256*asc(substr(hdr,6,1))+65536*asc(substr(hdr,7,1))+16777216*asc(substr(hdr,8,1))
hl=asc(substr(hdr,9,1))+256*asc(substr(hdr,10,1))
rl=asc(substr(hdr,11,1))+256*asc(substr(hdr,12,1))
?"Header Information"
?" Recs ="+str(nr,10)+" records"
?" Header ="+str(hl,10)+" bytes"
?" Record ="+str(rl,10)+" bytes"
?" Calc len="+str(hl+nr*rl,10)+" bytes"
?
?"Analyzing"
needfix=.f.
high=fseek(fi,0,2)
nr2=(high-hl)/rl-nr
pos=fseek(fi,high-1)
if pos>hl+nr*rl then
?" File is too large by "+allt(str(nr2,10,2))+" records, "
if ((xpad and nr2>=0) or nr2>=1) and xreco
??"recovering"
needfix=.t.
else
??"will truncate"
high=fseek(fi,hl+nr*rl+1)
pos=fseek(fi,high-1)
needfix=.t.
endif
endif
release nr2
if pos+1 == hl+nr*rl
?" No data lost"
pos=fseek(fi,pos+1)
ctlz=chr(0)
nr2=nr
else
if pos==hl+nr*rl
?" All records present"
else
?" Record count may be adjusted"
needfix=.t.
endif
ctlz=fread(fi,1)
nr2=int((pos-hl)/rl)
endif
?" Act len ="+str(pos,10)
if ctlz==chr(26) then
?" Ctrl-Z mark found

"
else
?" Ctrl-Z mark not found ;("
needfix=.t.
endif
?
if needfix then
?"Fixing"+iif(xfix,""," (write disabled)")
if xpad then
pos=fseek(fi,high)
if pos>hl+nr2*rl+1 && if there's only a DELE(), don't save it
?" Padding last record"
nr2=nr2+1
need=hl+nr2*rl-pos
=fwrite(fi,repl(chr(0),need),need) && need to write bytes that are MEMO safe
else
if pos#hl+nr2*rl+1
?" Unable to pad"
endif
endif
endif
?" New calculated records"+str(nr2,10)
pos=fseek(fi,hl+nr2*rl)
=fwrite(fi,chr(26),1)
?" ^Z written"
=fchsize(fi,hl+nr2*rl+1)
if nr2#nr then
?iif(nr2<nr," Truncating "," Expanding ")+allt(str(abs(nr-nr2)))+" records"
nr2a=mod(nr2,256)
nr2=int(nr2/256)
nr2b=mod(nr2,256)
nr2=int(nr2/256)
nr2c=mod(nr2,256)
nr2d=int(nr2/256)
=fseek(fi,4)
=fwrite(fi,chr(nr2a)+chr(nr2b)+chr(nr2c)+chr(nr2d),4)
endif
else
?"Nothing to fix"
endif
=fclose(fi)
else
??" file not found"
endif
set talk on