summaryrefslogtreecommitdiffstats
path: root/hostTools/lzma/compress/LZMADecoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'hostTools/lzma/compress/LZMADecoder.cpp')
-rw-r--r--hostTools/lzma/compress/LZMADecoder.cpp276
1 files changed, 276 insertions, 0 deletions
diff --git a/hostTools/lzma/compress/LZMADecoder.cpp b/hostTools/lzma/compress/LZMADecoder.cpp
new file mode 100644
index 0000000..1c834a4
--- /dev/null
+++ b/hostTools/lzma/compress/LZMADecoder.cpp
@@ -0,0 +1,276 @@
+#include "Portable.h"
+#include "LZMADecoder.h"
+
+#define RETURN_E_OUTOFMEMORY_IF_FALSE(x) { if (!(x)) return E_OUTOFMEMORY; }
+
+namespace NCompress {
+namespace NLZMA {
+
+HRESULT CDecoder::SetDictionarySize(UINT32 aDictionarySize)
+{
+ if (aDictionarySize > (1 << kDicLogSizeMax))
+ return E_INVALIDARG;
+
+ UINT32 aWindowReservSize = MyMax(aDictionarySize, UINT32(1 << 21));
+
+ if (m_DictionarySize != aDictionarySize)
+ {
+ m_OutWindowStream.Create(aDictionarySize, kMatchMaxLen, aWindowReservSize);
+ m_DictionarySize = aDictionarySize;
+ }
+ return S_OK;
+}
+
+HRESULT CDecoder::SetLiteralProperties(
+ UINT32 aLiteralPosStateBits, UINT32 aLiteralContextBits)
+{
+ if (aLiteralPosStateBits > 8)
+ return E_INVALIDARG;
+ if (aLiteralContextBits > 8)
+ return E_INVALIDARG;
+ m_LiteralDecoder.Create(aLiteralPosStateBits, aLiteralContextBits);
+ return S_OK;
+}
+
+HRESULT CDecoder::SetPosBitsProperties(UINT32 aNumPosStateBits)
+{
+ if (aNumPosStateBits > NLength::kNumPosStatesBitsMax)
+ return E_INVALIDARG;
+ UINT32 aNumPosStates = 1 << aNumPosStateBits;
+ m_LenDecoder.Create(aNumPosStates);
+ m_RepMatchLenDecoder.Create(aNumPosStates);
+ m_PosStateMask = aNumPosStates - 1;
+ return S_OK;
+}
+
+CDecoder::CDecoder():
+ m_DictionarySize((UINT32)-1)
+{
+ Create();
+}
+
+HRESULT CDecoder::Create()
+{
+ for(int i = 0; i < kNumPosModels; i++)
+ {
+ RETURN_E_OUTOFMEMORY_IF_FALSE(
+ m_PosDecoders[i].Create(kDistDirectBits[kStartPosModelIndex + i]));
+ }
+ return S_OK;
+}
+
+
+HRESULT CDecoder::Init(ISequentialInStream *anInStream,
+ ISequentialOutStream *anOutStream)
+{
+ m_RangeDecoder.Init(anInStream);
+
+ m_OutWindowStream.Init(anOutStream);
+
+ int i;
+ for(i = 0; i < kNumStates; i++)
+ {
+ for (UINT32 j = 0; j <= m_PosStateMask; j++)
+ {
+ m_MainChoiceDecoders[i][j].Init();
+ m_MatchRepShortChoiceDecoders[i][j].Init();
+ }
+ m_MatchChoiceDecoders[i].Init();
+ m_MatchRepChoiceDecoders[i].Init();
+ m_MatchRep1ChoiceDecoders[i].Init();
+ m_MatchRep2ChoiceDecoders[i].Init();
+ }
+
+ m_LiteralDecoder.Init();
+
+ // m_RepMatchLenDecoder.Init();
+
+ for (i = 0; i < kNumLenToPosStates; i++)
+ m_PosSlotDecoder[i].Init();
+
+ for(i = 0; i < kNumPosModels; i++)
+ m_PosDecoders[i].Init();
+
+ m_LenDecoder.Init();
+ m_RepMatchLenDecoder.Init();
+
+ m_PosAlignDecoder.Init();
+ return S_OK;
+
+}
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *anInStream,
+ ISequentialOutStream *anOutStream,
+ const UINT64 *anInSize, const UINT64 *anOutSize)
+{
+ if (anOutSize == NULL)
+ return E_INVALIDARG;
+
+ Init(anInStream, anOutStream);
+
+ CState aState;
+ aState.Init();
+ bool aPeviousIsMatch = false;
+ BYTE aPreviousByte = 0;
+ UINT32 aRepDistances[kNumRepDistances];
+ for(int i = 0 ; i < kNumRepDistances; i++)
+ aRepDistances[i] = 0;
+
+ UINT64 aNowPos64 = 0;
+ UINT64 aSize = *anOutSize;
+ while(aNowPos64 < aSize)
+ {
+ UINT64 aNext = MyMin(aNowPos64 + (1 << 18), aSize);
+ while(aNowPos64 < aNext)
+ {
+ UINT32 aPosState = UINT32(aNowPos64) & m_PosStateMask;
+ if (m_MainChoiceDecoders[aState.m_Index][aPosState].Decode(&m_RangeDecoder) == kMainChoiceLiteralIndex)
+ {
+ // aCounts[0]++;
+ aState.UpdateChar();
+ if(aPeviousIsMatch)
+ {
+ BYTE aMatchByte = m_OutWindowStream.GetOneByte(0 - aRepDistances[0] - 1);
+ aPreviousByte = m_LiteralDecoder.DecodeWithMatchByte(&m_RangeDecoder,
+ UINT32(aNowPos64), aPreviousByte, aMatchByte);
+ aPeviousIsMatch = false;
+ }
+ else
+ aPreviousByte = m_LiteralDecoder.DecodeNormal(&m_RangeDecoder,
+ UINT32(aNowPos64), aPreviousByte);
+ m_OutWindowStream.PutOneByte(aPreviousByte);
+ aNowPos64++;
+ }
+ else
+ {
+ aPeviousIsMatch = true;
+ UINT32 aDistance, aLen;
+ if(m_MatchChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) ==
+ kMatchChoiceRepetitionIndex)
+ {
+ if(m_MatchRepChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) == 0)
+ {
+ if(m_MatchRepShortChoiceDecoders[aState.m_Index][aPosState].Decode(&m_RangeDecoder) == 0)
+ {
+ aState.UpdateShortRep();
+ aPreviousByte = m_OutWindowStream.GetOneByte(0 - aRepDistances[0] - 1);
+ m_OutWindowStream.PutOneByte(aPreviousByte);
+ aNowPos64++;
+ // aCounts[3 + 4]++;
+ continue;
+ }
+ // aCounts[3 + 0]++;
+ aDistance = aRepDistances[0];
+ }
+ else
+ {
+ if(m_MatchRep1ChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) == 0)
+ {
+ aDistance = aRepDistances[1];
+ aRepDistances[1] = aRepDistances[0];
+ // aCounts[3 + 1]++;
+ }
+ else
+ {
+ if (m_MatchRep2ChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) == 0)
+ {
+ // aCounts[3 + 2]++;
+ aDistance = aRepDistances[2];
+ }
+ else
+ {
+ // aCounts[3 + 3]++;
+ aDistance = aRepDistances[3];
+ aRepDistances[3] = aRepDistances[2];
+ }
+ aRepDistances[2] = aRepDistances[1];
+ aRepDistances[1] = aRepDistances[0];
+ }
+ aRepDistances[0] = aDistance;
+ }
+ aLen = m_RepMatchLenDecoder.Decode(&m_RangeDecoder, aPosState) + kMatchMinLen;
+ // aCounts[aLen]++;
+ aState.UpdateRep();
+ }
+ else
+ {
+ aLen = kMatchMinLen + m_LenDecoder.Decode(&m_RangeDecoder, aPosState);
+ aState.UpdateMatch();
+ UINT32 aPosSlot = m_PosSlotDecoder[GetLenToPosState(aLen)].Decode(&m_RangeDecoder);
+ // aCounts[aPosSlot]++;
+ if (aPosSlot >= kStartPosModelIndex)
+ {
+ aDistance = kDistStart[aPosSlot];
+ if (aPosSlot < kEndPosModelIndex)
+ aDistance += m_PosDecoders[aPosSlot - kStartPosModelIndex].Decode(&m_RangeDecoder);
+ else
+ {
+ aDistance += (m_RangeDecoder.DecodeDirectBits(kDistDirectBits[aPosSlot] -
+ kNumAlignBits) << kNumAlignBits);
+ aDistance += m_PosAlignDecoder.Decode(&m_RangeDecoder);
+ }
+ }
+ else
+ aDistance = aPosSlot;
+
+
+ aRepDistances[3] = aRepDistances[2];
+ aRepDistances[2] = aRepDistances[1];
+ aRepDistances[1] = aRepDistances[0];
+
+ aRepDistances[0] = aDistance;
+ // UpdateStat(aLen, aPosSlot);
+ }
+ if (aDistance >= aNowPos64)
+ throw E_INVALIDDATA;
+ m_OutWindowStream.CopyBackBlock(aDistance, aLen);
+ aNowPos64 += aLen;
+ aPreviousByte = m_OutWindowStream.GetOneByte(0 - 1);
+ }
+ }
+ }
+ return Flush();
+}
+
+HRESULT CDecoder::Code(ISequentialInStream *anInStream, ISequentialOutStream *anOutStream, const UINT64 *anInSize, const UINT64 *anOutSize)
+{
+ try {
+ return CodeReal(anInStream, anOutStream, anInSize, anOutSize);
+ } catch (HRESULT& e) {
+ return e;
+ } catch (...) {
+ return E_FAIL;
+ }
+}
+
+HRESULT CDecoder::ReadCoderProperties(ISequentialInStream *anInStream)
+{
+ UINT32 aNumPosStateBits;
+ UINT32 aLiteralPosStateBits;
+ UINT32 aLiteralContextBits;
+ UINT32 aDictionarySize;
+
+ UINT32 aProcessesedSize;
+
+ BYTE aByte;
+ RETURN_IF_NOT_S_OK(anInStream->Read(&aByte, sizeof(aByte), &aProcessesedSize));
+ if (aProcessesedSize != sizeof(aByte))
+ return E_INVALIDARG;
+
+ aLiteralContextBits = aByte % 9;
+ BYTE aRemainder = aByte / 9;
+ aLiteralPosStateBits = aRemainder % 5;
+ aNumPosStateBits = aRemainder / 5;
+
+ RETURN_IF_NOT_S_OK(anInStream->Read(&aDictionarySize, sizeof(aDictionarySize), &aProcessesedSize));
+ if (aProcessesedSize != sizeof(aDictionarySize))
+ return E_INVALIDARG;
+
+ RETURN_IF_NOT_S_OK(SetDictionarySize(aDictionarySize));
+ RETURN_IF_NOT_S_OK(SetLiteralProperties(aLiteralPosStateBits, aLiteralContextBits));
+ RETURN_IF_NOT_S_OK(SetPosBitsProperties(aNumPosStateBits));
+
+ return S_OK;
+}
+
+}}