368 lines
11 KiB
Ada
368 lines
11 KiB
Ada
with Ada.Text_IO;
|
|
with Ada.Unchecked_Deallocation;
|
|
|
|
package body GID.Decoding_PNG.Huffman is
|
|
|
|
procedure Build(t: out Huff_tree; descr: in Huff_descriptor) is
|
|
curr, alloc: Natural;
|
|
code, mask: Unsigned_32;
|
|
begin
|
|
alloc:= root;
|
|
for i in descr'Range loop
|
|
if descr(i).length > 0 then
|
|
curr:= root;
|
|
code:= Unsigned_32(descr(i).code);
|
|
mask:= Shift_Left(Unsigned_32'(1), descr(i).length-1);
|
|
for j in 0..descr(i).length-1 loop
|
|
if (code and mask) /= 0 then
|
|
if t.node(curr).one = nil then
|
|
alloc:= alloc + 1;
|
|
t.node(curr).one:= alloc;
|
|
end if;
|
|
curr:= t.node(curr).one;
|
|
else
|
|
if t.node(curr).zero = nil then
|
|
alloc:= alloc + 1;
|
|
t.node(curr).zero:= alloc;
|
|
end if;
|
|
curr:= t.node(curr).zero;
|
|
end if;
|
|
mask:= Shift_Right(mask, 1);
|
|
end loop;
|
|
t.node(curr).n:= i;
|
|
end if;
|
|
end loop;
|
|
t.last:= alloc;
|
|
end Build;
|
|
|
|
-- Free huffman tables starting with table where t points to
|
|
|
|
procedure HufT_free ( tl: in out p_Table_list ) is
|
|
|
|
procedure Dispose is new
|
|
Ada.Unchecked_Deallocation( HufT_table, p_HufT_table );
|
|
procedure Dispose is new
|
|
Ada.Unchecked_Deallocation( Table_list, p_Table_list );
|
|
|
|
current: p_Table_list;
|
|
tcount : Natural; -- just a stat. Idea: replace table_list with an array
|
|
tot_length: Natural;
|
|
|
|
begin
|
|
if full_trace then
|
|
Ada.Text_IO.Put("[HufT_Free... ");
|
|
tcount:= 0;
|
|
tot_length:= 0;
|
|
end if;
|
|
while tl /= null loop
|
|
if full_trace then
|
|
tcount:= tcount+1;
|
|
tot_length:= tot_length + tl.table'Length;
|
|
end if;
|
|
Dispose( tl.table ); -- destroy the Huffman table
|
|
current:= tl;
|
|
tl := tl.next;
|
|
Dispose( current ); -- destroy the current node
|
|
end loop;
|
|
if full_trace then
|
|
Ada.Text_IO.Put_Line(
|
|
Integer'Image(tcount)& " tables, of" &
|
|
Integer'Image(tot_length)& " tot. length]"
|
|
);
|
|
end if;
|
|
end HufT_free;
|
|
|
|
-- Build huffman table from code lengths given by array b
|
|
|
|
procedure HufT_build ( b : Length_array;
|
|
s : Integer;
|
|
d, e : Length_array;
|
|
tl : out p_Table_list;
|
|
m : in out Integer;
|
|
huft_incomplete : out Boolean)
|
|
is
|
|
b_max : constant:= 16;
|
|
b_maxp1: constant:= b_max + 1;
|
|
|
|
-- bit length count table
|
|
count : array( 0 .. b_maxp1 ) of Integer:= (others=> 0);
|
|
|
|
f : Integer; -- i repeats in table every f entries
|
|
g : Integer; -- max. code length
|
|
i, -- counter, current code
|
|
j : Integer; -- counter
|
|
kcc : Integer; -- number of bits in current code
|
|
|
|
c_idx, v_idx: Natural; -- array indices
|
|
|
|
current_table_ptr : p_HufT_table:= null;
|
|
current_node_ptr : p_Table_list:= null; -- curr. node for the curr. table
|
|
new_node_ptr : p_Table_list; -- new node for the new table
|
|
|
|
new_entry: HufT; -- table entry for structure assignment
|
|
|
|
u : array( 0..b_max ) of p_HufT_table; -- table stack
|
|
|
|
n_max : constant:= 288;
|
|
-- values in order of bit length
|
|
v : array( 0..n_max ) of Integer:= (others=> 0);
|
|
el_v, el_v_m_s: Integer;
|
|
|
|
w : Natural:= 0; -- bits before this table
|
|
|
|
offset, code_stack : array( 0..b_maxp1 ) of Integer;
|
|
|
|
table_level : Integer:= -1;
|
|
bits : array( Integer'(-1)..b_maxp1 ) of Integer;
|
|
-- ^bits(table_level) = # bits in table of level table_level
|
|
|
|
y : Integer; -- number of dummy codes added
|
|
z : Natural:= 0; -- number of entries in current table
|
|
el : Integer; -- length of eob code=code 256
|
|
|
|
no_copy_length_array: constant Boolean:= d'Length=0 or e'Length=0;
|
|
|
|
begin
|
|
if full_trace then
|
|
Ada.Text_IO.Put("[HufT_Build...");
|
|
end if;
|
|
tl:= null;
|
|
|
|
if b'Length > 256 then -- set length of EOB code, if any
|
|
el := b(256);
|
|
else
|
|
el := b_max;
|
|
end if;
|
|
|
|
-- Generate counts for each bit length
|
|
|
|
for k in b'Range loop
|
|
if b(k) > b_max then
|
|
-- m := 0; -- GNAT 2005 doesn't like it (warning).
|
|
raise huft_error;
|
|
end if;
|
|
count( b(k) ):= count( b(k) ) + 1;
|
|
end loop;
|
|
|
|
if count(0) = b'Length then
|
|
m := 0;
|
|
huft_incomplete:= False; -- spotted by Tucker Taft, 19-Aug-2004
|
|
return; -- complete
|
|
end if;
|
|
|
|
-- Find minimum and maximum length, bound m by those
|
|
|
|
j := 1;
|
|
while j <= b_max and then count(j) = 0 loop
|
|
j:= j + 1;
|
|
end loop;
|
|
kcc := j;
|
|
if m < j then
|
|
m := j;
|
|
end if;
|
|
i := b_max;
|
|
while i > 0 and then count(i) = 0 loop
|
|
i:= i - 1;
|
|
end loop;
|
|
g := i;
|
|
if m > i then
|
|
m := i;
|
|
end if;
|
|
|
|
-- Adjust last length count to fill out codes, if needed
|
|
|
|
y := Integer( Shift_Left(Unsigned_32'(1), j) ); -- y:= 2 ** j;
|
|
while j < i loop
|
|
y := y - count(j);
|
|
if y < 0 then
|
|
raise huft_error;
|
|
end if;
|
|
y:= y * 2;
|
|
j:= j + 1;
|
|
end loop;
|
|
|
|
y:= y - count(i);
|
|
if y < 0 then
|
|
raise huft_error;
|
|
end if;
|
|
count(i):= count(i) + y;
|
|
|
|
-- Generate starting offsets into the value table for each length
|
|
|
|
offset(1) := 0;
|
|
j:= 0;
|
|
for idx in 2..i loop
|
|
j:= j + count( idx-1 );
|
|
offset( idx ) := j;
|
|
end loop;
|
|
|
|
-- Make table of values in order of bit length
|
|
|
|
for idx in b'Range loop
|
|
j := b(idx);
|
|
if j /= 0 then
|
|
v( offset(j) ) := idx-b'First;
|
|
offset(j):= offset(j) + 1;
|
|
end if;
|
|
end loop;
|
|
|
|
-- Generate huffman codes and for each, make the table entries
|
|
|
|
code_stack(0) := 0;
|
|
i := 0;
|
|
v_idx:= v'First;
|
|
bits(-1) := 0;
|
|
|
|
-- go through the bit lengths (kcc already is bits in shortest code)
|
|
for k in kcc .. g loop
|
|
|
|
for am1 in reverse 0 .. count(k)-1 loop -- a counts codes of length k
|
|
|
|
-- here i is the huffman code of length k bits for value v(v_idx)
|
|
while k > w + bits(table_level) loop
|
|
|
|
w:= w + bits(table_level); -- Length of tables to this position
|
|
table_level:= table_level+ 1;
|
|
z:= g - w; -- Compute min size table <= m bits
|
|
if z > m then
|
|
z := m;
|
|
end if;
|
|
j := k - w;
|
|
f := Integer(Shift_Left(Unsigned_32'(1), j)); -- f:= 2 ** j;
|
|
if f > am1 + 2 then -- Try a k-w bit table
|
|
f:= f - (am1 + 2);
|
|
c_idx:= k;
|
|
loop -- Try smaller tables up to z bits
|
|
j:= j + 1;
|
|
exit when j >= z;
|
|
f := f * 2;
|
|
c_idx:= c_idx + 1;
|
|
exit when f - count(c_idx) <= 0;
|
|
f:= f - count(c_idx);
|
|
end loop;
|
|
end if;
|
|
|
|
if w + j > el and then w < el then
|
|
j:= el - w; -- Make EOB code end at table
|
|
end if;
|
|
if w = 0 then
|
|
j := m; -- Fix: main table always m bits!
|
|
end if;
|
|
z:= Integer(Shift_Left(Unsigned_32'(1), j)); -- z:= 2 ** j;
|
|
bits(table_level) := j;
|
|
|
|
-- Allocate and link new table
|
|
|
|
begin
|
|
current_table_ptr := new HufT_table ( 0..z );
|
|
new_node_ptr := new Table_list'( current_table_ptr, null );
|
|
exception
|
|
when Storage_Error =>
|
|
raise huft_out_of_memory;
|
|
end;
|
|
|
|
if current_node_ptr = null then -- first table
|
|
tl:= new_node_ptr;
|
|
else
|
|
current_node_ptr.next:= new_node_ptr; -- not my first...
|
|
end if;
|
|
|
|
current_node_ptr:= new_node_ptr; -- always non-Null from there
|
|
|
|
u( table_level ):= current_table_ptr;
|
|
|
|
-- Connect to last table, if there is one
|
|
|
|
if table_level > 0 then
|
|
code_stack(table_level) := i;
|
|
new_entry.bits := bits(table_level-1);
|
|
new_entry.extra_bits := 16 + j;
|
|
new_entry.next_table := current_table_ptr;
|
|
|
|
j := Integer(
|
|
Shift_Right( Unsigned_32(i) and
|
|
(Shift_Left(Unsigned_32'(1), w) - 1 ),
|
|
w - bits(table_level-1) )
|
|
);
|
|
|
|
-- Test against bad input!
|
|
|
|
if j > u( table_level - 1 )'Last then
|
|
raise huft_error;
|
|
end if;
|
|
u( table_level - 1 ) (j) := new_entry;
|
|
end if;
|
|
|
|
end loop;
|
|
|
|
-- Set up table entry in new_entry
|
|
|
|
new_entry.bits := k - w;
|
|
new_entry.next_table:= null; -- Unused
|
|
|
|
if v_idx >= b'Length then
|
|
new_entry.extra_bits := invalid;
|
|
else
|
|
el_v:= v(v_idx);
|
|
el_v_m_s:= el_v - s;
|
|
if el_v_m_s < 0 then -- Simple code, raw value
|
|
if el_v < 256 then
|
|
new_entry.extra_bits:= 16;
|
|
else
|
|
new_entry.extra_bits:= 15;
|
|
end if;
|
|
new_entry.n := el_v;
|
|
else -- Non-simple -> lookup in lists
|
|
if no_copy_length_array then
|
|
raise huft_error;
|
|
end if;
|
|
new_entry.extra_bits := e( el_v_m_s );
|
|
new_entry.n := d( el_v_m_s );
|
|
end if;
|
|
v_idx:= v_idx + 1;
|
|
end if;
|
|
|
|
-- fill code-like entries with new_entry
|
|
f := Integer( Shift_Left( Unsigned_32'(1) , k - w ));
|
|
-- i.e. f := 2 ** (k-w);
|
|
j := Integer( Shift_Right( Unsigned_32(i), w ) );
|
|
while j < z loop
|
|
current_table_ptr(j) := new_entry;
|
|
j:= j + f;
|
|
end loop;
|
|
|
|
-- backwards increment the k-bit code i
|
|
j := Integer( Shift_Left( Unsigned_32'(1) , k - 1 ));
|
|
-- i.e.: j:= 2 ** (k-1)
|
|
while ( Unsigned_32(i) and Unsigned_32(j) ) /= 0 loop
|
|
i := Integer( Unsigned_32(i) xor Unsigned_32(j) );
|
|
j := j / 2;
|
|
end loop;
|
|
i := Integer( Unsigned_32(i) xor Unsigned_32(j) );
|
|
|
|
-- backup over finished tables
|
|
while
|
|
Integer(Unsigned_32(i) and (Shift_Left(1, w)-1)) /=
|
|
code_stack(table_level)
|
|
loop
|
|
table_level:= table_level - 1;
|
|
w:= w - bits(table_level); -- Size of previous table!
|
|
end loop;
|
|
|
|
end loop; -- am1
|
|
end loop; -- k
|
|
|
|
if full_trace then
|
|
Ada.Text_IO.Put_Line("finished]");
|
|
end if;
|
|
|
|
huft_incomplete:= y /= 0 and g /= 1;
|
|
|
|
exception
|
|
when others =>
|
|
HufT_free( tl );
|
|
raise;
|
|
end HufT_build;
|
|
|
|
end GID.Decoding_PNG.Huffman;
|