| lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 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; |