home *** CD-ROM | disk | FTP | other *** search
- {
- ==============================================================================
- DEARC.PAS - Program to extract all files from an archive created by version
- 5.12 or earlier of the ARC utility.
-
- ARC is COPYRIGHT 1985 by System Enhancement Associates.
-
- This program requires Turbo Pascal Version 4.01. It should work in all
- supported environments (PCDOS, CPM, etc.) but it has only been tested on
- an IBM PC running PC DOS version 3.10.
-
- Usage: DEARC arcname
-
- arcname : path/file name of the archive file.
-
- All files will be extracted into the current directory.
-
- Modification History:
-
- *** ORIGINAL AUTHOR UNKNOWN ***
-
- Version 1.01 - 10/19/85. Changed end-of-file processing to, hopefully, be
- more compatible with CPM (whatever that is).
-
- Version 1.01A - 12/19/85 By Roy Collins
- Mail: TechMail BBS @ 703-430-2535
- - or -
- P.O.Box 1192, Leesburg, Va 22075
- Modified V1.01 to work with Turbo Pascal Version 2
- Added functions ARGC (argument count) and ARGV
- (argument value)
- Modified all references to "EXIT" command to be
- GOTO EXIT, with EXIT defined as a LABEL, at the
- end of the function/procedure involved.
- Will not accept path names - archives must be in
- the current directory.
-
- Version 2.00 - 6/11/86 By David W. Carroll
- Mail: High Sierra RBBS-PC @ 209/296-3534
- Now supports ARC version 5.12 files, compression
- types 7 and 8.
-
- Version 3.00 - 7/30/87 By Richard P. Byrne
- UN*X E-Mail: ...!ihnp4!mduxf!rpb
- BBS Mail: Software Society BBS @ (201) 729-7410
- Modified Version 2.00 to handle compression type
- 9 (ie. Squashed ).
-
- Version 3.01 - 11/23/87 By Robert D. Tolz
- Compuserve 70475,1071
- BBS (914) 762-8150
- Modified Version 3.00 solely to comment how to
- obtain extracted files which are precisely the
- same length as the files which were archived.
- Prior versions would extract in 128-byte
- multiples. Problem with precise extraction is
- that it increases extraction time (already
- quite slow compared to PKXARC and ARC-E) by
- several times. Search for the term "PRECISE"
- to see the 3 changes necessary to the code.
- I invite the next person who tries their hand
- at this code to try (1) to increase speed
- and/or (2) to find a method to extract precisely
- only specific files that need it and leave the
- faster 128-byte block method for other files.
-
- Version 4.0 - 1/23/88 By Jim North
- Compuserve 70357,2701
- Changes are as follows:
- - Convert to TP version 4.0
- - Rewrote file I/O to make use of large
- file buffering in heap while still
- maintaining precise size of extracted
- files. This resulted in dramatic speed
- improvements.
- - Program now skips files it can't de-arc
- (because of new compression method) instead
- of aborting. Will extract all files it can
- de-arc.
- - Added check for the extract file already
- existing. If it does, a warning is issued
- with an "Overwrite(Y/N)" option.
- - Beefed up I/O error reporting.
- - Edited and re-organized source. Added some
- comments.
- No functional changes were made to the actual
- de-arc routines.
-
- ==============================================================================
- }
- Program DEARC;
-
- {$R-} {Range checking off}
- {$B+} {Boolean complete evaluation on}
- {$S-} {Stack checking off}
- {$I+} {I/O checking on}
- {$N-} {No numeric coprocessor}
- {$M 65500,16384,655360} {Turbo 3 default stack and heap}
-
- Const BLOCKSIZE = $D000; { size of file buffers in heap }
- ARCMARC = 26; { special archive marker }
- ARCVER = 9; { max archive header version code }
- STRLEN = 100; { standard string length }
- FNLEN = 12; { file name length - 1 }
- { --- crc table --- }
- CRCTAB : array [0..255] of word =
- ( $0000, $C0C1, $C181, $0140, $C301, $03C0, $0280, $C241,
- $C601, $06C0, $0780, $C741, $0500, $C5C1, $C481, $0440,
- $CC01, $0CC0, $0D80, $CD41, $0F00, $CFC1, $CE81, $0E40,
- $0A00, $CAC1, $CB81, $0B40, $C901, $09C0, $0880, $C841,
- $D801, $18C0, $1980, $D941, $1B00, $DBC1, $DA81, $1A40,
- $1E00, $DEC1, $DF81, $1F40, $DD01, $1DC0, $1C80, $DC41,
- $1400, $D4C1, $D581, $1540, $D701, $17C0, $1680, $D641,
- $D201, $12C0, $1380, $D341, $1100, $D1C1, $D081, $1040,
- $F001, $30C0, $3180, $F141, $3300, $F3C1, $F281, $3240,
- $3600, $F6C1, $F781, $3740, $F501, $35C0, $3480, $F441,
- $3C00, $FCC1, $FD81, $3D40, $FF01, $3FC0, $3E80, $FE41,
- $FA01, $3AC0, $3B80, $FB41, $3900, $F9C1, $F881, $3840,
- $2800, $E8C1, $E981, $2940, $EB01, $2BC0, $2A80, $EA41,
- $EE01, $2EC0, $2F80, $EF41, $2D00, $EDC1, $EC81, $2C40,
- $E401, $24C0, $2580, $E541, $2700, $E7C1, $E681, $2640,
- $2200, $E2C1, $E381, $2340, $E101, $21C0, $2080, $E041,
- $A001, $60C0, $6180, $A141, $6300, $A3C1, $A281, $6240,
- $6600, $A6C1, $A781, $6740, $A501, $65C0, $6480, $A441,
- $6C00, $ACC1, $AD81, $6D40, $AF01, $6FC0, $6E80, $AE41,
- $AA01, $6AC0, $6B80, $AB41, $6900, $A9C1, $A881, $6840,
- $7800, $B8C1, $B981, $7940, $BB01, $7BC0, $7A80, $BA41,
- $BE01, $7EC0, $7F80, $BF41, $7D00, $BDC1, $BC81, $7C40,
- $B401, $74C0, $7580, $B541, $7700, $B7C1, $B681, $7640,
- $7200, $B2C1, $B381, $7340, $B101, $71C0, $7080, $B041,
- $5000, $90C1, $9181, $5140, $9301, $53C0, $5280, $9241,
- $9601, $56C0, $5780, $9741, $5500, $95C1, $9481, $5440,
- $9C01, $5CC0, $5D80, $9D41, $5F00, $9FC1, $9E81, $5E40,
- $5A00, $9AC1, $9B81, $5B40, $9901, $59C0, $5880, $9841,
- $8801, $48C0, $4980, $8941, $4B00, $8BC1, $8A81, $4A40,
- $4E00, $8EC1, $8F81, $4F40, $8D01, $4DC0, $4C80, $8C41,
- $4400, $84C1, $8581, $4540, $8701, $47C0, $4680, $8641,
- $8201, $42C0, $4380, $8341, $4100, $81C1, $8081, $4040 );
- { --- constants for unpack --- }
- DLE = $90;
- { --- constants for unsqueeze --- }
- ERROR = -1;
- SPEOF = 256;
- NUMVALS = 256; { 1 less than the number of values }
- { --- constants for uncrunch --- }
- TABSIZE = 4096;
- TABSIZEM1 = 4095;
- NO_PRED = -1;
- EMPTY = -1;
- { --- constants for dynamic uncrunch --- }
- CRUNCH_BITS = 12;
- SQUASH_BITS = 13;
- HSIZE = 8192;
- INIT_BITS = 9;
- FIRST = 257;
- CLEAR = 256;
- HSIZEM1 = 8191;
- BITSM1 = 12;
- RMASK : array[0..8] of byte =
- ($00, $01, $03, $07, $0f, $1f, $3f, $7f, $ff);
-
- Type strtype = string[strlen]; { general string definition }
- fntype = array [0..fnlen] of char; { file name definition }
- buftype = array [1..BLOCKSIZE] of byte; { file buffer def. (in heap) }
- bufptr = ^buftype; { pointer type for file buffer }
- heads = record { ARC file header record def }
- name : fntype;
- size : longint;
- date : word;
- time : word;
- crc : word;
- length : longint;
- end;
- { --- type definitions for unsqueeze --- }
- nd = record
- child : array [0..1] of integer;
- end;
- { --- type definitions for uncrunch --- }
- entry = record
- used : boolean;
- next : integer;
- predecessor : integer;
- follower : byte;
- end;
-
- Var hdrver : byte; { holds header version (compression type) }
- arcfile : file; { file variable for input (archive) file }
- arcbuf : bufptr; { heap pointer for archive file buffer }
- arcptr : word; { archive buffer location pointer }
- arccount : word; { holds # of valid bytes in archive buffer }
- arcname : string[79]; { holds path & name of file being de-arced }
- endfile : boolean; { end-of-file flag for archive file }
- extfile : file; { file variable for output (de-arced) file }
- extbuf : bufptr; { heap pointer for output file buffer }
- extptr : word; { output file buffer location pointer }
- extname : strtype; { holds name of current output file }
- { --- variables for unpack --- }
- state : (NOHIST, INREP);
- crcval : word;
- size : longint;
- lastc : integer;
- { --- variables for unsqueeze --- }
- node : array [0..NUMVALS] of nd;
- bpos : integer;
- curin : integer;
- numnodes : integer;
- { --- variables for uncrunch --- }
- stack : array [0..TABSIZEM1] of byte;
- sp : integer;
- string_tab : array [0..TABSIZEM1] of entry;
- code_count : integer;
- code : integer;
- firstc : boolean;
- oldcode : integer;
- finchar : integer;
- inbuf : integer;
- outbuf : integer;
- newhash : boolean;
- { --- variables for dynamic uncrunch --- }
- bits,
- n_bits,
- maxcode : integer;
- prefix : array[0..HSIZEM1] of integer;
- suffix : array[0..HSIZEM1] of byte;
- buf : array[0..BITSM1] of byte;
- clear_flg : integer;
- stack1 : array[0..HSIZEM1] of byte;
- free_ent : integer;
- maxcodemax : integer;
- offset,
- sizex : integer;
- firstch : boolean;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: Abort
- Action : Display error message [s] and terminate.
- ----------------------------------------------------------------------}
- Procedure Abort(s:strtype);
- begin
- writeln(s);
- writeln('Returning to DOS');
- halt;
- end;
-
-
- {----------------------------------------------------------------------
- FUNCTION: Fn_To_Str
- Action : Converts (fntype) parameter from C format (trailing
- 0) to TP string format.
- Parameters : var (fntype)
- Returns : var converted to str
- ----------------------------------------------------------------------}
- Function Fn_To_Str(var fn: fntype): strtype;
- Var s : strtype;
- i : integer;
- begin
- s := '';
- i := 0;
- while fn[i] <> #0 do
- begin
- s := s + fn[i];
- i := i + 1;
- end;
- fn_to_str := s;
- end;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: IO_Test
- Action : Test ioresult. Reports fatal errors and terminates
- ----------------------------------------------------------------------}
- Procedure IO_Test;
- var ec: word;
- begin
- ec:=ioresult;
- if ec<>0 then
- begin
- case ec of
- 2 : writeln('File Not Found');
- 3 : writeln('Path Not Found');
- 5 : writeln('Directory Full');
- 101 : writeln('Disk Full');
- else
- writeln('IO Error # ',ec);
- end;
- writeln('Returning to DOS');
- halt;
- end;
- end;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: Read_Arc_Block
- Action : Read a block of archive file into "arcbuf"
- Globals Altered: arcptr, arccount, endfile
- ----------------------------------------------------------------------}
- Procedure Read_Arc_Block;
- begin
- if eof(arcfile) then
- endfile := TRUE
- else
- BlockRead(arcfile, arcbuf^, BLOCKSIZE, arccount);
- arcptr := 1;
- end;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: Write_Ext_Block
- Action : Write a [extptr-1] bytes from "extbuf" to disk.
- Globals Altered: extptr
- ----------------------------------------------------------------------}
- Procedure Write_Ext_Block;
- begin
- if extptr > 1 then
- begin
- {$I-}
- BlockWrite(extfile, extbuf^, extptr-1);
- {$I+}
- IO_Test;
- extptr := 1;
- end;
- end;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: Open_Arc
- Action : Open archive file [arcname] for input.
- Globals Altered: arcfile,endfile
- ----------------------------------------------------------------------}
- Procedure Open_Arc;
- begin
- assign(arcfile, arcname);
- {$I-}
- reset(arcfile,1);
- {$I+}
- IO_Test;
- endfile := FALSE;
- Read_Arc_Block; { pre-load buffer }
- end;
-
-
- {----------------------------------------------------------------------
- FUNCTION: Open_Ext
- Action : Create & open new destination file for extract.
- If file exists, asks user to verify overwrite.
- Returns : TRUE to proceed, FALSE if user says to skip.
- Globals Altered: extfile,extptr
- ----------------------------------------------------------------------}
- Function Open_Ext:boolean;
- label
- exit;
- var
- yn : char;
- begin
- assign(extfile, extname);
- {$I-}
- reset(extfile,1); { see if file exists }
- {$I+}
- if ioresult=0 then
- begin
- close(extfile);
- write('WARNING: ',extname,' already exists. Overwrite(Y/N)?');
- readln(yn);
- if upcase(yn)<>'Y' then
- begin
- open_ext:=FALSE;
- goto exit;
- end;
- end;
- open_ext:=TRUE;
- {$I-}
- rewrite(extfile,1);
- {$I+}
- IO_Test;
- extptr:=1;
- exit:
- end;
-
-
- {----------------------------------------------------------------------
- FUNCTION: Get_Arc
- Action : Get next byte from "arcbuf". Calls Read_Arc_Block
- if buffer is empty.
- Returns : next byte or 0 if end of file
- Globals Altered: arcptr
- ----------------------------------------------------------------------}
- Function Get_Arc: byte;
- begin
- if endfile then
- Get_Arc := 0
- else
- begin
- Get_Arc := arcbuf^[arcptr];
- if arcptr = arccount then
- Read_Arc_Block
- else
- arcptr := arcptr + 1
- end;
- end;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: Put_Ext
- Action : Write byte into "extbuf". Calls Write_Ext_Block
- if buffer is full.
- Parameters : byte to be written
- Globals Altered: extptr
- ----------------------------------------------------------------------}
- Procedure Put_Ext(c : byte);
- begin
- extbuf^[extptr] := c;
- extptr := extptr + 1;
- if extptr > BLOCKSIZE then Write_Ext_Block;
- end;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: Close_Arc
- Action : Close archive file.
- ----------------------------------------------------------------------}
- Procedure Close_Arc;
- begin
- {$I-}
- close(arcfile);
- {$I+}
- IO_Test;
- end;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: Close_Ext
- Action : Close extract file.
- ----------------------------------------------------------------------}
- Procedure Close_Ext;
- begin
- Write_Ext_Block; { flush buffer }
- {$I-}
- close(extfile);
- {$I+}
- IO_Test;
- end;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: FSkip
- Action : Skip over [offset] bytes of archive file
- Parameters : # of bytes to skip
- Globals Altered: arcptr
- ----------------------------------------------------------------------}
- Procedure FSkip(offset: longint);
- Var rec: longint;
- begin
- if (offset+arcptr)<=arccount then
- arcptr:=arcptr+offset
- else
- begin
- rec:=filepos(arcfile)+(offset-(arccount-arcptr)-1);
- {$I-}
- seek(arcfile,rec);
- {$I+}
- IO_Test;
- Read_Arc_Block;
- end;
- end;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: FRead
- Action : Read variable length record from archive file
- Parameters : buf: destination buffer, reclen: length
- Globals Altered:
- ----------------------------------------------------------------------}
- Procedure FRead(var buf; reclen : integer);
- Var i : integer;
- b : array [1..MaxInt] of byte absolute buf;
- begin
- for i := 1 to reclen do
- b[i] := get_arc
- end;
-
-
- {----------------------------------------------------------------------
- FUNCTION: Read_Hdr
- Action : Read next header into [hdr] buffer.
- Returns : TRUE if ok, FALSE if end of file
- Globals Altered: arcptr
- ----------------------------------------------------------------------}
- Function Read_Hdr(var hdr: heads): boolean;
- label exit;
- var name: fntype;
- begin
- if endfile then
- begin
- read_hdr:=FALSE; { end of file }
- goto exit;
- end;
- if Get_Arc<>ARCMARC then Abort('Missing or invalid header in '+arcname);
- hdrver:=Get_Arc;
- if hdrver<0 then Abort ('Missing or invalid header in '+arcname);
- if hdrver=0 then
- begin
- read_hdr:=FALSE; { end of file }
- goto exit;
- end;
- if hdrver=1 then
- begin
- Fread(hdr,sizeof(heads)-sizeof(longint));
- hdrver:=2;
- hdr.length:=hdr.size;
- end
- else
- fread(hdr,sizeof(heads));
- read_hdr:=TRUE;
- exit:
- end;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: Putc_Unp
- ----------------------------------------------------------------------}
- Procedure Putc_Unp(c:integer);
- begin
- crcval:=((crcval shr 8) and $00FF) xor crctab[(crcval xor c) and $00FF];
- put_ext(c)
- end;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: Putc_Ncr
- ----------------------------------------------------------------------}
- Procedure Putc_Ncr(c:integer);
- begin
- case state of
- NOHIST : if c=DLE then
- state:=INREP
- else
- begin
- lastc:= c;
- putc_unp(c);
- end;
- INREP : begin
- if c=0 then
- putc_unp(DLE)
- else
- begin
- c:=c-1;
- while (c<>0) do
- begin
- putc_unp(lastc);
- c:=c-1;
- end;
- end;
- state:=NOHIST
- end;
- end;
- end;
-
-
- {----------------------------------------------------------------------
- FUNCTION: Getc_Unp
- ----------------------------------------------------------------------}
- Function Getc_Unp:integer;
- begin
- if size=0.0 then
- getc_unp:=-1
- else
- begin
- size:=size-1;
- getc_unp:=get_arc;
- end;
- end;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: Init_Usq
- Action : Initialize for Unsqueeze
- ----------------------------------------------------------------------}
- Procedure Init_Usq;
- var
- i : integer;
- begin
- bpos:=99;
- fread(numnodes,sizeof(numnodes));
- if (numnodes<0) or (numnodes>NUMVALS) then
- Abort(extname+' has an invalid decode tree');
- node[0].child[0]:=-(SPEOF+1);
- node[0].child[1]:=-(SPEOF+1);
- for i:=0 to numnodes-1 do
- begin
- fread(node[i].child[0],sizeof(integer));
- fread(node[i].child[1],sizeof(integer));
- end;
- end;
-
-
- {----------------------------------------------------------------------
- FUNCTION: Getc_Usq
- Action : Unsqueeze a byte
- ----------------------------------------------------------------------}
- Function Getc_Usq:integer;
- label exit;
- var
- i : integer;
- begin
- i:=0;
- while i >= 0 do
- begin
- bpos:=bpos+1;
- if bpos>7 then
- begin
- curin:=getc_unp;
- if curin=ERROR then
- begin
- getc_usq:=ERROR;
- goto exit;
- end;
- bpos:=0;
- i:=node[i].child[1 and curin];
- end
- else
- begin
- curin:=curin shr 1;
- i:=node[i].child[1 and curin];
- end;
- end;
- i:=-(i + 1);
- if i=SPEOF then
- getc_usq:=-1
- else
- getc_usq:=i;
- exit:
- end;
-
-
- {----------------------------------------------------------------------
- FUNCTION: H
- Action : Calculate hash value (thanks to Bella Lubkin)
- ----------------------------------------------------------------------}
- Function H(pred,foll: integer): integer;
- var
- Local : Real;
- S : String[20];
- I, V : integer;
- C : char;
- begin
- if not newhash then
- begin
- Local:=(pred+foll) or $0800;
- if Local<0.0 then
- Local:=Local+65536.0;
- Local:=(Local*Local)/64.0;
- { convert Local to an integer, truncating high order bits. }
- { there ***MUST*** be a better way to do this!!! }
- Str(Local:15:5,S);
- V:=0;
- I:=1;
- C:=S[1];
- while C<>'.' do
- begin
- if (C>='0') and (C<='9') then
- V:=V*10+(Ord(C)-Ord('0'));
- I:=I+1;
- C:=S[I];
- end;
- h:=V and $0FFF;
- end
- else
- begin
- Local:=(pred+foll)*15073;
- { convert Local to an integer, truncating high order bits. }
- { there ***MUST*** be a better way to do this!!! }
- Str(Local:15:5,S);
- V:=0;
- I:=1;
- C:=S[1];
- while C<>'.' do
- begin
- if (C>='0') and (C<='9') then
- V:=V*10+(Ord(C)-Ord('0'));
- I:=I+1;
- C:=S[I];
- end;
- h:=V and $0FFF;
- end;
- end;
-
-
- {----------------------------------------------------------------------
- FUNCTION: Eolist
- ----------------------------------------------------------------------}
- Function Eolist(index:integer):integer;
- var
- temp:integer;
- begin
- temp:=string_tab[index].next;
- while temp<>0 do
- begin
- index:=temp;
- temp:=string_tab[index].next;
- end;
- eolist:=index;
- end;
-
-
- {----------------------------------------------------------------------
- FUNCTION: Hash
- ----------------------------------------------------------------------}
- Function Hash(pred,foll:integer):integer;
- var
- local : integer;
- tempnext : integer;
- begin
- local:=h(pred,foll);
- if not string_tab[local].used then
- hash:=local
- else
- begin
- local:=eolist(local);
- tempnext:=(local+101) and $0FFF;
- while string_tab[tempnext].used do
- begin
- tempnext:=tempnext+1;
- if tempnext=TABSIZE then
- tempnext:=0;
- end;
- string_tab[local].next:=tempnext;
- hash:=tempnext;
- end;
- end;
-
- {----------------------------------------------------------------------
- PROCEDURE: Upd_Tab
- ----------------------------------------------------------------------}
- Procedure Upd_Tab(pred,foll:integer);
- begin
- with string_tab[hash(pred, foll)] do
- begin
- used:=TRUE;
- next:=0;
- predecessor:=pred;
- follower:=foll;
- end;
- end;
-
- {----------------------------------------------------------------------
- FUNCTION: Gocode
- ----------------------------------------------------------------------}
- Function Gocode:integer;
- label exit;
- var
- localbuf : integer;
- returnval : integer;
- begin
- if inbuf=EMPTY then
- begin
- localbuf:=getc_unp;
- if localbuf=-1 then
- begin
- gocode:=-1;
- goto exit;
- end;
- localbuf:=localbuf and $00FF;
- inbuf:=getc_unp;
- if inbuf=-1 then
- begin
- gocode:=-1;
- goto exit;
- end;
- inbuf:=inbuf and $00FF;
- returnval:=((localbuf shl 4) and $0FF0)+((inbuf shr 4) and $000F);
- inbuf:=inbuf and $000F;
- end
- else
- begin
- localbuf:=getc_unp;
- if localbuf=-1 then
- begin
- gocode:=-1;
- goto exit;
- end;
- localbuf:=localbuf and $00FF;
- returnval:=localbuf+((inbuf shl 8) and $0F00);
- inbuf:=EMPTY;
- end;
- gocode:=returnval;
- exit:
- end;
-
-
- {----------------------------------------------------------------------
- FUNCTION: Push
- ----------------------------------------------------------------------}
- Procedure Push(c:integer);
- begin
- stack[sp]:=c;
- sp:=sp+1;
- if sp>=TABSIZE then
- Abort('Stack overflow');
- end;
-
-
- {----------------------------------------------------------------------
- FUNCTION: Pop
- ----------------------------------------------------------------------}
- Function Pop:integer;
- begin
- if sp>0 then
- begin
- sp:=sp-1;
- pop:=stack[sp];
- end
- else
- pop:=EMPTY;
- end;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: Init_Tab
- ----------------------------------------------------------------------}
- Procedure Init_Tab;
- var
- i : integer;
- begin
- FillChar(string_tab, sizeof(string_tab), 0);
- for i := 0 to 255 do
- upd_tab(NO_PRED, i);
- inbuf := EMPTY;
- { outbuf := EMPTY }
- end;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: Init_Ucr
- ----------------------------------------------------------------------}
- Procedure Init_Ucr(i:integer);
- begin
- newhash:=(i=1);
- sp:=0;
- init_tab;
- code_count:=TABSIZE-256;
- firstc:=TRUE;
- end;
-
-
- {----------------------------------------------------------------------
- FUNCTION: Getc_Ucr
- ----------------------------------------------------------------------}
- Function Getc_Ucr:integer;
- label exit;
- var
- c : integer;
- code : integer;
- newcode : integer;
- begin
- if firstc then
- begin
- firstc:=FALSE;
- oldcode:=gocode;
- finchar:=string_tab[oldcode].follower;
- getc_ucr:=finchar;
- goto exit;
- end;
- if sp=0 then
- begin
- newcode:=gocode;
- code:=newcode;
- if code=-1 then
- begin
- getc_ucr:=-1;
- goto exit;
- end;
- if not string_tab[code].used then
- begin
- code:=oldcode;
- push(finchar);
- end;
- while string_tab[code].predecessor <> NO_PRED do
- with string_tab[code] do
- begin
- push(follower);
- code:=predecessor;
- end;
- finchar:=string_tab[code].follower;
- push(finchar);
- if code_count<>0 then
- begin
- upd_tab(oldcode, finchar);
- code_count:=code_count-1;
- end;
- oldcode:=newcode;
- end;
- getc_ucr:=pop;
- exit:
- end;
-
-
- {----------------------------------------------------------------------
- FUNCTION: Getcode
- ----------------------------------------------------------------------}
- Function Getcode:integer;
- label
- next, exit;
- var
- code,
- r_off,
- bitsx : integer;
- bp : byte;
- begin
- if firstch then
- begin
- offset:=0;
- sizex:=0;
- firstch:=false;
- end;
- bp:=0;
- if (clear_flg>0) or (offset>=sizex) or (free_ent>maxcode) then
- begin
- if free_ent>maxcode then
- begin
- n_bits:=n_bits+1;
- if n_bits=BITS then
- maxcode:=maxcodemax
- else
- maxcode:=(1 shl n_bits)-1;
- end;
- if clear_flg > 0 then
- begin
- n_bits:=INIT_BITS;
- maxcode:=(1 shl n_bits)-1;
- clear_flg:=0;
- end;
- for sizex := 0 to n_bits-1 do
- begin
- code:=getc_unp;
- if code=-1 then
- goto next
- else
- buf[sizex]:=code;
- end;
- sizex:=sizex+1;
- next:
- if sizex<=0 then
- begin
- getcode:=-1;
- goto exit;
- end;
- offset:=0;
- sizex:=(sizex shl 3)-(n_bits-1);
- end;
- r_off:=offset;
- bitsx:=n_bits;
- { get first byte }
- bp:=bp+(r_off shr 3);
- r_off:=r_off and 7;
-
- { get first parft (low order bits) }
- code:=buf[bp] shr r_off;
- bp:=bp+1;
- bitsx:=bitsx-(8-r_off);
- r_off:=8-r_off;
-
- if bitsx>=8 then
- begin
- code:=code or (buf[bp] shl r_off);
- bp:=bp+1;
- r_off:=r_off+8;
- bitsx:=bitsx-8;
- end;
- code:=code or ((buf[bp] and rmask[bitsx]) shl r_off);
- offset:=offset+n_bits;
- getcode:=code;
- exit:
- end;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: Decomp
- ----------------------------------------------------------------------}
- Procedure Decomp(squashflag:integer);
- label
- next,exit;
- var
- stackp,
- finchar :integer;
- code,
- oldcode,
- incode :integer;
- begin
- if squashflag=0 then
- bits:=crunch_BITS
- else
- bits:=squash_BITS;
-
- if firstch then
- maxcodemax:=1 shl bits;
-
- if squashflag=0 then
- begin
- code:=getc_unp;
- if code<>BITS then
- begin
- writeln(extname,' packed with ',Code,' bits, I can only handle ',Bits);
- halt;
- end;
- end;
- clear_flg:=0;
- n_bits:=INIT_BITS;
- maxcode:=(1 shl n_bits )-1;
- for code:=255 downto 0 do
- begin
- prefix[code]:=0;
- suffix[code]:=code;
- end;
-
- free_ent:=FIRST;
- oldcode:=getcode;
- finchar:=oldcode;
- if oldcode=-1 then
- goto exit;
- if squashflag=0 then
- putc_ncr(finchar)
- else
- putc_unp(finchar);
- stackp:=0;
-
- code:=getcode;
- while (code>-1) do
- begin
- if code=CLEAR then
- begin
- for code:=255 downto 0 do
- prefix[code]:=0;
- clear_flg:=1;
- free_ent:=FIRST-1;
- code:=getcode;
- if code=-1 then
- goto next;
- end;
- next:
- incode:=code;
- if code>=free_ent then
- begin
- stack1[stackp]:=finchar;
- stackp:=stackp+1;
- code:=oldcode;
- end;
- while (code>=256) do
- begin
- stack1[stackp]:=suffix[code];
- stackp:=stackp+1;
- code:=prefix[code];
- end;
- finchar:=suffix[code];
- stack1[stackp]:=finchar;
- stackp:=stackp+1;
- repeat
- stackp:=stackp-1;
- if squashflag=0 then
- putc_ncr(stack1[stackp])
- else
- putc_unp(stack1[stackp]);
- until stackp<=0;
- code:=free_ent;
- if code<maxcodemax then
- begin
- prefix[code]:=oldcode;
- suffix[code]:=finchar;
- free_ent:=code+1;
- end;
- oldcode:=incode;
- code:=getcode;
- end;
- exit:
- end;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: Unpack
- Action : Unpack according to [hdrver] format.
- ----------------------------------------------------------------------}
- Procedure Unpack(var hdr:heads);
- label exit;
- var
- c: integer;
- begin
- crcval := 0;
- size := hdr.size;
- state := NOHIST;
- FirstCh := TRUE;
- case hdrver of
- 1, 2 : begin
- c:=getc_unp;
- while c<>-1 do
- begin
- putc_unp(c);
- c:=getc_unp;
- end;
- end;
- 3 : begin
- c:=getc_unp;
- while c<>-1 do
- begin
- putc_ncr(c);
- c:=getc_unp;
- end;
- end;
- 4 : begin
- init_usq;
- c:=getc_usq;
- while c<>-1 do
- begin
- putc_ncr(c);
- c:=getc_usq;
- end;
- end;
- 5 : begin
- init_ucr(0);
- c:=getc_ucr;
- while c<>-1 do
- begin
- putc_unp(c);
- c:=getc_ucr;
- end;
- end;
- 6 : begin
- init_ucr(0);
- c:=getc_ucr;
- while c <> -1 do
- begin
- putc_ncr(c);
- c:=getc_ucr;
- end;
- end;
- 7 : begin
- init_ucr(1);
- c:=getc_ucr;
- while c<>-1 do
- begin
- putc_ncr(c);
- c:=getc_ucr;
- end;
- end;
- 8 : begin
- decomp(0);
- end;
- 9 : begin
- decomp(1);
- end;
- end;
- if crcval<>hdr.crc then
- writeln('WARNING: File ',extname,' fails CRC check');
- exit:
- end;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: Extract_File
- Action : Extract file specified in [hdr].
- ----------------------------------------------------------------------}
- Procedure Extract_File(var hdr:heads);
- begin
- writeln('Extracting: '+extname);
- if Open_Ext then
- begin
- Unpack(hdr);
- Close_Ext;
- end
- else
- begin
- writeln('Skipping: '+extname);
- FSkip(hdr.size);
- end;
- end;
-
-
- {----------------------------------------------------------------------
- FUNCTION: Verify_File
- Action : Verify that program can decompress file.
- Returns : TRUE for proceed, FALSE for skip.
- ----------------------------------------------------------------------}
- Function Verify_File(var hdr:heads):boolean;
- begin
- verify_file:=TRUE; { default case }
- extname:= fn_to_str(hdr.name);
- if hdrver>ARCVER then
- begin
- writeln('Skipping: '+extname+' -- Try a newer version of DEARC');
- verify_file:=FALSE;
- end;
- end;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: Initialize
- Action : Perform one-time initialization --
- -- allocate file buffers in heap
- -- print heading
- Globals Altered: arcbuf, extbuf
- ----------------------------------------------------------------------}
- Procedure Initialize;
- begin
- writeln;
- writeln('Turbo Pascal v4 De-ARC Utility');
- writeln('Version 4.0, 1/23/88');
- writeln('Supports Phil Katz "squashed" files');
- writeln;
- New(arcbuf);
- New(extbuf);
- end;
-
- {----------------------------------------------------------------------
- PROCEDURE: Load_Parms
- Action : Read Command-Line Parameters
- Globals Altered: arcname
- ----------------------------------------------------------------------}
- Procedure Load_Parms;
- var
- i : integer;
- begin
- i:=ParamCount;
- if i>=1 then
- arcname:=ParamStr(1)
- else
- begin
- write('Enter archive filename: ');
- readln(arcname);
- if arcname='' then Abort('');
- end;
- for i:=1 to length(arcname) do
- arcname[i]:=UpCase(arcname[i]);
- if pos('.',arcname)=0 then
- arcname:=arcname+'.ARC';
- end;
-
-
- {----------------------------------------------------------------------
- PROCEDURE: Extract_Arc
- Action : Extract files from target archive file.
- Skips files it can't decompress.
- ----------------------------------------------------------------------}
- Procedure Extract_Arc;
- var
- hdr: heads;
- begin
- Open_Arc;
- while Read_Hdr(hdr) do
- if Verify_File(hdr) then
- Extract_File(hdr)
- else
- FSkip(hdr.size);
- Close_Arc;
- end;
-
-
- begin
- Initialize; { one-time initialization }
- Load_Parms; { get command line parameters }
- Extract_Arc; { de-arc the file }
- end.