mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-08 16:07:04 -06:00
4.34 beta
This commit is contained in:
committed by
Kornel Lesiński
parent
02516d3fce
commit
0f60a4933b
@@ -43,7 +43,7 @@ RSC=rc.exe
|
||||
# PROP Ignore_Export_Lib 1
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BZIP2_EXPORTS" /YX /FD /c
|
||||
# ADD CPP /nologo /Gz /MD /W3 /GX /O1 /I "..\..\..\\" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BZIP2_EXPORTS" /D "BZ_NO_STDIO" /Yu"StdAfx.h" /FD /c
|
||||
# ADD CPP /nologo /Gz /MD /W3 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "BZ_NO_STDIO" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BZIP2_EXPORTS" /D "COMPRESS_BZIP2_MT" /Yu"StdAfx.h" /FD /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x419 /d "NDEBUG"
|
||||
@@ -70,7 +70,7 @@ LINK32=link.exe
|
||||
# PROP Ignore_Export_Lib 1
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BZIP2_EXPORTS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /Gz /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\\" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BZIP2_EXPORTS" /Yu"StdAfx.h" /FD /GZ /c
|
||||
# ADD CPP /nologo /Gz /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BZIP2_EXPORTS" /D "COMPRESS_BZIP2_MT" /Yu"StdAfx.h" /FD /GZ /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x419 /d "_DEBUG"
|
||||
@@ -213,6 +213,26 @@ SOURCE=..\BWT\BlockSort.h
|
||||
SOURCE=..\BWT\Mtf8.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Windows"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\Synchronization.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\Synchronization.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\Thread.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\BZip2Const.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\BZip2CRC.cpp
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
namespace NCompress {
|
||||
namespace NBZip2 {
|
||||
|
||||
const UInt32 kNumThreadsMax = 4;
|
||||
|
||||
static const UInt32 kBufferSize = (1 << 17);
|
||||
|
||||
static Int16 kRandNums[512] = {
|
||||
@@ -69,11 +71,6 @@ static Int16 kRandNums[512] = {
|
||||
936, 638
|
||||
};
|
||||
|
||||
CState::~CState()
|
||||
{
|
||||
::BigFree(tt);
|
||||
}
|
||||
|
||||
bool CState::Alloc()
|
||||
{
|
||||
if (tt == 0)
|
||||
@@ -81,6 +78,109 @@ bool CState::Alloc()
|
||||
return (tt != 0);
|
||||
}
|
||||
|
||||
void CState::Free()
|
||||
{
|
||||
::BigFree(tt);
|
||||
tt = 0;
|
||||
}
|
||||
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
void CState::FinishStream()
|
||||
{
|
||||
Decoder->StreamWasFinished = true;
|
||||
StreamWasFinishedEvent.Set();
|
||||
Decoder->CS.Leave();
|
||||
Decoder->CanStartWaitingEvent.Lock();
|
||||
WaitingWasStartedEvent.Set();
|
||||
}
|
||||
|
||||
DWORD CState::ThreadFunc()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Decoder->CS.Enter();
|
||||
if (Decoder->CloseThreads)
|
||||
{
|
||||
Decoder->CS.Leave();
|
||||
return 0;
|
||||
}
|
||||
if (Decoder->StreamWasFinished)
|
||||
{
|
||||
FinishStream();
|
||||
continue;
|
||||
}
|
||||
HRESULT res = S_OK;
|
||||
try
|
||||
{
|
||||
UInt32 blockIndex = Decoder->NextBlockIndex;
|
||||
UInt32 nextBlockIndex = blockIndex + 1;
|
||||
if (nextBlockIndex == Decoder->NumThreads)
|
||||
nextBlockIndex = 0;
|
||||
Decoder->NextBlockIndex = nextBlockIndex;
|
||||
|
||||
bool wasFinished;
|
||||
UInt32 crc;
|
||||
res = Decoder->ReadSignatures(wasFinished, crc);
|
||||
if (res != S_OK)
|
||||
{
|
||||
Decoder->Result = res;
|
||||
FinishStream();
|
||||
continue;
|
||||
}
|
||||
if (wasFinished)
|
||||
{
|
||||
Decoder->Result = res;
|
||||
FinishStream();
|
||||
continue;
|
||||
}
|
||||
|
||||
res = Decoder->ReadBlock(Decoder->BlockSizeMax, *this);
|
||||
UInt64 packSize = Decoder->m_InStream.GetProcessedSize();
|
||||
if (res != S_OK)
|
||||
{
|
||||
Decoder->Result = res;
|
||||
FinishStream();
|
||||
continue;
|
||||
}
|
||||
Decoder->CS.Leave();
|
||||
|
||||
DecodeBlock1();
|
||||
|
||||
Decoder->m_States[blockIndex].CanWriteEvent.Lock();
|
||||
|
||||
if (DecodeBlock2(Decoder->m_OutStream) != crc)
|
||||
{
|
||||
Decoder->Result = S_FALSE;
|
||||
FinishStream();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Decoder->Progress)
|
||||
{
|
||||
UInt64 unpackSize = Decoder->m_OutStream.GetProcessedSize();
|
||||
res = Decoder->Progress->SetRatioInfo(&packSize, &unpackSize);
|
||||
}
|
||||
|
||||
Decoder->m_States[nextBlockIndex].CanWriteEvent.Set();
|
||||
}
|
||||
catch(const CInBufferException &e) { res = e.ErrorCode; }
|
||||
catch(const COutBufferException &e) { res = e.ErrorCode; }
|
||||
catch(...) { res = E_FAIL; }
|
||||
if (res != S_OK)
|
||||
{
|
||||
Decoder->Result = res;
|
||||
FinishStream();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD WINAPI MFThread(void *threadCoderInfo)
|
||||
{
|
||||
return ((CState *)threadCoderInfo)->ThreadFunc();
|
||||
}
|
||||
#endif
|
||||
|
||||
UInt32 CDecoder::ReadBits(int numBits) { return m_InStream.ReadBits(numBits); }
|
||||
Byte CDecoder::ReadByte() {return (Byte)ReadBits(8); }
|
||||
bool CDecoder::ReadBit() { return ReadBits(1) != 0; }
|
||||
@@ -201,7 +301,7 @@ HRESULT CDecoder::ReadBlock(UInt32 blockSizeMax, CState &state)
|
||||
groupSize = kGroupSize;
|
||||
huffmanDecoder = &m_HuffmanDecoders[state.m_Selectors[groupIndex++]];
|
||||
}
|
||||
groupSize--; \
|
||||
groupSize--;
|
||||
|
||||
UInt32 nextSym = huffmanDecoder->DecodeSymbol(&m_InStream);
|
||||
|
||||
@@ -241,7 +341,7 @@ HRESULT CDecoder::ReadBlock(UInt32 blockSizeMax, CState &state)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CState::DecodeBlock(COutBuffer &m_OutStream)
|
||||
void CState::DecodeBlock1()
|
||||
{
|
||||
UInt32 *charCounters = this->CharCounters;
|
||||
{
|
||||
@@ -259,8 +359,11 @@ HRESULT CState::DecodeBlock(COutBuffer &m_OutStream)
|
||||
do
|
||||
tt[charCounters[tt[i] & 0xFF]++] |= (i << 8);
|
||||
while(++i < blockSize);
|
||||
}
|
||||
|
||||
// Decode
|
||||
UInt32 CState::DecodeBlock2(COutBuffer &m_OutStream)
|
||||
{
|
||||
UInt32 blockSize = this->BlockSize;
|
||||
|
||||
CBZip2CRC crc;
|
||||
|
||||
@@ -310,11 +413,122 @@ HRESULT CState::DecodeBlock(COutBuffer &m_OutStream)
|
||||
m_OutStream.WriteByte(b);
|
||||
}
|
||||
while(--blockSize != 0);
|
||||
return (StoredCRC == crc.GetDigest()) ? S_OK : S_FALSE;
|
||||
return crc.GetDigest();
|
||||
}
|
||||
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
CDecoder::CDecoder():
|
||||
m_States(0)
|
||||
{
|
||||
m_NumThreadsPrev = 0;
|
||||
NumThreads = 1;
|
||||
CS.Enter();
|
||||
}
|
||||
|
||||
CDecoder::~CDecoder()
|
||||
{
|
||||
Free();
|
||||
}
|
||||
|
||||
bool CDecoder::Create()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (m_States != 0 && m_NumThreadsPrev == NumThreads)
|
||||
return true;
|
||||
Free();
|
||||
MtMode = (NumThreads > 1);
|
||||
m_NumThreadsPrev = NumThreads;
|
||||
m_States = new CState[NumThreads];
|
||||
if (m_States == 0)
|
||||
return false;
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
for (UInt32 t = 0; t < NumThreads; t++)
|
||||
{
|
||||
CState &ti = m_States[t];
|
||||
ti.Decoder = this;
|
||||
if (MtMode)
|
||||
if (!ti.Thread.Create(MFThread, &ti))
|
||||
{
|
||||
NumThreads = t;
|
||||
Free();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch(...) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDecoder::Free()
|
||||
{
|
||||
if (!m_States)
|
||||
return;
|
||||
CloseThreads = true;
|
||||
CS.Leave();
|
||||
for (UInt32 t = 0; t < NumThreads; t++)
|
||||
{
|
||||
CState &s = m_States[t];
|
||||
if (MtMode)
|
||||
s.Thread.Wait();
|
||||
s.Free();
|
||||
}
|
||||
delete []m_States;
|
||||
m_States = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
HRESULT CDecoder::ReadSignatures(bool &wasFinished, UInt32 &crc)
|
||||
{
|
||||
wasFinished = false;
|
||||
Byte s[6];
|
||||
for (int i = 0; i < 6; i++)
|
||||
s[i] = ReadByte();
|
||||
crc = ReadCRC();
|
||||
if (s[0] == kFinSig0)
|
||||
{
|
||||
if (s[1] != kFinSig1 ||
|
||||
s[2] != kFinSig2 ||
|
||||
s[3] != kFinSig3 ||
|
||||
s[4] != kFinSig4 ||
|
||||
s[5] != kFinSig5)
|
||||
return S_FALSE;
|
||||
|
||||
wasFinished = true;
|
||||
return (crc == CombinedCRC.GetDigest()) ? S_OK : S_FALSE;
|
||||
}
|
||||
if (s[0] != kBlockSig0 ||
|
||||
s[1] != kBlockSig1 ||
|
||||
s[2] != kBlockSig2 ||
|
||||
s[3] != kBlockSig3 ||
|
||||
s[4] != kBlockSig4 ||
|
||||
s[5] != kBlockSig5)
|
||||
return S_FALSE;
|
||||
CombinedCRC.Update(crc);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CDecoder::DecodeFile(bool &isBZ, ICompressProgressInfo *progress)
|
||||
{
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
Progress = progress;
|
||||
if (!Create())
|
||||
return E_FAIL;
|
||||
for (UInt32 t = 0; t < NumThreads; t++)
|
||||
{
|
||||
CState &s = m_States[t];
|
||||
if (!s.Alloc())
|
||||
return E_OUTOFMEMORY;
|
||||
s.StreamWasFinishedEvent.Reset();
|
||||
s.WaitingWasStartedEvent.Reset();
|
||||
s.CanWriteEvent.Reset();
|
||||
}
|
||||
#else
|
||||
if (!m_States[0].Alloc())
|
||||
return E_OUTOFMEMORY;
|
||||
#endif
|
||||
|
||||
isBZ = false;
|
||||
Byte s[6];
|
||||
int i;
|
||||
@@ -329,45 +543,53 @@ HRESULT CDecoder::DecodeFile(bool &isBZ, ICompressProgressInfo *progress)
|
||||
isBZ = true;
|
||||
UInt32 dicSize = (UInt32)(s[3] - kArSig3) * kBlockSizeStep;
|
||||
|
||||
if (!m_State.Alloc())
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
CBZip2CombinedCRC computedCombinedCRC;
|
||||
while (true)
|
||||
CombinedCRC.Init();
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
if (MtMode)
|
||||
{
|
||||
if (progress)
|
||||
{
|
||||
UInt64 packSize = m_InStream.GetProcessedSize();
|
||||
UInt64 unpackSize = m_OutStream.GetProcessedSize();
|
||||
RINOK(progress->SetRatioInfo(&packSize, &unpackSize));
|
||||
}
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
s[i] = ReadByte();
|
||||
UInt32 crc = ReadCRC();
|
||||
if (s[0] == kFinSig0)
|
||||
{
|
||||
if (s[1] != kFinSig1 ||
|
||||
s[2] != kFinSig2 ||
|
||||
s[3] != kFinSig3 ||
|
||||
s[4] != kFinSig4 ||
|
||||
s[5] != kFinSig5)
|
||||
return S_FALSE;
|
||||
|
||||
return (crc == computedCombinedCRC.GetDigest()) ? S_OK : S_FALSE;
|
||||
}
|
||||
if (s[0] != kBlockSig0 ||
|
||||
s[1] != kBlockSig1 ||
|
||||
s[2] != kBlockSig2 ||
|
||||
s[3] != kBlockSig3 ||
|
||||
s[4] != kBlockSig4 ||
|
||||
s[5] != kBlockSig5)
|
||||
return S_FALSE;
|
||||
m_State.StoredCRC = crc;
|
||||
computedCombinedCRC.Update(crc);
|
||||
RINOK(ReadBlock(dicSize, m_State));
|
||||
RINOK(m_State.DecodeBlock(m_OutStream));
|
||||
NextBlockIndex = 0;
|
||||
StreamWasFinished = false;
|
||||
CloseThreads = false;
|
||||
CanStartWaitingEvent.Reset();
|
||||
m_States[0].CanWriteEvent.Set();
|
||||
BlockSizeMax = dicSize;
|
||||
Result = S_OK;
|
||||
CS.Leave();
|
||||
UInt32 t;
|
||||
for (t = 0; t < NumThreads; t++)
|
||||
m_States[t].StreamWasFinishedEvent.Lock();
|
||||
CS.Enter();
|
||||
CanStartWaitingEvent.Set();
|
||||
for (t = 0; t < NumThreads; t++)
|
||||
m_States[t].WaitingWasStartedEvent.Lock();
|
||||
CanStartWaitingEvent.Reset();
|
||||
RINOK(Result);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
CState &state = m_States[0];
|
||||
while (true)
|
||||
{
|
||||
if (progress)
|
||||
{
|
||||
UInt64 packSize = m_InStream.GetProcessedSize();
|
||||
UInt64 unpackSize = m_OutStream.GetProcessedSize();
|
||||
RINOK(progress->SetRatioInfo(&packSize, &unpackSize));
|
||||
}
|
||||
bool wasFinished;
|
||||
UInt32 crc;
|
||||
RINOK(ReadSignatures(wasFinished, crc));
|
||||
if (wasFinished)
|
||||
return S_OK;
|
||||
|
||||
RINOK(ReadBlock(dicSize, state));
|
||||
state.DecodeBlock1();
|
||||
if (state.DecodeBlock2(m_OutStream) != crc)
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CDecoder::CodeReal(ISequentialInStream *inStream,
|
||||
@@ -408,4 +630,16 @@ STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
STDMETHODIMP CDecoder::SetNumberOfThreads(UInt32 numThreads)
|
||||
{
|
||||
NumThreads = numThreads;
|
||||
if (NumThreads < 1)
|
||||
NumThreads = 1;
|
||||
if (NumThreads > kNumThreadsMax)
|
||||
NumThreads = kNumThreadsMax;
|
||||
return S_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
}}
|
||||
|
||||
@@ -10,12 +10,20 @@
|
||||
#include "../../Common/OutBuffer.h"
|
||||
#include "../Huffman/HuffmanDecoder.h"
|
||||
#include "BZip2Const.h"
|
||||
#include "BZip2CRC.h"
|
||||
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
#include "../../../Windows/Thread.h"
|
||||
#include "../../../Windows/Synchronization.h"
|
||||
#endif
|
||||
|
||||
namespace NCompress {
|
||||
namespace NBZip2 {
|
||||
|
||||
typedef NCompress::NHuffman::CDecoder<kMaxHuffmanLen, kMaxAlphaSize> CHuffmanDecoder;
|
||||
|
||||
class CDecoder;
|
||||
|
||||
struct CState
|
||||
{
|
||||
UInt32 *tt;
|
||||
@@ -24,31 +32,55 @@ struct CState
|
||||
UInt32 BlockSize;
|
||||
UInt32 CharCounters[256];
|
||||
Byte m_Selectors[kNumSelectorsMax];
|
||||
UInt32 StoredCRC;
|
||||
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
|
||||
CDecoder *Decoder;
|
||||
NWindows::CThread Thread;
|
||||
bool m_OptimizeNumTables;
|
||||
|
||||
NWindows::NSynchronization::CAutoResetEvent StreamWasFinishedEvent;
|
||||
NWindows::NSynchronization::CAutoResetEvent WaitingWasStartedEvent;
|
||||
|
||||
// it's not member of this thread. We just need one event per thread
|
||||
NWindows::NSynchronization::CAutoResetEvent CanWriteEvent;
|
||||
|
||||
Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
|
||||
|
||||
void FinishStream();
|
||||
DWORD ThreadFunc();
|
||||
|
||||
#endif
|
||||
|
||||
CState(): tt(0) {}
|
||||
~CState();
|
||||
~CState() { Free(); }
|
||||
bool Alloc();
|
||||
HRESULT DecodeBlock(COutBuffer &m_OutStream);
|
||||
void Free();
|
||||
void DecodeBlock1();
|
||||
UInt32 DecodeBlock2(COutBuffer &m_OutStream);
|
||||
};
|
||||
|
||||
class CDecoder :
|
||||
public ICompressCoder,
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
public ICompressSetCoderMt,
|
||||
#endif
|
||||
public ICompressGetInStreamProcessedSize,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
NStream::NMSBF::CDecoder<CInBuffer> m_InStream;
|
||||
public:
|
||||
COutBuffer m_OutStream;
|
||||
|
||||
Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
|
||||
NStream::NMSBF::CDecoder<CInBuffer> m_InStream;
|
||||
private:
|
||||
CHuffmanDecoder m_HuffmanDecoders[kNumTablesMax];
|
||||
|
||||
CState m_State;
|
||||
|
||||
UInt32 m_NumThreadsPrev;
|
||||
|
||||
UInt32 ReadBits(int numBits);
|
||||
Byte ReadByte();
|
||||
bool ReadBit();
|
||||
UInt32 ReadCRC();
|
||||
HRESULT ReadBlock(UInt32 blockSizeMax, CState &state);
|
||||
HRESULT PrepareBlock(CState &state);
|
||||
HRESULT DecodeFile(bool &isBZ, ICompressProgressInfo *progress);
|
||||
HRESULT CodeReal(ISequentialInStream *inStream,
|
||||
@@ -69,6 +101,37 @@ class CDecoder :
|
||||
};
|
||||
|
||||
public:
|
||||
CBZip2CombinedCRC CombinedCRC;
|
||||
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
ICompressProgressInfo *Progress;
|
||||
CState *m_States;
|
||||
|
||||
NWindows::NSynchronization::CCriticalSection CS;
|
||||
UInt32 NumThreads;
|
||||
bool MtMode;
|
||||
UInt32 NextBlockIndex;
|
||||
bool CloseThreads;
|
||||
bool StreamWasFinished;
|
||||
NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent;
|
||||
|
||||
HRESULT Result;
|
||||
|
||||
UInt32 BlockSizeMax;
|
||||
CDecoder();
|
||||
~CDecoder();
|
||||
bool Create();
|
||||
void Free();
|
||||
|
||||
#else
|
||||
CState m_States[1];
|
||||
#endif
|
||||
|
||||
HRESULT ReadBlock(UInt32 blockSizeMax, CState &state);
|
||||
|
||||
HRESULT ReadSignatures(bool &wasFinished, UInt32 &crc);
|
||||
|
||||
|
||||
HRESULT Flush() { return m_OutStream.Flush(); }
|
||||
void ReleaseStreams()
|
||||
{
|
||||
@@ -76,13 +139,22 @@ public:
|
||||
m_OutStream.ReleaseStream();
|
||||
}
|
||||
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
MY_UNKNOWN_IMP2(ICompressSetCoderMt, ICompressGetInStreamProcessedSize)
|
||||
#else
|
||||
MY_UNKNOWN_IMP1(ICompressGetInStreamProcessedSize)
|
||||
#endif
|
||||
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream,
|
||||
ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
|
||||
ICompressProgressInfo *progress);
|
||||
|
||||
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
|
||||
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
STDMETHOD(SetNumberOfThreads)(UInt32 numThreads);
|
||||
#endif
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../Common/Alloc.h"
|
||||
|
||||
#include "BZip2Encoder.h"
|
||||
|
||||
#include "../../../Common/Alloc.h"
|
||||
#include "../BWT/Mtf8.h"
|
||||
#include "BZip2CRC.h"
|
||||
|
||||
@@ -14,19 +15,161 @@ namespace NBZip2 {
|
||||
static const UInt32 kBufferSize = (1 << 17);
|
||||
static const int kNumHuffPasses = 4;
|
||||
|
||||
CEncoder::CEncoder():
|
||||
m_Block(0),
|
||||
m_NeedHuffmanCreate(true),
|
||||
m_NumPasses(1),
|
||||
bool CThreadInfo::Create()
|
||||
{
|
||||
if (!m_BlockSorter.Create(kBlockSizeMax))
|
||||
return false;
|
||||
|
||||
if (m_Block == 0)
|
||||
{
|
||||
m_Block = (Byte *)::BigAlloc(kBlockSizeMax * 5 + kBlockSizeMax / 10 + (20 << 10));
|
||||
if (m_Block == 0)
|
||||
return false;
|
||||
m_MtfArray = m_Block + kBlockSizeMax;
|
||||
m_TempArray = m_MtfArray + kBlockSizeMax * 2 + 2;
|
||||
}
|
||||
if (m_NeedHuffmanCreate)
|
||||
{
|
||||
for (int i = 0; i < kNumTablesMax; i++)
|
||||
if (!m_HuffEncoders[i].Create(kMaxAlphaSize, 0, 0, kMaxHuffmanLen))
|
||||
return false;
|
||||
m_NeedHuffmanCreate = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CThreadInfo::Free()
|
||||
{
|
||||
m_BlockSorter.Free();
|
||||
::BigFree(m_Block);
|
||||
m_Block = 0;
|
||||
}
|
||||
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
void CThreadInfo::FinishStream()
|
||||
{
|
||||
Encoder->StreamWasFinished = true;
|
||||
StreamWasFinishedEvent.Set();
|
||||
Encoder->CS.Leave();
|
||||
Encoder->CanStartWaitingEvent.Lock();
|
||||
WaitingWasStartedEvent.Set();
|
||||
}
|
||||
|
||||
DWORD CThreadInfo::ThreadFunc()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Encoder->CS.Enter();
|
||||
if (Encoder->CloseThreads)
|
||||
{
|
||||
Encoder->CS.Leave();
|
||||
return 0;
|
||||
}
|
||||
if (Encoder->StreamWasFinished)
|
||||
{
|
||||
FinishStream();
|
||||
continue;
|
||||
}
|
||||
HRESULT res = S_OK;
|
||||
try
|
||||
{
|
||||
UInt32 blockSize = Encoder->ReadRleBlock(m_Block);
|
||||
m_PackSize = Encoder->m_InStream.GetProcessedSize();
|
||||
m_BlockIndex = Encoder->NextBlockIndex;
|
||||
if (++Encoder->NextBlockIndex == Encoder->NumThreads)
|
||||
Encoder->NextBlockIndex = 0;
|
||||
if (blockSize == 0)
|
||||
{
|
||||
FinishStream();
|
||||
continue;
|
||||
}
|
||||
Encoder->CS.Leave();
|
||||
res = EncodeBlock3(blockSize);
|
||||
}
|
||||
catch(const CInBufferException &e) { res = e.ErrorCode; }
|
||||
catch(const COutBufferException &e) { res = e.ErrorCode; }
|
||||
catch(...) { res = E_FAIL; }
|
||||
if (res != S_OK)
|
||||
{
|
||||
Encoder->Result = res;
|
||||
FinishStream();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD WINAPI MFThread(void *threadCoderInfo)
|
||||
{
|
||||
return ((CThreadInfo *)threadCoderInfo)->ThreadFunc();
|
||||
}
|
||||
#endif
|
||||
|
||||
CEncoder::CEncoder():
|
||||
NumPasses(1),
|
||||
m_OptimizeNumTables(false),
|
||||
m_BlockSizeMult(kBlockSizeMultMax)
|
||||
{}
|
||||
{
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
ThreadsInfo = 0;
|
||||
m_NumThreadsPrev = 0;
|
||||
NumThreads = 1;
|
||||
CS.Enter();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
CEncoder::~CEncoder()
|
||||
{
|
||||
::BigFree(m_Block);
|
||||
Free();
|
||||
}
|
||||
|
||||
bool CEncoder::Create()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ThreadsInfo != 0 && m_NumThreadsPrev == NumThreads)
|
||||
return true;
|
||||
Free();
|
||||
MtMode = (NumThreads > 1);
|
||||
m_NumThreadsPrev = NumThreads;
|
||||
ThreadsInfo = new CThreadInfo[NumThreads];
|
||||
if (ThreadsInfo == 0)
|
||||
return false;
|
||||
for (UInt32 t = 0; t < NumThreads; t++)
|
||||
{
|
||||
CThreadInfo &ti = ThreadsInfo[t];
|
||||
ti.Encoder = this;
|
||||
if (MtMode)
|
||||
if (!ti.Thread.Create(MFThread, &ti))
|
||||
{
|
||||
NumThreads = t;
|
||||
Free();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(...) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
void CEncoder::Free()
|
||||
{
|
||||
if (!ThreadsInfo)
|
||||
return;
|
||||
CloseThreads = true;
|
||||
CS.Leave();
|
||||
for (UInt32 t = 0; t < NumThreads; t++)
|
||||
{
|
||||
CThreadInfo &ti = ThreadsInfo[t];
|
||||
if (MtMode)
|
||||
ti.Thread.Wait();
|
||||
ti.Free();
|
||||
}
|
||||
delete []ThreadsInfo;
|
||||
ThreadsInfo = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
UInt32 CEncoder::ReadRleBlock(Byte *buffer)
|
||||
{
|
||||
UInt32 i = 0;
|
||||
@@ -66,11 +209,11 @@ UInt32 CEncoder::ReadRleBlock(Byte *buffer)
|
||||
return i;
|
||||
}
|
||||
|
||||
void CEncoder::WriteBits2(UInt32 value, UInt32 numBits)
|
||||
void CThreadInfo::WriteBits2(UInt32 value, UInt32 numBits)
|
||||
{ m_OutStreamCurrent->WriteBits(value, numBits); }
|
||||
void CEncoder::WriteByte2(Byte b) { WriteBits2(b , 8); }
|
||||
void CEncoder::WriteBit2(bool v) { WriteBits2((v ? 1 : 0), 1); }
|
||||
void CEncoder::WriteCRC2(UInt32 v)
|
||||
void CThreadInfo::WriteByte2(Byte b) { WriteBits2(b , 8); }
|
||||
void CThreadInfo::WriteBit2(bool v) { WriteBits2((v ? 1 : 0), 1); }
|
||||
void CThreadInfo::WriteCRC2(UInt32 v)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
WriteByte2(((Byte)(v >> (24 - i * 8))));
|
||||
@@ -88,7 +231,7 @@ void CEncoder::WriteCRC(UInt32 v)
|
||||
|
||||
|
||||
// blockSize > 0
|
||||
void CEncoder::EncodeBlock(Byte *block, UInt32 blockSize)
|
||||
void CThreadInfo::EncodeBlock(Byte *block, UInt32 blockSize)
|
||||
{
|
||||
WriteBit2(false); // Randomised = false
|
||||
|
||||
@@ -404,7 +547,7 @@ void CEncoder::EncodeBlock(Byte *block, UInt32 blockSize)
|
||||
}
|
||||
|
||||
// blockSize > 0
|
||||
UInt32 CEncoder::EncodeBlockWithHeaders(Byte *block, UInt32 blockSize)
|
||||
UInt32 CThreadInfo::EncodeBlockWithHeaders(Byte *block, UInt32 blockSize)
|
||||
{
|
||||
WriteByte2(kBlockSig0);
|
||||
WriteByte2(kBlockSig1);
|
||||
@@ -443,11 +586,10 @@ UInt32 CEncoder::EncodeBlockWithHeaders(Byte *block, UInt32 blockSize)
|
||||
return crcRes;
|
||||
}
|
||||
|
||||
void CEncoder::EncodeBlock2(CBZip2CombinedCRC &combinedCRC,
|
||||
Byte *block, UInt32 blockSize, UInt32 numPasses)
|
||||
void CThreadInfo::EncodeBlock2(Byte *block, UInt32 blockSize, UInt32 numPasses)
|
||||
{
|
||||
UInt32 numCrcs = m_NumCrcs;
|
||||
bool needCompare = false;
|
||||
CBZip2CombinedCRC specCombinedCRC = combinedCRC;
|
||||
|
||||
UInt32 startBytePos = m_OutStreamCurrent->GetBytePos();
|
||||
UInt32 startPos = m_OutStreamCurrent->GetPos();
|
||||
@@ -462,9 +604,8 @@ void CEncoder::EncodeBlock2(CBZip2CombinedCRC &combinedCRC,
|
||||
blockSize0 < blockSize; blockSize0++);
|
||||
if (blockSize0 < blockSize)
|
||||
{
|
||||
EncodeBlock2(specCombinedCRC, block, blockSize0, numPasses - 1);
|
||||
EncodeBlock2(specCombinedCRC, block + blockSize0, blockSize - blockSize0,
|
||||
numPasses - 1);
|
||||
EncodeBlock2(block, blockSize0, numPasses - 1);
|
||||
EncodeBlock2(block + blockSize0, blockSize - blockSize0, numPasses - 1);
|
||||
endPos = m_OutStreamCurrent->GetPos();
|
||||
endCurByte = m_OutStreamCurrent->GetCurByte();
|
||||
if ((endPos & 7) > 0)
|
||||
@@ -479,8 +620,6 @@ void CEncoder::EncodeBlock2(CBZip2CombinedCRC &combinedCRC,
|
||||
UInt32 crcVal = EncodeBlockWithHeaders(block, blockSize);
|
||||
UInt32 endPos2 = m_OutStreamCurrent->GetPos();
|
||||
|
||||
combinedCRC.Update(crcVal);
|
||||
|
||||
if (needCompare)
|
||||
{
|
||||
UInt32 size2 = endPos2 - startPos2;
|
||||
@@ -491,59 +630,102 @@ void CEncoder::EncodeBlock2(CBZip2CombinedCRC &combinedCRC,
|
||||
for (UInt32 i = 0; i < numBytes; i++)
|
||||
buffer[startBytePos + i] = buffer[startBytePos2 + i];
|
||||
m_OutStreamCurrent->SetPos(startPos + endPos2 - startPos2);
|
||||
m_NumCrcs = numCrcs;
|
||||
m_CRCs[m_NumCrcs++] = crcVal;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_OutStreamCurrent->SetPos(endPos);
|
||||
m_OutStreamCurrent->SetCurState((endPos & 7), endCurByte);
|
||||
combinedCRC = specCombinedCRC;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_NumCrcs = numCrcs;
|
||||
m_CRCs[m_NumCrcs++] = crcVal;
|
||||
}
|
||||
}
|
||||
|
||||
void CEncoder::EncodeBlock3(CBZip2CombinedCRC &combinedCRC, UInt32 blockSize)
|
||||
HRESULT CThreadInfo::EncodeBlock3(UInt32 blockSize)
|
||||
{
|
||||
CMsbfEncoderTemp outStreamTemp;
|
||||
outStreamTemp.SetStream(m_TempArray);
|
||||
outStreamTemp.Init();
|
||||
m_OutStreamCurrent = &outStreamTemp;
|
||||
|
||||
EncodeBlock2(combinedCRC, m_Block, blockSize, m_NumPasses);
|
||||
m_NumCrcs = 0;
|
||||
|
||||
UInt32 size = outStreamTemp.GetPos();
|
||||
UInt32 bytesSize = (size / 8);
|
||||
for (UInt32 i = 0; i < bytesSize; i++)
|
||||
m_OutStream.WriteBits(m_TempArray[i], 8);
|
||||
WriteBits(outStreamTemp.GetCurByte(), (size & 7));
|
||||
EncodeBlock2(m_Block, blockSize, Encoder->NumPasses);
|
||||
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
if (Encoder->MtMode)
|
||||
Encoder->ThreadsInfo[m_BlockIndex].CanWriteEvent.Lock();
|
||||
#endif
|
||||
for (UInt32 i = 0; i < m_NumCrcs; i++)
|
||||
Encoder->CombinedCRC.Update(m_CRCs[i]);
|
||||
Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetCurByte());
|
||||
HRESULT res = S_OK;
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
if (Encoder->MtMode)
|
||||
{
|
||||
UInt32 blockIndex = m_BlockIndex + 1;
|
||||
if (blockIndex == Encoder->NumThreads)
|
||||
blockIndex = 0;
|
||||
|
||||
if (Encoder->Progress)
|
||||
{
|
||||
UInt64 unpackSize = Encoder->m_OutStream.GetProcessedSize();
|
||||
res = Encoder->Progress->SetRatioInfo(&m_PackSize, &unpackSize);
|
||||
}
|
||||
|
||||
Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set();
|
||||
}
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte)
|
||||
{
|
||||
UInt32 bytesSize = (sizeInBits / 8);
|
||||
for (UInt32 i = 0; i < bytesSize; i++)
|
||||
m_OutStream.WriteBits(data[i], 8);
|
||||
WriteBits(lastByte, (sizeInBits & 7));
|
||||
}
|
||||
|
||||
|
||||
HRESULT CEncoder::CodeReal(ISequentialInStream *inStream,
|
||||
ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
|
||||
ICompressProgressInfo *progress)
|
||||
{
|
||||
if (!m_BlockSorter.Create(kBlockSizeMax))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
if (m_Block == 0)
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
Progress = progress;
|
||||
if (!Create())
|
||||
return E_FAIL;
|
||||
for (UInt32 t = 0; t < NumThreads; t++)
|
||||
#endif
|
||||
{
|
||||
m_Block = (Byte *)BigAlloc(kBlockSizeMax * 5 + kBlockSizeMax / 10 + (20 << 10));
|
||||
if (m_Block == 0)
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
CThreadInfo &ti = ThreadsInfo[t];
|
||||
ti.StreamWasFinishedEvent.Reset();
|
||||
ti.WaitingWasStartedEvent.Reset();
|
||||
ti.CanWriteEvent.Reset();
|
||||
#else
|
||||
CThreadInfo &ti = ThreadsInfo;
|
||||
ti.Encoder = this;
|
||||
#endif
|
||||
|
||||
ti.m_OptimizeNumTables = m_OptimizeNumTables;
|
||||
|
||||
if (!ti.Create())
|
||||
return E_OUTOFMEMORY;
|
||||
m_MtfArray = m_Block + kBlockSizeMax;
|
||||
m_TempArray = m_MtfArray + kBlockSizeMax * 2 + 2;
|
||||
}
|
||||
|
||||
|
||||
if (!m_InStream.Create(kBufferSize))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!m_OutStream.Create(kBufferSize))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
if (m_NeedHuffmanCreate)
|
||||
{
|
||||
for (int i = 0; i < kNumTablesMax; i++)
|
||||
if (!m_HuffEncoders[i].Create(kMaxAlphaSize, 0, 0, kMaxHuffmanLen))
|
||||
return E_OUTOFMEMORY;
|
||||
m_NeedHuffmanCreate = false;
|
||||
}
|
||||
|
||||
m_InStream.SetStream(inStream);
|
||||
m_InStream.Init();
|
||||
@@ -553,24 +735,57 @@ HRESULT CEncoder::CodeReal(ISequentialInStream *inStream,
|
||||
|
||||
CFlusher flusher(this);
|
||||
|
||||
CBZip2CombinedCRC combinedCRC;
|
||||
CombinedCRC.Init();
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
NextBlockIndex = 0;
|
||||
StreamWasFinished = false;
|
||||
CloseThreads = false;
|
||||
CanStartWaitingEvent.Reset();
|
||||
#endif
|
||||
|
||||
WriteByte(kArSig0);
|
||||
WriteByte(kArSig1);
|
||||
WriteByte(kArSig2);
|
||||
WriteByte((Byte)(kArSig3 + m_BlockSizeMult));
|
||||
|
||||
while (true)
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
|
||||
if (MtMode)
|
||||
{
|
||||
UInt32 blockSize = ReadRleBlock(m_Block);
|
||||
if (blockSize == 0)
|
||||
break;
|
||||
EncodeBlock3(combinedCRC, blockSize);
|
||||
if (progress)
|
||||
ThreadsInfo[0].CanWriteEvent.Set();
|
||||
Result = S_OK;
|
||||
CS.Leave();
|
||||
UInt32 t;
|
||||
for (t = 0; t < NumThreads; t++)
|
||||
ThreadsInfo[t].StreamWasFinishedEvent.Lock();
|
||||
CS.Enter();
|
||||
CanStartWaitingEvent.Set();
|
||||
for (t = 0; t < NumThreads; t++)
|
||||
ThreadsInfo[t].WaitingWasStartedEvent.Lock();
|
||||
CanStartWaitingEvent.Reset();
|
||||
RINOK(Result);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
UInt64 packSize = m_InStream.GetProcessedSize();
|
||||
UInt64 unpackSize = m_OutStream.GetProcessedSize();
|
||||
RINOK(progress->SetRatioInfo(&packSize, &unpackSize));
|
||||
CThreadInfo &ti =
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
ThreadsInfo[0];
|
||||
#else
|
||||
ThreadsInfo;
|
||||
#endif
|
||||
UInt32 blockSize = ReadRleBlock(ti.m_Block);
|
||||
if (blockSize == 0)
|
||||
break;
|
||||
RINOK(ti.EncodeBlock3(blockSize));
|
||||
if (progress)
|
||||
{
|
||||
UInt64 packSize = m_InStream.GetProcessedSize();
|
||||
UInt64 unpackSize = m_OutStream.GetProcessedSize();
|
||||
RINOK(progress->SetRatioInfo(&packSize, &unpackSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
WriteByte(kFinSig0);
|
||||
@@ -580,7 +795,7 @@ HRESULT CEncoder::CodeReal(ISequentialInStream *inStream,
|
||||
WriteByte(kFinSig4);
|
||||
WriteByte(kFinSig5);
|
||||
|
||||
WriteCRC(combinedCRC.GetDigest());
|
||||
WriteCRC(CombinedCRC.GetDigest());
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -589,6 +804,8 @@ STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream,
|
||||
ICompressProgressInfo *progress)
|
||||
{
|
||||
try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
|
||||
catch(const CInBufferException &e) { return e.ErrorCode; }
|
||||
catch(const COutBufferException &e) { return e.ErrorCode; }
|
||||
catch(...) { return S_FALSE; }
|
||||
}
|
||||
|
||||
@@ -605,10 +822,12 @@ HRESULT CEncoder::SetCoderProperties(const PROPID *propIDs,
|
||||
if (property.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
UInt32 numPasses = property.ulVal;
|
||||
if(numPasses == 0 || numPasses > 10)
|
||||
return E_INVALIDARG;
|
||||
m_NumPasses = numPasses;
|
||||
m_OptimizeNumTables = (m_NumPasses > 1);
|
||||
if (numPasses == 0)
|
||||
numPasses = 1;
|
||||
if (numPasses > kNumPassesMax)
|
||||
numPasses = kNumPassesMax;
|
||||
NumPasses = numPasses;
|
||||
m_OptimizeNumTables = (NumPasses > 1);
|
||||
break;
|
||||
}
|
||||
case NCoderPropID::kDictionarySize:
|
||||
@@ -623,6 +842,17 @@ HRESULT CEncoder::SetCoderProperties(const PROPID *propIDs,
|
||||
m_BlockSizeMult = dictionary;
|
||||
break;
|
||||
}
|
||||
case NCoderPropID::kNumThreads:
|
||||
{
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
if (property.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
NumThreads = property.ulVal;
|
||||
if (NumThreads < 1)
|
||||
NumThreads = 1;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
@@ -630,4 +860,14 @@ HRESULT CEncoder::SetCoderProperties(const PROPID *propIDs,
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
STDMETHODIMP CEncoder::SetNumberOfThreads(UInt32 numThreads)
|
||||
{
|
||||
NumThreads = numThreads;
|
||||
if (NumThreads < 1)
|
||||
NumThreads = 1;
|
||||
return S_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
}}
|
||||
|
||||
@@ -12,7 +12,12 @@
|
||||
#include "../BWT/BlockSort.h"
|
||||
#include "BZip2Const.h"
|
||||
#include "BZip2CRC.h"
|
||||
|
||||
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
#include "../../../Windows/Thread.h"
|
||||
#include "../../../Windows/Synchronization.h"
|
||||
#endif
|
||||
|
||||
namespace NCompress {
|
||||
namespace NBZip2 {
|
||||
|
||||
@@ -76,49 +81,123 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class CEncoder :
|
||||
public ICompressCoder,
|
||||
public ICompressSetCoderProperties,
|
||||
public CMyUnknownImp
|
||||
class CEncoder;
|
||||
|
||||
const int kNumPassesMax = 10;
|
||||
|
||||
class CThreadInfo
|
||||
{
|
||||
public:
|
||||
Byte *m_Block;
|
||||
CInBuffer m_InStream;
|
||||
NStream::NMSBF::CEncoder<COutBuffer> m_OutStream;
|
||||
CMsbfEncoderTemp *m_OutStreamCurrent;
|
||||
CBlockSorter m_BlockSorter;
|
||||
|
||||
bool m_NeedHuffmanCreate;
|
||||
NCompression::NHuffman::CEncoder m_HuffEncoders[kNumTablesMax];
|
||||
|
||||
private:
|
||||
Byte *m_MtfArray;
|
||||
Byte *m_TempArray;
|
||||
CBlockSorter m_BlockSorter;
|
||||
|
||||
CMsbfEncoderTemp *m_OutStreamCurrent;
|
||||
|
||||
NCompression::NHuffman::CEncoder m_HuffEncoders[kNumTablesMax];
|
||||
Byte m_Selectors[kNumSelectorsMax];
|
||||
|
||||
UInt32 m_BlockSizeMult;
|
||||
UInt32 m_NumPasses;
|
||||
bool m_OptimizeNumTables;
|
||||
bool m_NeedHuffmanCreate;
|
||||
|
||||
UInt32 ReadRleBlock(Byte *buffer);
|
||||
UInt32 m_CRCs[1 << kNumPassesMax];
|
||||
UInt32 m_NumCrcs;
|
||||
|
||||
int m_BlockIndex;
|
||||
|
||||
void FinishStream();
|
||||
|
||||
void WriteBits2(UInt32 value, UInt32 numBits);
|
||||
void WriteByte2(Byte b);
|
||||
void WriteBit2(bool v);
|
||||
void WriteCRC2(UInt32 v);
|
||||
|
||||
|
||||
void EncodeBlock(Byte *block, UInt32 blockSize);
|
||||
UInt32 EncodeBlockWithHeaders(Byte *block, UInt32 blockSize);
|
||||
void EncodeBlock2(Byte *block, UInt32 blockSize, UInt32 numPasses);
|
||||
public:
|
||||
bool m_OptimizeNumTables;
|
||||
CEncoder *Encoder;
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
NWindows::CThread Thread;
|
||||
|
||||
NWindows::NSynchronization::CAutoResetEvent StreamWasFinishedEvent;
|
||||
NWindows::NSynchronization::CAutoResetEvent WaitingWasStartedEvent;
|
||||
|
||||
// it's not member of this thread. We just need one event per thread
|
||||
NWindows::NSynchronization::CAutoResetEvent CanWriteEvent;
|
||||
|
||||
UInt64 m_PackSize;
|
||||
|
||||
Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
|
||||
#endif
|
||||
|
||||
CThreadInfo(): m_Block(0), m_NeedHuffmanCreate(true) {}
|
||||
~CThreadInfo() { Free(); }
|
||||
bool Create();
|
||||
void Free();
|
||||
|
||||
HRESULT EncodeBlock3(UInt32 blockSize);
|
||||
DWORD ThreadFunc();
|
||||
};
|
||||
|
||||
class CEncoder :
|
||||
public ICompressCoder,
|
||||
public ICompressSetCoderProperties,
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
public ICompressSetCoderMt,
|
||||
#endif
|
||||
public CMyUnknownImp
|
||||
{
|
||||
UInt32 m_BlockSizeMult;
|
||||
bool m_OptimizeNumTables;
|
||||
|
||||
UInt32 m_NumPassesPrev;
|
||||
|
||||
UInt32 m_NumThreadsPrev;
|
||||
public:
|
||||
CInBuffer m_InStream;
|
||||
Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
|
||||
NStream::NMSBF::CEncoder<COutBuffer> m_OutStream;
|
||||
UInt32 NumPasses;
|
||||
CBZip2CombinedCRC CombinedCRC;
|
||||
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
CThreadInfo *ThreadsInfo;
|
||||
NWindows::NSynchronization::CCriticalSection CS;
|
||||
UInt32 NumThreads;
|
||||
bool MtMode;
|
||||
UInt32 NextBlockIndex;
|
||||
|
||||
bool CloseThreads;
|
||||
bool StreamWasFinished;
|
||||
NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent;
|
||||
|
||||
HRESULT Result;
|
||||
ICompressProgressInfo *Progress;
|
||||
#else
|
||||
CThreadInfo ThreadsInfo;
|
||||
#endif
|
||||
|
||||
UInt32 ReadRleBlock(Byte *buffer);
|
||||
void WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte);
|
||||
|
||||
void WriteBits(UInt32 value, UInt32 numBits);
|
||||
void WriteByte(Byte b);
|
||||
void WriteBit(bool v);
|
||||
void WriteCRC(UInt32 v);
|
||||
|
||||
void EncodeBlock(Byte *block, UInt32 blockSize);
|
||||
UInt32 EncodeBlockWithHeaders(Byte *block, UInt32 blockSize);
|
||||
void EncodeBlock2(CBZip2CombinedCRC &combinedCRC, Byte *block, UInt32 blockSize, UInt32 numPasses);
|
||||
void EncodeBlock3(CBZip2CombinedCRC &combinedCRC, UInt32 blockSize);
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
bool Create();
|
||||
void Free();
|
||||
#endif
|
||||
|
||||
public:
|
||||
CEncoder();
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
~CEncoder();
|
||||
#endif
|
||||
|
||||
HRESULT Flush() { return m_OutStream.Flush(); }
|
||||
|
||||
@@ -142,7 +221,11 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
MY_UNKNOWN_IMP1(ICompressSetCoderProperties)
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
MY_UNKNOWN_IMP2(ICompressSetCoderMt, ICompressSetCoderProperties)
|
||||
#else
|
||||
MY_UNKNOWN_IMP1(ICompressGetInStreamProcessedSize)
|
||||
#endif
|
||||
|
||||
HRESULT CodeReal(ISequentialInStream *inStream,
|
||||
ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
|
||||
@@ -153,6 +236,10 @@ public:
|
||||
ICompressProgressInfo *progress);
|
||||
STDMETHOD(SetCoderProperties)(const PROPID *propIDs,
|
||||
const PROPVARIANT *properties, UInt32 numProperties);
|
||||
|
||||
#ifdef COMPRESS_BZIP2_MT
|
||||
STDMETHOD(SetNumberOfThreads)(UInt32 numThreads);
|
||||
#endif
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
PROG = BZip2.dll
|
||||
DEF_FILE = ../Codec.def
|
||||
CFLAGS = $(CFLAGS) -I ../../../
|
||||
CFLAGS = $(CFLAGS) -I ../../../ -DCOMPRESS_BZIP2_MT
|
||||
LIBS = $(LIBS) oleaut32.lib
|
||||
|
||||
BZIP2_OBJS = \
|
||||
@@ -14,6 +14,9 @@ BZIP2_OPT_OBJS = \
|
||||
COMMON_OBJS = \
|
||||
$O\Alloc.obj \
|
||||
|
||||
WIN_OBJS = \
|
||||
$O\Synchronization.obj
|
||||
|
||||
7ZIP_COMMON_OBJS = \
|
||||
$O\InBuffer.obj \
|
||||
$O\OutBuffer.obj \
|
||||
@@ -23,6 +26,7 @@ OBJS = \
|
||||
$(BZIP2_OBJS) \
|
||||
$(BZIP2_OPT_OBJS) \
|
||||
$(COMMON_OBJS) \
|
||||
$(WIN_OBJS) \
|
||||
$(7ZIP_COMMON_OBJS) \
|
||||
$O\BlockSort.obj \
|
||||
$O\HuffmanEncoder.obj \
|
||||
@@ -36,6 +40,8 @@ $(BZIP2_OPT_OBJS): $(*B).cpp
|
||||
$(COMPL_O2)
|
||||
$(COMMON_OBJS): ../../../Common/$(*B).cpp
|
||||
$(COMPL)
|
||||
$(WIN_OBJS): ../../../Windows/$(*B).cpp
|
||||
$(COMPL)
|
||||
$(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp
|
||||
$(COMPL)
|
||||
$O\BlockSort.obj: ../BWT/$(*B).cpp
|
||||
|
||||
@@ -86,7 +86,9 @@ CCoder::CCoder(bool deflate64Mode):
|
||||
m_DistanceMemory(0),
|
||||
m_Created(false),
|
||||
m_Values(0),
|
||||
m_Tables(0)
|
||||
m_Tables(0),
|
||||
m_MatchFinderCycles(0),
|
||||
m_SetMfPasses(0)
|
||||
{
|
||||
m_MatchMaxLen = deflate64Mode ? kMatchMaxLen64 : kMatchMaxLen32;
|
||||
m_NumLenCombinations = deflate64Mode ? kNumLenSymbols64 : kNumLenSymbols32;
|
||||
@@ -99,7 +101,9 @@ HRESULT CCoder::Create()
|
||||
COM_TRY_BEGIN
|
||||
if (!m_MatchFinder)
|
||||
{
|
||||
m_MatchFinder = new NBT3Z::CMatchFinder;
|
||||
NBT3Z::CMatchFinder *matchFinderSpec = new NBT3Z::CMatchFinder;
|
||||
m_SetMfPasses = matchFinderSpec;
|
||||
m_MatchFinder = matchFinderSpec;
|
||||
if (m_MatchFinder == 0)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
@@ -149,6 +153,8 @@ HRESULT CCoder::Create()
|
||||
if (!LevelCoder.Create(kLevelTableSize, kLevelDirectBits, kTableDirectLevels, kMaxLevelBitLength))
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
if (m_MatchFinderCycles != 0 && m_SetMfPasses != 0)
|
||||
m_SetMfPasses->SetNumPasses(m_MatchFinderCycles);
|
||||
m_Created = true;
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
@@ -160,13 +166,13 @@ HRESULT CCoder::BaseSetEncoderProperties2(const PROPID *propIDs,
|
||||
{
|
||||
for(UInt32 i = 0; i < numProperties; i++)
|
||||
{
|
||||
const PROPVARIANT &property = properties[i];
|
||||
const PROPVARIANT &prop = properties[i];
|
||||
switch(propIDs[i])
|
||||
{
|
||||
case NCoderPropID::kNumPasses:
|
||||
if (property.vt != VT_UI4)
|
||||
if (prop.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
m_NumDivPasses = property.ulVal;
|
||||
m_NumDivPasses = prop.ulVal;
|
||||
if (m_NumDivPasses == 0)
|
||||
m_NumDivPasses = 1;
|
||||
if (m_NumDivPasses == 1)
|
||||
@@ -180,12 +186,19 @@ HRESULT CCoder::BaseSetEncoderProperties2(const PROPID *propIDs,
|
||||
}
|
||||
break;
|
||||
case NCoderPropID::kNumFastBytes:
|
||||
if (property.vt != VT_UI4)
|
||||
if (prop.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
m_NumFastBytes = property.ulVal;
|
||||
m_NumFastBytes = prop.ulVal;
|
||||
if(m_NumFastBytes < kMatchMinLen || m_NumFastBytes > m_MatchMaxLen)
|
||||
return E_INVALIDARG;
|
||||
break;
|
||||
case NCoderPropID::kMatchFinderCycles:
|
||||
{
|
||||
if (prop.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
m_MatchFinderCycles = prop.ulVal;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
@@ -102,6 +102,9 @@ public:
|
||||
CTables *m_Tables;
|
||||
COptimal m_Optimum[kNumOpts];
|
||||
|
||||
UInt32 m_MatchFinderCycles;
|
||||
IMatchFinderSetNumPasses *m_SetMfPasses;
|
||||
|
||||
void GetMatches();
|
||||
void MovePos(UInt32 num);
|
||||
UInt32 Backward(UInt32 &backRes, UInt32 cur);
|
||||
|
||||
@@ -11,7 +11,8 @@ const UInt32 kMaxValForNormalize = (UInt32(1) << 31) - 1;
|
||||
class CMatchFinder:
|
||||
public IMatchFinder,
|
||||
public CLZInWindow,
|
||||
public CMyUnknownImp
|
||||
public CMyUnknownImp,
|
||||
public IMatchFinderSetNumPasses
|
||||
{
|
||||
UInt32 _cyclicBufferPos;
|
||||
UInt32 _cyclicBufferSize; // it must be historySize + 1
|
||||
@@ -47,7 +48,7 @@ class CMatchFinder:
|
||||
public:
|
||||
CMatchFinder();
|
||||
virtual ~CMatchFinder();
|
||||
void SetCutValue(UInt32 cutValue) { _cutValue = cutValue; }
|
||||
virtual void SetNumPasses(UInt32 numPasses) { _cutValue = numPasses; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -24,4 +24,9 @@ struct IMatchFinder: public IInWindowStream
|
||||
STDMETHOD(Skip)(UInt32 num) PURE;
|
||||
};
|
||||
|
||||
struct IMatchFinderSetNumPasses
|
||||
{
|
||||
virtual void SetNumPasses(UInt32 numPasses) PURE;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -220,6 +220,7 @@ void CEncoder::SetPrices(UInt32 posState, UInt32 numSymbols, UInt32 *prices) con
|
||||
}
|
||||
CEncoder::CEncoder():
|
||||
_numFastBytes(kNumFastBytesDefault),
|
||||
_matchFinderCycles(0),
|
||||
_distTableSize(kDefaultDictionaryLogSize * 2),
|
||||
_posStateBits(2),
|
||||
_posStateMask(4 - 1),
|
||||
@@ -229,6 +230,7 @@ CEncoder::CEncoder():
|
||||
_dictionarySizePrev(UInt32(-1)),
|
||||
_numFastBytesPrev(UInt32(-1)),
|
||||
_matchFinderIndex(kBT4),
|
||||
setMfPasses(0),
|
||||
#ifdef COMPRESS_MF_MT
|
||||
_multiThread(false),
|
||||
#endif
|
||||
@@ -249,25 +251,41 @@ HRESULT CEncoder::Create()
|
||||
#ifdef COMPRESS_MF_BT
|
||||
#ifdef COMPRESS_MF_BT2
|
||||
case kBT2:
|
||||
_matchFinder = new NBT2::CMatchFinder;
|
||||
{
|
||||
NBT2::CMatchFinder *mfSpec = new NBT2::CMatchFinder;
|
||||
setMfPasses = mfSpec;
|
||||
_matchFinder = mfSpec;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef COMPRESS_MF_BT3
|
||||
case kBT3:
|
||||
_matchFinder = new NBT3::CMatchFinder;
|
||||
{
|
||||
NBT3::CMatchFinder *mfSpec = new NBT3::CMatchFinder;
|
||||
setMfPasses = mfSpec;
|
||||
_matchFinder = mfSpec;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef COMPRESS_MF_BT4
|
||||
case kBT4:
|
||||
_matchFinder = new NBT4::CMatchFinder;
|
||||
{
|
||||
NBT4::CMatchFinder *mfSpec = new NBT4::CMatchFinder;
|
||||
setMfPasses = mfSpec;
|
||||
_matchFinder = mfSpec;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef COMPRESS_MF_HC
|
||||
case kHC4:
|
||||
_matchFinder = new NHC4::CMatchFinder;
|
||||
{
|
||||
NHC4::CMatchFinder *mfSpec = new NHC4::CMatchFinder;
|
||||
setMfPasses = mfSpec;
|
||||
_matchFinder = mfSpec;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (_matchFinder == 0)
|
||||
@@ -293,6 +311,8 @@ HRESULT CEncoder::Create()
|
||||
if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes)
|
||||
return S_OK;
|
||||
RINOK(_matchFinder->Create(_dictionarySize, kNumOpts, _numFastBytes, kMatchMaxLen + 1)); // actually it's + _numFastBytes - _numFastBytes
|
||||
if (_matchFinderCycles != 0 && setMfPasses != 0)
|
||||
setMfPasses->SetNumPasses(_matchFinderCycles);
|
||||
_dictionarySizePrev = _dictionarySize;
|
||||
_numFastBytesPrev = _numFastBytes;
|
||||
return S_OK;
|
||||
@@ -340,6 +360,13 @@ STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
|
||||
_numFastBytes = numFastBytes;
|
||||
break;
|
||||
}
|
||||
case NCoderPropID::kMatchFinderCycles:
|
||||
{
|
||||
if (prop.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
_matchFinderCycles = prop.ulVal;
|
||||
break;
|
||||
}
|
||||
case NCoderPropID::kAlgorithm:
|
||||
{
|
||||
if (prop.vt != VT_UI4)
|
||||
@@ -360,8 +387,8 @@ STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
|
||||
_matchFinderIndex = m;
|
||||
if (_matchFinder && matchFinderIndexPrev != _matchFinderIndex)
|
||||
{
|
||||
_dictionarySizePrev = UInt32(-1);
|
||||
_matchFinder.Release();
|
||||
_dictionarySizePrev = (UInt32)-1;
|
||||
ReleaseMatchFinder();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -373,10 +400,23 @@ STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
|
||||
bool newMultiThread = (prop.boolVal == VARIANT_TRUE);
|
||||
if (newMultiThread != _multiThread)
|
||||
{
|
||||
_dictionarySizePrev = UInt32(-1);
|
||||
_matchFinder.Release();
|
||||
_dictionarySizePrev = (UInt32)-1;
|
||||
ReleaseMatchFinder();
|
||||
_multiThread = newMultiThread;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NCoderPropID::kNumThreads:
|
||||
{
|
||||
if (prop.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
bool newMultiThread = (prop.ulVal > 1);
|
||||
if (newMultiThread != _multiThread)
|
||||
{
|
||||
_dictionarySizePrev = (UInt32)-1;
|
||||
ReleaseMatchFinder();
|
||||
_multiThread = newMultiThread;
|
||||
}
|
||||
_multiThread = newMultiThread;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@@ -1219,12 +1259,6 @@ HRESULT CEncoder::GetOptimumFast(UInt32 position, UInt32 &backRes, UInt32 &lenRe
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CEncoder::InitMatchFinder(IMatchFinder *matchFinder)
|
||||
{
|
||||
_matchFinder = matchFinder;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CEncoder::Flush(UInt32 nowPos)
|
||||
{
|
||||
ReleaseMFStream();
|
||||
|
||||
@@ -240,6 +240,7 @@ class CEncoder :
|
||||
bool _finished;
|
||||
ISequentialInStream *_inStream;
|
||||
|
||||
UInt32 _matchFinderCycles;
|
||||
int _matchFinderIndex;
|
||||
#ifdef COMPRESS_MF_MT
|
||||
bool _multiThread;
|
||||
@@ -248,6 +249,14 @@ class CEncoder :
|
||||
bool _writeEndMark;
|
||||
|
||||
bool _needReleaseMFStream;
|
||||
|
||||
IMatchFinderSetNumPasses *setMfPasses;
|
||||
|
||||
void ReleaseMatchFinder()
|
||||
{
|
||||
setMfPasses = 0;
|
||||
_matchFinder.Release();
|
||||
}
|
||||
|
||||
HRESULT ReadMatchDistances(UInt32 &len, UInt32 &numDistancePairs);
|
||||
|
||||
@@ -384,9 +393,6 @@ public:
|
||||
const UInt64 *inSize, const UInt64 *outSize,
|
||||
ICompressProgressInfo *progress);
|
||||
|
||||
// IInitMatchFinder interface
|
||||
STDMETHOD(InitMatchFinder)(IMatchFinder *matchFinder);
|
||||
|
||||
// ICompressSetCoderProperties2
|
||||
STDMETHOD(SetCoderProperties)(const PROPID *propIDs,
|
||||
const PROPVARIANT *properties, UInt32 numProperties);
|
||||
|
||||
@@ -59,6 +59,7 @@ enum Enum
|
||||
kMode,
|
||||
kDictionary,
|
||||
kFastBytes,
|
||||
kMatchFinderCycles,
|
||||
kLitContext,
|
||||
kLitPos,
|
||||
kPosBits,
|
||||
@@ -77,6 +78,7 @@ static const CSwitchForm kSwitchForms[] =
|
||||
{ L"A", NSwitchType::kUnLimitedPostString, false, 1 },
|
||||
{ L"D", NSwitchType::kUnLimitedPostString, false, 1 },
|
||||
{ L"FB", NSwitchType::kUnLimitedPostString, false, 1 },
|
||||
{ L"MC", NSwitchType::kUnLimitedPostString, false, 1 },
|
||||
{ L"LC", NSwitchType::kUnLimitedPostString, false, 1 },
|
||||
{ L"LP", NSwitchType::kUnLimitedPostString, false, 1 },
|
||||
{ L"PB", NSwitchType::kUnLimitedPostString, false, 1 },
|
||||
@@ -99,6 +101,7 @@ static void PrintHelp()
|
||||
" -a{N}: set compression mode - [0, 1], default: 1 (max)\n"
|
||||
" -d{N}: set dictionary - [0,30], default: 23 (8MB)\n"
|
||||
" -fb{N}: set number of fast bytes - [5, 273], default: 128\n"
|
||||
" -mc{N}: set number of cycles for match finder\n"
|
||||
" -lc{N}: set number of literal context bits - [0, 8], default: 3\n"
|
||||
" -lp{N}: set number of literal pos bits - [0, 4], default: 0\n"
|
||||
" -pb{N}: set number of pos bits - [0, 4], default: 2\n"
|
||||
@@ -149,7 +152,7 @@ int main2(int n, const char *args[])
|
||||
g_IsNT = IsItWindowsNT();
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "\nLZMA 4.33 Copyright (c) 1999-2006 Igor Pavlov 2006-02-05\n");
|
||||
fprintf(stderr, "\nLZMA 4.34 Copyright (c) 1999-2006 Igor Pavlov 2006-02-23\n");
|
||||
|
||||
if (n == 1)
|
||||
{
|
||||
@@ -353,6 +356,8 @@ int main2(int n, const char *args[])
|
||||
// UInt32 litPosBits = 2; // for 32-bit data
|
||||
UInt32 algorithm = 2;
|
||||
UInt32 numFastBytes = 128;
|
||||
UInt32 matchFinderCycles = 16 + numFastBytes / 2;
|
||||
bool matchFinderCyclesDefined = false;
|
||||
|
||||
bool eos = parser[NKey::kEOS].ThereIs || stdInMode;
|
||||
|
||||
@@ -363,6 +368,9 @@ int main2(int n, const char *args[])
|
||||
if(parser[NKey::kFastBytes].ThereIs)
|
||||
if (!GetNumber(parser[NKey::kFastBytes].PostStrings[0], numFastBytes))
|
||||
IncorrectCommand();
|
||||
if (matchFinderCyclesDefined = parser[NKey::kMatchFinderCycles].ThereIs)
|
||||
if (!GetNumber(parser[NKey::kMatchFinderCycles].PostStrings[0], matchFinderCycles))
|
||||
IncorrectCommand();
|
||||
if(parser[NKey::kLitContext].ThereIs)
|
||||
if (!GetNumber(parser[NKey::kLitContext].PostStrings[0], litContextBits))
|
||||
IncorrectCommand();
|
||||
@@ -382,9 +390,10 @@ int main2(int n, const char *args[])
|
||||
NCoderPropID::kAlgorithm,
|
||||
NCoderPropID::kNumFastBytes,
|
||||
NCoderPropID::kMatchFinder,
|
||||
NCoderPropID::kEndMarker
|
||||
NCoderPropID::kEndMarker,
|
||||
NCoderPropID::kMatchFinderCycles
|
||||
};
|
||||
const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]);
|
||||
const int kNumPropsMax = sizeof(propIDs) / sizeof(propIDs[0]);
|
||||
/*
|
||||
NWindows::NCOM::CPropVariant properties[kNumProps];
|
||||
properties[0] = UInt32(dictionary);
|
||||
@@ -397,15 +406,19 @@ int main2(int n, const char *args[])
|
||||
properties[6] = mf;
|
||||
properties[7] = eos;
|
||||
*/
|
||||
PROPVARIANT properties[kNumProps];
|
||||
PROPVARIANT properties[kNumPropsMax];
|
||||
for (int p = 0; p < 6; p++)
|
||||
properties[p].vt = VT_UI4;
|
||||
|
||||
properties[0].ulVal = UInt32(dictionary);
|
||||
properties[1].ulVal = UInt32(posStateBits);
|
||||
properties[2].ulVal = UInt32(litContextBits);
|
||||
properties[3].ulVal = UInt32(litPosBits);
|
||||
properties[4].ulVal = UInt32(algorithm);
|
||||
properties[5].ulVal = UInt32(numFastBytes);
|
||||
|
||||
properties[8].vt = VT_UI4;
|
||||
properties[8].ulVal = UInt32(matchFinderCycles);
|
||||
|
||||
properties[6].vt = VT_BSTR;
|
||||
properties[6].bstrVal = (BSTR)(const wchar_t *)mf;
|
||||
@@ -413,7 +426,11 @@ int main2(int n, const char *args[])
|
||||
properties[7].vt = VT_BOOL;
|
||||
properties[7].boolVal = eos ? VARIANT_TRUE : VARIANT_FALSE;
|
||||
|
||||
if (encoderSpec->SetCoderProperties(propIDs, properties, kNumProps) != S_OK)
|
||||
int numProps = kNumPropsMax;
|
||||
if (!matchFinderCyclesDefined)
|
||||
numProps--;
|
||||
|
||||
if (encoderSpec->SetCoderProperties(propIDs, properties, numProps) != S_OK)
|
||||
IncorrectCommand();
|
||||
encoderSpec->WriteCoderProperties(outStream);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user