{ unsq file from file in_file to out_file }

{ This program unsqueezes a file which has been squeezed or compressed }
{ to reduce the space required to store it on disk. The program was    }
{ converted from the original version written for CP/M in the C        }
{ language. This program can be used to unsqueeze files which have     }
{ been downloaded from RCP/M systems where almost all files are saved  }
{ in this squeezed format.                                             }

{ The technique used is the Huffman encoding technique which converts  }
{ the most common characters in the input file to a compressed bit     }
{ stream of data. This program unsqueezes such a Huffman encoded file. }

{ PUBLIC DOMAIN - Feel free to distribute this program. Do not         }
{ distribute it by commercial means or make any charge for this pgm.   }

{ Version 1.0 - 9/5/82 }

{ Scott Loftesness - 9/05/82 }

{$debug-}
{$list-}
{$include:'a:filkqq.inc'}
{$include:'a:filuqq.inc'}
{$list+}
program unsq(in_file,out_file,output);
  uses filkqq, filuqq;

const
    recognize = #ff76;
    numvals = 257;  { max tree size + 1 }
    speof = 256;   { special end of file marker }
    dle = chr(#90);

type
    tree = array [0..255,0..1] of word;

var in_file, out_file: file of char;
    dnode: tree;
    bpos, i, repct: integer;
    c, inchar: char;
    lastchar: char;
    curin, filecksum: word;
    numnodes: integer;
    origfile: string(14);
    eofin: boolean;

{ getparm -- get parms from command line }
procedure getparm;
var error: word;
    l: lstring(255);
begin
    error:=ppmuqq(0,adr null,l);
    writeln('This was on the command line:',l)
end; {getparm}

{ getw - get a word value from the input file }
function getw: word;
    var in1,in2: char;
  begin
    read(in_file,in1);
    read(in_file,in2);
    getw:=byword(in2,in1)
  end; {getw}

function getc: char;
  begin
    read(in_file,getc)
  end; {getc}

procedure openfiles;
  begin
    reset(in_file);   { open the input file }
    rewrite(out_file); {open the output file }
  end; {openfiles}

procedure initialize;
  begin
    openfiles;        { go open the files }
    if recognize<>getw then {check for valid unsqueezed file format }
        abort('Error - file is not a squeezed file',1,0);
    filecksum:=getw;  { get checksum from chars 2 - 3 of file }
    i:=0;
    repct:=0;
    bpos:=99;
    origfile:='              ';           { initialize to blanks }
    eofin:=false;
    repeat
        i:=i+1;
        inchar:=getc;
        if inchar<>chr(0) then
            origfile[i]:=chr(inchar)      { build original file name }
    until inchar=chr(0); { bypass the file name in the header }
    writeln(output,'File: ',origfile,' -> ');
    numnodes:=ord(getw); { get the number of nodes in this files tree }
    if (numnodes<0) or (numnodes>=numvals) then
        abort('Error - File has invalid decode tree size',2,0);
    dnode[0,0]:= -(speof+1);
    dnode[0,1]:= -(speof+1);
    numnodes:=numnodes-1;
    for i:=0 to numnodes do begin
        dnode[i,0]:=getw;
        dnode[i,1]:=getw;
    end; {for}
  end; {initialize}

procedure dochar(c:char);
  begin
    write(out_file,c);
  end; {dochar}

function getuhuff: char;
var i: integer;
  begin
    i:=0;
    repeat
      bpos:=bpos+1;
      if bpos>7 then begin
        curin:=wrd(getc);
        bpos:=0;
        i:=ord(dnode[i,ord(curin and #0001)]);
      end {if}
      else begin
        curin:=curin div wrd(2);
        i:=ord(dnode[i,ord(curin and #0001)]);
      end; {else}
    until (i<0); {repeat}
    i:=-(i+1);
    if i=speof then begin
       eofin:=true;
       getuhuff:=chr(26)
       end {if}
    else getuhuff:=chr(i);
  end; {getuhuff}


function getcr: char;
var c: char;
  begin
    if (repct>0) then begin
        repct:=repct-1;
        getcr:=lastchar;
    end {if}
    else begin
        c:=getuhuff;
        if c<>dle then begin
            getcr:=c;
            lastchar:=c;
        end {if}
        else begin
            repct:=ord(getuhuff);
            if repct=0 then getcr:=dle
            else begin;
                repct:=repct-2;
                getcr:=lastchar;
            end; {else}
        end; {else}
    end; {else}
  end; {getcr}

begin   { main program }
    initialize;
    writeln(output,'Tree loaded sucessfully. Un-squeezing begins...');
    while not(eof(in_file)) or not(eofin) do begin
        c:=getcr;
        dochar(c);
    end; {while}
end. {unsq}
