702 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Ada
		
	
	
	
	
	
		
		
			
		
	
	
			702 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Ada
		
	
	
	
	
	
|   | ----------------------------------------------------------------
 | ||
|  | --  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; |