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