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