|  | ---------------------------------------------------------------- | 
|  | --  ZLib for Ada thick binding.                               -- | 
|  | --                                                            -- | 
|  | --  Copyright (C) 2002-2004 Dmitriy Anisimkov                 -- | 
|  | --                                                            -- | 
|  | --  Open source license information is in the zlib.ads file.  -- | 
|  | ---------------------------------------------------------------- | 
|  |  | 
|  | --  $Id: zlib.adb,v 1.31 2004/09/06 06:53:19 vagul Exp $ | 
|  |  | 
|  | with Ada.Exceptions; | 
|  | with Ada.Unchecked_Conversion; | 
|  | with Ada.Unchecked_Deallocation; | 
|  |  | 
|  | with Interfaces.C.Strings; | 
|  |  | 
|  | with ZLib.Thin; | 
|  |  | 
|  | package body ZLib is | 
|  |  | 
|  | use type Thin.Int; | 
|  |  | 
|  | type Z_Stream is new Thin.Z_Stream; | 
|  |  | 
|  | type Return_Code_Enum is | 
|  | (OK, | 
|  | STREAM_END, | 
|  | NEED_DICT, | 
|  | ERRNO, | 
|  | STREAM_ERROR, | 
|  | DATA_ERROR, | 
|  | MEM_ERROR, | 
|  | BUF_ERROR, | 
|  | VERSION_ERROR); | 
|  |  | 
|  | type Flate_Step_Function is access | 
|  | function (Strm : in Thin.Z_Streamp; Flush : in Thin.Int) return Thin.Int; | 
|  | pragma Convention (C, Flate_Step_Function); | 
|  |  | 
|  | type Flate_End_Function is access | 
|  | function (Ctrm : in Thin.Z_Streamp) return Thin.Int; | 
|  | pragma Convention (C, Flate_End_Function); | 
|  |  | 
|  | type Flate_Type is record | 
|  | Step : Flate_Step_Function; | 
|  | Done : Flate_End_Function; | 
|  | end record; | 
|  |  | 
|  | subtype Footer_Array is Stream_Element_Array (1 .. 8); | 
|  |  | 
|  | Simple_GZip_Header : constant Stream_Element_Array (1 .. 10) | 
|  | := (16#1f#, 16#8b#,                 --  Magic header | 
|  | 16#08#,                         --  Z_DEFLATED | 
|  | 16#00#,                         --  Flags | 
|  | 16#00#, 16#00#, 16#00#, 16#00#, --  Time | 
|  | 16#00#,                         --  XFlags | 
|  | 16#03#                          --  OS code | 
|  | ); | 
|  | --  The simplest gzip header is not for informational, but just for | 
|  | --  gzip format compatibility. | 
|  | --  Note that some code below is using assumption | 
|  | --  Simple_GZip_Header'Last > Footer_Array'Last, so do not make | 
|  | --  Simple_GZip_Header'Last <= Footer_Array'Last. | 
|  |  | 
|  | Return_Code : constant array (Thin.Int range <>) of Return_Code_Enum | 
|  | := (0 => OK, | 
|  | 1 => STREAM_END, | 
|  | 2 => NEED_DICT, | 
|  | -1 => ERRNO, | 
|  | -2 => STREAM_ERROR, | 
|  | -3 => DATA_ERROR, | 
|  | -4 => MEM_ERROR, | 
|  | -5 => BUF_ERROR, | 
|  | -6 => VERSION_ERROR); | 
|  |  | 
|  | Flate : constant array (Boolean) of Flate_Type | 
|  | := (True  => (Step => Thin.Deflate'Access, | 
|  | Done => Thin.DeflateEnd'Access), | 
|  | False => (Step => Thin.Inflate'Access, | 
|  | Done => Thin.InflateEnd'Access)); | 
|  |  | 
|  | Flush_Finish : constant array (Boolean) of Flush_Mode | 
|  | := (True => Finish, False => No_Flush); | 
|  |  | 
|  | procedure Raise_Error (Stream : in Z_Stream); | 
|  | pragma Inline (Raise_Error); | 
|  |  | 
|  | procedure Raise_Error (Message : in String); | 
|  | pragma Inline (Raise_Error); | 
|  |  | 
|  | procedure Check_Error (Stream : in Z_Stream; Code : in Thin.Int); | 
|  |  | 
|  | procedure Free is new Ada.Unchecked_Deallocation | 
|  | (Z_Stream, Z_Stream_Access); | 
|  |  | 
|  | function To_Thin_Access is new Ada.Unchecked_Conversion | 
|  | (Z_Stream_Access, Thin.Z_Streamp); | 
|  |  | 
|  | procedure Translate_GZip | 
|  | (Filter    : in out Filter_Type; | 
|  | In_Data   : in     Ada.Streams.Stream_Element_Array; | 
|  | In_Last   :    out Ada.Streams.Stream_Element_Offset; | 
|  | Out_Data  :    out Ada.Streams.Stream_Element_Array; | 
|  | Out_Last  :    out Ada.Streams.Stream_Element_Offset; | 
|  | Flush     : in     Flush_Mode); | 
|  | --  Separate translate routine for make gzip header. | 
|  |  | 
|  | procedure Translate_Auto | 
|  | (Filter    : in out Filter_Type; | 
|  | In_Data   : in     Ada.Streams.Stream_Element_Array; | 
|  | In_Last   :    out Ada.Streams.Stream_Element_Offset; | 
|  | Out_Data  :    out Ada.Streams.Stream_Element_Array; | 
|  | Out_Last  :    out Ada.Streams.Stream_Element_Offset; | 
|  | Flush     : in     Flush_Mode); | 
|  | --  translate routine without additional headers. | 
|  |  | 
|  | ----------------- | 
|  | -- Check_Error -- | 
|  | ----------------- | 
|  |  | 
|  | procedure Check_Error (Stream : in Z_Stream; Code : in Thin.Int) is | 
|  | use type Thin.Int; | 
|  | begin | 
|  | if Code /= Thin.Z_OK then | 
|  | Raise_Error | 
|  | (Return_Code_Enum'Image (Return_Code (Code)) | 
|  | & ": " & Last_Error_Message (Stream)); | 
|  | end if; | 
|  | end Check_Error; | 
|  |  | 
|  | ----------- | 
|  | -- Close -- | 
|  | ----------- | 
|  |  | 
|  | procedure Close | 
|  | (Filter       : in out Filter_Type; | 
|  | Ignore_Error : in     Boolean := False) | 
|  | is | 
|  | Code : Thin.Int; | 
|  | begin | 
|  | if not Ignore_Error and then not Is_Open (Filter) then | 
|  | raise Status_Error; | 
|  | end if; | 
|  |  | 
|  | Code := Flate (Filter.Compression).Done (To_Thin_Access (Filter.Strm)); | 
|  |  | 
|  | if Ignore_Error or else Code = Thin.Z_OK then | 
|  | Free (Filter.Strm); | 
|  | else | 
|  | declare | 
|  | Error_Message : constant String | 
|  | := Last_Error_Message (Filter.Strm.all); | 
|  | begin | 
|  | Free (Filter.Strm); | 
|  | Ada.Exceptions.Raise_Exception | 
|  | (ZLib_Error'Identity, | 
|  | Return_Code_Enum'Image (Return_Code (Code)) | 
|  | & ": " & Error_Message); | 
|  | end; | 
|  | end if; | 
|  | end Close; | 
|  |  | 
|  | ----------- | 
|  | -- CRC32 -- | 
|  | ----------- | 
|  |  | 
|  | function CRC32 | 
|  | (CRC  : in Unsigned_32; | 
|  | Data : in Ada.Streams.Stream_Element_Array) | 
|  | return Unsigned_32 | 
|  | is | 
|  | use Thin; | 
|  | begin | 
|  | return Unsigned_32 (crc32 (ULong (CRC), | 
|  | Data'Address, | 
|  | Data'Length)); | 
|  | end CRC32; | 
|  |  | 
|  | procedure CRC32 | 
|  | (CRC  : in out Unsigned_32; | 
|  | Data : in     Ada.Streams.Stream_Element_Array) is | 
|  | begin | 
|  | CRC := CRC32 (CRC, Data); | 
|  | end CRC32; | 
|  |  | 
|  | ------------------ | 
|  | -- Deflate_Init -- | 
|  | ------------------ | 
|  |  | 
|  | procedure Deflate_Init | 
|  | (Filter       : in out Filter_Type; | 
|  | Level        : in     Compression_Level  := Default_Compression; | 
|  | Strategy     : in     Strategy_Type      := Default_Strategy; | 
|  | Method       : in     Compression_Method := Deflated; | 
|  | Window_Bits  : in     Window_Bits_Type   := Default_Window_Bits; | 
|  | Memory_Level : in     Memory_Level_Type  := Default_Memory_Level; | 
|  | Header       : in     Header_Type        := Default) | 
|  | is | 
|  | use type Thin.Int; | 
|  | Win_Bits : Thin.Int := Thin.Int (Window_Bits); | 
|  | begin | 
|  | if Is_Open (Filter) then | 
|  | raise Status_Error; | 
|  | end if; | 
|  |  | 
|  | --  We allow ZLib to make header only in case of default header type. | 
|  | --  Otherwise we would either do header by ourselfs, or do not do | 
|  | --  header at all. | 
|  |  | 
|  | if Header = None or else Header = GZip then | 
|  | Win_Bits := -Win_Bits; | 
|  | end if; | 
|  |  | 
|  | --  For the GZip CRC calculation and make headers. | 
|  |  | 
|  | if Header = GZip then | 
|  | Filter.CRC    := 0; | 
|  | Filter.Offset := Simple_GZip_Header'First; | 
|  | else | 
|  | Filter.Offset := Simple_GZip_Header'Last + 1; | 
|  | end if; | 
|  |  | 
|  | Filter.Strm        := new Z_Stream; | 
|  | Filter.Compression := True; | 
|  | Filter.Stream_End  := False; | 
|  | Filter.Header      := Header; | 
|  |  | 
|  | if Thin.Deflate_Init | 
|  | (To_Thin_Access (Filter.Strm), | 
|  | Level      => Thin.Int (Level), | 
|  | method     => Thin.Int (Method), | 
|  | windowBits => Win_Bits, | 
|  | memLevel   => Thin.Int (Memory_Level), | 
|  | strategy   => Thin.Int (Strategy)) /= Thin.Z_OK | 
|  | then | 
|  | Raise_Error (Filter.Strm.all); | 
|  | end if; | 
|  | end Deflate_Init; | 
|  |  | 
|  | ----------- | 
|  | -- Flush -- | 
|  | ----------- | 
|  |  | 
|  | procedure Flush | 
|  | (Filter    : in out Filter_Type; | 
|  | Out_Data  :    out Ada.Streams.Stream_Element_Array; | 
|  | Out_Last  :    out Ada.Streams.Stream_Element_Offset; | 
|  | Flush     : in     Flush_Mode) | 
|  | is | 
|  | No_Data : Stream_Element_Array := (1 .. 0 => 0); | 
|  | Last    : Stream_Element_Offset; | 
|  | begin | 
|  | Translate (Filter, No_Data, Last, Out_Data, Out_Last, Flush); | 
|  | end Flush; | 
|  |  | 
|  | ----------------------- | 
|  | -- Generic_Translate -- | 
|  | ----------------------- | 
|  |  | 
|  | procedure Generic_Translate | 
|  | (Filter          : in out ZLib.Filter_Type; | 
|  | In_Buffer_Size  : in     Integer := Default_Buffer_Size; | 
|  | Out_Buffer_Size : in     Integer := Default_Buffer_Size) | 
|  | is | 
|  | In_Buffer  : Stream_Element_Array | 
|  | (1 .. Stream_Element_Offset (In_Buffer_Size)); | 
|  | Out_Buffer : Stream_Element_Array | 
|  | (1 .. Stream_Element_Offset (Out_Buffer_Size)); | 
|  | Last       : Stream_Element_Offset; | 
|  | In_Last    : Stream_Element_Offset; | 
|  | In_First   : Stream_Element_Offset; | 
|  | Out_Last   : Stream_Element_Offset; | 
|  | begin | 
|  | Main : loop | 
|  | Data_In (In_Buffer, Last); | 
|  |  | 
|  | In_First := In_Buffer'First; | 
|  |  | 
|  | loop | 
|  | Translate | 
|  | (Filter   => Filter, | 
|  | In_Data  => In_Buffer (In_First .. Last), | 
|  | In_Last  => In_Last, | 
|  | Out_Data => Out_Buffer, | 
|  | Out_Last => Out_Last, | 
|  | Flush    => Flush_Finish (Last < In_Buffer'First)); | 
|  |  | 
|  | if Out_Buffer'First <= Out_Last then | 
|  | Data_Out (Out_Buffer (Out_Buffer'First .. Out_Last)); | 
|  | end if; | 
|  |  | 
|  | exit Main when Stream_End (Filter); | 
|  |  | 
|  | --  The end of in buffer. | 
|  |  | 
|  | exit when In_Last = Last; | 
|  |  | 
|  | In_First := In_Last + 1; | 
|  | end loop; | 
|  | end loop Main; | 
|  |  | 
|  | end Generic_Translate; | 
|  |  | 
|  | ------------------ | 
|  | -- Inflate_Init -- | 
|  | ------------------ | 
|  |  | 
|  | procedure Inflate_Init | 
|  | (Filter      : in out Filter_Type; | 
|  | Window_Bits : in     Window_Bits_Type := Default_Window_Bits; | 
|  | Header      : in     Header_Type      := Default) | 
|  | is | 
|  | use type Thin.Int; | 
|  | Win_Bits : Thin.Int := Thin.Int (Window_Bits); | 
|  |  | 
|  | procedure Check_Version; | 
|  | --  Check the latest header types compatibility. | 
|  |  | 
|  | procedure Check_Version is | 
|  | begin | 
|  | if Version <= "1.1.4" then | 
|  | Raise_Error | 
|  | ("Inflate header type " & Header_Type'Image (Header) | 
|  | & " incompatible with ZLib version " & Version); | 
|  | end if; | 
|  | end Check_Version; | 
|  |  | 
|  | begin | 
|  | if Is_Open (Filter) then | 
|  | raise Status_Error; | 
|  | end if; | 
|  |  | 
|  | case Header is | 
|  | when None => | 
|  | Check_Version; | 
|  |  | 
|  | --  Inflate data without headers determined | 
|  | --  by negative Win_Bits. | 
|  |  | 
|  | Win_Bits := -Win_Bits; | 
|  | when GZip => | 
|  | Check_Version; | 
|  |  | 
|  | --  Inflate gzip data defined by flag 16. | 
|  |  | 
|  | Win_Bits := Win_Bits + 16; | 
|  | when Auto => | 
|  | Check_Version; | 
|  |  | 
|  | --  Inflate with automatic detection | 
|  | --  of gzip or native header defined by flag 32. | 
|  |  | 
|  | Win_Bits := Win_Bits + 32; | 
|  | when Default => null; | 
|  | end case; | 
|  |  | 
|  | Filter.Strm        := new Z_Stream; | 
|  | Filter.Compression := False; | 
|  | Filter.Stream_End  := False; | 
|  | Filter.Header      := Header; | 
|  |  | 
|  | if Thin.Inflate_Init | 
|  | (To_Thin_Access (Filter.Strm), Win_Bits) /= Thin.Z_OK | 
|  | then | 
|  | Raise_Error (Filter.Strm.all); | 
|  | end if; | 
|  | end Inflate_Init; | 
|  |  | 
|  | ------------- | 
|  | -- Is_Open -- | 
|  | ------------- | 
|  |  | 
|  | function Is_Open (Filter : in Filter_Type) return Boolean is | 
|  | begin | 
|  | return Filter.Strm /= null; | 
|  | end Is_Open; | 
|  |  | 
|  | ----------------- | 
|  | -- Raise_Error -- | 
|  | ----------------- | 
|  |  | 
|  | procedure Raise_Error (Message : in String) is | 
|  | begin | 
|  | Ada.Exceptions.Raise_Exception (ZLib_Error'Identity, Message); | 
|  | end Raise_Error; | 
|  |  | 
|  | procedure Raise_Error (Stream : in Z_Stream) is | 
|  | begin | 
|  | Raise_Error (Last_Error_Message (Stream)); | 
|  | end Raise_Error; | 
|  |  | 
|  | ---------- | 
|  | -- Read -- | 
|  | ---------- | 
|  |  | 
|  | procedure Read | 
|  | (Filter : in out Filter_Type; | 
|  | Item   :    out Ada.Streams.Stream_Element_Array; | 
|  | Last   :    out Ada.Streams.Stream_Element_Offset; | 
|  | Flush  : in     Flush_Mode := No_Flush) | 
|  | is | 
|  | In_Last    : Stream_Element_Offset; | 
|  | Item_First : Ada.Streams.Stream_Element_Offset := Item'First; | 
|  | V_Flush    : Flush_Mode := Flush; | 
|  |  | 
|  | begin | 
|  | pragma Assert (Rest_First in Buffer'First .. Buffer'Last + 1); | 
|  | pragma Assert (Rest_Last in Buffer'First - 1 .. Buffer'Last); | 
|  |  | 
|  | loop | 
|  | if Rest_Last = Buffer'First - 1 then | 
|  | V_Flush := Finish; | 
|  |  | 
|  | elsif Rest_First > Rest_Last then | 
|  | Read (Buffer, Rest_Last); | 
|  | Rest_First := Buffer'First; | 
|  |  | 
|  | if Rest_Last < Buffer'First then | 
|  | V_Flush := Finish; | 
|  | end if; | 
|  | end if; | 
|  |  | 
|  | Translate | 
|  | (Filter   => Filter, | 
|  | In_Data  => Buffer (Rest_First .. Rest_Last), | 
|  | In_Last  => In_Last, | 
|  | Out_Data => Item (Item_First .. Item'Last), | 
|  | Out_Last => Last, | 
|  | Flush    => V_Flush); | 
|  |  | 
|  | Rest_First := In_Last + 1; | 
|  |  | 
|  | exit when Stream_End (Filter) | 
|  | or else Last = Item'Last | 
|  | or else (Last >= Item'First and then Allow_Read_Some); | 
|  |  | 
|  | Item_First := Last + 1; | 
|  | end loop; | 
|  | end Read; | 
|  |  | 
|  | ---------------- | 
|  | -- Stream_End -- | 
|  | ---------------- | 
|  |  | 
|  | function Stream_End (Filter : in Filter_Type) return Boolean is | 
|  | begin | 
|  | if Filter.Header = GZip and Filter.Compression then | 
|  | return Filter.Stream_End | 
|  | and then Filter.Offset = Footer_Array'Last + 1; | 
|  | else | 
|  | return Filter.Stream_End; | 
|  | end if; | 
|  | end Stream_End; | 
|  |  | 
|  | -------------- | 
|  | -- Total_In -- | 
|  | -------------- | 
|  |  | 
|  | function Total_In (Filter : in Filter_Type) return Count is | 
|  | begin | 
|  | return Count (Thin.Total_In (To_Thin_Access (Filter.Strm).all)); | 
|  | end Total_In; | 
|  |  | 
|  | --------------- | 
|  | -- Total_Out -- | 
|  | --------------- | 
|  |  | 
|  | function Total_Out (Filter : in Filter_Type) return Count is | 
|  | begin | 
|  | return Count (Thin.Total_Out (To_Thin_Access (Filter.Strm).all)); | 
|  | end Total_Out; | 
|  |  | 
|  | --------------- | 
|  | -- Translate -- | 
|  | --------------- | 
|  |  | 
|  | procedure Translate | 
|  | (Filter    : in out Filter_Type; | 
|  | In_Data   : in     Ada.Streams.Stream_Element_Array; | 
|  | In_Last   :    out Ada.Streams.Stream_Element_Offset; | 
|  | Out_Data  :    out Ada.Streams.Stream_Element_Array; | 
|  | Out_Last  :    out Ada.Streams.Stream_Element_Offset; | 
|  | Flush     : in     Flush_Mode) is | 
|  | begin | 
|  | if Filter.Header = GZip and then Filter.Compression then | 
|  | Translate_GZip | 
|  | (Filter   => Filter, | 
|  | In_Data  => In_Data, | 
|  | In_Last  => In_Last, | 
|  | Out_Data => Out_Data, | 
|  | Out_Last => Out_Last, | 
|  | Flush    => Flush); | 
|  | else | 
|  | Translate_Auto | 
|  | (Filter   => Filter, | 
|  | In_Data  => In_Data, | 
|  | In_Last  => In_Last, | 
|  | Out_Data => Out_Data, | 
|  | Out_Last => Out_Last, | 
|  | Flush    => Flush); | 
|  | end if; | 
|  | end Translate; | 
|  |  | 
|  | -------------------- | 
|  | -- Translate_Auto -- | 
|  | -------------------- | 
|  |  | 
|  | procedure Translate_Auto | 
|  | (Filter    : in out Filter_Type; | 
|  | In_Data   : in     Ada.Streams.Stream_Element_Array; | 
|  | In_Last   :    out Ada.Streams.Stream_Element_Offset; | 
|  | Out_Data  :    out Ada.Streams.Stream_Element_Array; | 
|  | Out_Last  :    out Ada.Streams.Stream_Element_Offset; | 
|  | Flush     : in     Flush_Mode) | 
|  | is | 
|  | use type Thin.Int; | 
|  | Code : Thin.Int; | 
|  |  | 
|  | begin | 
|  | if not Is_Open (Filter) then | 
|  | raise Status_Error; | 
|  | end if; | 
|  |  | 
|  | if Out_Data'Length = 0 and then In_Data'Length = 0 then | 
|  | raise Constraint_Error; | 
|  | end if; | 
|  |  | 
|  | Set_Out (Filter.Strm.all, Out_Data'Address, Out_Data'Length); | 
|  | Set_In  (Filter.Strm.all, In_Data'Address, In_Data'Length); | 
|  |  | 
|  | Code := Flate (Filter.Compression).Step | 
|  | (To_Thin_Access (Filter.Strm), | 
|  | Thin.Int (Flush)); | 
|  |  | 
|  | if Code = Thin.Z_STREAM_END then | 
|  | Filter.Stream_End := True; | 
|  | else | 
|  | Check_Error (Filter.Strm.all, Code); | 
|  | end if; | 
|  |  | 
|  | In_Last  := In_Data'Last | 
|  | - Stream_Element_Offset (Avail_In (Filter.Strm.all)); | 
|  | Out_Last := Out_Data'Last | 
|  | - Stream_Element_Offset (Avail_Out (Filter.Strm.all)); | 
|  | end Translate_Auto; | 
|  |  | 
|  | -------------------- | 
|  | -- Translate_GZip -- | 
|  | -------------------- | 
|  |  | 
|  | procedure Translate_GZip | 
|  | (Filter    : in out Filter_Type; | 
|  | In_Data   : in     Ada.Streams.Stream_Element_Array; | 
|  | In_Last   :    out Ada.Streams.Stream_Element_Offset; | 
|  | Out_Data  :    out Ada.Streams.Stream_Element_Array; | 
|  | Out_Last  :    out Ada.Streams.Stream_Element_Offset; | 
|  | Flush     : in     Flush_Mode) | 
|  | is | 
|  | Out_First : Stream_Element_Offset; | 
|  |  | 
|  | procedure Add_Data (Data : in Stream_Element_Array); | 
|  | --  Add data to stream from the Filter.Offset till necessary, | 
|  | --  used for add gzip headr/footer. | 
|  |  | 
|  | procedure Put_32 | 
|  | (Item : in out Stream_Element_Array; | 
|  | Data : in     Unsigned_32); | 
|  | pragma Inline (Put_32); | 
|  |  | 
|  | -------------- | 
|  | -- Add_Data -- | 
|  | -------------- | 
|  |  | 
|  | procedure Add_Data (Data : in Stream_Element_Array) is | 
|  | Data_First : Stream_Element_Offset renames Filter.Offset; | 
|  | Data_Last  : Stream_Element_Offset; | 
|  | Data_Len   : Stream_Element_Offset; --  -1 | 
|  | Out_Len    : Stream_Element_Offset; --  -1 | 
|  | begin | 
|  | Out_First := Out_Last + 1; | 
|  |  | 
|  | if Data_First > Data'Last then | 
|  | return; | 
|  | end if; | 
|  |  | 
|  | Data_Len  := Data'Last     - Data_First; | 
|  | Out_Len   := Out_Data'Last - Out_First; | 
|  |  | 
|  | if Data_Len <= Out_Len then | 
|  | Out_Last  := Out_First  + Data_Len; | 
|  | Data_Last := Data'Last; | 
|  | else | 
|  | Out_Last  := Out_Data'Last; | 
|  | Data_Last := Data_First + Out_Len; | 
|  | end if; | 
|  |  | 
|  | Out_Data (Out_First .. Out_Last) := Data (Data_First .. Data_Last); | 
|  |  | 
|  | Data_First := Data_Last + 1; | 
|  | Out_First  := Out_Last + 1; | 
|  | end Add_Data; | 
|  |  | 
|  | ------------ | 
|  | -- Put_32 -- | 
|  | ------------ | 
|  |  | 
|  | procedure Put_32 | 
|  | (Item : in out Stream_Element_Array; | 
|  | Data : in     Unsigned_32) | 
|  | is | 
|  | D : Unsigned_32 := Data; | 
|  | begin | 
|  | for J in Item'First .. Item'First + 3 loop | 
|  | Item (J) := Stream_Element (D and 16#FF#); | 
|  | D := Shift_Right (D, 8); | 
|  | end loop; | 
|  | end Put_32; | 
|  |  | 
|  | begin | 
|  | Out_Last := Out_Data'First - 1; | 
|  |  | 
|  | if not Filter.Stream_End then | 
|  | Add_Data (Simple_GZip_Header); | 
|  |  | 
|  | Translate_Auto | 
|  | (Filter   => Filter, | 
|  | In_Data  => In_Data, | 
|  | In_Last  => In_Last, | 
|  | Out_Data => Out_Data (Out_First .. Out_Data'Last), | 
|  | Out_Last => Out_Last, | 
|  | Flush    => Flush); | 
|  |  | 
|  | CRC32 (Filter.CRC, In_Data (In_Data'First .. In_Last)); | 
|  | end if; | 
|  |  | 
|  | if Filter.Stream_End and then Out_Last <= Out_Data'Last then | 
|  | --  This detection method would work only when | 
|  | --  Simple_GZip_Header'Last > Footer_Array'Last | 
|  |  | 
|  | if Filter.Offset = Simple_GZip_Header'Last + 1 then | 
|  | Filter.Offset := Footer_Array'First; | 
|  | end if; | 
|  |  | 
|  | declare | 
|  | Footer : Footer_Array; | 
|  | begin | 
|  | Put_32 (Footer, Filter.CRC); | 
|  | Put_32 (Footer (Footer'First + 4 .. Footer'Last), | 
|  | Unsigned_32 (Total_In (Filter))); | 
|  | Add_Data (Footer); | 
|  | end; | 
|  | end if; | 
|  | end Translate_GZip; | 
|  |  | 
|  | ------------- | 
|  | -- Version -- | 
|  | ------------- | 
|  |  | 
|  | function Version return String is | 
|  | begin | 
|  | return Interfaces.C.Strings.Value (Thin.zlibVersion); | 
|  | end Version; | 
|  |  | 
|  | ----------- | 
|  | -- Write -- | 
|  | ----------- | 
|  |  | 
|  | procedure Write | 
|  | (Filter : in out Filter_Type; | 
|  | Item   : in     Ada.Streams.Stream_Element_Array; | 
|  | Flush  : in     Flush_Mode := No_Flush) | 
|  | is | 
|  | Buffer   : Stream_Element_Array (1 .. Buffer_Size); | 
|  | In_Last  : Stream_Element_Offset; | 
|  | Out_Last : Stream_Element_Offset; | 
|  | In_First : Stream_Element_Offset := Item'First; | 
|  | begin | 
|  | if Item'Length = 0 and Flush = No_Flush then | 
|  | return; | 
|  | end if; | 
|  |  | 
|  | loop | 
|  | Translate | 
|  | (Filter   => Filter, | 
|  | In_Data  => Item (In_First .. Item'Last), | 
|  | In_Last  => In_Last, | 
|  | Out_Data => Buffer, | 
|  | Out_Last => Out_Last, | 
|  | Flush    => Flush); | 
|  |  | 
|  | if Out_Last >= Buffer'First then | 
|  | Write (Buffer (1 .. Out_Last)); | 
|  | end if; | 
|  |  | 
|  | exit when In_Last = Item'Last or Stream_End (Filter); | 
|  |  | 
|  | In_First := In_Last + 1; | 
|  | end loop; | 
|  | end Write; | 
|  |  | 
|  | end ZLib; |