home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 September
/
Simtel20_Sept92.cdr
/
msdos
/
arc_lbr
/
mdcd10.arc
/
MDCD.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1988-10-26
|
65KB
|
1,263 lines
{---- 10/26/1988 00:26:31 ----}
{$A-,R-,B-,S-,I-,F-,O-,V-,N-,E-,D+,L+}
{$M 3072,0,45000} { stack, min heap, max heap }
{----------------------------------------------------------------------------}
{ }
{ 'MDCD' }
{ }
{ File compress and decompress utility. }
{ }
{ Written By: Mike Davenport }
{ Mike Davenport & Associates }
{ 6751 N. Blackstone Ave. Suite 252 }
{ Fresno CA 93710 }
{ Voice: (209) 298-8846 }
{ CIS: 76676,1362 }
{ PLINK: MIKE D }
{ GENIE: MDAVENPORT }
{ Amiga Techniques + PC Tech BBS - (GT POWER) }
{ (209) 298-8453 - 1200-9600 HST (24 hours) }
{ }
{----------------------------------------------------------------------------}
{ }
{ ---------------------- }
{ PROGRAM CHANGE HISTORY }
{ ---------------------- }
{ }
{ change# ..date.. by .................. change ........................ }
{ }
{ 000 10-14-88 md Original module creation - version .9 }
{ 001 10-19-88 md Original module finished - version .9 (beta) }
{ 002 10-22-88 md Added 13 bit compression interface }
{ 003 10-26-88 md Finished 1.0 release }
{ }
{----------------------------------------------------------------------------}
{ }
{ }
{ INTERNAL Modules }
{ -------- }
{ TYPE ...... NAME ........... ............ DESCRIPTION ................. }
{ }
{ Func CompressFile LZW file compress from mdcd1213.obj }
{ Func DeCompressFile LZW file decompress from mdcd1213.obj }
{ Func TimeStamp Get time in milli-seconds since midnite }
{ Proc GetKey Inline get key routine via int 16h }
{ Proc CheckIO Check IOResult for file and error/halt }
{ Func CompressOneFile Setup for compressing one file }
{ Func ProcessCompress Processes command line C compress option }
{ Func ProcessDeCompress Processes command line D/R decompress optn }
{ Func ProcessList Processes command line F/L list option }
{ Func CVS Local to ProcessList - convert word to str }
{ Proc DisplayHelp Display program LOGO & help screen }
{ }
{----------------------------------------------------------------------------}
Program MDCD;
Uses Dos;
{$L MDCD1213.OBJ} { Assembler module for LZW compress/decompress }
{$F+}
Function CompressFile(InFile : Word; {handle of input file }
OutFile : Word; {handle of output file }
AbsOfst : LongInt; {absolute offset to start write at }
RP : Pointer; {pointer to return area }
HashSg : Word; {segment:0 of allocated hash table }
LZWtype : Word {12 = 12 bit, 13 = 13 bit lzw }
) : Word; {-1 = good return }
external {MDCD1213} ;
{$F-}
{$F+}
Function DeCompressFile(InFile : Word; {handle of input file }
OutFile : Word; {handle of output file }
AbsOfst : LongInt; {absolute offset to start write at}
RP : Pointer; {pointer to return area }
HashSg : Word; {segment:0 of allocated hash table}
LZWtype : Word {12 = 12 bit, 13 = 13 bit lzw }
) : Word; {-1 = good return }
external {MDCD1213} ;
{$F-}
Type
Array4 = Array[1..4] of Char;
String12 = String[12];
String2 = String[2];
DirPtr = ^DirStr; {to allocate Dir on heap }
OutFilePtr = ^PathStr; {to allocate file full path on heap}
InFilePtr = ^PathStr; {to allocate file full path on heap}
SRecPtr = ^SearchRec; {to allocate findfirst/next on heap}
FileHeader = Record {header for each compressed file }
Signature : Array4; {file/header signature (MDmd) }
ReleaseLevel : Byte; {compress version }
HeaderType : Byte; {header type. only type 1 for now }
HeaderSize : Word; {size of this header in bytes }
UserInfo : Word; {any user info desired }
Reserved1 : Word; {future use and upward compatablty }
Reserved2 : LongInt; {future use and upward compatablty }
Reserved3 : Array[1..8] of byte; {future use and upward compatablty }
CompressType : Byte; {type of compression }
OrigFileSize : LongInt; {original file size in bytes }
CompFileSize : LongInt; {compressed file size in bytes }
FileAttr : Word; {original file attribute }
FileDate : LongInt; {original file date/time }
FileCRC : Word; {file crc }
FileName : String12; {file name }
PathName : DirStr; {original drive\path }
end;
FileHeaderPtr = ^FileHeader; {pointer to allocate my header/heap}
{ return code from mdcd1213.obj module }
ReturnRec = Record {return info from mdcd1213.obj }
FileCrc : Word; { calculated file crc decompressed}
FileSize : LongInt; { compressed/decompressed filesize}
end; {.. }
Const
PgmRelLvl = 10; {mdcd program release level }
Compressed = 1; {indicates LZW 13 bit compression }
UnCompressed = 0; {indicates NO compression }
LZWH1 = 20480*2; {size of LZW hash compress 13 bit }
LZWH2 = 12288*2; {size of LZW hash decompress 13 bit}
LZWBits = 13; {number of LZW bits for compression}
ValidSig : Array4 = 'MDmd'; {signature to verify mdcd file }
HexXlate : Array[0..$F] of Char = {table to translate word to hex }
'0123456789ABCDEF';
Dashes =
'-------------------------------------------------------------------------';
Hdr1 = 'MDCD File Compress/DeCompress Utility Version 1.0 10-23-88';
Hdr2 = 'Mike Davenport CIS: 76676,1362 BBS: (209) 298-8453 1200-9600 HST';
Var
MRC : Word; {storage for mainline return code }
InKey : Word; {input from int 16 keyboard }
WorkStr : String12; {work string }
Option : Char; {command line option requested }
ReturnR : ReturnRec; {storage for return info from mdcd }
InF : File; {input file }
OutF : File; {output file }
StartTime: LongInt; {start time from midnite in ms }
BeginTime: LongInt; {start time from midnite in ms }
MDCheck : Array4; {check for valid mdcd file }
FileCount: Word; {number of files processed }
ForceCopy: Boolean; {force file copy vs. compression }
{----------------------------------------------------------------------------}
{ }
{ function 'TimeStamp' }
{ }
{ This function returns the number of milliseconds since midnite }
{ }
{----------------------------------------------------------------------------}
Function TimeStamp : LongInt;
Var
Hour : Word;
Minute : Word;
Second : Word;
Sec100 : Word;
begin {TimeStamp}
GetTime(Hour, Minute, Second, Sec100); {Borlands int 21h 2ch }
TimeStamp := 1000*((LongInt(Hour)*3600) + {1000 times seconds in hours + }
(LongInt(Minute)*60) + {seconds in minutes + }
(LongInt(Second)) ) + {seconds ) }
Sec100; {+ hundreths of seconds }
end; {TimeStamp}
{----------------------------------------------------------------------------}
{ }
{ Procedure 'GetKey' }
{ }
{ This procedure calls ROM-BIOS interrupt 16H to check for the keyboard }
{ status. If no key is ready, then it returns 0 for both the keyboard scan }
{ code and character. If a key is ready, then it returns both the keyboard }
{ scan code and the character. If one of the extended or function keys is }
{ pressed, the character returned will be an ASCII zero. The scan code is }
{ then used to determine the exact identity of the key stroke. This rou- }
{ tine sets the global variable "inkey" to the last key stroke pressed. }
{ }
{----------------------------------------------------------------------------}
Procedure GetKey;
begin { GetKey }
inline($C7/$06/inkey/$00/$00/ { mov word ptr ds:[inkey],0h ;init. }
$B4/$01/ { mov ah,01h ;key ready? }
$CD/$16/ { int 16h ;kbd serv. }
$74/$07/ { jz ex ;no key }
$B4/$00/ { mov ah,00h ;get key }
$CD/$16/ { int 16h ;kbd serv. }
$A3/inkey); { mov word ptr ds:[inkey],ax ;result }
{ex: ;exit label }
end; { GetKey }
{----------------------------------------------------------------------------}
{ }
{ procedure 'CheckIO' }
{ }
{ This procedure checks the IOResult code for a file and displays an error }
{ and halts if the error is non-zero. }
{ }
{----------------------------------------------------------------------------}
Procedure CheckIO(var F : File);
Var
r : Word;
d : Word;
begin {CheckIO}
r := IoResult;
d := DosError;
if ((r+d) <> 0) then begin
WriteLn;
Write('IOResult: ', r:3, ' DOS Error: ', d:3, ' while reading/writing File: ');
r := 0;
While (FileRec(f).Name[r] <> #0) do begin
Write(FileRec(F).Name[r]);
Inc(r);
end;
WriteLn;
Repeat GetKey; Until (InKey = 0); {flush keyboard buffer}
WriteLn('Press any key to continue....');
Repeat GetKey; Until (InKey <> 0); {until keypressed}
WriteLn;
Halt(1);
end;
end; {CheckIO}
{----------------------------------------------------------------------------}
{ }
{ function 'CompressOneFile' }
{ }
{ This procedure coordinates the compression of a single file }
{ }
{----------------------------------------------------------------------------}
Function CompressOneFile(CInputFile : String12; {file to compress }
COutputFile : PathStr; {compress output file }
CDir : DirStr; {input path }
CUserInfo : Word) {any user info }
: Word; {function returns a word }
Var
i : Word; {loop control/work variable }
r : Word; {return code }
ReSeek : LongInt; {file byte to seek to for compress data}
HdrSeek : LongInt; {file byte to seek to for header data }
FileHdr : FileHeaderPtr; {compress file header record pointer }
IHandle : Word; {handle of input file for mdcd1213.obj }
OHandle : Word; {handle of output file for mdcd1213.obj}
HashPtr : Pointer; {pointer to heap allocated hash table }
HashSeg : Word; {segment of allocated hash table }
ActualR : Word; {bytes actually read w/blockread }
ActualW : Word; {bytes actually written w/blockwrite }
CmpType : Word; {type of file compression used }
CopyPtr : Pointer; {pointer to heap buffer for block(r/w) }
OtherChk : Byte; {check .ARC ^Z or .ZOO 'Z' as first chr}
begin {CompressOneFile}
StartTime := TimeStamp; {get time in ms since midnite }
{ create or open the output file & make sure its a valid compress file }
Assign(OutF, COutputFile); {setup output file variable }
Reset(OutF,1); {attempt to open output file }
If (IOResult <> 0) then begin {if file was not opened.. }
ReWrite(OutF,1); { create output file }
CheckIO(OutF);
end {.. }
else begin {else }
BlockRead(OutF, MDCheck, 4); { read first 4 bytes for signature }
CheckIO(OutF);
if (MDCheck <> ValidSig) then begin { if not a valid signature }
CompressOneFile := 999; { set return code }
Exit; { get out }
end; { .. }
end; {.. }
{ open input file }
Assign(InF, CDir+CInputFile); {setup input file variable }
System.FileMode := 0; {read only to get hidden/sys files }
Reset(InF,1); {open input file to assign handle }
System.FileMode := 2; {read write }
r := IOResult; {get io return code }
If (r <> 0) then begin {if return code is bad.. }
CompressOneFile := r; { set return code }
Exit; { get out }
end; {.. }
{ seek to end of output file and write a dummy header to reserve space }
HdrSeek := FileSize(OutF); {get the current end of file }
Seek(OutF, HdrSeek); {seek to the end of the file }
New(FileHdr); {allocate header record on heap }
BlockWrite(OutF, FileHdr^, {write dummy header to make space }
SizeOf(FileHdr^)); { }
CheckIO(OutF);
ReSeek := HdrSeek + SizeOf(FileHdr^); {seek past header to end of file }
{ get everything set up and go and compress the file }
IHandle := FileRec(InF).Handle; {extract input file handle }
OHandle := FileRec(OutF).Handle; {extract output file handle }
Write(CInputFile:12, ',', {write compress info to screen }
FileSize(InF):7,' --> ', { }
COutputFile, ','); { }
{ if .ZOO or .ARC file check for 'Z' or ^Z to double check }
If (ForceCopy) then begin {if .ZOO or .ARC file extension }
BlockRead(InF, OtherChk, 1); { read first byte of file }
CheckIO(InF); { check io error }
Seek(InF, 0); { seek to the beginning of the file }
CheckIO(InF); { check io error }
If ( (OtherChk <> $1A) and { if first byte not ^Z and }
(OtherChk <> $5A) ) then begin { first byte not Z then }
ForceCopy := False { turn off forced copy & compress }
end; { .. }
end; {.. }
if (not ForceCopy) then begin
GetMem(HashPtr, LZWH1+15); {get memory for hash table + 15 bytes}
if Ofs(HashPtr^) = 0 then {if offset -0- then seg is okay }
HashSeg := Seg(HashPtr^) { store segment }
else {else }
HashSeg := 1+Seg(HashPtr^); { add 1 paragraph (16 bytes) to seg }
r := CompressFile( {compress the file }
Ihandle, {input file handle }
Ohandle, {output file handle }
ReSeek, {starting point in output file }
@ReturnR, {where to send return info back to }
HashSeg, {segment of heap allocated hash table}
LZWBits); {number of LZW bits }
FreeMem(HashPtr, LZWH1+15); {get rid of heap memory for hash table }
{ display error and halt if error return code }
If (r <> $ffff) then begin
WriteLn;
WriteLn('Error: ', r, ' returned from MDCD1213.OBJ - Program Terminated');
WriteLn;
Halt(1);
end;
{ close and reopen so we know what mdcd1213.obj did }
Close(InF); {close input file }
CheckIO(InF);
Close(OutF); {close output file }
CheckIO(OutF);
System.FileMode := 0; {read only to get hidden/sys }
Reset(InF,1); {open input file to assign handle }
CheckIO(InF);
System.FileMode := 2; {read write }
Reset(OutF,1); {reopen output file to process }
CheckIO(OutF);
end
else begin
ReturnR.FileSize:=FileSize(InF)+1; {force file copy }
end;
{ if compressed file is larger then input, just copy input file as is }
CmpType := Compressed; {assume file is compressed}
if ReturnR.Filesize > Filesize(InF) then begin {if compressed > actual ! }
CheckIO(InF);
Seek(InF, 0); { seek to input begin }
CheckIO(InF);
Seek(OutF, ReSeek); { seek to before file }
CheckIO(OutF);
Truncate(OutF); { chop it off }
CheckIO(OutF);
GetMem(CopyPtr, LZWH1); { get heap for buffer }
While (not EOF(InF)) do begin { while not end of file }
BlockRead(InF, CopyPtr^, LZWH1, ActualR); { read original }
CheckIO(InF);
BlockWrite(OutF, CopyPtr^, ActualR, ActualW);{ write as is to output}
CheckIO(OutF);
if ActualW <> ActualR then begin { if read error }
WriteLn; { disk probaly full }
WriteLn('DISK FULL???'); { disk probaly full }
WriteLn('DISK FULL???'); { }
WriteLn; { disk probaly full }
Halt(99); { halt the sucker }
end; { .. }
end; { .. }
FreeMem(CopyPtr, LZWH1); { release heap buffer }
ReturnR.FileSize:=FileSize(InF); { set new file size }
CheckIO(InF);
CmpType := UnCompressed; { file is not compressed }
end; {.. }
{ build compressed file header record and write it to the file }
With FileHdr^ do begin {Use FileHdr record }
Signature := ValidSig; { set compress file id }
ReleaseLevel := PgmRelLvl; { set mdcd program id }
HeaderType := 1; { only type 1 for now }
HeaderSize := sizeof(FileHdr^); { set header record size }
UserInfo := CUserInfo; { set user info }
Reserved1 := 0; { reserved for future use }
Reserved2 := 0; { reserved for future use }
FillChar(Reserved3, SizeOf(Reserved3), 0); { reserved for future use }
CompressType := CmpType; { set type of file compress }
FillChar(FileName, SizeOf(Filename), ' '); { clear file name field }
FillChar(PathName, SizeOf(Pathname), ' '); { clear path name field }
FileName := CInputFile; { set file name }
PathName := CDir; { set original path name }
OrigFileSize := FileSize(InF); { set original file size }
CheckIO(InF);
CompFileSize := ReturnR.FileSize; { set compressed file size }
FileCRC := ReturnR.FileCrc; { set file CRC }
GetFTime(InF, FileDate); { set orig'l file data/time }
CheckIO(InF);
Close(InF); { close the input file }
CheckIO(InF);
GetFAttr(InF, FileAttr); { set input file attrubutes }
CheckIO(InF);
end; {.. }
Seek(OutF, HdrSeek); {seek back to header loc'n }
CheckIO(OutF);
BlockWrite(OutF, FileHdr^, SizeOf(FileHdr^)); {write the file header }
CheckIO(OutF);
Close(OutF); {close output file }
CheckIO(OutF);
{ display file info on screen }
Write(FileHdr^.CompFileSize:7);
If (FileHdr^.OrigFileSize = 0) then
Write(' ( 0%)')
else
Write(' (', 100-((FileHdr^.CompFileSize * 100) / FileHdr^.OrigFileSize):2:0, '%)');
Write( ' ', ((TimeStamp-StartTime)/1000)+1:4:0, ' seconds');
Write(' CRC: ');
Write(HexXlate[Hi(returnr.filecrc) shr 4]);
Write(HexXlate[Hi(returnr.filecrc) and $F]);
Write(HexXlate[Lo(returnr.filecrc) shr 4]);
Write(HexXlate[Lo(returnr.filecrc) and $F]);
WriteLn;
dispose(FileHdr); {free allocated heap space }
CompressOneFile := 0; {set good return code }
end; {CompressOneFile}
{----------------------------------------------------------------------------}
{ }
{ function 'ProcessCompress' }
{ }
{ This procedure controls the requested (C)ompress option }
{ }
{----------------------------------------------------------------------------}
Function ProcessCompress : Word;
Var
Srec : SRecPtr; {findfirst/next search record }
RC : Word; {return code }
i : Word; {loop control variable }
Done : Boolean; {all files processed flag }
Name : NameStr; {file name }
TName : NameStr; {file name }
Ext : ExtStr; {file extension }
TExt : ExtStr; {file extension }
Ignore : String[12]; {name to keep from compressing output file}
OutFile : OutFilePtr; {compressed output file name on heap }
InFile : InFilePtr; {input file name on heap }
Dir : DirPtr; {directory path name on heap }
TDir : DirPtr; {work dir for fsplit }
begin {ProcessCompress}
{ allocate variables from the heap and initialize any required variables }
New(Srec); {allocate search record on heap }
New(Dir); {allocate directory path on heap }
New(TDir); {allocate directory path on heap }
New(OutFile); {allocate output file name on heap }
New(InFile); {allocate input file name on heap }
Done := False; {reset done processing flag }
FileCount := 0; {reset processed file count }
BeginTime := TimeStamp; {get starting time }
{ split output file name apart, make sure its a valid compress type of }
{ file, add an extension of .MD if not entered, and save output file name }
{ in a form that will compare equal if a FindNext file retrieved for }
{ compression has the same name (don't compress the output file itself!) }
OutFile^ := FExpand(ParamStr(3)); {expand command line output file name}
FSplit(OutFile^, Dir^, Name, Ext); {split it into components }
if (Length(Ext)=0) then Ext:='.MD'; {if no extension, assume .md }
OutFile^ := Dir^ + Name + Ext; {rebuild output file name }
Ignore := Name + Ext; {prevent compressing output file }
{ split input file mask apart so the original path can be saved. If no path }
{ entered, get the path of the current directory to include in the file. }
InFile^ := FExpand(ParamStr(2)); {expand input file mask }
FSplit(InFile^, Dir^, Name, Ext); {split it into components }
InFile^ := Dir^ + Name + Ext; {rebuild input file mask }
{ get the first file to compress }
{NOTE: the word "Archive" in the line below has no relationship to SEA's }
{ pending trademark on the word ARC. It references a constant defined }
{ in Borland's Turbo Pascal 5.0 DOS unit, and refers to a file that }
{ has the archive bit set. This is an MSDOS term. }
FindFirst(InFile^, ReadOnly+Hidden+SysFile+Archive, SRec^);
if (DosError<>0) then Done := True;
{ compress files until there are no more }
While (not Done) do begin {while more files }
if (DosError=0) then begin { if findnext ok }
if (Ignore<>SRec^.Name) then begin { if not output file }
FSplit(SRec^.Name, TDir^, TName, TExt); { get file extension }
If ( (TExt = '.ARC') or { if .ARC file or }
(TExt = '.ZOO') ) then { if .ZOO file }
ForceCopy := True { cheat and copy }
else { else }
ForceCopy := False; { try compression }
RC := CompressOneFile(SRec^.Name, { compress this file }
OutFile^, Dir^, 0); { }
If RC = 999 then begin; { if not compress file }
WriteLn; { tell the user }
WriteLn('Output file: ', Outfile^, { " }
' is not a valid compress file'); { " }
WriteLn; { " }
Halt(1); { end program }
end; { .. }
If RC <> 0 then begin { if bad return code }
WriteLn; { tell the user }
WriteLn(' Return Code error: ', RC, { " }
' compressing ', SRec^.Name); { " }
WriteLn; { " }
Halt(1); { end program }
end; { .. }
Inc(FileCount); { bump file count }
end; { .. }
end { .. }
else begin { else }
Done:=True; { flag we are done }
end; { .. }
FindNext(SRec^); { get next file to compress }
end; {while not done} {.. }
{ display files compressed count and total time }
If FileCount = 0 then begin
WriteLn('No files found to Compress');
end
else begin
WriteLn;
Write(FileCount, ' File(s) added to: ', OutFile^);
WriteLn( ' in ', ((TimeStamp-BeginTime)/1000)+1:4:0, ' seconds');
WriteLn;
end;
{ release heap memory used }
Dispose(InFile);
Dispose(OutFile);
Dispose(TDir);
Dispose(Dir);
Dispose(Srec);
end; {ProcessCompress}
{----------------------------------------------------------------------------}
{ }
{ function 'ProcessDeCompress' }
{ }
{ This procedure controls the requested (D)ecompress option }
{ }
{----------------------------------------------------------------------------}
Function ProcessDeCompress(Option : Char) : Word;
Var
FileHdr : FileHeaderPtr; {my compress file header from heap }
ActualR : Word; {actual blockread bytes read }
ActualW : Word; {actual blockwrite bytes written }
r : Word; {return code }
Done : Boolean; {processing done flag }
Doit : Boolean; {decompress flag (to control overwrite)}
SkipFile : Boolean; {skip current file }
CurLoc : LongInt; {current file location in bytes }
ToRead : LongInt; {file bytes to read (copy vs lzw) }
LeftToReaD : LongInt; {file bytes left to read }
Dir : DirPtr; {dir path from heap }
HoldDir : DirPtr; {dir path from heap to hold current dir}
Name : NameStr; {file name }
Ext : ExtStr; {file extension }
OutFile : OutFilePtr; {output file name from heap }
InFile : InFilePtr; {input file name from heap }
CopyPtr : Pointer; {pointer to heap buffer for block(r/w) }
IHandle : Word; {handle of input file for mdcd1213.obj }
OHandle : Word; {handle of output file for mdcd1213.obj}
HashPtr : Pointer; {pointer to heap allocated hash table }
HashSeg : Word; {segment of allocated hash table }
begin {ProcessDeCompress}
{ allocate variables from the heap and initialize any required variables }
New(Dir); {allocate dir from heap }
New(OutFile); {allocate output file fm heap }
New(InFile); {allocate input file fm heap }
BeginTime := TimeStamp; {get beginning time }
FileCount := 0; {reset processed file count }
{ split input compressed file name apart, and add an extension of .MD if }
{ no file extension was entered. }
InFile^ := FExpand(ParamStr(2)); { }
FSplit(InFile^, Dir^, Name, Ext); { }
If (Length(Ext)=0) then Ext:='.MD'; { }
InFile^ := Dir^ + Name + Ext; { }
{ get the current directory, save it, fixup the output path, and attempt to }
{ do a chdir to it to verify that it is correct. }
New(HoldDir); {allocate dir on heap }
GetDir(0, HoldDir^); {get current directory }
OutFile^ := ParamStr(3); {get outdir from command line }
ChDir(OutFile^); {attempt to chdir to out dir }
if ((Length(OutFile^) > 0) and {if any outdir entered and }
(OutFile^[Length(OutFile^)] <> ':') and { last char not ':' and }
(OutFile^[Length(OutFile^)] <> '\')) then { last char not '\' then }
OutFile^ := OutFile^ + '\'; { slap a '\' on end }
If (IOResult <> 0) then begin {if chdir didnt work }
ChDir(HoldDir^); { back to original dir }
WriteLn; { inform user }
WriteLn(' Parameter 3 (Output Directory) must be blank or be a valid Path');
WriteLn; { }
ProcessDeCompress := 1; { set function return }
Dispose(HoldDir); { deallocate heap }
Dispose(InFile); { deallocate heap }
Dispose(OutFile); { deallocate heap }
Dispose(Dir); { deallocate heap }
Exit; { exit }
end; {.. }
ChDir(HoldDir^); {change back to original dir }
{ attempt to open input compressed file and make sure its a valid file }
Assign(InF, InFile^);
Reset(InF, 1);
If (IOResult <> 0) then begin
WriteLn;
WriteLn(' Requested file: ', InFile^, ' not found');
WriteLn;
ProcessDeCompress := 1;
Dispose(InFile);
Dispose(OutFile);
Dispose(Dir);
Exit;
end
else begin
BlockRead(InF, MDCheck, 4);
CheckIO(InF);
if (MDCheck <> ValidSig) then begin
WriteLn;
WriteLn('File: ', InFile^, ' is not a valid compress file');
WriteLn;
ProcessDeCompress := 1;
Dispose(InFile);
Dispose(OutFile);
Dispose(Dir);
Exit;
end;
end;
{ initialize stuff and prepare to begin decompressing }
New(FileHdr); {allocate on heap }
CurLoc := 0; {input file position to read }
Seek(InF, CurLoc); {seek to current location }
CheckIO(InF);
WriteLn;
Write('DeCompressing: ', InFile^);
If (Option = 'R') then
Write(' Duplicate Output files will be overwritten');
WriteLn;
WriteLn;
{ go through the entire input compressed file and decompress it }
Done := False; {reset done flag }
While (Done = False) do begin {while more to do }
BlockRead(InF, FileHdr^, { read compress header }
SizeOf(FileHdr^), ActualR); { }
CheckIO(InF);
CurLoc := CurLoc + SizeOf(FileHdr^); { point to compress data }
If (ActualR = SizeOf(FileHdr^)) then begin { if we read data ok.. }
With FileHdr^ do begin { begin processing }
SkipFile := False; { assume file is ok }
If (Signature <> ValidSig) then begin { if not valid signature }
WriteLn; { tell user }
WriteLn('Compress file is corrupted. Invalid signature found');
WriteLn; { }
Halt(1); { end program }
end; { .. }
{ i only recognize header type 1 with this version }
If (HeaderType <> 1) then begin { if invalid header type.}
WriteLn; { tell user }
WriteLn('Unidentified Header Type. File was compressed with a ',
' newer version. Skipping');
SkipFile := True; { skip this file }
WriteLn; { }
end; { .. }
{ if this file compressed with a newer release, ask user what to do }
If ( (not SkipFile) and { if file still ok... & }
(ReleaseLevel>PgmRelLvl) )then begin{ newer release level }
Repeat { flush keyboard buffer}
GetKey; { }
Until (InKey = 0); { }
Write('File: ', FileName, { ok to decompress? }
' Compressed with version: ', { }
ReleaseLevel, { }
'. Decompress it? '); { }
Repeat { wait for keypress }
GetKey; { }
Until (InKey <> 0); { }
If (InKey = $2E03) then halt(0); { if ^C then end }
If ((InKey shr 8)<>$15) then begin { if not y/Y }
Write('Ignored '); { ignore message }
SkipFile := True; { dont decompress it }
end; { .. }
WriteLn; { }
end; { .. }
{ check type of compression used. if unrecognized, skip file }
If ( (not SkipFile) and { if file still ok... & }
(CompressType <> 0) and { not type 0 and }
(CompressType <> 1) ) then begin { not type 1 }
Write('File: ', FileName, { ok to decompress? }
' Compressed with Type: ', { }
CompressType, { }
'. Unrecognized. Skipping '); { }
SkipFile := True; { dont decompress it }
WriteLn; { }
end; { .. }
DoIt := True; { assume decompression }
{ check if output file exists and if so, check with user }
{ NOTE: if Append, or some other such TSR is loaded and the file to be }
{ decompressed is somewhere in the TSR's search path then you will }
{ get the following message that says the file exists, even if it }
{ doesn't. Answering 'Y'es to the overwrite prompts will decompress }
{ the file correctly to the desired sub-directory. }
If (SkipFile) then begin {if file is to be skipped }
DoIt := False; { make it known to program }
end {.. }
else begin {else }
Assign(OutF, OutFile^+FileName); { set up compress output file}
Reset(OutF, 1); { try and open output file }
If (IOResult = 0) then begin { if file already exists }
Close(OutF); { close the file }
CheckIO(OutF);
If (Option <> 'R') then begin { if replace not selectd }
Repeat { flush keyboard buffer }
GetKey; { }
Until (InKey = 0); { }
Write('Output file: ', { ask if overwrite ok }
OutFile^+FileName, { }
' Exists. Overwrite? '); { }
Repeat { wait for keypress }
GetKey; { }
Until (InKey <> 0); { }
If (InKey = $2E03) then halt(0); { if ^C then end program }
If ((InKey shr 8)<>$15) { if not y/Y }
then begin { }
Write('Bypassed'); { write bypassed msg }
DoIt := False; { dont decompress it }
end; { .. }
WriteLn; { }
end { .. }
else begin { else }
Write('OverWriting & '); { say we're overwriting }
end; { .. }
end; {if ioresult = 0} { .. }
end; {if skipfile} {.. }
{ everything is cool - decompress the file }
If (DoIt) then begin { if ok to decompress }
ReWrite(OutF, 1); { open empty output file }
CheckIO(OutF);
IHandle := FileRec(InF).Handle; { get input DOS handle }
OHandle := FileRec(OutF).Handle; { get output DOS handle }
StartTime := TimeStamp; { get start time }
Case CompressType of { }
Compressed : begin { if LZW compressed file }
Write('UnLZW13ing: ', { tell user what we doing}
FileName:12, ' --> ', { }
OutFile^, ' '); { }
GetMem(HashPtr, LZWH2+15); { get heap for hash decmp}
if Ofs(HashPtr^) = 0 then { align on segment bndry }
HashSeg := Seg(HashPtr^) { }
else { }
HashSeg := 1+Seg(HashPtr^); { }
r := DeCompressFile(Ihandle, { input file handle }
Ohandle, { output file handle }
CurLoc, { byte where file starts }
@ReturnR, { address of return code }
HashSeg, { segment of hash table }
LZWBits); { number of LZW bits }
FreeMem(HashPtr, LZWH2+15); { release heap hash table}
{ display error and halt if error return code }
If (r <> $ffff) then begin
WriteLn;
WriteLn('Error: ', r, ' returned from MDCD1213.OBJ - Program Terminated');
WriteLn;
Halt(1);
end;
If (ReturnR.FileCrc <> FileCrc) { if decompress crc error}
then begin { tell user }
WriteLn('CRC ERROR - File left in place but is corrupted');
FileDate := 0; { file date/time = zero}
end; { .. }
SetFTime(OutF, FileDate); { set file date }
CheckIO(OutF);
Close(OutF); { close output file }
CheckIO(OutF);
SetFAttr(OutF, FileAttr); { set original file attr }
CheckIO(OutF);
Inc(FileCount); { bump file count }
end; {case compressed} { .. }
{ }
UnCompressed : begin { If file not compressed.. }
Write('UnStoring : ',FileName:12,{ tell user what we doing}
' --> ', OutFile^, ' '); { }
Seek(InF, CurLoc); { position to file begin }
CheckIO(OutF);
GetMem(CopyPtr, LZWH1); { get copy buffer }
LeftToRead := OrigFileSize; { bytes left = original }
While (LeftToRead > 0) do begin { while anything left }
If LeftToRead >= LZWH1 then { if more than buffer }
ToRead := LZWH1 { read whole buffer }
else { else }
ToRead := LeftToRead; { read remainder }
LeftToRead:=LeftToRead-ToRead; { adjust remaining }
BlockRead(InF, CopyPtr^, { read input }
ToRead, ActualR); { }
CheckIO(OutF);
BlockWrite(OutF, CopyPtr^, { write output }
ActualR, ActualW); { }
CheckIO(OutF);
if ActualW<>ActualR then begin { if write <> read }
WriteLn; { disk probaly full }
WriteLn('DISK FULL???'); { disk probaly full }
WriteLn('DISK FULL???'); { }
WriteLn; { disk probaly full }
Halt(99); { end program }
end; { .. }
end; { .. }
FreeMem(CopyPtr, LZWH1); { release buffer }
SetFTime(OutF, FileDate); { set file date/time }
CheckIO(OutF);
Close(OutF); { close output file }
CheckIO(OutF);
SetFAttr(OutF, FileAttr); { set original attr }
CheckIO(OutF);
Inc(FileCount); { bump file count }
end; {case uncompressed} { .. }
{ }
end; {case}
Write( ' ', ((TimeStamp-StartTime)/1000)+1:4:0, ' seconds');
WriteLn;
end; {if DoIt} { .. }
CurLoc:=CurLoc + CompFileSize; { point to next file }
Seek(InF, CurLoc); { seek to next header }
CheckIO(InF);
end; {with FileHdr^} {.. }
end {if ActualR = sizeof(filehdr^}
else begin
Done := True;
end;
end; {while done = false }
Close(InF); {close input file }
CheckIO(OutF);
{ display number of files decompressed and time to decompress }
If FileCount = 0 then begin
WriteLn('No files were DeCompressed');
end
else begin
WriteLn;
Write(FileCount, ' File(s) DeCompressed from: ', InFile^);
WriteLn( ' in ', ((TimeStamp-BeginTime)/1000)+1:4:0, ' seconds');
WriteLn;
end;
{ release all allocated heap space }
Dispose(HoldDir);
Dispose(FileHdr);
Dispose(InFile);
Dispose(OutFile);
Dispose(Dir);
end; {ProcessDeCompress}
{----------------------------------------------------------------------------}
{ }
{ function 'ProcessList' }
{ }
{ This procedure (L)ists all the files in the compressed file }
{ }
{----------------------------------------------------------------------------}
Function ProcessList(Option : Char) : Word;
Type
DirPtr = ^DirStr; {to allcocate dir path on heap }
OutFilePtr = ^PathStr; {to allocate output file on heap }
Const
OrigTotal : LongInt = 0; {total size of files orginally }
CompTotal : LongInt = 0; {total size of files compressed }
OvhdTotal : LongInt = 0; {total size of file overhead (hdrs)}
PctTotal : LongInt = 0; {total file compression percentage }
Spaces : String[6] = ''; {to print variable spaces }
Var
FileHdr : FileHeaderPtr; {compress file header on heap }
ActualR : Word; {actual bytes read }
Lines : Word; {screen display line count for paws}
i : Word; {loop variable }
Done : Boolean; {done processing flag }
CurLoc : LongInt; {current location in file }
Dir : DirPtr; {heap space for dir path }
Name : NameStr; {file name }
Ext : ExtStr; {file extension }
OutFile : OutFilePtr; {heap space for output file name }
DT : DateTime; {unpack space for file date/time }
{ local function to convert word to 2 byte string and pad with zero }
Function CVS(W : Word) : String2;
Var S : String[2];
begin
Str(W:2, S); {convert word to string }
If S[1]=' ' then S[1]:='0'; {if 1st position blank, make '0' }
CVS:=S; {return string to caller }
end;
begin {ProcessList}
{ allocate heap variables }
New(Dir);
New(OutFile);
{ split input compress file on command line into components, append a file }
{ extension of .MD if not specified, rebuild file name and make upper case }
FSplit(ParamStr(2), Dir^, Name, Ext);
if (Length(Ext)=0) then Ext:='.MD';
OutFile^ := Dir^ + Name + Ext;
For i:=1 to Length(OutFile^) do
OutFile^[i] := UpCase(OutFile^[i]);
{ attempt to open compress file, and make sure it has a valid signature }
Assign(InF, OutFile^);
Reset(InF, 1);
If (IOResult <> 0) then begin
WriteLn;
WriteLn(' Requested file: ', OutFile^, ' not found');
WriteLn;
ProcessList := 1;
Dispose(OutFile);
Dispose(Dir);
Exit;
end
else begin
BlockRead(InF, MDCheck, 4);
if (MDCheck <> ValidSig) then begin
WriteLn;
WriteLn('File: ', OutFile^, ' is not a valid compress file');
WriteLn;
ProcessList := 1;
Dispose(OutFile);
Dispose(Dir);
Exit;
end;
end;
{ initialize variables, allocate needed heap space, and display heading }
Done := False;
New(FileHdr);
CurLoc := 0;
Seek(InF, CurLoc);
CheckIO(InF);
WriteLn;
WriteLn('Compressed File: ', OutFile^);
WriteLn;
WriteLn(' ORIG CMP HDR CMP CMP PRG ');
Write (' FILE NAME SIZE SIZE LEN PCT TYP VER CRC ');
if (Option = 'L') then
WriteLn(' DATE TIME')
else
WriteLn('ORIGINAL PATH');
WriteLn(Dashes);
Lines := 0;
{ go through and display one line for each file in the compress file }
While (Done = False) do begin
BlockRead(InF, FileHdr^, SizeOf(FileHdr^), ActualR);
CheckIO(InF);
If (ActualR = SizeOf(FileHdr^)) then begin
With FileHdr^ do begin
if (Signature<> ValidSig) then begin
WriteLn;
WriteLn('Compress file is corrupted. Invalid signature found');
WriteLn;
Halt(1);
end;
OrigTotal := OrigTotal + OrigFileSize;
CompTotal := CompTotal + CompFileSize;
OvhdTotal := OvhdTotal + HeaderSize;
FSplit(FileName, Dir^, Name, Ext);
Write(Name:8, Ext);
Write(Spaces:5-Length(Ext));
Write(OrigFileSize:7, ' ');
Write(CompFileSize:7, ' ');
Write(HeaderSize:5, ' ');
If (OrigFileSize = CompFileSize) then
Write(' 0% ')
else
Write(99-((CompFileSize * 100) / OrigFileSize):2:0, '% ');
Case CompressType of
Compressed : Write('LZW13 ');
UnCompressed : Write('NONE ');
end;
Write(ReleaseLevel:2, ' ');
Write(HexXlate[Hi(FileCrc) shr 4]);
Write(HexXlate[Hi(FileCrc) and $F]);
Write(HexXlate[Lo(FileCrc) shr 4]);
Write(HexXlate[Lo(FileCrc) and $F]);
{ display file date & time if 'L' option or original path if 'F' }
if (Option='L') then begin
UnpackTime(FileDate, DT);
WorkStr:=CVS(DT.Month)+'-'+CVS(DT.Day)+'-'+CVS(DT.Year-1900);
Write(' ', WorkStr);
WorkStr:=CVS(DT.Hour)+':'+CVS(DT.Min)+':'+CVS(DT.Sec);
Write(' ', WorkStr);
end
else begin
Write(' ', PathName);
end;
WriteLn;
Inc(Lines);
{ if display is full, pause for any key.. }
If (Lines = 18) then begin
Lines := 0;
Write('Pausing...');
Repeat
GetKey;
Until (InKey <> 0);
Write(#8#8#8#8#8#8#8#8#8#8#8);
end;
CurLoc:=CurLoc+HeaderSize+CompFileSize;
Seek(InF, CurLoc);
CheckIO(InF);
end;
end
else begin
Done := True;
end;
end;
{ display compress file totals }
If (OrigTotal = 0) then
PctTotal := 0
else
PctTotal := 99 - ((CompTotal * 100 ) div OrigTotal);
if (PctTotal = -1) then
PctTotal := 0;
WriteLn(' ------ ------ ---- -- ');
WriteLn(' ', OrigTotal:8, CompTotal:8, OvhdTotal:6, PctTotal:3, '%');
{ release allocated heap space, clean up and return }
CLose(InF);
CheckIO(InF);
Dispose(FileHdr);
Dispose(OutFile);
Dispose(Dir);
end; {ProcessList}
{----------------------------------------------------------------------------}
{ }
{ procedure 'DisplayHelp' }
{ }
{ This procedure displays help information for running this program }
{ }
{----------------------------------------------------------------------------}
Procedure DisplayHelp;
begin {DisplayHelp}
WriteLn('Usage:');
WriteLn(' MDCD [c] [d:][path]AnyFile{wildcards ok} [d:][path]CompressFile[.ext(.md)]');
WriteLn(' MDCD [dr] [d:][path]CompressFile[.ext(.md)] [d:][path]');
WriteLn(' MDCD [lf] [d:][path]CcompressFile[.ext(.md)]');
WriteLn;
WriteLn('Options: C = Compress file(s)');
WriteLn(' D = Decompress file(s) with pause if output file exists');
WriteLn(' R = Decompress file(s) with automatic file overwrite');
WriteLn(' L = list file(s) in compress file - show date & time');
WriteLn(' F = list file(s) in compress file - show original file path');
WriteLn;
WriteLn('Examples:');
WriteLn(' mdcd c q.exe quattro.cd ;compress q.exe & add to quattro.cd');
WriteLn(' mdcd c *.pas mypas.cd ;compress all .pas files & add to mypas.cd');
WriteLn(' mdcd c *.wkq quat ;compress all .wkq files & add to quat.md ');
WriteLn(' mdcd l mypas.cd ;list file(s) in mypas.cd with date and time');
WriteLn(' mdcd f quattro ;list file(s) in quattro.md w/original drive/path name');
WriteLn(' mdcd d mypas.cd ;decompress mypas.cd into current directory');
WriteLn(' mdcd d quat e:\quattro ;decompress quat.md into e:\quattro directory');
WriteLn(' mdcd r quat ;decompress quat.md to current dir with file overwrite');
end; {DisplayHelp}
{----------------------------------------------------------------------------}
{ }
{ 'MAINLINE PROGRAM' }
{ }
{----------------------------------------------------------------------------}
Begin
{ write program logo screen }
DosError := 0;
WriteLn;
WriteLn(Hdr1);
WriteLn(Hdr2);
WriteLn;
{ check command line parameter for valid option. display help if not valid }
WorkStr := ParamStr(1);
Option := UpCase(WorkStr[1]);
If ( (Length(WorkStr) <> 1) ) or
( (Option<>'C') and
(Option<>'D') and
(Option<>'R') and
(Option<>'L') and
(Option<>'F') ) then begin
DisplayHelp;
Halt(1);
end;
{ valid option. call the appropriate routine to process }
Case Option of
'C' : begin {compress }
If (Length(ParamStr(2))=0) then begin
WriteLn('Parm 2 must be an input file name/wildcard mask');
Halt(1)
end;
If (Length(ParamStr(3))=0) then begin
WriteLn('Parm 3 must be the name of the compressed output file');
Halt(1);
end;
MRC:=ProcessCompress;
end;
'R','D': begin {decompress/overwrite}
If (Length(ParamStr(2))=0) then begin
WriteLn('Parm 2 must be a valid compressed file');
Halt(1)
end;
MRC:=ProcessDeCompress(Option);
end;
'L','F': begin {list date or path }
If (Length(ParamStr(2))=0) then begin
WriteLn('Parameter 2 must be a valid compressed file');
Halt(1);
end;
MRC:=ProcessList(Option);
end;
end;
End.