Example #1
0
void LZHLEncoderStat::calcStat( HUFFINT* groups )
{
  HuffStatTmpStruct s[ NHUFFSYMBOLS ];
  int total = makeSortedTmp( s );

  nextStat = HUFFRECALCLEN;

  int pos = 0;
  int nTotal = 0;

  for ( HUFFINT group=0; group < 14 ; ++group )
  {
    int avgGroup = ( total - nTotal )/( 16 - group );
    int i = 0, n = 0, nn = 0;

    for ( HUFFINT nBits=0 ;; ++nBits )
    {
      int over = 0;
      int nItems = 1 << nBits;

      if ( pos + i + nItems > NHUFFSYMBOLS )
      {
        nItems = NHUFFSYMBOLS - pos;
        over = 1;
      }

      for ( ; i < nItems ; ++i )
        nn += s[ pos + i ].n;

      if ( over || nBits >= 8 || nn > avgGroup )
      {
        if ( nBits == 0 || abs( n - avgGroup ) > abs( nn - avgGroup ) ) {
          n = nn;
        } else {
          --nBits;
        }

        _addGroup( groups, group, nBits );
        nTotal += n;
        pos += 1 << nBits;

        break;

      } else {
        n = nn;
      }
    }
  }

  HUFFINT bestNBits = 0, bestNBits15 = 0;
  int best = 0x7FFFFFFF;
  int i = 0, nn = 0, left = 0;

  for ( int j=pos; j < NHUFFSYMBOLS ; ++j )
    left += s[ j ].n;

  for ( HUFFINT nBits = 0 ;; ++nBits ) {
    int nItems = 1 << nBits;
    if ( pos + i + nItems > NHUFFSYMBOLS )
      break;

    for ( ; i < nItems ; ++i )
      nn += s[ pos + i ].n;

    int nItems15 = NHUFFSYMBOLS - ( pos + i );

    HUFFINT nBits15;
    for ( nBits15=0 ;; ++nBits15 )
      if ( 1 << nBits15 >= nItems15 )
        break;

    assert( left >= nn );

    if ( nBits <= 8 && nBits15 <= 8 ) {
      int n = nn * nBits + ( left - nn ) * nBits15;

      if ( n < best ) {
        best = n;
        bestNBits   = nBits;
        bestNBits15 = nBits15;

      } else {
        break;  // PERF optimization
      }
    }
  }

  // (unused) int pos15 = pos + ( 1 << bestNBits );
  _addGroup( groups, 14, bestNBits );
  _addGroup( groups, 15, bestNBits15 );

  pos = 0;

  for ( HUFFUINT j=0; j < 16 ; ++j ) {
    HUFFINT nBits = groups[ j ];
    int nItems = 1 << nBits;
    int maxK = std::min( nItems, NHUFFSYMBOLS - pos );

    for ( HUFFUINT k=0; k < maxK ; ++k ) {
      HUFFINT symbol = s[ pos + k ].i;
      symbolTable[ symbol ].nBits = nBits + 4;
      symbolTable[ symbol ].code = (HUFFUINT)( j << nBits ) | k;
    }

    pos += 1 << nBits;
  }
}
bool LZHLDecompressor::decompress( uint8_t* dst, size_t* dstSz, const uint8_t* src, size_t* srcSz )
{
  uint8_t* startDst = dst;
  const uint8_t* startSrc = src;
  const uint8_t* endSrc = src + *srcSz;
  const uint8_t* endDst = dst + *dstSz;
  nBits = 0;

  for (;;) {
    int grp = _get( src, endSrc, 4 );
    if ( grp < 0 ) {
      return false;
    }

    Group& group = groupTable[ grp ];

    HUFFINT symbol;
    int nBits = group.nBits;

    if ( nBits == 0 ) {
      symbol = symbolTable[ group.pos ];
    } else {
      assert( nBits <= 8 );
      int got = _get( src, endSrc, nBits );

      if ( got < 0 ) {
        return false;
      }

      int pos = group.pos + got;

      if ( pos >= NHUFFSYMBOLS ) {
        return false;
      }

      symbol = symbolTable[ pos ];
    }

    assert( symbol < NHUFFSYMBOLS );
    ++stat[ symbol ];

    int matchOver;

    if ( symbol < 256 ) {
      if ( dst >= endDst ) {
        return false;
      }

      *dst++ = (uint8_t)symbol;
      _toBuf( (uint8_t)symbol );
      continue; //forever

    } else if ( symbol == NHUFFSYMBOLS - 2 ) {
      HuffStatTmpStruct s[ NHUFFSYMBOLS ];
      makeSortedTmp( s );

      for ( int i=0; i < NHUFFSYMBOLS ; ++i )
        symbolTable[ i ] = s[ i ].i;

      int lastNBits = 0;
      int pos = 0;

      for ( int i=0; i < 16 ; ++i ) {

        int n;
        for ( n=0 ;; ++n )
          if ( _get( src, endSrc, 1 ) )
            break;

        lastNBits += n;
        groupTable[ i ].nBits = lastNBits;
        groupTable[ i ].pos   = pos;

        pos += 1 << lastNBits;
      }

      assert( pos < NHUFFSYMBOLS + 255 );
      continue;  //forever


    } else if ( symbol == NHUFFSYMBOLS - 1 )
      break;    //forever

    static struct MatchOverItem {
      int nExtraBits;
      int base;
    } _matchOverTable[] = {
      { 1,   8 },
      { 2,  10 },
      { 3,  14 },
      { 4,  22 },
      { 5,  38 },
      { 6,  70 },
      { 7, 134 },
      { 8, 262 }
    };

    if ( symbol < 256 + 8 ) {
      matchOver = symbol - 256;
    } else {
      MatchOverItem* item = &_matchOverTable[ symbol - 256 - 8 ];
      int extra = _get( src, endSrc, item->nExtraBits );

      if ( extra < 0 ) {
        return false;
      }

      matchOver = item->base + extra;
    }

    int dispPrefix = _get( src, endSrc, 3 );

    if ( dispPrefix < 0 ) {
      return false;
    }

    static struct DispItem {
      int nBits;
      int disp;
    } _dispTable[] = {
      { 0,  0 },
      { 0,  1 },
      { 1,  2 },
      { 2,  4 },
      { 3,  8 },
      { 4, 16 },
      { 5, 32 },
      { 6, 64 }
    };

    DispItem* item = &_dispTable[ dispPrefix ];
    nBits = item->nBits + LZBUFBITS - 7;

    int disp = 0;
    assert( nBits <= 16 );

    if ( nBits > 8 ) {
      nBits -= 8;
      disp |= _get( src, endSrc, 8 ) << nBits;
    }

    assert( nBits <= 8 );
    int got = _get( src, endSrc, nBits );

    if ( got < 0 ) {
      return false;
    }

    disp |= got;
    disp += item->disp << (LZBUFBITS - 7);
    assert( disp >=0 && disp < LZBUFSIZE );

    int matchLen = matchOver + LZMIN;

    if ( dst + matchLen > endDst ) {
      return false;
    }

    int pos = bufPos - disp;
    if ( matchLen < disp ) {
      _bufCpy( dst, pos, matchLen );
    } else {
      _bufCpy( dst, pos, disp );

      for ( int i=0; i < matchLen - disp; ++i ) {
        dst[ i + disp ] = dst[ i ];
      }
    }

    _toBuf( dst, matchLen );
    dst += matchLen;

  } // forever

  if ( dstSz )
    *dstSz = dst - startDst;

  if ( srcSz )
    *srcSz = src - startSrc;

  return true;
}