8 #include "../../../../C/Alloc.h"
14 inline bool IsJcc(Byte b0, Byte b1) { return (b0 == 0x0F && (b1 & 0xF0) == 0x80); }
15 inline bool IsJ(Byte b0, Byte b1) { return ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1)); }
16 inline unsigned GetIndex(Byte b0, Byte b1) { return ((b1 == 0xE8) ? b0 : ((b1 == 0xE9) ? 256 : 257)); }
20 static const int kBufferSize = 1 << 17;
22 static bool inline Test86MSByte(Byte b)
24 return (b == 0 || b == 0xFF);
27 bool CEncoder::Create()
29 if (!_mainStream.Create(1 << 16))
31 if (!_callStream.Create(1 << 20))
33 if (!_jumpStream.Create(1 << 20))
35 if (!_rangeEncoder.Create(1 << 20))
39 _buffer = (Byte *)MidAlloc(kBufferSize);
51 HRESULT CEncoder::Flush()
53 RINOK(_mainStream.Flush());
54 RINOK(_callStream.Flush());
55 RINOK(_jumpStream.Flush());
56 _rangeEncoder.FlushData();
57 return _rangeEncoder.FlushStream();
60 const UInt32 kDefaultLimit = (1 << 24);
62 HRESULT CEncoder::CodeReal(ISequentialInStream **inStreams,
63 const UInt64 **inSizes,
65 ISequentialOutStream **outStreams,
66 const UInt64 ** /* outSizes */,
68 ICompressProgressInfo *progress)
70 if (numInStreams != 1 || numOutStreams != 4)
76 bool sizeIsDefined = false;
79 if (inSizes[0] != NULL)
82 if (inSize <= kDefaultLimit)
86 ISequentialInStream *inStream = inStreams[0];
88 _mainStream.SetStream(outStreams[0]);
90 _callStream.SetStream(outStreams[1]);
92 _jumpStream.SetStream(outStreams[2]);
94 _rangeEncoder.SetStream(outStreams[3]);
96 for (int i = 0; i < 256 + 2; i++)
97 _statusEncoder[i].Init();
98 CCoderReleaser releaser(this);
100 CMyComPtr<ICompressGetSubStreamSize> getSubStreamSize;
102 inStream->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize);
107 UInt32 bufferPos = 0;
111 UInt64 subStreamIndex = 0;
112 UInt64 subStreamStartPos = 0;
113 UInt64 subStreamEndPos = 0;
117 UInt32 processedSize = 0;
120 UInt32 size = kBufferSize - (bufferPos + processedSize);
121 UInt32 processedSizeLoc;
124 RINOK(inStream->Read(_buffer + bufferPos + processedSize, size, &processedSizeLoc));
125 if (processedSizeLoc == 0)
127 processedSize += processedSizeLoc;
129 UInt32 endPos = bufferPos + processedSize;
134 for (bufferPos = 0; bufferPos < endPos; bufferPos++)
136 Byte b = _buffer[bufferPos];
137 _mainStream.WriteByte(b);
143 else if (IsJcc(prevByte, b))
150 _statusEncoder[index].Encode(&_rangeEncoder, 0);
158 UInt32 limit = endPos - 5;
159 while(bufferPos <= limit)
161 Byte b = _buffer[bufferPos];
162 _mainStream.WriteByte(b);
163 if (!IsJ(prevByte, b))
169 Byte nextByte = _buffer[bufferPos + 4];
171 (UInt32(nextByte) << 24) |
172 (UInt32(_buffer[bufferPos + 3]) << 16) |
173 (UInt32(_buffer[bufferPos + 2]) << 8) |
174 (_buffer[bufferPos + 1]);
175 UInt32 dest = (nowPos + bufferPos + 5) + src;
176 // if (Test86MSByte(nextByte))
178 if (getSubStreamSize != NULL)
180 UInt64 currentPos = (nowPos64 + bufferPos);
181 while (subStreamEndPos < currentPos)
183 UInt64 subStreamSize;
184 HRESULT result = getSubStreamSize->GetSubStreamSize(subStreamIndex, &subStreamSize);
187 subStreamStartPos = subStreamEndPos;
188 subStreamEndPos += subStreamSize;
191 else if (result == S_FALSE || result == E_NOTIMPL)
193 getSubStreamSize.Release();
194 subStreamStartPos = 0;
195 subStreamEndPos = subStreamStartPos - 1;
200 if (getSubStreamSize == NULL)
203 convert = (dest < inSize);
205 convert = Test86MSByte(nextByte);
207 else if (subStreamEndPos - subStreamStartPos > kDefaultLimit)
208 convert = Test86MSByte(nextByte);
211 UInt64 dest64 = (currentPos + 5) + Int64(Int32(src));
212 convert = (dest64 >= subStreamStartPos && dest64 < subStreamEndPos);
215 else if (sizeIsDefined)
216 convert = (dest < inSize);
218 convert = Test86MSByte(nextByte);
219 unsigned index = GetIndex(prevByte, b);
222 _statusEncoder[index].Encode(&_rangeEncoder, 1);
224 COutBuffer &s = (b == 0xE8) ? _callStream : _jumpStream;
225 for (int i = 24; i >= 0; i -= 8)
226 s.WriteByte((Byte)(dest >> i));
231 _statusEncoder[index].Encode(&_rangeEncoder, 0);
237 nowPos64 += bufferPos;
239 if (progress != NULL)
242 const UInt64 compressedSize =
243 _mainStream.GetProcessedSize() +
244 _callStream.GetProcessedSize() +
245 _jumpStream.GetProcessedSize() +
246 _rangeEncoder.GetProcessedSize();
248 RINOK(progress->SetRatioInfo(&nowPos64, NULL));
252 while(bufferPos < endPos)
253 _buffer[i++] = _buffer[bufferPos++];
258 STDMETHODIMP CEncoder::Code(ISequentialInStream **inStreams,
259 const UInt64 **inSizes,
261 ISequentialOutStream **outStreams,
262 const UInt64 **outSizes,
263 UInt32 numOutStreams,
264 ICompressProgressInfo *progress)
268 return CodeReal(inStreams, inSizes, numInStreams,
269 outStreams, outSizes,numOutStreams, progress);
271 catch(const COutBufferException &e) { return e.ErrorCode; }
272 catch(...) { return S_FALSE; }
277 HRESULT CDecoder::CodeReal(ISequentialInStream **inStreams,
278 const UInt64 ** /* inSizes */,
280 ISequentialOutStream **outStreams,
281 const UInt64 ** /* outSizes */,
282 UInt32 numOutStreams,
283 ICompressProgressInfo *progress)
285 if (numInStreams != 4 || numOutStreams != 1)
288 if (!_mainInStream.Create(1 << 16))
289 return E_OUTOFMEMORY;
290 if (!_callStream.Create(1 << 20))
291 return E_OUTOFMEMORY;
292 if (!_jumpStream.Create(1 << 16))
293 return E_OUTOFMEMORY;
294 if (!_rangeDecoder.Create(1 << 20))
295 return E_OUTOFMEMORY;
296 if (!_outStream.Create(1 << 16))
297 return E_OUTOFMEMORY;
299 _mainInStream.SetStream(inStreams[0]);
300 _callStream.SetStream(inStreams[1]);
301 _jumpStream.SetStream(inStreams[2]);
302 _rangeDecoder.SetStream(inStreams[3]);
303 _outStream.SetStream(outStreams[0]);
305 _mainInStream.Init();
308 _rangeDecoder.Init();
311 for (int i = 0; i < 256 + 2; i++)
312 _statusDecoder[i].Init();
314 CCoderReleaser releaser(this);
317 UInt32 processedBytes = 0;
320 if (processedBytes >= (1 << 20) && progress != NULL)
323 const UInt64 compressedSize =
324 _mainInStream.GetProcessedSize() +
325 _callStream.GetProcessedSize() +
326 _jumpStream.GetProcessedSize() +
327 _rangeDecoder.GetProcessedSize();
329 const UInt64 nowPos64 = _outStream.GetProcessedSize();
330 RINOK(progress->SetRatioInfo(NULL, &nowPos64));
335 const UInt32 kBurstSize = (1 << 18);
336 for (i = 0; i < kBurstSize; i++)
338 if (!_mainInStream.ReadByte(b))
340 _outStream.WriteByte(b);
341 if (IsJ(prevByte, b))
348 unsigned index = GetIndex(prevByte, b);
349 if (_statusDecoder[index].Decode(&_rangeDecoder) == 1)
352 CInBuffer &s = (b == 0xE8) ? _callStream : _jumpStream;
353 for (int i = 0; i < 4; i++)
361 UInt32 dest = src - (UInt32(_outStream.GetProcessedSize()) + 4) ;
362 _outStream.WriteByte((Byte)(dest));
363 _outStream.WriteByte((Byte)(dest >> 8));
364 _outStream.WriteByte((Byte)(dest >> 16));
365 _outStream.WriteByte((Byte)(dest >> 24));
366 prevByte = (Byte)(dest >> 24);
374 STDMETHODIMP CDecoder::Code(ISequentialInStream **inStreams,
375 const UInt64 **inSizes,
377 ISequentialOutStream **outStreams,
378 const UInt64 **outSizes,
379 UInt32 numOutStreams,
380 ICompressProgressInfo *progress)
384 return CodeReal(inStreams, inSizes, numInStreams,
385 outStreams, outSizes,numOutStreams, progress);
387 catch(const CInBufferException &e) { return e.ErrorCode; }
388 catch(const COutBufferException &e) { return e.ErrorCode; }
389 catch(...) { return S_FALSE; }