1/*
2Copyright (C) 2005-2006 NSRT Team ( http://nsrt.edgeemu.com )
3Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
4Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org )
5
6This library is free software; you can redistribute it and/or
7modify it under the terms of the GNU Lesser General Public
8License version 2.1 as published by the Free Software Foundation.
9
10This library is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13Lesser General Public License for more details.
14
15You should have received a copy of the GNU Lesser General Public
16License along with this library; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18*/
19
20#include "portable.h"
21#include "lzmadec.h"
22
23#define RETURN_E_OUTOFMEMORY_IF_FALSE(x) { if (!(x)) return E_OUTOFMEMORY; }
24
25namespace NCompress {
26namespace NLZMA {
27
28HRESULT CDecoder::SetDictionarySize(UINT32 aDictionarySize)
29{
30 if (aDictionarySize > (1 << kDicLogSizeMax))
31 return E_INVALIDARG;
32
33 UINT32 aWindowReservSize = MyMax(aDictionarySize, UINT32(1 << 21));
34
35 if (m_DictionarySize != aDictionarySize)
36 {
37 m_OutWindowStream.Create(aDictionarySize, kMatchMaxLen, aWindowReservSize);
38 m_DictionarySize = aDictionarySize;
39 }
40 return S_OK;
41}
42
43HRESULT CDecoder::SetLiteralProperties(
44 UINT32 aLiteralPosStateBits, UINT32 aLiteralContextBits)
45{
46 if (aLiteralPosStateBits > 8)
47 return E_INVALIDARG;
48 if (aLiteralContextBits > 8)
49 return E_INVALIDARG;
50 m_LiteralDecoder.Create(aLiteralPosStateBits, aLiteralContextBits);
51 return S_OK;
52}
53
54HRESULT CDecoder::SetPosBitsProperties(UINT32 aNumPosStateBits)
55{
56 if (aNumPosStateBits > NLength::kNumPosStatesBitsMax)
57 return E_INVALIDARG;
58 UINT32 aNumPosStates = 1 << aNumPosStateBits;
59 m_LenDecoder.Create(aNumPosStates);
60 m_RepMatchLenDecoder.Create(aNumPosStates);
61 m_PosStateMask = aNumPosStates - 1;
62 return S_OK;
63}
64
65CDecoder::CDecoder():
66 m_DictionarySize((UINT32)-1)
67{
68 Create();
69}
70
71HRESULT CDecoder::Create()
72{
73 for(int i = 0; i < kNumPosModels; i++)
74 {
75 RETURN_E_OUTOFMEMORY_IF_FALSE(
76 m_PosDecoders[i].Create(kDistDirectBits[kStartPosModelIndex + i]));
77 }
78 return S_OK;
79}
80
81
82HRESULT CDecoder::Init(ISequentialInStream *anInStream,
83 ISequentialOutStream *anOutStream)
84{
85 m_RangeDecoder.Init(anInStream);
86
87 m_OutWindowStream.Init(anOutStream);
88
89 int i;
90 for(i = 0; i < kNumStates; i++)
91 {
92 for (UINT32 j = 0; j <= m_PosStateMask; j++)
93 {
94 m_MainChoiceDecoders[i][j].Init();
95 m_MatchRepShortChoiceDecoders[i][j].Init();
96 }
97 m_MatchChoiceDecoders[i].Init();
98 m_MatchRepChoiceDecoders[i].Init();
99 m_MatchRep1ChoiceDecoders[i].Init();
100 m_MatchRep2ChoiceDecoders[i].Init();
101 }
102
103 m_LiteralDecoder.Init();
104
105 // m_RepMatchLenDecoder.Init();
106
107 for (i = 0; (UINT32) i < kNumLenToPosStates; i++)
108 m_PosSlotDecoder[i].Init();
109
110 for(i = 0; i < kNumPosModels; i++)
111 m_PosDecoders[i].Init();
112
113 m_LenDecoder.Init();
114 m_RepMatchLenDecoder.Init();
115
116 m_PosAlignDecoder.Init();
117 return S_OK;
118
119}
120
121HRESULT CDecoder::CodeReal(ISequentialInStream *anInStream,
122 ISequentialOutStream *anOutStream,
123 const UINT64 *anInSize, const UINT64 *anOutSize)
124{
125 if (anOutSize == NULL)
126 return E_INVALIDARG;
127
128 Init(anInStream, anOutStream);
129
130 CState aState;
131 aState.Init();
132 bool aPeviousIsMatch = false;
133 BYTE aPreviousByte = 0;
134 UINT32 aRepDistances[kNumRepDistances];
135 for(UINT32 i = 0 ; i < kNumRepDistances; i++)
136 aRepDistances[i] = 0;
137
138 UINT64 aNowPos64 = 0;
139 UINT64 aSize = *anOutSize;
140 while(aNowPos64 < aSize)
141 {
142 UINT64 aNext = MyMin(aNowPos64 + (1 << 18), aSize);
143 while(aNowPos64 < aNext)
144 {
145 UINT32 aPosState = UINT32(aNowPos64) & m_PosStateMask;
146 if (m_MainChoiceDecoders[aState.m_Index][aPosState].Decode(&m_RangeDecoder) == (UINT32) kMainChoiceLiteralIndex)
147 {
148 // aCounts[0]++;
149 aState.UpdateChar();
150 if(aPeviousIsMatch)
151 {
152 BYTE aMatchByte = m_OutWindowStream.GetOneByte(0 - aRepDistances[0] - 1);
153 aPreviousByte = m_LiteralDecoder.DecodeWithMatchByte(&m_RangeDecoder,
154 UINT32(aNowPos64), aPreviousByte, aMatchByte);
155 aPeviousIsMatch = false;
156 }
157 else
158 aPreviousByte = m_LiteralDecoder.DecodeNormal(&m_RangeDecoder,
159 UINT32(aNowPos64), aPreviousByte);
160 m_OutWindowStream.PutOneByte(aPreviousByte);
161 aNowPos64++;
162 }
163 else
164 {
165 aPeviousIsMatch = true;
166 UINT32 aDistance, aLen;
167 if(m_MatchChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) ==
168 (UINT32) kMatchChoiceRepetitionIndex)
169 {
170 if(m_MatchRepChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) == 0)
171 {
172 if(m_MatchRepShortChoiceDecoders[aState.m_Index][aPosState].Decode(&m_RangeDecoder) == 0)
173 {
174 aState.UpdateShortRep();
175 aPreviousByte = m_OutWindowStream.GetOneByte(0 - aRepDistances[0] - 1);
176 m_OutWindowStream.PutOneByte(aPreviousByte);
177 aNowPos64++;
178 // aCounts[3 + 4]++;
179 continue;
180 }
181 // aCounts[3 + 0]++;
182 aDistance = aRepDistances[0];
183 }
184 else
185 {
186 if(m_MatchRep1ChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) == 0)
187 {
188 aDistance = aRepDistances[1];
189 aRepDistances[1] = aRepDistances[0];
190 // aCounts[3 + 1]++;
191 }
192 else
193 {
194 if (m_MatchRep2ChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) == 0)
195 {
196 // aCounts[3 + 2]++;
197 aDistance = aRepDistances[2];
198 }
199 else
200 {
201 // aCounts[3 + 3]++;
202 aDistance = aRepDistances[3];
203 aRepDistances[3] = aRepDistances[2];
204 }
205 aRepDistances[2] = aRepDistances[1];
206 aRepDistances[1] = aRepDistances[0];
207 }
208 aRepDistances[0] = aDistance;
209 }
210 aLen = m_RepMatchLenDecoder.Decode(&m_RangeDecoder, aPosState) + kMatchMinLen;
211 // aCounts[aLen]++;
212 aState.UpdateRep();
213 }
214 else
215 {
216 aLen = kMatchMinLen + m_LenDecoder.Decode(&m_RangeDecoder, aPosState);
217 aState.UpdateMatch();
218 UINT32 aPosSlot = m_PosSlotDecoder[GetLenToPosState(aLen)].Decode(&m_RangeDecoder);
219 // aCounts[aPosSlot]++;
220 if (aPosSlot >= (UINT32) kStartPosModelIndex)
221 {
222 aDistance = kDistStart[aPosSlot];
223 if (aPosSlot < (UINT32) kEndPosModelIndex)
224 aDistance += m_PosDecoders[aPosSlot - kStartPosModelIndex].Decode(&m_RangeDecoder);
225 else
226 {
227 aDistance += (m_RangeDecoder.DecodeDirectBits(kDistDirectBits[aPosSlot] -
228 kNumAlignBits) << kNumAlignBits);
229 aDistance += m_PosAlignDecoder.Decode(&m_RangeDecoder);
230 }
231 }
232 else
233 aDistance = aPosSlot;
234
235
236 aRepDistances[3] = aRepDistances[2];
237 aRepDistances[2] = aRepDistances[1];
238 aRepDistances[1] = aRepDistances[0];
239
240 aRepDistances[0] = aDistance;
241 // UpdateStat(aLen, aPosSlot);
242 }
243 if (aDistance >= aNowPos64)
244 throw E_INVALIDDATA;
245 m_OutWindowStream.CopyBackBlock(aDistance, aLen);
246 aNowPos64 += aLen;
247 aPreviousByte = m_OutWindowStream.GetOneByte(0 - 1);
248 }
249 }
250 }
251 return Flush();
252}
253
254HRESULT CDecoder::Code(ISequentialInStream *anInStream, ISequentialOutStream *anOutStream, const UINT64 *anInSize, const UINT64 *anOutSize)
255{
256 try {
257 return CodeReal(anInStream, anOutStream, anInSize, anOutSize);
258 } catch (HRESULT& e) {
259 return e;
260 } catch (...) {
261 return E_FAIL;
262 }
263}
264
265HRESULT CDecoder::ReadCoderProperties(ISequentialInStream *anInStream)
266{
267 UINT32 aNumPosStateBits;
268 UINT32 aLiteralPosStateBits;
269 UINT32 aLiteralContextBits;
270 UINT32 aDictionarySize;
271
272 UINT32 aProcessesedSize;
273
274 BYTE aByte;
275 RETURN_IF_NOT_S_OK(anInStream->Read(&aByte, sizeof(aByte), &aProcessesedSize));
276 if (aProcessesedSize != sizeof(aByte))
277 return E_INVALIDARG;
278
279 aLiteralContextBits = aByte % 9;
280 BYTE aRemainder = aByte / 9;
281 aLiteralPosStateBits = aRemainder % 5;
282 aNumPosStateBits = aRemainder / 5;
283
284 UINT8 uint_buffer[UINT_SIZE];
285 RETURN_IF_NOT_S_OK(anInStream->Read(uint_buffer, sizeof(aDictionarySize), &aProcessesedSize));
286 aDictionarySize = charp_to_uint(uint_buffer);
287
288 if (aProcessesedSize != sizeof(aDictionarySize))
289 return E_INVALIDARG;
290
291 RETURN_IF_NOT_S_OK(SetDictionarySize(aDictionarySize));
292 RETURN_IF_NOT_S_OK(SetLiteralProperties(aLiteralPosStateBits, aLiteralContextBits));
293 RETURN_IF_NOT_S_OK(SetPosBitsProperties(aNumPosStateBits));
294
295 return S_OK;
296}
297
298}}
299