Path: blob/main/misc/emulator/xnes/snes9x/jma/lzmadec.cpp
28798 views
/*1Copyright (C) 2005-2006 NSRT Team ( http://nsrt.edgeemu.com )2Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )3Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org )45This library is free software; you can redistribute it and/or6modify it under the terms of the GNU Lesser General Public7License version 2.1 as published by the Free Software Foundation.89This library is distributed in the hope that it will be useful,10but WITHOUT ANY WARRANTY; without even the implied warranty of11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU12Lesser General Public License for more details.1314You should have received a copy of the GNU Lesser General Public15License along with this library; if not, write to the Free Software16Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA17*/1819#include "portable.h"20#include "lzmadec.h"2122#define RETURN_E_OUTOFMEMORY_IF_FALSE(x) { if (!(x)) return E_OUTOFMEMORY; }2324namespace NCompress {25namespace NLZMA {2627HRESULT CDecoder::SetDictionarySize(UINT32 aDictionarySize)28{29if (aDictionarySize > (1 << kDicLogSizeMax))30return E_INVALIDARG;3132UINT32 aWindowReservSize = MyMax(aDictionarySize, UINT32(1 << 21));3334if (m_DictionarySize != aDictionarySize)35{36m_OutWindowStream.Create(aDictionarySize, kMatchMaxLen, aWindowReservSize);37m_DictionarySize = aDictionarySize;38}39return S_OK;40}4142HRESULT CDecoder::SetLiteralProperties(43UINT32 aLiteralPosStateBits, UINT32 aLiteralContextBits)44{45if (aLiteralPosStateBits > 8)46return E_INVALIDARG;47if (aLiteralContextBits > 8)48return E_INVALIDARG;49m_LiteralDecoder.Create(aLiteralPosStateBits, aLiteralContextBits);50return S_OK;51}5253HRESULT CDecoder::SetPosBitsProperties(UINT32 aNumPosStateBits)54{55if (aNumPosStateBits > NLength::kNumPosStatesBitsMax)56return E_INVALIDARG;57UINT32 aNumPosStates = 1 << aNumPosStateBits;58m_LenDecoder.Create(aNumPosStates);59m_RepMatchLenDecoder.Create(aNumPosStates);60m_PosStateMask = aNumPosStates - 1;61return S_OK;62}6364CDecoder::CDecoder():65m_DictionarySize((UINT32)-1)66{67Create();68}6970HRESULT CDecoder::Create()71{72for(int i = 0; i < kNumPosModels; i++)73{74RETURN_E_OUTOFMEMORY_IF_FALSE(75m_PosDecoders[i].Create(kDistDirectBits[kStartPosModelIndex + i]));76}77return S_OK;78}798081HRESULT CDecoder::Init(ISequentialInStream *anInStream,82ISequentialOutStream *anOutStream)83{84m_RangeDecoder.Init(anInStream);8586m_OutWindowStream.Init(anOutStream);8788int i;89for(i = 0; i < kNumStates; i++)90{91for (UINT32 j = 0; j <= m_PosStateMask; j++)92{93m_MainChoiceDecoders[i][j].Init();94m_MatchRepShortChoiceDecoders[i][j].Init();95}96m_MatchChoiceDecoders[i].Init();97m_MatchRepChoiceDecoders[i].Init();98m_MatchRep1ChoiceDecoders[i].Init();99m_MatchRep2ChoiceDecoders[i].Init();100}101102m_LiteralDecoder.Init();103104// m_RepMatchLenDecoder.Init();105106for (i = 0; (UINT32) i < kNumLenToPosStates; i++)107m_PosSlotDecoder[i].Init();108109for(i = 0; i < kNumPosModels; i++)110m_PosDecoders[i].Init();111112m_LenDecoder.Init();113m_RepMatchLenDecoder.Init();114115m_PosAlignDecoder.Init();116return S_OK;117118}119120HRESULT CDecoder::CodeReal(ISequentialInStream *anInStream,121ISequentialOutStream *anOutStream,122const UINT64 *anInSize, const UINT64 *anOutSize)123{124if (anOutSize == NULL)125return E_INVALIDARG;126127Init(anInStream, anOutStream);128129CState aState;130aState.Init();131bool aPeviousIsMatch = false;132BYTE aPreviousByte = 0;133UINT32 aRepDistances[kNumRepDistances];134for(UINT32 i = 0 ; i < kNumRepDistances; i++)135aRepDistances[i] = 0;136137UINT64 aNowPos64 = 0;138UINT64 aSize = *anOutSize;139while(aNowPos64 < aSize)140{141UINT64 aNext = MyMin(aNowPos64 + (1 << 18), aSize);142while(aNowPos64 < aNext)143{144UINT32 aPosState = UINT32(aNowPos64) & m_PosStateMask;145if (m_MainChoiceDecoders[aState.m_Index][aPosState].Decode(&m_RangeDecoder) == (UINT32) kMainChoiceLiteralIndex)146{147// aCounts[0]++;148aState.UpdateChar();149if(aPeviousIsMatch)150{151BYTE aMatchByte = m_OutWindowStream.GetOneByte(0 - aRepDistances[0] - 1);152aPreviousByte = m_LiteralDecoder.DecodeWithMatchByte(&m_RangeDecoder,153UINT32(aNowPos64), aPreviousByte, aMatchByte);154aPeviousIsMatch = false;155}156else157aPreviousByte = m_LiteralDecoder.DecodeNormal(&m_RangeDecoder,158UINT32(aNowPos64), aPreviousByte);159m_OutWindowStream.PutOneByte(aPreviousByte);160aNowPos64++;161}162else163{164aPeviousIsMatch = true;165UINT32 aDistance, aLen;166if(m_MatchChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) ==167(UINT32) kMatchChoiceRepetitionIndex)168{169if(m_MatchRepChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) == 0)170{171if(m_MatchRepShortChoiceDecoders[aState.m_Index][aPosState].Decode(&m_RangeDecoder) == 0)172{173aState.UpdateShortRep();174aPreviousByte = m_OutWindowStream.GetOneByte(0 - aRepDistances[0] - 1);175m_OutWindowStream.PutOneByte(aPreviousByte);176aNowPos64++;177// aCounts[3 + 4]++;178continue;179}180// aCounts[3 + 0]++;181aDistance = aRepDistances[0];182}183else184{185if(m_MatchRep1ChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) == 0)186{187aDistance = aRepDistances[1];188aRepDistances[1] = aRepDistances[0];189// aCounts[3 + 1]++;190}191else192{193if (m_MatchRep2ChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) == 0)194{195// aCounts[3 + 2]++;196aDistance = aRepDistances[2];197}198else199{200// aCounts[3 + 3]++;201aDistance = aRepDistances[3];202aRepDistances[3] = aRepDistances[2];203}204aRepDistances[2] = aRepDistances[1];205aRepDistances[1] = aRepDistances[0];206}207aRepDistances[0] = aDistance;208}209aLen = m_RepMatchLenDecoder.Decode(&m_RangeDecoder, aPosState) + kMatchMinLen;210// aCounts[aLen]++;211aState.UpdateRep();212}213else214{215aLen = kMatchMinLen + m_LenDecoder.Decode(&m_RangeDecoder, aPosState);216aState.UpdateMatch();217UINT32 aPosSlot = m_PosSlotDecoder[GetLenToPosState(aLen)].Decode(&m_RangeDecoder);218// aCounts[aPosSlot]++;219if (aPosSlot >= (UINT32) kStartPosModelIndex)220{221aDistance = kDistStart[aPosSlot];222if (aPosSlot < (UINT32) kEndPosModelIndex)223aDistance += m_PosDecoders[aPosSlot - kStartPosModelIndex].Decode(&m_RangeDecoder);224else225{226aDistance += (m_RangeDecoder.DecodeDirectBits(kDistDirectBits[aPosSlot] -227kNumAlignBits) << kNumAlignBits);228aDistance += m_PosAlignDecoder.Decode(&m_RangeDecoder);229}230}231else232aDistance = aPosSlot;233234235aRepDistances[3] = aRepDistances[2];236aRepDistances[2] = aRepDistances[1];237aRepDistances[1] = aRepDistances[0];238239aRepDistances[0] = aDistance;240// UpdateStat(aLen, aPosSlot);241}242if (aDistance >= aNowPos64)243throw E_INVALIDDATA;244m_OutWindowStream.CopyBackBlock(aDistance, aLen);245aNowPos64 += aLen;246aPreviousByte = m_OutWindowStream.GetOneByte(0 - 1);247}248}249}250return Flush();251}252253HRESULT CDecoder::Code(ISequentialInStream *anInStream, ISequentialOutStream *anOutStream, const UINT64 *anInSize, const UINT64 *anOutSize)254{255try {256return CodeReal(anInStream, anOutStream, anInSize, anOutSize);257} catch (HRESULT& e) {258return e;259} catch (...) {260return E_FAIL;261}262}263264HRESULT CDecoder::ReadCoderProperties(ISequentialInStream *anInStream)265{266UINT32 aNumPosStateBits;267UINT32 aLiteralPosStateBits;268UINT32 aLiteralContextBits;269UINT32 aDictionarySize;270271UINT32 aProcessesedSize;272273BYTE aByte;274RETURN_IF_NOT_S_OK(anInStream->Read(&aByte, sizeof(aByte), &aProcessesedSize));275if (aProcessesedSize != sizeof(aByte))276return E_INVALIDARG;277278aLiteralContextBits = aByte % 9;279BYTE aRemainder = aByte / 9;280aLiteralPosStateBits = aRemainder % 5;281aNumPosStateBits = aRemainder / 5;282283UINT8 uint_buffer[UINT_SIZE];284RETURN_IF_NOT_S_OK(anInStream->Read(uint_buffer, sizeof(aDictionarySize), &aProcessesedSize));285aDictionarySize = charp_to_uint(uint_buffer);286287if (aProcessesedSize != sizeof(aDictionarySize))288return E_INVALIDARG;289290RETURN_IF_NOT_S_OK(SetDictionarySize(aDictionarySize));291RETURN_IF_NOT_S_OK(SetLiteralProperties(aLiteralPosStateBits, aLiteralContextBits));292RETURN_IF_NOT_S_OK(SetPosBitsProperties(aNumPosStateBits));293294return S_OK;295}296297}}298299300