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