| // ArjDecoder2.cpp |
| |
| #include "StdAfx.h" |
| |
| #include "ArjDecoder2.h" |
| |
| namespace NCompress{ |
| namespace NArj { |
| namespace NDecoder2 { |
| |
| static const UInt32 kHistorySize = 26624; |
| static const UInt32 kMatchMinLen = 3; |
| |
| HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, |
| const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo * /* progress */) |
| { |
| if (outSize == NULL) |
| return E_INVALIDARG; |
| |
| if (!m_OutWindowStream.Create(kHistorySize)) |
| return E_OUTOFMEMORY; |
| if (!m_InBitStream.Create(1 << 20)) |
| return E_OUTOFMEMORY; |
| |
| UInt64 pos = 0; |
| m_OutWindowStream.SetStream(outStream); |
| m_OutWindowStream.Init(false); |
| m_InBitStream.SetStream(inStream); |
| m_InBitStream.Init(); |
| CCoderReleaser coderReleaser(this); |
| |
| while(pos < *outSize) |
| { |
| const UInt32 kStartWidth = 0; |
| const UInt32 kStopWidth = 7; |
| UInt32 power = 1 << kStartWidth; |
| UInt32 width; |
| UInt32 len = 0; |
| for (width = kStartWidth; width < kStopWidth; width++) |
| { |
| if (m_InBitStream.ReadBits(1) == 0) |
| break; |
| len += power; |
| power <<= 1; |
| } |
| if (width != 0) |
| len += m_InBitStream.ReadBits(width); |
| if (len == 0) |
| { |
| m_OutWindowStream.PutByte((Byte)m_InBitStream.ReadBits(8)); |
| pos++; |
| continue; |
| } |
| else |
| { |
| len = len - 1 + kMatchMinLen; |
| const UInt32 kStartWidth = 9; |
| const UInt32 kStopWidth = 13; |
| UInt32 power = 1 << kStartWidth; |
| UInt32 width; |
| UInt32 distance = 0; |
| for (width = kStartWidth; width < kStopWidth; width++) |
| { |
| if (m_InBitStream.ReadBits(1) == 0) |
| break; |
| distance += power; |
| power <<= 1; |
| } |
| if (width != 0) |
| distance += m_InBitStream.ReadBits(width); |
| if (distance >= pos) |
| return S_FALSE; |
| m_OutWindowStream.CopyBlock(distance, len); |
| pos += len; |
| } |
| } |
| coderReleaser.NeedFlush = false; |
| return m_OutWindowStream.Flush(); |
| } |
| |
| STDMETHODIMP CCoder::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 CLzOutWindowException &e) { return e.ErrorCode; } |
| catch(...) { return S_FALSE; } |
| } |
| |
| }}} |