zlib.adb
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:20k
源码类别:

通讯编程

开发平台:

Visual C++

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