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