misc/libphysfs/lzma/CPP/7zip/Compress/LZMA/LZMAEncoder.cpp
author nemo
Mon, 10 Apr 2017 12:06:43 -0400
changeset 12218 bb5522e88ab2
permissions -rw-r--r--
bulk copy of latest physfs to our misc/libphysfs since this seems to fix an off-by-1 error reliably hit in readln read of 1 byte probably introduced in the addition of the buffered read. Whether this is excessive or whether libphysfs should even be maintained by us is another matter. But at least we shouldn't crash

// LZMA/Encoder.cpp

#include "StdAfx.h"

#include <stdio.h>

#ifdef _WIN32
#define USE_ALLOCA
#endif

#ifdef USE_ALLOCA
#ifdef _WIN32
#include <malloc.h>
#else
#include <stdlib.h>
#endif
#endif

#include "../../../Common/Defs.h"
#include "../../Common/StreamUtils.h"

#include "LZMAEncoder.h"

// extern "C" { #include "../../../../C/7zCrc.h" }

// #define SHOW_STAT


namespace NCompress {
namespace NLZMA {

// struct CCrcInit { CCrcInit() { InitCrcTable(); } } g_CrcInit;

const int kDefaultDictionaryLogSize = 22;
const UInt32 kNumFastBytesDefault = 0x20;

#ifndef LZMA_LOG_BSR
Byte g_FastPos[1 << kNumLogBits];

class CFastPosInit
{
public:
  CFastPosInit() { Init(); }
  void Init()
  {
    const Byte kFastSlots = kNumLogBits * 2;
    int c = 2;
    g_FastPos[0] = 0;
    g_FastPos[1] = 1;

    for (Byte slotFast = 2; slotFast < kFastSlots; slotFast++)
    {
      UInt32 k = (1 << ((slotFast >> 1) - 1));
      for (UInt32 j = 0; j < k; j++, c++)
        g_FastPos[c] = slotFast;
    }
  }
} g_FastPosInit;
#endif

void CLiteralEncoder2::Encode(NRangeCoder::CEncoder *rangeEncoder, Byte symbol)
{
  UInt32 context = 1;
  int i = 8;
  do 
  {
    i--;
    UInt32 bit = (symbol >> i) & 1;
    _encoders[context].Encode(rangeEncoder, bit);
    context = (context << 1) | bit;
  }
  while(i != 0);
}

void CLiteralEncoder2::EncodeMatched(NRangeCoder::CEncoder *rangeEncoder, 
    Byte matchByte, Byte symbol)
{
  UInt32 context = 1;
  int i = 8;
  do 
  {
    i--;
    UInt32 bit = (symbol >> i) & 1;
    UInt32 matchBit = (matchByte >> i) & 1;
    _encoders[0x100 + (matchBit << 8) + context].Encode(rangeEncoder, bit);
    context = (context << 1) | bit;
    if (matchBit != bit)
    {
      while(i != 0)
      {
        i--;
        UInt32 bit = (symbol >> i) & 1;
        _encoders[context].Encode(rangeEncoder, bit);
        context = (context << 1) | bit;
      }
      break;
    }
  }
  while(i != 0);
}

UInt32 CLiteralEncoder2::GetPrice(bool matchMode, Byte matchByte, Byte symbol) const
{
  UInt32 price = 0;
  UInt32 context = 1;
  int i = 8;
  if (matchMode)
  {
    do 
    {
      i--;
      UInt32 matchBit = (matchByte >> i) & 1;
      UInt32 bit = (symbol >> i) & 1;
      price += _encoders[0x100 + (matchBit << 8) + context].GetPrice(bit);
      context = (context << 1) | bit;
      if (matchBit != bit)
        break;
    }
    while (i != 0);
  }
  while(i != 0)
  {
    i--;
    UInt32 bit = (symbol >> i) & 1;
    price += _encoders[context].GetPrice(bit);
    context = (context << 1) | bit;
  }
  return price;
};


namespace NLength {

void CEncoder::Init(UInt32 numPosStates)
{
  _choice.Init();
  _choice2.Init();
  for (UInt32 posState = 0; posState < numPosStates; posState++)
  {
    _lowCoder[posState].Init();
    _midCoder[posState].Init();
  }
  _highCoder.Init();
}

void CEncoder::Encode(NRangeCoder::CEncoder *rangeEncoder, UInt32 symbol, UInt32 posState)
{
  if(symbol < kNumLowSymbols)
  {
    _choice.Encode(rangeEncoder, 0);
    _lowCoder[posState].Encode(rangeEncoder, symbol);
  }
  else
  {
    _choice.Encode(rangeEncoder, 1);
    if(symbol < kNumLowSymbols + kNumMidSymbols)
    {
      _choice2.Encode(rangeEncoder, 0);
      _midCoder[posState].Encode(rangeEncoder, symbol - kNumLowSymbols);
    }
    else
    {
      _choice2.Encode(rangeEncoder, 1);
      _highCoder.Encode(rangeEncoder, symbol - kNumLowSymbols - kNumMidSymbols);
    }
  }
}

void CEncoder::SetPrices(UInt32 posState, UInt32 numSymbols, UInt32 *prices) const
{
  UInt32 a0 = _choice.GetPrice0();
  UInt32 a1 = _choice.GetPrice1();
  UInt32 b0 = a1 + _choice2.GetPrice0();
  UInt32 b1 = a1 + _choice2.GetPrice1();
  UInt32 i = 0;
  for (i = 0; i < kNumLowSymbols; i++)
  {
    if (i >= numSymbols)
      return;
    prices[i] = a0 + _lowCoder[posState].GetPrice(i);
  }
  for (; i < kNumLowSymbols + kNumMidSymbols; i++)
  {
    if (i >= numSymbols)
      return;
    prices[i] = b0 + _midCoder[posState].GetPrice(i - kNumLowSymbols);
  }
  for (; i < numSymbols; i++)
    prices[i] = b1 + _highCoder.GetPrice(i - kNumLowSymbols - kNumMidSymbols);
}

}

CEncoder::CEncoder():
  _numFastBytes(kNumFastBytesDefault),
  _distTableSize(kDefaultDictionaryLogSize * 2),
  _posStateBits(2),
  _posStateMask(4 - 1),
  _numLiteralPosStateBits(0),
  _numLiteralContextBits(3),
  _dictionarySize(1 << kDefaultDictionaryLogSize),
  _matchFinderCycles(0),
  #ifdef COMPRESS_MF_MT
  _multiThread(false),
  #endif
  _writeEndMark(false)
{
  MatchFinder_Construct(&_matchFinderBase);
  // _maxMode = false;
  _fastMode = false;
  #ifdef COMPRESS_MF_MT
  MatchFinderMt_Construct(&_matchFinderMt);
  _matchFinderMt.MatchFinder = &_matchFinderBase;
  #endif
}


static void *SzAlloc(size_t size) { return BigAlloc(size); }
static void SzFree(void *address) { BigFree(address); }
ISzAlloc g_Alloc = { SzAlloc, SzFree };

CEncoder::~CEncoder()
{
  #ifdef COMPRESS_MF_MT
  MatchFinderMt_Destruct(&_matchFinderMt, &g_Alloc);
  #endif
  MatchFinder_Free(&_matchFinderBase, &g_Alloc);
}

static const UInt32 kBigHashDicLimit = (UInt32)1 << 24;

HRESULT CEncoder::Create()
{
  if (!_rangeEncoder.Create(1 << 20))
    return E_OUTOFMEMORY;
  bool btMode = (_matchFinderBase.btMode != 0);
  #ifdef COMPRESS_MF_MT
  _mtMode = (_multiThread && !_fastMode && btMode);
  #endif
  
  if (!_literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits))
    return E_OUTOFMEMORY;

  _matchFinderBase.bigHash = (_dictionarySize > kBigHashDicLimit);

  UInt32 numCycles = 16 + (_numFastBytes >> 1);
  if (!btMode)
    numCycles >>= 1;
  if (_matchFinderCycles != 0)
    numCycles = _matchFinderCycles;
  _matchFinderBase.cutValue = numCycles;
  #ifdef COMPRESS_MF_MT
  if (_mtMode)
  {
    RINOK(MatchFinderMt_Create(&_matchFinderMt, _dictionarySize, kNumOpts, _numFastBytes, kMatchMaxLen, &g_Alloc));
    _matchFinderObj = &_matchFinderMt;
    MatchFinderMt_CreateVTable(&_matchFinderMt, &_matchFinder);
  }
  else
  #endif
  {
    if (!MatchFinder_Create(&_matchFinderBase, _dictionarySize, kNumOpts, _numFastBytes, kMatchMaxLen, &g_Alloc))
      return E_OUTOFMEMORY;
    _matchFinderObj = &_matchFinderBase;
    MatchFinder_CreateVTable(&_matchFinderBase, &_matchFinder);
  }
  return S_OK;
}

inline wchar_t GetUpperChar(wchar_t c)
{
  if (c >= 'a' && c <= 'z')
    c -= 0x20;
  return c;
}

static int ParseMatchFinder(const wchar_t *s, int *btMode, UInt32 *numHashBytes /* , int *skipModeBits */)
{
  wchar_t c = GetUpperChar(*s++);
  if (c == L'H')
  {
    if (GetUpperChar(*s++) != L'C')
      return 0;
    int numHashBytesLoc = (int)(*s++ - L'0');
    if (numHashBytesLoc < 4 || numHashBytesLoc > 4)
      return 0;
    if (*s++ != 0)
      return 0;
    *btMode = 0;
    *numHashBytes = numHashBytesLoc;
    return 1;
  }
  if (c != L'B')
    return 0;

  if (GetUpperChar(*s++) != L'T')
    return 0;
  int numHashBytesLoc = (int)(*s++ - L'0');
  if (numHashBytesLoc < 2 || numHashBytesLoc > 4)
    return 0;
  c = GetUpperChar(*s++);
  /*
  int skipModeBitsLoc = 0;
  if (c == L'D')
  {
    skipModeBitsLoc = 2;
    c = GetUpperChar(*s++);
  }
  */
  if (c != L'\0')
    return 0;
  *btMode = 1;
  *numHashBytes = numHashBytesLoc;
  // *skipModeBits = skipModeBitsLoc;
  return 1;
}

STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, 
    const PROPVARIANT *properties, UInt32 numProperties)
{
  for (UInt32 i = 0; i < numProperties; i++)
  {
    const PROPVARIANT &prop = properties[i];
    switch(propIDs[i])
    {
      case NCoderPropID::kNumFastBytes:
      {
        if (prop.vt != VT_UI4)
          return E_INVALIDARG;
        UInt32 numFastBytes = prop.ulVal;
        if(numFastBytes < 5 || numFastBytes > kMatchMaxLen)
          return E_INVALIDARG;
        _numFastBytes = numFastBytes;
        break;
      }
      case NCoderPropID::kMatchFinderCycles:
      {
        if (prop.vt != VT_UI4)
          return E_INVALIDARG;
        _matchFinderCycles = prop.ulVal;
        break;
      }
      case NCoderPropID::kAlgorithm:
      {
        if (prop.vt != VT_UI4)
          return E_INVALIDARG;
        UInt32 maximize = prop.ulVal;
        _fastMode = (maximize == 0); 
        // _maxMode = (maximize >= 2);
        break;
      }
      case NCoderPropID::kMatchFinder:
      {
        if (prop.vt != VT_BSTR)
          return E_INVALIDARG;
        if (!ParseMatchFinder(prop.bstrVal, &_matchFinderBase.btMode, &_matchFinderBase.numHashBytes /* , &_matchFinderBase.skipModeBits */))
          return E_INVALIDARG;
        break;
      }
      case NCoderPropID::kMultiThread:
      {
        if (prop.vt != VT_BOOL)
          return E_INVALIDARG;
        #ifdef COMPRESS_MF_MT
        Bool newMultiThread = (prop.boolVal == VARIANT_TRUE);
        if (newMultiThread != _multiThread)
        {
          ReleaseMatchFinder();
          _multiThread = newMultiThread;
        }
        #endif
        break;
      }
      case NCoderPropID::kNumThreads:
      {
        if (prop.vt != VT_UI4)
          return E_INVALIDARG;
        #ifdef COMPRESS_MF_MT
        Bool newMultiThread = (prop.ulVal > 1) ? True : False;
        if (newMultiThread != _multiThread)
        {
          ReleaseMatchFinder();
          _multiThread = newMultiThread;
        }
        #endif
        break;
      }
      case NCoderPropID::kDictionarySize:
      {
        const int kDicLogSizeMaxCompress = 30; // must be <= ((kNumLogBits - 1) * 2) + 7 = 31;
        if (prop.vt != VT_UI4)
          return E_INVALIDARG;
        UInt32 dictionarySize = prop.ulVal;
        if (dictionarySize < UInt32(1 << kDicLogSizeMin) ||
            dictionarySize > UInt32(1 << kDicLogSizeMaxCompress))
          return E_INVALIDARG;
        _dictionarySize = dictionarySize;
        UInt32 dicLogSize;
        for(dicLogSize = 0; dicLogSize < (UInt32)kDicLogSizeMaxCompress; dicLogSize++)
          if (dictionarySize <= (UInt32(1) << dicLogSize))
            break;
        _distTableSize = dicLogSize * 2;
        break;
      }
      case NCoderPropID::kPosStateBits:
      {
        if (prop.vt != VT_UI4)
          return E_INVALIDARG;
        UInt32 value = prop.ulVal;
        if (value > (UInt32)NLength::kNumPosStatesBitsEncodingMax)
          return E_INVALIDARG;
        _posStateBits = value;
        _posStateMask = (1 << _posStateBits) - 1;
        break;
      }
      case NCoderPropID::kLitPosBits:
      {
        if (prop.vt != VT_UI4)
          return E_INVALIDARG;
        UInt32 value = prop.ulVal;
        if (value > (UInt32)kNumLitPosStatesBitsEncodingMax)
          return E_INVALIDARG;
        _numLiteralPosStateBits = value;
        break;
      }
      case NCoderPropID::kLitContextBits:
      {
        if (prop.vt != VT_UI4)
          return E_INVALIDARG;
        UInt32 value = prop.ulVal;
        if (value > (UInt32)kNumLitContextBitsMax)
          return E_INVALIDARG;
        _numLiteralContextBits = value;
        break;
      }
      case NCoderPropID::kEndMarker:
      {
        if (prop.vt != VT_BOOL)
          return E_INVALIDARG;
        SetWriteEndMarkerMode(prop.boolVal == VARIANT_TRUE);
        break;
      }
      default:
        return E_INVALIDARG;
    }
  }
  return S_OK;
}

STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
{ 
  const UInt32 kPropSize = 5;
  Byte properties[kPropSize];
  properties[0] = (Byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits);
  for (int i = 0; i < 4; i++)
    properties[1 + i] = Byte(_dictionarySize >> (8 * i));
  return WriteStream(outStream, properties, kPropSize, NULL);
}

STDMETHODIMP CEncoder::SetOutStream(ISequentialOutStream *outStream)
{
  _rangeEncoder.SetStream(outStream);
  return S_OK;
}

STDMETHODIMP CEncoder::ReleaseOutStream()
{
  _rangeEncoder.ReleaseStream();
  return S_OK;
}

HRESULT CEncoder::Init()
{
  CBaseState::Init();

  _rangeEncoder.Init();

  for(int i = 0; i < kNumStates; i++)
  {
    for (UInt32 j = 0; j <= _posStateMask; j++)
    {
      _isMatch[i][j].Init();
      _isRep0Long[i][j].Init();
    }
    _isRep[i].Init();
    _isRepG0[i].Init();
    _isRepG1[i].Init();
    _isRepG2[i].Init();
  }

  _literalEncoder.Init();

  {
    for(UInt32 i = 0; i < kNumLenToPosStates; i++)
      _posSlotEncoder[i].Init();
  }
  {
    for(UInt32 i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
      _posEncoders[i].Init();
  }

  _lenEncoder.Init(1 << _posStateBits);
  _repMatchLenEncoder.Init(1 << _posStateBits);

  _posAlignEncoder.Init();

  _longestMatchWasFound = false;
  _optimumEndIndex = 0;
  _optimumCurrentIndex = 0;
  _additionalOffset = 0;

  return S_OK;
}

#ifdef SHOW_STAT
static int ttt = 0;
#endif

void CEncoder::MovePos(UInt32 num)
{
  #ifdef SHOW_STAT
  ttt += num;
  printf("\n MovePos %d", num);
  #endif
  if (num != 0)
  {
    _additionalOffset += num;
    _matchFinder.Skip(_matchFinderObj, num);
  }
}

UInt32 CEncoder::Backward(UInt32 &backRes, UInt32 cur)
{
  _optimumEndIndex = cur;
  UInt32 posMem = _optimum[cur].PosPrev;
  UInt32 backMem = _optimum[cur].BackPrev;
  do
  {
    if (_optimum[cur].Prev1IsChar)
    {
      _optimum[posMem].MakeAsChar();
      _optimum[posMem].PosPrev = posMem - 1;
      if (_optimum[cur].Prev2)
      {
        _optimum[posMem - 1].Prev1IsChar = false;
        _optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2;
        _optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2;
      }
    }
    UInt32 posPrev = posMem;
    UInt32 backCur = backMem;

    backMem = _optimum[posPrev].BackPrev;
    posMem = _optimum[posPrev].PosPrev;

    _optimum[posPrev].BackPrev = backCur;
    _optimum[posPrev].PosPrev = cur;
    cur = posPrev;
  }
  while(cur != 0);
  backRes = _optimum[0].BackPrev;
  _optimumCurrentIndex  = _optimum[0].PosPrev;
  return _optimumCurrentIndex; 
}

/*
Out:
  (lenRes == 1) && (backRes == 0xFFFFFFFF) means Literal
*/

UInt32 CEncoder::GetOptimum(UInt32 position, UInt32 &backRes)
{
  if(_optimumEndIndex != _optimumCurrentIndex)
  {
    const COptimal &optimum = _optimum[_optimumCurrentIndex];
    UInt32 lenRes = optimum.PosPrev - _optimumCurrentIndex;
    backRes = optimum.BackPrev;
    _optimumCurrentIndex = optimum.PosPrev;
    return lenRes;
  }
  _optimumCurrentIndex = _optimumEndIndex = 0;
  
  UInt32 numAvailableBytes = _matchFinder.GetNumAvailableBytes(_matchFinderObj);

  UInt32 lenMain, numDistancePairs;
  if (!_longestMatchWasFound)
  {
    lenMain = ReadMatchDistances(numDistancePairs);
  }
  else
  {
    lenMain = _longestMatchLength;
    numDistancePairs = _numDistancePairs;
    _longestMatchWasFound = false;
  }

  const Byte *data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1;
  if (numAvailableBytes < 2)
  {
    backRes = (UInt32)(-1);
    return 1;
  }
  if (numAvailableBytes > kMatchMaxLen)
    numAvailableBytes = kMatchMaxLen;

  UInt32 reps[kNumRepDistances];
  UInt32 repLens[kNumRepDistances];
  UInt32 repMaxIndex = 0;
  UInt32 i;
  for(i = 0; i < kNumRepDistances; i++)
  {
    reps[i] = _repDistances[i];
    const Byte *data2 = data - (reps[i] + 1);
    if (data[0] != data2[0] || data[1] != data2[1])
    {
      repLens[i] = 0;
      continue;
    }
    UInt32 lenTest;
    for (lenTest = 2; lenTest < numAvailableBytes && data[lenTest] == data2[lenTest]; lenTest++);
    repLens[i] = lenTest;
    if (lenTest > repLens[repMaxIndex])
      repMaxIndex = i;
  }
  if(repLens[repMaxIndex] >= _numFastBytes)
  {
    backRes = repMaxIndex;
    UInt32 lenRes = repLens[repMaxIndex];
    MovePos(lenRes - 1);
    return lenRes;
  }

  UInt32 *matchDistances = _matchDistances;
  if(lenMain >= _numFastBytes)
  {
    backRes = matchDistances[numDistancePairs - 1] + kNumRepDistances; 
    MovePos(lenMain - 1);
    return lenMain;
  }
  Byte currentByte = *data;
  Byte matchByte = *(data - (reps[0] + 1));

  if(lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2)
  {
    backRes = (UInt32)-1;
    return 1;
  }

  _optimum[0].State = _state;

  UInt32 posState = (position & _posStateMask);

  _optimum[1].Price = _isMatch[_state.Index][posState].GetPrice0() + 
      _literalEncoder.GetSubCoder(position, _previousByte)->GetPrice(!_state.IsCharState(), matchByte, currentByte);
  _optimum[1].MakeAsChar();

  UInt32 matchPrice = _isMatch[_state.Index][posState].GetPrice1();
  UInt32 repMatchPrice = matchPrice + _isRep[_state.Index].GetPrice1();

  if(matchByte == currentByte)
  {
    UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState);
    if(shortRepPrice < _optimum[1].Price)
    {
      _optimum[1].Price = shortRepPrice;
      _optimum[1].MakeAsShortRep();
    }
  }
  UInt32 lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]);

  if(lenEnd < 2)
  {
    backRes = _optimum[1].BackPrev;
    return 1;
  }

  _optimum[1].PosPrev = 0;
  for (i = 0; i < kNumRepDistances; i++)
    _optimum[0].Backs[i] = reps[i];

  UInt32 len = lenEnd;
  do
    _optimum[len--].Price = kIfinityPrice;
  while (len >= 2);

  for(i = 0; i < kNumRepDistances; i++)
  {
    UInt32 repLen = repLens[i];
    if (repLen < 2)
      continue;
    UInt32 price = repMatchPrice + GetPureRepPrice(i, _state, posState);
    do
    {
      UInt32 curAndLenPrice = price + _repMatchLenEncoder.GetPrice(repLen - 2, posState);
      COptimal &optimum = _optimum[repLen];
      if (curAndLenPrice < optimum.Price) 
      {
        optimum.Price = curAndLenPrice;
        optimum.PosPrev = 0;
        optimum.BackPrev = i;
        optimum.Prev1IsChar = false;
      }
    }
    while(--repLen >= 2);
  }

  UInt32 normalMatchPrice = matchPrice + _isRep[_state.Index].GetPrice0();

  len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
  if (len <= lenMain)
  {
    UInt32 offs = 0;
    while (len > matchDistances[offs])
      offs += 2;
    for(; ; len++)
    {
      UInt32 distance = matchDistances[offs + 1];
      UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(distance, len, posState);
      COptimal &optimum = _optimum[len];
      if (curAndLenPrice < optimum.Price) 
      {
        optimum.Price = curAndLenPrice;
        optimum.PosPrev = 0;
        optimum.BackPrev = distance + kNumRepDistances;
        optimum.Prev1IsChar = false;
      }
      if (len == matchDistances[offs])
      {
        offs += 2;
        if (offs == numDistancePairs)
          break;
      }
    }
  }

  UInt32 cur = 0;

  for (;;)
  {
    cur++;
    if(cur == lenEnd)
    {
      return Backward(backRes, cur);
    }
    UInt32 numAvailableBytesFull = _matchFinder.GetNumAvailableBytes(_matchFinderObj);
    UInt32 newLen, numDistancePairs;
    newLen = ReadMatchDistances(numDistancePairs);
    if(newLen >= _numFastBytes)
    {
      _numDistancePairs = numDistancePairs;
      _longestMatchLength = newLen;
      _longestMatchWasFound = true;
      return Backward(backRes, cur);
    }
    position++;
    COptimal &curOptimum = _optimum[cur];
    UInt32 posPrev = curOptimum.PosPrev;
    CState state;
    if (curOptimum.Prev1IsChar)
    {
      posPrev--;
      if (curOptimum.Prev2)
      {
        state = _optimum[curOptimum.PosPrev2].State;
        if (curOptimum.BackPrev2 < kNumRepDistances)
          state.UpdateRep();
        else
          state.UpdateMatch();
      }
      else
        state = _optimum[posPrev].State;
      state.UpdateChar();
    }
    else
      state = _optimum[posPrev].State;
    if (posPrev == cur - 1)
    {
      if (curOptimum.IsShortRep())
        state.UpdateShortRep();
      else
        state.UpdateChar();
    }
    else
    {
      UInt32 pos;
      if (curOptimum.Prev1IsChar && curOptimum.Prev2)
      {
        posPrev = curOptimum.PosPrev2;
        pos = curOptimum.BackPrev2;
        state.UpdateRep();
      }
      else
      {
        pos = curOptimum.BackPrev;
        if (pos < kNumRepDistances)
          state.UpdateRep();
        else
          state.UpdateMatch();
      }
      const COptimal &prevOptimum = _optimum[posPrev];
      if (pos < kNumRepDistances)
      {
        reps[0] = prevOptimum.Backs[pos];
        UInt32 i;
        for(i = 1; i <= pos; i++)
          reps[i] = prevOptimum.Backs[i - 1];
        for(; i < kNumRepDistances; i++)
          reps[i] = prevOptimum.Backs[i];
      }
      else
      {
        reps[0] = (pos - kNumRepDistances);
        for(UInt32 i = 1; i < kNumRepDistances; i++)
          reps[i] = prevOptimum.Backs[i - 1];
      }
    }
    curOptimum.State = state;
    for(UInt32 i = 0; i < kNumRepDistances; i++)
      curOptimum.Backs[i] = reps[i];
    UInt32 curPrice = curOptimum.Price; 
    const Byte *data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1;
    const Byte currentByte = *data;
    const Byte matchByte = *(data - (reps[0] + 1));

    UInt32 posState = (position & _posStateMask);

    UInt32 curAnd1Price = curPrice +
        _isMatch[state.Index][posState].GetPrice0() +
        _literalEncoder.GetSubCoder(position, *(data - 1))->GetPrice(!state.IsCharState(), matchByte, currentByte);

    COptimal &nextOptimum = _optimum[cur + 1];

    bool nextIsChar = false;
    if (curAnd1Price < nextOptimum.Price) 
    {
      nextOptimum.Price = curAnd1Price;
      nextOptimum.PosPrev = cur;
      nextOptimum.MakeAsChar();
      nextIsChar = true;
    }

    UInt32 matchPrice = curPrice + _isMatch[state.Index][posState].GetPrice1();
    UInt32 repMatchPrice = matchPrice + _isRep[state.Index].GetPrice1();
    
    if(matchByte == currentByte &&
        !(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0))
    {
      UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState);
      if(shortRepPrice <= nextOptimum.Price)
      {
        nextOptimum.Price = shortRepPrice;
        nextOptimum.PosPrev = cur;
        nextOptimum.MakeAsShortRep();
        nextIsChar = true;
      }
    }
    /*
    if(newLen == 2 && matchDistances[2] >= kDistLimit2) // test it maybe set 2000 ?
      continue;
    */

    numAvailableBytesFull = MyMin(kNumOpts - 1 - cur, numAvailableBytesFull);
    UInt32 numAvailableBytes = numAvailableBytesFull;

    if (numAvailableBytes < 2)
      continue;
    if (numAvailableBytes > _numFastBytes)
      numAvailableBytes = _numFastBytes;
    if (!nextIsChar && matchByte != currentByte) // speed optimization
    {
      // try Literal + rep0
      const Byte *data2 = data - (reps[0] + 1);
      UInt32 limit = MyMin(numAvailableBytesFull, _numFastBytes + 1);
      UInt32 temp;
      for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++);
      UInt32 lenTest2 = temp - 1;
      if (lenTest2 >= 2)
      {
        CState state2 = state;
        state2.UpdateChar();
        UInt32 posStateNext = (position + 1) & _posStateMask;
        UInt32 nextRepMatchPrice = curAnd1Price + 
            _isMatch[state2.Index][posStateNext].GetPrice1() +
            _isRep[state2.Index].GetPrice1();
        // for (; lenTest2 >= 2; lenTest2--)
        {
          UInt32 offset = cur + 1 + lenTest2;
          while(lenEnd < offset)
            _optimum[++lenEnd].Price = kIfinityPrice;
          UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
              0, lenTest2, state2, posStateNext);
          COptimal &optimum = _optimum[offset];
          if (curAndLenPrice < optimum.Price) 
          {
            optimum.Price = curAndLenPrice;
            optimum.PosPrev = cur + 1;
            optimum.BackPrev = 0;
            optimum.Prev1IsChar = true;
            optimum.Prev2 = false;
          }
        }
      }
    }
    
    UInt32 startLen = 2; // speed optimization 
    for(UInt32 repIndex = 0; repIndex < kNumRepDistances; repIndex++)
    {
      // UInt32 repLen = _matchFinder.GetMatchLen(0 - 1, reps[repIndex], newLen); // test it;
      const Byte *data2 = data - (reps[repIndex] + 1);
      if (data[0] != data2[0] || data[1] != data2[1])
        continue;
      UInt32 lenTest;
      for (lenTest = 2; lenTest < numAvailableBytes && data[lenTest] == data2[lenTest]; lenTest++);
      while(lenEnd < cur + lenTest)
        _optimum[++lenEnd].Price = kIfinityPrice;
      UInt32 lenTestTemp = lenTest;
      UInt32 price = repMatchPrice + GetPureRepPrice(repIndex, state, posState);
      do
      {
        UInt32 curAndLenPrice = price + _repMatchLenEncoder.GetPrice(lenTest - 2, posState);
        COptimal &optimum = _optimum[cur + lenTest];
        if (curAndLenPrice < optimum.Price) 
        {
          optimum.Price = curAndLenPrice;
          optimum.PosPrev = cur;
          optimum.BackPrev = repIndex;
          optimum.Prev1IsChar = false;
        }
      }
      while(--lenTest >= 2);
      lenTest = lenTestTemp;
      
      if (repIndex == 0)
        startLen = lenTest + 1;
        
      // if (_maxMode)
        {
          UInt32 lenTest2 = lenTest + 1;
          UInt32 limit = MyMin(numAvailableBytesFull, lenTest2 + _numFastBytes);
          for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
          lenTest2 -= lenTest + 1;
          if (lenTest2 >= 2)
          {
            CState state2 = state;
            state2.UpdateRep();
            UInt32 posStateNext = (position + lenTest) & _posStateMask;
            UInt32 curAndLenCharPrice = 
                price + _repMatchLenEncoder.GetPrice(lenTest - 2, posState) + 
                _isMatch[state2.Index][posStateNext].GetPrice0() +
                _literalEncoder.GetSubCoder(position + lenTest, data[lenTest - 1])->GetPrice(
                true, data2[lenTest], data[lenTest]);
            state2.UpdateChar();
            posStateNext = (position + lenTest + 1) & _posStateMask;
            UInt32 nextRepMatchPrice = curAndLenCharPrice + 
                _isMatch[state2.Index][posStateNext].GetPrice1() +
                _isRep[state2.Index].GetPrice1();
            
            // for(; lenTest2 >= 2; lenTest2--)
            {
              UInt32 offset = cur + lenTest + 1 + lenTest2;
              while(lenEnd < offset)
                _optimum[++lenEnd].Price = kIfinityPrice;
              UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
                  0, lenTest2, state2, posStateNext);
              COptimal &optimum = _optimum[offset];
              if (curAndLenPrice < optimum.Price) 
              {
                optimum.Price = curAndLenPrice;
                optimum.PosPrev = cur + lenTest + 1;
                optimum.BackPrev = 0;
                optimum.Prev1IsChar = true;
                optimum.Prev2 = true;
                optimum.PosPrev2 = cur;
                optimum.BackPrev2 = repIndex;
              }
            }
          }
        }
      }
    
    //    for(UInt32 lenTest = 2; lenTest <= newLen; lenTest++)
    if (newLen > numAvailableBytes)
    {
      newLen = numAvailableBytes;
      for (numDistancePairs = 0; newLen > matchDistances[numDistancePairs]; numDistancePairs += 2);
      matchDistances[numDistancePairs] = newLen;
      numDistancePairs += 2;
    }
    if (newLen >= startLen)
    {
      UInt32 normalMatchPrice = matchPrice + _isRep[state.Index].GetPrice0();
      while(lenEnd < cur + newLen)
        _optimum[++lenEnd].Price = kIfinityPrice;

      UInt32 offs = 0;
      while(startLen > matchDistances[offs])
        offs += 2;
      UInt32 curBack = matchDistances[offs + 1];
      UInt32 posSlot = GetPosSlot2(curBack);
      for(UInt32 lenTest = /*2*/ startLen; ; lenTest++)
      {
        UInt32 curAndLenPrice = normalMatchPrice;
        UInt32 lenToPosState = GetLenToPosState(lenTest);
        if (curBack < kNumFullDistances)
          curAndLenPrice += _distancesPrices[lenToPosState][curBack];
        else
          curAndLenPrice += _posSlotPrices[lenToPosState][posSlot] + _alignPrices[curBack & kAlignMask];
  
        curAndLenPrice += _lenEncoder.GetPrice(lenTest - kMatchMinLen, posState);
        
        COptimal &optimum = _optimum[cur + lenTest];
        if (curAndLenPrice < optimum.Price) 
        {
          optimum.Price = curAndLenPrice;
          optimum.PosPrev = cur;
          optimum.BackPrev = curBack + kNumRepDistances;
          optimum.Prev1IsChar = false;
        }

        if (/*_maxMode && */lenTest == matchDistances[offs])
        {
          // Try Match + Literal + Rep0
          const Byte *data2 = data - (curBack + 1);
          UInt32 lenTest2 = lenTest + 1;
          UInt32 limit = MyMin(numAvailableBytesFull, lenTest2 + _numFastBytes);
          for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
          lenTest2 -= lenTest + 1;
          if (lenTest2 >= 2)
          {
            CState state2 = state;
            state2.UpdateMatch();
            UInt32 posStateNext = (position + lenTest) & _posStateMask;
            UInt32 curAndLenCharPrice = curAndLenPrice + 
                _isMatch[state2.Index][posStateNext].GetPrice0() +
                _literalEncoder.GetSubCoder(position + lenTest, data[lenTest - 1])->GetPrice( 
                true, data2[lenTest], data[lenTest]);
            state2.UpdateChar();
            posStateNext = (posStateNext + 1) & _posStateMask;
            UInt32 nextRepMatchPrice = curAndLenCharPrice + 
                _isMatch[state2.Index][posStateNext].GetPrice1() +
                _isRep[state2.Index].GetPrice1();
            
            // for(; lenTest2 >= 2; lenTest2--)
            {
              UInt32 offset = cur + lenTest + 1 + lenTest2;
              while(lenEnd < offset)
                _optimum[++lenEnd].Price = kIfinityPrice;
              UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
              COptimal &optimum = _optimum[offset];
              if (curAndLenPrice < optimum.Price) 
              {
                optimum.Price = curAndLenPrice;
                optimum.PosPrev = cur + lenTest + 1;
                optimum.BackPrev = 0;
                optimum.Prev1IsChar = true;
                optimum.Prev2 = true;
                optimum.PosPrev2 = cur;
                optimum.BackPrev2 = curBack + kNumRepDistances;
              }
            }
          }
          offs += 2;
          if (offs == numDistancePairs)
            break;
          curBack = matchDistances[offs + 1];
          if (curBack >= kNumFullDistances)
            posSlot = GetPosSlot2(curBack);
        }
      }
    }
  }
}

static inline bool ChangePair(UInt32 smallDist, UInt32 bigDist)
{
  return ((bigDist >> 7) > smallDist);
}

UInt32 CEncoder::ReadMatchDistances(UInt32 &numDistancePairs)
{
  UInt32 lenRes = 0;
  numDistancePairs = _matchFinder.GetMatches(_matchFinderObj, _matchDistances);
  #ifdef SHOW_STAT
  printf("\n i = %d numPairs = %d    ", ttt, numDistancePairs / 2);
  if (ttt >= 61994)
    ttt = ttt;

  ttt++;
  for (UInt32 i = 0; i < numDistancePairs; i += 2)
    printf("%2d %6d   | ", _matchDistances[i], _matchDistances[i + 1]);
  #endif
  if (numDistancePairs > 0)
  {
    lenRes = _matchDistances[numDistancePairs - 2];
    if (lenRes == _numFastBytes)
    {
      UInt32 numAvail = _matchFinder.GetNumAvailableBytes(_matchFinderObj) + 1;
      const Byte *pby = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1;
      UInt32 distance = _matchDistances[numDistancePairs - 1] + 1;
      if (numAvail > kMatchMaxLen)
        numAvail = kMatchMaxLen;

      const Byte *pby2 = pby - distance;
      for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++);
    }
  }
  _additionalOffset++;
  return lenRes;
}

UInt32 CEncoder::GetOptimumFast(UInt32 &backRes)
{
  UInt32 numAvailableBytes = _matchFinder.GetNumAvailableBytes(_matchFinderObj);
  UInt32 lenMain, numDistancePairs;
  if (!_longestMatchWasFound)
  {
    lenMain = ReadMatchDistances(numDistancePairs);
  }
  else
  {
    lenMain = _longestMatchLength;
    numDistancePairs = _numDistancePairs;
    _longestMatchWasFound = false;
  }

  const Byte *data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1;
  if (numAvailableBytes > kMatchMaxLen)
    numAvailableBytes = kMatchMaxLen;
  if (numAvailableBytes < 2)
  {
    backRes = (UInt32)(-1);
    return 1;
  }

  UInt32 repLens[kNumRepDistances];
  UInt32 repMaxIndex = 0;

  for(UInt32 i = 0; i < kNumRepDistances; i++)
  {
    const Byte *data2 = data - (_repDistances[i] + 1);
    if (data[0] != data2[0] || data[1] != data2[1])
    {
      repLens[i] = 0;
      continue;
    }
    UInt32 len;
    for (len = 2; len < numAvailableBytes && data[len] == data2[len]; len++);
    if(len >= _numFastBytes)
    {
      backRes = i;
      MovePos(len - 1);
      return len;
    }
    repLens[i] = len;
    if (len > repLens[repMaxIndex])
      repMaxIndex = i;
  }
  UInt32 *matchDistances = _matchDistances;
  if(lenMain >= _numFastBytes)
  {
    backRes = matchDistances[numDistancePairs - 1] + kNumRepDistances; 
    MovePos(lenMain - 1);
    return lenMain;
  }

  UInt32 backMain = 0; // for GCC
  if (lenMain >= 2)
  {
    backMain = matchDistances[numDistancePairs - 1];
    while (numDistancePairs > 2 && lenMain == matchDistances[numDistancePairs - 4] + 1)
    {
      if (!ChangePair(matchDistances[numDistancePairs - 3], backMain))
        break;
      numDistancePairs -= 2;
      lenMain = matchDistances[numDistancePairs - 2];
      backMain = matchDistances[numDistancePairs - 1];
    }
    if (lenMain == 2 && backMain >= 0x80)
      lenMain = 1;
  }

  if (repLens[repMaxIndex] >= 2)
  {
    if (repLens[repMaxIndex] + 1 >= lenMain || 
        repLens[repMaxIndex] + 2 >= lenMain && (backMain > (1 << 9)) ||
        repLens[repMaxIndex] + 3 >= lenMain && (backMain > (1 << 15)))
    {
      backRes = repMaxIndex;
      UInt32 lenRes = repLens[repMaxIndex];
      MovePos(lenRes - 1);
      return lenRes;
    }
  }
  
  if (lenMain >= 2 && numAvailableBytes > 2)
  {
    numAvailableBytes = _matchFinder.GetNumAvailableBytes(_matchFinderObj);
    _longestMatchLength = ReadMatchDistances(_numDistancePairs);
    if (_longestMatchLength >= 2)
    {
      UInt32 newDistance = matchDistances[_numDistancePairs - 1];
      if (_longestMatchLength >= lenMain && newDistance < backMain || 
          _longestMatchLength == lenMain + 1 && !ChangePair(backMain, newDistance) ||
          _longestMatchLength > lenMain + 1 ||
          _longestMatchLength + 1 >= lenMain && lenMain >= 3 && ChangePair(newDistance, backMain))
      {
        _longestMatchWasFound = true;
        backRes = UInt32(-1);
        return 1;
      }
    }
    data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1;
    for(UInt32 i = 0; i < kNumRepDistances; i++)
    {
      const Byte *data2 = data - (_repDistances[i] + 1);
      if (data[1] != data2[1] || data[2] != data2[2])
      {
        repLens[i] = 0;
        continue;
      }
      UInt32 len;
      for (len = 2; len < numAvailableBytes && data[len] == data2[len]; len++);
      if (len + 1 >= lenMain)
      {
        _longestMatchWasFound = true;
        backRes = UInt32(-1);
        return 1;
      }
    }
    backRes = backMain + kNumRepDistances; 
    MovePos(lenMain - 2);
    return lenMain;
  }
  backRes = UInt32(-1);
  return 1;
}

HRESULT CEncoder::Flush(UInt32 nowPos)
{
  // ReleaseMFStream();
  if (_matchFinderBase.result != SZ_OK)
    return _matchFinderBase.result;
  WriteEndMarker(nowPos & _posStateMask);
  _rangeEncoder.FlushData();
  return _rangeEncoder.FlushStream();
}

void CEncoder::WriteEndMarker(UInt32 posState)
{
  // This function for writing End Mark for stream version of LZMA. 
  // In current version this feature is not used.
  if (!_writeEndMark)
    return;

  _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 1);
  _isRep[_state.Index].Encode(&_rangeEncoder, 0);
  _state.UpdateMatch();
  UInt32 len = kMatchMinLen; // kMatchMaxLen;
  _lenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState, !_fastMode);
  UInt32 posSlot = (1 << kNumPosSlotBits)  - 1;
  UInt32 lenToPosState = GetLenToPosState(len);
  _posSlotEncoder[lenToPosState].Encode(&_rangeEncoder, posSlot);
  UInt32 footerBits = 30;
  UInt32 posReduced = (UInt32(1) << footerBits) - 1;
  _rangeEncoder.EncodeDirectBits(posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
  _posAlignEncoder.ReverseEncode(&_rangeEncoder, posReduced & kAlignMask);
}

HRESULT CEncoder::CodeReal(ISequentialInStream *inStream,
      ISequentialOutStream *outStream, 
      const UInt64 *inSize, const UInt64 *outSize,
      ICompressProgressInfo *progress)
{
  // _needReleaseMFStream = false;
  #ifdef COMPRESS_MF_MT
  #ifdef USE_ALLOCA
  alloca(0x300);
  #endif
  #endif
  CCoderReleaser coderReleaser(this);
  RINOK(SetStreams(inStream, outStream, inSize, outSize));
  for (;;)
  {
    UInt64 processedInSize;
    UInt64 processedOutSize;
    Int32 finished;
    RINOK(CodeOneBlock(&processedInSize, &processedOutSize, &finished));
    if (finished != 0)
      break;
    if (progress != 0)
    {
      RINOK(progress->SetRatioInfo(&processedInSize, &processedOutSize));
    }
  }
  return S_OK;
}

HRESULT CEncoder::SetStreams(ISequentialInStream *inStream,
      ISequentialOutStream *outStream, 
      const UInt64 * /* inSize */, const UInt64 * /* outSize */)
{
  _inStream = inStream;
  _finished = false;
  RINOK(Create());
  RINOK(SetOutStream(outStream));
  RINOK(Init());
  
  if (!_fastMode)
  {
    FillDistancesPrices();
    FillAlignPrices();
  }

  _lenEncoder.SetTableSize(_numFastBytes + 1 - kMatchMinLen);
  _lenEncoder.UpdateTables(1 << _posStateBits);
  _repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - kMatchMinLen);
  _repMatchLenEncoder.UpdateTables(1 << _posStateBits);

  nowPos64 = 0;
  return S_OK;
}

static HRes MyRead(void *object, void *data, UInt32 size, UInt32 *processedSize)
{
  return (HRes)((CSeqInStream *)object)->RealStream->Read(data, size, processedSize);
}

HRESULT CEncoder::CodeOneBlock(UInt64 *inSize, UInt64 *outSize, Int32 *finished)
{
  if (_inStream != 0)
  {
    _seqInStream.RealStream = _inStream;
    _seqInStream.SeqInStream.Read = MyRead;
    _matchFinderBase.stream = &_seqInStream.SeqInStream;
    _matchFinder.Init(_matchFinderObj);
    _needReleaseMFStream = true;
    _inStream = 0;
  }


  *finished = 1;
  if (_finished)
    return _matchFinderBase.result;
  _finished = true;

  if (nowPos64 == 0)
  {
    if (_matchFinder.GetNumAvailableBytes(_matchFinderObj) == 0)
      return Flush((UInt32)nowPos64);
    UInt32 len, numDistancePairs;
    len = ReadMatchDistances(numDistancePairs);
    UInt32 posState = UInt32(nowPos64) & _posStateMask;
    _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 0);
    _state.UpdateChar();
    Byte curByte = _matchFinder.GetIndexByte(_matchFinderObj, 0 - _additionalOffset);
    _literalEncoder.GetSubCoder(UInt32(nowPos64), _previousByte)->Encode(&_rangeEncoder, curByte);
    _previousByte = curByte;
    _additionalOffset--;
    nowPos64++;
  }

  UInt32 nowPos32 = (UInt32)nowPos64;
  UInt32 progressPosValuePrev = nowPos32;

  if (_matchFinder.GetNumAvailableBytes(_matchFinderObj) == 0)
    return Flush(nowPos32);

  for (;;)
  {
    #ifdef _NO_EXCEPTIONS
    if (_rangeEncoder.Stream.ErrorCode != S_OK)
      return _rangeEncoder.Stream.ErrorCode;
    #endif
    UInt32 pos, len;

    if (_fastMode)
      len = GetOptimumFast(pos);
    else
      len = GetOptimum(nowPos32, pos);

    UInt32 posState = nowPos32 & _posStateMask;
    if(len == 1 && pos == 0xFFFFFFFF)
    {
      _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 0);
      Byte curByte = _matchFinder.GetIndexByte(_matchFinderObj, 0 - _additionalOffset);
      CLiteralEncoder2 *subCoder = _literalEncoder.GetSubCoder(nowPos32, _previousByte);
      if(_state.IsCharState())
        subCoder->Encode(&_rangeEncoder, curByte);
      else
      {
        Byte matchByte = _matchFinder.GetIndexByte(_matchFinderObj, 0 - _repDistances[0] - 1 - _additionalOffset);
        subCoder->EncodeMatched(&_rangeEncoder, matchByte, curByte);
      }
      _state.UpdateChar();
      _previousByte = curByte;
    }
    else
    {
      _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 1);
      if(pos < kNumRepDistances)
      {
        _isRep[_state.Index].Encode(&_rangeEncoder, 1);
        if(pos == 0)
        {
          _isRepG0[_state.Index].Encode(&_rangeEncoder, 0);
          _isRep0Long[_state.Index][posState].Encode(&_rangeEncoder, ((len == 1) ? 0 : 1));
        }
        else
        {
          UInt32 distance = _repDistances[pos];
          _isRepG0[_state.Index].Encode(&_rangeEncoder, 1);
          if (pos == 1)
            _isRepG1[_state.Index].Encode(&_rangeEncoder, 0);
          else
          {
            _isRepG1[_state.Index].Encode(&_rangeEncoder, 1);
            _isRepG2[_state.Index].Encode(&_rangeEncoder, pos - 2);
            if (pos == 3)
              _repDistances[3] = _repDistances[2];
            _repDistances[2] = _repDistances[1];
          }
          _repDistances[1] = _repDistances[0];
          _repDistances[0] = distance;
        }
        if (len == 1)
          _state.UpdateShortRep();
        else
        {
          _repMatchLenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState, !_fastMode);
          _state.UpdateRep();
        }
      }
      else
      {
        _isRep[_state.Index].Encode(&_rangeEncoder, 0);
        _state.UpdateMatch();
        _lenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState, !_fastMode);
        pos -= kNumRepDistances;
        UInt32 posSlot = GetPosSlot(pos);
        _posSlotEncoder[GetLenToPosState(len)].Encode(&_rangeEncoder, posSlot);
        
        if (posSlot >= kStartPosModelIndex)
        {
          UInt32 footerBits = ((posSlot >> 1) - 1);
          UInt32 base = ((2 | (posSlot & 1)) << footerBits);
          UInt32 posReduced = pos - base;

          if (posSlot < kEndPosModelIndex)
            NRangeCoder::ReverseBitTreeEncode(_posEncoders + base - posSlot - 1, 
                &_rangeEncoder, footerBits, posReduced);
          else
          {
            _rangeEncoder.EncodeDirectBits(posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
            _posAlignEncoder.ReverseEncode(&_rangeEncoder, posReduced & kAlignMask);
            _alignPriceCount++;
          }
        }
        _repDistances[3] = _repDistances[2];
        _repDistances[2] = _repDistances[1];
        _repDistances[1] = _repDistances[0];
        _repDistances[0] = pos;
        _matchPriceCount++;
      }
      _previousByte = _matchFinder.GetIndexByte(_matchFinderObj, len - 1 - _additionalOffset);
    }
    _additionalOffset -= len;
    nowPos32 += len;
    if (_additionalOffset == 0)
    {
      if (!_fastMode)
      {
        if (_matchPriceCount >= (1 << 7))
          FillDistancesPrices();
        if (_alignPriceCount >= kAlignTableSize)
          FillAlignPrices();
      }
      if (_matchFinder.GetNumAvailableBytes(_matchFinderObj) == 0)
        return Flush(nowPos32);
      if (nowPos32 - progressPosValuePrev >= (1 << 14))
      {
        nowPos64 += nowPos32 - progressPosValuePrev;
        *inSize = nowPos64;
        *outSize = _rangeEncoder.GetProcessedSize();
        _finished = false;
        *finished = 0;
        return _matchFinderBase.result;
      }
    }
  }
}

STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream,
    ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
    ICompressProgressInfo *progress)
{
  #ifndef _NO_EXCEPTIONS
  try 
  { 
  #endif
    return CodeReal(inStream, outStream, inSize, outSize, progress); 
  #ifndef _NO_EXCEPTIONS
  }
  catch(const COutBufferException &e) { return e.ErrorCode; }
  catch(...) { return E_FAIL; }
  #endif
}
  
void CEncoder::FillDistancesPrices()
{
  UInt32 tempPrices[kNumFullDistances];
  for (UInt32 i = kStartPosModelIndex; i < kNumFullDistances; i++)
  { 
    UInt32 posSlot = GetPosSlot(i);
    UInt32 footerBits = ((posSlot >> 1) - 1);
    UInt32 base = ((2 | (posSlot & 1)) << footerBits);
    tempPrices[i] = NRangeCoder::ReverseBitTreeGetPrice(_posEncoders + 
      base - posSlot - 1, footerBits, i - base);
  }

  for (UInt32 lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
  {
    UInt32 posSlot;
    NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumPosSlotBits> &encoder = _posSlotEncoder[lenToPosState];
    UInt32 *posSlotPrices = _posSlotPrices[lenToPosState];
    for (posSlot = 0; posSlot < _distTableSize; posSlot++)
      posSlotPrices[posSlot] = encoder.GetPrice(posSlot);
    for (posSlot = kEndPosModelIndex; posSlot < _distTableSize; posSlot++)
      posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << NRangeCoder::kNumBitPriceShiftBits);

    UInt32 *distancesPrices = _distancesPrices[lenToPosState];
    UInt32 i;
    for (i = 0; i < kStartPosModelIndex; i++)
      distancesPrices[i] = posSlotPrices[i];
    for (; i < kNumFullDistances; i++)
      distancesPrices[i] = posSlotPrices[GetPosSlot(i)] + tempPrices[i];
  }
  _matchPriceCount = 0;
}

void CEncoder::FillAlignPrices()
{
  for (UInt32 i = 0; i < kAlignTableSize; i++)
    _alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i);
  _alignPriceCount = 0;
}

}}