Back to... Zip-Ada

Source file : lzma-decoding.adb



   1  --  LZMA.Decoding - Ada 95 translation of LzmaSpec.cpp, LZMA Reference Decoder 9.31
   2  --  LzmaSpec.cpp : 2013-07-28 : Igor Pavlov : Public domain
   3  ----------------
   4  --
   5  --  Rework in 2016 by G. de Montmollin.
   6  --    - some confusing identifiers were changed:
   7  --        mostly, "range" was renamed "width", various names for probability data
   8  --        have been renamed "probs", different things called "pos" have been renamed
   9  --    - the whole probability model has been encapsulated
  10  --    - parts common to encoding were moved to the root LZMA package.
  11  
  12  --  Legal licensing note:
  13  
  14  --  Copyright (c) 2014 .. 2021 Gautier de Montmollin (maintainer of the Ada version)
  15  --  SWITZERLAND
  16  
  17  --  Permission is hereby granted, free of charge, to any person obtaining a copy
  18  --  of this software and associated documentation files (the "Software"), to deal
  19  --  in the Software without restriction, including without limitation the rights
  20  --  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  21  --  copies of the Software, and to permit persons to whom the Software is
  22  --  furnished to do so, subject to the following conditions:
  23  
  24  --  The above copyright notice and this permission notice shall be included in
  25  --  all copies or substantial portions of the Software.
  26  
  27  --  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  28  --  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  29  --  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  30  --  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  31  --  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  32  --  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  33  --  THE SOFTWARE.
  34  
  35  --  NB: this is the MIT License, as found on the site
  36  --  http://www.opensource.org/licenses/mit-license.php
  37  
  38  with Ada.Text_IO,
  39       Ada.Unchecked_Deallocation;
  40  
  41  package body LZMA.Decoding is
  42  
  43    type Byte_buffer is array (UInt32 range <>) of Byte;
  44    type p_Byte_buffer is access Byte_buffer;
  45  
  46    type Out_Window is record
  47      buf       : p_Byte_buffer := null;
  48      pos       : UInt32        := 0;
  49      size      : UInt32;
  50      is_full   : Boolean       := False;
  51      total_pos : Unsigned      := 0;
  52    end record;
  53  
  54    procedure Create (o : in out Out_Window; new_dictionary_size : UInt32) is
  55    begin
  56      o.buf  := new Byte_buffer (0 .. new_dictionary_size - 1);
  57      o.size := new_dictionary_size;
  58    end Create;
  59  
  60    type Range_Decoder is record
  61      width     : UInt32  := 16#FFFF_FFFF#;  --  (*)
  62      code      : UInt32  := 0;
  63      corrupted : Boolean := False;
  64    end record;
  65    --  (*) called "range" in LZMA spec and "remaining width" in G.N.N. Martin's
  66    --      article about range encoding.
  67  
  68    procedure Init (o : in out Range_Decoder) is
  69    begin
  70      if Read_Byte /= 0 then
  71        o.corrupted := True;
  72      end if;
  73      for i in 0 .. 3 loop
  74        o.code := Shift_Left (o.code, 8) or UInt32 (Read_Byte);
  75      end loop;
  76      if o.code = o.width then
  77        o.corrupted := True;
  78      end if;
  79    end Init;
  80  
  81    procedure Decode_Properties (o : in out LZMA_Decoder_Info; b : Byte_buffer) is
  82      d : Unsigned := Unsigned (b (b'First));
  83    begin
  84      if d >= 9 * 5 * 5 then
  85        raise LZMA_Error with "Incorrect LZMA properties";
  86      end if;
  87      o.lc := Literal_Context_Bits_Range (d mod 9);
  88      d := d / 9;
  89      o.lp := Literal_Position_Bits_Range (d mod 5);
  90      o.pb := Position_Bits_Range (d / 5);
  91      o.dictSizeInProperties := 0;
  92      for i in 0 .. 3 loop
  93        o.dictSizeInProperties := o.dictSizeInProperties +
  94          UInt32 (b (UInt32 (i) + 1 + b'First)) * 2 ** (8 * i);
  95      end loop;
  96      o.dictionary_size := o.dictSizeInProperties;
  97      if o.dictionary_size < Min_dictionary_size then
  98        o.dictionary_size := Min_dictionary_size;
  99      end if;
 100    end Decode_Properties;
 101  
 102    procedure Decode_Contents (o : in out LZMA_Decoder_Info; res : out LZMA_Result) is
 103      state : State_range := 0;
 104      --  Small stack of recent distances used for LZ. Required: initialized with zero values.
 105      rep0, rep1, rep2, rep3 : UInt32 := 0;
 106      pos_state : Pos_state_range;
 107      --  Local copies of invariant properties.
 108      is_unpack_size_defined : constant Boolean := o.unpackSizeDefined;
 109      literal_pos_mask : constant UInt32 := 2 ** o.lp - 1;
 110      lc : constant Literal_Context_Bits_Range := o.lc;
 111      --
 112      use type Data_Bytes_Count;
 113      out_win : Out_Window;
 114      --  Local range decoder
 115      range_dec : Range_Decoder;
 116      --  Entire probability model. Maximum lit_prob_index is: 3,145,727.
 117      probs : All_probabilities (last_lit_prob_index => 16#300# * 2 ** (o.lc + o.lp) - 1);
 118  
 119      --  Normalize corresponds to G.N.N. Martin's revised algorithm's adding of
 120      --  trailing digits - for encoding. Here we decode and know the encoded
 121      --  data, brought by Read_Byte.
 122      procedure Normalize is
 123      pragma Inline (Normalize);
 124      begin
 125        --  Assertion: the width is large enough for the normalization to be needed
 126        --  once per bit decoding. Worst case: width = 2**24 before; bound = (2**13) * (2**5-1)
 127        --  new width's (leading binary digit) = 2**17; after normalization: 2**(17+8) = 2**25.
 128        if range_dec.width < width_threshold then
 129          range_dec.width := Shift_Left (range_dec.width, 8);
 130          range_dec.code  := Shift_Left (range_dec.code, 8) or UInt32 (Read_Byte);
 131        end if;
 132      end Normalize;
 133  
 134      procedure Decode_Bit (prob : in out CProb; symbol : out Unsigned) is
 135      pragma Inline (Decode_Bit);
 136        cur_prob : constant CProb := prob;  --  Local copy
 137        bound : constant UInt32 := Shift_Right (range_dec.width, probability_model_bits) * UInt32 (cur_prob);
 138        --  See encoder for explanations about the maths.
 139      begin
 140        if range_dec.code < bound then
 141          prob := cur_prob + Shift_Right (probability_model_count - cur_prob, probability_change_bits);
 142          range_dec.width := bound;
 143          Normalize;
 144          symbol := 0;
 145        else
 146          prob := cur_prob - Shift_Right (cur_prob, probability_change_bits);
 147          range_dec.code  := range_dec.code - bound;
 148          range_dec.width := range_dec.width - bound;
 149          Normalize;
 150          symbol := 1;
 151        end if;
 152      end Decode_Bit;
 153  
 154      function Is_Empty return Boolean is
 155      pragma Inline (Is_Empty);
 156      begin
 157        return out_win.pos = 0 and then not out_win.is_full;
 158      end Is_Empty;
 159  
 160      LZ77_Dump : Ada.Text_IO.File_Type;
 161      some_trace : constant Boolean := False;
 162  
 163      procedure Put_Byte (b : Byte) is
 164      pragma Inline (Put_Byte);
 165      begin
 166        out_win.total_pos := out_win.total_pos + 1;
 167        out_win.buf (out_win.pos) := b;
 168        out_win.pos := out_win.pos + 1;
 169        if out_win.pos = out_win.size then
 170          out_win.pos := 0;
 171          out_win.is_full := True;
 172        end if;
 173        Write_Byte (b);
 174        if some_trace then
 175          Ada.Text_IO.Put (LZ77_Dump, "Lit" & Byte'Image (b));
 176          if b in 32 .. 126 then
 177            Ada.Text_IO.Put (LZ77_Dump, " '" & Character'Val (b) & ''');
 178          end if;
 179          Ada.Text_IO.New_Line (LZ77_Dump);
 180        end if;
 181      end Put_Byte;
 182  
 183      function Get_Byte (dist : UInt32) return Byte is
 184      pragma Inline (Get_Byte);
 185      begin
 186        if dist <= out_win.pos then
 187          return out_win.buf (out_win.pos - dist);
 188        else
 189          return out_win.buf (out_win.pos - dist + out_win.size);
 190        end if;
 191      end Get_Byte;
 192  
 193      procedure Process_Literal is
 194      pragma Inline (Process_Literal);
 195        prev_byte    : Byte := 0;
 196        symbol       : Unsigned := 1;
 197        lit_state    : Integer;
 198        probs_idx    : Integer;
 199        bit_nomatch  : Unsigned;
 200      begin
 201        if is_unpack_size_defined and then o.unpackSize = 0 then
 202          raise LZMA_Error with "Decoded data will exceed expected data size (Process_Literal)";
 203        end if;
 204        --
 205        if not Is_Empty then
 206          prev_byte := Get_Byte (dist => 1);
 207        end if;
 208        lit_state :=
 209          Integer (
 210            Shift_Left (UInt32 (out_win.total_pos) and literal_pos_mask, lc) +
 211            Shift_Right (UInt32 (prev_byte), 8 - lc)
 212          );
 213        probs_idx := 16#300# * lit_state;
 214        if state < 7 then
 215          loop
 216            Decode_Bit (probs.lit (probs_idx + Integer (symbol)), bit_nomatch);
 217            symbol := (2 * symbol) or bit_nomatch;
 218            exit when symbol >= 16#100#;
 219          end loop;
 220        else
 221          declare
 222            --
 223            --  The probabilities used for decoding this literal assume
 224            --  that the current literal sequence resembles to the last
 225            --  distance-length copied sequence.
 226            --
 227            match_byte     : UInt32 := UInt32 (Get_Byte (dist => rep0 + 1));
 228            match_bit      : UInt32;    --  either 0 or 16#100#
 229            prob_idx_match : Integer;   --  either 0 (normal case without match), 16#100# or 16#200#
 230            bit_a, bit_b   : Unsigned;
 231          begin
 232            loop
 233              match_byte := match_byte + match_byte;
 234              match_bit  := match_byte and 16#100#;
 235              prob_idx_match := Integer (16#100# + match_bit);
 236              Decode_Bit (probs.lit (probs_idx + prob_idx_match + Integer (symbol)), bit_a);
 237              symbol := (2 * symbol) or bit_a;
 238              exit when symbol >= 16#100#;
 239              if match_bit /= Shift_Left (UInt32 (bit_a), 8) then
 240                --  No bit match, then give up byte match
 241                loop
 242                  Decode_Bit (probs.lit (probs_idx + Integer (symbol)), bit_b);
 243                  symbol := (2 * symbol) or bit_b;
 244                  exit when symbol >= 16#100#;
 245                end loop;
 246                exit;
 247              end if;
 248            end loop;
 249          end;
 250        end if;
 251        Put_Byte (Byte (symbol - 16#100#));  --  The output of a simple literal happens here.
 252        --
 253        state := Update_State_Literal (state);
 254        o.unpackSize := o.unpackSize - 1;
 255      end Process_Literal;
 256  
 257      dict_size : constant UInt32 := o.dictionary_size;
 258  
 259      function Is_Finished_OK return Boolean is
 260      pragma Inline (Is_Finished_OK);
 261      begin
 262        return range_dec.code = 0;
 263      end Is_Finished_OK;
 264  
 265      type DL_Return_Code is (Normal, End_Of_Stream);
 266  
 267      function Process_Distance_and_Length return DL_Return_Code is
 268      pragma Inline (Process_Distance_and_Length);
 269        --
 270        procedure Bit_Tree_Decode (
 271          prob     : in out CProb_array;
 272          num_bits :        Positive;
 273          m        :    out Unsigned)
 274        is
 275        pragma Inline (Bit_Tree_Decode);
 276          a_bit : Unsigned;
 277        begin
 278          m := 1;
 279          for count in reverse 1 .. num_bits loop
 280            Decode_Bit (prob (Integer (m) + prob'First), a_bit);
 281            m := 2 * m + a_bit;
 282          end loop;
 283          m := m - 2**num_bits;
 284        end Bit_Tree_Decode;
 285        --
 286        len : Unsigned := 0;
 287        --
 288        procedure Copy_Match (dist : UInt32) is
 289        pragma Inline (Copy_Match);
 290          len32 : constant UInt32 := UInt32 (len);
 291          --  Conversion to UInt64 needed for dictionary size > 2**32 - 273:
 292          will_fill : constant Boolean :=
 293            UInt64 (out_win.pos) + UInt64 (len32) >= UInt64 (out_win.size);
 294          --
 295          procedure Easy_case is
 296          pragma Inline (Easy_case);
 297            src_from, src_to : UInt32;
 298            b1 : Byte;
 299          begin
 300            --  The src and dest slices are within circular buffer bounds.
 301            --  May overlap (len32 > dist), even several times.
 302            src_from := out_win.pos - dist;
 303            src_to   := out_win.pos - dist + len32 - 1;
 304            --  We copy in forward order, with eventual overlapping(s)..
 305            for i in src_from .. src_to loop
 306              b1 := out_win.buf (i);
 307              out_win.buf (i + dist) := b1;
 308              Write_Byte (b1);
 309            end loop;
 310            out_win.pos := out_win.pos + len32;
 311          end Easy_case;
 312          --
 313          procedure Modulo_case is
 314          pragma Inline (Modulo_case);
 315            b2, b3 : Byte;
 316          begin
 317            --  src starts below 0 or dest goes beyond size-1
 318            for count in reverse 1 .. len loop
 319              if dist <= out_win.pos then
 320                b2 := out_win.buf (out_win.pos - dist);
 321                out_win.buf (out_win.pos) := b2;
 322                out_win.pos := out_win.pos + 1;
 323                if out_win.pos = out_win.size then
 324                  out_win.pos := 0;
 325                end if;
 326                Write_Byte (b2);
 327              else
 328                b3 := out_win.buf (out_win.size - dist + out_win.pos);
 329                out_win.buf (out_win.pos) := b3;
 330                out_win.pos := out_win.pos + 1;
 331                if out_win.pos = out_win.size then
 332                  out_win.pos := 0;
 333                end if;
 334                Write_Byte (b3);
 335              end if;
 336            end loop;
 337          end Modulo_case;
 338        begin
 339          out_win.is_full := out_win.is_full or will_fill;
 340          out_win.total_pos := out_win.total_pos + len;
 341          if dist <= out_win.pos and not will_fill then
 342            Easy_case;
 343          else
 344            Modulo_case;
 345          end if;
 346          if some_trace then
 347            Ada.Text_IO.Put_Line (LZ77_Dump, "DLE" & UInt32'Image (dist) & Unsigned'Image (len));
 348          end if;
 349        end Copy_Match;
 350        --
 351        procedure Decode_Distance (dist : out UInt32) is
 352        pragma Inline (Decode_Distance);
 353          --
 354          decode_direct : UInt32;
 355          --
 356          procedure Decode_Direct_Bits (num_bits : Natural) is
 357          pragma Inline (Decode_Direct_Bits);
 358            t : UInt32;
 359          begin
 360            decode_direct := 0;
 361            for count in reverse 1 .. num_bits loop
 362              range_dec.width := Shift_Right (range_dec.width, 1);
 363              range_dec.code := range_dec.code - range_dec.width;
 364              t := -Shift_Right (range_dec.code, 31);
 365              range_dec.code := range_dec.code + (range_dec.width and t);
 366              if range_dec.code = range_dec.width then
 367                range_dec.corrupted := True;
 368              end if;
 369              Normalize;
 370              decode_direct := decode_direct + decode_direct + t + 1;
 371            end loop;
 372          end Decode_Direct_Bits;
 373          --
 374          procedure Bit_Tree_Reverse_Decode (prob : in out CProb_array; num_bits : in Natural) is
 375          pragma Inline (Bit_Tree_Reverse_Decode);
 376            m : Unsigned := 1;
 377            a_bit : Unsigned;
 378          begin
 379            for i in 0 .. num_bits - 1 loop
 380              Decode_Bit (prob (Integer (m) + prob'First), a_bit);
 381              m := 2 * m + a_bit;
 382              dist := dist or Shift_Left (UInt32 (a_bit), i);
 383            end loop;
 384          end Bit_Tree_Reverse_Decode;
 385          --
 386          --  len has been set up previously by Decode_Length.
 387          len_state     : constant Unsigned := Unsigned'Min (len, len_to_pos_states - 1);
 388          dist_slot     : Unsigned;
 389          numDirectBits : Natural;
 390          --
 391        begin  --  Decode_Distance
 392          Bit_Tree_Decode (probs.dist.slot_coder (len_state), Dist_slot_bits, dist_slot);
 393          if dist_slot < Start_dist_model_index then
 394            dist := UInt32 (dist_slot);
 395            return;
 396          end if;
 397          numDirectBits := Natural (Shift_Right (UInt32 (dist_slot), 1) - 1);
 398          dist := Shift_Left (2 or (UInt32 (dist_slot) and 1), numDirectBits);
 399          if dist_slot < End_dist_model_index then
 400            Bit_Tree_Reverse_Decode (
 401              probs.dist.pos_coder (Integer (dist) - Integer (dist_slot) .. Pos_coder_range'Last),
 402              numDirectBits
 403            );
 404          else
 405            Decode_Direct_Bits (numDirectBits - align_bits);
 406            dist := dist + Shift_Left (decode_direct, align_bits);
 407            Bit_Tree_Reverse_Decode (probs.dist.align_coder, align_bits);
 408          end if;
 409        end Decode_Distance;
 410        --
 411        procedure Decode_Length (probs_len : in out Probs_for_LZ_Lengths) is
 412        pragma Inline (Decode_Length);
 413          choice : Unsigned;
 414        begin
 415          Decode_Bit (probs_len.choice_1, choice);
 416          if choice = 0 then
 417            Bit_Tree_Decode (probs_len.low_coder (pos_state), Len_low_bits, len);
 418            --  final length is in 2 + [0..7]
 419            return;
 420          end if;
 421          Decode_Bit (probs_len.choice_2, choice);
 422          if choice = 0 then
 423            Bit_Tree_Decode (probs_len.mid_coder (pos_state), Len_mid_bits, len);
 424            len := len + Len_low_symbols;
 425            --  final length is in 2 + [8..15]
 426            return;
 427          end if;
 428          Bit_Tree_Decode (probs_len.high_coder, Len_high_bits, len);
 429          len := len + Len_low_symbols + Len_mid_symbols;
 430          --  final length is in 2 + [16..271]
 431        end Decode_Length;
 432        --
 433        function Is_Distance_Valid return Boolean is
 434        pragma Inline (Is_Distance_Valid);
 435        begin
 436          return
 437              rep0 < dict_size
 438            and
 439              (
 440                  --  When the window / dictionary is not yet full, the distance
 441                  --  needs to be between 0 and the position.
 442                  rep0 <= out_win.pos
 443                or
 444                  --  When the dictionary is full the distance can exceed the
 445                  --  position (it's a circular buffer).
 446                  out_win.is_full
 447              );
 448        end Is_Distance_Valid;
 449        --
 450        data_length_error : Boolean;
 451        dist : UInt32;
 452        bit_a, bit_b, bit_c, bit_d, bit_e : Unsigned;
 453        --
 454      begin  --  Process_Distance_and_Length
 455        Decode_Bit (probs.switch.rep (state), bit_a);
 456        if bit_a = Simple_match_choice then
 457          --  "Simple Match"
 458          rep3 := rep2;
 459          rep2 := rep1;
 460          rep1 := rep0;
 461          Decode_Length (probs.len);
 462          state := Update_State_Match (state);
 463          Decode_Distance (dist => rep0);
 464          if rep0 = end_of_stream_magic_distance then
 465            if Is_Finished_OK then
 466              return End_Of_Stream;
 467            else
 468              raise LZMA_Error with
 469                "Range decoder not finished on EOS marker (in Process_Distance_and_Length)";
 470            end if;
 471          end if;
 472          if is_unpack_size_defined and then o.unpackSize = 0 then
 473            raise LZMA_Error with
 474              "Decoded data will exceed expected data size (in Process_Distance_and_Length, #2).";
 475          end if;
 476          if not Is_Distance_Valid then
 477            raise LZMA_Error with
 478              "Invalid distance (in Process_Distance_and_Length):" &
 479              "; Dictionary size =" & UInt32'Image (dict_size) &
 480              "; Position        =" & UInt32'Image (out_win.pos) &
 481              "; Distance        =" & UInt32'Image (rep0) &
 482              "; Is window full ? " & Boolean'Image (out_win.is_full);
 483          end if;
 484        else
 485          --  "Rep Match"
 486          if is_unpack_size_defined and then o.unpackSize = 0 then
 487            raise LZMA_Error with
 488              "Decoded data will exceed expected data size (in Process_Distance_and_Length, #1)";
 489          end if;
 490          if Is_Empty then
 491            raise LZMA_Error with "Output window buffer is empty (in Process_Distance_and_Length)";
 492          end if;
 493          Decode_Bit (probs.switch.rep_g0 (state), bit_b);
 494          if bit_b = The_distance_is_rep0_choice then
 495            Decode_Bit (probs.switch.rep0_long (state, pos_state), bit_c);
 496            if bit_c = The_length_is_1_choice then
 497              state := Update_State_ShortRep (state);
 498              Put_Byte (Get_Byte (dist => rep0 + 1));
 499              o.unpackSize := o.unpackSize - 1;
 500              return Normal;  -- GdM: this way, we go to the next iteration (C++: continue)
 501            end if;
 502          else
 503            Decode_Bit (probs.switch.rep_g1 (state), bit_d);
 504            if bit_d = The_distance_is_rep1_choice then
 505              dist := rep1;
 506            else
 507              Decode_Bit (probs.switch.rep_g2 (state), bit_e);
 508              if bit_e = The_distance_is_rep2_choice then
 509                dist := rep2;
 510              else
 511                dist := rep3;
 512                rep3 := rep2;
 513              end if;
 514              rep2 := rep1;
 515            end if;
 516            rep1 := rep0;
 517            rep0 := dist;
 518          end if;
 519          Decode_Length (probs.rep_len);
 520          state := Update_State_Rep (state);
 521        end if;
 522        len := len + Min_match_length;
 523        data_length_error := False;
 524        if is_unpack_size_defined and then o.unpackSize < Data_Bytes_Count (len) then
 525          len := Unsigned (o.unpackSize);
 526          data_length_error := True;
 527        end if;
 528        --  The LZ distance/length copy happens here.
 529        Copy_Match (dist => rep0 + 1);
 530        if data_length_error then
 531          raise LZMA_Error with
 532            "Decoded data will exceed expected data size (in Process_Distance_and_Length, #3)";
 533        end if;
 534        o.unpackSize := o.unpackSize - Data_Bytes_Count (len);
 535        return Normal;
 536      end Process_Distance_and_Length;
 537  
 538      bit_choice : Unsigned;
 539      pos_bits_mask : constant UInt32 := 2 ** o.pb - 1;
 540      size_defined_and_marker_not_mandatory : constant Boolean :=
 541        is_unpack_size_defined and not o.markerIsMandatory;
 542  
 543      procedure Full_Decoding is
 544      begin
 545        Create (out_win, o.dictionary_size);
 546        Init (range_dec);
 547        loop
 548          if o.unpackSize = 0
 549            and then Is_Finished_OK
 550            and then size_defined_and_marker_not_mandatory
 551          then
 552            res := LZMA_finished_without_marker;
 553            return;
 554          end if;
 555          pos_state := Pos_state_range (UInt32 (out_win.total_pos) and pos_bits_mask);
 556          Decode_Bit (probs.switch.match (state, pos_state), bit_choice);
 557          --  LZ decoding happens here: either we have a new literal
 558          --  in 1 byte, or we copy a slice of past data.
 559          if bit_choice = Literal_choice then
 560            Process_Literal;
 561          else
 562            case Process_Distance_and_Length is
 563              when Normal =>
 564                null;
 565              when End_Of_Stream =>
 566                res := LZMA_finished_with_marker;
 567                return;
 568            end case;
 569          end if;
 570        end loop;
 571      end Full_Decoding;
 572  
 573      procedure Finalize is
 574        procedure Dispose is new Ada.Unchecked_Deallocation (Byte_buffer, p_Byte_buffer);
 575      begin
 576        Dispose (out_win.buf);
 577        o.range_dec_corrupted := range_dec.corrupted;
 578      end Finalize;
 579  
 580    begin
 581      if some_trace then
 582        Ada.Text_IO.Create (LZ77_Dump, Ada.Text_IO.Out_File, "dump.lz77");
 583      end if;
 584      Full_Decoding;
 585      Finalize;
 586      if some_trace then
 587        Ada.Text_IO.Close (LZ77_Dump);
 588      end if;
 589    end Decode_Contents;
 590  
 591    procedure Decode_Header (o : out LZMA_Decoder_Info; hints : LZMA_Hints) is
 592      header : Byte_buffer (0 .. 12);
 593      b : Byte;
 594      use type Data_Bytes_Count;
 595      last_bit : Natural;
 596    begin
 597      o.unpackSize := 0;
 598      o.unpackSizeDefined := False;
 599  
 600      for i in header'Range loop
 601        header (i) := Read_Byte;
 602        exit when i = 4 and not hints.has_size;
 603      end loop;
 604  
 605      Decode_Properties (o, header);
 606  
 607      if hints.has_size then
 608        for i in UInt32'(0) .. 7 loop
 609          b := header (5 + i);
 610          if b /= 16#FF# then
 611            o.unpackSizeDefined := True;
 612          end if;
 613        end loop;
 614        if o.unpackSizeDefined then
 615          for i in UInt32'(0) .. 7 loop
 616            b := header (5 + i);
 617            if b /= 0 then
 618              for bit_pos in 0 .. 7 loop
 619                if (b and Shift_Left (Byte'(1), bit_pos)) /= 0 then
 620                  last_bit := bit_pos;
 621                end if;
 622              end loop;
 623              last_bit := last_bit + Natural (8 * i);
 624              if last_bit > Data_Bytes_Count'Size - 1 then
 625                raise LZMA_Error with
 626                  "Indicated size bits for decoded data," &
 627                  Natural'Image (last_bit) &
 628                  ", exceeds the maximum file size bits," &
 629                  Natural'Image (Data_Bytes_Count'Size - 1);
 630              else
 631                o.unpackSize := o.unpackSize + Data_Bytes_Count (b) * 2 ** Natural (8 * i);
 632              end if;
 633            end if;
 634          end loop;
 635          o.unpackSize_as_defined := o.unpackSize;
 636        else
 637          o.unpackSize := Data_Bytes_Count'Last;
 638        end if;
 639      else
 640        o.unpackSize := hints.given_size;
 641        o.unpackSizeDefined := True;
 642      end if;
 643      o.markerIsMandatory := hints.marker_expected or not o.unpackSizeDefined;
 644    end Decode_Header;
 645  
 646    procedure Decode (info : out LZMA_Decoder_Info; hints : LZMA_Hints; res : out LZMA_Result) is
 647    begin
 648      Decode_Header (info, hints);
 649      Decode_Contents (info, res);
 650      if hints.fail_on_bad_range_code and info.range_dec_corrupted then
 651        raise LZMA_Error with "Range decoder had a corrupted value";
 652      end if;
 653    end Decode;
 654  
 655    procedure Decompress (hints : LZMA_Hints) is
 656      --  Technical informations are discarded in this version of Decompress.
 657      info : LZMA_Decoder_Info;
 658      res  : LZMA_Result;
 659    begin
 660      Decode (info, hints, res);
 661    end Decompress;
 662  
 663    function Literal_context_bits (info : LZMA_Decoder_Info) return Natural is
 664    begin
 665      return info.lc;
 666    end Literal_context_bits;
 667  
 668    function Literal_pos_bits (info : LZMA_Decoder_Info) return Natural is
 669    begin
 670      return info.lp;
 671    end Literal_pos_bits;
 672  
 673    function Pos_bits (info : LZMA_Decoder_Info) return Natural is
 674    begin
 675      return info.pb;
 676    end Pos_bits;
 677  
 678    function Unpack_size_defined (info : LZMA_Decoder_Info) return Boolean is
 679    begin
 680      return info.unpackSizeDefined;
 681    end Unpack_size_defined;
 682  
 683    function Unpack_size_as_defined (info : LZMA_Decoder_Info) return Data_Bytes_Count is
 684    begin
 685      return info.unpackSize_as_defined;
 686    end Unpack_size_as_defined;
 687  
 688    function Probability_model_size (info : LZMA_Decoder_Info) return Interfaces.Unsigned_32 is
 689      probs : All_probabilities (last_lit_prob_index => 16#300# * 2 ** (info.lc + info.lp) - 1);
 690    begin
 691      return probs'Size / 8;
 692    end Probability_model_size;
 693  
 694    function Dictionary_size (info : LZMA_Decoder_Info) return Interfaces.Unsigned_32 is
 695    begin
 696      return info.dictionary_size;
 697    end Dictionary_size;
 698  
 699    function Dictionary_size_in_properties (info : LZMA_Decoder_Info) return Interfaces.Unsigned_32 is
 700    begin
 701      return info.dictSizeInProperties;
 702    end Dictionary_size_in_properties;
 703  
 704    function Range_decoder_corrupted (info : LZMA_Decoder_Info) return Boolean is
 705    begin
 706      return info.range_dec_corrupted;
 707    end Range_decoder_corrupted;
 708  
 709  end LZMA.Decoding;

Web view of Ada source code generated by GNATHTML, project: ALI_Parse version 1.0.
Zip-Ada: Ada library for zip archive files (.zip). Ada programming.
Some news about Zip-Ada and other Ada projects on Gautier's blog.