zoukankan      html  css  js  c++  java
  • 7zip使用的压缩算法,C#实现的LZMA压缩算法单文件版

    http://www.oschina.net/code/snippet_222150_7935

     http://115.com/file/dpxi8m6v#  代码下载

    using System;
    using System.IO;
    using System.Collections;

    namespace SevenZip.CommandLineParser
    {
     public enum SwitchType
     {
      Simple,
      PostMinus,
      LimitedPostString,
      UnLimitedPostString,
      PostChar
     }

     public class SwitchForm
     {
      public string IDString;
      public SwitchType Type;
      public bool Multi;
      public int MinLen;
      public int MaxLen;
      public string PostCharSet;

      public SwitchForm(string idString, SwitchType type, bool multi,
       int minLen, int maxLen, string postCharSet)
      {
       IDString = idString;
       Type = type;
       Multi = multi;
       MinLen = minLen;
       MaxLen = maxLen;
       PostCharSet = postCharSet;
      }
      public SwitchForm(string idString, SwitchType type, bool multi, int minLen):
       this(idString, type, multi, minLen, 0, "")
      {
      }
      public SwitchForm(string idString, SwitchType type, bool multi):
       this(idString, type, multi, 0)
      {
      }
     }

     public class SwitchResult
     {
      public bool ThereIs;
      public bool WithMinus;
      public ArrayList PostStrings = new ArrayList();
      public int PostCharIndex;
      public SwitchResult()
      {
       ThereIs = false;
      }
     }

     public class Parser
     {
      public ArrayList NonSwitchStrings = new ArrayList();
      SwitchResult[] _switches;

      public Parser(int numSwitches)
      {
       _switches = new SwitchResult[numSwitches];
       for (int i = 0; i < numSwitches; i++)
        _switches[i] = new SwitchResult();
      }

      bool ParseString(string srcString, SwitchForm[] switchForms)
      {
       int len = srcString.Length;
       if (len == 0)
        return false;
       int pos = 0;
       if (!IsItSwitchChar(srcString[pos]))
        return false;
       while (pos < len)
       {
        if (IsItSwitchChar(srcString[pos]))
         pos++;
        const int kNoLen = -1;
        int matchedSwitchIndex = 0;
        int maxLen = kNoLen;
        for (int switchIndex = 0; switchIndex < _switches.Length; switchIndex++)
        {
         int switchLen = switchForms[switchIndex].IDString.Length;
         if (switchLen <= maxLen || pos + switchLen > len)
          continue;
         if (String.Compare(switchForms[switchIndex].IDString, 0,
           srcString, pos, switchLen, true) == 0)
         {
          matchedSwitchIndex = switchIndex;
          maxLen = switchLen;
         }
        }
        if (maxLen == kNoLen)
         throw new Exception("maxLen == kNoLen");
        SwitchResult matchedSwitch = _switches[matchedSwitchIndex];
        SwitchForm switchForm = switchForms[matchedSwitchIndex];
        if ((!switchForm.Multi) && matchedSwitch.ThereIs)
         throw new Exception("switch must be single");
        matchedSwitch.ThereIs = true;
        pos += maxLen;
        int tailSize = len - pos;
        SwitchType type = switchForm.Type;
        switch (type)
        {
         case SwitchType.PostMinus:
          {
           if (tailSize == 0)
            matchedSwitch.WithMinus = false;
           else
           {
            matchedSwitch.WithMinus = (srcString[pos] == kSwitchMinus);
            if (matchedSwitch.WithMinus)
             pos++;
           }
           break;
          }
         case SwitchType.PostChar:
          {
           if (tailSize < switchForm.MinLen)
            throw new Exception("switch is not full");
           string charSet = switchForm.PostCharSet;
           const int kEmptyCharValue = -1;
           if (tailSize == 0)
            matchedSwitch.PostCharIndex = kEmptyCharValue;
           else
           {
            int index = charSet.IndexOf(srcString[pos]);
            if (index < 0)
             matchedSwitch.PostCharIndex = kEmptyCharValue;
            else
            {
             matchedSwitch.PostCharIndex = index;
             pos++;
            }
           }
           break;
          }
         case SwitchType.LimitedPostString:
         case SwitchType.UnLimitedPostString:
          {
           int minLen = switchForm.MinLen;
           if (tailSize < minLen)
            throw new Exception("switch is not full");
           if (type == SwitchType.UnLimitedPostString)
           {
            matchedSwitch.PostStrings.Add(srcString.Substring(pos));
            return true;
           }
           String stringSwitch = srcString.Substring(pos, minLen);
           pos += minLen;
           for (int i = minLen; i < switchForm.MaxLen && pos < len; i++, pos++)
           {
            char c = srcString[pos];
            if (IsItSwitchChar(c))
             break;
            stringSwitch += c;
           }
           matchedSwitch.PostStrings.Add(stringSwitch);
           break;
          }
        }
       }
       return true;

      }

      public void ParseStrings(SwitchForm[] switchForms, string[] commandStrings)
      {
       int numCommandStrings = commandStrings.Length;
       bool stopSwitch = false;
       for (int i = 0; i < numCommandStrings; i++)
       {
        string s = commandStrings[i];
        if (stopSwitch)
         NonSwitchStrings.Add(s);
        else
         if (s == kStopSwitchParsing)
         stopSwitch = true;
        else
         if (!ParseString(s, switchForms))
         NonSwitchStrings.Add(s);
       }
      }

      public SwitchResult this[int index] { get { return _switches[index]; } }

      public static int ParseCommand(CommandForm[] commandForms, string commandString,
       out string postString)
      {
       for (int i = 0; i < commandForms.Length; i++)
       {
        string id = commandForms[i].IDString;
        if (commandForms[i].PostStringMode)
        {
         if (commandString.IndexOf(id) == 0)
         {
          postString = commandString.Substring(id.Length);
          return i;
         }
        }
        else
         if (commandString == id)
        {
         postString = "";
         return i;
        }
       }
       postString = "";
       return -1;
      }

      static bool ParseSubCharsCommand(int numForms, CommandSubCharsSet[] forms,
       string commandString, ArrayList indices)
      {
       indices.Clear();
       int numUsedChars = 0;
       for (int i = 0; i < numForms; i++)
       {
        CommandSubCharsSet charsSet = forms[i];
        int currentIndex = -1;
        int len = charsSet.Chars.Length;
        for (int j = 0; j < len; j++)
        {
         char c = charsSet.Chars[j];
         int newIndex = commandString.IndexOf(c);
         if (newIndex >= 0)
         {
          if (currentIndex >= 0)
           return false;
          if (commandString.IndexOf(c, newIndex + 1) >= 0)
           return false;
          currentIndex = j;
          numUsedChars++;
         }
        }
        if (currentIndex == -1 && !charsSet.EmptyAllowed)
         return false;
        indices.Add(currentIndex);
       }
       return (numUsedChars == commandString.Length);
      }
      const char kSwitchID1 = '-';
      const char kSwitchID2 = '/';

      const char kSwitchMinus = '-';
      const string kStopSwitchParsing = "--";

      static bool IsItSwitchChar(char c)
      {
       return (c == kSwitchID1 || c == kSwitchID2);
      }
     }

     public class CommandForm
     {
      public string IDString = "";
      public bool PostStringMode = false;
      public CommandForm(string idString, bool postStringMode)
      {
       IDString = idString;
       PostStringMode = postStringMode;
      }
     }

     class CommandSubCharsSet
     {
      public string Chars = "";
      public bool EmptyAllowed = false;
     }
    }

    namespace SevenZip
    {
     class CRC
     {
      public static readonly uint[] Table;

      static CRC()
      {
       Table = new uint[256];
       const uint kPoly = 0xEDB88320;
       for (uint i = 0; i < 256; i++)
       {
        uint r = i;
        for (int j = 0; j < 8; j++)
         if ((r & 1) != 0)
          r = (r >> 1) ^ kPoly;
         else
          r >>= 1;
        Table[i] = r;
       }
      }

      uint _value = 0xFFFFFFFF;

      public void Init() { _value = 0xFFFFFFFF; }

      public void UpdateByte(byte b)
      {
       _value = Table[(((byte)(_value)) ^ b)] ^ (_value >> 8);
      }

      public void Update(byte[] data, uint offset, uint size)
      {
       for (uint i = 0; i < size; i++)
        _value = Table[(((byte)(_value)) ^ data[offset + i])] ^ (_value >> 8);
      }

      public uint GetDigest() { return _value ^ 0xFFFFFFFF; }

      static uint CalculateDigest(byte[] data, uint offset, uint size)
      {
       CRC crc = new CRC();
       // crc.Init();
       crc.Update(data, offset, size);
       return crc.GetDigest();
      }

      static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size)
      {
       return (CalculateDigest(data, offset, size) == digest);
      }
     }
    }

    namespace SevenZip.Compression.LZ
    {
     interface IInWindowStream
     {
      void SetStream(System.IO.Stream inStream);
      void Init();
      void ReleaseStream();
      Byte GetIndexByte(Int32 index);
      UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit);
      UInt32 GetNumAvailableBytes();
     }

     interface IMatchFinder : IInWindowStream
     {
      void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
        UInt32 matchMaxLen, UInt32 keepAddBufferAfter);
      UInt32 GetMatches(UInt32[] distances);
      void Skip(UInt32 num);
     }
    }
    namespace SevenZip.Compression.LZ
    {
     public class InWindow
     {
      public Byte[] _bufferBase = null; // pointer to buffer with data
      System.IO.Stream _stream;
      UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done
      bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream

      UInt32 _pointerToLastSafePosition;

      public UInt32 _bufferOffset;

      public UInt32 _blockSize; // Size of Allocated memory block
      public UInt32 _pos; // offset (from _buffer) of curent byte
      UInt32 _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos
      UInt32 _keepSizeAfter; // how many BYTEs must be kept buffer after _pos
      public UInt32 _streamPos; // offset (from _buffer) of first not read byte from Stream

      public void MoveBlock()
      {
       UInt32 offset = (UInt32)(_bufferOffset) + _pos - _keepSizeBefore;
       // we need one additional byte, since MovePos moves on 1 byte.
       if (offset > 0)
        offset--;
       
       UInt32 numBytes = (UInt32)(_bufferOffset) + _streamPos - offset;

       // check negative offset ????
       for (UInt32 i = 0; i < numBytes; i++)
        _bufferBase[i] = _bufferBase[offset + i];
       _bufferOffset -= offset;
      }

      public virtual void ReadBlock()
      {
       if (_streamEndWasReached)
        return;
       while (true)
       {
        int size = (int)((0 - _bufferOffset) + _blockSize - _streamPos);
        if (size == 0)
         return;
        int numReadBytes = _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), size);
        if (numReadBytes == 0)
        {
         _posLimit = _streamPos;
         UInt32 pointerToPostion = _bufferOffset + _posLimit;
         if (pointerToPostion > _pointerToLastSafePosition)
          _posLimit = (UInt32)(_pointerToLastSafePosition - _bufferOffset);

         _streamEndWasReached = true;
         return;
        }
        _streamPos += (UInt32)numReadBytes;
        if (_streamPos >= _pos + _keepSizeAfter)
         _posLimit = _streamPos - _keepSizeAfter;
       }
      }

      void Free() { _bufferBase = null; }

      public void Create(UInt32 keepSizeBefore, UInt32 keepSizeAfter, UInt32 keepSizeReserv)
      {
       _keepSizeBefore = keepSizeBefore;
       _keepSizeAfter = keepSizeAfter;
       UInt32 blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv;
       if (_bufferBase == null || _blockSize != blockSize)
       {
        Free();
        _blockSize = blockSize;
        _bufferBase = new Byte[_blockSize];
       }
       _pointerToLastSafePosition = _blockSize - keepSizeAfter;
      }

      public void SetStream(System.IO.Stream stream) { _stream = stream; }
      public void ReleaseStream() { _stream = null; }

      public void Init()
      {
       _bufferOffset = 0;
       _pos = 0;
       _streamPos = 0;
       _streamEndWasReached = false;
       ReadBlock();
      }

      public void MovePos()
      {
       _pos++;
       if (_pos > _posLimit)
       {
        UInt32 pointerToPostion = _bufferOffset + _pos;
        if (pointerToPostion > _pointerToLastSafePosition)
         MoveBlock();
        ReadBlock();
       }
      }

      public Byte GetIndexByte(Int32 index) { return _bufferBase[_bufferOffset + _pos + index]; }

      // index + limit have not to exceed _keepSizeAfter;
      public UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
      {
       if (_streamEndWasReached)
        if ((_pos + index) + limit > _streamPos)
         limit = _streamPos - (UInt32)(_pos + index);
       distance++;
       // Byte *pby = _buffer + (size_t)_pos + index;
       UInt32 pby = _bufferOffset + _pos + (UInt32)index;

       UInt32 i;
       for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++);
       return i;
      }

      public UInt32 GetNumAvailableBytes() { return _streamPos - _pos; }

      public void ReduceOffsets(Int32 subValue)
      {
       _bufferOffset += (UInt32)subValue;
       _posLimit -= (UInt32)subValue;
       _pos -= (UInt32)subValue;
       _streamPos -= (UInt32)subValue;
      }
     }
    }
    // LzOutWindow.cs

    namespace SevenZip.Compression.LZ
    {
     public class OutWindow
     {
      byte[] _buffer = null;
      uint _pos;
      uint _windowSize = 0;
      uint _streamPos;
      System.IO.Stream _stream;

      public uint TrainSize = 0;

      public void Create(uint windowSize)
      {
       if (_windowSize != windowSize)
       {
        // System.GC.Collect();
        _buffer = new byte[windowSize];
       }
       _windowSize = windowSize;
       _pos = 0;
       _streamPos = 0;
      }

      public void Init(System.IO.Stream stream, bool solid)
      {
       ReleaseStream();
       _stream = stream;
       if (!solid)
       {
        _streamPos = 0;
        _pos = 0;
        TrainSize = 0;
       }
      }
     
      public bool Train(System.IO.Stream stream)
      {
       long len = stream.Length;
       uint size = (len < _windowSize) ? (uint)len : _windowSize;
       TrainSize = size;
       stream.Position = len - size;
       _streamPos = _pos = 0;
       while (size > 0)
       {
        uint curSize = _windowSize - _pos;
        if (size < curSize)
         curSize = size;
        int numReadBytes = stream.Read(_buffer, (int)_pos, (int)curSize);
        if (numReadBytes == 0)
         return false;
        size -= (uint)numReadBytes;
        _pos += (uint)numReadBytes;
        _streamPos += (uint)numReadBytes;
        if (_pos == _windowSize)
         _streamPos = _pos = 0;
       }
       return true;
      }

      public void ReleaseStream()
      {
       Flush();
       _stream = null;
      }

      public void Flush()
      {
       uint size = _pos - _streamPos;
       if (size == 0)
        return;
       _stream.Write(_buffer, (int)_streamPos, (int)size);
       if (_pos >= _windowSize)
        _pos = 0;
       _streamPos = _pos;
      }

      public void CopyBlock(uint distance, uint len)
      {
       uint pos = _pos - distance - 1;
       if (pos >= _windowSize)
        pos += _windowSize;
       for (; len > 0; len--)
       {
        if (pos >= _windowSize)
         pos = 0;
        _buffer[_pos++] = _buffer[pos++];
        if (_pos >= _windowSize)
         Flush();
       }
      }

      public void PutByte(byte b)
      {
       _buffer[_pos++] = b;
       if (_pos >= _windowSize)
        Flush();
      }

      public byte GetByte(uint distance)
      {
       uint pos = _pos - distance - 1;
       if (pos >= _windowSize)
        pos += _windowSize;
       return _buffer[pos];
      }
     }
    }
    // LzmaBase.cs

    namespace SevenZip.Compression.LZMA
    {
     internal abstract class Base
     {
      public const uint kNumRepDistances = 4;
      public const uint kNumStates = 12;

      // static byte []kLiteralNextStates  = {0, 0, 0, 0, 1, 2, 3, 4,  5,  6,   4, 5};
      // static byte []kMatchNextStates    = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
      // static byte []kRepNextStates      = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
      // static byte []kShortRepNextStates = {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};

      public struct State
      {
       public uint Index;
       public void Init() { Index = 0; }
       public void UpdateChar()
       {
        if (Index < 4) Index = 0;
        else if (Index < 10) Index -= 3;
        else Index -= 6;
       }
       public void UpdateMatch() { Index = (uint)(Index < 7 ? 7 : 10); }
       public void UpdateRep() { Index = (uint)(Index < 7 ? 8 : 11); }
       public void UpdateShortRep() { Index = (uint)(Index < 7 ? 9 : 11); }
       public bool IsCharState() { return Index < 7; }
      }

      public const int kNumPosSlotBits = 6;
      public const int kDicLogSizeMin = 0;
      // public const int kDicLogSizeMax = 30;
      // public const uint kDistTableSizeMax = kDicLogSizeMax * 2;

      public const int kNumLenToPosStatesBits = 2; // it's for speed optimization
      public const uint kNumLenToPosStates = 1 << kNumLenToPosStatesBits;

      public const uint kMatchMinLen = 2;

      public static uint GetLenToPosState(uint len)
      {
       len -= kMatchMinLen;
       if (len < kNumLenToPosStates)
        return len;
       return (uint)(kNumLenToPosStates - 1);
      }

      public const int kNumAlignBits = 4;
      public const uint kAlignTableSize = 1 << kNumAlignBits;
      public const uint kAlignMask = (kAlignTableSize - 1);

      public const uint kStartPosModelIndex = 4;
      public const uint kEndPosModelIndex = 14;
      public const uint kNumPosModels = kEndPosModelIndex - kStartPosModelIndex;

      public const uint kNumFullDistances = 1 << ((int)kEndPosModelIndex / 2);

      public const uint kNumLitPosStatesBitsEncodingMax = 4;
      public const uint kNumLitContextBitsMax = 8;

      public const int kNumPosStatesBitsMax = 4;
      public const uint kNumPosStatesMax = (1 << kNumPosStatesBitsMax);
      public const int kNumPosStatesBitsEncodingMax = 4;
      public const uint kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax);

      public const int kNumLowLenBits = 3;
      public const int kNumMidLenBits = 3;
      public const int kNumHighLenBits = 8;
      public const uint kNumLowLenSymbols = 1 << kNumLowLenBits;
      public const uint kNumMidLenSymbols = 1 << kNumMidLenBits;
      public const uint kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols +
        (1 << kNumHighLenBits);
      public const uint kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1;
     }
    }
    namespace SevenZip.Compression.RangeCoder
    {
     class Encoder
     {
      public const uint kTopValue = (1 << 24);

      System.IO.Stream Stream;

      public UInt64 Low;
      public uint Range;
      uint _cacheSize;
      byte _cache;

      long StartPosition;

      public void SetStream(System.IO.Stream stream)
      {
       Stream = stream;
      }

      public void ReleaseStream()
      {
       Stream = null;
      }

      public void Init()
      {
       StartPosition = Stream.Position;

       Low = 0;
       Range = 0xFFFFFFFF;
       _cacheSize = 1;
       _cache = 0;
      }

      public void FlushData()
      {
       for (int i = 0; i < 5; i++)
        ShiftLow();
      }

      public void FlushStream()
      {
       Stream.Flush();
      }

      public void CloseStream()
      {
       Stream.Close();
      }

      public void Encode(uint start, uint size, uint total)
      {
       Low += start * (Range /= total);
       Range *= size;
       while (Range < kTopValue)
       {
        Range <<= 8;
        ShiftLow();
       }
      }

      public void ShiftLow()
      {
       if ((uint)Low < (uint)0xFF000000 || (uint)(Low >> 32) == 1)
       {
        byte temp = _cache;
        do
        {
         Stream.WriteByte((byte)(temp + (Low >> 32)));
         temp = 0xFF;
        }
        while (--_cacheSize != 0);
        _cache = (byte)(((uint)Low) >> 24);
       }
       _cacheSize++;
       Low = ((uint)Low) << 8;
      }

      public void EncodeDirectBits(uint v, int numTotalBits)
      {
       for (int i = numTotalBits - 1; i >= 0; i--)
       {
        Range >>= 1;
        if (((v >> i) & 1) == 1)
         Low += Range;
        if (Range < kTopValue)
        {
         Range <<= 8;
         ShiftLow();
        }
       }
      }

      public void EncodeBit(uint size0, int numTotalBits, uint symbol)
      {
       uint newBound = (Range >> numTotalBits) * size0;
       if (symbol == 0)
        Range = newBound;
       else
       {
        Low += newBound;
        Range -= newBound;
       }
       while (Range < kTopValue)
       {
        Range <<= 8;
        ShiftLow();
       }
      }

      public long GetProcessedSizeAdd()
      {
       return _cacheSize +
        Stream.Position - StartPosition + 4;
       // (long)Stream.GetProcessedSize();
      }
     }

     class Decoder
     {
      public const uint kTopValue = (1 << 24);
      public uint Range;
      public uint Code;
      // public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16);
      public System.IO.Stream Stream;

      public void Init(System.IO.Stream stream)
      {
       // Stream.Init(stream);
       Stream = stream;

       Code = 0;
       Range = 0xFFFFFFFF;
       for (int i = 0; i < 5; i++)
        Code = (Code << 8) | (byte)Stream.ReadByte();
      }

      public void ReleaseStream()
      {
       // Stream.ReleaseStream();
       Stream = null;
      }

      public void CloseStream()
      {
       Stream.Close();
      }

      public void Normalize()
      {
       while (Range < kTopValue)
       {
        Code = (Code << 8) | (byte)Stream.ReadByte();
        Range <<= 8;
       }
      }

      public void Normalize2()
      {
       if (Range < kTopValue)
       {
        Code = (Code << 8) | (byte)Stream.ReadByte();
        Range <<= 8;
       }
      }

      public uint GetThreshold(uint total)
      {
       return Code / (Range /= total);
      }

      public void Decode(uint start, uint size, uint total)
      {
       Code -= start * Range;
       Range *= size;
       Normalize();
      }

      public uint DecodeDirectBits(int numTotalBits)
      {
       uint range = Range;
       uint code = Code;
       uint result = 0;
       for (int i = numTotalBits; i > 0; i--)
       {
        range >>= 1;
        /*
        result <<= 1;
        if (code >= range)
        {
         code -= range;
         result |= 1;
        }
        */
        uint t = (code - range) >> 31;
        code -= range & (t - 1);
        result = (result << 1) | (1 - t);

        if (range < kTopValue)
        {
         code = (code << 8) | (byte)Stream.ReadByte();
         range <<= 8;
        }
       }
       Range = range;
       Code = code;
       return result;
      }

      public uint DecodeBit(uint size0, int numTotalBits)
      {
       uint newBound = (Range >> numTotalBits) * size0;
       uint symbol;
       if (Code < newBound)
       {
        symbol = 0;
        Range = newBound;
       }
       else
       {
        symbol = 1;
        Code -= newBound;
        Range -= newBound;
       }
       Normalize();
       return symbol;
      }

      // ulong GetProcessedSize() {return Stream.GetProcessedSize(); }
     }
    }
    namespace SevenZip.Compression.RangeCoder
    {
     struct BitEncoder
     {
      public const int kNumBitModelTotalBits = 11;
      public const uint kBitModelTotal = (1 << kNumBitModelTotalBits);
      const int kNumMoveBits = 5;
      const int kNumMoveReducingBits = 2;
      public const int kNumBitPriceShiftBits = 6;

      uint Prob;

      public void Init() { Prob = kBitModelTotal >> 1; }

      public void UpdateModel(uint symbol)
      {
       if (symbol == 0)
        Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
       else
        Prob -= (Prob) >> kNumMoveBits;
      }

      public void Encode(Encoder encoder, uint symbol)
      {
       // encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol);
       // UpdateModel(symbol);
       uint newBound = (encoder.Range >> kNumBitModelTotalBits) * Prob;
       if (symbol == 0)
       {
        encoder.Range = newBound;
        Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
       }
       else
       {
        encoder.Low += newBound;
        encoder.Range -= newBound;
        Prob -= (Prob) >> kNumMoveBits;
       }
       if (encoder.Range < Encoder.kTopValue)
       {
        encoder.Range <<= 8;
        encoder.ShiftLow();
       }
      }

      private static UInt32[] ProbPrices = new UInt32[kBitModelTotal >> kNumMoveReducingBits];

      static BitEncoder()
      {
       const int kNumBits = (kNumBitModelTotalBits - kNumMoveReducingBits);
       for (int i = kNumBits - 1; i >= 0; i--)
       {
        UInt32 start = (UInt32)1 << (kNumBits - i - 1);
        UInt32 end = (UInt32)1 << (kNumBits - i);
        for (UInt32 j = start; j < end; j++)
         ProbPrices[j] = ((UInt32)i << kNumBitPriceShiftBits) +
          (((end - j) << kNumBitPriceShiftBits) >> (kNumBits - i - 1));
       }
      }

      public uint GetPrice(uint symbol)
      {
       return ProbPrices[(((Prob - symbol) ^ ((-(int)symbol))) & (kBitModelTotal - 1)) >> kNumMoveReducingBits];
      }
      public uint GetPrice0() { return ProbPrices[Prob >> kNumMoveReducingBits]; }
      public uint GetPrice1() { return ProbPrices[(kBitModelTotal - Prob) >> kNumMoveReducingBits]; }
     }

     struct BitDecoder
     {
      public const int kNumBitModelTotalBits = 11;
      public const uint kBitModelTotal = (1 << kNumBitModelTotalBits);
      const int kNumMoveBits = 5;

      uint Prob;

      public void UpdateModel(int numMoveBits, uint symbol)
      {
       if (symbol == 0)
        Prob += (kBitModelTotal - Prob) >> numMoveBits;
       else
        Prob -= (Prob) >> numMoveBits;
      }

      public void Init() { Prob = kBitModelTotal >> 1; }

      public uint Decode(RangeCoder.Decoder rangeDecoder)
      {
       uint newBound = (uint)(rangeDecoder.Range >> kNumBitModelTotalBits) * (uint)Prob;
       if (rangeDecoder.Code < newBound)
       {
        rangeDecoder.Range = newBound;
        Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
        if (rangeDecoder.Range < Decoder.kTopValue)
        {
         rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
         rangeDecoder.Range <<= 8;
        }
        return 0;
       }
       else
       {
        rangeDecoder.Range -= newBound;
        rangeDecoder.Code -= newBound;
        Prob -= (Prob) >> kNumMoveBits;
        if (rangeDecoder.Range < Decoder.kTopValue)
        {
         rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
         rangeDecoder.Range <<= 8;
        }
        return 1;
       }
      }
     }
    }
    namespace SevenZip.Compression.RangeCoder
    {
     struct BitTreeEncoder
     {
      BitEncoder[] Models;
      int NumBitLevels;

      public BitTreeEncoder(int numBitLevels)
      {
       NumBitLevels = numBitLevels;
       Models = new BitEncoder[1 << numBitLevels];
      }

      public void Init()
      {
       for (uint i = 1; i < (1 << NumBitLevels); i++)
        Models[i].Init();
      }

      public void Encode(Encoder rangeEncoder, UInt32 symbol)
      {
       UInt32 m = 1;
       for (int bitIndex = NumBitLevels; bitIndex > 0; )
       {
        bitIndex--;
        UInt32 bit = (symbol >> bitIndex) & 1;
        Models[m].Encode(rangeEncoder, bit);
        m = (m << 1) | bit;
       }
      }

      public void ReverseEncode(Encoder rangeEncoder, UInt32 symbol)
      {
       UInt32 m = 1;
       for (UInt32 i = 0; i < NumBitLevels; i++)
       {
        UInt32 bit = symbol & 1;
        Models[m].Encode(rangeEncoder, bit);
        m = (m << 1) | bit;
        symbol >>= 1;
       }
      }

      public UInt32 GetPrice(UInt32 symbol)
      {
       UInt32 price = 0;
       UInt32 m = 1;
       for (int bitIndex = NumBitLevels; bitIndex > 0; )
       {
        bitIndex--;
        UInt32 bit = (symbol >> bitIndex) & 1;
        price += Models[m].GetPrice(bit);
        m = (m << 1) + bit;
       }
       return price;
      }

      public UInt32 ReverseGetPrice(UInt32 symbol)
      {
       UInt32 price = 0;
       UInt32 m = 1;
       for (int i = NumBitLevels; i > 0; i--)
       {
        UInt32 bit = symbol & 1;
        symbol >>= 1;
        price += Models[m].GetPrice(bit);
        m = (m << 1) | bit;
       }
       return price;
      }

      public static UInt32 ReverseGetPrice(BitEncoder[] Models, UInt32 startIndex,
       int NumBitLevels, UInt32 symbol)
      {
       UInt32 price = 0;
       UInt32 m = 1;
       for (int i = NumBitLevels; i > 0; i--)
       {
        UInt32 bit = symbol & 1;
        symbol >>= 1;
        price += Models[startIndex + m].GetPrice(bit);
        m = (m << 1) | bit;
       }
       return price;
      }

      public static void ReverseEncode(BitEncoder[] Models, UInt32 startIndex,
       Encoder rangeEncoder, int NumBitLevels, UInt32 symbol)
      {
       UInt32 m = 1;
       for (int i = 0; i < NumBitLevels; i++)
       {
        UInt32 bit = symbol & 1;
        Models[startIndex + m].Encode(rangeEncoder, bit);
        m = (m << 1) | bit;
        symbol >>= 1;
       }
      }
     }

     struct BitTreeDecoder
     {
      BitDecoder[] Models;
      int NumBitLevels;

      public BitTreeDecoder(int numBitLevels)
      {
       NumBitLevels = numBitLevels;
       Models = new BitDecoder[1 << numBitLevels];
      }

      public void Init()
      {
       for (uint i = 1; i < (1 << NumBitLevels); i++)
        Models[i].Init();
      }

      public uint Decode(RangeCoder.Decoder rangeDecoder)
      {
       uint m = 1;
       for (int bitIndex = NumBitLevels; bitIndex > 0; bitIndex--)
        m = (m << 1) + Models[m].Decode(rangeDecoder);
       return m - ((uint)1 << NumBitLevels);
      }

      public uint ReverseDecode(RangeCoder.Decoder rangeDecoder)
      {
       uint m = 1;
       uint symbol = 0;
       for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
       {
        uint bit = Models[m].Decode(rangeDecoder);
        m <<= 1;
        m += bit;
        symbol |= (bit << bitIndex);
       }
       return symbol;
      }

      public static uint ReverseDecode(BitDecoder[] Models, UInt32 startIndex,
       RangeCoder.Decoder rangeDecoder, int NumBitLevels)
      {
       uint m = 1;
       uint symbol = 0;
       for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
       {
        uint bit = Models[startIndex + m].Decode(rangeDecoder);
        m <<= 1;
        m += bit;
        symbol |= (bit << bitIndex);
       }
       return symbol;
      }
     }
    }
    namespace SevenZip
    {
     /// <summary>
     /// The exception that is thrown when an error in input stream occurs during decoding.
     /// </summary>
     class DataErrorException : ApplicationException
     {
      public DataErrorException(): base("Data Error") { }
     }

     /// <summary>
     /// The exception that is thrown when the value of an argument is outside the allowable range.
     /// </summary>
     class InvalidParamException : ApplicationException
     {
      public InvalidParamException(): base("Invalid Parameter") { }
     }

     public interface ICodeProgress
     {
      /// <summary>
      /// Callback progress.
      /// </summary>
      /// <param name="inSize">
      /// input size. -1 if unknown.
      /// </param>
      /// <param name="outSize">
      /// output size. -1 if unknown.
      /// </param>
      void SetProgress(Int64 inSize, Int64 outSize);
     };

     public interface ICoder
     {
      /// <summary>
      /// Codes streams.
      /// </summary>
      /// <param name="inStream">
      /// input Stream.
      /// </param>
      /// <param name="outStream">
      /// output Stream.
      /// </param>
      /// <param name="inSize">
      /// input Size. -1 if unknown.
      /// </param>
      /// <param name="outSize">
      /// output Size. -1 if unknown.
      /// </param>
      /// <param name="progress">
      /// callback progress reference.
      /// </param>
      /// <exception cref="SevenZip.DataErrorException">
      /// if input stream is not valid
      /// </exception>
      void Code(System.IO.Stream inStream, System.IO.Stream outStream,
       Int64 inSize, Int64 outSize, ICodeProgress progress);
     };

     /*
     public interface ICoder2
     {
       void Code(ISequentialInStream []inStreams,
        const UInt64 []inSizes,
        ISequentialOutStream []outStreams,
        UInt64 []outSizes,
        ICodeProgress progress);
     };
      */

     /// <summary>
     /// Provides the fields that represent properties idenitifiers for compressing.
     /// </summary>
     public enum CoderPropID
     {
      /// <summary>
      /// Specifies default property.
      /// </summary>
      DefaultProp = 0,
      /// <summary>
      /// Specifies size of dictionary.
      /// </summary>
      DictionarySize,
      /// <summary>
      /// Specifies size of memory for PPM*.
      /// </summary>
      UsedMemorySize,
      /// <summary>
      /// Specifies order for PPM methods.
      /// </summary>
      Order,
      /// <summary>
      /// Specifies Block Size.
      /// </summary>
      BlockSize,
      /// <summary>
      /// Specifies number of postion state bits for LZMA (0 <= x <= 4).
      /// </summary>
      PosStateBits,
      /// <summary>
      /// Specifies number of literal context bits for LZMA (0 <= x <= 8).
      /// </summary>
      LitContextBits,
      /// <summary>
      /// Specifies number of literal position bits for LZMA (0 <= x <= 4).
      /// </summary>
      LitPosBits,
      /// <summary>
      /// Specifies number of fast bytes for LZ*.
      /// </summary>
      NumFastBytes,
      /// <summary>
      /// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B".
      /// </summary>
      MatchFinder,
      /// <summary>
      /// Specifies the number of match finder cyckes.
      /// </summary>
      MatchFinderCycles,
      /// <summary>
      /// Specifies number of passes.
      /// </summary>
      NumPasses,
      /// <summary>
      /// Specifies number of algorithm.
      /// </summary>
      Algorithm,
      /// <summary>
      /// Specifies the number of threads.
      /// </summary>
      NumThreads,
      /// <summary>
      /// Specifies mode with end marker.
      /// </summary>
      EndMarker
     };


     public interface ISetCoderProperties
     {
      void SetCoderProperties(CoderPropID[] propIDs, object[] properties);
     };

     public interface IWriteCoderProperties
     {
      void WriteCoderProperties(System.IO.Stream outStream);
     }

     public interface ISetDecoderProperties
     {
      void SetDecoderProperties(byte[] properties);
     }
    }

    namespace SevenZip.Compression.LZ
    {
     public class BinTree : InWindow, IMatchFinder
     {
      UInt32 _cyclicBufferPos;
      UInt32 _cyclicBufferSize = 0;
      UInt32 _matchMaxLen;

      UInt32[] _son;
      UInt32[] _hash;

      UInt32 _cutValue = 0xFF;
      UInt32 _hashMask;
      UInt32 _hashSizeSum = 0;

      bool HASH_ARRAY = true;

      const UInt32 kHash2Size = 1 << 10;
      const UInt32 kHash3Size = 1 << 16;
      const UInt32 kBT2HashSize = 1 << 16;
      const UInt32 kStartMaxLen = 1;
      const UInt32 kHash3Offset = kHash2Size;
      const UInt32 kEmptyHashValue = 0;
      const UInt32 kMaxValForNormalize = ((UInt32)1 << 31) - 1;
     
      UInt32 kNumHashDirectBytes = 0;
      UInt32 kMinMatchCheck = 4;
      UInt32 kFixHashSize = kHash2Size + kHash3Size;
      
      public void SetType(int numHashBytes)
      {
       HASH_ARRAY = (numHashBytes > 2);
       if (HASH_ARRAY)
       {
        kNumHashDirectBytes = 0;
        kMinMatchCheck = 4;
        kFixHashSize = kHash2Size + kHash3Size;
       }
       else
       {
        kNumHashDirectBytes = 2;
        kMinMatchCheck = 2 + 1;
        kFixHashSize = 0;
       }
      }

      public new void SetStream(System.IO.Stream stream) { base.SetStream(stream); }
      public new void ReleaseStream() { base.ReleaseStream(); }
      
      public new void Init()
      {
       base.Init();
       for (UInt32 i = 0; i < _hashSizeSum; i++)
        _hash[i] = kEmptyHashValue;
       _cyclicBufferPos = 0;
       ReduceOffsets(-1);
      }

      public new void MovePos()
      {
       if (++_cyclicBufferPos >= _cyclicBufferSize)
        _cyclicBufferPos = 0;
       base.MovePos();
       if (_pos == kMaxValForNormalize)
        Normalize();
      }

      public new Byte GetIndexByte(Int32 index) { return base.GetIndexByte(index); }

      public new UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
      { return base.GetMatchLen(index, distance, limit); }

      public new UInt32 GetNumAvailableBytes() { return base.GetNumAvailableBytes(); }

      public void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
        UInt32 matchMaxLen, UInt32 keepAddBufferAfter)
      {
       if (historySize > kMaxValForNormalize - 256)
        throw new Exception();
       _cutValue = 16 + (matchMaxLen >> 1);
        
       UInt32 windowReservSize = (historySize + keepAddBufferBefore +
         matchMaxLen + keepAddBufferAfter) / 2 + 256;

       base.Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize);

       _matchMaxLen = matchMaxLen;

       UInt32 cyclicBufferSize = historySize + 1;
       if (_cyclicBufferSize != cyclicBufferSize)
        _son = new UInt32[(_cyclicBufferSize = cyclicBufferSize) * 2];

       UInt32 hs = kBT2HashSize;

       if (HASH_ARRAY)
       {
        hs = historySize - 1;
        hs |= (hs >> 1);
        hs |= (hs >> 2);
        hs |= (hs >> 4);
        hs |= (hs >> 8);
        hs >>= 1;
        hs |= 0xFFFF;
        if (hs > (1 << 24))
         hs >>= 1;
        _hashMask = hs;
        hs++;
        hs += kFixHashSize;
       }
       if (hs != _hashSizeSum)
        _hash = new UInt32[_hashSizeSum = hs];
      }

      public UInt32 GetMatches(UInt32[] distances)
      {
       UInt32 lenLimit;
       if (_pos + _matchMaxLen <= _streamPos)
        lenLimit = _matchMaxLen;
       else
       {
        lenLimit = _streamPos - _pos;
        if (lenLimit < kMinMatchCheck)
        {
         MovePos();
         return 0;
        }
       }

       UInt32 offset = 0;
       UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
       UInt32 cur = _bufferOffset + _pos;
       UInt32 maxLen = kStartMaxLen; // to avoid items for len < hashSize;
       UInt32 hashValue, hash2Value = 0, hash3Value = 0;

       if (HASH_ARRAY)
       {
        UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
        hash2Value = temp & (kHash2Size - 1);
        temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8);
        hash3Value = temp & (kHash3Size - 1);
        hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
       }
       else
        hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8);

       UInt32 curMatch = _hash[kFixHashSize + hashValue];
       if (HASH_ARRAY)
       {
        UInt32 curMatch2 = _hash[hash2Value];
        UInt32 curMatch3 = _hash[kHash3Offset + hash3Value];
        _hash[hash2Value] = _pos;
        _hash[kHash3Offset + hash3Value] = _pos;
        if (curMatch2 > matchMinPos)
         if (_bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur])
         {
          distances[offset++] = maxLen = 2;
          distances[offset++] = _pos - curMatch2 - 1;
         }
        if (curMatch3 > matchMinPos)
         if (_bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur])
         {
          if (curMatch3 == curMatch2)
           offset -= 2;
          distances[offset++] = maxLen = 3;
          distances[offset++] = _pos - curMatch3 - 1;
          curMatch2 = curMatch3;
         }
        if (offset != 0 && curMatch2 == curMatch)
        {
         offset -= 2;
         maxLen = kStartMaxLen;
        }
       }

       _hash[kFixHashSize + hashValue] = _pos;

       UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
       UInt32 ptr1 = (_cyclicBufferPos << 1);

       UInt32 len0, len1;
       len0 = len1 = kNumHashDirectBytes;
       
       if (kNumHashDirectBytes != 0)
       {
        if (curMatch > matchMinPos)
        {
         if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] !=
           _bufferBase[cur + kNumHashDirectBytes])
         {
          distances[offset++] = maxLen = kNumHashDirectBytes;
          distances[offset++] = _pos - curMatch - 1;
         }
        }
       }
       
       UInt32 count = _cutValue;
       
       while(true)
       {
        if(curMatch <= matchMinPos || count-- == 0)
        {
         _son[ptr0] = _son[ptr1] = kEmptyHashValue;
         break;
        }
        UInt32 delta = _pos - curMatch;
        UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
           (_cyclicBufferPos - delta) :
           (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;

        UInt32 pby1 = _bufferOffset + curMatch;
        UInt32 len = Math.Min(len0, len1);
        if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
        {
         while(++len != lenLimit)
          if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
           break;
         if (maxLen < len)
         {
          distances[offset++] = maxLen = len;
          distances[offset++] = delta - 1;
          if (len == lenLimit)
          {
           _son[ptr1] = _son[cyclicPos];
           _son[ptr0] = _son[cyclicPos + 1];
           break;
          }
         }
        }
        if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
        {
         _son[ptr1] = curMatch;
         ptr1 = cyclicPos + 1;
         curMatch = _son[ptr1];
         len1 = len;
        }
        else
        {
         _son[ptr0] = curMatch;
         ptr0 = cyclicPos;
         curMatch = _son[ptr0];
         len0 = len;
        }
       }
       MovePos();
       return offset;
      }

      public void Skip(UInt32 num)
      {
       do
       {
        UInt32 lenLimit;
        if (_pos + _matchMaxLen <= _streamPos)
         lenLimit = _matchMaxLen;
        else
        {
         lenLimit = _streamPos - _pos;
         if (lenLimit < kMinMatchCheck)
         {
          MovePos();
          continue;
         }
        }

        UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
        UInt32 cur = _bufferOffset + _pos;

        UInt32 hashValue;

        if (HASH_ARRAY)
        {
         UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
         UInt32 hash2Value = temp & (kHash2Size - 1);
         _hash[hash2Value] = _pos;
         temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8);
         UInt32 hash3Value = temp & (kHash3Size - 1);
         _hash[kHash3Offset + hash3Value] = _pos;
         hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
        }
        else
         hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8);

        UInt32 curMatch = _hash[kFixHashSize + hashValue];
        _hash[kFixHashSize + hashValue] = _pos;

        UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
        UInt32 ptr1 = (_cyclicBufferPos << 1);

        UInt32 len0, len1;
        len0 = len1 = kNumHashDirectBytes;

        UInt32 count = _cutValue;
        while (true)
        {
         if (curMatch <= matchMinPos || count-- == 0)
         {
          _son[ptr0] = _son[ptr1] = kEmptyHashValue;
          break;
         }

         UInt32 delta = _pos - curMatch;
         UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
            (_cyclicBufferPos - delta) :
            (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;

         UInt32 pby1 = _bufferOffset + curMatch;
         UInt32 len = Math.Min(len0, len1);
         if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
         {
          while (++len != lenLimit)
           if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
            break;
          if (len == lenLimit)
          {
           _son[ptr1] = _son[cyclicPos];
           _son[ptr0] = _son[cyclicPos + 1];
           break;
          }
         }
         if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
         {
          _son[ptr1] = curMatch;
          ptr1 = cyclicPos + 1;
          curMatch = _son[ptr1];
          len1 = len;
         }
         else
         {
          _son[ptr0] = curMatch;
          ptr0 = cyclicPos;
          curMatch = _son[ptr0];
          len0 = len;
         }
        }
        MovePos();
       }
       while (--num != 0);
      }

      void NormalizeLinks(UInt32[] items, UInt32 numItems, UInt32 subValue)
      {
       for (UInt32 i = 0; i < numItems; i++)
       {
        UInt32 value = items[i];
        if (value <= subValue)
         value = kEmptyHashValue;
        else
         value -= subValue;
        items[i] = value;
       }
      }

      void Normalize()
      {
       UInt32 subValue = _pos - _cyclicBufferSize;
       NormalizeLinks(_son, _cyclicBufferSize * 2, subValue);
       NormalizeLinks(_hash, _hashSizeSum, subValue);
       ReduceOffsets((Int32)subValue);
      }

      public void SetCutValue(UInt32 cutValue) { _cutValue = cutValue; }
     }
    }
    namespace SevenZip.Compression.LZMA
    {
     using RangeCoder;

     public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
     {
      class LenDecoder
      {
       BitDecoder m_Choice = new BitDecoder();
       BitDecoder m_Choice2 = new BitDecoder();
       BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
       BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
       BitTreeDecoder m_HighCoder = new BitTreeDecoder(Base.kNumHighLenBits);
       uint m_NumPosStates = 0;

       public void Create(uint numPosStates)
       {
        for (uint posState = m_NumPosStates; posState < numPosStates; posState++)
        {
         m_LowCoder[posState] = new BitTreeDecoder(Base.kNumLowLenBits);
         m_MidCoder[posState] = new BitTreeDecoder(Base.kNumMidLenBits);
        }
        m_NumPosStates = numPosStates;
       }

       public void Init()
       {
        m_Choice.Init();
        for (uint posState = 0; posState < m_NumPosStates; posState++)
        {
         m_LowCoder[posState].Init();
         m_MidCoder[posState].Init();
        }
        m_Choice2.Init();
        m_HighCoder.Init();
       }

       public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState)
       {
        if (m_Choice.Decode(rangeDecoder) == 0)
         return m_LowCoder[posState].Decode(rangeDecoder);
        else
        {
         uint symbol = Base.kNumLowLenSymbols;
         if (m_Choice2.Decode(rangeDecoder) == 0)
          symbol += m_MidCoder[posState].Decode(rangeDecoder);
         else
         {
          symbol += Base.kNumMidLenSymbols;
          symbol += m_HighCoder.Decode(rangeDecoder);
         }
         return symbol;
        }
       }
      }

      class LiteralDecoder
      {
       struct Decoder2
       {
        BitDecoder[] m_Decoders;
        public void Create() { m_Decoders = new BitDecoder[0x300]; }
        public void Init() { for (int i = 0; i < 0x300; i++) m_Decoders[i].Init(); }

        public byte DecodeNormal(RangeCoder.Decoder rangeDecoder)
        {
         uint symbol = 1;
         do
          symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
         while (symbol < 0x100);
         return (byte)symbol;
        }

        public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte)
        {
         uint symbol = 1;
         do
         {
          uint matchBit = (uint)(matchByte >> 7) & 1;
          matchByte <<= 1;
          uint bit = m_Decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder);
          symbol = (symbol << 1) | bit;
          if (matchBit != bit)
          {
           while (symbol < 0x100)
            symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
           break;
          }
         }
         while (symbol < 0x100);
         return (byte)symbol;
        }
       }

       Decoder2[] m_Coders;
       int m_NumPrevBits;
       int m_NumPosBits;
       uint m_PosMask;

       public void Create(int numPosBits, int numPrevBits)
       {
        if (m_Coders != null && m_NumPrevBits == numPrevBits &&
         m_NumPosBits == numPosBits)
         return;
        m_NumPosBits = numPosBits;
        m_PosMask = ((uint)1 << numPosBits) - 1;
        m_NumPrevBits = numPrevBits;
        uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
        m_Coders = new Decoder2[numStates];
        for (uint i = 0; i < numStates; i++)
         m_Coders[i].Create();
       }

       public void Init()
       {
        uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
        for (uint i = 0; i < numStates; i++)
         m_Coders[i].Init();
       }

       uint GetState(uint pos, byte prevByte)
       { return ((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits)); }

       public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte)
       { return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); }

       public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte)
       { return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); }
      };

      LZ.OutWindow m_OutWindow = new LZ.OutWindow();
      RangeCoder.Decoder m_RangeDecoder = new RangeCoder.Decoder();

      BitDecoder[] m_IsMatchDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
      BitDecoder[] m_IsRepDecoders = new BitDecoder[Base.kNumStates];
      BitDecoder[] m_IsRepG0Decoders = new BitDecoder[Base.kNumStates];
      BitDecoder[] m_IsRepG1Decoders = new BitDecoder[Base.kNumStates];
      BitDecoder[] m_IsRepG2Decoders = new BitDecoder[Base.kNumStates];
      BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];

      BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates];
      BitDecoder[] m_PosDecoders = new BitDecoder[Base.kNumFullDistances - Base.kEndPosModelIndex];

      BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(Base.kNumAlignBits);

      LenDecoder m_LenDecoder = new LenDecoder();
      LenDecoder m_RepLenDecoder = new LenDecoder();

      LiteralDecoder m_LiteralDecoder = new LiteralDecoder();

      uint m_DictionarySize;
      uint m_DictionarySizeCheck;

      uint m_PosStateMask;

      public Decoder()
      {
       m_DictionarySize = 0xFFFFFFFF;
       for (int i = 0; i < Base.kNumLenToPosStates; i++)
        m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits);
      }

      void SetDictionarySize(uint dictionarySize)
      {
       if (m_DictionarySize != dictionarySize)
       {
        m_DictionarySize = dictionarySize;
        m_DictionarySizeCheck = Math.Max(m_DictionarySize, 1);
        uint blockSize = Math.Max(m_DictionarySizeCheck, (1 << 12));
        m_OutWindow.Create(blockSize);
       }
      }

      void SetLiteralProperties(int lp, int lc)
      {
       if (lp > 8)
        throw new InvalidParamException();
       if (lc > 8)
        throw new InvalidParamException();
       m_LiteralDecoder.Create(lp, lc);
      }

      void SetPosBitsProperties(int pb)
      {
       if (pb > Base.kNumPosStatesBitsMax)
        throw new InvalidParamException();
       uint numPosStates = (uint)1 << pb;
       m_LenDecoder.Create(numPosStates);
       m_RepLenDecoder.Create(numPosStates);
       m_PosStateMask = numPosStates - 1;
      }

      bool _solid = false;
      void Init(System.IO.Stream inStream, System.IO.Stream outStream)
      {
       m_RangeDecoder.Init(inStream);
       m_OutWindow.Init(outStream, _solid);

       uint i;
       for (i = 0; i < Base.kNumStates; i++)
       {
        for (uint j = 0; j <= m_PosStateMask; j++)
        {
         uint index = (i << Base.kNumPosStatesBitsMax) + j;
         m_IsMatchDecoders[index].Init();
         m_IsRep0LongDecoders[index].Init();
        }
        m_IsRepDecoders[i].Init();
        m_IsRepG0Decoders[i].Init();
        m_IsRepG1Decoders[i].Init();
        m_IsRepG2Decoders[i].Init();
       }

       m_LiteralDecoder.Init();
       for (i = 0; i < Base.kNumLenToPosStates; i++)
        m_PosSlotDecoder[i].Init();
       // m_PosSpecDecoder.Init();
       for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++)
        m_PosDecoders[i].Init();

       m_LenDecoder.Init();
       m_RepLenDecoder.Init();
       m_PosAlignDecoder.Init();
      }

      public void Code(System.IO.Stream inStream, System.IO.Stream outStream,
       Int64 inSize, Int64 outSize, ICodeProgress progress)
      {
       Init(inStream, outStream);

       Base.State state = new Base.State();
       state.Init();
       uint rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;

       UInt64 nowPos64 = 0;
       UInt64 outSize64 = (UInt64)outSize;
       if (nowPos64 < outSize64)
       {
        if (m_IsMatchDecoders[state.Index << Base.kNumPosStatesBitsMax].Decode(m_RangeDecoder) != 0)
         throw new DataErrorException();
        state.UpdateChar();
        byte b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, 0, 0);
        m_OutWindow.PutByte(b);
        nowPos64++;
       }
       while (nowPos64 < outSize64)
       {
        // UInt64 next = Math.Min(nowPos64 + (1 << 18), outSize64);
         // while(nowPos64 < next)
        {
         uint posState = (uint)nowPos64 & m_PosStateMask;
         if (m_IsMatchDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
         {
          byte b;
          byte prevByte = m_OutWindow.GetByte(0);
          if (!state.IsCharState())
           b = m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder,
            (uint)nowPos64, prevByte, m_OutWindow.GetByte(rep0));
          else
           b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)nowPos64, prevByte);
          m_OutWindow.PutByte(b);
          state.UpdateChar();
          nowPos64++;
         }
         else
         {
          uint len;
          if (m_IsRepDecoders[state.Index].Decode(m_RangeDecoder) == 1)
          {
           if (m_IsRepG0Decoders[state.Index].Decode(m_RangeDecoder) == 0)
           {
            if (m_IsRep0LongDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
            {
             state.UpdateShortRep();
             m_OutWindow.PutByte(m_OutWindow.GetByte(rep0));
             nowPos64++;
             continue;
            }
           }
           else
           {
            UInt32 distance;
            if (m_IsRepG1Decoders[state.Index].Decode(m_RangeDecoder) == 0)
            {
             distance = rep1;
            }
            else
            {
             if (m_IsRepG2Decoders[state.Index].Decode(m_RangeDecoder) == 0)
              distance = rep2;
             else
             {
              distance = rep3;
              rep3 = rep2;
             }
             rep2 = rep1;
            }
            rep1 = rep0;
            rep0 = distance;
           }
           len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + Base.kMatchMinLen;
           state.UpdateRep();
          }
          else
          {
           rep3 = rep2;
           rep2 = rep1;
           rep1 = rep0;
           len = Base.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState);
           state.UpdateMatch();
           uint posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(m_RangeDecoder);
           if (posSlot >= Base.kStartPosModelIndex)
           {
            int numDirectBits = (int)((posSlot >> 1) - 1);
            rep0 = ((2 | (posSlot & 1)) << numDirectBits);
            if (posSlot < Base.kEndPosModelIndex)
             rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders,
               rep0 - posSlot - 1, m_RangeDecoder, numDirectBits);
            else
            {
             rep0 += (m_RangeDecoder.DecodeDirectBits(
              numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits);
             rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder);
            }
           }
           else
            rep0 = posSlot;
          }
          if (rep0 >= m_OutWindow.TrainSize + nowPos64 || rep0 >= m_DictionarySizeCheck)
          {
           if (rep0 == 0xFFFFFFFF)
            break;
           throw new DataErrorException();
          }
          m_OutWindow.CopyBlock(rep0, len);
          nowPos64 += len;
         }
        }
       }
       m_OutWindow.Flush();
       m_OutWindow.ReleaseStream();
       m_RangeDecoder.ReleaseStream();
      }

      public void SetDecoderProperties(byte[] properties)
      {
       if (properties.Length < 5)
        throw new InvalidParamException();
       int lc = properties[0] % 9;
       int remainder = properties[0] / 9;
       int lp = remainder % 5;
       int pb = remainder / 5;
       if (pb > Base.kNumPosStatesBitsMax)
        throw new InvalidParamException();
       UInt32 dictionarySize = 0;
       for (int i = 0; i < 4; i++)
        dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8);
       SetDictionarySize(dictionarySize);
       SetLiteralProperties(lp, lc);
       SetPosBitsProperties(pb);
      }

      public bool Train(System.IO.Stream stream)
      {
       _solid = true;
       return m_OutWindow.Train(stream);
      }

      /*
      public override bool CanRead { get { return true; }}
      public override bool CanWrite { get { return true; }}
      public override bool CanSeek { get { return true; }}
      public override long Length { get { return 0; }}
      public override long Position
      {
       get { return 0; }
       set { }
      }
      public override void Flush() { }
      public override int Read(byte[] buffer, int offset, int count)
      {
       return 0;
      }
      public override void Write(byte[] buffer, int offset, int count)
      {
      }
      public override long Seek(long offset, System.IO.SeekOrigin origin)
      {
       return 0;
      }
      public override void SetLength(long value) {}
      */
     }
    }
    namespace SevenZip.Compression.LZMA
    {
     using RangeCoder;

     public class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
     {
      enum EMatchFinderType
      {
       BT2,
       BT4,
      };

      const UInt32 kIfinityPrice = 0xFFFFFFF;

      static Byte[] g_FastPos = new Byte[1 << 11];

      static Encoder()
      {
       const Byte kFastSlots = 22;
       int c = 2;
       g_FastPos[0] = 0;
       g_FastPos[1] = 1;
       for (Byte slotFast = 2; slotFast < kFastSlots; slotFast++)
       {
        UInt32 k = ((UInt32)1 << ((slotFast >> 1) - 1));
        for (UInt32 j = 0; j < k; j++, c++)
         g_FastPos[c] = slotFast;
       }
      }

      static UInt32 GetPosSlot(UInt32 pos)
      {
       if (pos < (1 << 11))
        return g_FastPos[pos];
       if (pos < (1 << 21))
        return (UInt32)(g_FastPos[pos >> 10] + 20);
       return (UInt32)(g_FastPos[pos >> 20] + 40);
      }

      static UInt32 GetPosSlot2(UInt32 pos)
      {
       if (pos < (1 << 17))
        return (UInt32)(g_FastPos[pos >> 6] + 12);
       if (pos < (1 << 27))
        return (UInt32)(g_FastPos[pos >> 16] + 32);
       return (UInt32)(g_FastPos[pos >> 26] + 52);
      }

      Base.State _state = new Base.State();
      Byte _previousByte;
      UInt32[] _repDistances = new UInt32[Base.kNumRepDistances];

      void BaseInit()
      {
       _state.Init();
       _previousByte = 0;
       for (UInt32 i = 0; i < Base.kNumRepDistances; i++)
        _repDistances[i] = 0;
      }

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

      class LiteralEncoder
      {
       public struct Encoder2
       {
        BitEncoder[] m_Encoders;

        public void Create() { m_Encoders = new BitEncoder[0x300]; }

        public void Init() { for (int i = 0; i < 0x300; i++) m_Encoders[i].Init(); }

        public void Encode(RangeCoder.Encoder rangeEncoder, byte symbol)
        {
         uint context = 1;
         for (int i = 7; i >= 0; i--)
         {
          uint bit = (uint)((symbol >> i) & 1);
          m_Encoders[context].Encode(rangeEncoder, bit);
          context = (context << 1) | bit;
         }
        }

        public void EncodeMatched(RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol)
        {
         uint context = 1;
         bool same = true;
         for (int i = 7; i >= 0; i--)
         {
          uint bit = (uint)((symbol >> i) & 1);
          uint state = context;
          if (same)
          {
           uint matchBit = (uint)((matchByte >> i) & 1);
           state += ((1 + matchBit) << 8);
           same = (matchBit == bit);
          }
          m_Encoders[state].Encode(rangeEncoder, bit);
          context = (context << 1) | bit;
         }
        }

        public uint GetPrice(bool matchMode, byte matchByte, byte symbol)
        {
         uint price = 0;
         uint context = 1;
         int i = 7;
         if (matchMode)
         {
          for (; i >= 0; i--)
          {
           uint matchBit = (uint)(matchByte >> i) & 1;
           uint bit = (uint)(symbol >> i) & 1;
           price += m_Encoders[((1 + matchBit) << 8) + context].GetPrice(bit);
           context = (context << 1) | bit;
           if (matchBit != bit)
           {
            i--;
            break;
           }
          }
         }
         for (; i >= 0; i--)
         {
          uint bit = (uint)(symbol >> i) & 1;
          price += m_Encoders[context].GetPrice(bit);
          context = (context << 1) | bit;
         }
         return price;
        }
       }

       Encoder2[] m_Coders;
       int m_NumPrevBits;
       int m_NumPosBits;
       uint m_PosMask;

       public void Create(int numPosBits, int numPrevBits)
       {
        if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits)
         return;
        m_NumPosBits = numPosBits;
        m_PosMask = ((uint)1 << numPosBits) - 1;
        m_NumPrevBits = numPrevBits;
        uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
        m_Coders = new Encoder2[numStates];
        for (uint i = 0; i < numStates; i++)
         m_Coders[i].Create();
       }

       public void Init()
       {
        uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
        for (uint i = 0; i < numStates; i++)
         m_Coders[i].Init();
       }

       public Encoder2 GetSubCoder(UInt32 pos, Byte prevByte)
       { return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits))]; }
      }

      class LenEncoder
      {
       RangeCoder.BitEncoder _choice = new RangeCoder.BitEncoder();
       RangeCoder.BitEncoder _choice2 = new RangeCoder.BitEncoder();
       RangeCoder.BitTreeEncoder[] _lowCoder = new RangeCoder.BitTreeEncoder[Base.kNumPosStatesEncodingMax];
       RangeCoder.BitTreeEncoder[] _midCoder = new RangeCoder.BitTreeEncoder[Base.kNumPosStatesEncodingMax];
       RangeCoder.BitTreeEncoder _highCoder = new RangeCoder.BitTreeEncoder(Base.kNumHighLenBits);

       public LenEncoder()
       {
        for (UInt32 posState = 0; posState < Base.kNumPosStatesEncodingMax; posState++)
        {
         _lowCoder[posState] = new RangeCoder.BitTreeEncoder(Base.kNumLowLenBits);
         _midCoder[posState] = new RangeCoder.BitTreeEncoder(Base.kNumMidLenBits);
        }
       }

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

       public void Encode(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState)
       {
        if (symbol < Base.kNumLowLenSymbols)
        {
         _choice.Encode(rangeEncoder, 0);
         _lowCoder[posState].Encode(rangeEncoder, symbol);
        }
        else
        {
         symbol -= Base.kNumLowLenSymbols;
         _choice.Encode(rangeEncoder, 1);
         if (symbol < Base.kNumMidLenSymbols)
         {
          _choice2.Encode(rangeEncoder, 0);
          _midCoder[posState].Encode(rangeEncoder, symbol);
         }
         else
         {
          _choice2.Encode(rangeEncoder, 1);
          _highCoder.Encode(rangeEncoder, symbol - Base.kNumMidLenSymbols);
         }
        }
       }

       public void SetPrices(UInt32 posState, UInt32 numSymbols, UInt32[] prices, UInt32 st)
       {
        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 < Base.kNumLowLenSymbols; i++)
        {
         if (i >= numSymbols)
          return;
         prices[st + i] = a0 + _lowCoder[posState].GetPrice(i);
        }
        for (; i < Base.kNumLowLenSymbols + Base.kNumMidLenSymbols; i++)
        {
         if (i >= numSymbols)
          return;
         prices[st + i] = b0 + _midCoder[posState].GetPrice(i - Base.kNumLowLenSymbols);
        }
        for (; i < numSymbols; i++)
         prices[st + i] = b1 + _highCoder.GetPrice(i - Base.kNumLowLenSymbols - Base.kNumMidLenSymbols);
       }
      };

      const UInt32 kNumLenSpecSymbols = Base.kNumLowLenSymbols + Base.kNumMidLenSymbols;

      class LenPriceTableEncoder : LenEncoder
      {
       UInt32[] _prices = new UInt32[Base.kNumLenSymbols << Base.kNumPosStatesBitsEncodingMax];
       UInt32 _tableSize;
       UInt32[] _counters = new UInt32[Base.kNumPosStatesEncodingMax];

       public void SetTableSize(UInt32 tableSize) { _tableSize = tableSize; }

       public UInt32 GetPrice(UInt32 symbol, UInt32 posState)
       {
        return _prices[posState * Base.kNumLenSymbols + symbol];
       }

       void UpdateTable(UInt32 posState)
       {
        SetPrices(posState, _tableSize, _prices, posState * Base.kNumLenSymbols);
        _counters[posState] = _tableSize;
       }

       public void UpdateTables(UInt32 numPosStates)
       {
        for (UInt32 posState = 0; posState < numPosStates; posState++)
         UpdateTable(posState);
       }

       public new void Encode(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState)
       {
        base.Encode(rangeEncoder, symbol, posState);
        if (--_counters[posState] == 0)
         UpdateTable(posState);
       }
      }

      const UInt32 kNumOpts = 1 << 12;
      class Optimal
      {
       public Base.State State;

       public bool Prev1IsChar;
       public bool Prev2;

       public UInt32 PosPrev2;
       public UInt32 BackPrev2;

       public UInt32 Price;
       public UInt32 PosPrev;
       public UInt32 BackPrev;

       public UInt32 Backs0;
       public UInt32 Backs1;
       public UInt32 Backs2;
       public UInt32 Backs3;

       public void MakeAsChar() { BackPrev = 0xFFFFFFFF; Prev1IsChar = false; }
       public void MakeAsShortRep() { BackPrev = 0; ; Prev1IsChar = false; }
       public bool IsShortRep() { return (BackPrev == 0); }
      };
      Optimal[] _optimum = new Optimal[kNumOpts];
      LZ.IMatchFinder _matchFinder = null;
      RangeCoder.Encoder _rangeEncoder = new RangeCoder.Encoder();

      RangeCoder.BitEncoder[] _isMatch = new RangeCoder.BitEncoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
      RangeCoder.BitEncoder[] _isRep = new RangeCoder.BitEncoder[Base.kNumStates];
      RangeCoder.BitEncoder[] _isRepG0 = new RangeCoder.BitEncoder[Base.kNumStates];
      RangeCoder.BitEncoder[] _isRepG1 = new RangeCoder.BitEncoder[Base.kNumStates];
      RangeCoder.BitEncoder[] _isRepG2 = new RangeCoder.BitEncoder[Base.kNumStates];
      RangeCoder.BitEncoder[] _isRep0Long = new RangeCoder.BitEncoder[Base.kNumStates << Base.kNumPosStatesBitsMax];

      RangeCoder.BitTreeEncoder[] _posSlotEncoder = new RangeCoder.BitTreeEncoder[Base.kNumLenToPosStates];
      
      RangeCoder.BitEncoder[] _posEncoders = new RangeCoder.BitEncoder[Base.kNumFullDistances - Base.kEndPosModelIndex];
      RangeCoder.BitTreeEncoder _posAlignEncoder = new RangeCoder.BitTreeEncoder(Base.kNumAlignBits);

      LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder();
      LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder();

      LiteralEncoder _literalEncoder = new LiteralEncoder();

      UInt32[] _matchDistances = new UInt32[Base.kMatchMaxLen * 2 + 2];
      
      UInt32 _numFastBytes = kNumFastBytesDefault;
      UInt32 _longestMatchLength;
      UInt32 _numDistancePairs;

      UInt32 _additionalOffset;

      UInt32 _optimumEndIndex;
      UInt32 _optimumCurrentIndex;

      bool _longestMatchWasFound;

      UInt32[] _posSlotPrices = new UInt32[1 << (Base.kNumPosSlotBits + Base.kNumLenToPosStatesBits)];
      UInt32[] _distancesPrices = new UInt32[Base.kNumFullDistances << Base.kNumLenToPosStatesBits];
      UInt32[] _alignPrices = new UInt32[Base.kAlignTableSize];
      UInt32 _alignPriceCount;

      UInt32 _distTableSize = (kDefaultDictionaryLogSize * 2);

      int _posStateBits = 2;
      UInt32 _posStateMask = (4 - 1);
      int _numLiteralPosStateBits = 0;
      int _numLiteralContextBits = 3;

      UInt32 _dictionarySize = (1 << kDefaultDictionaryLogSize);
      UInt32 _dictionarySizePrev = 0xFFFFFFFF;
      UInt32 _numFastBytesPrev = 0xFFFFFFFF;

      Int64 nowPos64;
      bool _finished;
      System.IO.Stream _inStream;

      EMatchFinderType _matchFinderType = EMatchFinderType.BT4;
      bool _writeEndMark = false;
      
      bool _needReleaseMFStream;

      void Create()
      {
       if (_matchFinder == null)
       {
        LZ.BinTree bt = new LZ.BinTree();
        int numHashBytes = 4;
        if (_matchFinderType == EMatchFinderType.BT2)
         numHashBytes = 2;
        bt.SetType(numHashBytes);
        _matchFinder = bt;
       }
       _literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits);

       if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes)
        return;
       _matchFinder.Create(_dictionarySize, kNumOpts, _numFastBytes, Base.kMatchMaxLen + 1);
       _dictionarySizePrev = _dictionarySize;
       _numFastBytesPrev = _numFastBytes;
      }

      public Encoder()
      {
       for (int i = 0; i < kNumOpts; i++)
        _optimum[i] = new Optimal();
       for (int i = 0; i < Base.kNumLenToPosStates; i++)
        _posSlotEncoder[i] = new RangeCoder.BitTreeEncoder(Base.kNumPosSlotBits);
      }

      void SetWriteEndMarkerMode(bool writeEndMarker)
      {
       _writeEndMark = writeEndMarker;
      }

      void Init()
      {
       BaseInit();
       _rangeEncoder.Init();

       uint i;
       for (i = 0; i < Base.kNumStates; i++)
       {
        for (uint j = 0; j <= _posStateMask; j++)
        {
         uint complexState = (i << Base.kNumPosStatesBitsMax) + j;
         _isMatch[complexState].Init();
         _isRep0Long[complexState].Init();
        }
        _isRep[i].Init();
        _isRepG0[i].Init();
        _isRepG1[i].Init();
        _isRepG2[i].Init();
       }
       _literalEncoder.Init();
       for (i = 0; i < Base.kNumLenToPosStates; i++)
        _posSlotEncoder[i].Init();
       for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++)
        _posEncoders[i].Init();

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

       _posAlignEncoder.Init();

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

      void ReadMatchDistances(out UInt32 lenRes, out UInt32 numDistancePairs)
      {
       lenRes = 0;
       numDistancePairs = _matchFinder.GetMatches(_matchDistances);
       if (numDistancePairs > 0)
       {
        lenRes = _matchDistances[numDistancePairs - 2];
        if (lenRes == _numFastBytes)
         lenRes += _matchFinder.GetMatchLen((int)lenRes - 1, _matchDistances[numDistancePairs - 1],
          Base.kMatchMaxLen - lenRes);
       }
       _additionalOffset++;
      }


      void MovePos(UInt32 num)
      {
       if (num > 0)
       {
        _matchFinder.Skip(num);
        _additionalOffset += num;
       }
      }

      UInt32 GetRepLen1Price(Base.State state, UInt32 posState)
      {
       return _isRepG0[state.Index].GetPrice0() +
         _isRep0Long[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0();
      }

      UInt32 GetPureRepPrice(UInt32 repIndex, Base.State state, UInt32 posState)
      {
       UInt32 price;
       if (repIndex == 0)
       {
        price = _isRepG0[state.Index].GetPrice0();
        price += _isRep0Long[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1();
       }
       else
       {
        price = _isRepG0[state.Index].GetPrice1();
        if (repIndex == 1)
         price += _isRepG1[state.Index].GetPrice0();
        else
        {
         price += _isRepG1[state.Index].GetPrice1();
         price += _isRepG2[state.Index].GetPrice(repIndex - 2);
        }
       }
       return price;
      }

      UInt32 GetRepPrice(UInt32 repIndex, UInt32 len, Base.State state, UInt32 posState)
      {
       UInt32 price = _repMatchLenEncoder.GetPrice(len - Base.kMatchMinLen, posState);
       return price + GetPureRepPrice(repIndex, state, posState);
      }
     
      UInt32 GetPosLenPrice(UInt32 pos, UInt32 len, UInt32 posState)
      {
       UInt32 price;
       UInt32 lenToPosState = Base.GetLenToPosState(len);
       if (pos < Base.kNumFullDistances)
        price = _distancesPrices[(lenToPosState * Base.kNumFullDistances) + pos];
       else
        price = _posSlotPrices[(lenToPosState << Base.kNumPosSlotBits) + GetPosSlot2(pos)] +
         _alignPrices[pos & Base.kAlignMask];
       return price + _lenEncoder.GetPrice(len - Base.kMatchMinLen, posState);
      }

      UInt32 Backward(out 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;
      }

      UInt32[] reps = new UInt32[Base.kNumRepDistances];
      UInt32[] repLens = new UInt32[Base.kNumRepDistances];


      UInt32 GetOptimum(UInt32 position, out UInt32 backRes)
      {
       if (_optimumEndIndex != _optimumCurrentIndex)
       {
        UInt32 lenRes = _optimum[_optimumCurrentIndex].PosPrev - _optimumCurrentIndex;
        backRes = _optimum[_optimumCurrentIndex].BackPrev;
        _optimumCurrentIndex = _optimum[_optimumCurrentIndex].PosPrev;
        return lenRes;
       }
       _optimumCurrentIndex = _optimumEndIndex = 0;

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

       UInt32 numAvailableBytes = _matchFinder.GetNumAvailableBytes() + 1;
       if (numAvailableBytes < 2)
       {
        backRes = 0xFFFFFFFF;
        return 1;
       }
       if (numAvailableBytes > Base.kMatchMaxLen)
        numAvailableBytes = Base.kMatchMaxLen;

       UInt32 repMaxIndex = 0;
       UInt32 i;   
       for (i = 0; i < Base.kNumRepDistances; i++)
       {
        reps[i] = _repDistances[i];
        repLens[i] = _matchFinder.GetMatchLen(0 - 1, reps[i], Base.kMatchMaxLen);
        if (repLens[i] > repLens[repMaxIndex])
         repMaxIndex = i;
       }
       if (repLens[repMaxIndex] >= _numFastBytes)
       {
        backRes = repMaxIndex;
        UInt32 lenRes = repLens[repMaxIndex];
        MovePos(lenRes - 1);
        return lenRes;
       }

       if (lenMain >= _numFastBytes)
       {
        backRes = _matchDistances[numDistancePairs - 1] + Base.kNumRepDistances;
        MovePos(lenMain - 1);
        return lenMain;
       }
       
       Byte currentByte = _matchFinder.GetIndexByte(0 - 1);
       Byte matchByte = _matchFinder.GetIndexByte((Int32)(0 - _repDistances[0] - 1 - 1));

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

       _optimum[0].State = _state;

       UInt32 posState = (position & _posStateMask);

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

       UInt32 matchPrice = _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + 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;

       _optimum[0].Backs0 = reps[0];
       _optimum[0].Backs1 = reps[1];
       _optimum[0].Backs2 = reps[2];
       _optimum[0].Backs3 = reps[3];

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

       for (i = 0; i < Base.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);
         Optimal 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);
         Optimal optimum = _optimum[len];
         if (curAndLenPrice < optimum.Price)
         {
          optimum.Price = curAndLenPrice;
          optimum.PosPrev = 0;
          optimum.BackPrev = distance + Base.kNumRepDistances;
          optimum.Prev1IsChar = false;
         }
         if (len == _matchDistances[offs])
         {
          offs += 2;
          if (offs == numDistancePairs)
           break;
         }
        }
       }

       UInt32 cur = 0;

       while (true)
       {
        cur++;
        if (cur == lenEnd)
         return Backward(out backRes, cur);
        UInt32 newLen;
        ReadMatchDistances(out newLen, out numDistancePairs);
        if (newLen >= _numFastBytes)
        {
         _numDistancePairs = numDistancePairs;
         _longestMatchLength = newLen;
         _longestMatchWasFound = true;
         return Backward(out backRes, cur);
        }
        position++;
        UInt32 posPrev = _optimum[cur].PosPrev;
        Base.State state;
        if (_optimum[cur].Prev1IsChar)
        {
         posPrev--;
         if (_optimum[cur].Prev2)
         {
          state = _optimum[_optimum[cur].PosPrev2].State;
          if (_optimum[cur].BackPrev2 < Base.kNumRepDistances)
           state.UpdateRep();
          else
           state.UpdateMatch();
         }
         else
          state = _optimum[posPrev].State;
         state.UpdateChar();
        }
        else
         state = _optimum[posPrev].State;
        if (posPrev == cur - 1)
        {
         if (_optimum[cur].IsShortRep())
          state.UpdateShortRep();
         else
          state.UpdateChar();
        }
        else
        {
         UInt32 pos;
         if (_optimum[cur].Prev1IsChar && _optimum[cur].Prev2)
         {
          posPrev = _optimum[cur].PosPrev2;
          pos = _optimum[cur].BackPrev2;
          state.UpdateRep();
         }
         else
         {
          pos = _optimum[cur].BackPrev;
          if (pos < Base.kNumRepDistances)
           state.UpdateRep();
          else
           state.UpdateMatch();
         }
         Optimal opt = _optimum[posPrev];
         if (pos < Base.kNumRepDistances)
         {
          if (pos == 0)
          {
           reps[0] = opt.Backs0;
           reps[1] = opt.Backs1;
           reps[2] = opt.Backs2;
           reps[3] = opt.Backs3;
          }
          else if (pos == 1)
          {
           reps[0] = opt.Backs1;
           reps[1] = opt.Backs0;
           reps[2] = opt.Backs2;
           reps[3] = opt.Backs3;
          }
          else if (pos == 2)
          {
           reps[0] = opt.Backs2;
           reps[1] = opt.Backs0;
           reps[2] = opt.Backs1;
           reps[3] = opt.Backs3;
          }
          else
          {
           reps[0] = opt.Backs3;
           reps[1] = opt.Backs0;
           reps[2] = opt.Backs1;
           reps[3] = opt.Backs2;
          }
         }
         else
         {
          reps[0] = (pos - Base.kNumRepDistances);
          reps[1] = opt.Backs0;
          reps[2] = opt.Backs1;
          reps[3] = opt.Backs2;
         }
        }
        _optimum[cur].State = state;
        _optimum[cur].Backs0 = reps[0];
        _optimum[cur].Backs1 = reps[1];
        _optimum[cur].Backs2 = reps[2];
        _optimum[cur].Backs3 = reps[3];
        UInt32 curPrice = _optimum[cur].Price;

        currentByte = _matchFinder.GetIndexByte(0 - 1);
        matchByte = _matchFinder.GetIndexByte((Int32)(0 - reps[0] - 1 - 1));

        posState = (position & _posStateMask);

        UInt32 curAnd1Price = curPrice +
         _isMatch[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0() +
         _literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)).
         GetPrice(!state.IsCharState(), matchByte, currentByte);

        Optimal nextOptimum = _optimum[cur + 1];

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

        matchPrice = curPrice + _isMatch[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1();
        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;
         }
        }

        UInt32 numAvailableBytesFull = _matchFinder.GetNumAvailableBytes() + 1;
        numAvailableBytesFull = Math.Min(kNumOpts - 1 - cur, numAvailableBytesFull);
        numAvailableBytes = numAvailableBytesFull;

        if (numAvailableBytes < 2)
         continue;
        if (numAvailableBytes > _numFastBytes)
         numAvailableBytes = _numFastBytes;
        if (!nextIsChar && matchByte != currentByte)
        {
         // try Literal + rep0
         UInt32 t = Math.Min(numAvailableBytesFull - 1, _numFastBytes);
         UInt32 lenTest2 = _matchFinder.GetMatchLen(0, reps[0], t);
         if (lenTest2 >= 2)
         {
          Base.State state2 = state;
          state2.UpdateChar();
          UInt32 posStateNext = (position + 1) & _posStateMask;
          UInt32 nextRepMatchPrice = curAnd1Price +
           _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1() +
           _isRep[state2.Index].GetPrice1();
          {
           UInt32 offset = cur + 1 + lenTest2;
           while (lenEnd < offset)
            _optimum[++lenEnd].Price = kIfinityPrice;
           UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
            0, lenTest2, state2, posStateNext);
           Optimal 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 < Base.kNumRepDistances; repIndex++)
        {
         UInt32 lenTest = _matchFinder.GetMatchLen(0 - 1, reps[repIndex], numAvailableBytes);
         if (lenTest < 2)
          continue;
         UInt32 lenTestTemp = lenTest;
         do
         {
          while (lenEnd < cur + lenTest)
           _optimum[++lenEnd].Price = kIfinityPrice;
          UInt32 curAndLenPrice = repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState);
          Optimal 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)
         if (lenTest < numAvailableBytesFull)
         {
          UInt32 t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
          UInt32 lenTest2 = _matchFinder.GetMatchLen((Int32)lenTest, reps[repIndex], t);
          if (lenTest2 >= 2)
          {
           Base.State state2 = state;
           state2.UpdateRep();
           UInt32 posStateNext = (position + lenTest) & _posStateMask;
           UInt32 curAndLenCharPrice =
             repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState) +
             _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice0() +
             _literalEncoder.GetSubCoder(position + lenTest,
             _matchFinder.GetIndexByte((Int32)lenTest - 1 - 1)).GetPrice(true,
             _matchFinder.GetIndexByte((Int32)((Int32)lenTest - 1 - (Int32)(reps[repIndex] + 1))),
             _matchFinder.GetIndexByte((Int32)lenTest - 1));
           state2.UpdateChar();
           posStateNext = (position + lenTest + 1) & _posStateMask;
           UInt32 nextMatchPrice = curAndLenCharPrice + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1();
           UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2.Index].GetPrice1();
           
           // for(; lenTest2 >= 2; lenTest2--)
           {
            UInt32 offset = lenTest + 1 + lenTest2;
            while(lenEnd < cur + offset)
             _optimum[++lenEnd].Price = kIfinityPrice;
            UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
            Optimal optimum = _optimum[cur + 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;
            }
           }
          }
         }
        }

        if (newLen > numAvailableBytes)
        {
         newLen = numAvailableBytes;
         for (numDistancePairs = 0; newLen > _matchDistances[numDistancePairs]; numDistancePairs += 2) ;
         _matchDistances[numDistancePairs] = newLen;
         numDistancePairs += 2;
        }
        if (newLen >= startLen)
        {
         normalMatchPrice = matchPrice + _isRep[state.Index].GetPrice0();
         while (lenEnd < cur + newLen)
          _optimum[++lenEnd].Price = kIfinityPrice;

         UInt32 offs = 0;
         while (startLen > _matchDistances[offs])
          offs += 2;

         for (UInt32 lenTest = startLen; ; lenTest++)
         {
          UInt32 curBack = _matchDistances[offs + 1];
          UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState);
          Optimal optimum = _optimum[cur + lenTest];
          if (curAndLenPrice < optimum.Price)
          {
           optimum.Price = curAndLenPrice;
           optimum.PosPrev = cur;
           optimum.BackPrev = curBack + Base.kNumRepDistances;
           optimum.Prev1IsChar = false;
          }

          if (lenTest == _matchDistances[offs])
          {
           if (lenTest < numAvailableBytesFull)
           {
            UInt32 t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
            UInt32 lenTest2 = _matchFinder.GetMatchLen((Int32)lenTest, curBack, t);
            if (lenTest2 >= 2)
            {
             Base.State state2 = state;
             state2.UpdateMatch();
             UInt32 posStateNext = (position + lenTest) & _posStateMask;
             UInt32 curAndLenCharPrice = curAndLenPrice +
              _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice0() +
              _literalEncoder.GetSubCoder(position + lenTest,
              _matchFinder.GetIndexByte((Int32)lenTest - 1 - 1)).
              GetPrice(true,
              _matchFinder.GetIndexByte((Int32)lenTest - (Int32)(curBack + 1) - 1),
              _matchFinder.GetIndexByte((Int32)lenTest - 1));
             state2.UpdateChar();
             posStateNext = (position + lenTest + 1) & _posStateMask;
             UInt32 nextMatchPrice = curAndLenCharPrice + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1();
             UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2.Index].GetPrice1();

             UInt32 offset = lenTest + 1 + lenTest2;
             while (lenEnd < cur + offset)
              _optimum[++lenEnd].Price = kIfinityPrice;
             curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
             optimum = _optimum[cur + 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 + Base.kNumRepDistances;
             }
            }
           }
           offs += 2;
           if (offs == numDistancePairs)
            break;
          }
         }
        }
       }
      }

      bool ChangePair(UInt32 smallDist, UInt32 bigDist)
      {
       const int kDif = 7;
       return (smallDist < ((UInt32)(1) << (32 - kDif)) && bigDist >= (smallDist << kDif));
      }

      void WriteEndMarker(UInt32 posState)
      {
       if (!_writeEndMark)
        return;

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

      void Flush(UInt32 nowPos)
      {
       ReleaseMFStream();
       WriteEndMarker(nowPos & _posStateMask);
       _rangeEncoder.FlushData();
       _rangeEncoder.FlushStream();
      }

      public void CodeOneBlock(out Int64 inSize, out Int64 outSize, out bool finished)
      {
       inSize = 0;
       outSize = 0;
       finished = true;

       if (_inStream != null)
       {
        _matchFinder.SetStream(_inStream);
        _matchFinder.Init();
        _needReleaseMFStream = true;
        _inStream = null;
        if (_trainSize > 0)
         _matchFinder.Skip(_trainSize);
       }

       if (_finished)
        return;
       _finished = true;


       Int64 progressPosValuePrev = nowPos64;
       if (nowPos64 == 0)
       {
        if (_matchFinder.GetNumAvailableBytes() == 0)
        {
         Flush((UInt32)nowPos64);
         return;
        }
        UInt32 len, numDistancePairs; // it's not used
        ReadMatchDistances(out len, out numDistancePairs);
        UInt32 posState = (UInt32)(nowPos64) & _posStateMask;
        _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].Encode(_rangeEncoder, 0);
        _state.UpdateChar();
        Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset));
        _literalEncoder.GetSubCoder((UInt32)(nowPos64), _previousByte).Encode(_rangeEncoder, curByte);
        _previousByte = curByte;
        _additionalOffset--;
        nowPos64++;
       }
       if (_matchFinder.GetNumAvailableBytes() == 0)
       {
        Flush((UInt32)nowPos64);
        return;
       }
       while (true)
       {
        UInt32 pos;
        UInt32 len = GetOptimum((UInt32)nowPos64, out pos);
        
        UInt32 posState = ((UInt32)nowPos64) & _posStateMask;
        UInt32 complexState = (_state.Index << Base.kNumPosStatesBitsMax) + posState;
        if (len == 1 && pos == 0xFFFFFFFF)
        {
         _isMatch[complexState].Encode(_rangeEncoder, 0);
         Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset));
         LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder((UInt32)nowPos64, _previousByte);
         if (!_state.IsCharState())
         {
          Byte matchByte = _matchFinder.GetIndexByte((Int32)(0 - _repDistances[0] - 1 - _additionalOffset));
          subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte);
         }
         else
          subCoder.Encode(_rangeEncoder, curByte);
         _previousByte = curByte;
         _state.UpdateChar();
        }
        else
        {
         _isMatch[complexState].Encode(_rangeEncoder, 1);
         if (pos < Base.kNumRepDistances)
         {
          _isRep[_state.Index].Encode(_rangeEncoder, 1);
          if (pos == 0)
          {
           _isRepG0[_state.Index].Encode(_rangeEncoder, 0);
           if (len == 1)
            _isRep0Long[complexState].Encode(_rangeEncoder, 0);
           else
            _isRep0Long[complexState].Encode(_rangeEncoder, 1);
          }
          else
          {
           _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 (len == 1)
           _state.UpdateShortRep();
          else
          {
           _repMatchLenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
           _state.UpdateRep();
          }
          UInt32 distance = _repDistances[pos];
          if (pos != 0)
          {
           for (UInt32 i = pos; i >= 1; i--)
            _repDistances[i] = _repDistances[i - 1];
           _repDistances[0] = distance;
          }
         }
         else
         {
          _isRep[_state.Index].Encode(_rangeEncoder, 0);
          _state.UpdateMatch();
          _lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
          pos -= Base.kNumRepDistances;
          UInt32 posSlot = GetPosSlot(pos);
          UInt32 lenToPosState = Base.GetLenToPosState(len);
          _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);

          if (posSlot >= Base.kStartPosModelIndex)
          {
           int footerBits = (int)((posSlot >> 1) - 1);
           UInt32 baseVal = ((2 | (posSlot & 1)) << footerBits);
           UInt32 posReduced = pos - baseVal;

           if (posSlot < Base.kEndPosModelIndex)
            RangeCoder.BitTreeEncoder.ReverseEncode(_posEncoders,
              baseVal - posSlot - 1, _rangeEncoder, footerBits, posReduced);
           else
           {
            _rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);
            _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);
            _alignPriceCount++;
           }
          }
          UInt32 distance = pos;
          for (UInt32 i = Base.kNumRepDistances - 1; i >= 1; i--)
           _repDistances[i] = _repDistances[i - 1];
          _repDistances[0] = distance;
          _matchPriceCount++;
         }
         _previousByte = _matchFinder.GetIndexByte((Int32)(len - 1 - _additionalOffset));
        }
        _additionalOffset -= len;
        nowPos64 += len;
        if (_additionalOffset == 0)
        {
         // if (!_fastMode)
         if (_matchPriceCount >= (1 << 7))
          FillDistancesPrices();
         if (_alignPriceCount >= Base.kAlignTableSize)
          FillAlignPrices();
         inSize = nowPos64;
         outSize = _rangeEncoder.GetProcessedSizeAdd();
         if (_matchFinder.GetNumAvailableBytes() == 0)
         {
          Flush((UInt32)nowPos64);
          return;
         }

         if (nowPos64 - progressPosValuePrev >= (1 << 12))
         {
          _finished = false;
          finished = false;
          return;
         }
        }
       }
      }

      void ReleaseMFStream()
      {
       if (_matchFinder != null && _needReleaseMFStream)
       {
        _matchFinder.ReleaseStream();
        _needReleaseMFStream = false;
       }
      }

      void SetOutStream(System.IO.Stream outStream) { _rangeEncoder.SetStream(outStream); }
      void ReleaseOutStream() { _rangeEncoder.ReleaseStream(); }

      void ReleaseStreams()
      {
       ReleaseMFStream();
       ReleaseOutStream();
      }

      void SetStreams(System.IO.Stream inStream, System.IO.Stream outStream,
        Int64 inSize, Int64 outSize)
      {
       _inStream = inStream;
       _finished = false;
       Create();
       SetOutStream(outStream);
       Init();

       // if (!_fastMode)
       {
        FillDistancesPrices();
        FillAlignPrices();
       }

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

       nowPos64 = 0;
      }


      public void Code(System.IO.Stream inStream, System.IO.Stream outStream,
       Int64 inSize, Int64 outSize, ICodeProgress progress)
      {
       _needReleaseMFStream = false;
       try
       {
        SetStreams(inStream, outStream, inSize, outSize);
        while (true)
        {
         Int64 processedInSize;
         Int64 processedOutSize;
         bool finished;
         CodeOneBlock(out processedInSize, out processedOutSize, out finished);
         if (finished)
          return;
         if (progress != null)
         {
          progress.SetProgress(processedInSize, processedOutSize);
         }
        }
       }
       finally
       {
        ReleaseStreams();
       }
      }

      const int kPropSize = 5;
      Byte[] properties = new Byte[kPropSize];

      public void WriteCoderProperties(System.IO.Stream outStream)
      {
       properties[0] = (Byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits);
       for (int i = 0; i < 4; i++)
        properties[1 + i] = (Byte)((_dictionarySize >> (8 * i)) & 0xFF);
       outStream.Write(properties, 0, kPropSize);
      }
      
      UInt32[] tempPrices = new UInt32[Base.kNumFullDistances];
      UInt32 _matchPriceCount;

      void FillDistancesPrices()
      {
       for (UInt32 i = Base.kStartPosModelIndex; i < Base.kNumFullDistances; i++)
       {
        UInt32 posSlot = GetPosSlot(i);
        int footerBits = (int)((posSlot >> 1) - 1);
        UInt32 baseVal = ((2 | (posSlot & 1)) << footerBits);
        tempPrices[i] = BitTreeEncoder.ReverseGetPrice(_posEncoders,
         baseVal - posSlot - 1, footerBits, i - baseVal);
       }

       for (UInt32 lenToPosState = 0; lenToPosState < Base.kNumLenToPosStates; lenToPosState++)
       {
        UInt32 posSlot;
        RangeCoder.BitTreeEncoder encoder = _posSlotEncoder[lenToPosState];
       
        UInt32 st = (lenToPosState << Base.kNumPosSlotBits);
        for (posSlot = 0; posSlot < _distTableSize; posSlot++)
         _posSlotPrices[st + posSlot] = encoder.GetPrice(posSlot);
        for (posSlot = Base.kEndPosModelIndex; posSlot < _distTableSize; posSlot++)
         _posSlotPrices[st + posSlot] += ((((posSlot >> 1) - 1) - Base.kNumAlignBits) << RangeCoder.BitEncoder.kNumBitPriceShiftBits);

        UInt32 st2 = lenToPosState * Base.kNumFullDistances;
        UInt32 i;
        for (i = 0; i < Base.kStartPosModelIndex; i++)
         _distancesPrices[st2 + i] = _posSlotPrices[st + i];
        for (; i < Base.kNumFullDistances; i++)
         _distancesPrices[st2 + i] = _posSlotPrices[st + GetPosSlot(i)] + tempPrices[i];
       }
       _matchPriceCount = 0;
      }

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


      static string[] kMatchFinderIDs =
      {
       "BT2",
       "BT4",
      };

      static int FindMatchFinder(string s)
      {
       for (int m = 0; m < kMatchFinderIDs.Length; m++)
        if (s == kMatchFinderIDs[m])
         return m;
       return -1;
      }
     
      public void SetCoderProperties(CoderPropID[] propIDs, object[] properties)
      {
       for (UInt32 i = 0; i < properties.Length; i++)
       {
        object prop = properties[i];
        switch (propIDs[i])
        {
         case CoderPropID.NumFastBytes:
         {
          if (!(prop is Int32))
           throw new InvalidParamException();
          Int32 numFastBytes = (Int32)prop;
          if (numFastBytes < 5 || numFastBytes > Base.kMatchMaxLen)
           throw new InvalidParamException();
          _numFastBytes = (UInt32)numFastBytes;
          break;
         }
         case CoderPropID.Algorithm:
         {
          /*
          if (!(prop is Int32))
           throw new InvalidParamException();
          Int32 maximize = (Int32)prop;
          _fastMode = (maximize == 0);
          _maxMode = (maximize >= 2);
          */
          break;
         }
         case CoderPropID.MatchFinder:
         {
          if (!(prop is String))
           throw new InvalidParamException();
          EMatchFinderType matchFinderIndexPrev = _matchFinderType;
          int m = FindMatchFinder(((string)prop).ToUpper());
          if (m < 0)
           throw new InvalidParamException();
          _matchFinderType = (EMatchFinderType)m;
          if (_matchFinder != null && matchFinderIndexPrev != _matchFinderType)
           {
           _dictionarySizePrev = 0xFFFFFFFF;
           _matchFinder = null;
           }
          break;
         }
         case CoderPropID.DictionarySize:
         {
          const int kDicLogSizeMaxCompress = 30;
          if (!(prop is Int32))
           throw new InvalidParamException(); ;
          Int32 dictionarySize = (Int32)prop;
          if (dictionarySize < (UInt32)(1 << Base.kDicLogSizeMin) ||
           dictionarySize > (UInt32)(1 << kDicLogSizeMaxCompress))
           throw new InvalidParamException();
          _dictionarySize = (UInt32)dictionarySize;
          int dicLogSize;
          for (dicLogSize = 0; dicLogSize < (UInt32)kDicLogSizeMaxCompress; dicLogSize++)
           if (dictionarySize <= ((UInt32)(1) << dicLogSize))
            break;
          _distTableSize = (UInt32)dicLogSize * 2;
          break;
         }
         case CoderPropID.PosStateBits:
         {
          if (!(prop is Int32))
           throw new InvalidParamException();
          Int32 v = (Int32)prop;
          if (v < 0 || v > (UInt32)Base.kNumPosStatesBitsEncodingMax)
           throw new InvalidParamException();
          _posStateBits = (int)v;
          _posStateMask = (((UInt32)1) << (int)_posStateBits) - 1;
          break;
         }
         case CoderPropID.LitPosBits:
         {
          if (!(prop is Int32))
           throw new InvalidParamException();
          Int32 v = (Int32)prop;
          if (v < 0 || v > (UInt32)Base.kNumLitPosStatesBitsEncodingMax)
           throw new InvalidParamException();
          _numLiteralPosStateBits = (int)v;
          break;
         }
         case CoderPropID.LitContextBits:
         {
          if (!(prop is Int32))
           throw new InvalidParamException();
          Int32 v = (Int32)prop;
          if (v < 0 || v > (UInt32)Base.kNumLitContextBitsMax)
           throw new InvalidParamException(); ;
          _numLiteralContextBits = (int)v;
          break;
         }
         case CoderPropID.EndMarker:
         {
          if (!(prop is Boolean))
           throw new InvalidParamException();
          SetWriteEndMarkerMode((Boolean)prop);
          break;
         }
         default:
          throw new InvalidParamException();
        }
       }
      }

      uint _trainSize = 0;
      public void SetTrainSize(uint trainSize)
      {
       _trainSize = trainSize;
      }
      
     }
    }
    namespace SevenZip
    {
     /// <summary>
     /// LZMA Benchmark
     /// </summary>
     internal abstract class LzmaBench
     {
      const UInt32 kAdditionalSize = (6 << 20);
      const UInt32 kCompressedAdditionalSize = (1 << 10);
      const UInt32 kMaxLzmaPropSize = 10;

      class CRandomGenerator
      {
       UInt32 A1;
       UInt32 A2;
       public CRandomGenerator() { Init(); }
       public void Init() { A1 = 362436069; A2 = 521288629; }
       public UInt32 GetRnd()
       {
        return
         ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) ^
         ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)));
       }
      };

      class CBitRandomGenerator
      {
       CRandomGenerator RG = new CRandomGenerator();
       UInt32 Value;
       int NumBits;
       public void Init()
       {
        Value = 0;
        NumBits = 0;
       }
       public UInt32 GetRnd(int numBits)
       {
        UInt32 result;
        if (NumBits > numBits)
        {
         result = Value & (((UInt32)1 << numBits) - 1);
         Value >>= numBits;
         NumBits -= numBits;
         return result;
        }
        numBits -= NumBits;
        result = (Value << numBits);
        Value = RG.GetRnd();
        result |= Value & (((UInt32)1 << numBits) - 1);
        Value >>= numBits;
        NumBits = 32 - numBits;
        return result;
       }
      };

      class CBenchRandomGenerator
      {
       CBitRandomGenerator RG = new CBitRandomGenerator();
       UInt32 Pos;
       UInt32 Rep0;
       
       public UInt32 BufferSize;
       public Byte[] Buffer = null;

       public CBenchRandomGenerator() { }

       public void Set(UInt32 bufferSize)
       {
        Buffer = new Byte[bufferSize];
        Pos = 0;
        BufferSize = bufferSize;
       }
       UInt32 GetRndBit() { return RG.GetRnd(1); }
       UInt32 GetLogRandBits(int numBits)
       {
        UInt32 len = RG.GetRnd(numBits);
        return RG.GetRnd((int)len);
       }
       UInt32 GetOffset()
       {
        if (GetRndBit() == 0)
         return GetLogRandBits(4);
        return (GetLogRandBits(4) << 10) | RG.GetRnd(10);
       }
       UInt32 GetLen1() { return RG.GetRnd(1 + (int)RG.GetRnd(2)); }
       UInt32 GetLen2() { return RG.GetRnd(2 + (int)RG.GetRnd(2)); }
       public void Generate()
       {
        RG.Init();
        Rep0 = 1;
        while (Pos < BufferSize)
        {
         if (GetRndBit() == 0 || Pos < 1)
          Buffer[Pos++] = (Byte)RG.GetRnd(8);
         else
         {
          UInt32 len;
          if (RG.GetRnd(3) == 0)
           len = 1 + GetLen1();
          else
          {
           do
            Rep0 = GetOffset();
           while (Rep0 >= Pos);
           Rep0++;
           len = 2 + GetLen2();
          }
          for (UInt32 i = 0; i < len && Pos < BufferSize; i++, Pos++)
           Buffer[Pos] = Buffer[Pos - Rep0];
         }
        }
       }
      };

      class CrcOutStream : System.IO.Stream
      {
       public CRC CRC = new CRC();
       public void Init() { CRC.Init(); }
       public UInt32 GetDigest() { return CRC.GetDigest(); }

       public override bool CanRead { get { return false; } }
       public override bool CanSeek { get { return false; } }
       public override bool CanWrite { get { return true; } }
       public override Int64 Length { get { return 0; } }
       public override Int64 Position { get { return 0; } set { } }
       public override void Flush() { }
       public override long Seek(long offset, SeekOrigin origin) { return 0; }
       public override void SetLength(long value) { }
       public override int Read(byte[] buffer, int offset, int count) { return 0; }

       public override void WriteByte(byte b)
       {
        CRC.UpdateByte(b);
       }
       public override void Write(byte[] buffer, int offset, int count)
       {
        CRC.Update(buffer, (uint)offset, (uint)count);
       }
      };

      class CProgressInfo : ICodeProgress
      {
       public Int64 ApprovedStart;
       public Int64 InSize;
       public System.DateTime Time;
       public void Init() { InSize = 0; }
       public void SetProgress(Int64 inSize, Int64 outSize)
       {
        if (inSize >= ApprovedStart && InSize == 0)
        {
         Time = DateTime.UtcNow;
         InSize = inSize;
        }
       }
      }
      const int kSubBits = 8;

      static UInt32 GetLogSize(UInt32 size)
      {
       for (int i = kSubBits; i < 32; i++)
        for (UInt32 j = 0; j < (1 << kSubBits); j++)
         if (size <= (((UInt32)1) << i) + (j << (i - kSubBits)))
          return (UInt32)(i << kSubBits) + j;
       return (32 << kSubBits);
      }

      static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime)
      {
       UInt64 freq = TimeSpan.TicksPerSecond;
       UInt64 elTime = elapsedTime;
       while (freq > 1000000)
       {
        freq >>= 1;
        elTime >>= 1;
       }
       if (elTime == 0)
        elTime = 1;
       return value * freq / elTime;
      }

      static UInt64 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 size)
      {
       UInt64 t = GetLogSize(dictionarySize) - (18 << kSubBits);
       UInt64 numCommandsForOne = 1060 + ((t * t * 10) >> (2 * kSubBits));
       UInt64 numCommands = (UInt64)(size) * numCommandsForOne;
       return MyMultDiv64(numCommands, elapsedTime);
      }

      static UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 outSize, UInt64 inSize)
      {
       UInt64 numCommands = inSize * 220 + outSize * 20;
       return MyMultDiv64(numCommands, elapsedTime);
      }

      static UInt64 GetTotalRating(
       UInt32 dictionarySize,
       UInt64 elapsedTimeEn, UInt64 sizeEn,
       UInt64 elapsedTimeDe,
       UInt64 inSizeDe, UInt64 outSizeDe)
      {
       return (GetCompressRating(dictionarySize, elapsedTimeEn, sizeEn) +
        GetDecompressRating(elapsedTimeDe, inSizeDe, outSizeDe)) / 2;
      }

      static void PrintValue(UInt64 v)
      {
       string s = v.ToString();
       for (int i = 0; i + s.Length < 6; i++)
        System.Console.Write(" ");
       System.Console.Write(s);
      }

      static void PrintRating(UInt64 rating)
      {
       PrintValue(rating / 1000000);
       System.Console.Write(" MIPS");
      }

      static void PrintResults(
       UInt32 dictionarySize,
       UInt64 elapsedTime,
       UInt64 size,
       bool decompressMode, UInt64 secondSize)
      {
       UInt64 speed = MyMultDiv64(size, elapsedTime);
       PrintValue(speed / 1024);
       System.Console.Write(" KB/s  ");
       UInt64 rating;
       if (decompressMode)
        rating = GetDecompressRating(elapsedTime, size, secondSize);
       else
        rating = GetCompressRating(dictionarySize, elapsedTime, size);
       PrintRating(rating);
      }

      static public int LzmaBenchmark(Int32 numIterations, UInt32 dictionarySize)
      {
       if (numIterations <= 0)
        return 0;
       if (dictionarySize < (1 << 18))
       {
        System.Console.WriteLine("\nError: dictionary size for benchmark must be >= 19 (512 KB)");
        return 1;
       }
       System.Console.Write("\n       Compressing                Decompressing\n\n");

       Compression.LZMA.Encoder encoder = new Compression.LZMA.Encoder();
       Compression.LZMA.Decoder decoder = new Compression.LZMA.Decoder();


       CoderPropID[] propIDs =
       {
        CoderPropID.DictionarySize,
       };
       object[] properties =
       {
        (Int32)(dictionarySize),
       };

       UInt32 kBufferSize = dictionarySize + kAdditionalSize;
       UInt32 kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize;

       encoder.SetCoderProperties(propIDs, properties);
       System.IO.MemoryStream propStream = new System.IO.MemoryStream();
       encoder.WriteCoderProperties(propStream);
       byte[] propArray = propStream.ToArray();

       CBenchRandomGenerator rg = new CBenchRandomGenerator();

       rg.Set(kBufferSize);
       rg.Generate();
       CRC crc = new CRC();
       crc.Init();
       crc.Update(rg.Buffer, 0, rg.BufferSize);

       CProgressInfo progressInfo = new CProgressInfo();
       progressInfo.ApprovedStart = dictionarySize;

       UInt64 totalBenchSize = 0;
       UInt64 totalEncodeTime = 0;
       UInt64 totalDecodeTime = 0;
       UInt64 totalCompressedSize = 0;

       MemoryStream inStream = new MemoryStream(rg.Buffer, 0, (int)rg.BufferSize);
       MemoryStream compressedStream = new MemoryStream((int)kCompressedBufferSize);
       CrcOutStream crcOutStream = new CrcOutStream();
       for (Int32 i = 0; i < numIterations; i++)
       {
        progressInfo.Init();
        inStream.Seek(0, SeekOrigin.Begin);
        compressedStream.Seek(0, SeekOrigin.Begin);
        encoder.Code(inStream, compressedStream, -1, -1, progressInfo);
        TimeSpan sp2 = DateTime.UtcNow - progressInfo.Time;
        UInt64 encodeTime = (UInt64)sp2.Ticks;

        long compressedSize = compressedStream.Position;
        if (progressInfo.InSize == 0)
         throw (new Exception("Internal ERROR 1282"));

        UInt64 decodeTime = 0;
        for (int j = 0; j < 2; j++)
        {
         compressedStream.Seek(0, SeekOrigin.Begin);
         crcOutStream.Init();

         decoder.SetDecoderProperties(propArray);
         UInt64 outSize = kBufferSize;
         System.DateTime startTime = DateTime.UtcNow;
         decoder.Code(compressedStream, crcOutStream, 0, (Int64)outSize, null);
         TimeSpan sp = (DateTime.UtcNow - startTime);
         decodeTime = (ulong)sp.Ticks;
         if (crcOutStream.GetDigest() != crc.GetDigest())
          throw (new Exception("CRC Error"));
        }
        UInt64 benchSize = kBufferSize - (UInt64)progressInfo.InSize;
        PrintResults(dictionarySize, encodeTime, benchSize, false, 0);
        System.Console.Write("     ");
        PrintResults(dictionarySize, decodeTime, kBufferSize, true, (ulong)compressedSize);
        System.Console.WriteLine();

        totalBenchSize += benchSize;
        totalEncodeTime += encodeTime;
        totalDecodeTime += decodeTime;
        totalCompressedSize += (ulong)compressedSize;
       }
       System.Console.WriteLine("---------------------------------------------------");
       PrintResults(dictionarySize, totalEncodeTime, totalBenchSize, false, 0);
       System.Console.Write("     ");
       PrintResults(dictionarySize, totalDecodeTime,
         kBufferSize * (UInt64)numIterations, true, totalCompressedSize);
       System.Console.WriteLine("    Average");
       return 0;
      }
     }
    }
    namespace SevenZip
    {
     using CommandLineParser;
     
     public class CDoubleStream: Stream
     {
      public System.IO.Stream s1;
      public System.IO.Stream s2;
      public int fileIndex;
      public long skipSize;
      
      public override bool CanRead { get { return true; }}
      public override bool CanWrite { get { return false; }}
      public override bool CanSeek { get { return false; }}
      public override long Length { get { return s1.Length + s2.Length - skipSize; } }
      public override long Position
      {
       get { return 0; }
       set { }
      }
      public override void Flush() { }
      public override int Read(byte[] buffer, int offset, int count)
      {
       int numTotal = 0;
       while (count > 0)
       {
        if (fileIndex == 0)
        {
         int num = s1.Read(buffer, offset, count);
         offset += num;
         count -= num;
         numTotal += num;
         if (num == 0)
          fileIndex++;
        }
        if (fileIndex == 1)
        {
         numTotal += s2.Read(buffer, offset, count);
         return numTotal;
        }
       }
       return numTotal;
      }
      public override void Write(byte[] buffer, int offset, int count)
      {
       throw (new Exception("can't Write"));
      }
      public override long Seek(long offset, System.IO.SeekOrigin origin)
      {
       throw (new Exception("can't Seek"));
      }
      public override void SetLength(long value)
      {
       throw (new Exception("can't SetLength"));
      }
     }
     
     class LzmaAlone
     {
      enum Key
      {
       Help1 = 0,
       Help2,
       Mode,
       Dictionary,
       FastBytes,
       LitContext,
       LitPos,
       PosBits,
       MatchFinder,
       EOS,
       StdIn,
       StdOut,
       Train
      };

      static void PrintHelp()
      {
       System.Console.WriteLine("\nUsage:  LZMA <e|d> [<switches>...] inputFile outputFile\n" +
        "  e: encode file\n" +
        "  d: decode file\n" +
        "  b: Benchmark\n" +
        "<Switches>\n" +
        // "  -a{N}:  set compression mode - [0, 1], default: 1 (max)\n" +
        "  -d{N}:  set dictionary - [0, 29], default: 23 (8MB)\n" +
        "  -fb{N}: set number of fast bytes - [5, 273], default: 128\n" +
        "  -lc{N}: set number of literal context bits - [0, 8], default: 3\n" +
        "  -lp{N}: set number of literal pos bits - [0, 4], default: 0\n" +
        "  -pb{N}: set number of pos bits - [0, 4], default: 2\n" +
        "  -mf{MF_ID}: set Match Finder: [bt2, bt4], default: bt4\n" +
        "  -eos:   write End Of Stream marker\n"
        // + "  -si:    read data from stdin\n"
        // + "  -so:    write data to stdout\n"
        );
      }

      static bool GetNumber(string s, out Int32 v)
      {
       v = 0;
       for (int i = 0; i < s.Length; i++)
       {
        char c = s[i];
        if (c < '0' || c > '9')
         return false;
        v *= 10;
        v += (Int32)(c - '0');
       }
       return true;
      }

      static int IncorrectCommand()
      {
       throw (new Exception("Command line error"));
       // System.Console.WriteLine("\nCommand line error\n");
       // return 1;
      }
      static int Main2(string[] args)
      {
       System.Console.WriteLine("\nLZMA# 4.61  2008-11-23\n");

       if (args.Length == 0)
       {
        PrintHelp();
        return 0;
       }

       SwitchForm[] kSwitchForms = new SwitchForm[13];
       int sw = 0;
       kSwitchForms[sw++] = new SwitchForm("?", SwitchType.Simple, false);
       kSwitchForms[sw++] = new SwitchForm("H", SwitchType.Simple, false);
       kSwitchForms[sw++] = new SwitchForm("A", SwitchType.UnLimitedPostString, false, 1);
       kSwitchForms[sw++] = new SwitchForm("D", SwitchType.UnLimitedPostString, false, 1);
       kSwitchForms[sw++] = new SwitchForm("FB", SwitchType.UnLimitedPostString, false, 1);
       kSwitchForms[sw++] = new SwitchForm("LC", SwitchType.UnLimitedPostString, false, 1);
       kSwitchForms[sw++] = new SwitchForm("LP", SwitchType.UnLimitedPostString, false, 1);
       kSwitchForms[sw++] = new SwitchForm("PB", SwitchType.UnLimitedPostString, false, 1);
       kSwitchForms[sw++] = new SwitchForm("MF", SwitchType.UnLimitedPostString, false, 1);
       kSwitchForms[sw++] = new SwitchForm("EOS", SwitchType.Simple, false);
       kSwitchForms[sw++] = new SwitchForm("SI", SwitchType.Simple, false);
       kSwitchForms[sw++] = new SwitchForm("SO", SwitchType.Simple, false);
       kSwitchForms[sw++] = new SwitchForm("T", SwitchType.UnLimitedPostString, false, 1);


       Parser parser = new Parser(sw);
       try
       {
        parser.ParseStrings(kSwitchForms, args);
       }
       catch
       {
        return IncorrectCommand();
       }

       if (parser[(int)Key.Help1].ThereIs || parser[(int)Key.Help2].ThereIs)
       {
        PrintHelp();
        return 0;
       }

       System.Collections.ArrayList nonSwitchStrings = parser.NonSwitchStrings;

       int paramIndex = 0;
       if (paramIndex >= nonSwitchStrings.Count)
        return IncorrectCommand();
       string command = (string)nonSwitchStrings[paramIndex++];
       command = command.ToLower();

       bool dictionaryIsDefined = false;
       Int32 dictionary = 1 << 21;
       if (parser[(int)Key.Dictionary].ThereIs)
       {
        Int32 dicLog;
        if (!GetNumber((string)parser[(int)Key.Dictionary].PostStrings[0], out dicLog))
         IncorrectCommand();
        dictionary = (Int32)1 << dicLog;
        dictionaryIsDefined = true;
       }
       string mf = "bt4";
       if (parser[(int)Key.MatchFinder].ThereIs)
        mf = (string)parser[(int)Key.MatchFinder].PostStrings[0];
       mf = mf.ToLower();

       if (command == "b")
       {
        const Int32 kNumDefaultItereations = 10;
        Int32 numIterations = kNumDefaultItereations;
        if (paramIndex < nonSwitchStrings.Count)
         if (!GetNumber((string)nonSwitchStrings[paramIndex++], out numIterations))
          numIterations = kNumDefaultItereations;
        return LzmaBench.LzmaBenchmark(numIterations, (UInt32)dictionary);
       }

       string train = "";
       if (parser[(int)Key.Train].ThereIs)
        train = (string)parser[(int)Key.Train].PostStrings[0];

       bool encodeMode = false;
       if (command == "e")
        encodeMode = true;
       else if (command == "d")
        encodeMode = false;
       else
        IncorrectCommand();

       bool stdInMode = parser[(int)Key.StdIn].ThereIs;
       bool stdOutMode = parser[(int)Key.StdOut].ThereIs;

       Stream inStream = null;
       if (stdInMode)
       {
        throw (new Exception("Not implemeted"));
       }
       else
       {
        if (paramIndex >= nonSwitchStrings.Count)
         IncorrectCommand();
        string inputName = (string)nonSwitchStrings[paramIndex++];
        inStream = new FileStream(inputName, FileMode.Open, FileAccess.Read);
       }

       FileStream outStream = null;
       if (stdOutMode)
       {
        throw (new Exception("Not implemeted"));
       }
       else
       {
        if (paramIndex >= nonSwitchStrings.Count)
         IncorrectCommand();
        string outputName = (string)nonSwitchStrings[paramIndex++];
        outStream = new FileStream(outputName, FileMode.Create, FileAccess.Write);
       }

       FileStream trainStream = null;
       if (train.Length != 0)
        trainStream = new FileStream(train, FileMode.Open, FileAccess.Read);

       if (encodeMode)
       {
        if (!dictionaryIsDefined)
         dictionary = 1 << 23;

        Int32 posStateBits = 2;
        Int32 litContextBits = 3; // for normal files
        // UInt32 litContextBits = 0; // for 32-bit data
        Int32 litPosBits = 0;
        // UInt32 litPosBits = 2; // for 32-bit data
        Int32 algorithm = 2;
        Int32 numFastBytes = 128;

        bool eos = parser[(int)Key.EOS].ThereIs || stdInMode;

        if (parser[(int)Key.Mode].ThereIs)
         if (!GetNumber((string)parser[(int)Key.Mode].PostStrings[0], out algorithm))
          IncorrectCommand();

        if (parser[(int)Key.FastBytes].ThereIs)
         if (!GetNumber((string)parser[(int)Key.FastBytes].PostStrings[0], out numFastBytes))
          IncorrectCommand();
        if (parser[(int)Key.LitContext].ThereIs)
         if (!GetNumber((string)parser[(int)Key.LitContext].PostStrings[0], out litContextBits))
          IncorrectCommand();
        if (parser[(int)Key.LitPos].ThereIs)
         if (!GetNumber((string)parser[(int)Key.LitPos].PostStrings[0], out litPosBits))
          IncorrectCommand();
        if (parser[(int)Key.PosBits].ThereIs)
         if (!GetNumber((string)parser[(int)Key.PosBits].PostStrings[0], out posStateBits))
          IncorrectCommand();

        CoderPropID[] propIDs =
        {
         CoderPropID.DictionarySize,
         CoderPropID.PosStateBits,
         CoderPropID.LitContextBits,
         CoderPropID.LitPosBits,
         CoderPropID.Algorithm,
         CoderPropID.NumFastBytes,
         CoderPropID.MatchFinder,
         CoderPropID.EndMarker
        };
        object[] properties =
        {
         (Int32)(dictionary),
         (Int32)(posStateBits),
         (Int32)(litContextBits),
         (Int32)(litPosBits),
         (Int32)(algorithm),
         (Int32)(numFastBytes),
         mf,
         eos
        };

        Compression.LZMA.Encoder encoder = new Compression.LZMA.Encoder();
        encoder.SetCoderProperties(propIDs, properties);
        encoder.WriteCoderProperties(outStream);
        Int64 fileSize;
        if (eos || stdInMode)
         fileSize = -1;
        else
         fileSize = inStream.Length;
        for (int i = 0; i < 8; i++)
         outStream.WriteByte((Byte)(fileSize >> (8 * i)));
        if (trainStream != null)
        {
         CDoubleStream doubleStream = new CDoubleStream();
         doubleStream.s1 = trainStream;
         doubleStream.s2 = inStream;
         doubleStream.fileIndex = 0;
         inStream = doubleStream;
         long trainFileSize = trainStream.Length;
         doubleStream.skipSize = 0;
         if (trainFileSize > dictionary)
          doubleStream.skipSize = trainFileSize - dictionary;
         trainStream.Seek(doubleStream.skipSize, SeekOrigin.Begin);
         encoder.SetTrainSize((uint)(trainFileSize - doubleStream.skipSize));
        }
        encoder.Code(inStream, outStream, -1, -1, null);
       }
       else if (command == "d")
       {
        byte[] properties = new byte[5];
        if (inStream.Read(properties, 0, 5) != 5)
         throw (new Exception("input .lzma is too short"));
        Compression.LZMA.Decoder decoder = new Compression.LZMA.Decoder();
        decoder.SetDecoderProperties(properties);
        if (trainStream != null)
        {
         if (!decoder.Train(trainStream))
          throw (new Exception("can't train"));
        }
        long outSize = 0;
        for (int i = 0; i < 8; i++)
        {
         int v = inStream.ReadByte();
         if (v < 0)
          throw (new Exception("Can't Read 1"));
         outSize |= ((long)(byte)v) << (8 * i);
        }
        long compressedSize = inStream.Length - inStream.Position;
        decoder.Code(inStream, outStream, compressedSize, outSize, null);
       }
       else
        throw (new Exception("Command Error"));
       return 0;
      }

      [STAThread]
      static int Main(string[] args)
      {
       try
       {
        return Main2(args);
       }
       catch (Exception e)
       {
        Console.WriteLine("{0} Caught exception #1.", e);
        // throw e;
        return 1;
       }
      }
     }
    }

  • 相关阅读:
    创建可按比例调整的布局的 Windows 窗体
    Visual C# 2010 实现资源管理器
    Visual C# 2010 实现菜单项和状态栏
    使用异步事件在后台进行计算并报告进度
    A Byte of Python(简明Python教程) for Python 3.0 下载
    面向对象思想
    封装变化(二)
    好玩,看你的博客价值几何?
    基于消息与.Net Remoting的分布式处理架构
    设计之道
  • 原文地址:https://www.cnblogs.com/cnjava/p/2324052.html
Copyright © 2011-2022 走看看