Files
nsis-plugin-ns7zip/versions/26.00/CPP/7zip/Compress/BZip2Encoder.cpp
T
Simone d074cc7c07 chore: initial commit (extracted from Launchers monorepo)
Plugin: ns7zip v2.0.0
Architectures: x86-ansi, x86-unicode, amd64-unicode
License: LGPL-2.1-or-later
2026-04-29 14:07:51 +02:00

1117 lines
28 KiB
C++

// BZip2Encoder.cpp
#include "StdAfx.h"
#include "../../../C/Alloc.h"
#include "../../../C/BwtSort.h"
#include "../../../C/HuffEnc.h"
#include "BZip2Encoder.h"
namespace NCompress {
namespace NBZip2 {
#define HUFFMAN_LEN 16
#if HUFFMAN_LEN > Z7_HUFFMAN_LEN_MAX
#error Stop_Compiling_Bad_HUFFMAN_LEN_BZip2Encoder
#endif
static const size_t kBufferSize = 1 << 17;
static const unsigned kNumHuffPasses = 4;
bool CThreadInfo::Alloc()
{
if (!m_BlockSorterIndex)
{
m_BlockSorterIndex = (UInt32 *)::BigAlloc(BLOCK_SORT_BUF_SIZE(kBlockSizeMax) * sizeof(UInt32));
if (!m_BlockSorterIndex)
return false;
}
if (!m_Block_Base)
{
const unsigned kPadSize = 1 << 7; // we need at least 1 byte backward padding, becuase we use (m_Block - 1) pointer;
m_Block_Base = (Byte *)::MidAlloc(kBlockSizeMax * 5
+ kBlockSizeMax / 10 + (20 << 10)
+ kPadSize);
if (!m_Block_Base)
return false;
m_Block = m_Block_Base + kPadSize;
m_MtfArray = m_Block + kBlockSizeMax;
m_TempArray = m_MtfArray + kBlockSizeMax * 2 + 2;
}
return true;
}
void CThreadInfo::Free()
{
::BigFree(m_BlockSorterIndex);
m_BlockSorterIndex = NULL;
::MidFree(m_Block_Base);
m_Block_Base = NULL;
}
#ifndef Z7_ST
static THREAD_FUNC_DECL MFThread(void *threadCoderInfo)
{
return ((CThreadInfo *)threadCoderInfo)->ThreadFunc();
}
HRESULT CThreadInfo::Create()
{
WRes wres = StreamWasFinishedEvent.Create();
if (wres == 0) { wres = WaitingWasStartedEvent.Create();
if (wres == 0) { wres = CanWriteEvent.Create();
if (wres == 0)
{
wres =
#ifdef _WIN32
Encoder->_props.NumThreadGroups > 1 ?
Thread.Create_With_Group(MFThread, this, ThreadNextGroup_GetNext(&Encoder->ThreadNextGroup), 0) : // affinity
#endif
Encoder->_props.Affinity != 0 ?
Thread.Create_With_Affinity(MFThread, this, (CAffinityMask)Encoder->_props.Affinity) :
Thread.Create(MFThread, this);
}}}
return HRESULT_FROM_WIN32(wres);
}
void CThreadInfo::FinishStream(bool needLeave)
{
Encoder->StreamWasFinished = true;
StreamWasFinishedEvent.Set();
if (needLeave)
Encoder->CS.Leave();
Encoder->CanStartWaitingEvent.Lock();
WaitingWasStartedEvent.Set();
}
THREAD_FUNC_RET_TYPE CThreadInfo::ThreadFunc()
{
for (;;)
{
Encoder->CanProcessEvent.Lock();
Encoder->CS.Enter();
if (Encoder->CloseThreads)
{
Encoder->CS.Leave();
return 0;
}
if (Encoder->StreamWasFinished)
{
FinishStream(true);
continue;
}
HRESULT res = S_OK;
bool needLeave = true;
try
{
const UInt32 blockSize = Encoder->ReadRleBlock(m_Block);
m_UnpackSize = Encoder->m_InStream.GetProcessedSize();
m_BlockIndex = Encoder->NextBlockIndex;
if (++Encoder->NextBlockIndex == Encoder->NumThreads)
Encoder->NextBlockIndex = 0;
if (blockSize == 0)
{
FinishStream(true);
continue;
}
Encoder->CS.Leave();
needLeave = false;
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(needLeave);
continue;
}
}
}
#endif
void CEncProps::Normalize(int level)
{
if (level < 0) level = 5;
if (level > 9) level = 9;
if (NumPasses == (UInt32)(Int32)-1)
NumPasses = (level >= 9 ? 7 : (level >= 7 ? 2 : 1));
if (NumPasses < 1) NumPasses = 1;
if (NumPasses > kNumPassesMax) NumPasses = kNumPassesMax;
if (BlockSizeMult == (UInt32)(Int32)-1)
BlockSizeMult = (level >= 5 ? 9 : (level >= 1 ? (unsigned)level * 2 - 1: 1));
if (BlockSizeMult < kBlockSizeMultMin) BlockSizeMult = kBlockSizeMultMin;
if (BlockSizeMult > kBlockSizeMultMax) BlockSizeMult = kBlockSizeMultMax;
}
CEncoder::CEncoder()
{
_props.Normalize(-1);
#ifndef Z7_ST
ThreadsInfo = NULL;
m_NumThreadsPrev = 0;
NumThreads = 1;
#endif
}
#ifndef Z7_ST
CEncoder::~CEncoder()
{
Free();
}
HRESULT CEncoder::Create()
{
{
WRes wres = CanProcessEvent.CreateIfNotCreated_Reset();
if (wres == 0) { wres = CanStartWaitingEvent.CreateIfNotCreated_Reset(); }
if (wres != 0)
return HRESULT_FROM_WIN32(wres);
}
if (ThreadsInfo && m_NumThreadsPrev == NumThreads)
return S_OK;
try
{
Free();
MtMode = (NumThreads > 1);
m_NumThreadsPrev = NumThreads;
ThreadsInfo = new CThreadInfo[NumThreads];
if (!ThreadsInfo)
return E_OUTOFMEMORY;
}
catch(...) { return E_OUTOFMEMORY; }
for (UInt32 t = 0; t < NumThreads; t++)
{
CThreadInfo &ti = ThreadsInfo[t];
ti.Encoder = this;
if (MtMode)
{
HRESULT res = ti.Create();
if (res != S_OK)
{
NumThreads = t;
Free();
return res;
}
}
}
return S_OK;
}
void CEncoder::Free()
{
if (!ThreadsInfo)
return;
CloseThreads = true;
CanProcessEvent.Set();
for (UInt32 t = 0; t < NumThreads; t++)
{
CThreadInfo &ti = ThreadsInfo[t];
if (MtMode)
ti.Thread.Wait_Close();
ti.Free();
}
delete []ThreadsInfo;
ThreadsInfo = NULL;
}
#endif
struct CRleEncoder
{
const Byte *_src;
const Byte *_srcLim;
Byte *_dest;
const Byte *_destLim;
Byte _prevByte;
unsigned _numReps;
void Encode();
};
Z7_NO_INLINE
void CRleEncoder::Encode()
{
const Byte *src = _src;
const Byte * const srcLim = _srcLim;
Byte *dest = _dest;
const Byte * const destLim = _destLim;
Byte prev = _prevByte;
unsigned numReps = _numReps;
// (dest < destLim)
// src = srcLim; // for debug
while (dest < destLim)
{
if (src == srcLim)
break;
const Byte b = *src++;
if (b != prev)
{
if (numReps >= kRleModeRepSize)
*dest++ = (Byte)(numReps - kRleModeRepSize);
*dest++ = b;
numReps = 1;
prev = b;
/*
{ // speed optimization code:
if (dest >= destLim || src == srcLim)
break;
const Byte b2 = *src++;
*dest++ = b2;
numReps += (prev == b2);
prev = b2;
}
*/
continue;
}
numReps++;
if (numReps <= kRleModeRepSize)
*dest++ = b;
else if (numReps == kRleModeRepSize + 255)
{
*dest++ = (Byte)(numReps - kRleModeRepSize);
numReps = 0;
}
}
_src = src;
_dest = dest;
_prevByte = prev;
_numReps = numReps;
// (dest <= destLim + 1)
}
// out: return value is blockSize: size of data filled in buffer[]:
// (returned_blockSize <= _props.BlockSizeMult * kBlockSizeStep)
UInt32 CEncoder::ReadRleBlock(Byte *buffer)
{
CRleEncoder rle;
UInt32 i = 0;
if (m_InStream.ReadByte(rle._prevByte))
{
NumBlocks++;
const UInt32 blockSize = _props.BlockSizeMult * kBlockSizeStep - 1; // -1 for RLE
rle._destLim = buffer + blockSize;
rle._numReps = 1;
buffer[i++] = rle._prevByte;
while (i < blockSize)
{
rle._dest = buffer + i;
size_t rem;
const Byte * const ptr = m_InStream.Lookahead(rem);
if (rem == 0)
break;
rle._src = ptr;
rle._srcLim = ptr + rem;
rle.Encode();
m_InStream.Skip((size_t)(rle._src - ptr));
i = (UInt32)(size_t)(rle._dest - buffer);
// (i <= blockSize + 1)
}
const int n = (int)rle._numReps - (int)kRleModeRepSize;
if (n >= 0)
buffer[i++] = (Byte)n;
}
return i;
}
Z7_NO_INLINE
void CThreadInfo::WriteBits2(UInt32 value, unsigned numBits)
{ m_OutStreamCurrent.WriteBits(value, numBits); }
/*
Z7_NO_INLINE
void CThreadInfo::WriteByte2(unsigned b)
{ m_OutStreamCurrent.WriteByte(b); }
*/
// void CEncoder::WriteBits(UInt32 value, unsigned numBits) { m_OutStream.WriteBits(value, numBits); }
Z7_NO_INLINE
void CEncoder::WriteByte(Byte b) { m_OutStream.WriteByte(b); }
#define WRITE_BITS_UPDATE(value, numBits) \
{ \
numBits -= _bitPos; \
const UInt32 hi = value >> numBits; \
*_buf++ = (Byte)(_curByte | hi); \
value -= hi << numBits; \
_bitPos = 8; \
_curByte = 0; \
}
#if HUFFMAN_LEN > 16
#define WRITE_BITS_HUFF(value2, numBits2) \
{ \
UInt32 value = value2; \
unsigned numBits = numBits2; \
while (numBits >= _bitPos) { \
WRITE_BITS_UPDATE(value, numBits) \
} \
_bitPos -= numBits; \
_curByte |= (value << _bitPos); \
}
#else // HUFFMAN_LEN <= 16
// numBits2 <= 16 is supported
#define WRITE_BITS_HUFF(value2, numBits2) \
{ \
UInt32 value = value2; \
unsigned numBits = numBits2; \
if (numBits >= _bitPos) \
{ \
WRITE_BITS_UPDATE(value, numBits) \
if (numBits >= _bitPos) \
{ \
numBits -= _bitPos; \
const UInt32 hi = value >> numBits; \
*_buf++ = (Byte)hi; \
value -= hi << numBits; \
} \
} \
_bitPos -= numBits; \
_curByte |= (value << _bitPos); \
}
#endif
#define WRITE_BITS_8(value2, numBits2) \
{ \
UInt32 value = value2; \
unsigned numBits = numBits2; \
if (numBits >= _bitPos) \
{ \
WRITE_BITS_UPDATE(value, numBits) \
} \
_bitPos -= numBits; \
_curByte |= (value << _bitPos); \
}
#define WRITE_BIT_PRE \
{ _bitPos--; }
#define WRITE_BIT_POST \
{ \
if (_bitPos == 0) \
{ \
*_buf++ = (Byte)_curByte; \
_curByte = 0; \
_bitPos = 8; \
} \
}
#define WRITE_BIT_0 \
{ \
WRITE_BIT_PRE \
WRITE_BIT_POST \
}
#define WRITE_BIT_1 \
{ \
WRITE_BIT_PRE \
_curByte |= 1u << _bitPos; \
WRITE_BIT_POST \
}
// blockSize > 0
void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
{
// WriteBit2(0); // Randomised = false
{
const UInt32 origPtr = BlockSort(m_BlockSorterIndex, block, blockSize);
// if (m_BlockSorterIndex[origPtr] != 0) throw 1;
m_BlockSorterIndex[origPtr] = blockSize;
WriteBits2(origPtr, kNumOrigBits + 1); // + 1 for additional high bit flag (Randomised = false)
}
Byte mtfBuf[256];
// memset(mtfBuf, 0, sizeof(mtfBuf)); // to disable MSVC warning
unsigned numInUse;
{
Byte inUse[256];
Byte inUse16[16];
unsigned i;
for (i = 0; i < 256; i++)
inUse[i] = 0;
for (i = 0; i < 16; i++)
inUse16[i] = 0;
{
const Byte * cur = block;
block = block + (size_t)blockSize - 1;
if (cur != block)
{
do
{
const unsigned b0 = cur[0];
const unsigned b1 = cur[1];
cur += 2;
inUse[b0] = 1;
inUse[b1] = 1;
}
while (cur < block);
}
if (cur == block)
inUse[cur[0]] = 1;
block -= blockSize; // block pointer is (original_block - 1)
}
numInUse = 0;
for (i = 0; i < 256; i++)
if (inUse[i])
{
inUse16[i >> 4] = 1;
mtfBuf[numInUse++] = (Byte)i;
}
for (i = 0; i < 16; i++)
WriteBit2(inUse16[i]);
for (i = 0; i < 256; i++)
if (inUse16[i >> 4])
WriteBit2(inUse[i]);
}
const unsigned alphaSize = numInUse + 2;
UInt32 symbolCounts[kMaxAlphaSize];
{
for (unsigned i = 0; i < kMaxAlphaSize; i++)
symbolCounts[i] = 0;
symbolCounts[(size_t)alphaSize - 1] = 1;
}
Byte *mtfs = m_MtfArray;
{
const UInt32 *bsIndex = m_BlockSorterIndex;
const UInt32 *bsIndex_rle = bsIndex;
const UInt32 * const bsIndex_end = bsIndex + blockSize;
// block--; // backward fix
// block pointer is (original_block - 1)
do
{
const Byte v = block[*bsIndex++];
Byte a = mtfBuf[0];
if (v != a)
{
mtfBuf[0] = v;
{
UInt32 rleSize = (UInt32)(size_t)(bsIndex - bsIndex_rle) - 1;
bsIndex_rle = bsIndex;
while (rleSize)
{
const unsigned sym = (unsigned)(--rleSize & 1);
*mtfs++ = (Byte)sym;
symbolCounts[sym]++;
rleSize >>= 1;
}
}
unsigned pos1 = 2; // = real_pos + 1
Byte b;
b = mtfBuf[1]; mtfBuf[1] = a; if (v != b)
{ a = mtfBuf[2]; mtfBuf[2] = b; if (v == a) pos1 = 3;
else { b = mtfBuf[3]; mtfBuf[3] = a; if (v == b) pos1 = 4;
else
{
Byte *m = mtfBuf + 7;
for (;;)
{
a = m[-3]; m[-3] = b; if (v == a) { pos1 = (unsigned)(size_t)(m - (mtfBuf + 2)); break; }
b = m[-2]; m[-2] = a; if (v == b) { pos1 = (unsigned)(size_t)(m - (mtfBuf + 1)); break; }
a = m[-1]; m[-1] = b; if (v == a) { pos1 = (unsigned)(size_t)(m - (mtfBuf )); break; }
b = m[ 0]; m[ 0] = a; m += 4; if (v == b) { pos1 = (unsigned)(size_t)(m - (mtfBuf + 3)); break; }
}
}}}
symbolCounts[pos1]++;
if (pos1 >= 0xff)
{
*mtfs++ = 0xff;
// pos1 -= 0xff;
pos1++; // we need only low byte
}
*mtfs++ = (Byte)pos1;
}
}
while (bsIndex < bsIndex_end);
UInt32 rleSize = (UInt32)(size_t)(bsIndex - bsIndex_rle);
while (rleSize)
{
const unsigned sym = (unsigned)(--rleSize & 1);
*mtfs++ = (Byte)sym;
symbolCounts[sym]++;
rleSize >>= 1;
}
unsigned d = alphaSize - 1;
if (alphaSize >= 256)
{
*mtfs++ = 0xff;
d = alphaSize; // (-256)
}
*mtfs++ = (Byte)d;
}
const Byte * const mtf_lim = mtfs;
UInt32 numSymbols = 0;
{
for (unsigned i = 0; i < kMaxAlphaSize; i++)
numSymbols += symbolCounts[i];
}
unsigned bestNumTables = kNumTablesMin;
UInt32 bestPrice = 0xFFFFFFFF;
const UInt32 startPos = m_OutStreamCurrent.GetPos();
const unsigned startCurByte = m_OutStreamCurrent.GetCurByte();
for (unsigned nt = kNumTablesMin; nt <= kNumTablesMax + 1; nt++)
{
unsigned numTables;
if (m_OptimizeNumTables)
{
m_OutStreamCurrent.SetPos(startPos);
m_OutStreamCurrent.SetCurState(startPos & 7, startCurByte);
numTables = (nt <= kNumTablesMax ? nt : bestNumTables);
}
else
{
if (numSymbols < 200) numTables = 2;
else if (numSymbols < 600) numTables = 3;
else if (numSymbols < 1200) numTables = 4;
else if (numSymbols < 2400) numTables = 5;
else numTables = 6;
}
WriteBits2(numTables, kNumTablesBits);
const unsigned numSelectors = (numSymbols + kGroupSize - 1) / kGroupSize;
WriteBits2((UInt32)numSelectors, kNumSelectorsBits);
{
UInt32 remFreq = numSymbols;
unsigned gs = 0;
unsigned t = numTables;
do
{
UInt32 tFreq = remFreq / t;
unsigned ge = gs;
UInt32 aFreq = 0;
while (aFreq < tFreq) // && ge < alphaSize)
aFreq += symbolCounts[ge++];
if (ge > gs + 1 && t != numTables && t != 1 && (((numTables - t) & 1) == 1))
aFreq -= symbolCounts[--ge];
Byte *lens = Lens[(size_t)t - 1];
unsigned i = 0;
do
lens[i] = (Byte)((i >= gs && i < ge) ? 0 : 1);
while (++i < alphaSize);
gs = ge;
remFreq -= aFreq;
}
while (--t != 0);
}
for (unsigned pass = 0; pass < kNumHuffPasses; pass++)
{
memset(Freqs, 0, sizeof(Freqs[0]) * numTables);
// memset(Freqs, 0, sizeof(Freqs));
{
mtfs = m_MtfArray;
UInt32 g = 0;
do
{
unsigned symbols[kGroupSize];
unsigned i = 0;
do
{
UInt32 symbol = *mtfs++;
if (symbol >= 0xFF)
symbol += *mtfs++;
symbols[i] = symbol;
}
while (++i < kGroupSize && mtfs < mtf_lim);
UInt32 bestPrice2 = 0xFFFFFFFF;
unsigned t = 0;
do
{
const Byte *lens = Lens[t];
UInt32 price = 0;
unsigned j = 0;
do
price += lens[symbols[j]];
while (++j < i);
if (price < bestPrice2)
{
m_Selectors[g] = (Byte)t;
bestPrice2 = price;
}
}
while (++t < numTables);
UInt32 *freqs = Freqs[m_Selectors[g++]];
unsigned j = 0;
do
freqs[symbols[j]]++;
while (++j < i);
}
while (mtfs < mtf_lim);
}
unsigned t = 0;
do
{
UInt32 *freqs = Freqs[t];
unsigned i = 0;
do
if (freqs[i] == 0)
freqs[i] = 1;
while (++i < alphaSize);
Huffman_Generate(freqs, Codes[t], Lens[t], kMaxAlphaSize, HUFFMAN_LEN);
}
while (++t < numTables);
}
unsigned _bitPos; // 0 < _bitPos <= 8 : number of non-filled low bits in _curByte
unsigned _curByte; // low (_bitPos) bits are zeros
// high (8 - _bitPos) bits are filled
Byte *_buf;
{
Byte mtfSel[kNumTablesMax];
{
unsigned t = 0;
do
mtfSel[t] = (Byte)t;
while (++t < numTables);
}
_bitPos = m_OutStreamCurrent._bitPos;
_curByte = m_OutStreamCurrent._curByte;
_buf = m_OutStreamCurrent._buf;
// stream.Init_from_Global(m_OutStreamCurrent);
const Byte *selectors = m_Selectors;
const Byte * const selectors_lim = selectors + numSelectors;
Byte prev = 0; // mtfSel[0];
do
{
const Byte sel = *selectors++;
if (prev != sel)
{
Byte *mtfSel_cur = &mtfSel[1];
for (;;)
{
WRITE_BIT_1
const Byte next = *mtfSel_cur;
*mtfSel_cur++ = prev;
prev = next;
if (next == sel)
break;
}
// mtfSel[0] = sel;
}
WRITE_BIT_0
}
while (selectors != selectors_lim);
}
{
unsigned t = 0;
do
{
const Byte *lens = Lens[t];
unsigned len = lens[0];
WRITE_BITS_8(len, kNumLevelsBits)
unsigned i = 0;
do
{
const unsigned level = lens[i];
while (len != level)
{
WRITE_BIT_1
if (len < level)
{
len++;
WRITE_BIT_0
}
else
{
len--;
WRITE_BIT_1
}
}
WRITE_BIT_0
}
while (++i < alphaSize);
}
while (++t < numTables);
}
{
UInt32 groupSize = 1;
const Byte *selectors = m_Selectors;
const Byte *lens = NULL;
const UInt32 *codes = NULL;
mtfs = m_MtfArray;
do
{
unsigned symbol = *mtfs++;
if (symbol >= 0xFF)
symbol += *mtfs++;
if (--groupSize == 0)
{
groupSize = kGroupSize;
const unsigned t = *selectors++;
lens = Lens[t];
codes = Codes[t];
}
WRITE_BITS_HUFF(codes[symbol], lens[symbol])
}
while (mtfs < mtf_lim);
}
// Restore_from_Local:
m_OutStreamCurrent._bitPos = _bitPos;
m_OutStreamCurrent._curByte = _curByte;
m_OutStreamCurrent._buf = _buf;
if (!m_OptimizeNumTables)
break;
const UInt32 price = m_OutStreamCurrent.GetPos() - startPos;
if (price <= bestPrice)
{
if (nt == kNumTablesMax)
break;
bestPrice = price;
bestNumTables = nt;
}
}
}
// blockSize > 0
UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize)
{
WriteByte2(kBlockSig0);
WriteByte2(kBlockSig1);
WriteByte2(kBlockSig2);
WriteByte2(kBlockSig3);
WriteByte2(kBlockSig4);
WriteByte2(kBlockSig5);
CBZip2Crc crc;
const Byte * const lim = block + blockSize;
unsigned b = *block++;
crc.UpdateByte(b);
for (;;)
{
const unsigned prev = b;
if (block >= lim) { break; } b = *block++; crc.UpdateByte(b); if (prev != b) continue;
if (block >= lim) { break; } b = *block++; crc.UpdateByte(b); if (prev != b) continue;
if (block >= lim) { break; } b = *block++; crc.UpdateByte(b); if (prev != b) continue;
if (block >= lim) { break; } b = *block++; if (b) do crc.UpdateByte(prev); while (--b);
if (block >= lim) { break; } b = *block++; crc.UpdateByte(b);
}
const UInt32 crcRes = crc.GetDigest();
for (int i = 24; i >= 0; i -= 8)
WriteByte2((Byte)(crcRes >> i));
EncodeBlock(lim - blockSize, blockSize);
return crcRes;
}
void CThreadInfo::EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses)
{
const UInt32 numCrcs = m_NumCrcs;
const UInt32 startBytePos = m_OutStreamCurrent.GetBytePos();
const UInt32 startPos = m_OutStreamCurrent.GetPos();
const unsigned startCurByte = m_OutStreamCurrent.GetCurByte();
unsigned endCurByte = 0;
UInt32 endPos = 0; // 0 means no no additional passes
if (numPasses > 1 && blockSize >= (1 << 10))
{
UInt32 bs0 = blockSize / 2;
for (; bs0 < blockSize &&
(block[ bs0 ] ==
block[(size_t)bs0 - 1] ||
block[(size_t)bs0 - 1] ==
block[(size_t)bs0 - 2]);
bs0++)
{}
if (bs0 < blockSize)
{
EncodeBlock2(block, bs0, numPasses - 1);
EncodeBlock2(block + bs0, blockSize - bs0, numPasses - 1);
endPos = m_OutStreamCurrent.GetPos();
endCurByte = m_OutStreamCurrent.GetCurByte();
// we prepare next byte as identical byte to starting byte for main encoding attempt:
if (endPos & 7)
WriteBits2(0, 8 - (endPos & 7));
m_OutStreamCurrent.SetCurState((startPos & 7), startCurByte);
}
}
const UInt32 startBytePos2 = m_OutStreamCurrent.GetBytePos();
const UInt32 startPos2 = m_OutStreamCurrent.GetPos();
const UInt32 crcVal = EncodeBlockWithHeaders(block, blockSize);
if (endPos)
{
const UInt32 size2 = m_OutStreamCurrent.GetPos() - startPos2;
if (size2 >= endPos - startPos)
{
m_OutStreamCurrent.SetPos(endPos);
m_OutStreamCurrent.SetCurState((endPos & 7), endCurByte);
return;
}
const UInt32 numBytes = m_OutStreamCurrent.GetBytePos() - startBytePos2;
Byte * const buffer = m_OutStreamCurrent.GetStream();
memmove(buffer + startBytePos, buffer + startBytePos2, numBytes);
m_OutStreamCurrent.SetPos(startPos + size2);
// we don't call m_OutStreamCurrent.SetCurState() here because
// m_OutStreamCurrent._curByte is correct already
}
m_CRCs[numCrcs] = crcVal;
m_NumCrcs = numCrcs + 1;
}
HRESULT CThreadInfo::EncodeBlock3(UInt32 blockSize)
{
CMsbfEncoderTemp &outStreamTemp = m_OutStreamCurrent;
outStreamTemp.SetStream(m_TempArray);
outStreamTemp.Init();
m_NumCrcs = 0;
EncodeBlock2(m_Block, blockSize, Encoder->_props.NumPasses);
#ifndef Z7_ST
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.GetNonFlushedByteBits());
HRESULT res = S_OK;
#ifndef Z7_ST
if (Encoder->MtMode)
{
UInt32 blockIndex = m_BlockIndex + 1;
if (blockIndex == Encoder->NumThreads)
blockIndex = 0;
if (Encoder->Progress)
{
const UInt64 packSize = Encoder->m_OutStream.GetProcessedSize();
res = Encoder->Progress->SetRatioInfo(&m_UnpackSize, &packSize);
}
Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set();
}
#endif
return res;
}
void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, unsigned lastByteBits)
{
m_OutStream.WriteBytes(data, sizeInBits >> 3);
sizeInBits &= 7;
if (sizeInBits)
m_OutStream.WriteBits(lastByteBits, sizeInBits);
}
HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
{
NumBlocks = 0;
#ifndef Z7_ST
Progress = progress;
ThreadNextGroup_Init(&ThreadNextGroup, _props.NumThreadGroups, 0); // startGroup
RINOK(Create())
for (UInt32 t = 0; t < NumThreads; t++)
#endif
{
#ifndef Z7_ST
CThreadInfo &ti = ThreadsInfo[t];
if (MtMode)
{
WRes wres = ti.StreamWasFinishedEvent.Reset();
if (wres == 0) { wres = ti.WaitingWasStartedEvent.Reset();
if (wres == 0) { wres = ti.CanWriteEvent.Reset(); }}
if (wres != 0)
return HRESULT_FROM_WIN32(wres);
}
#else
CThreadInfo &ti = ThreadsInfo;
ti.Encoder = this;
#endif
ti.m_OptimizeNumTables = _props.DoOptimizeNumTables();
if (!ti.Alloc())
return E_OUTOFMEMORY;
}
if (!m_InStream.Create(kBufferSize))
return E_OUTOFMEMORY;
if (!m_OutStream.Create(kBufferSize))
return E_OUTOFMEMORY;
m_InStream.SetStream(inStream);
m_InStream.Init();
m_OutStream.SetStream(outStream);
m_OutStream.Init();
CombinedCrc.Init();
#ifndef Z7_ST
NextBlockIndex = 0;
StreamWasFinished = false;
CloseThreads = false;
CanStartWaitingEvent.Reset();
#endif
WriteByte(kArSig0);
WriteByte(kArSig1);
WriteByte(kArSig2);
WriteByte((Byte)(kArSig3 + _props.BlockSizeMult));
#ifndef Z7_ST
if (MtMode)
{
ThreadsInfo[0].CanWriteEvent.Set();
Result = S_OK;
CanProcessEvent.Set();
UInt32 t;
for (t = 0; t < NumThreads; t++)
ThreadsInfo[t].StreamWasFinishedEvent.Lock();
CanProcessEvent.Reset();
CanStartWaitingEvent.Set();
for (t = 0; t < NumThreads; t++)
ThreadsInfo[t].WaitingWasStartedEvent.Lock();
CanStartWaitingEvent.Reset();
RINOK(Result)
}
else
#endif
{
for (;;)
{
CThreadInfo &ti =
#ifndef Z7_ST
ThreadsInfo[0];
#else
ThreadsInfo;
#endif
const UInt32 blockSize = ReadRleBlock(ti.m_Block);
if (blockSize == 0)
break;
RINOK(ti.EncodeBlock3(blockSize))
if (progress)
{
const UInt64 unpackSize = m_InStream.GetProcessedSize();
const UInt64 packSize = m_OutStream.GetProcessedSize();
RINOK(progress->SetRatioInfo(&unpackSize, &packSize))
}
}
}
WriteByte(kFinSig0);
WriteByte(kFinSig1);
WriteByte(kFinSig2);
WriteByte(kFinSig3);
WriteByte(kFinSig4);
WriteByte(kFinSig5);
{
const UInt32 v = CombinedCrc.GetDigest();
for (int i = 24; i >= 0; i -= 8)
WriteByte((Byte)(v >> i));
}
RINOK(Flush())
if (!m_InStream.WasFinished())
return E_FAIL;
return S_OK;
}
Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, 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; }
}
Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps))
{
int level = -1;
CEncProps props;
for (UInt32 i = 0; i < numProps; i++)
{
const PROPVARIANT &prop = coderProps[i];
const PROPID propID = propIDs[i];
if (propID == NCoderPropID::kAffinity)
{
if (prop.vt != VT_UI8)
return E_INVALIDARG;
props.Affinity = prop.uhVal.QuadPart;
continue;
}
if (propID == NCoderPropID::kNumThreadGroups)
{
if (prop.vt != VT_UI4)
return E_INVALIDARG;
props.NumThreadGroups = (UInt32)prop.ulVal;
continue;
}
if (propID >= NCoderPropID::kReduceSize)
continue;
if (prop.vt != VT_UI4)
return E_INVALIDARG;
const UInt32 v = (UInt32)prop.ulVal;
switch (propID)
{
case NCoderPropID::kNumPasses: props.NumPasses = v; break;
case NCoderPropID::kDictionarySize: props.BlockSizeMult = v / kBlockSizeStep; break;
case NCoderPropID::kLevel: level = (int)v; break;
case NCoderPropID::kNumThreads:
{
#ifndef Z7_ST
SetNumberOfThreads(v);
#endif
break;
}
default: return E_INVALIDARG;
}
}
props.Normalize(level);
_props = props;
return S_OK;
}
#ifndef Z7_ST
Z7_COM7F_IMF(CEncoder::SetNumberOfThreads(UInt32 numThreads))
{
const UInt32 kNumThreadsMax = 64;
if (numThreads < 1) numThreads = 1;
if (numThreads > kNumThreadsMax) numThreads = kNumThreadsMax;
NumThreads = numThreads;
return S_OK;
}
#endif
}}