1 | /* |
2 | Copyright (C) 2005-2006 NSRT Team ( http://nsrt.edgeemu.com ) |
3 | Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) |
4 | Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org ) |
5 | |
6 | This library is free software; you can redistribute it and/or |
7 | modify it under the terms of the GNU Lesser General Public |
8 | License version 2.1 as published by the Free Software Foundation. |
9 | |
10 | This library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with this library; if not, write to the Free Software |
17 | Foundation, 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 | |
25 | namespace NCompress { |
26 | namespace NLZMA { |
27 | |
28 | HRESULT 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 | |
43 | HRESULT 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 | |
54 | HRESULT 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 | |
65 | CDecoder::CDecoder(): |
66 | m_DictionarySize((UINT32)-1) |
67 | { |
68 | Create(); |
69 | } |
70 | |
71 | HRESULT 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 | |
82 | HRESULT 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 | |
121 | HRESULT 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 | |
254 | HRESULT 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 | |
265 | HRESULT 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 | |