Logo Search packages:      
Sourcecode: p7zip version File versions  Download package

DeflateEncoder.cpp

// DeflateEncoder.cpp

#include "StdAfx.h"

#include "DeflateEncoder.h"
#include "DeflateConst.h"

#include "Windows/Defs.h"
#include "Common/ComTry.h"
#include "../../../Common/Alloc.h"
#include "../LZ/BinTree/BinTree3Z.h"

namespace NCompress {
namespace NDeflate {
namespace NEncoder {

class CMatchFinderException
{
public:
  HRESULT m_Result;
  CMatchFinderException(HRESULT result): m_Result (result) {}
};

static const int kValueBlockSize = 0x2000;

static const int kMaxCodeBitLength = 15;
static const int kMaxLevelBitLength = 7;

static const Byte kFlagImm     = 0;
static const Byte kFlagLenPos  = 4;

static const UInt32 kMaxUncompressedBlockSize = 0xFFFF; // test it !!!

static const UInt32 kBlockUncompressedSizeThreshold = 
    kMaxUncompressedBlockSize - kMatchMaxLen32 - kNumOpts;

static const int kNumGoodBacks = 0x10000; 

static Byte kNoLiteralDummy = 13;
static Byte kNoLenDummy = 13;
static Byte kNoPosDummy = 6;

static Byte g_LenSlots[kNumLenCombinations32];
static Byte g_FastPos[1 << 9];

class CFastPosInit
{
public:
  CFastPosInit()
  {
    int i;
    for(i = 0; i < kLenTableSize; i++)
    {
      int c = kLenStart32[i];
      int j = 1 << kLenDirectBits32[i];
      for(int k = 0; k < j; k++, c++)
        g_LenSlots[c] = (Byte)i;
    }
    
    const int kFastSlots = 18;
    int c = 0;
    for (Byte slotFast = 0; slotFast < kFastSlots; slotFast++)
    {
      UInt32 k = (1 << kDistDirectBits[slotFast]);
      for (UInt32 j = 0; j < k; j++, c++)
        g_FastPos[c] = slotFast;
    }
  }
};

static CFastPosInit g_FastPosInit;


inline UInt32 GetPosSlot(UInt32 pos)
{
  //  for (UInt32 i = 1; pos >= kDistStart[i]; i++);
  //    return i - 1;
  if (pos < 0x200)
    return g_FastPos[pos];
  return g_FastPos[pos >> 8] + 16;
}

CCoder::CCoder(bool deflate64Mode):
  _deflate64Mode(deflate64Mode),
  m_NumPasses(1),
  m_NumFastBytes(32),
  m_OnePosMatchesMemory(0),
  m_OnePosMatchesArray(0),
  m_MatchDistances(0),
  m_Created(false),
  m_Values(0)
{
  m_MatchMaxLen = deflate64Mode ? kMatchMaxLen64 : kMatchMaxLen32;
  m_NumLenCombinations = deflate64Mode ? kNumLenCombinations64 : 
    kNumLenCombinations32;
  m_LenStart = deflate64Mode ? kLenStart64 : kLenStart32;
  m_LenDirectBits = deflate64Mode ? kLenDirectBits64 : kLenDirectBits32;
}

HRESULT CCoder::Create()
{
  COM_TRY_BEGIN
  if (!m_MatchFinder)
  {
    m_MatchFinder = new NBT3Z::CMatchFinderBinTree;
    if (m_MatchFinder == 0)
      return E_OUTOFMEMORY;
  }
  if (m_Values == 0)
  {
    m_Values = (CCodeValue *)MyAlloc((kValueBlockSize + kNumOpts) * sizeof(CCodeValue));
    if (m_Values == 0)
      return E_OUTOFMEMORY;
  }
  RINOK(m_MatchFinder->Create(_deflate64Mode ? kHistorySize64 : kHistorySize32, 
      kNumOpts + kNumGoodBacks, m_NumFastBytes, m_MatchMaxLen - m_NumFastBytes));
  if (!m_OutStream.Create(1 << 20))
    return E_OUTOFMEMORY;

  Free();
  if (m_NumPasses > 1)
  {
    m_OnePosMatchesMemory = (UInt16 *)::MidAlloc(kNumGoodBacks * (m_NumFastBytes + 1) * sizeof(UInt16));
    if (m_OnePosMatchesMemory == 0)
      return E_OUTOFMEMORY;
    m_OnePosMatchesArray = (COnePosMatches *)MyAlloc(kNumGoodBacks * sizeof(COnePosMatches));
    if (m_OnePosMatchesArray == 0)
      return E_OUTOFMEMORY;
    UInt16 *goodBacksWordsCurrent = m_OnePosMatchesMemory;
    for(int i = 0; i < kNumGoodBacks; i++, goodBacksWordsCurrent += (m_NumFastBytes + 1))
      m_OnePosMatchesArray[i].Init(goodBacksWordsCurrent);
  }
  else
  {
    m_MatchDistances = (UInt16 *)MyAlloc((m_NumFastBytes + 1) * sizeof(UInt16));
    if (m_MatchDistances == 0)
      return E_OUTOFMEMORY;
  }
  return S_OK;
  COM_TRY_END
}

// ICompressSetEncoderProperties2
HRESULT CCoder::BaseSetEncoderProperties2(const PROPID *propIDs, 
    const PROPVARIANT *properties, UInt32 numProperties)
{
  for(UInt32 i = 0; i < numProperties; i++)
  {
    const PROPVARIANT &property = properties[i]; 
    switch(propIDs[i])
    {
      case NCoderPropID::kNumPasses:
        if (property.vt != VT_UI4)
          return E_INVALIDARG;
        m_NumPasses = property.ulVal;
        if(m_NumPasses == 0 || m_NumPasses > 255)
          return E_INVALIDARG;
        break;
      case NCoderPropID::kNumFastBytes:
        if (property.vt != VT_UI4)
          return E_INVALIDARG;
        m_NumFastBytes = property.ulVal;
        if(m_NumFastBytes < 3 || m_NumFastBytes > m_MatchMaxLen)
          return E_INVALIDARG;
        break;
      default:
        return E_INVALIDARG;
    }
  }
  return S_OK;
}
  
void CCoder::Free()
{
  if(m_NumPasses > 0)
  {
    if (m_NumPasses > 1)
    {
      ::MidFree(m_OnePosMatchesMemory);
      MyFree(m_OnePosMatchesArray);
    }
    else
      MyFree(m_MatchDistances);
  }
}

CCoder::~CCoder()
{
  Free();
  MyFree(m_Values);
}

void CCoder::ReadGoodBacks()
{
  UInt32 goodIndex;
  if (m_NumPasses > 1)
  {
    goodIndex = m_FinderPos % kNumGoodBacks;
    m_MatchDistances = m_OnePosMatchesArray[goodIndex].MatchDistances;
  }
  UInt32 distanceTmp[kMatchMaxLen32 + 1];
  UInt32 len = m_MatchFinder->GetLongestMatch(distanceTmp);
  for(UInt32 i = kMatchMinLen; i <= len; i++)
    m_MatchDistances[i] = (UInt16)distanceTmp[i];

  m_LongestMatchDistance = m_MatchDistances[len];
  if (len == m_NumFastBytes && m_NumFastBytes != m_MatchMaxLen)
    m_LongestMatchLength = len + m_MatchFinder->GetMatchLen(len, 
        m_LongestMatchDistance, m_MatchMaxLen - len);
  else
    m_LongestMatchLength = len;
  if (m_NumPasses > 1)
  {
    m_OnePosMatchesArray[goodIndex].LongestMatchDistance = UInt16(m_LongestMatchDistance);
    m_OnePosMatchesArray[goodIndex].LongestMatchLength = UInt16(m_LongestMatchLength);
  }
  HRESULT result = m_MatchFinder->MovePos();
  if (result != S_OK)
    throw CMatchFinderException(result);
  m_FinderPos++;
  m_AdditionalOffset++;
}

void CCoder::GetBacks(UInt32 pos)
{
  if(pos == m_FinderPos)
    ReadGoodBacks();
  else
  {
    if (m_NumPasses == 1)
    {
      if(pos + 1 == m_FinderPos) 
        return;
      throw 1932;   
    }
    else
    {
      UInt32 goodIndex = pos % kNumGoodBacks;
      m_MatchDistances = m_OnePosMatchesArray[goodIndex].MatchDistances;
      m_LongestMatchDistance = m_OnePosMatchesArray[goodIndex].LongestMatchDistance;
      m_LongestMatchLength = m_OnePosMatchesArray[goodIndex].LongestMatchLength;
    }
  }
}


void CCoder::MovePos(UInt32 num)
{
  if (m_NumPasses > 1)
  {
    for(UInt32 i = 0; i < num; i++)
      GetBacks(UInt32(m_BlockStartPostion + m_CurrentBlockUncompressedSize + i + 1));
  }
  else
  {
    for (;num > 0; num--)
    {
      m_MatchFinder->DummyLongestMatch();
      HRESULT result = m_MatchFinder->MovePos();
      if (result != S_OK)
        throw CMatchFinderException(result);
      m_FinderPos++;
      m_AdditionalOffset++;
    }
  }
}

static const UInt32 kIfinityPrice = 0xFFFFFFF;

UInt32 CCoder::Backward(UInt32 &backRes, UInt32 cur)
{
  m_OptimumEndIndex = cur;
  UInt32 posMem = m_Optimum[cur].PosPrev;
  UInt16 backMem = m_Optimum[cur].BackPrev;
  do
  {
    UInt32 posPrev = posMem;
    UInt16 backCur = backMem;
    backMem = m_Optimum[posPrev].BackPrev;
    posMem = m_Optimum[posPrev].PosPrev;
    m_Optimum[posPrev].BackPrev = backCur;
    m_Optimum[posPrev].PosPrev = (UInt16)cur;
    cur = posPrev;
  }
  while(cur > 0);
  backRes = m_Optimum[0].BackPrev;
  m_OptimumCurrentIndex  = m_Optimum[0].PosPrev;
  return m_OptimumCurrentIndex; 
}

UInt32 CCoder::GetOptimal(UInt32 &backRes)
{
  if(m_OptimumEndIndex != m_OptimumCurrentIndex)
  {
    UInt32 len = m_Optimum[m_OptimumCurrentIndex].PosPrev - m_OptimumCurrentIndex;
    backRes = m_Optimum[m_OptimumCurrentIndex].BackPrev;
    m_OptimumCurrentIndex = m_Optimum[m_OptimumCurrentIndex].PosPrev;
    return len;
  }
  m_OptimumCurrentIndex = 0;
  m_OptimumEndIndex = 0;
  
  GetBacks(UInt32(m_BlockStartPostion + m_CurrentBlockUncompressedSize));

  UInt32 lenMain = m_LongestMatchLength;
  UInt32 backMain = m_LongestMatchDistance;

  if(lenMain < kMatchMinLen)
    return 1;
  if(lenMain > m_NumFastBytes)
  {
    backRes = backMain; 
    MovePos(lenMain - 1);
    return lenMain;
  }
  m_Optimum[1].Price = m_LiteralPrices[m_MatchFinder->GetIndexByte(0 - m_AdditionalOffset)];
  m_Optimum[1].PosPrev = 0;

  m_Optimum[2].Price = kIfinityPrice;
  m_Optimum[2].PosPrev = 1;

  for(UInt32 i = kMatchMinLen; i <= lenMain; i++)
  {
    m_Optimum[i].PosPrev = 0;
    m_Optimum[i].BackPrev = m_MatchDistances[i];
    m_Optimum[i].Price = m_LenPrices[i - kMatchMinLen] + m_PosPrices[GetPosSlot(m_MatchDistances[i])];
  }


  UInt32 cur = 0;
  UInt32 lenEnd = lenMain;
  while(true)
  {
    cur++;
    if(cur == lenEnd)  
      return Backward(backRes, cur);
    GetBacks(UInt32(m_BlockStartPostion + m_CurrentBlockUncompressedSize + cur));
    UInt32 newLen = m_LongestMatchLength;
    if(newLen > m_NumFastBytes)
      return Backward(backRes, cur);
    
    UInt32 curPrice = m_Optimum[cur].Price; 
    UInt32 curAnd1Price = curPrice +
        m_LiteralPrices[m_MatchFinder->GetIndexByte(cur - m_AdditionalOffset)];
    COptimal &optimum = m_Optimum[cur + 1];
    if (curAnd1Price < optimum.Price) 
    {
      optimum.Price = curAnd1Price;
      optimum.PosPrev = (UInt16)cur;
    }
    if (newLen < kMatchMinLen)
      continue;
    if(cur + newLen > lenEnd)
    {
      if (cur + newLen > kNumOpts - 1)
        newLen = kNumOpts - 1 - cur;
      UInt32 lenEndNew = cur + newLen;
      if (lenEnd < lenEndNew)
      {
        for(UInt32 i = lenEnd + 1; i <= lenEndNew; i++)
          m_Optimum[i].Price = kIfinityPrice;
        lenEnd = lenEndNew;
      }
    }       
    for(UInt32 lenTest = kMatchMinLen; lenTest <= newLen; lenTest++)
    {
      UInt16 curBack = m_MatchDistances[lenTest];
      UInt32 curAndLenPrice = curPrice + 
          m_LenPrices[lenTest - kMatchMinLen] + m_PosPrices[GetPosSlot(curBack)];
      COptimal &optimum = m_Optimum[cur + lenTest];
      if (curAndLenPrice < optimum.Price) 
      {
        optimum.Price = curAndLenPrice;
        optimum.PosPrev = (UInt16)cur;
        optimum.BackPrev = curBack;
      }
    }
  }
}


void CCoder::InitStructures()
{
  memset(m_LastLevels, 0, kMaxTableSize64);

  m_ValueIndex = 0;
  m_OptimumEndIndex = 0;
  m_OptimumCurrentIndex = 0;
  m_AdditionalOffset = 0;

  m_BlockStartPostion = 0;
  m_CurrentBlockUncompressedSize = 0;

  m_MainCoder.StartNewBlock();
  m_DistCoder.StartNewBlock();
 
  UInt32 i;
  for(i = 0; i < 256; i++)
    m_LiteralPrices[i] = 8;
  for(i = 0; i < m_NumLenCombinations; i++)
    m_LenPrices[i] = (Byte)(5 + m_LenDirectBits[g_LenSlots[i]]); // test it
  for(i = 0; i < kDistTableSize64; i++)
    m_PosPrices[i] = (Byte)(5 + kDistDirectBits[i]);
}

void CCoder::WriteBlockData(bool writeMode, bool finalBlock)
{
  m_MainCoder.AddSymbol(kReadTableNumber);
  int method = WriteTables(writeMode, finalBlock);
  
  if (writeMode)
  {
    if(method == NBlockType::kStored)
    {
      for(UInt32 i = 0; i < m_CurrentBlockUncompressedSize; i++)
      {
        Byte b = m_MatchFinder->GetIndexByte(i - m_AdditionalOffset - 
              m_CurrentBlockUncompressedSize);
        m_OutStream.WriteBits(b, 8);
      }
    }
    else
    {
      for (UInt32 i = 0; i < m_ValueIndex; i++)
      {
        if (m_Values[i].Flag == kFlagImm)
          m_MainCoder.CodeOneValue(&m_ReverseOutStream, m_Values[i].Imm);
        else if (m_Values[i].Flag == kFlagLenPos)
        {
          UInt32 len = m_Values[i].Len;
          UInt32 lenSlot = g_LenSlots[len];
          m_MainCoder.CodeOneValue(&m_ReverseOutStream, kMatchNumber + lenSlot);
          m_OutStream.WriteBits(len - m_LenStart[lenSlot], m_LenDirectBits[lenSlot]);
          UInt32 dist = m_Values[i].Pos;
          UInt32 posSlot = GetPosSlot(dist);
          m_DistCoder.CodeOneValue(&m_ReverseOutStream, posSlot);
          m_OutStream.WriteBits(dist - kDistStart[posSlot], kDistDirectBits[posSlot]);
        }
      }
      m_MainCoder.CodeOneValue(&m_ReverseOutStream, kReadTableNumber);
    }
  }
  m_MainCoder.StartNewBlock();
  m_DistCoder.StartNewBlock();
  m_ValueIndex = 0;
  UInt32 i;
  for(i = 0; i < 256; i++)
    if(m_LastLevels[i] != 0)
      m_LiteralPrices[i] = m_LastLevels[i];
    else
      m_LiteralPrices[i] = kNoLiteralDummy;

  // -------------- Normal match -----------------------------
  
  for(i = 0; i < m_NumLenCombinations; i++)
  {
    UInt32 slot = g_LenSlots[i];
    Byte dummy = m_LastLevels[kMatchNumber + slot];
    if (dummy != 0)
      m_LenPrices[i] = dummy;
    else
      m_LenPrices[i] = kNoLenDummy;
    m_LenPrices[i] += m_LenDirectBits[slot];
  }
  for(i = 0; i < kDistTableSize64; i++)
  {
    Byte dummy = m_LastLevels[kDistTableStart + i];
    if (dummy != 0) // NEED FIXED (1) to avoid Conditional jump or move depends on uninitialised value(s)
      m_PosPrices[i] = dummy;
    else
      m_PosPrices[i] = kNoPosDummy;
    m_PosPrices[i] += kDistDirectBits[i];
  }
}

void CCoder::CodeLevelTable(Byte *newLevels, int numLevels, bool codeMode)
{
  int prevLen = 0xFF;        // last emitted length
  int nextLen = newLevels[0]; // length of next code
  int count = 0;             // repeat count of the current code
  int maxCount = 7;          // max repeat count
  int minCount = 4;          // min repeat count
  if (nextLen == 0) 
  {
    maxCount = 138;
    minCount = 3;
  }
  Byte oldValueInGuardElement = newLevels[numLevels]; // push guard value
  try
  {
    newLevels[numLevels] = 0xFF; // guard already set
    for (int n = 0; n < numLevels; n++) 
    {
      int curLen = nextLen; 
      nextLen = newLevels[n + 1];
      count++;
      if (count < maxCount && curLen == nextLen) 
        continue;
      else if (count < minCount) 
        for(int i = 0; i < count; i++) 
        {
          int codeLen = curLen;
          if (codeMode)
            m_LevelCoder.CodeOneValue(&m_ReverseOutStream, codeLen);
          else
            m_LevelCoder.AddSymbol(codeLen);
        }
        else if (curLen != 0) 
        {
          if (curLen != prevLen) 
          {
            int codeLen = curLen;
            if (codeMode)
              m_LevelCoder.CodeOneValue(&m_ReverseOutStream, codeLen);
            else
              m_LevelCoder.AddSymbol(codeLen);
            count--;
          }
          if (codeMode)
          {
            m_LevelCoder.CodeOneValue(&m_ReverseOutStream, kTableLevelRepNumber);
            m_OutStream.WriteBits(count - 3, 2);
          }
          else
            m_LevelCoder.AddSymbol(kTableLevelRepNumber);
        } 
        else if (count <= 10) 
        {
          if (codeMode)
          {
            m_LevelCoder.CodeOneValue(&m_ReverseOutStream, kTableLevel0Number);
            m_OutStream.WriteBits(count - 3, 3);
          }
          else
            m_LevelCoder.AddSymbol(kTableLevel0Number);
        }
        else 
        {
          if (codeMode)
          {
            m_LevelCoder.CodeOneValue(&m_ReverseOutStream, kTableLevel0Number2);
            m_OutStream.WriteBits(count - 11, 7);
          }
          else
            m_LevelCoder.AddSymbol(kTableLevel0Number2);
        }
        count = 0; 
        prevLen = curLen;
        if (nextLen == 0) 
        {
          maxCount = 138;
          minCount = 3;
        } 
        else if (curLen == nextLen) 
        {
          maxCount = 6;
          minCount = 3;
        } 
        else 
        {
          maxCount = 7;
          minCount = 4;
        }
    }
  }
  catch(...)
  {
    newLevels[numLevels] = oldValueInGuardElement; // old guard 
    throw;
  }
  newLevels[numLevels] = oldValueInGuardElement; // old guard 
}

int CCoder::WriteTables(bool writeMode, bool finalBlock)
{
  Byte newLevels[kMaxTableSize64 + 1]; // (+ 1) for guard 

  memset(newLevels, 0, kMaxTableSize64); // FIXED (1)

  m_MainCoder.BuildTree(&newLevels[0]);
  m_DistCoder.BuildTree(&newLevels[kDistTableStart]);

  
  memset(m_LastLevels, 0, kMaxTableSize64);

  if (writeMode)
  {
    if(finalBlock)
      m_OutStream.WriteBits(NFinalBlockField::kFinalBlock, kFinalBlockFieldSize);
    else
      m_OutStream.WriteBits(NFinalBlockField::kNotFinalBlock, kFinalBlockFieldSize);
    
    m_LevelCoder.StartNewBlock();
    
    int numLitLenLevels = kMainTableSize;
    while(numLitLenLevels > kDeflateNumberOfLitLenCodesMin && newLevels[numLitLenLevels - 1] == 0)
      numLitLenLevels--;
    
    int numDistLevels = _deflate64Mode ? kDistTableSize64 : kDistTableSize32;
    while(numDistLevels > kDeflateNumberOfDistanceCodesMin && 
      newLevels[kDistTableStart + numDistLevels - 1] == 0)
      numDistLevels--;
    
    
    /////////////////////////
    // First Pass

    CodeLevelTable(newLevels, numLitLenLevels, false);
    CodeLevelTable(&newLevels[kDistTableStart], numDistLevels, false);

    memcpy(m_LastLevels, newLevels, kMaxTableSize64);
    

    Byte levelLevels[kLevelTableSize];
    m_LevelCoder.BuildTree(levelLevels);
    
    Byte levelLevelsStream[kLevelTableSize];
    int numLevelCodes = kDeflateNumberOfLevelCodesMin;
    int i;
    for (i = 0; i < kLevelTableSize; i++)
    {
      int streamPos = kCodeLengthAlphabetOrder[i];
      Byte level = levelLevels[streamPos]; 
      if (level > 0 && i >= numLevelCodes)
        numLevelCodes = i + 1;
      levelLevelsStream[i] = level;
    }
    
    UInt32 numLZHuffmanBits = m_MainCoder.GetBlockBitLength();
    numLZHuffmanBits += m_DistCoder.GetBlockBitLength();
    numLZHuffmanBits += m_LevelCoder.GetBlockBitLength();
    numLZHuffmanBits += kDeflateNumberOfLengthCodesFieldSize +
      kDeflateNumberOfDistanceCodesFieldSize +
      kDeflateNumberOfLevelCodesFieldSize;
    numLZHuffmanBits += numLevelCodes * kDeflateLevelCodeFieldSize;

    UInt32 nextBitPosition = 
        (m_OutStream.GetBitPosition() + kBlockTypeFieldSize) % 8;
    UInt32 numBitsForAlign = nextBitPosition > 0 ? (8 - nextBitPosition): 0;

    UInt32 numStoreBits = numBitsForAlign + (2 * 2) * 8;
    numStoreBits += m_CurrentBlockUncompressedSize * 8;
    if(numStoreBits < numLZHuffmanBits)
    {
      m_OutStream.WriteBits(NBlockType::kStored, kBlockTypeFieldSize); // test it
      m_OutStream.WriteBits(0, numBitsForAlign); // test it
      UInt16 currentBlockUncompressedSize = UInt16(m_CurrentBlockUncompressedSize);
      UInt16 currentBlockUncompressedSizeNot = ~currentBlockUncompressedSize;
      m_OutStream.WriteBits(currentBlockUncompressedSize, kDeflateStoredBlockLengthFieldSizeSize);
      m_OutStream.WriteBits(currentBlockUncompressedSizeNot, kDeflateStoredBlockLengthFieldSizeSize);
      return NBlockType::kStored;
    }
    else
    {
      m_OutStream.WriteBits(NBlockType::kDynamicHuffman, kBlockTypeFieldSize);
      m_OutStream.WriteBits(numLitLenLevels - kDeflateNumberOfLitLenCodesMin, kDeflateNumberOfLengthCodesFieldSize);
      m_OutStream.WriteBits(numDistLevels - kDeflateNumberOfDistanceCodesMin, 
        kDeflateNumberOfDistanceCodesFieldSize);
      m_OutStream.WriteBits(numLevelCodes - kDeflateNumberOfLevelCodesMin, 
        kDeflateNumberOfLevelCodesFieldSize);
      
      for (i = 0; i < numLevelCodes; i++)
        m_OutStream.WriteBits(levelLevelsStream[i], kDeflateLevelCodeFieldSize);
      
      /////////////////////////
      // Second Pass

      CodeLevelTable(newLevels, numLitLenLevels, true);
      CodeLevelTable(&newLevels[kDistTableStart], numDistLevels, true);
      return NBlockType::kDynamicHuffman;
    }
  }
  else
    memcpy(m_LastLevels, newLevels, kMaxTableSize64);
  return -1;
}

HRESULT CCoder::CodeReal(ISequentialInStream *inStream,
    ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
    ICompressProgressInfo *progress)
{
  if (!m_Created)
  {
    RINOK(Create());

    if (!m_MainCoder.Create(kMainTableSize, _deflate64Mode ? kLenDirectBits64 : kLenDirectBits32, 
        kMatchNumber, kMaxCodeBitLength))
      return E_OUTOFMEMORY;
    if (!m_DistCoder.Create(_deflate64Mode ? kDistTableSize64 : kDistTableSize32, 
        kDistDirectBits, 0, kMaxCodeBitLength))
      return E_OUTOFMEMORY;
    if (!m_LevelCoder.Create(kLevelTableSize, kLevelDirectBits, 0, kMaxLevelBitLength))
      return E_OUTOFMEMORY;
    m_Created = true;
  }

  UInt64 nowPos = 0;
  m_FinderPos = 0;

  RINOK(m_MatchFinder->Init(inStream));
  m_OutStream.SetStream(outStream);
  m_OutStream.Init();
  m_ReverseOutStream.Init(&m_OutStream);

  CCoderReleaser coderReleaser(this);
  InitStructures();

  while(true)
  {
    int currentPassIndex = 0;
    bool noMoreBytes;
    while (true)
    {
      while(true)
      {
        noMoreBytes = (m_AdditionalOffset == 0 && m_MatchFinder->GetNumAvailableBytes() == 0);
  
        if (((m_CurrentBlockUncompressedSize >= kBlockUncompressedSizeThreshold || 
                 m_ValueIndex >= kValueBlockSize) && 
              (m_OptimumEndIndex == m_OptimumCurrentIndex)) 
            || noMoreBytes)
          break;
        UInt32 pos;
        UInt32 len = GetOptimal(pos);
        if (len >= kMatchMinLen)
        {
          UInt32 newLen = len - kMatchMinLen;
          m_Values[m_ValueIndex].Flag = kFlagLenPos;
          m_Values[m_ValueIndex].Len = Byte(newLen);
          UInt32 lenSlot = g_LenSlots[newLen];
          m_MainCoder.AddSymbol(kMatchNumber + lenSlot);
          m_Values[m_ValueIndex].Pos = UInt16(pos);
          UInt32 posSlot = GetPosSlot(pos);
          m_DistCoder.AddSymbol(posSlot);
        }
        else if (len == 1)  
        {
          Byte b = m_MatchFinder->GetIndexByte(0 - m_AdditionalOffset);
          len = 1;
          m_MainCoder.AddSymbol(b);
          m_Values[m_ValueIndex].Flag = kFlagImm;
          m_Values[m_ValueIndex].Imm = b;
        }
        else
          throw 12112342;
        m_ValueIndex++;
        m_AdditionalOffset -= len;
        nowPos += len;
        m_CurrentBlockUncompressedSize += len;
        
      }
      currentPassIndex++;
      bool writeMode = (currentPassIndex == m_NumPasses);
      WriteBlockData(writeMode, noMoreBytes);
      if (writeMode)
        break;
      nowPos = m_BlockStartPostion;
      m_AdditionalOffset = UInt32(m_FinderPos - m_BlockStartPostion);
      m_CurrentBlockUncompressedSize = 0;
    }
    m_BlockStartPostion += m_CurrentBlockUncompressedSize;
    m_CurrentBlockUncompressedSize = 0;
    if (progress != NULL)
    {
      UInt64 packSize = m_OutStream.GetProcessedSize();
      RINOK(progress->SetRatioInfo(&nowPos, &packSize));
    }
    if (noMoreBytes)
      break;
  }
  return  m_OutStream.Flush();
}

HRESULT CCoder::BaseCode(ISequentialInStream *inStream,
    ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
    ICompressProgressInfo *progress)
{
  try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
  catch(CMatchFinderException &e) {  return e.m_Result;   }
  catch(const COutBufferException &e) { return e.ErrorCode; }
  catch(...) { return E_FAIL; }
}

STDMETHODIMP CCOMCoder::Code(ISequentialInStream *inStream,
    ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
    ICompressProgressInfo *progress)
  { return BaseCode(inStream, outStream, inSize, outSize, progress); }

STDMETHODIMP CCOMCoder::SetCoderProperties(const PROPID *propIDs, 
    const PROPVARIANT *properties, UInt32 numProperties)
  { return BaseSetEncoderProperties2(propIDs, properties, numProperties); }

STDMETHODIMP CCOMCoder64::Code(ISequentialInStream *inStream,
    ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
    ICompressProgressInfo *progress)
  { return BaseCode(inStream, outStream, inSize, outSize, progress); }

STDMETHODIMP CCOMCoder64::SetCoderProperties(const PROPID *propIDs, 
    const PROPVARIANT *properties, UInt32 numProperties)
  { return BaseSetEncoderProperties2(propIDs, properties, numProperties); }

}}}

Generated by  Doxygen 1.6.0   Back to index