Source file : unzip-decompress-huffman.adb
1 -- Legal licensing note:
2
3 -- Copyright (c) 1999 .. 2023 Gautier de Montmollin
4 -- SWITZERLAND
5
6 -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 -- of this software and associated documentation files (the "Software"), to deal
8 -- in the Software without restriction, including without limitation the rights
9 -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 -- copies of the Software, and to permit persons to whom the Software is
11 -- furnished to do so, subject to the following conditions:
12
13 -- The above copyright notice and this permission notice shall be included in
14 -- all copies or substantial portions of the Software.
15
16 -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 -- THE SOFTWARE.
23
24 -- NB: this is the MIT License, as found on the site
25 -- http://www.opensource.org/licenses/mit-license.php
26
27 with Ada.Text_IO,
28 Ada.Unchecked_Deallocation;
29 with Interfaces;
30
31 package body UnZip.Decompress.Huffman is
32
33 -- Note from Pascal source:
34 -- C code by info-zip group, translated to pascal by Christian Ghisler
35 -- based on unz51g.zip
36
37 -- Free huffman tables starting with table where t points to
38
39 procedure HufT_free (tl : in out p_Table_list) is
40
41 procedure Dispose is new
42 Ada.Unchecked_Deallocation (HufT_table, p_HufT_table);
43 procedure Dispose is new
44 Ada.Unchecked_Deallocation (Table_list, p_Table_list);
45
46 current : p_Table_list;
47 tcount : Natural := 0; -- just a stat. Idea: replace table_list with an array
48
49 begin
50 if full_trace then
51 Ada.Text_IO.Put ("[HufT_Free... ");
52 end if;
53 while tl /= null loop
54 Dispose (tl.table); -- destroy the Huffman table
55 current := tl;
56 tl := tl.next;
57 Dispose (current); -- destroy the current node
58 if full_trace then
59 tcount := tcount + 1;
60 end if;
61 end loop;
62 if full_trace then
63 Ada.Text_IO.Put_Line (Integer'Image (tcount) & " tables]");
64 end if;
65 end HufT_free;
66
67 -- Build huffman table from code lengths given by array b
68
69 procedure HufT_build (b : Length_array;
70 s : Integer;
71 d, e : Length_array;
72 tl : out p_Table_list;
73 m : in out Integer;
74 huft_incomplete : out Boolean)
75 is
76 use Interfaces;
77
78 b_max : constant := 16;
79 b_maxp1 : constant := b_max + 1;
80
81 -- bit length count table
82 count : array (0 .. b_maxp1) of Integer := (others => 0);
83
84 f : Integer; -- i repeats in table every f entries
85 g : Integer; -- max. code length
86 i, -- counter, current code
87 j : Integer; -- counter
88 kcc : Integer; -- number of bits in current code
89
90 c_idx, v_idx : Natural; -- array indices
91
92 current_table_ptr : p_HufT_table := null;
93 current_node_ptr : p_Table_list := null; -- curr. node for the curr. table
94 new_node_ptr : p_Table_list; -- new node for the new table
95
96 new_entry : HufT; -- table entry for structure assignment
97
98 u : array (0 .. b_max) of p_HufT_table; -- table stack
99
100 n_max : constant := 288;
101 -- values in order of bit length
102 v : array (0 .. n_max) of Integer := (others => 0);
103 el_v, el_v_m_s : Integer;
104
105 w : Natural := 0; -- bits before this table
106
107 offset, code_stack : array (0 .. b_maxp1) of Integer;
108
109 table_level : Integer := -1;
110 bits : array (Integer'(-1) .. b_maxp1) of Integer;
111 -- ^bits (table_level) = # bits in table of level table_level
112
113 y : Integer; -- number of dummy codes added
114 z : Natural := 0; -- number of entries in current table
115 el : Integer; -- length of eob code=code 256
116
117 no_copy_length_array : constant Boolean := d'Length = 0 or e'Length = 0;
118
119 begin
120 if full_trace then
121 Ada.Text_IO.Put ("[HufT_Build...");
122 end if;
123 tl := null;
124
125 if b'Length > 256 then -- set length of EOB code, if any
126 el := b (256);
127 else
128 el := b_max;
129 end if;
130
131 -- Generate counts for each bit length
132
133 for k in b'Range loop
134 if b (k) > b_max then
135 -- m := 0; -- GNAT 2005 doesn't like it (warning).
136 raise huft_error;
137 end if;
138 count (b (k)) := count (b (k)) + 1;
139 end loop;
140
141 if count (0) = b'Length then
142 m := 0;
143 huft_incomplete := False; -- spotted by Tucker Taft, 19-Aug-2004
144 return; -- complete
145 end if;
146
147 -- Find minimum and maximum length, bound m by those
148
149 j := 1;
150 while j <= b_max and then count (j) = 0 loop
151 j := j + 1;
152 end loop;
153 kcc := j;
154 if m < j then
155 m := j;
156 end if;
157 i := b_max;
158 while i > 0 and then count (i) = 0 loop
159 i := i - 1;
160 end loop;
161 g := i;
162 if m > i then
163 m := i;
164 end if;
165
166 -- Adjust last length count to fill out codes, if needed
167
168 y := Integer (Shift_Left (Unsigned_32'(1), j)); -- y:= 2 ** j;
169 while j < i loop
170 y := y - count (j);
171 if y < 0 then
172 raise huft_error;
173 end if;
174 y := y * 2;
175 j := j + 1;
176 end loop;
177
178 y := y - count (i);
179 if y < 0 then
180 raise huft_error;
181 end if;
182 count (i) := count (i) + y;
183
184 -- Generate starting offsets into the value table for each length
185
186 offset (1) := 0;
187 j := 0;
188 for idx in 2 .. i loop
189 j := j + count (idx - 1);
190 offset (idx) := j;
191 end loop;
192
193 -- Make table of values in order of bit length
194
195 for idx in b'Range loop
196 j := b (idx);
197 if j /= 0 then
198 v (offset (j)) := idx - b'First;
199 offset (j) := offset (j) + 1;
200 end if;
201 end loop;
202
203 -- Generate huffman codes and for each, make the table entries
204
205 code_stack (0) := 0;
206 i := 0;
207 v_idx := v'First;
208 bits (-1) := 0;
209
210 -- go through the bit lengths (kcc already is bits in shortest code)
211 for k in kcc .. g loop
212
213 for am1 in reverse 0 .. count (k) - 1 loop -- a counts codes of length k
214
215 -- here i is the huffman code of length k bits for value v(v_idx)
216 while k > w + bits (table_level) loop
217
218 w := w + bits (table_level); -- Length of tables to this position
219 table_level := table_level + 1;
220 z := g - w; -- Compute min size table <= m bits
221 if z > m then
222 z := m;
223 end if;
224 j := k - w;
225 f := Integer (Shift_Left (Unsigned_32'(1), j)); -- f:= 2 ** j;
226 if f > am1 + 2 then -- Try a k-w bit table
227 f := f - (am1 + 2);
228 c_idx := k;
229 loop -- Try smaller tables up to z bits
230 j := j + 1;
231 exit when j >= z;
232 f := f * 2;
233 c_idx := c_idx + 1;
234 exit when f - count (c_idx) <= 0;
235 f := f - count (c_idx);
236 end loop;
237 end if;
238
239 if w + j > el and then w < el then
240 j := el - w; -- Make EOB code end at table
241 end if;
242 if w = 0 then
243 j := m; -- Fix: main table always m bits!
244 end if;
245 z := Integer (Shift_Left (Unsigned_32'(1), j)); -- z:= 2 ** j;
246 bits (table_level) := j;
247
248 -- Allocate and link new table
249
250 begin
251 current_table_ptr := new HufT_table (0 .. z);
252 new_node_ptr := new Table_list'(current_table_ptr, null);
253 exception
254 when Storage_Error =>
255 raise huft_out_of_memory;
256 end;
257
258 if current_node_ptr = null then -- first table
259 tl := new_node_ptr;
260 else
261 current_node_ptr.next := new_node_ptr; -- not my first...
262 end if;
263
264 current_node_ptr := new_node_ptr; -- always non-Null from there
265
266 u (table_level) := current_table_ptr;
267
268 -- Connect to last table, if there is one
269
270 if table_level > 0 then
271 code_stack (table_level) := i;
272 new_entry.bits := bits (table_level - 1);
273 new_entry.extra_bits := 16 + j;
274 new_entry.next_table := current_table_ptr;
275
276 j := Integer (
277 Shift_Right (Unsigned_32 (i) and
278 (Shift_Left (Unsigned_32'(1), w) - 1),
279 w - bits (table_level - 1))
280 );
281
282 -- Test against bad input!
283
284 if j > u (table_level - 1)'Last then
285 raise huft_error;
286 end if;
287 u (table_level - 1) (j) := new_entry;
288 end if;
289
290 end loop;
291
292 -- Set up table entry in new_entry
293
294 new_entry.bits := k - w;
295 new_entry.next_table := null; -- Unused
296
297 if v_idx >= b'Length then
298 new_entry.extra_bits := invalid;
299 else
300 el_v := v (v_idx);
301 el_v_m_s := el_v - s;
302 if el_v_m_s < 0 then -- Simple code, raw value
303 if el_v < 256 then
304 new_entry.extra_bits := 16;
305 else
306 new_entry.extra_bits := 15;
307 end if;
308 new_entry.n := el_v;
309 else -- Non-simple -> lookup in lists
310 if no_copy_length_array then
311 raise huft_error;
312 end if;
313 new_entry.extra_bits := e (el_v_m_s);
314 new_entry.n := d (el_v_m_s);
315 end if;
316 v_idx := v_idx + 1;
317 end if;
318
319 -- fill code-like entries with new_entry
320 f := Integer (Shift_Left (Unsigned_32'(1), k - w));
321 -- i.e. f := 2 ** (k-w);
322 j := Integer (Shift_Right (Unsigned_32 (i), w));
323 while j < z loop
324 current_table_ptr (j) := new_entry;
325 j := j + f;
326 end loop;
327
328 -- backwards increment the k-bit code i
329 j := Integer (Shift_Left (Unsigned_32'(1), k - 1));
330 -- i.e.: j:= 2 ** (k-1)
331 while (Unsigned_32 (i) and Unsigned_32 (j)) /= 0 loop
332 i := Integer (Unsigned_32 (i) xor Unsigned_32 (j));
333 j := j / 2;
334 end loop;
335 i := Integer (Unsigned_32 (i) xor Unsigned_32 (j));
336
337 -- backup over finished tables
338 while
339 Integer (Unsigned_32 (i) and (Shift_Left (1, w) - 1)) /=
340 code_stack (table_level)
341 loop
342 table_level := table_level - 1;
343 w := w - bits (table_level); -- Size of previous table!
344 end loop;
345
346 end loop; -- am1
347 end loop; -- k
348
349 if full_trace then
350 Ada.Text_IO.Put_Line ("finished]");
351 end if;
352
353 huft_incomplete := y /= 0 and g /= 1;
354
355 exception
356 when others =>
357 HufT_free (tl);
358 raise;
359 end HufT_build;
360
361 end UnZip.Decompress.Huffman;
Web view of Ada source code generated by GNATHTML, project: ALI_Parse version 1.0.
Zip-Ada: Ada library for zip archive files (.zip).
Ada programming.
Some news about Zip-Ada and other Ada projects
on Gautier's blog.