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