1 |
---------------------------------------------------------------- |
2 |
-- ZLib for Ada thick binding. -- |
3 |
-- -- |
4 |
-- Copyright (C) 2002-2004 Dmitriy Anisimkov -- |
5 |
-- -- |
6 |
-- Open source license information is in the zlib.ads file. -- |
7 |
---------------------------------------------------------------- |
8 |
|
9 |
-- $Id: zlib.adb,v 1.31 2004/09/06 06:53:19 vagul Exp $ |
10 |
|
11 |
with Ada.Exceptions; |
12 |
with Ada.Unchecked_Conversion; |
13 |
with Ada.Unchecked_Deallocation; |
14 |
|
15 |
with Interfaces.C.Strings; |
16 |
|
17 |
with ZLib.Thin; |
18 |
|
19 |
package body ZLib is |
20 |
|
21 |
use type Thin.Int; |
22 |
|
23 |
type Z_Stream is new Thin.Z_Stream; |
24 |
|
25 |
type Return_Code_Enum is |
26 |
(OK, |
27 |
STREAM_END, |
28 |
NEED_DICT, |
29 |
ERRNO, |
30 |
STREAM_ERROR, |
31 |
DATA_ERROR, |
32 |
MEM_ERROR, |
33 |
BUF_ERROR, |
34 |
VERSION_ERROR); |
35 |
|
36 |
type Flate_Step_Function is access |
37 |
function (Strm : in Thin.Z_Streamp; Flush : in Thin.Int) return Thin.Int; |
38 |
pragma Convention (C, Flate_Step_Function); |
39 |
|
40 |
type Flate_End_Function is access |
41 |
function (Ctrm : in Thin.Z_Streamp) return Thin.Int; |
42 |
pragma Convention (C, Flate_End_Function); |
43 |
|
44 |
type Flate_Type is record |
45 |
Step : Flate_Step_Function; |
46 |
Done : Flate_End_Function; |
47 |
end record; |
48 |
|
49 |
subtype Footer_Array is Stream_Element_Array (1 .. 8); |
50 |
|
51 |
Simple_GZip_Header : constant Stream_Element_Array (1 .. 10) |
52 |
:= (16#1f#, 16#8b#, -- Magic header |
53 |
16#08#, -- Z_DEFLATED |
54 |
16#00#, -- Flags |
55 |
16#00#, 16#00#, 16#00#, 16#00#, -- Time |
56 |
16#00#, -- XFlags |
57 |
16#03# -- OS code |
58 |
); |
59 |
-- The simplest gzip header is not for informational, but just for |
60 |
-- gzip format compatibility. |
61 |
-- Note that some code below is using assumption |
62 |
-- Simple_GZip_Header'Last > Footer_Array'Last, so do not make |
63 |
-- Simple_GZip_Header'Last <= Footer_Array'Last. |
64 |
|
65 |
Return_Code : constant array (Thin.Int range <>) of Return_Code_Enum |
66 |
:= (0 => OK, |
67 |
1 => STREAM_END, |
68 |
2 => NEED_DICT, |
69 |
-1 => ERRNO, |
70 |
-2 => STREAM_ERROR, |
71 |
-3 => DATA_ERROR, |
72 |
-4 => MEM_ERROR, |
73 |
-5 => BUF_ERROR, |
74 |
-6 => VERSION_ERROR); |
75 |
|
76 |
Flate : constant array (Boolean) of Flate_Type |
77 |
:= (True => (Step => Thin.Deflate'Access, |
78 |
Done => Thin.DeflateEnd'Access), |
79 |
False => (Step => Thin.Inflate'Access, |
80 |
Done => Thin.InflateEnd'Access)); |
81 |
|
82 |
Flush_Finish : constant array (Boolean) of Flush_Mode |
83 |
:= (True => Finish, False => No_Flush); |
84 |
|
85 |
procedure Raise_Error (Stream : in Z_Stream); |
86 |
pragma Inline (Raise_Error); |
87 |
|
88 |
procedure Raise_Error (Message : in String); |
89 |
pragma Inline (Raise_Error); |
90 |
|
91 |
procedure Check_Error (Stream : in Z_Stream; Code : in Thin.Int); |
92 |
|
93 |
procedure Free is new Ada.Unchecked_Deallocation |
94 |
(Z_Stream, Z_Stream_Access); |
95 |
|
96 |
function To_Thin_Access is new Ada.Unchecked_Conversion |
97 |
(Z_Stream_Access, Thin.Z_Streamp); |
98 |
|
99 |
procedure Translate_GZip |
100 |
(Filter : in out Filter_Type; |
101 |
In_Data : in Ada.Streams.Stream_Element_Array; |
102 |
In_Last : out Ada.Streams.Stream_Element_Offset; |
103 |
Out_Data : out Ada.Streams.Stream_Element_Array; |
104 |
Out_Last : out Ada.Streams.Stream_Element_Offset; |
105 |
Flush : in Flush_Mode); |
106 |
-- Separate translate routine for make gzip header. |
107 |
|
108 |
procedure Translate_Auto |
109 |
(Filter : in out Filter_Type; |
110 |
In_Data : in Ada.Streams.Stream_Element_Array; |
111 |
In_Last : out Ada.Streams.Stream_Element_Offset; |
112 |
Out_Data : out Ada.Streams.Stream_Element_Array; |
113 |
Out_Last : out Ada.Streams.Stream_Element_Offset; |
114 |
Flush : in Flush_Mode); |
115 |
-- translate routine without additional headers. |
116 |
|
117 |
----------------- |
118 |
-- Check_Error -- |
119 |
----------------- |
120 |
|
121 |
procedure Check_Error (Stream : in Z_Stream; Code : in Thin.Int) is |
122 |
use type Thin.Int; |
123 |
begin |
124 |
if Code /= Thin.Z_OK then |
125 |
Raise_Error |
126 |
(Return_Code_Enum'Image (Return_Code (Code)) |
127 |
& ": " & Last_Error_Message (Stream)); |
128 |
end if; |
129 |
end Check_Error; |
130 |
|
131 |
----------- |
132 |
-- Close -- |
133 |
----------- |
134 |
|
135 |
procedure Close |
136 |
(Filter : in out Filter_Type; |
137 |
Ignore_Error : in Boolean := False) |
138 |
is |
139 |
Code : Thin.Int; |
140 |
begin |
141 |
if not Ignore_Error and then not Is_Open (Filter) then |
142 |
raise Status_Error; |
143 |
end if; |
144 |
|
145 |
Code := Flate (Filter.Compression).Done (To_Thin_Access (Filter.Strm)); |
146 |
|
147 |
if Ignore_Error or else Code = Thin.Z_OK then |
148 |
Free (Filter.Strm); |
149 |
else |
150 |
declare |
151 |
Error_Message : constant String |
152 |
:= Last_Error_Message (Filter.Strm.all); |
153 |
begin |
154 |
Free (Filter.Strm); |
155 |
Ada.Exceptions.Raise_Exception |
156 |
(ZLib_Error'Identity, |
157 |
Return_Code_Enum'Image (Return_Code (Code)) |
158 |
& ": " & Error_Message); |
159 |
end; |
160 |
end if; |
161 |
end Close; |
162 |
|
163 |
----------- |
164 |
-- CRC32 -- |
165 |
----------- |
166 |
|
167 |
function CRC32 |
168 |
(CRC : in Unsigned_32; |
169 |
Data : in Ada.Streams.Stream_Element_Array) |
170 |
return Unsigned_32 |
171 |
is |
172 |
use Thin; |
173 |
begin |
174 |
return Unsigned_32 (crc32 (ULong (CRC), |
175 |
Data'Address, |
176 |
Data'Length)); |
177 |
end CRC32; |
178 |
|
179 |
procedure CRC32 |
180 |
(CRC : in out Unsigned_32; |
181 |
Data : in Ada.Streams.Stream_Element_Array) is |
182 |
begin |
183 |
CRC := CRC32 (CRC, Data); |
184 |
end CRC32; |
185 |
|
186 |
------------------ |
187 |
-- Deflate_Init -- |
188 |
------------------ |
189 |
|
190 |
procedure Deflate_Init |
191 |
(Filter : in out Filter_Type; |
192 |
Level : in Compression_Level := Default_Compression; |
193 |
Strategy : in Strategy_Type := Default_Strategy; |
194 |
Method : in Compression_Method := Deflated; |
195 |
Window_Bits : in Window_Bits_Type := Default_Window_Bits; |
196 |
Memory_Level : in Memory_Level_Type := Default_Memory_Level; |
197 |
Header : in Header_Type := Default) |
198 |
is |
199 |
use type Thin.Int; |
200 |
Win_Bits : Thin.Int := Thin.Int (Window_Bits); |
201 |
begin |
202 |
if Is_Open (Filter) then |
203 |
raise Status_Error; |
204 |
end if; |
205 |
|
206 |
-- We allow ZLib to make header only in case of default header type. |
207 |
-- Otherwise we would either do header by ourselfs, or do not do |
208 |
-- header at all. |
209 |
|
210 |
if Header = None or else Header = GZip then |
211 |
Win_Bits := -Win_Bits; |
212 |
end if; |
213 |
|
214 |
-- For the GZip CRC calculation and make headers. |
215 |
|
216 |
if Header = GZip then |
217 |
Filter.CRC := 0; |
218 |
Filter.Offset := Simple_GZip_Header'First; |
219 |
else |
220 |
Filter.Offset := Simple_GZip_Header'Last + 1; |
221 |
end if; |
222 |
|
223 |
Filter.Strm := new Z_Stream; |
224 |
Filter.Compression := True; |
225 |
Filter.Stream_End := False; |
226 |
Filter.Header := Header; |
227 |
|
228 |
if Thin.Deflate_Init |
229 |
(To_Thin_Access (Filter.Strm), |
230 |
Level => Thin.Int (Level), |
231 |
method => Thin.Int (Method), |
232 |
windowBits => Win_Bits, |
233 |
memLevel => Thin.Int (Memory_Level), |
234 |
strategy => Thin.Int (Strategy)) /= Thin.Z_OK |
235 |
then |
236 |
Raise_Error (Filter.Strm.all); |
237 |
end if; |
238 |
end Deflate_Init; |
239 |
|
240 |
----------- |
241 |
-- Flush -- |
242 |
----------- |
243 |
|
244 |
procedure Flush |
245 |
(Filter : in out Filter_Type; |
246 |
Out_Data : out Ada.Streams.Stream_Element_Array; |
247 |
Out_Last : out Ada.Streams.Stream_Element_Offset; |
248 |
Flush : in Flush_Mode) |
249 |
is |
250 |
No_Data : Stream_Element_Array := (1 .. 0 => 0); |
251 |
Last : Stream_Element_Offset; |
252 |
begin |
253 |
Translate (Filter, No_Data, Last, Out_Data, Out_Last, Flush); |
254 |
end Flush; |
255 |
|
256 |
----------------------- |
257 |
-- Generic_Translate -- |
258 |
----------------------- |
259 |
|
260 |
procedure Generic_Translate |
261 |
(Filter : in out ZLib.Filter_Type; |
262 |
In_Buffer_Size : in Integer := Default_Buffer_Size; |
263 |
Out_Buffer_Size : in Integer := Default_Buffer_Size) |
264 |
is |
265 |
In_Buffer : Stream_Element_Array |
266 |
(1 .. Stream_Element_Offset (In_Buffer_Size)); |
267 |
Out_Buffer : Stream_Element_Array |
268 |
(1 .. Stream_Element_Offset (Out_Buffer_Size)); |
269 |
Last : Stream_Element_Offset; |
270 |
In_Last : Stream_Element_Offset; |
271 |
In_First : Stream_Element_Offset; |
272 |
Out_Last : Stream_Element_Offset; |
273 |
begin |
274 |
Main : loop |
275 |
Data_In (In_Buffer, Last); |
276 |
|
277 |
In_First := In_Buffer'First; |
278 |
|
279 |
loop |
280 |
Translate |
281 |
(Filter => Filter, |
282 |
In_Data => In_Buffer (In_First .. Last), |
283 |
In_Last => In_Last, |
284 |
Out_Data => Out_Buffer, |
285 |
Out_Last => Out_Last, |
286 |
Flush => Flush_Finish (Last < In_Buffer'First)); |
287 |
|
288 |
if Out_Buffer'First <= Out_Last then |
289 |
Data_Out (Out_Buffer (Out_Buffer'First .. Out_Last)); |
290 |
end if; |
291 |
|
292 |
exit Main when Stream_End (Filter); |
293 |
|
294 |
-- The end of in buffer. |
295 |
|
296 |
exit when In_Last = Last; |
297 |
|
298 |
In_First := In_Last + 1; |
299 |
end loop; |
300 |
end loop Main; |
301 |
|
302 |
end Generic_Translate; |
303 |
|
304 |
------------------ |
305 |
-- Inflate_Init -- |
306 |
------------------ |
307 |
|
308 |
procedure Inflate_Init |
309 |
(Filter : in out Filter_Type; |
310 |
Window_Bits : in Window_Bits_Type := Default_Window_Bits; |
311 |
Header : in Header_Type := Default) |
312 |
is |
313 |
use type Thin.Int; |
314 |
Win_Bits : Thin.Int := Thin.Int (Window_Bits); |
315 |
|
316 |
procedure Check_Version; |
317 |
-- Check the latest header types compatibility. |
318 |
|
319 |
procedure Check_Version is |
320 |
begin |
321 |
if Version <= "1.1.4" then |
322 |
Raise_Error |
323 |
("Inflate header type " & Header_Type'Image (Header) |
324 |
& " incompatible with ZLib version " & Version); |
325 |
end if; |
326 |
end Check_Version; |
327 |
|
328 |
begin |
329 |
if Is_Open (Filter) then |
330 |
raise Status_Error; |
331 |
end if; |
332 |
|
333 |
case Header is |
334 |
when None => |
335 |
Check_Version; |
336 |
|
337 |
-- Inflate data without headers determined |
338 |
-- by negative Win_Bits. |
339 |
|
340 |
Win_Bits := -Win_Bits; |
341 |
when GZip => |
342 |
Check_Version; |
343 |
|
344 |
-- Inflate gzip data defined by flag 16. |
345 |
|
346 |
Win_Bits := Win_Bits + 16; |
347 |
when Auto => |
348 |
Check_Version; |
349 |
|
350 |
-- Inflate with automatic detection |
351 |
-- of gzip or native header defined by flag 32. |
352 |
|
353 |
Win_Bits := Win_Bits + 32; |
354 |
when Default => null; |
355 |
end case; |
356 |
|
357 |
Filter.Strm := new Z_Stream; |
358 |
Filter.Compression := False; |
359 |
Filter.Stream_End := False; |
360 |
Filter.Header := Header; |
361 |
|
362 |
if Thin.Inflate_Init |
363 |
(To_Thin_Access (Filter.Strm), Win_Bits) /= Thin.Z_OK |
364 |
then |
365 |
Raise_Error (Filter.Strm.all); |
366 |
end if; |
367 |
end Inflate_Init; |
368 |
|
369 |
------------- |
370 |
-- Is_Open -- |
371 |
------------- |
372 |
|
373 |
function Is_Open (Filter : in Filter_Type) return Boolean is |
374 |
begin |
375 |
return Filter.Strm /= null; |
376 |
end Is_Open; |
377 |
|
378 |
----------------- |
379 |
-- Raise_Error -- |
380 |
----------------- |
381 |
|
382 |
procedure Raise_Error (Message : in String) is |
383 |
begin |
384 |
Ada.Exceptions.Raise_Exception (ZLib_Error'Identity, Message); |
385 |
end Raise_Error; |
386 |
|
387 |
procedure Raise_Error (Stream : in Z_Stream) is |
388 |
begin |
389 |
Raise_Error (Last_Error_Message (Stream)); |
390 |
end Raise_Error; |
391 |
|
392 |
---------- |
393 |
-- Read -- |
394 |
---------- |
395 |
|
396 |
procedure Read |
397 |
(Filter : in out Filter_Type; |
398 |
Item : out Ada.Streams.Stream_Element_Array; |
399 |
Last : out Ada.Streams.Stream_Element_Offset; |
400 |
Flush : in Flush_Mode := No_Flush) |
401 |
is |
402 |
In_Last : Stream_Element_Offset; |
403 |
Item_First : Ada.Streams.Stream_Element_Offset := Item'First; |
404 |
V_Flush : Flush_Mode := Flush; |
405 |
|
406 |
begin |
407 |
pragma Assert (Rest_First in Buffer'First .. Buffer'Last + 1); |
408 |
pragma Assert (Rest_Last in Buffer'First - 1 .. Buffer'Last); |
409 |
|
410 |
loop |
411 |
if Rest_Last = Buffer'First - 1 then |
412 |
V_Flush := Finish; |
413 |
|
414 |
elsif Rest_First > Rest_Last then |
415 |
Read (Buffer, Rest_Last); |
416 |
Rest_First := Buffer'First; |
417 |
|
418 |
if Rest_Last < Buffer'First then |
419 |
V_Flush := Finish; |
420 |
end if; |
421 |
end if; |
422 |
|
423 |
Translate |
424 |
(Filter => Filter, |
425 |
In_Data => Buffer (Rest_First .. Rest_Last), |
426 |
In_Last => In_Last, |
427 |
Out_Data => Item (Item_First .. Item'Last), |
428 |
Out_Last => Last, |
429 |
Flush => V_Flush); |
430 |
|
431 |
Rest_First := In_Last + 1; |
432 |
|
433 |
exit when Stream_End (Filter) |
434 |
or else Last = Item'Last |
435 |
or else (Last >= Item'First and then Allow_Read_Some); |
436 |
|
437 |
Item_First := Last + 1; |
438 |
end loop; |
439 |
end Read; |
440 |
|
441 |
---------------- |
442 |
-- Stream_End -- |
443 |
---------------- |
444 |
|
445 |
function Stream_End (Filter : in Filter_Type) return Boolean is |
446 |
begin |
447 |
if Filter.Header = GZip and Filter.Compression then |
448 |
return Filter.Stream_End |
449 |
and then Filter.Offset = Footer_Array'Last + 1; |
450 |
else |
451 |
return Filter.Stream_End; |
452 |
end if; |
453 |
end Stream_End; |
454 |
|
455 |
-------------- |
456 |
-- Total_In -- |
457 |
-------------- |
458 |
|
459 |
function Total_In (Filter : in Filter_Type) return Count is |
460 |
begin |
461 |
return Count (Thin.Total_In (To_Thin_Access (Filter.Strm).all)); |
462 |
end Total_In; |
463 |
|
464 |
--------------- |
465 |
-- Total_Out -- |
466 |
--------------- |
467 |
|
468 |
function Total_Out (Filter : in Filter_Type) return Count is |
469 |
begin |
470 |
return Count (Thin.Total_Out (To_Thin_Access (Filter.Strm).all)); |
471 |
end Total_Out; |
472 |
|
473 |
--------------- |
474 |
-- Translate -- |
475 |
--------------- |
476 |
|
477 |
procedure Translate |
478 |
(Filter : in out Filter_Type; |
479 |
In_Data : in Ada.Streams.Stream_Element_Array; |
480 |
In_Last : out Ada.Streams.Stream_Element_Offset; |
481 |
Out_Data : out Ada.Streams.Stream_Element_Array; |
482 |
Out_Last : out Ada.Streams.Stream_Element_Offset; |
483 |
Flush : in Flush_Mode) is |
484 |
begin |
485 |
if Filter.Header = GZip and then Filter.Compression then |
486 |
Translate_GZip |
487 |
(Filter => Filter, |
488 |
In_Data => In_Data, |
489 |
In_Last => In_Last, |
490 |
Out_Data => Out_Data, |
491 |
Out_Last => Out_Last, |
492 |
Flush => Flush); |
493 |
else |
494 |
Translate_Auto |
495 |
(Filter => Filter, |
496 |
In_Data => In_Data, |
497 |
In_Last => In_Last, |
498 |
Out_Data => Out_Data, |
499 |
Out_Last => Out_Last, |
500 |
Flush => Flush); |
501 |
end if; |
502 |
end Translate; |
503 |
|
504 |
-------------------- |
505 |
-- Translate_Auto -- |
506 |
-------------------- |
507 |
|
508 |
procedure Translate_Auto |
509 |
(Filter : in out Filter_Type; |
510 |
In_Data : in Ada.Streams.Stream_Element_Array; |
511 |
In_Last : out Ada.Streams.Stream_Element_Offset; |
512 |
Out_Data : out Ada.Streams.Stream_Element_Array; |
513 |
Out_Last : out Ada.Streams.Stream_Element_Offset; |
514 |
Flush : in Flush_Mode) |
515 |
is |
516 |
use type Thin.Int; |
517 |
Code : Thin.Int; |
518 |
|
519 |
begin |
520 |
if not Is_Open (Filter) then |
521 |
raise Status_Error; |
522 |
end if; |
523 |
|
524 |
if Out_Data'Length = 0 and then In_Data'Length = 0 then |
525 |
raise Constraint_Error; |
526 |
end if; |
527 |
|
528 |
Set_Out (Filter.Strm.all, Out_Data'Address, Out_Data'Length); |
529 |
Set_In (Filter.Strm.all, In_Data'Address, In_Data'Length); |
530 |
|
531 |
Code := Flate (Filter.Compression).Step |
532 |
(To_Thin_Access (Filter.Strm), |
533 |
Thin.Int (Flush)); |
534 |
|
535 |
if Code = Thin.Z_STREAM_END then |
536 |
Filter.Stream_End := True; |
537 |
else |
538 |
Check_Error (Filter.Strm.all, Code); |
539 |
end if; |
540 |
|
541 |
In_Last := In_Data'Last |
542 |
- Stream_Element_Offset (Avail_In (Filter.Strm.all)); |
543 |
Out_Last := Out_Data'Last |
544 |
- Stream_Element_Offset (Avail_Out (Filter.Strm.all)); |
545 |
end Translate_Auto; |
546 |
|
547 |
-------------------- |
548 |
-- Translate_GZip -- |
549 |
-------------------- |
550 |
|
551 |
procedure Translate_GZip |
552 |
(Filter : in out Filter_Type; |
553 |
In_Data : in Ada.Streams.Stream_Element_Array; |
554 |
In_Last : out Ada.Streams.Stream_Element_Offset; |
555 |
Out_Data : out Ada.Streams.Stream_Element_Array; |
556 |
Out_Last : out Ada.Streams.Stream_Element_Offset; |
557 |
Flush : in Flush_Mode) |
558 |
is |
559 |
Out_First : Stream_Element_Offset; |
560 |
|
561 |
procedure Add_Data (Data : in Stream_Element_Array); |
562 |
-- Add data to stream from the Filter.Offset till necessary, |
563 |
-- used for add gzip headr/footer. |
564 |
|
565 |
procedure Put_32 |
566 |
(Item : in out Stream_Element_Array; |
567 |
Data : in Unsigned_32); |
568 |
pragma Inline (Put_32); |
569 |
|
570 |
-------------- |
571 |
-- Add_Data -- |
572 |
-------------- |
573 |
|
574 |
procedure Add_Data (Data : in Stream_Element_Array) is |
575 |
Data_First : Stream_Element_Offset renames Filter.Offset; |
576 |
Data_Last : Stream_Element_Offset; |
577 |
Data_Len : Stream_Element_Offset; -- -1 |
578 |
Out_Len : Stream_Element_Offset; -- -1 |
579 |
begin |
580 |
Out_First := Out_Last + 1; |
581 |
|
582 |
if Data_First > Data'Last then |
583 |
return; |
584 |
end if; |
585 |
|
586 |
Data_Len := Data'Last - Data_First; |
587 |
Out_Len := Out_Data'Last - Out_First; |
588 |
|
589 |
if Data_Len <= Out_Len then |
590 |
Out_Last := Out_First + Data_Len; |
591 |
Data_Last := Data'Last; |
592 |
else |
593 |
Out_Last := Out_Data'Last; |
594 |
Data_Last := Data_First + Out_Len; |
595 |
end if; |
596 |
|
597 |
Out_Data (Out_First .. Out_Last) := Data (Data_First .. Data_Last); |
598 |
|
599 |
Data_First := Data_Last + 1; |
600 |
Out_First := Out_Last + 1; |
601 |
end Add_Data; |
602 |
|
603 |
------------ |
604 |
-- Put_32 -- |
605 |
------------ |
606 |
|
607 |
procedure Put_32 |
608 |
(Item : in out Stream_Element_Array; |
609 |
Data : in Unsigned_32) |
610 |
is |
611 |
D : Unsigned_32 := Data; |
612 |
begin |
613 |
for J in Item'First .. Item'First + 3 loop |
614 |
Item (J) := Stream_Element (D and 16#FF#); |
615 |
D := Shift_Right (D, 8); |
616 |
end loop; |
617 |
end Put_32; |
618 |
|
619 |
begin |
620 |
Out_Last := Out_Data'First - 1; |
621 |
|
622 |
if not Filter.Stream_End then |
623 |
Add_Data (Simple_GZip_Header); |
624 |
|
625 |
Translate_Auto |
626 |
(Filter => Filter, |
627 |
In_Data => In_Data, |
628 |
In_Last => In_Last, |
629 |
Out_Data => Out_Data (Out_First .. Out_Data'Last), |
630 |
Out_Last => Out_Last, |
631 |
Flush => Flush); |
632 |
|
633 |
CRC32 (Filter.CRC, In_Data (In_Data'First .. In_Last)); |
634 |
end if; |
635 |
|
636 |
if Filter.Stream_End and then Out_Last <= Out_Data'Last then |
637 |
-- This detection method would work only when |
638 |
-- Simple_GZip_Header'Last > Footer_Array'Last |
639 |
|
640 |
if Filter.Offset = Simple_GZip_Header'Last + 1 then |
641 |
Filter.Offset := Footer_Array'First; |
642 |
end if; |
643 |
|
644 |
declare |
645 |
Footer : Footer_Array; |
646 |
begin |
647 |
Put_32 (Footer, Filter.CRC); |
648 |
Put_32 (Footer (Footer'First + 4 .. Footer'Last), |
649 |
Unsigned_32 (Total_In (Filter))); |
650 |
Add_Data (Footer); |
651 |
end; |
652 |
end if; |
653 |
end Translate_GZip; |
654 |
|
655 |
------------- |
656 |
-- Version -- |
657 |
------------- |
658 |
|
659 |
function Version return String is |
660 |
begin |
661 |
return Interfaces.C.Strings.Value (Thin.zlibVersion); |
662 |
end Version; |
663 |
|
664 |
----------- |
665 |
-- Write -- |
666 |
----------- |
667 |
|
668 |
procedure Write |
669 |
(Filter : in out Filter_Type; |
670 |
Item : in Ada.Streams.Stream_Element_Array; |
671 |
Flush : in Flush_Mode := No_Flush) |
672 |
is |
673 |
Buffer : Stream_Element_Array (1 .. Buffer_Size); |
674 |
In_Last : Stream_Element_Offset; |
675 |
Out_Last : Stream_Element_Offset; |
676 |
In_First : Stream_Element_Offset := Item'First; |
677 |
begin |
678 |
if Item'Length = 0 and Flush = No_Flush then |
679 |
return; |
680 |
end if; |
681 |
|
682 |
loop |
683 |
Translate |
684 |
(Filter => Filter, |
685 |
In_Data => Item (In_First .. Item'Last), |
686 |
In_Last => In_Last, |
687 |
Out_Data => Buffer, |
688 |
Out_Last => Out_Last, |
689 |
Flush => Flush); |
690 |
|
691 |
if Out_Last >= Buffer'First then |
692 |
Write (Buffer (1 .. Out_Last)); |
693 |
end if; |
694 |
|
695 |
exit when In_Last = Item'Last or Stream_End (Filter); |
696 |
|
697 |
In_First := In_Last + 1; |
698 |
end loop; |
699 |
end Write; |
700 |
|
701 |
end ZLib; |