| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- 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;
- table : array [0..255] of longint;
- tbllens : array [0..255] of byte;
- INP,OUT : FILE;
- Nums : ps;
- THead : PTree;
- {-----}
- Code : longint;
- CodeLen : byte;
- {-----}
- GO,GNum : byte;
- done : boolean;
- Size,Csize : longint;
- {---------------------------------}
- 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 SetTimes(var F:File);
- var
- curpos,rsize : word;
- ch : byte;
- begin
- FillChar(counts,256,0);
- CurPos := FilePos(F);
- Seek(F,0);
- RBFirst:=true;
- RBLast:=false;
- while FreadBuf(F,ch) do inc(counts[ch]);
- RBLast:=true;
- FReadBuf(F,ch);
- Seek(F,CurPos);
- end;{SetTimes}
- {---------------------------------}
- 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}
- {---------------------------------}
- 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 GetCode(VAL:Byte;BRA:PTree;cur:longint;len:byte);
- begin
- if (Bra^.left=nil) and (Bra^.right=nil) and (BRA^.info = VAL) then
- begin
- Code := cur;
- CodeLen:=len;
- end;
- if (Bra^.left<>nil) then begin
- GetCode(val,Bra^.left,(cur shl 1) + 1,len+1);
- GetCode(val,Bra^.right,(cur shl 1),len+1)
- end;
- end;{GetCode}
- {---------------------------------}
- Procedure SetTable;
- var i : byte;
- begin
- for i := 0 to 255 do
- if counts[i] <> 0 then
- begin
- GetCode(i,THead,0,0);
- table[i] := Code;
- tbllens[i] := codelen;
- end;
- end;{SetTable}
- {---------------------------------}
- Procedure PutTimes(var F:file);
- begin BlockWrite(F,counts,256*4) end;{GetTimes}
- {---------------------------------}
- Procedure IfNeedWrite(var gg:longint;var num:byte;var F:FILE);
- var
- FFF : byte;
- begin
- while num >= 8 do
- begin
- FWriteBuf(F,((gg shl (32-num)) and $FF000000) shr 24);
- dec(num,8);
- end;
- end;{IfNeedWrite}
- {---------------------------------}
- VAR
- CURCODE : longint;
- curlen : byte;
- CUR : byte;
- i : byte;
- Ctr : Ptree;
- BEGIN
- if (ParamCount<1) then
- begin
- WriteLn('Usage: HUF.exe <FILENAME.EXT> [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)) + 'HUF';
- Assign(INP,Fname);
- Reset(INP,1);
- { Size:=FileSize(INP);}
- SetTimes(INP);
- CreateTree;
- SetTable;
- DelBranch(THead);
- Assign(OUT,Fout);
- Rewrite(OUT,1);
- PutTimes(OUT);
- curcode:=0;
- curlen:=0;
- RBFirst:=true;
- RBLast:=false;
- WBFirst:=true;
- WBLast:=false;
- while FreadBuf(inp,cur) do
- begin
- if ((curlen mod 8) + tbllens[cur])< 32 then
- begin
- if (curlen+tbllens[cur]) > 32 then ifNeedWrite(curcode,curlen,OUT);
- curcode := (curcode shl tbllens[cur]) + table[cur];
- inc(curlen,tbllens[cur]);
- end
- else
- begin
- for i := 1 to tbllens[cur] do
- begin
- if curlen >= 8 then IfNeedWrite(curcode,curlen,OUT);
- curcode := (curcode shl 1) +
- ((table[cur] shr (tbllens[cur]-i)) and 1);
- inc(curlen);
- end;
- end;
- end;
- if (curlen mod 8) <> 0 then
- begin
- cur := 8-(curlen mod 8);
- curcode := curcode shl (cur);
- inc(curlen,cur);
- end;
- ifNeedWrite(curcode,curlen,OUT);
- FWriteBuf(OUT,cur);
- RBLast:=true;
- FReadBuf(INP,cur);
- WBLast:=true;
- FWriteBuf(OUT,0);
- Close(OUT);
- Close(INP);
- END.
|