misc/libphysfs/lzma/CPP/7zip/Compress/Branch/x86_2.cpp
changeset 13881 99b265e0d1d0
parent 13880 5f819b90d479
child 13882 b172a5d40eee
equal deleted inserted replaced
13880:5f819b90d479 13881:99b265e0d1d0
     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 }}