Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations John Tel on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How do I repair a corrupt memo file?? 1

Status
Not open for further replies.

acorbally

Programmer
Jan 9, 2001
65
US
I am trying to figure out how to repair a corrupt memo file. I am using my developer's guide but get stuck halfway through. I really need to get this fixed. I even started documenting it when I have fixed it in the past with help with an old co-worker, but now they are gone and I can't remember it all. I only have a third of the documentation I need. HELP!!!

Thanks in advance.
 
I have tried that thread. The first link ends with object not found error and the second link on that thread works fine, but I downloaded a "fix" program and when I copied the corrupt memo file to test the program it blew every memo away. Nice fix. Anyway. I have fixed these before using UltraEdit and shifting bits in Hex, but I am having trouble finding the link between the dbf and the fpt. I know it it an address location in the dbf that points to the memo block position in the fpt but I don't remember the exact steps. Please help.
 
Sorry for any inconveniences.
I was able to fix some tables using those programs before.
I have not done what you are trying to do, but maybe this faq can help you:

How to read a DBF Header and get info about it

faq182-3161

If not, just be patient, I am sure somebody else will help you.
 
aanewlon:

Make sure you have a backup of the damaged files first!!!

Then try what I've found on Rob.


*****************************************************************************
* 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: <pinpal@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 &quot;Can't open dbf! Repair not made!&quot;
loop
else
wait window nowait &quot;Analyzing dbf . . .&quot;
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 &quot;Can't read dbf! Repair not made!&quot;
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(&quot;Just Checking . . .&quot;, ;
&quot;This may be a FoxBase+ or dBaseIII Plus dbf with memo file.&quot; ;
+ chr(13) + &quot;Fix it anyway?&quot;)
loop
endif
case xhdrtype = chr(139) && x'8B'
if !attention(&quot;Just Checking . . .&quot;, ;
&quot;This may be a dBaseIV dbf with memo file.&quot; ;
+ chr(13) + &quot;Fix it anyway?&quot;)
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(&quot;Fatal Error&quot;, ;
&quot;Invalid field record. Dbf is not repairable&quot;, .T.)
loop
endif
endif
enddo

* if little (<32 bytes) or no data, or premature eof
if feof(dbhandle)
if pof = 0
=attention(&quot;Fatal Error&quot;, ;
&quot;No header delimiter found. Dbf is not repairable&quot;, .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 &quot;Hdr/Data Length Inconsistency&quot;
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 &quot;Data Length inconsistency&quot;
endif

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

if hasmemo and !hasfpt && missing fpt file, but fix whatever else we can
=attention(&quot;For your information . . .&quot;, ;
&quot;There is no .fpt file for this dbf!&quot; + chr(13) + ;
&quot;To salvage data, make a copy without the memo fields!&quot;, .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(&quot;Please tell me . . .&quot;, &quot;This dbf has a bad header.&quot; + chr(13) + ;
&quot;Should I repair it?&quot;)
wait window nowait &quot;Repairing dbf . . .&quot;
=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 &quot;dbf Repair successful!&quot;
else
wait window timeout 3 &quot;New dbf header not written. Repair not done!&quot;

endif
endif
else

=attention(&quot;For your information . . .&quot;, &quot;This dbf is OK!&quot;, .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 &quot;Can't open fpt! Repair not made!&quot;
loop
else
wait window nowait &quot;Analyzing fpt&quot;
endif

fpthdr = fread(fpthandle, 8) && get fpt header
if ferror() # 0
wait window timeout 5 &quot;Can't read fpt! Repair not made!&quot;
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(&quot;Possible Blocksize Error&quot;, ;
+ &quot;fpt file shows a blocksize of &quot; + alltrim(str(fptblksz)) ;
+ &quot;. Default is &quot; + alltrim(str(envblksz)) + &quot;. Value to use:&quot;, ;
envblksz)

if y > 0 and y = int(y) && must be a positive integer
valok = .T.
else
if y = 0
exit
else
wait window nowait ;
&quot;Blocksize must be a positive integer!&quot;
endif
endif
enddo
if y = 0 && if no value was supplied, assume user wants to cancel
wait window timeout 3 &quot;fpt repair cancelled&quot;
loop
else && easy to fix it, now that all the work is done
wait window nowait &quot;Repairing fpt . . .&quot;
=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 &quot;fpt Repair successful!&quot;
else
wait window timeout 3 &quot;New fpt header not written. Repair not done!&quot;

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 &quot;OK&quot; 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 &quot;@*HT3 \!OK&quot; ;
SIZE 2,8,1 ;
DEFAULT 1
else
@ 6,23 GET mresponse ;
PICTURE &quot;@*HT3 \!OK;\?No&quot; ;
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 &quot;99999&quot; ;
SIZE 1,5 ;
DEFAULT val

@ 6,23 GET mresponse ;
PICTURE &quot;@*HT3 \!OK;\?No&quot; ;
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
 
What should I look for on the website you gave me?
 
I copied the prg you added in and tried to use it. I got a message &quot;fpt is ok&quot;. It did not fix my corrupt memo file either.
 
Then what leads you to the conclusion the memo file is corrupted?
Please be specific.

Rob.
 
I am seeing many carriage return or pipe looking symbols. The memo has other recipients information in the memo. I have seen this before. I know it is corrupt. I usually have to shift bits, but I can't figure out how to get to that 10 bit pointer that shows where the block is in the fpt file.

 
The pointer to the block in the memo field is in the DBF file and it is 4 bytes (32 bits) long.

If you had VFP 6 or higher I would have a utility that perhaps could fix your FPT file.

Rob.
 
Do you have detailed instructions on how to step through starting with the dbf then via the pointer into the fpt? I am completely lost.
 
I'm working on a program to restore data from damaged dbf's and ftp's and I'm analysing the ftp files now.
I haven't figured it out yet.

Rob.
 
Please let me know when you do. I would ever so greatly appreciate it.

Thanks again.
 
I did and I get an error that it is a demo version and only able to read *.dbf files with the same file size as the demo dbf's. My dbf is not the same size. It did not fix.
 
I'll fix it tomorrow, for now I'm going to get some sleep.

Rob.
 
The redownload worked. I think. It completely deleted the comments from the corrupt case, but in the recovrep.txt, it showed the exact record number I was having trouble with. Thank You Thank You Thank You Thank You Thank You
You are a saint.

Andrea
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top