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