rlm@1
|
1 // Bcj2Coder.cpp
|
rlm@1
|
2
|
rlm@1
|
3 #include "StdAfx.h"
|
rlm@1
|
4
|
rlm@1
|
5 extern "C"
|
rlm@1
|
6 {
|
rlm@1
|
7 #include "../../../C/Alloc.h"
|
rlm@1
|
8 }
|
rlm@1
|
9
|
rlm@1
|
10 #include "Bcj2Coder.h"
|
rlm@1
|
11
|
rlm@1
|
12 namespace NCompress {
|
rlm@1
|
13 namespace NBcj2 {
|
rlm@1
|
14
|
rlm@1
|
15 inline bool IsJcc(Byte b0, Byte b1) { return (b0 == 0x0F && (b1 & 0xF0) == 0x80); }
|
rlm@1
|
16 inline bool IsJ(Byte b0, Byte b1) { return ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1)); }
|
rlm@1
|
17 inline unsigned GetIndex(Byte b0, Byte b1) { return ((b1 == 0xE8) ? b0 : ((b1 == 0xE9) ? 256 : 257)); }
|
rlm@1
|
18
|
rlm@1
|
19 #ifndef EXTRACT_ONLY
|
rlm@1
|
20
|
rlm@1
|
21 static const int kBufferSize = 1 << 17;
|
rlm@1
|
22
|
rlm@1
|
23 static bool inline Test86MSByte(Byte b)
|
rlm@1
|
24 {
|
rlm@1
|
25 return (b == 0 || b == 0xFF);
|
rlm@1
|
26 }
|
rlm@1
|
27
|
rlm@1
|
28 bool CEncoder::Create()
|
rlm@1
|
29 {
|
rlm@1
|
30 if (!_mainStream.Create(1 << 16))
|
rlm@1
|
31 return false;
|
rlm@1
|
32 if (!_callStream.Create(1 << 20))
|
rlm@1
|
33 return false;
|
rlm@1
|
34 if (!_jumpStream.Create(1 << 20))
|
rlm@1
|
35 return false;
|
rlm@1
|
36 if (!_rangeEncoder.Create(1 << 20))
|
rlm@1
|
37 return false;
|
rlm@1
|
38 if (_buffer == 0)
|
rlm@1
|
39 {
|
rlm@1
|
40 _buffer = (Byte *)MidAlloc(kBufferSize);
|
rlm@1
|
41 if (_buffer == 0)
|
rlm@1
|
42 return false;
|
rlm@1
|
43 }
|
rlm@1
|
44 return true;
|
rlm@1
|
45 }
|
rlm@1
|
46
|
rlm@1
|
47 CEncoder::~CEncoder()
|
rlm@1
|
48 {
|
rlm@1
|
49 ::MidFree(_buffer);
|
rlm@1
|
50 }
|
rlm@1
|
51
|
rlm@1
|
52 HRESULT CEncoder::Flush()
|
rlm@1
|
53 {
|
rlm@1
|
54 RINOK(_mainStream.Flush());
|
rlm@1
|
55 RINOK(_callStream.Flush());
|
rlm@1
|
56 RINOK(_jumpStream.Flush());
|
rlm@1
|
57 _rangeEncoder.FlushData();
|
rlm@1
|
58 return _rangeEncoder.FlushStream();
|
rlm@1
|
59 }
|
rlm@1
|
60
|
rlm@1
|
61 const UInt32 kDefaultLimit = (1 << 24);
|
rlm@1
|
62
|
rlm@1
|
63 HRESULT CEncoder::CodeReal(ISequentialInStream **inStreams,
|
rlm@1
|
64 const UInt64 **inSizes,
|
rlm@1
|
65 UInt32 numInStreams,
|
rlm@1
|
66 ISequentialOutStream **outStreams,
|
rlm@1
|
67 const UInt64 ** /* outSizes */,
|
rlm@1
|
68 UInt32 numOutStreams,
|
rlm@1
|
69 ICompressProgressInfo *progress)
|
rlm@1
|
70 {
|
rlm@1
|
71 if (numInStreams != 1 || numOutStreams != 4)
|
rlm@1
|
72 return E_INVALIDARG;
|
rlm@1
|
73
|
rlm@1
|
74 if (!Create())
|
rlm@1
|
75 return E_OUTOFMEMORY;
|
rlm@1
|
76
|
rlm@1
|
77 bool sizeIsDefined = false;
|
rlm@1
|
78 UInt64 inSize = 0;
|
rlm@1
|
79 if (inSizes != NULL)
|
rlm@1
|
80 if (inSizes[0] != NULL)
|
rlm@1
|
81 {
|
rlm@1
|
82 inSize = *inSizes[0];
|
rlm@1
|
83 if (inSize <= kDefaultLimit)
|
rlm@1
|
84 sizeIsDefined = true;
|
rlm@1
|
85 }
|
rlm@1
|
86
|
rlm@1
|
87 ISequentialInStream *inStream = inStreams[0];
|
rlm@1
|
88
|
rlm@1
|
89 _mainStream.SetStream(outStreams[0]);
|
rlm@1
|
90 _mainStream.Init();
|
rlm@1
|
91 _callStream.SetStream(outStreams[1]);
|
rlm@1
|
92 _callStream.Init();
|
rlm@1
|
93 _jumpStream.SetStream(outStreams[2]);
|
rlm@1
|
94 _jumpStream.Init();
|
rlm@1
|
95 _rangeEncoder.SetStream(outStreams[3]);
|
rlm@1
|
96 _rangeEncoder.Init();
|
rlm@1
|
97 for (int i = 0; i < 256 + 2; i++)
|
rlm@1
|
98 _statusEncoder[i].Init();
|
rlm@1
|
99 CCoderReleaser releaser(this);
|
rlm@1
|
100
|
rlm@1
|
101 CMyComPtr<ICompressGetSubStreamSize> getSubStreamSize;
|
rlm@1
|
102 {
|
rlm@1
|
103 inStream->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize);
|
rlm@1
|
104 }
|
rlm@1
|
105
|
rlm@1
|
106 UInt32 nowPos = 0;
|
rlm@1
|
107 UInt64 nowPos64 = 0;
|
rlm@1
|
108 UInt32 bufferPos = 0;
|
rlm@1
|
109
|
rlm@1
|
110 Byte prevByte = 0;
|
rlm@1
|
111
|
rlm@1
|
112 UInt64 subStreamIndex = 0;
|
rlm@1
|
113 UInt64 subStreamStartPos = 0;
|
rlm@1
|
114 UInt64 subStreamEndPos = 0;
|
rlm@1
|
115
|
rlm@1
|
116 for (;;)
|
rlm@1
|
117 {
|
rlm@1
|
118 UInt32 processedSize = 0;
|
rlm@1
|
119 for (;;)
|
rlm@1
|
120 {
|
rlm@1
|
121 UInt32 size = kBufferSize - (bufferPos + processedSize);
|
rlm@1
|
122 UInt32 processedSizeLoc;
|
rlm@1
|
123 if (size == 0)
|
rlm@1
|
124 break;
|
rlm@1
|
125 RINOK(inStream->Read(_buffer + bufferPos + processedSize, size, &processedSizeLoc));
|
rlm@1
|
126 if (processedSizeLoc == 0)
|
rlm@1
|
127 break;
|
rlm@1
|
128 processedSize += processedSizeLoc;
|
rlm@1
|
129 }
|
rlm@1
|
130 UInt32 endPos = bufferPos + processedSize;
|
rlm@1
|
131
|
rlm@1
|
132 if (endPos < 5)
|
rlm@1
|
133 {
|
rlm@1
|
134 // change it
|
rlm@1
|
135 for (bufferPos = 0; bufferPos < endPos; bufferPos++)
|
rlm@1
|
136 {
|
rlm@1
|
137 Byte b = _buffer[bufferPos];
|
rlm@1
|
138 _mainStream.WriteByte(b);
|
rlm@1
|
139 UInt32 index;
|
rlm@1
|
140 if (b == 0xE8)
|
rlm@1
|
141 index = prevByte;
|
rlm@1
|
142 else if (b == 0xE9)
|
rlm@1
|
143 index = 256;
|
rlm@1
|
144 else if (IsJcc(prevByte, b))
|
rlm@1
|
145 index = 257;
|
rlm@1
|
146 else
|
rlm@1
|
147 {
|
rlm@1
|
148 prevByte = b;
|
rlm@1
|
149 continue;
|
rlm@1
|
150 }
|
rlm@1
|
151 _statusEncoder[index].Encode(&_rangeEncoder, 0);
|
rlm@1
|
152 prevByte = b;
|
rlm@1
|
153 }
|
rlm@1
|
154 return Flush();
|
rlm@1
|
155 }
|
rlm@1
|
156
|
rlm@1
|
157 bufferPos = 0;
|
rlm@1
|
158
|
rlm@1
|
159 UInt32 limit = endPos - 5;
|
rlm@1
|
160 while(bufferPos <= limit)
|
rlm@1
|
161 {
|
rlm@1
|
162 Byte b = _buffer[bufferPos];
|
rlm@1
|
163 _mainStream.WriteByte(b);
|
rlm@1
|
164 if (!IsJ(prevByte, b))
|
rlm@1
|
165 {
|
rlm@1
|
166 bufferPos++;
|
rlm@1
|
167 prevByte = b;
|
rlm@1
|
168 continue;
|
rlm@1
|
169 }
|
rlm@1
|
170 Byte nextByte = _buffer[bufferPos + 4];
|
rlm@1
|
171 UInt32 src =
|
rlm@1
|
172 (UInt32(nextByte) << 24) |
|
rlm@1
|
173 (UInt32(_buffer[bufferPos + 3]) << 16) |
|
rlm@1
|
174 (UInt32(_buffer[bufferPos + 2]) << 8) |
|
rlm@1
|
175 (_buffer[bufferPos + 1]);
|
rlm@1
|
176 UInt32 dest = (nowPos + bufferPos + 5) + src;
|
rlm@1
|
177 // if (Test86MSByte(nextByte))
|
rlm@1
|
178 bool convert;
|
rlm@1
|
179 if (getSubStreamSize != NULL)
|
rlm@1
|
180 {
|
rlm@1
|
181 UInt64 currentPos = (nowPos64 + bufferPos);
|
rlm@1
|
182 while (subStreamEndPos < currentPos)
|
rlm@1
|
183 {
|
rlm@1
|
184 UInt64 subStreamSize;
|
rlm@1
|
185 HRESULT result = getSubStreamSize->GetSubStreamSize(subStreamIndex, &subStreamSize);
|
rlm@1
|
186 if (result == S_OK)
|
rlm@1
|
187 {
|
rlm@1
|
188 subStreamStartPos = subStreamEndPos;
|
rlm@1
|
189 subStreamEndPos += subStreamSize;
|
rlm@1
|
190 subStreamIndex++;
|
rlm@1
|
191 }
|
rlm@1
|
192 else if (result == S_FALSE || result == E_NOTIMPL)
|
rlm@1
|
193 {
|
rlm@1
|
194 getSubStreamSize.Release();
|
rlm@1
|
195 subStreamStartPos = 0;
|
rlm@1
|
196 subStreamEndPos = subStreamStartPos - 1;
|
rlm@1
|
197 }
|
rlm@1
|
198 else
|
rlm@1
|
199 return result;
|
rlm@1
|
200 }
|
rlm@1
|
201 if (getSubStreamSize == NULL)
|
rlm@1
|
202 {
|
rlm@1
|
203 if (sizeIsDefined)
|
rlm@1
|
204 convert = (dest < inSize);
|
rlm@1
|
205 else
|
rlm@1
|
206 convert = Test86MSByte(nextByte);
|
rlm@1
|
207 }
|
rlm@1
|
208 else if (subStreamEndPos - subStreamStartPos > kDefaultLimit)
|
rlm@1
|
209 convert = Test86MSByte(nextByte);
|
rlm@1
|
210 else
|
rlm@1
|
211 {
|
rlm@1
|
212 UInt64 dest64 = (currentPos + 5) + Int64(Int32(src));
|
rlm@1
|
213 convert = (dest64 >= subStreamStartPos && dest64 < subStreamEndPos);
|
rlm@1
|
214 }
|
rlm@1
|
215 }
|
rlm@1
|
216 else if (sizeIsDefined)
|
rlm@1
|
217 convert = (dest < inSize);
|
rlm@1
|
218 else
|
rlm@1
|
219 convert = Test86MSByte(nextByte);
|
rlm@1
|
220 unsigned index = GetIndex(prevByte, b);
|
rlm@1
|
221 if (convert)
|
rlm@1
|
222 {
|
rlm@1
|
223 _statusEncoder[index].Encode(&_rangeEncoder, 1);
|
rlm@1
|
224 bufferPos += 5;
|
rlm@1
|
225 COutBuffer &s = (b == 0xE8) ? _callStream : _jumpStream;
|
rlm@1
|
226 for (int i = 24; i >= 0; i -= 8)
|
rlm@1
|
227 s.WriteByte((Byte)(dest >> i));
|
rlm@1
|
228 prevByte = nextByte;
|
rlm@1
|
229 }
|
rlm@1
|
230 else
|
rlm@1
|
231 {
|
rlm@1
|
232 _statusEncoder[index].Encode(&_rangeEncoder, 0);
|
rlm@1
|
233 bufferPos++;
|
rlm@1
|
234 prevByte = b;
|
rlm@1
|
235 }
|
rlm@1
|
236 }
|
rlm@1
|
237 nowPos += bufferPos;
|
rlm@1
|
238 nowPos64 += bufferPos;
|
rlm@1
|
239
|
rlm@1
|
240 if (progress != NULL)
|
rlm@1
|
241 {
|
rlm@1
|
242 /*
|
rlm@1
|
243 const UInt64 compressedSize =
|
rlm@1
|
244 _mainStream.GetProcessedSize() +
|
rlm@1
|
245 _callStream.GetProcessedSize() +
|
rlm@1
|
246 _jumpStream.GetProcessedSize() +
|
rlm@1
|
247 _rangeEncoder.GetProcessedSize();
|
rlm@1
|
248 */
|
rlm@1
|
249 RINOK(progress->SetRatioInfo(&nowPos64, NULL));
|
rlm@1
|
250 }
|
rlm@1
|
251
|
rlm@1
|
252 UInt32 i = 0;
|
rlm@1
|
253 while(bufferPos < endPos)
|
rlm@1
|
254 _buffer[i++] = _buffer[bufferPos++];
|
rlm@1
|
255 bufferPos = i;
|
rlm@1
|
256 }
|
rlm@1
|
257 }
|
rlm@1
|
258
|
rlm@1
|
259 STDMETHODIMP CEncoder::Code(ISequentialInStream **inStreams,
|
rlm@1
|
260 const UInt64 **inSizes,
|
rlm@1
|
261 UInt32 numInStreams,
|
rlm@1
|
262 ISequentialOutStream **outStreams,
|
rlm@1
|
263 const UInt64 **outSizes,
|
rlm@1
|
264 UInt32 numOutStreams,
|
rlm@1
|
265 ICompressProgressInfo *progress)
|
rlm@1
|
266 {
|
rlm@1
|
267 try
|
rlm@1
|
268 {
|
rlm@1
|
269 return CodeReal(inStreams, inSizes, numInStreams,
|
rlm@1
|
270 outStreams, outSizes,numOutStreams, progress);
|
rlm@1
|
271 }
|
rlm@1
|
272 catch(const COutBufferException &e) { return e.ErrorCode; }
|
rlm@1
|
273 catch(...) { return S_FALSE; }
|
rlm@1
|
274 }
|
rlm@1
|
275
|
rlm@1
|
276 #endif
|
rlm@1
|
277
|
rlm@1
|
278 HRESULT CDecoder::CodeReal(ISequentialInStream **inStreams,
|
rlm@1
|
279 const UInt64 ** /* inSizes */,
|
rlm@1
|
280 UInt32 numInStreams,
|
rlm@1
|
281 ISequentialOutStream **outStreams,
|
rlm@1
|
282 const UInt64 ** /* outSizes */,
|
rlm@1
|
283 UInt32 numOutStreams,
|
rlm@1
|
284 ICompressProgressInfo *progress)
|
rlm@1
|
285 {
|
rlm@1
|
286 if (numInStreams != 4 || numOutStreams != 1)
|
rlm@1
|
287 return E_INVALIDARG;
|
rlm@1
|
288
|
rlm@1
|
289 if (!_mainInStream.Create(1 << 16))
|
rlm@1
|
290 return E_OUTOFMEMORY;
|
rlm@1
|
291 if (!_callStream.Create(1 << 20))
|
rlm@1
|
292 return E_OUTOFMEMORY;
|
rlm@1
|
293 if (!_jumpStream.Create(1 << 16))
|
rlm@1
|
294 return E_OUTOFMEMORY;
|
rlm@1
|
295 if (!_rangeDecoder.Create(1 << 20))
|
rlm@1
|
296 return E_OUTOFMEMORY;
|
rlm@1
|
297 if (!_outStream.Create(1 << 16))
|
rlm@1
|
298 return E_OUTOFMEMORY;
|
rlm@1
|
299
|
rlm@1
|
300 _mainInStream.SetStream(inStreams[0]);
|
rlm@1
|
301 _callStream.SetStream(inStreams[1]);
|
rlm@1
|
302 _jumpStream.SetStream(inStreams[2]);
|
rlm@1
|
303 _rangeDecoder.SetStream(inStreams[3]);
|
rlm@1
|
304 _outStream.SetStream(outStreams[0]);
|
rlm@1
|
305
|
rlm@1
|
306 _mainInStream.Init();
|
rlm@1
|
307 _callStream.Init();
|
rlm@1
|
308 _jumpStream.Init();
|
rlm@1
|
309 _rangeDecoder.Init();
|
rlm@1
|
310 _outStream.Init();
|
rlm@1
|
311
|
rlm@1
|
312 for (int i = 0; i < 256 + 2; i++)
|
rlm@1
|
313 _statusDecoder[i].Init();
|
rlm@1
|
314
|
rlm@1
|
315 CCoderReleaser releaser(this);
|
rlm@1
|
316
|
rlm@1
|
317 Byte prevByte = 0;
|
rlm@1
|
318 UInt32 processedBytes = 0;
|
rlm@1
|
319 for (;;)
|
rlm@1
|
320 {
|
rlm@1
|
321 if (processedBytes >= (1 << 20) && progress != NULL)
|
rlm@1
|
322 {
|
rlm@1
|
323 /*
|
rlm@1
|
324 const UInt64 compressedSize =
|
rlm@1
|
325 _mainInStream.GetProcessedSize() +
|
rlm@1
|
326 _callStream.GetProcessedSize() +
|
rlm@1
|
327 _jumpStream.GetProcessedSize() +
|
rlm@1
|
328 _rangeDecoder.GetProcessedSize();
|
rlm@1
|
329 */
|
rlm@1
|
330 const UInt64 nowPos64 = _outStream.GetProcessedSize();
|
rlm@1
|
331 RINOK(progress->SetRatioInfo(NULL, &nowPos64));
|
rlm@1
|
332 processedBytes = 0;
|
rlm@1
|
333 }
|
rlm@1
|
334 UInt32 i;
|
rlm@1
|
335 Byte b = 0;
|
rlm@1
|
336 const UInt32 kBurstSize = (1 << 18);
|
rlm@1
|
337 for (i = 0; i < kBurstSize; i++)
|
rlm@1
|
338 {
|
rlm@1
|
339 if (!_mainInStream.ReadByte(b))
|
rlm@1
|
340 return Flush();
|
rlm@1
|
341 _outStream.WriteByte(b);
|
rlm@1
|
342 if (IsJ(prevByte, b))
|
rlm@1
|
343 break;
|
rlm@1
|
344 prevByte = b;
|
rlm@1
|
345 }
|
rlm@1
|
346 processedBytes += i;
|
rlm@1
|
347 if (i == kBurstSize)
|
rlm@1
|
348 continue;
|
rlm@1
|
349 unsigned index = GetIndex(prevByte, b);
|
rlm@1
|
350 if (_statusDecoder[index].Decode(&_rangeDecoder) == 1)
|
rlm@1
|
351 {
|
rlm@1
|
352 UInt32 src = 0;
|
rlm@1
|
353 CInBuffer &s = (b == 0xE8) ? _callStream : _jumpStream;
|
rlm@1
|
354 for (int i = 0; i < 4; i++)
|
rlm@1
|
355 {
|
rlm@1
|
356 Byte b0;
|
rlm@1
|
357 if(!s.ReadByte(b0))
|
rlm@1
|
358 return S_FALSE;
|
rlm@1
|
359 src <<= 8;
|
rlm@1
|
360 src |= ((UInt32)b0);
|
rlm@1
|
361 }
|
rlm@1
|
362 UInt32 dest = src - (UInt32(_outStream.GetProcessedSize()) + 4) ;
|
rlm@1
|
363 _outStream.WriteByte((Byte)(dest));
|
rlm@1
|
364 _outStream.WriteByte((Byte)(dest >> 8));
|
rlm@1
|
365 _outStream.WriteByte((Byte)(dest >> 16));
|
rlm@1
|
366 _outStream.WriteByte((Byte)(dest >> 24));
|
rlm@1
|
367 prevByte = (Byte)(dest >> 24);
|
rlm@1
|
368 processedBytes += 4;
|
rlm@1
|
369 }
|
rlm@1
|
370 else
|
rlm@1
|
371 prevByte = b;
|
rlm@1
|
372 }
|
rlm@1
|
373 }
|
rlm@1
|
374
|
rlm@1
|
375 STDMETHODIMP CDecoder::Code(ISequentialInStream **inStreams,
|
rlm@1
|
376 const UInt64 **inSizes,
|
rlm@1
|
377 UInt32 numInStreams,
|
rlm@1
|
378 ISequentialOutStream **outStreams,
|
rlm@1
|
379 const UInt64 **outSizes,
|
rlm@1
|
380 UInt32 numOutStreams,
|
rlm@1
|
381 ICompressProgressInfo *progress)
|
rlm@1
|
382 {
|
rlm@1
|
383 try
|
rlm@1
|
384 {
|
rlm@1
|
385 return CodeReal(inStreams, inSizes, numInStreams,
|
rlm@1
|
386 outStreams, outSizes,numOutStreams, progress);
|
rlm@1
|
387 }
|
rlm@1
|
388 catch(const CInBufferException &e) { return e.ErrorCode; }
|
rlm@1
|
389 catch(const COutBufferException &e) { return e.ErrorCode; }
|
rlm@1
|
390 catch(...) { return S_FALSE; }
|
rlm@1
|
391 }
|
rlm@1
|
392
|
rlm@1
|
393 }}
|