Uses Buffered; Type PTree = ^TTree; TTree = record info : byte; ti : longint; Left : PTree; Right: PTree; end; ps = ^el; el = record data : PTree; prev : ps; end; CONST fname : string[13] = 'input.txt'; fout : string[13] = 'input.huf'; VAR counts : array [0..255] of longint; INP,OUT : FILE; Nums : ps; THead : PTree; {-----} GNum : byte; done : boolean; Size,Csize,Go : longint; LastLen : byte; {---------------------------------} Procedure DelBranch(br:PTree); begin if br^.left <> nil then DelBranch(br^.left); if br^.right <> nil then DelBranch(br^.right); Dispose(br); end;{DelBranch} {---------------------------------} Procedure AddItem(var HEAD:ps; VAL : PTree); var c,NEWs : ps; Begin c := HEAD; New(News); News^.data := VAL; News^.prev := nil; if c=nil then begin HEAD := NEWs; exit end; if val^.ti <= C^.DATA^.ti then begin News^.prev:=C; HEAD:=News; exit end; while (c^.prev <> nil) and (not ((val^.ti>C^.data^.ti) and (val^.ti<=C^.prev^.data^.ti))) do c:=c^.prev; News^.prev := c^.prev; C^.prev := News; end;{AddItem} {---------------------------------} Procedure RemoveItem(var HEAD:ps; VAL : PTree); var c,cur : ps; Begin c := HEAD; if c=nil then exit; if c^.data = val then begin HEAD:=C^.prev; Dispose(C); exit end; while (c^.prev <> nil) and (C^.prev^.data <> val) do c:=c^.prev; if c^.prev^.data <> val then exit; cur := c^.prev; C^.prev := cur^.prev; Dispose(cur); end;{RemoveItem} {---------------------------------} Function GetBit(var F:File):boolean; var Suxx:byte; begin if GNum = 0 then begin GNum := 8; done:=FReadBuf(F,Suxx); inc(CSize); go:=Suxx; if not done then begin RBLast:=true; FReadBuf(F,Suxx); WBLast:=true; FWriteBuf(OUT,0); close(INP); Close(OUT); Halt(0); end; if csize=Size-1 then begin done:=FReadBuf(F,Gnum) end; end; Dec(GNum); GetBit := (GO and 128) = 128; Go := GO shl 1; end;{GetBit} {----------------------------} Procedure DeleteAll(var HEAD:ps); var c:ps; begin while HEAD <> nil do begin c:=HEAD^.prev; Dispose(HEAD); HEAD := C; end; end;{DeleteAll} {---------------------------------} Procedure CreateTree; var i : byte; News : PTree; begin for i := 0 to 255 do if counts[i] <> 0 then begin New(News); News^.info:=i; News^.ti:=counts[i]; News^.Left:=nil;News^.Right:=nil; AddItem(Nums,News); end; while NUMS^.prev <> nil do begin New(News); News^.ti := NUMS^.data^.ti+NUMS^.prev^.data^.ti; News^.left := Nums^.data; News^.right := Nums^.prev^.data; RemoveItem(NUMS,NUMS^.data); RemoveItem(NUMS,NUMS^.data); AddItem(NUMS,News); end; THead := News; RemoveItem(NUMS,News); end;{CreateTree} {---------------------------------} Procedure GetTimes(var F:file); begin BlockRead(F,counts,256*4) end;{GetTimes} {---------------------------------} VAR CURCODE : longint; curlen : byte; CUR : byte; i : byte; Ctr : Ptree; BEGIN if (ParamCount<1) then begin WriteLn('Usage: unHUF.exe [OUTNAME.ext]'); Halt(10); end; Fname := ParamStr(1); for size := 1 to Length(Fname) do fname[size] := UpCase(fname[size]); if Paramcount = 2 then fout := ParamStr(2) else fout := Copy(Fname,1,pos('.',Fname)) + 'TXT'; Assign(INP,Fname); Reset(INP,1); Assign(OUT,Fout); Rewrite(OUT,1); Size:=FileSize(INP)-256*4; GetTimes(INP); CreateTree; Ctr := THead; RBFirst:=true; WBFirst:=true; RBLast:=false; WBLast:=false; while true do begin while CTR^.left <> nil do begin if GetBit(INP) then CTR:=CTR^.left else CTR:=CTR^.right; end; Write(#13'Complete: ',round((csize/size)*100),'%'); FWriteBuf(OUT,CTR^.INFO); CTR:=THead; end; END.