"Fossies" - the Fresh Open Source Software Archive

Member "lzip-1.22-rc2/decoder.cc" (30 Apr 2020, 8654 Bytes) of package /linux/misc/lzip-1.22-rc2.tar.lz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "decoder.cc" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.21_vs_1.22-rc1.

    1 /* Lzip - LZMA lossless data compressor
    2    Copyright (C) 2008-2020 Antonio Diaz Diaz.
    3 
    4    This program is free software: you can redistribute it and/or modify
    5    it under the terms of the GNU General Public License as published by
    6    the Free Software Foundation, either version 2 of the License, or
    7    (at your option) any later version.
    8 
    9    This program is distributed in the hope that it will be useful,
   10    but WITHOUT ANY WARRANTY; without even the implied warranty of
   11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12    GNU General Public License for more details.
   13 
   14    You should have received a copy of the GNU General Public License
   15    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   16 */
   17 
   18 #define _FILE_OFFSET_BITS 64
   19 
   20 #include <algorithm>
   21 #include <cerrno>
   22 #include <cstdio>
   23 #include <cstdlib>
   24 #include <cstring>
   25 #include <string>
   26 #include <vector>
   27 #include <stdint.h>
   28 #include <unistd.h>
   29 
   30 #include "lzip.h"
   31 #include "decoder.h"
   32 
   33 
   34 /* Returns the number of bytes really read.
   35    If (returned value < size) and (errno == 0), means EOF was reached.
   36 */
   37 int readblock( const int fd, uint8_t * const buf, const int size )
   38   {
   39   int sz = 0;
   40   errno = 0;
   41   while( sz < size )
   42     {
   43     const int n = read( fd, buf + sz, size - sz );
   44     if( n > 0 ) sz += n;
   45     else if( n == 0 ) break;                // EOF
   46     else if( errno != EINTR ) break;
   47     errno = 0;
   48     }
   49   return sz;
   50   }
   51 
   52 
   53 /* Returns the number of bytes really written.
   54    If (returned value < size), it is always an error.
   55 */
   56 int writeblock( const int fd, const uint8_t * const buf, const int size )
   57   {
   58   int sz = 0;
   59   errno = 0;
   60   while( sz < size )
   61     {
   62     const int n = write( fd, buf + sz, size - sz );
   63     if( n > 0 ) sz += n;
   64     else if( n < 0 && errno != EINTR ) break;
   65     errno = 0;
   66     }
   67   return sz;
   68   }
   69 
   70 
   71 bool Range_decoder::read_block()
   72   {
   73   if( !at_stream_end )
   74     {
   75     stream_pos = readblock( infd, buffer, buffer_size );
   76     if( stream_pos != buffer_size && errno ) throw Error( "Read error" );
   77     at_stream_end = ( stream_pos < buffer_size );
   78     partial_member_pos += pos;
   79     pos = 0;
   80     show_dprogress();
   81     }
   82   return pos < stream_pos;
   83   }
   84 
   85 
   86 void LZ_decoder::flush_data()
   87   {
   88   if( pos > stream_pos )
   89     {
   90     const int size = pos - stream_pos;
   91     crc32.update_buf( crc_, buffer + stream_pos, size );
   92     if( outfd >= 0 && writeblock( outfd, buffer + stream_pos, size ) != size )
   93       throw Error( "Write error" );
   94     if( pos >= dictionary_size )
   95       { partial_data_pos += pos; pos = 0; pos_wrapped = true; }
   96     stream_pos = pos;
   97     }
   98   }
   99 
  100 
  101 bool LZ_decoder::verify_trailer( const Pretty_print & pp ) const
  102   {
  103   Lzip_trailer trailer;
  104   int size = rdec.read_data( trailer.data, Lzip_trailer::size );
  105   const unsigned long long data_size = data_position();
  106   const unsigned long long member_size = rdec.member_position();
  107   bool error = false;
  108 
  109   if( size < Lzip_trailer::size )
  110     {
  111     error = true;
  112     if( verbosity >= 0 )
  113       {
  114       pp();
  115       std::fprintf( stderr, "Trailer truncated at trailer position %d;"
  116                             " some checks may fail.\n", size );
  117       }
  118     while( size < Lzip_trailer::size ) trailer.data[size++] = 0;
  119     }
  120 
  121   const unsigned td_crc = trailer.data_crc();
  122   if( td_crc != crc() )
  123     {
  124     error = true;
  125     if( verbosity >= 0 )
  126       {
  127       pp();
  128       std::fprintf( stderr, "CRC mismatch; stored %08X, computed %08X\n",
  129                     td_crc, crc() );
  130       }
  131     }
  132   const unsigned long long td_size = trailer.data_size();
  133   if( td_size != data_size )
  134     {
  135     error = true;
  136     if( verbosity >= 0 )
  137       {
  138       pp();
  139       std::fprintf( stderr, "Data size mismatch; stored %llu (0x%llX), computed %llu (0x%llX)\n",
  140                     td_size, td_size, data_size, data_size );
  141       }
  142     }
  143   const unsigned long long tm_size = trailer.member_size();
  144   if( tm_size != member_size )
  145     {
  146     error = true;
  147     if( verbosity >= 0 )
  148       {
  149       pp();
  150       std::fprintf( stderr, "Member size mismatch; stored %llu (0x%llX), computed %llu (0x%llX)\n",
  151                     tm_size, tm_size, member_size, member_size );
  152       }
  153     }
  154   if( error ) return false;
  155   if( verbosity >= 2 )
  156     {
  157     if( verbosity >= 4 ) show_header( dictionary_size );
  158     if( data_size == 0 || member_size == 0 )
  159       std::fputs( "no data compressed. ", stderr );
  160     else
  161       std::fprintf( stderr, "%6.3f:1, %5.2f%% ratio, %5.2f%% saved. ",
  162                     (double)data_size / member_size,
  163                     ( 100.0 * member_size ) / data_size,
  164                     100.0 - ( ( 100.0 * member_size ) / data_size ) );
  165     if( verbosity >= 4 ) std::fprintf( stderr, "CRC %08X, ", td_crc );
  166     if( verbosity >= 3 )
  167       std::fprintf( stderr, "%9llu out, %8llu in. ", data_size, member_size );
  168     }
  169   return true;
  170   }
  171 
  172 
  173 /* Return value: 0 = OK, 1 = decoder error, 2 = unexpected EOF,
  174                  3 = trailer error, 4 = unknown marker found. */
  175 int LZ_decoder::decode_member( const Pretty_print & pp )
  176   {
  177   Bit_model bm_literal[1<<literal_context_bits][0x300];
  178   Bit_model bm_match[State::states][pos_states];
  179   Bit_model bm_rep[State::states];
  180   Bit_model bm_rep0[State::states];
  181   Bit_model bm_rep1[State::states];
  182   Bit_model bm_rep2[State::states];
  183   Bit_model bm_len[State::states][pos_states];
  184   Bit_model bm_dis_slot[len_states][1<<dis_slot_bits];
  185   Bit_model bm_dis[modeled_distances-end_dis_model+1];
  186   Bit_model bm_align[dis_align_size];
  187   Len_model match_len_model;
  188   Len_model rep_len_model;
  189   unsigned rep0 = 0;        // rep[0-3] latest four distances
  190   unsigned rep1 = 0;        // used for efficient coding of
  191   unsigned rep2 = 0;        // repeated distances
  192   unsigned rep3 = 0;
  193   State state;
  194 
  195   rdec.load();
  196   while( !rdec.finished() )
  197     {
  198     const int pos_state = data_position() & pos_state_mask;
  199     if( rdec.decode_bit( bm_match[state()][pos_state] ) == 0 )  // 1st bit
  200       {
  201       // literal byte
  202       Bit_model * const bm = bm_literal[get_lit_state(peek_prev())];
  203       if( state.is_char_set_char() )
  204         put_byte( rdec.decode_tree8( bm ) );
  205       else
  206         put_byte( rdec.decode_matched( bm, peek( rep0 ) ) );
  207       continue;
  208       }
  209     // match or repeated match
  210     int len;
  211     if( rdec.decode_bit( bm_rep[state()] ) != 0 )       // 2nd bit
  212       {
  213       if( rdec.decode_bit( bm_rep0[state()] ) == 0 )        // 3rd bit
  214         {
  215         if( rdec.decode_bit( bm_len[state()][pos_state] ) == 0 ) // 4th bit
  216           { state.set_short_rep(); put_byte( peek( rep0 ) ); continue; }
  217         }
  218       else
  219         {
  220         unsigned distance;
  221         if( rdec.decode_bit( bm_rep1[state()] ) == 0 )      // 4th bit
  222           distance = rep1;
  223         else
  224           {
  225           if( rdec.decode_bit( bm_rep2[state()] ) == 0 )    // 5th bit
  226             distance = rep2;
  227           else
  228             { distance = rep3; rep3 = rep2; }
  229           rep2 = rep1;
  230           }
  231         rep1 = rep0;
  232         rep0 = distance;
  233         }
  234       state.set_rep();
  235       len = min_match_len + rdec.decode_len( rep_len_model, pos_state );
  236       }
  237     else                    // match
  238       {
  239       len = min_match_len + rdec.decode_len( match_len_model, pos_state );
  240       unsigned distance = rdec.decode_tree6( bm_dis_slot[get_len_state(len)] );
  241       if( distance >= start_dis_model )
  242         {
  243         const unsigned dis_slot = distance;
  244         const int direct_bits = ( dis_slot >> 1 ) - 1;
  245         distance = ( 2 | ( dis_slot & 1 ) ) << direct_bits;
  246         if( dis_slot < end_dis_model )
  247           distance += rdec.decode_tree_reversed(
  248                       bm_dis + ( distance - dis_slot ), direct_bits );
  249         else
  250           {
  251           distance +=
  252             rdec.decode( direct_bits - dis_align_bits ) << dis_align_bits;
  253           distance += rdec.decode_tree_reversed4( bm_align );
  254           if( distance == 0xFFFFFFFFU )     // marker found
  255             {
  256             rdec.normalize();
  257             flush_data();
  258             if( len == min_match_len )      // End Of Stream marker
  259               {
  260               if( verify_trailer( pp ) ) return 0; else return 3;
  261               }
  262             if( len == min_match_len + 1 )  // Sync Flush marker
  263               {
  264               rdec.load(); continue;
  265               }
  266             if( verbosity >= 0 )
  267               {
  268               pp();
  269               std::fprintf( stderr, "Unsupported marker code '%d'\n", len );
  270               }
  271             return 4;
  272             }
  273           }
  274         }
  275       rep3 = rep2; rep2 = rep1; rep1 = rep0; rep0 = distance;
  276       state.set_match();
  277       if( rep0 >= dictionary_size || ( rep0 >= pos && !pos_wrapped ) )
  278         { flush_data(); return 1; }
  279       }
  280     copy_block( rep0, len );
  281     }
  282   flush_data();
  283   return 2;
  284   }