Annotation of elwix/tools/oldlzma/SRC/7zip/Compress/LZMA/LZMAEncoder.cpp, revision 1.1

1.1     ! misho       1: // LZMA/Encoder.cpp
        !             2: 
        !             3: #include "StdAfx.h"
        !             4: 
        !             5: #include "../../../Common/Defs.h"
        !             6: 
        !             7: #include "LZMAEncoder.h"
        !             8: 
        !             9: // for minimal compressing code size define these:
        !            10: // #define COMPRESS_MF_BT
        !            11: // #define COMPRESS_MF_BT4
        !            12: 
        !            13: #if !defined(COMPRESS_MF_BT) && !defined(COMPRESS_MF_PAT) && !defined(COMPRESS_MF_HC)
        !            14: #define COMPRESS_MF_BT
        !            15: #define COMPRESS_MF_PAT
        !            16: #define COMPRESS_MF_HC
        !            17: #endif
        !            18: 
        !            19: #ifdef COMPRESS_MF_BT
        !            20: #if !defined(COMPRESS_MF_BT2) && !defined(COMPRESS_MF_BT3) && !defined(COMPRESS_MF_BT4) && !defined(COMPRESS_MF_BT4B)
        !            21: #define COMPRESS_MF_BT2
        !            22: #define COMPRESS_MF_BT3
        !            23: #define COMPRESS_MF_BT4
        !            24: #define COMPRESS_MF_BT4B
        !            25: #endif
        !            26: #ifdef COMPRESS_MF_BT2
        !            27: #include "../LZ/BinTree/BinTree2.h"
        !            28: #endif
        !            29: #ifdef COMPRESS_MF_BT3
        !            30: #include "../LZ/BinTree/BinTree3.h"
        !            31: #endif
        !            32: #ifdef COMPRESS_MF_BT4
        !            33: #include "../LZ/BinTree/BinTree4.h"
        !            34: #endif
        !            35: #ifdef COMPRESS_MF_BT4B
        !            36: #include "../LZ/BinTree/BinTree4b.h"
        !            37: #endif
        !            38: #endif
        !            39: 
        !            40: #ifdef COMPRESS_MF_PAT
        !            41: #include "../LZ/Patricia/Pat2.h"
        !            42: #include "../LZ/Patricia/Pat2H.h"
        !            43: #include "../LZ/Patricia/Pat3H.h"
        !            44: #include "../LZ/Patricia/Pat4H.h"
        !            45: #include "../LZ/Patricia/Pat2R.h"
        !            46: #endif
        !            47: 
        !            48: #ifdef COMPRESS_MF_HC
        !            49: #include "../LZ/HashChain/HC3.h"
        !            50: #include "../LZ/HashChain/HC4.h"
        !            51: #endif
        !            52: 
        !            53: #ifdef COMPRESS_MF_MT
        !            54: #include "../LZ/MT/MT.h"
        !            55: #endif
        !            56: 
        !            57: namespace NCompress {
        !            58: namespace NLZMA {
        !            59: 
        !            60: const int kDefaultDictionaryLogSize = 20;
        !            61: const UInt32 kNumFastBytesDefault = 0x20;
        !            62: 
        !            63: enum 
        !            64: {
        !            65:   kBT2,
        !            66:   kBT3,
        !            67:   kBT4,
        !            68:   kBT4B,
        !            69:   kPat2,
        !            70:   kPat2H,
        !            71:   kPat3H,
        !            72:   kPat4H,
        !            73:   kPat2R,
        !            74:   kHC3,
        !            75:   kHC4
        !            76: };
        !            77: 
        !            78: static const wchar_t *kMatchFinderIDs[] = 
        !            79: {
        !            80:   L"BT2",
        !            81:   L"BT3",
        !            82:   L"BT4",
        !            83:   L"BT4B",
        !            84:   L"PAT2",
        !            85:   L"PAT2H",
        !            86:   L"PAT3H",
        !            87:   L"PAT4H",
        !            88:   L"PAT2R",
        !            89:   L"HC3",
        !            90:   L"HC4"
        !            91: };
        !            92: 
        !            93: Byte g_FastPos[1024];
        !            94: 
        !            95: class CFastPosInit
        !            96: {
        !            97: public:
        !            98:   CFastPosInit() { Init(); }
        !            99:   void Init()
        !           100:   {
        !           101:     const Byte kFastSlots = 20;
        !           102:     int c = 2;
        !           103:     g_FastPos[0] = 0;
        !           104:     g_FastPos[1] = 1;
        !           105: 
        !           106:     for (Byte slotFast = 2; slotFast < kFastSlots; slotFast++)
        !           107:     {
        !           108:       UInt32 k = (1 << ((slotFast >> 1) - 1));
        !           109:       for (UInt32 j = 0; j < k; j++, c++)
        !           110:         g_FastPos[c] = slotFast;
        !           111:     }
        !           112:   }
        !           113: } g_FastPosInit;
        !           114: 
        !           115: 
        !           116: void CLiteralEncoder2::Encode(NRangeCoder::CEncoder *rangeEncoder, Byte symbol)
        !           117: {
        !           118:   UInt32 context = 1;
        !           119:   int i = 8;
        !           120:   do 
        !           121:   {
        !           122:     i--;
        !           123:     UInt32 bit = (symbol >> i) & 1;
        !           124:     _encoders[context].Encode(rangeEncoder, bit);
        !           125:     context = (context << 1) | bit;
        !           126:   }
        !           127:   while(i != 0);
        !           128: }
        !           129: 
        !           130: void CLiteralEncoder2::EncodeMatched(NRangeCoder::CEncoder *rangeEncoder, 
        !           131:     Byte matchByte, Byte symbol)
        !           132: {
        !           133:   UInt32 context = 1;
        !           134:   int i = 8;
        !           135:   do 
        !           136:   {
        !           137:     i--;
        !           138:     UInt32 bit = (symbol >> i) & 1;
        !           139:     UInt32 matchBit = (matchByte >> i) & 1;
        !           140:     _encoders[0x100 + (matchBit << 8) + context].Encode(rangeEncoder, bit);
        !           141:     context = (context << 1) | bit;
        !           142:     if (matchBit != bit)
        !           143:     {
        !           144:       while(i != 0)
        !           145:       {
        !           146:         i--;
        !           147:         UInt32 bit = (symbol >> i) & 1;
        !           148:         _encoders[context].Encode(rangeEncoder, bit);
        !           149:         context = (context << 1) | bit;
        !           150:       }
        !           151:       break;
        !           152:     }
        !           153:   }
        !           154:   while(i != 0);
        !           155: }
        !           156: 
        !           157: UInt32 CLiteralEncoder2::GetPrice(bool matchMode, Byte matchByte, Byte symbol) const
        !           158: {
        !           159:   UInt32 price = 0;
        !           160:   UInt32 context = 1;
        !           161:   int i = 8;
        !           162:   if (matchMode)
        !           163:   {
        !           164:     do 
        !           165:     {
        !           166:       i--;
        !           167:       UInt32 matchBit = (matchByte >> i) & 1;
        !           168:       UInt32 bit = (symbol >> i) & 1;
        !           169:       price += _encoders[0x100 + (matchBit << 8) + context].GetPrice(bit);
        !           170:       context = (context << 1) | bit;
        !           171:       if (matchBit != bit)
        !           172:         break;
        !           173:     }
        !           174:     while (i != 0);
        !           175:   }
        !           176:   while(i != 0)
        !           177:   {
        !           178:     i--;
        !           179:     UInt32 bit = (symbol >> i) & 1;
        !           180:     price += _encoders[context].GetPrice(bit);
        !           181:     context = (context << 1) | bit;
        !           182:   }
        !           183:   return price;
        !           184: };
        !           185: 
        !           186: 
        !           187: namespace NLength {
        !           188: 
        !           189: void CEncoder::Init(UInt32 numPosStates)
        !           190: {
        !           191:   _choice.Init();
        !           192:   _choice2.Init();
        !           193:   for (UInt32 posState = 0; posState < numPosStates; posState++)
        !           194:   {
        !           195:     _lowCoder[posState].Init();
        !           196:     _midCoder[posState].Init();
        !           197:   }
        !           198:   _highCoder.Init();
        !           199: }
        !           200: 
        !           201: void CEncoder::Encode(NRangeCoder::CEncoder *rangeEncoder, UInt32 symbol, UInt32 posState)
        !           202: {
        !           203:   if(symbol < kNumLowSymbols)
        !           204:   {
        !           205:     _choice.Encode(rangeEncoder, 0);
        !           206:     _lowCoder[posState].Encode(rangeEncoder, symbol);
        !           207:   }
        !           208:   else
        !           209:   {
        !           210:     _choice.Encode(rangeEncoder, 1);
        !           211:     if(symbol < kNumLowSymbols + kNumMidSymbols)
        !           212:     {
        !           213:       _choice2.Encode(rangeEncoder, 0);
        !           214:       _midCoder[posState].Encode(rangeEncoder, symbol - kNumLowSymbols);
        !           215:     }
        !           216:     else
        !           217:     {
        !           218:       _choice2.Encode(rangeEncoder, 1);
        !           219:       _highCoder.Encode(rangeEncoder, symbol - kNumLowSymbols - kNumMidSymbols);
        !           220:     }
        !           221:   }
        !           222: }
        !           223: 
        !           224: UInt32 CEncoder::GetPrice(UInt32 symbol, UInt32 posState) const
        !           225: {
        !           226:   if(symbol < kNumLowSymbols)
        !           227:     return _choice.GetPrice0() + _lowCoder[posState].GetPrice(symbol);
        !           228:   UInt32 price = _choice.GetPrice1();
        !           229:   if(symbol < kNumLowSymbols + kNumMidSymbols)
        !           230:   {
        !           231:     price += _choice2.GetPrice0();
        !           232:     price += _midCoder[posState].GetPrice(symbol - kNumLowSymbols);
        !           233:   }
        !           234:   else
        !           235:   {
        !           236:     price += _choice2.GetPrice1();
        !           237:     price += _highCoder.GetPrice(symbol - kNumLowSymbols - kNumMidSymbols);
        !           238:   }
        !           239:   return price;
        !           240: }
        !           241: 
        !           242: }
        !           243: CEncoder::CEncoder():
        !           244:   _numFastBytes(kNumFastBytesDefault),
        !           245:   _distTableSize(kDefaultDictionaryLogSize * 2),
        !           246:   _posStateBits(2),
        !           247:   _posStateMask(4 - 1),
        !           248:   _numLiteralPosStateBits(0),
        !           249:   _numLiteralContextBits(3),
        !           250:   _dictionarySize(1 << kDefaultDictionaryLogSize),
        !           251:   _dictionarySizePrev(UInt32(-1)),
        !           252:   _numFastBytesPrev(UInt32(-1)),
        !           253:   _matchFinderIndex(kBT4),
        !           254:    #ifdef COMPRESS_MF_MT
        !           255:   _multiThread(false),
        !           256:    #endif
        !           257:   _writeEndMark(false)
        !           258: {
        !           259:   _maxMode = false;
        !           260:   _fastMode = false;
        !           261: }
        !           262: 
        !           263: HRESULT CEncoder::Create()
        !           264: {
        !           265:   if (!_rangeEncoder.Create(1 << 20))
        !           266:     return E_OUTOFMEMORY;
        !           267:   if (!_matchFinder)
        !           268:   {
        !           269:     switch(_matchFinderIndex)
        !           270:     {
        !           271:       #ifdef COMPRESS_MF_BT
        !           272:       #ifdef COMPRESS_MF_BT2
        !           273:       case kBT2:
        !           274:         _matchFinder = new NBT2::CMatchFinderBinTree;
        !           275:         break;
        !           276:       #endif
        !           277:       #ifdef COMPRESS_MF_BT3
        !           278:       case kBT3:
        !           279:         _matchFinder = new NBT3::CMatchFinderBinTree;
        !           280:         break;
        !           281:       #endif
        !           282:       #ifdef COMPRESS_MF_BT4
        !           283:       case kBT4:
        !           284:         _matchFinder = new NBT4::CMatchFinderBinTree;
        !           285:         break;
        !           286:       #endif
        !           287:       #ifdef COMPRESS_MF_BT4B
        !           288:       case kBT4B:
        !           289:         _matchFinder = new NBT4B::CMatchFinderBinTree;
        !           290:         break;
        !           291:       #endif
        !           292:       #endif
        !           293:       
        !           294:       #ifdef COMPRESS_MF_PAT
        !           295:       case kPat2:
        !           296:         _matchFinder = new NPat2::CPatricia;
        !           297:         break;
        !           298:       case kPat2H:
        !           299:         _matchFinder = new NPat2H::CPatricia;
        !           300:         break;
        !           301:       case kPat3H:
        !           302:         _matchFinder = new NPat3H::CPatricia;
        !           303:         break;
        !           304:       case kPat4H:
        !           305:         _matchFinder = new NPat4H::CPatricia;
        !           306:         break;
        !           307:       case kPat2R:
        !           308:         _matchFinder = new NPat2R::CPatricia;
        !           309:         break;
        !           310:       #endif
        !           311: 
        !           312:       #ifdef COMPRESS_MF_HC
        !           313:       case kHC3:
        !           314:         _matchFinder = new NHC3::CMatchFinderHC;
        !           315:         break;
        !           316:       case kHC4:
        !           317:         _matchFinder = new NHC4::CMatchFinderHC;
        !           318:         break;
        !           319:       #endif
        !           320:     }
        !           321:     if (_matchFinder == 0)
        !           322:       return E_OUTOFMEMORY;
        !           323: 
        !           324:     #ifdef COMPRESS_MF_MT
        !           325:     if (_multiThread && !(_fastMode && (_matchFinderIndex == kHC3 || _matchFinderIndex == kHC4)))
        !           326:     {
        !           327:       CMatchFinderMT *mfSpec = new CMatchFinderMT;
        !           328:       if (mfSpec == 0)
        !           329:         return E_OUTOFMEMORY;
        !           330:       CMyComPtr<IMatchFinder> mf = mfSpec;
        !           331:       RINOK(mfSpec->SetMatchFinder(_matchFinder));
        !           332:       _matchFinder.Release();
        !           333:       _matchFinder = mf;
        !           334:     }
        !           335:     #endif
        !           336:   }
        !           337:   
        !           338:   if (!_literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits))
        !           339:     return E_OUTOFMEMORY;
        !           340: 
        !           341:   if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes)
        !           342:     return S_OK;
        !           343:   RINOK(_matchFinder->Create(_dictionarySize, kNumOpts, _numFastBytes, 
        !           344:       kMatchMaxLen - _numFastBytes));
        !           345:   _dictionarySizePrev = _dictionarySize;
        !           346:   _numFastBytesPrev = _numFastBytes;
        !           347:   return S_OK;
        !           348: }
        !           349: 
        !           350: static bool AreStringsEqual(const wchar_t *base, const wchar_t *testString)
        !           351: {
        !           352:   while (true)
        !           353:   {
        !           354:     wchar_t c = *testString;
        !           355:     if (c >= 'a' && c <= 'z')
        !           356:       c -= 0x20;
        !           357:     if (*base != c)
        !           358:       return false;
        !           359:     if (c == 0)
        !           360:       return true;
        !           361:     base++;
        !           362:     testString++;
        !           363:   }
        !           364: }
        !           365: 
        !           366: static int FindMatchFinder(const wchar_t *s)
        !           367: {
        !           368:   for (int m = 0; m < (int)(sizeof(kMatchFinderIDs) / sizeof(kMatchFinderIDs[0])); m++)
        !           369:     if (AreStringsEqual(kMatchFinderIDs[m], s))
        !           370:       return m;
        !           371:   return -1;
        !           372: }
        !           373: 
        !           374: STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, 
        !           375:     const PROPVARIANT *properties, UInt32 numProperties)
        !           376: {
        !           377:   for (UInt32 i = 0; i < numProperties; i++)
        !           378:   {
        !           379:     const PROPVARIANT &prop = properties[i];
        !           380:     switch(propIDs[i])
        !           381:     {
        !           382:       case NCoderPropID::kNumFastBytes:
        !           383:       {
        !           384:         if (prop.vt != VT_UI4)
        !           385:           return E_INVALIDARG;
        !           386:         UInt32 numFastBytes = prop.ulVal;
        !           387:         if(numFastBytes < 2 || numFastBytes > kMatchMaxLen)
        !           388:           return E_INVALIDARG;
        !           389:         _numFastBytes = numFastBytes;
        !           390:         break;
        !           391:       }
        !           392:       case NCoderPropID::kAlgorithm:
        !           393:       {
        !           394:         if (prop.vt != VT_UI4)
        !           395:           return E_INVALIDARG;
        !           396:         UInt32 maximize = prop.ulVal;
        !           397:         _fastMode = (maximize == 0); 
        !           398:         _maxMode = (maximize >= 2);
        !           399:         break;
        !           400:       }
        !           401:       case NCoderPropID::kMatchFinder:
        !           402:       {
        !           403:         if (prop.vt != VT_BSTR)
        !           404:           return E_INVALIDARG;
        !           405:         int matchFinderIndexPrev = _matchFinderIndex;
        !           406:         int m = FindMatchFinder(prop.bstrVal);
        !           407:         if (m < 0)
        !           408:           return E_INVALIDARG;
        !           409:         _matchFinderIndex = m;
        !           410:         if (_matchFinder && matchFinderIndexPrev != _matchFinderIndex)
        !           411:         {
        !           412:           _dictionarySizePrev = UInt32(-1);
        !           413:           _matchFinder.Release();
        !           414:         }
        !           415:         break;
        !           416:       }
        !           417:       #ifdef COMPRESS_MF_MT
        !           418:       case NCoderPropID::kMultiThread:
        !           419:       {
        !           420:         if (prop.vt != VT_BOOL)
        !           421:           return E_INVALIDARG;
        !           422:         bool newMultiThread = (prop.boolVal == VARIANT_TRUE);
        !           423:         if (newMultiThread != _multiThread)
        !           424:         {
        !           425:           _dictionarySizePrev = UInt32(-1);
        !           426:           _matchFinder.Release();
        !           427:         }
        !           428:         _multiThread = newMultiThread;
        !           429:         break;
        !           430:       }
        !           431:       #endif
        !           432:       case NCoderPropID::kDictionarySize:
        !           433:       {
        !           434:         const int kDicLogSizeMaxCompress = 28;
        !           435:         if (prop.vt != VT_UI4)
        !           436:           return E_INVALIDARG;
        !           437:         UInt32 dictionarySize = prop.ulVal;
        !           438:         if (dictionarySize < UInt32(1 << kDicLogSizeMin) ||
        !           439:             dictionarySize > UInt32(1 << kDicLogSizeMaxCompress))
        !           440:           return E_INVALIDARG;
        !           441:         _dictionarySize = dictionarySize;
        !           442:         UInt32 dicLogSize;
        !           443:         for(dicLogSize = 0; dicLogSize < (UInt32)kDicLogSizeMaxCompress; dicLogSize++)
        !           444:           if (dictionarySize <= (UInt32(1) << dicLogSize))
        !           445:             break;
        !           446:         _distTableSize = dicLogSize * 2;
        !           447:         break;
        !           448:       }
        !           449:       case NCoderPropID::kPosStateBits:
        !           450:       {
        !           451:         if (prop.vt != VT_UI4)
        !           452:           return E_INVALIDARG;
        !           453:         UInt32 value = prop.ulVal;
        !           454:         if (value > (UInt32)NLength::kNumPosStatesBitsEncodingMax)
        !           455:           return E_INVALIDARG;
        !           456:         _posStateBits = value;
        !           457:         _posStateMask = (1 << _posStateBits) - 1;
        !           458:         break;
        !           459:       }
        !           460:       case NCoderPropID::kLitPosBits:
        !           461:       {
        !           462:         if (prop.vt != VT_UI4)
        !           463:           return E_INVALIDARG;
        !           464:         UInt32 value = prop.ulVal;
        !           465:         if (value > (UInt32)kNumLitPosStatesBitsEncodingMax)
        !           466:           return E_INVALIDARG;
        !           467:         _numLiteralPosStateBits = value;
        !           468:         break;
        !           469:       }
        !           470:       case NCoderPropID::kLitContextBits:
        !           471:       {
        !           472:         if (prop.vt != VT_UI4)
        !           473:           return E_INVALIDARG;
        !           474:         UInt32 value = prop.ulVal;
        !           475:         if (value > (UInt32)kNumLitContextBitsMax)
        !           476:           return E_INVALIDARG;
        !           477:         _numLiteralContextBits = value;
        !           478:         break;
        !           479:       }
        !           480:       case NCoderPropID::kEndMarker:
        !           481:       {
        !           482:         if (prop.vt != VT_BOOL)
        !           483:           return E_INVALIDARG;
        !           484:         SetWriteEndMarkerMode(prop.boolVal == VARIANT_TRUE);
        !           485:         break;
        !           486:       }
        !           487:       default:
        !           488:         return E_INVALIDARG;
        !           489:     }
        !           490:   }
        !           491:   return S_OK;
        !           492: }
        !           493: 
        !           494: STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
        !           495: { 
        !           496:   const UInt32 kPropSize = 5;
        !           497:   Byte properties[kPropSize];
        !           498:   properties[0] = (_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits;
        !           499:   for (int i = 0; i < 4; i++)
        !           500:     properties[1 + i] = Byte(_dictionarySize >> (8 * i));
        !           501:   return outStream->Write(properties, kPropSize, NULL);
        !           502: }
        !           503: 
        !           504: STDMETHODIMP CEncoder::SetOutStream(ISequentialOutStream *outStream)
        !           505: {
        !           506:   _rangeEncoder.SetStream(outStream);
        !           507:   return S_OK;
        !           508: }
        !           509: 
        !           510: STDMETHODIMP CEncoder::ReleaseOutStream()
        !           511: {
        !           512:   _rangeEncoder.ReleaseStream();
        !           513:   return S_OK;
        !           514: }
        !           515: 
        !           516: HRESULT CEncoder::Init()
        !           517: {
        !           518:   CBaseState::Init();
        !           519: 
        !           520:   // RINOK(_matchFinder->Init(inStream));
        !           521:   _rangeEncoder.Init();
        !           522: 
        !           523:   for(int i = 0; i < kNumStates; i++)
        !           524:   {
        !           525:     for (UInt32 j = 0; j <= _posStateMask; j++)
        !           526:     {
        !           527:       _isMatch[i][j].Init();
        !           528:       _isRep0Long[i][j].Init();
        !           529:     }
        !           530:     _isRep[i].Init();
        !           531:     _isRepG0[i].Init();
        !           532:     _isRepG1[i].Init();
        !           533:     _isRepG2[i].Init();
        !           534:   }
        !           535: 
        !           536:   _literalEncoder.Init();
        !           537: 
        !           538:   // _repMatchLenEncoder.Init();
        !           539:   
        !           540:   {
        !           541:     for(UInt32 i = 0; i < kNumLenToPosStates; i++)
        !           542:       _posSlotEncoder[i].Init();
        !           543:   }
        !           544:   {
        !           545:     for(UInt32 i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
        !           546:       _posEncoders[i].Init();
        !           547:   }
        !           548: 
        !           549:   _lenEncoder.Init(1 << _posStateBits);
        !           550:   _repMatchLenEncoder.Init(1 << _posStateBits);
        !           551: 
        !           552:   _posAlignEncoder.Init();
        !           553: 
        !           554:   _longestMatchWasFound = false;
        !           555:   _optimumEndIndex = 0;
        !           556:   _optimumCurrentIndex = 0;
        !           557:   _additionalOffset = 0;
        !           558: 
        !           559:   return S_OK;
        !           560: }
        !           561: 
        !           562: HRESULT CEncoder::MovePos(UInt32 num)
        !           563: {
        !           564:   for (;num != 0; num--)
        !           565:   {
        !           566:     _matchFinder->DummyLongestMatch();
        !           567:     RINOK(_matchFinder->MovePos());
        !           568:     _additionalOffset++;
        !           569:   }
        !           570:   return S_OK;
        !           571: }
        !           572: 
        !           573: UInt32 CEncoder::Backward(UInt32 &backRes, UInt32 cur)
        !           574: {
        !           575:   _optimumEndIndex = cur;
        !           576:   UInt32 posMem = _optimum[cur].PosPrev;
        !           577:   UInt32 backMem = _optimum[cur].BackPrev;
        !           578:   do
        !           579:   {
        !           580:     if (_optimum[cur].Prev1IsChar)
        !           581:     {
        !           582:       _optimum[posMem].MakeAsChar();
        !           583:       _optimum[posMem].PosPrev = posMem - 1;
        !           584:       if (_optimum[cur].Prev2)
        !           585:       {
        !           586:         _optimum[posMem - 1].Prev1IsChar = false;
        !           587:         _optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2;
        !           588:         _optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2;
        !           589:       }
        !           590:     }
        !           591:     UInt32 posPrev = posMem;
        !           592:     UInt32 backCur = backMem;
        !           593: 
        !           594:     backMem = _optimum[posPrev].BackPrev;
        !           595:     posMem = _optimum[posPrev].PosPrev;
        !           596: 
        !           597:     _optimum[posPrev].BackPrev = backCur;
        !           598:     _optimum[posPrev].PosPrev = cur;
        !           599:     cur = posPrev;
        !           600:   }
        !           601:   while(cur != 0);
        !           602:   backRes = _optimum[0].BackPrev;
        !           603:   _optimumCurrentIndex  = _optimum[0].PosPrev;
        !           604:   return _optimumCurrentIndex; 
        !           605: }
        !           606: 
        !           607: /*
        !           608: inline UInt32 GetMatchLen(const Byte *data, UInt32 back, UInt32 limit)
        !           609: {  
        !           610:   back++;
        !           611:   for(UInt32 i = 0; i < limit && data[i] == data[i - back]; i++);
        !           612:   return i;
        !           613: }
        !           614: */
        !           615: 
        !           616: HRESULT CEncoder::GetOptimum(UInt32 position, UInt32 &backRes, UInt32 &lenRes)
        !           617: {
        !           618:   if(_optimumEndIndex != _optimumCurrentIndex)
        !           619:   {
        !           620:     lenRes = _optimum[_optimumCurrentIndex].PosPrev - _optimumCurrentIndex;
        !           621:     backRes = _optimum[_optimumCurrentIndex].BackPrev;
        !           622:     _optimumCurrentIndex = _optimum[_optimumCurrentIndex].PosPrev;
        !           623:     return S_OK;
        !           624:   }
        !           625:   _optimumCurrentIndex = 0;
        !           626:   _optimumEndIndex = 0; // test it;
        !           627:   
        !           628:   UInt32 lenMain;
        !           629:   if (!_longestMatchWasFound)
        !           630:   {
        !           631:     RINOK(ReadMatchDistances(lenMain));
        !           632:   }
        !           633:   else
        !           634:   {
        !           635:     lenMain = _longestMatchLength;
        !           636:     _longestMatchWasFound = false;
        !           637:   }
        !           638: 
        !           639: 
        !           640:   UInt32 reps[kNumRepDistances];
        !           641:   UInt32 repLens[kNumRepDistances];
        !           642:   UInt32 repMaxIndex = 0;
        !           643:   UInt32 i;
        !           644:   for(i = 0; i < kNumRepDistances; i++)
        !           645:   {
        !           646:     reps[i] = _repDistances[i];
        !           647:     repLens[i] = _matchFinder->GetMatchLen(0 - 1, reps[i], kMatchMaxLen);
        !           648:     if (i == 0 || repLens[i] > repLens[repMaxIndex])
        !           649:       repMaxIndex = i;
        !           650:   }
        !           651:   if(repLens[repMaxIndex] > _numFastBytes)
        !           652:   {
        !           653:     backRes = repMaxIndex;
        !           654:     lenRes = repLens[repMaxIndex];
        !           655:     MovePos(lenRes - 1);
        !           656:     return S_OK;
        !           657:   }
        !           658: 
        !           659:   if(lenMain > _numFastBytes)
        !           660:   {
        !           661:     UInt32 backMain = (lenMain < _numFastBytes) ? _matchDistances[lenMain] :
        !           662:         _matchDistances[_numFastBytes];
        !           663:     backRes = backMain + kNumRepDistances; 
        !           664:     MovePos(lenMain - 1);
        !           665:     lenRes = lenMain;
        !           666:     return S_OK;
        !           667:   }
        !           668:   Byte currentByte = _matchFinder->GetIndexByte(0 - 1);
        !           669: 
        !           670:   _optimum[0].State = _state;
        !           671: 
        !           672:   Byte matchByte;
        !           673:   
        !           674:   matchByte = _matchFinder->GetIndexByte(0 - _repDistances[0] - 1 - 1);
        !           675: 
        !           676:   UInt32 posState = (position & _posStateMask);
        !           677: 
        !           678:   _optimum[1].Price = _isMatch[_state.Index][posState].GetPrice0() + 
        !           679:       _literalEncoder.GetPrice(position, _previousByte, !_state.IsCharState(), matchByte, currentByte);
        !           680:   _optimum[1].MakeAsChar();
        !           681: 
        !           682:   _optimum[1].PosPrev = 0;
        !           683: 
        !           684:   for (i = 0; i < kNumRepDistances; i++)
        !           685:     _optimum[0].Backs[i] = reps[i];
        !           686: 
        !           687:   UInt32 matchPrice = _isMatch[_state.Index][posState].GetPrice1();
        !           688:   UInt32 repMatchPrice = matchPrice + _isRep[_state.Index].GetPrice1();
        !           689: 
        !           690:   if(matchByte == currentByte)
        !           691:   {
        !           692:     UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState);
        !           693:     if(shortRepPrice < _optimum[1].Price)
        !           694:     {
        !           695:       _optimum[1].Price = shortRepPrice;
        !           696:       _optimum[1].MakeAsShortRep();
        !           697:     }
        !           698:   }
        !           699:   if(lenMain < 2)
        !           700:   {
        !           701:     backRes = _optimum[1].BackPrev;
        !           702:     lenRes = 1;
        !           703:     return S_OK;
        !           704:   }
        !           705: 
        !           706:   
        !           707:   UInt32 normalMatchPrice = matchPrice + 
        !           708:       _isRep[_state.Index].GetPrice0();
        !           709: 
        !           710:   if (lenMain <= repLens[repMaxIndex])
        !           711:     lenMain = 0;
        !           712: 
        !           713:   UInt32 len;
        !           714:   for(len = 2; len <= lenMain; len++)
        !           715:   {
        !           716:     _optimum[len].PosPrev = 0;
        !           717:     _optimum[len].BackPrev = _matchDistances[len] + kNumRepDistances;
        !           718:     _optimum[len].Price = normalMatchPrice + 
        !           719:         GetPosLenPrice(_matchDistances[len], len, posState);
        !           720:     _optimum[len].Prev1IsChar = false;
        !           721:   }
        !           722: 
        !           723:   if (lenMain < repLens[repMaxIndex])
        !           724:     lenMain = repLens[repMaxIndex];
        !           725: 
        !           726:   for (; len <= lenMain; len++)
        !           727:     _optimum[len].Price = kIfinityPrice;
        !           728: 
        !           729:   for(i = 0; i < kNumRepDistances; i++)
        !           730:   {
        !           731:     UInt32 repLen = repLens[i];
        !           732:     for(UInt32 lenTest = 2; lenTest <= repLen; lenTest++)
        !           733:     {
        !           734:       UInt32 curAndLenPrice = repMatchPrice + GetRepPrice(i, lenTest, _state, posState);
        !           735:       COptimal &optimum = _optimum[lenTest];
        !           736:       if (curAndLenPrice < optimum.Price) 
        !           737:       {
        !           738:         optimum.Price = curAndLenPrice;
        !           739:         optimum.PosPrev = 0;
        !           740:         optimum.BackPrev = i;
        !           741:         optimum.Prev1IsChar = false;
        !           742:       }
        !           743:     }
        !           744:   }
        !           745: 
        !           746:   UInt32 cur = 0;
        !           747:   UInt32 lenEnd = lenMain;
        !           748: 
        !           749:   while(true)
        !           750:   {
        !           751:     cur++;
        !           752:     if(cur == lenEnd)
        !           753:     {
        !           754:       lenRes = Backward(backRes, cur);
        !           755:       return S_OK;
        !           756:     }
        !           757:     position++;
        !           758:     UInt32 posPrev = _optimum[cur].PosPrev;
        !           759:     CState state;
        !           760:     if (_optimum[cur].Prev1IsChar)
        !           761:     {
        !           762:       posPrev--;
        !           763:       if (_optimum[cur].Prev2)
        !           764:       {
        !           765:         state = _optimum[_optimum[cur].PosPrev2].State;
        !           766:         if (_optimum[cur].BackPrev2 < kNumRepDistances)
        !           767:           state.UpdateRep();
        !           768:         else
        !           769:           state.UpdateMatch();
        !           770:       }
        !           771:       else
        !           772:         state = _optimum[posPrev].State;
        !           773:       state.UpdateChar();
        !           774:     }
        !           775:     else
        !           776:       state = _optimum[posPrev].State;
        !           777:     if (posPrev == cur - 1)
        !           778:     {
        !           779:       if (_optimum[cur].IsShortRep())
        !           780:         state.UpdateShortRep();
        !           781:       else
        !           782:         state.UpdateChar();
        !           783:       /*
        !           784:       if (_optimum[cur].Prev1IsChar)
        !           785:         for(int i = 0; i < kNumRepDistances; i++)
        !           786:           reps[i] = _optimum[posPrev].Backs[i];
        !           787:       */
        !           788:     }
        !           789:     else
        !           790:     {
        !           791:       UInt32 pos;
        !           792:       if (_optimum[cur].Prev1IsChar && _optimum[cur].Prev2)
        !           793:       {
        !           794:         posPrev = _optimum[cur].PosPrev2;
        !           795:         pos = _optimum[cur].BackPrev2;
        !           796:         state.UpdateRep();
        !           797:       }
        !           798:       else
        !           799:       {
        !           800:         pos = _optimum[cur].BackPrev;
        !           801:         if (pos < kNumRepDistances)
        !           802:           state.UpdateRep();
        !           803:         else
        !           804:           state.UpdateMatch();
        !           805:       }
        !           806:       if (pos < kNumRepDistances)
        !           807:       {
        !           808:         reps[0] = _optimum[posPrev].Backs[pos];
        !           809:                UInt32 i;
        !           810:         for(i = 1; i <= pos; i++)
        !           811:           reps[i] = _optimum[posPrev].Backs[i - 1];
        !           812:         for(; i < kNumRepDistances; i++)
        !           813:           reps[i] = _optimum[posPrev].Backs[i];
        !           814:       }
        !           815:       else
        !           816:       {
        !           817:         reps[0] = (pos - kNumRepDistances);
        !           818:         for(UInt32 i = 1; i < kNumRepDistances; i++)
        !           819:           reps[i] = _optimum[posPrev].Backs[i - 1];
        !           820:       }
        !           821:     }
        !           822:     _optimum[cur].State = state;
        !           823:     for(UInt32 i = 0; i < kNumRepDistances; i++)
        !           824:       _optimum[cur].Backs[i] = reps[i];
        !           825:     UInt32 newLen;
        !           826:     RINOK(ReadMatchDistances(newLen));
        !           827:     if(newLen > _numFastBytes)
        !           828:     {
        !           829:       _longestMatchLength = newLen;
        !           830:       _longestMatchWasFound = true;
        !           831:       lenRes = Backward(backRes, cur);
        !           832:       return S_OK;
        !           833:     }
        !           834:     UInt32 curPrice = _optimum[cur].Price; 
        !           835:     // Byte currentByte  = _matchFinder->GetIndexByte(0 - 1);
        !           836:     // Byte matchByte = _matchFinder->GetIndexByte(0 - reps[0] - 1 - 1);
        !           837:     const Byte *data = _matchFinder->GetPointerToCurrentPos() - 1;
        !           838:     Byte currentByte = *data;
        !           839:     Byte matchByte = data[(size_t)0 - reps[0] - 1];
        !           840: 
        !           841:     UInt32 posState = (position & _posStateMask);
        !           842: 
        !           843:     UInt32 curAnd1Price = curPrice +
        !           844:         _isMatch[state.Index][posState].GetPrice0() +
        !           845:         _literalEncoder.GetPrice(position, data[(size_t)0 - 1], !state.IsCharState(), matchByte, currentByte);
        !           846: 
        !           847:     COptimal &nextOptimum = _optimum[cur + 1];
        !           848: 
        !           849:     bool nextIsChar = false;
        !           850:     if (curAnd1Price < nextOptimum.Price) 
        !           851:     {
        !           852:       nextOptimum.Price = curAnd1Price;
        !           853:       nextOptimum.PosPrev = cur;
        !           854:       nextOptimum.MakeAsChar();
        !           855:       nextIsChar = true;
        !           856:     }
        !           857: 
        !           858:     UInt32 matchPrice = curPrice + _isMatch[state.Index][posState].GetPrice1();
        !           859:     UInt32 repMatchPrice = matchPrice + _isRep[state.Index].GetPrice1();
        !           860:     
        !           861:     if(matchByte == currentByte &&
        !           862:         !(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0))
        !           863:     {
        !           864:       UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState);
        !           865:       if(shortRepPrice <= nextOptimum.Price)
        !           866:       {
        !           867:         nextOptimum.Price = shortRepPrice;
        !           868:         nextOptimum.PosPrev = cur;
        !           869:         nextOptimum.MakeAsShortRep();
        !           870:         // nextIsChar = false;
        !           871:       }
        !           872:     }
        !           873:     /*
        !           874:     if(newLen == 2 && _matchDistances[2] >= kDistLimit2) // test it maybe set 2000 ?
        !           875:       continue;
        !           876:     */
        !           877: 
        !           878:     UInt32 numAvailableBytes = _matchFinder->GetNumAvailableBytes() + 1;
        !           879:     numAvailableBytes = MyMin(kNumOpts - 1 - cur, numAvailableBytes);
        !           880: 
        !           881:     if (numAvailableBytes < 2)
        !           882:       continue;
        !           883:     if (numAvailableBytes > _numFastBytes)
        !           884:       numAvailableBytes = _numFastBytes;
        !           885:     if (numAvailableBytes >= 3 && !nextIsChar)
        !           886:     {
        !           887:       UInt32 backOffset = reps[0] + 1;
        !           888:       UInt32 temp;
        !           889:       for (temp = 1; temp < numAvailableBytes; temp++)
        !           890:         if (data[temp] != data[(size_t)temp - backOffset])
        !           891:           break;
        !           892:       UInt32 lenTest2 = temp - 1;
        !           893:       if (lenTest2 >= 2)
        !           894:       {
        !           895:         CState state2 = state;
        !           896:         state2.UpdateChar();
        !           897:         UInt32 posStateNext = (position + 1) & _posStateMask;
        !           898:         UInt32 nextRepMatchPrice = curAnd1Price + 
        !           899:             _isMatch[state2.Index][posStateNext].GetPrice1() +
        !           900:             _isRep[state2.Index].GetPrice1();
        !           901:         // for (; lenTest2 >= 2; lenTest2--)
        !           902:         {
        !           903:           while(lenEnd < cur + 1 + lenTest2)
        !           904:             _optimum[++lenEnd].Price = kIfinityPrice;
        !           905:           UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
        !           906:               0, lenTest2, state2, posStateNext);
        !           907:           COptimal &optimum = _optimum[cur + 1 + lenTest2];
        !           908:           if (curAndLenPrice < optimum.Price) 
        !           909:           {
        !           910:             optimum.Price = curAndLenPrice;
        !           911:             optimum.PosPrev = cur + 1;
        !           912:             optimum.BackPrev = 0;
        !           913:             optimum.Prev1IsChar = true;
        !           914:             optimum.Prev2 = false;
        !           915:           }
        !           916:         }
        !           917:       }
        !           918:     }
        !           919:     for(UInt32 repIndex = 0; repIndex < kNumRepDistances; repIndex++)
        !           920:     {
        !           921:       // UInt32 repLen = _matchFinder->GetMatchLen(0 - 1, reps[repIndex], newLen); // test it;
        !           922:       UInt32 backOffset = reps[repIndex] + 1;
        !           923:       UInt32 lenTest;
        !           924:       for (lenTest = 0; lenTest < numAvailableBytes; lenTest++)
        !           925:         if (data[lenTest] != data[(size_t)lenTest - backOffset])
        !           926:           break;
        !           927:       for(; lenTest >= 2; lenTest--)
        !           928:       {
        !           929:         while(lenEnd < cur + lenTest)
        !           930:           _optimum[++lenEnd].Price = kIfinityPrice;
        !           931:         UInt32 curAndLenPrice = repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState);
        !           932:         COptimal &optimum = _optimum[cur + lenTest];
        !           933:         if (curAndLenPrice < optimum.Price) 
        !           934:         {
        !           935:           optimum.Price = curAndLenPrice;
        !           936:           optimum.PosPrev = cur;
        !           937:           optimum.BackPrev = repIndex;
        !           938:           optimum.Prev1IsChar = false;
        !           939:         }
        !           940: 
        !           941:         /*
        !           942:         if (_maxMode)
        !           943:         {
        !           944:           UInt32 temp;
        !           945:           for (temp = lenTest + 1; temp < numAvailableBytes; temp++)
        !           946:             if (data[temp] != data[(size_t)temp - backOffset])
        !           947:               break;
        !           948:           UInt32 lenTest2 = temp - (lenTest + 1);
        !           949:           if (lenTest2 >= 2)
        !           950:           {
        !           951:             CState state2 = state;
        !           952:             state2.UpdateRep();
        !           953:             UInt32 posStateNext = (position + lenTest) & _posStateMask;
        !           954:             UInt32 curAndLenCharPrice = curAndLenPrice + 
        !           955:                 _isMatch[state2.Index][posStateNext].GetPrice0() +
        !           956:                 _literalEncoder.GetPrice(position + lenTest, data[(size_t)lenTest - 1], 
        !           957:                 true, data[(size_t)lenTest - backOffset], data[lenTest]);
        !           958:             state2.UpdateChar();
        !           959:             posStateNext = (position + lenTest + 1) & _posStateMask;
        !           960:             UInt32 nextMatchPrice = curAndLenCharPrice + _isMatch[state2.Index][posStateNext].GetPrice1();
        !           961:             UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2.Index].GetPrice1();
        !           962:             
        !           963:             // for(; lenTest2 >= 2; lenTest2--)
        !           964:             {
        !           965:               UInt32 offset = lenTest + 1 + lenTest2;
        !           966:               while(lenEnd < cur + offset)
        !           967:                 _optimum[++lenEnd].Price = kIfinityPrice;
        !           968:               UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
        !           969:                   0, lenTest2, state2, posStateNext);
        !           970:               COptimal &optimum = _optimum[cur + offset];
        !           971:               if (curAndLenPrice < optimum.Price) 
        !           972:               {
        !           973:                 optimum.Price = curAndLenPrice;
        !           974:                 optimum.PosPrev = cur + lenTest + 1;
        !           975:                 optimum.BackPrev = 0;
        !           976:                 optimum.Prev1IsChar = true;
        !           977:                 optimum.Prev2 = true;
        !           978:                 optimum.PosPrev2 = cur;
        !           979:                 optimum.BackPrev2 = repIndex;
        !           980:               }
        !           981:             }
        !           982:           }
        !           983:         }
        !           984:         */
        !           985:       }
        !           986:     }
        !           987:     
        !           988:     //    for(UInt32 lenTest = 2; lenTest <= newLen; lenTest++)
        !           989:     if (newLen > numAvailableBytes)
        !           990:       newLen = numAvailableBytes;
        !           991:     if (newLen >= 2)
        !           992:     {
        !           993:       if (newLen == 2 && _matchDistances[2] >= 0x80)
        !           994:         continue;
        !           995:       UInt32 normalMatchPrice = matchPrice + 
        !           996:         _isRep[state.Index].GetPrice0();
        !           997:       while(lenEnd < cur + newLen)
        !           998:         _optimum[++lenEnd].Price = kIfinityPrice;
        !           999: 
        !          1000:       for(UInt32 lenTest = newLen; lenTest >= 2; lenTest--)
        !          1001:       {
        !          1002:         UInt32 curBack = _matchDistances[lenTest];
        !          1003:         UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState);
        !          1004:         COptimal &optimum = _optimum[cur + lenTest];
        !          1005:         if (curAndLenPrice < optimum.Price) 
        !          1006:         {
        !          1007:           optimum.Price = curAndLenPrice;
        !          1008:           optimum.PosPrev = cur;
        !          1009:           optimum.BackPrev = curBack + kNumRepDistances;
        !          1010:           optimum.Prev1IsChar = false;
        !          1011:         }
        !          1012: 
        !          1013:         if (_maxMode)
        !          1014:         {
        !          1015:           UInt32 backOffset = curBack + 1;
        !          1016:           UInt32 temp;
        !          1017:           for (temp = lenTest + 1; temp < numAvailableBytes; temp++)
        !          1018:             if (data[temp] != data[(size_t)temp - backOffset])
        !          1019:               break;
        !          1020:           UInt32 lenTest2 = temp - (lenTest + 1);
        !          1021:           if (lenTest2 >= 2)
        !          1022:           {
        !          1023:             CState state2 = state;
        !          1024:             state2.UpdateMatch();
        !          1025:             UInt32 posStateNext = (position + lenTest) & _posStateMask;
        !          1026:             UInt32 curAndLenCharPrice = curAndLenPrice + 
        !          1027:                 _isMatch[state2.Index][posStateNext].GetPrice0() +
        !          1028:                 _literalEncoder.GetPrice(position + lenTest, data[(size_t)lenTest - 1], 
        !          1029:                 true, data[(size_t)lenTest - backOffset], data[lenTest]);
        !          1030:             state2.UpdateChar();
        !          1031:             posStateNext = (position + lenTest + 1) & _posStateMask;
        !          1032:             UInt32 nextMatchPrice = curAndLenCharPrice + _isMatch[state2.Index][posStateNext].GetPrice1();
        !          1033:             UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2.Index].GetPrice1();
        !          1034:             
        !          1035:             // for(; lenTest2 >= 2; lenTest2--)
        !          1036:             {
        !          1037:               UInt32 offset = lenTest + 1 + lenTest2;
        !          1038:               while(lenEnd < cur + offset)
        !          1039:                 _optimum[++lenEnd].Price = kIfinityPrice;
        !          1040:               UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
        !          1041:                   0, lenTest2, state2, posStateNext);
        !          1042:               COptimal &optimum = _optimum[cur + offset];
        !          1043:               if (curAndLenPrice < optimum.Price) 
        !          1044:               {
        !          1045:                 optimum.Price = curAndLenPrice;
        !          1046:                 optimum.PosPrev = cur + lenTest + 1;
        !          1047:                 optimum.BackPrev = 0;
        !          1048:                 optimum.Prev1IsChar = true;
        !          1049:                 optimum.Prev2 = true;
        !          1050:                 optimum.PosPrev2 = cur;
        !          1051:                 optimum.BackPrev2 = curBack + kNumRepDistances;
        !          1052:               }
        !          1053:             }
        !          1054:           }
        !          1055:         }
        !          1056:       }
        !          1057:     }
        !          1058:   }
        !          1059: }
        !          1060: 
        !          1061: static inline bool ChangePair(UInt32 smallDist, UInt32 bigDist)
        !          1062: {
        !          1063:   const int kDif = 7;
        !          1064:   return (smallDist < (UInt32(1) << (32-kDif)) && bigDist >= (smallDist << kDif));
        !          1065: }
        !          1066: 
        !          1067: 
        !          1068: HRESULT CEncoder::ReadMatchDistances(UInt32 &lenRes)
        !          1069: {
        !          1070:   lenRes = _matchFinder->GetLongestMatch(_matchDistances);
        !          1071:   if (lenRes == _numFastBytes)
        !          1072:     lenRes += _matchFinder->GetMatchLen(lenRes, _matchDistances[lenRes], 
        !          1073:         kMatchMaxLen - lenRes);
        !          1074:   _additionalOffset++;
        !          1075:   return _matchFinder->MovePos();
        !          1076: }
        !          1077: 
        !          1078: HRESULT CEncoder::GetOptimumFast(UInt32 position, UInt32 &backRes, UInt32 &lenRes)
        !          1079: {
        !          1080:   UInt32 lenMain;
        !          1081:   if (!_longestMatchWasFound)
        !          1082:   {
        !          1083:     RINOK(ReadMatchDistances(lenMain));
        !          1084:   }
        !          1085:   else
        !          1086:   {
        !          1087:     lenMain = _longestMatchLength;
        !          1088:     _longestMatchWasFound = false;
        !          1089:   }
        !          1090:   UInt32 repLens[kNumRepDistances];
        !          1091:   UInt32 repMaxIndex = 0;
        !          1092:   for(UInt32 i = 0; i < kNumRepDistances; i++)
        !          1093:   {
        !          1094:     repLens[i] = _matchFinder->GetMatchLen(0 - 1, _repDistances[i], kMatchMaxLen);
        !          1095:     if (i == 0 || repLens[i] > repLens[repMaxIndex])
        !          1096:       repMaxIndex = i;
        !          1097:   }
        !          1098:   if(repLens[repMaxIndex] >= _numFastBytes)
        !          1099:   {
        !          1100:     backRes = repMaxIndex;
        !          1101:     lenRes = repLens[repMaxIndex];
        !          1102:     MovePos(lenRes - 1);
        !          1103:     return S_OK;
        !          1104:   }
        !          1105:   if(lenMain >= _numFastBytes)
        !          1106:   {
        !          1107:     backRes = _matchDistances[_numFastBytes] + kNumRepDistances; 
        !          1108:     MovePos(lenMain - 1);
        !          1109:     lenRes = lenMain;
        !          1110:     return S_OK;
        !          1111:   }
        !          1112:   while (lenMain > 2)
        !          1113:   {
        !          1114:     if (!ChangePair(_matchDistances[lenMain - 1], _matchDistances[lenMain]))
        !          1115:       break;
        !          1116:     lenMain--;
        !          1117:   }
        !          1118:   if (lenMain == 2 && _matchDistances[2] >= 0x80)
        !          1119:     lenMain = 1;
        !          1120: 
        !          1121:   UInt32 backMain = _matchDistances[lenMain];
        !          1122:   if (repLens[repMaxIndex] >= 2)
        !          1123:   {
        !          1124:     if (repLens[repMaxIndex] + 1 >= lenMain || 
        !          1125:         repLens[repMaxIndex] + 2 >= lenMain && (backMain > (1<<12)))
        !          1126:     {
        !          1127:       backRes = repMaxIndex;
        !          1128:       lenRes = repLens[repMaxIndex];
        !          1129:       MovePos(lenRes - 1);
        !          1130:       return S_OK;
        !          1131:     }
        !          1132:   }
        !          1133:   
        !          1134: 
        !          1135:   if (lenMain >= 2)
        !          1136:   {
        !          1137:     RINOK(ReadMatchDistances(_longestMatchLength));
        !          1138:     if (_longestMatchLength >= 2 &&
        !          1139:       (
        !          1140:         (_longestMatchLength >= lenMain && _matchDistances[lenMain] < backMain) || 
        !          1141:         _longestMatchLength == lenMain + 1 && 
        !          1142:           !ChangePair(backMain, _matchDistances[_longestMatchLength]) ||
        !          1143:         _longestMatchLength > lenMain + 1 ||
        !          1144:         _longestMatchLength + 1 >= lenMain && lenMain >= 3 &&
        !          1145:           ChangePair(_matchDistances[lenMain - 1], backMain)
        !          1146:       )
        !          1147:       )
        !          1148:     {
        !          1149:       _longestMatchWasFound = true;
        !          1150:       backRes = UInt32(-1);
        !          1151:       lenRes = 1;
        !          1152:       return S_OK;
        !          1153:     }
        !          1154:     for(UInt32 i = 0; i < kNumRepDistances; i++)
        !          1155:     {
        !          1156:       UInt32 repLen = _matchFinder->GetMatchLen(0 - 1, _repDistances[i], kMatchMaxLen);
        !          1157:       if (repLen >= 2 && repLen + 1 >= lenMain)
        !          1158:       {
        !          1159:         _longestMatchWasFound = true;
        !          1160:         backRes = UInt32(-1);
        !          1161:         lenRes = 1;
        !          1162:         return S_OK;
        !          1163:       }
        !          1164:     }
        !          1165:     backRes = backMain + kNumRepDistances; 
        !          1166:     MovePos(lenMain - 2);
        !          1167:     lenRes = lenMain;
        !          1168:     return S_OK;
        !          1169:   }
        !          1170:   backRes = UInt32(-1);
        !          1171:   lenRes = 1;
        !          1172:   return S_OK;
        !          1173: }
        !          1174: 
        !          1175: STDMETHODIMP CEncoder::InitMatchFinder(IMatchFinder *matchFinder)
        !          1176: {
        !          1177:   _matchFinder = matchFinder;
        !          1178:   return S_OK;
        !          1179: }
        !          1180: 
        !          1181: HRESULT CEncoder::Flush(UInt32 nowPos)
        !          1182: {
        !          1183:   ReleaseMFStream();
        !          1184:   WriteEndMarker(nowPos & _posStateMask);
        !          1185:   _rangeEncoder.FlushData();
        !          1186:   return _rangeEncoder.FlushStream();
        !          1187: }
        !          1188: 
        !          1189: void CEncoder::WriteEndMarker(UInt32 posState)
        !          1190: {
        !          1191:   // This function for writing End Mark for stream version of LZMA. 
        !          1192:   // In current version this feature is not used.
        !          1193:   if (!_writeEndMark)
        !          1194:     return;
        !          1195: 
        !          1196:   _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 1);
        !          1197:   _isRep[_state.Index].Encode(&_rangeEncoder, 0);
        !          1198:   _state.UpdateMatch();
        !          1199:   UInt32 len = kMatchMinLen; // kMatchMaxLen;
        !          1200:   _lenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState);
        !          1201:   UInt32 posSlot = (1 << kNumPosSlotBits)  - 1;
        !          1202:   UInt32 lenToPosState = GetLenToPosState(len);
        !          1203:   _posSlotEncoder[lenToPosState].Encode(&_rangeEncoder, posSlot);
        !          1204:   UInt32 footerBits = 30;
        !          1205:   UInt32 posReduced = (UInt32(1) << footerBits) - 1;
        !          1206:   _rangeEncoder.EncodeDirectBits(posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
        !          1207:   _posAlignEncoder.ReverseEncode(&_rangeEncoder, posReduced & kAlignMask);
        !          1208: }
        !          1209: 
        !          1210: HRESULT CEncoder::CodeReal(ISequentialInStream *inStream,
        !          1211:       ISequentialOutStream *outStream, 
        !          1212:       const UInt64 *inSize, const UInt64 *outSize,
        !          1213:       ICompressProgressInfo *progress)
        !          1214: {
        !          1215:   _needReleaseMFStream = false;
        !          1216:   CCoderReleaser coderReleaser(this);
        !          1217:   RINOK(SetStreams(inStream, outStream, inSize, outSize));
        !          1218:   while(true)
        !          1219:   {
        !          1220:     UInt64 processedInSize;
        !          1221:     UInt64 processedOutSize;
        !          1222:     Int32 finished;
        !          1223:     RINOK(CodeOneBlock(&processedInSize, &processedOutSize, &finished));
        !          1224:     if (finished != 0)
        !          1225:       return S_OK;
        !          1226:     if (progress != 0)
        !          1227:     {
        !          1228:       RINOK(progress->SetRatioInfo(&processedInSize, &processedOutSize));
        !          1229:     }
        !          1230:   }
        !          1231: }
        !          1232: 
        !          1233: HRESULT CEncoder::SetStreams(ISequentialInStream *inStream,
        !          1234:       ISequentialOutStream *outStream, 
        !          1235:       const UInt64 *inSize, const UInt64 *outSize)
        !          1236: {
        !          1237:   _inStream = inStream;
        !          1238:   _finished = false;
        !          1239:   RINOK(Create());
        !          1240:   RINOK(SetOutStream(outStream));
        !          1241:   RINOK(Init());
        !          1242:   
        !          1243:   // CCoderReleaser releaser(this);
        !          1244: 
        !          1245:   /*
        !          1246:   if (_matchFinder->GetNumAvailableBytes() == 0)
        !          1247:     return Flush();
        !          1248:   */
        !          1249: 
        !          1250:   if (!_fastMode)
        !          1251:   {
        !          1252:     FillPosSlotPrices();
        !          1253:     FillDistancesPrices();
        !          1254:     FillAlignPrices();
        !          1255:   }
        !          1256: 
        !          1257:   _lenEncoder.SetTableSize(_numFastBytes);
        !          1258:   _lenEncoder.UpdateTables(1 << _posStateBits);
        !          1259:   _repMatchLenEncoder.SetTableSize(_numFastBytes);
        !          1260:   _repMatchLenEncoder.UpdateTables(1 << _posStateBits);
        !          1261: 
        !          1262:   lastPosSlotFillingPos = 0;
        !          1263:   nowPos64 = 0;
        !          1264:   return S_OK;
        !          1265: }
        !          1266: 
        !          1267: HRESULT CEncoder::CodeOneBlock(UInt64 *inSize, UInt64 *outSize, Int32 *finished)
        !          1268: {
        !          1269:   if (_inStream != 0)
        !          1270:   {
        !          1271:     RINOK(_matchFinder->Init(_inStream));
        !          1272:     _needReleaseMFStream = true;
        !          1273:     _inStream = 0;
        !          1274:   }
        !          1275: 
        !          1276: 
        !          1277:   *finished = 1;
        !          1278:   if (_finished)
        !          1279:     return S_OK;
        !          1280:   _finished = true;
        !          1281: 
        !          1282: 
        !          1283:   UInt64 progressPosValuePrev = nowPos64;
        !          1284:   if (nowPos64 == 0)
        !          1285:   {
        !          1286:     if (_matchFinder->GetNumAvailableBytes() == 0)
        !          1287:       return Flush(UInt32(nowPos64));
        !          1288:     UInt32 len; // it's not used
        !          1289:     RINOK(ReadMatchDistances(len));
        !          1290:     UInt32 posState = UInt32(nowPos64) & _posStateMask;
        !          1291:     _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 0);
        !          1292:     _state.UpdateChar();
        !          1293:     Byte curByte = _matchFinder->GetIndexByte(0 - _additionalOffset);
        !          1294:     _literalEncoder.GetSubCoder(UInt32(nowPos64), _previousByte)->Encode(&_rangeEncoder, curByte);
        !          1295:     _previousByte = curByte;
        !          1296:     _additionalOffset--;
        !          1297:     nowPos64++;
        !          1298:   }
        !          1299:   if (_matchFinder->GetNumAvailableBytes() == 0)
        !          1300:     return Flush(UInt32(nowPos64));
        !          1301:   while(true)
        !          1302:   {
        !          1303:     #ifdef _NO_EXCEPTIONS
        !          1304:     if (_rangeEncoder.Stream.ErrorCode != S_OK)
        !          1305:       return _rangeEncoder.Stream.ErrorCode;
        !          1306:     #endif
        !          1307:     UInt32 pos;
        !          1308:     UInt32 posState = UInt32(nowPos64) & _posStateMask;
        !          1309: 
        !          1310:     UInt32 len;
        !          1311:     HRESULT result;
        !          1312:     if (_fastMode)
        !          1313:       result = GetOptimumFast(UInt32(nowPos64), pos, len);
        !          1314:     else
        !          1315:       result = GetOptimum(UInt32(nowPos64), pos, len);
        !          1316:     RINOK(result);
        !          1317: 
        !          1318:     if(len == 1 && pos == 0xFFFFFFFF)
        !          1319:     {
        !          1320:       _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 0);
        !          1321:       Byte curByte = _matchFinder->GetIndexByte(0 - _additionalOffset);
        !          1322:       CLiteralEncoder2 *subCoder = _literalEncoder.GetSubCoder(UInt32(nowPos64), _previousByte);
        !          1323:       if(!_state.IsCharState())
        !          1324:       {
        !          1325:         Byte matchByte = _matchFinder->GetIndexByte(0 - _repDistances[0] - 1 - _additionalOffset);
        !          1326:         subCoder->EncodeMatched(&_rangeEncoder, matchByte, curByte);
        !          1327:       }
        !          1328:       else
        !          1329:         subCoder->Encode(&_rangeEncoder, curByte);
        !          1330:       _state.UpdateChar();
        !          1331:       _previousByte = curByte;
        !          1332:     }
        !          1333:     else
        !          1334:     {
        !          1335:       _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 1);
        !          1336:       if(pos < kNumRepDistances)
        !          1337:       {
        !          1338:         _isRep[_state.Index].Encode(&_rangeEncoder, 1);
        !          1339:         if(pos == 0)
        !          1340:         {
        !          1341:           _isRepG0[_state.Index].Encode(&_rangeEncoder, 0);
        !          1342:           if(len == 1)
        !          1343:             _isRep0Long[_state.Index][posState].Encode(&_rangeEncoder, 0);
        !          1344:           else
        !          1345:             _isRep0Long[_state.Index][posState].Encode(&_rangeEncoder, 1);
        !          1346:         }
        !          1347:         else
        !          1348:         {
        !          1349:           _isRepG0[_state.Index].Encode(&_rangeEncoder, 1);
        !          1350:           if (pos == 1)
        !          1351:             _isRepG1[_state.Index].Encode(&_rangeEncoder, 0);
        !          1352:           else
        !          1353:           {
        !          1354:             _isRepG1[_state.Index].Encode(&_rangeEncoder, 1);
        !          1355:             _isRepG2[_state.Index].Encode(&_rangeEncoder, pos - 2);
        !          1356:           }
        !          1357:         }
        !          1358:         if (len == 1)
        !          1359:           _state.UpdateShortRep();
        !          1360:         else
        !          1361:         {
        !          1362:           _repMatchLenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState);
        !          1363:           _state.UpdateRep();
        !          1364:         }
        !          1365: 
        !          1366: 
        !          1367:         UInt32 distance = _repDistances[pos];
        !          1368:         if (pos != 0)
        !          1369:         {
        !          1370:           for(UInt32 i = pos; i >= 1; i--)
        !          1371:             _repDistances[i] = _repDistances[i - 1];
        !          1372:           _repDistances[0] = distance;
        !          1373:         }
        !          1374:       }
        !          1375:       else
        !          1376:       {
        !          1377:         _isRep[_state.Index].Encode(&_rangeEncoder, 0);
        !          1378:         _state.UpdateMatch();
        !          1379:         _lenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState);
        !          1380:         pos -= kNumRepDistances;
        !          1381:         UInt32 posSlot = GetPosSlot(pos);
        !          1382:         UInt32 lenToPosState = GetLenToPosState(len);
        !          1383:         _posSlotEncoder[lenToPosState].Encode(&_rangeEncoder, posSlot);
        !          1384:         
        !          1385:         if (posSlot >= kStartPosModelIndex)
        !          1386:         {
        !          1387:           UInt32 footerBits = ((posSlot >> 1) - 1);
        !          1388:           UInt32 base = ((2 | (posSlot & 1)) << footerBits);
        !          1389:           UInt32 posReduced = pos - base;
        !          1390: 
        !          1391:           if (posSlot < kEndPosModelIndex)
        !          1392:             NRangeCoder::ReverseBitTreeEncode(_posEncoders + base - posSlot - 1, 
        !          1393:                 &_rangeEncoder, footerBits, posReduced);
        !          1394:           else
        !          1395:           {
        !          1396:             _rangeEncoder.EncodeDirectBits(posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
        !          1397:             _posAlignEncoder.ReverseEncode(&_rangeEncoder, posReduced & kAlignMask);
        !          1398:             if (!_fastMode)
        !          1399:               if (--_alignPriceCount == 0)
        !          1400:                 FillAlignPrices();
        !          1401:           }
        !          1402:         }
        !          1403:         UInt32 distance = pos;
        !          1404:         for(UInt32 i = kNumRepDistances - 1; i >= 1; i--)
        !          1405:           _repDistances[i] = _repDistances[i - 1];
        !          1406:         _repDistances[0] = distance;
        !          1407:       }
        !          1408:       _previousByte = _matchFinder->GetIndexByte(len - 1 - _additionalOffset);
        !          1409:     }
        !          1410:     _additionalOffset -= len;
        !          1411:     nowPos64 += len;
        !          1412:     if (!_fastMode)
        !          1413:       if (nowPos64 - lastPosSlotFillingPos >= (1 << 9))
        !          1414:       {
        !          1415:         FillPosSlotPrices();
        !          1416:         FillDistancesPrices();
        !          1417:         lastPosSlotFillingPos = nowPos64;
        !          1418:       }
        !          1419:     if (_additionalOffset == 0)
        !          1420:     {
        !          1421:       *inSize = nowPos64;
        !          1422:       *outSize = _rangeEncoder.GetProcessedSize();
        !          1423:       if (_matchFinder->GetNumAvailableBytes() == 0)
        !          1424:         return Flush(UInt32(nowPos64));
        !          1425:       if (nowPos64 - progressPosValuePrev >= (1 << 12))
        !          1426:       {
        !          1427:         _finished = false;
        !          1428:         *finished = 0;
        !          1429:         return S_OK;
        !          1430:       }
        !          1431:     }
        !          1432:   }
        !          1433: }
        !          1434: 
        !          1435: STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream,
        !          1436:     ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
        !          1437:     ICompressProgressInfo *progress)
        !          1438: {
        !          1439:   #ifndef _NO_EXCEPTIONS
        !          1440:   try 
        !          1441:   { 
        !          1442:   #endif
        !          1443:     return CodeReal(inStream, outStream, inSize, outSize, progress); 
        !          1444:   #ifndef _NO_EXCEPTIONS
        !          1445:   }
        !          1446:   catch(const COutBufferException &e) { return e.ErrorCode; }
        !          1447:   catch(...) { return E_FAIL; }
        !          1448:   #endif
        !          1449: }
        !          1450:   
        !          1451: void CEncoder::FillPosSlotPrices()
        !          1452: {
        !          1453:   for (UInt32 lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
        !          1454:   {
        !          1455:          UInt32 posSlot;
        !          1456:     for (posSlot = 0; posSlot < kEndPosModelIndex && posSlot < _distTableSize; posSlot++)
        !          1457:       _posSlotPrices[lenToPosState][posSlot] = _posSlotEncoder[lenToPosState].GetPrice(posSlot);
        !          1458:     for (; posSlot < _distTableSize; posSlot++)
        !          1459:       _posSlotPrices[lenToPosState][posSlot] = _posSlotEncoder[lenToPosState].GetPrice(posSlot) + 
        !          1460:       ((((posSlot >> 1) - 1) - kNumAlignBits) << NRangeCoder::kNumBitPriceShiftBits);
        !          1461:   }
        !          1462: }
        !          1463: 
        !          1464: void CEncoder::FillDistancesPrices()
        !          1465: {
        !          1466:   for (UInt32 lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
        !          1467:   {
        !          1468:          UInt32 i;
        !          1469:     for (i = 0; i < kStartPosModelIndex; i++)
        !          1470:       _distancesPrices[lenToPosState][i] = _posSlotPrices[lenToPosState][i];
        !          1471:     for (; i < kNumFullDistances; i++)
        !          1472:     { 
        !          1473:       UInt32 posSlot = GetPosSlot(i);
        !          1474:       UInt32 footerBits = ((posSlot >> 1) - 1);
        !          1475:       UInt32 base = ((2 | (posSlot & 1)) << footerBits);
        !          1476: 
        !          1477:       _distancesPrices[lenToPosState][i] = _posSlotPrices[lenToPosState][posSlot] +
        !          1478:           NRangeCoder::ReverseBitTreeGetPrice(_posEncoders + 
        !          1479:               base - posSlot - 1, footerBits, i - base);
        !          1480:             
        !          1481:     }
        !          1482:   }
        !          1483: }
        !          1484: 
        !          1485: void CEncoder::FillAlignPrices()
        !          1486: {
        !          1487:   for (UInt32 i = 0; i < kAlignTableSize; i++)
        !          1488:     _alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i);
        !          1489:   _alignPriceCount = kAlignTableSize;
        !          1490: }
        !          1491: 
        !          1492: }}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>