-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
gid-decoding_png-huffman.adb
366 lines (302 loc) · 10.7 KB
/
gid-decoding_png-huffman.adb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
with Ada.Text_IO,
Ada.Unchecked_Deallocation;
package body GID.Decoding_PNG.Huffman is
use Interfaces;
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 := 0; -- just a stat. Idea: replace table_list with an array
tot_length : Natural := 0;
begin
if full_trace then
Ada.Text_IO.Put ("[HufT_Free... ");
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 := Natural (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 (Natural (b (k))) := count (Natural (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 := Natural (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 := Natural (e (el_v_m_s));
new_entry.n := Natural (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;