由于最近因为工作需要使用到LZW解压缩算法,找遍全网也没有发现DELPHI的版本,痛苦之下留下一个
印记,献给有类似需要的人
unit LzwDecompression;
interface
uses
Winapi.Windows,System.SysUtils, System.Classes;
function LZWDecode(pin,pout:pbyte):Integer;
implementation
const
INIT_BITS=9;
TABLE_SIZE= 18041;
MAX_BITS = 14;
HASHING_SHIFT = MAX_BITS-8;
CLEAR_TABLE = 256;
TERMINATOR = 257;
FIRST_CODE=258;
CHECK_TIME = 100;
var
currnt_code:PINT;
prefix_code:array [0..3999] of NativeUInt;
append_char:array [0..3999] of byte;
decode_stack:array [0..3999] of byte;
bytes_out:LongWord;
checkpoint:LongWord = CHECK_TIME;
num_bits:Cardinal = INIT_BITS;
max_code:Cardinal = 0;
end_flag:Cardinal=0;
input_bit_count:Cardinal = 0;
input_bit_buffer:Cardinal = 0;
function maxval(n:integer):Integer;
begin
result:= (1 shl n) -1;
end;
function input_code(var input:PByte):Cardinal;
var
return_value,input_bit_buf:Cardinal;
begin
while input_bit_count <=24 do
begin
input_bit_buf := input^;
Inc(input);
input_bit_buf:=input_bit_buf shl (24-input_bit_count);
input_bit_buffer:= input_bit_buffer or input_bit_buf;
Inc(input_bit_count,8);
end;
return_value:=input_bit_buffer shr (32-num_bits);
input_bit_buffer := input_bit_buffer shl num_bits;
input_bit_count := input_bit_count - num_bits;
result:=return_value;
end;
function decode_string(buffer:pbyte;code:Cardinal):pbyte;
var
i:Integer;
begin
i:=0;
while code>255 do
begin
buffer^ :=append_char[code];
Inc(buffer);
code := prefix_code[code];
inc(i);
if i>=4000 then
begin
raise Exception.Create('内存越界');
Exit;
end;
end;
buffer^ := byte(code);
Result :=(buffer);
end;
function LZWDecode(pin,pout:pbyte):Integer;
var
temppstr:PByte;
next_code:Cardinal;
new_code,old_code:Cardinal;
character:Integer;
clear_flag:Boolean;
s:string;
begin
currnt_code:=GetMemory(TABLE_SIZE*SIZEOF(INTEGER));
FillChar(append_char,SizeOf(append_char),0);
FillChar(prefix_code,SizeOf(prefix_code),0);
next_code:=FIRST_CODE;
new_code:=0;
clear_flag:=True;
bytes_out:=0;
character:=0;
old_code:=0;
max_code:= maxval(num_bits);
while (new_code <> TERMINATOR) do
begin
new_code:=input_code(pin);
if clear_flag then
begin
clear_flag:=False;
old_code:=new_code;
character:=old_code;
if old_code>255 then
pout^:=byte(old_code)
else
pout^:=old_code;
s:=s+char(pout^);
Inc(pout);
Inc(bytes_out);
Continue;
end;
if new_code = CLEAR_TABLE then
begin
clear_flag:=True;
num_bits:=INIT_BITS;
next_code:=FIRST_CODE;
max_code:=maxval(num_bits);
Continue;
end;
if new_code >= next_code then
begin
decode_stack[0]:=Byte(character);
temppstr:=@decode_stack[0];
Inc(temppstr);
temppstr:=decode_string(temppstr,old_code);
end
else
begin
temppstr:=@decode_stack[0];
temppstr:=decode_string(temppstr,new_code);
end;
character:=byte(temppstr^);
while temppstr >= pbyte(@decode_stack[0]) do
begin
pout^:=Byte(temppstr^);
Inc(bytes_out);
s:=s+char(pout^);
Inc(pout);
Dec(temppstr);
end;
if next_code<=Cardinal(max_code) then
begin
prefix_code[next_code] := old_code;
append_char[next_code] := character;
Inc(next_code);
if (next_code = max_code) and (num_bits <MAX_BITS) then
begin
Inc(num_bits);
max_code:=maxval(num_bits);
end;
end;
old_code:=new_code;
end;
result:=bytes_out-2;
FreeMem(currnt_code);
end;
end.