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