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