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