diff options
Diffstat (limited to 'src/libs/3rdparty/7zip/unix/CPP/7zip/Compress/Bcj2Coder.cpp')
-rw-r--r-- | src/libs/3rdparty/7zip/unix/CPP/7zip/Compress/Bcj2Coder.cpp | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/Compress/Bcj2Coder.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/Compress/Bcj2Coder.cpp new file mode 100644 index 000000000..9da6b9c28 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/Compress/Bcj2Coder.cpp @@ -0,0 +1,366 @@ +// Bcj2Coder.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "Bcj2Coder.h" + +namespace NCompress { +namespace NBcj2 { + +inline bool IsJcc(Byte b0, Byte b1) { return (b0 == 0x0F && (b1 & 0xF0) == 0x80); } +inline bool IsJ(Byte b0, Byte b1) { return ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1)); } +inline unsigned GetIndex(Byte b0, Byte b1) { return ((b1 == 0xE8) ? b0 : ((b1 == 0xE9) ? 256 : 257)); } + +#ifndef EXTRACT_ONLY + +static const unsigned kBufSize = 1 << 17; + +#define NUM_BITS 2 +#define SIGN_BIT (1 << NUM_BITS) +#define MASK_HIGH (0x100 - (1 << (NUM_BITS + 1))) + +static const UInt32 kDefaultLimit = (1 << (24 + NUM_BITS)); + +static bool inline Test86MSByte(Byte b) +{ + return (((b) + SIGN_BIT) & MASK_HIGH) == 0; +} + +CEncoder::~CEncoder() +{ + ::MidFree(_buf); +} + +HRESULT CEncoder::Flush() +{ + RINOK(_mainStream.Flush()); + RINOK(_callStream.Flush()); + RINOK(_jumpStream.Flush()); + _rc.FlushData(); + return _rc.FlushStream(); +} + +HRESULT CEncoder::CodeReal(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, + ISequentialOutStream **outStreams, const UInt64 ** /* outSizes */, UInt32 numOutStreams, + ICompressProgressInfo *progress) +{ + if (numInStreams != 1 || numOutStreams != 4) + return E_INVALIDARG; + + if (!_mainStream.Create(1 << 18)) return E_OUTOFMEMORY; + if (!_callStream.Create(1 << 18)) return E_OUTOFMEMORY; + if (!_jumpStream.Create(1 << 18)) return E_OUTOFMEMORY; + if (!_rc.Create(1 << 20)) return E_OUTOFMEMORY; + if (_buf == 0) + { + _buf = (Byte *)MidAlloc(kBufSize); + if (_buf == 0) + return E_OUTOFMEMORY; + } + + bool sizeIsDefined = false; + UInt64 inSize = 0; + if (inSizes) + if (inSizes[0]) + { + inSize = *inSizes[0]; + if (inSize <= kDefaultLimit) + sizeIsDefined = true; + } + + ISequentialInStream *inStream = inStreams[0]; + + _mainStream.SetStream(outStreams[0]); _mainStream.Init(); + _callStream.SetStream(outStreams[1]); _callStream.Init(); + _jumpStream.SetStream(outStreams[2]); _jumpStream.Init(); + _rc.SetStream(outStreams[3]); _rc.Init(); + for (unsigned i = 0; i < 256 + 2; i++) + _statusEncoder[i].Init(); + + CMyComPtr<ICompressGetSubStreamSize> getSubStreamSize; + { + inStream->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize); + } + + UInt32 nowPos = 0; + UInt64 nowPos64 = 0; + UInt32 bufPos = 0; + + Byte prevByte = 0; + + UInt64 subStreamIndex = 0; + UInt64 subStreamStartPos = 0; + UInt64 subStreamEndPos = 0; + + for (;;) + { + UInt32 processedSize = 0; + for (;;) + { + UInt32 size = kBufSize - (bufPos + processedSize); + UInt32 processedSizeLoc; + if (size == 0) + break; + RINOK(inStream->Read(_buf + bufPos + processedSize, size, &processedSizeLoc)); + if (processedSizeLoc == 0) + break; + processedSize += processedSizeLoc; + } + UInt32 endPos = bufPos + processedSize; + + if (endPos < 5) + { + // change it + for (bufPos = 0; bufPos < endPos; bufPos++) + { + Byte b = _buf[bufPos]; + _mainStream.WriteByte(b); + UInt32 index; + if (b == 0xE8) + index = prevByte; + else if (b == 0xE9) + index = 256; + else if (IsJcc(prevByte, b)) + index = 257; + else + { + prevByte = b; + continue; + } + _statusEncoder[index].Encode(&_rc, 0); + prevByte = b; + } + return Flush(); + } + + bufPos = 0; + + UInt32 limit = endPos - 5; + while (bufPos <= limit) + { + Byte b = _buf[bufPos]; + _mainStream.WriteByte(b); + if (!IsJ(prevByte, b)) + { + bufPos++; + prevByte = b; + continue; + } + Byte nextByte = _buf[bufPos + 4]; + UInt32 src = + (UInt32(nextByte) << 24) | + (UInt32(_buf[bufPos + 3]) << 16) | + (UInt32(_buf[bufPos + 2]) << 8) | + (_buf[bufPos + 1]); + UInt32 dest = (nowPos + bufPos + 5) + src; + // if (Test86MSByte(nextByte)) + bool convert; + if (getSubStreamSize) + { + UInt64 currentPos = (nowPos64 + bufPos); + while (subStreamEndPos < currentPos) + { + UInt64 subStreamSize; + HRESULT result = getSubStreamSize->GetSubStreamSize(subStreamIndex, &subStreamSize); + if (result == S_OK) + { + subStreamStartPos = subStreamEndPos; + subStreamEndPos += subStreamSize; + subStreamIndex++; + } + else if (result == S_FALSE || result == E_NOTIMPL) + { + getSubStreamSize.Release(); + subStreamStartPos = 0; + subStreamEndPos = subStreamStartPos - 1; + } + else + return result; + } + if (getSubStreamSize == NULL) + { + if (sizeIsDefined) + convert = (dest < inSize); + else + convert = Test86MSByte(nextByte); + } + else if (subStreamEndPos - subStreamStartPos > kDefaultLimit) + convert = Test86MSByte(nextByte); + else + { + UInt64 dest64 = (currentPos + 5) + Int64(Int32(src)); + convert = (dest64 >= subStreamStartPos && dest64 < subStreamEndPos); + } + } + else if (sizeIsDefined) + convert = (dest < inSize); + else + convert = Test86MSByte(nextByte); + unsigned index = GetIndex(prevByte, b); + if (convert) + { + _statusEncoder[index].Encode(&_rc, 1); + bufPos += 5; + COutBuffer &s = (b == 0xE8) ? _callStream : _jumpStream; + for (int i = 24; i >= 0; i -= 8) + s.WriteByte((Byte)(dest >> i)); + prevByte = nextByte; + } + else + { + _statusEncoder[index].Encode(&_rc, 0); + bufPos++; + prevByte = b; + } + } + nowPos += bufPos; + nowPos64 += bufPos; + + if (progress) + { + /* + const UInt64 compressedSize = + _mainStream.GetProcessedSize() + + _callStream.GetProcessedSize() + + _jumpStream.GetProcessedSize() + + _rc.GetProcessedSize(); + */ + RINOK(progress->SetRatioInfo(&nowPos64, NULL)); + } + + UInt32 i = 0; + while (bufPos < endPos) + _buf[i++] = _buf[bufPos++]; + bufPos = i; + } +} + +STDMETHODIMP CEncoder::Code(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, + ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams, + ICompressProgressInfo *progress) +{ + try + { + return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress); + } + catch(const COutBufferException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + +#endif + + +STDMETHODIMP CDecoder::SetInBufSize(UInt32 streamIndex, UInt32 size) { _inBufSizes[streamIndex] = size; return S_OK; } +STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outBufSize = size; return S_OK; } + +CDecoder::CDecoder(): + _outBufSize(1 << 16) +{ + _inBufSizes[0] = 1 << 20; + _inBufSizes[1] = 1 << 20; + _inBufSizes[2] = 1 << 20; + _inBufSizes[3] = 1 << 20; +} + +HRESULT CDecoder::CodeReal(ISequentialInStream **inStreams, const UInt64 ** /* inSizes */, UInt32 numInStreams, + ISequentialOutStream **outStreams, const UInt64 ** /* outSizes */, UInt32 numOutStreams, + ICompressProgressInfo *progress) +{ + if (numInStreams != 4 || numOutStreams != 1) + return E_INVALIDARG; + + if (!_mainStream.Create(_inBufSizes[0])) return E_OUTOFMEMORY; + if (!_callStream.Create(_inBufSizes[1])) return E_OUTOFMEMORY; + if (!_jumpStream.Create(_inBufSizes[2])) return E_OUTOFMEMORY; + if (!_rc.Create(_inBufSizes[3])) return E_OUTOFMEMORY; + if (!_outStream.Create(_outBufSize)) return E_OUTOFMEMORY; + + _mainStream.SetStream(inStreams[0]); + _callStream.SetStream(inStreams[1]); + _jumpStream.SetStream(inStreams[2]); + _rc.SetStream(inStreams[3]); + _outStream.SetStream(outStreams[0]); + + _mainStream.Init(); + _callStream.Init(); + _jumpStream.Init(); + _rc.Init(); + _outStream.Init(); + + for (unsigned i = 0; i < 256 + 2; i++) + _statusDecoder[i].Init(); + + Byte prevByte = 0; + UInt32 processedBytes = 0; + for (;;) + { + if (processedBytes >= (1 << 20) && progress) + { + /* + const UInt64 compressedSize = + _mainStream.GetProcessedSize() + + _callStream.GetProcessedSize() + + _jumpStream.GetProcessedSize() + + _rc.GetProcessedSize(); + */ + const UInt64 nowPos64 = _outStream.GetProcessedSize(); + RINOK(progress->SetRatioInfo(NULL, &nowPos64)); + processedBytes = 0; + } + UInt32 i; + Byte b = 0; + const UInt32 kBurstSize = (1 << 18); + for (i = 0; i < kBurstSize; i++) + { + if (!_mainStream.ReadByte(b)) + return _outStream.Flush(); + _outStream.WriteByte(b); + if (IsJ(prevByte, b)) + break; + prevByte = b; + } + processedBytes += i; + if (i == kBurstSize) + continue; + unsigned index = GetIndex(prevByte, b); + if (_statusDecoder[index].Decode(&_rc) == 1) + { + UInt32 src = 0; + CInBuffer &s = (b == 0xE8) ? _callStream : _jumpStream; + for (unsigned i = 0; i < 4; i++) + { + Byte b0; + if (!s.ReadByte(b0)) + return S_FALSE; + src <<= 8; + src |= ((UInt32)b0); + } + UInt32 dest = src - (UInt32(_outStream.GetProcessedSize()) + 4) ; + _outStream.WriteByte((Byte)(dest)); + _outStream.WriteByte((Byte)(dest >> 8)); + _outStream.WriteByte((Byte)(dest >> 16)); + _outStream.WriteByte((Byte)(dest >> 24)); + prevByte = (Byte)(dest >> 24); + processedBytes += 4; + } + else + prevByte = b; + } +} + +STDMETHODIMP CDecoder::Code(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams, + ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams, + ICompressProgressInfo *progress) +{ + try + { + return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress); + } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const COutBufferException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + +}} |