Annotation of elwix/tools/oldlzma/SRC/7zip/Compress/LZMA/LZMAEncoder.cpp, revision 1.1.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>