| OLD | NEW |
| (Empty) |
| 1 // Bcj2Coder.cpp | |
| 2 | |
| 3 #include "StdAfx.h" | |
| 4 | |
| 5 extern "C" | |
| 6 { | |
| 7 #include "../../../C/Alloc.h" | |
| 8 } | |
| 9 | |
| 10 #include "Bcj2Coder.h" | |
| 11 | |
| 12 namespace NCompress { | |
| 13 namespace NBcj2 { | |
| 14 | |
| 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)); } | |
| 18 | |
| 19 #ifndef EXTRACT_ONLY | |
| 20 | |
| 21 static const int kBufferSize = 1 << 17; | |
| 22 | |
| 23 static bool inline Test86MSByte(Byte b) | |
| 24 { | |
| 25 return (b == 0 || b == 0xFF); | |
| 26 } | |
| 27 | |
| 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 } | |
| 46 | |
| 47 CEncoder::~CEncoder() | |
| 48 { | |
| 49 ::MidFree(_buffer); | |
| 50 } | |
| 51 | |
| 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 } | |
| 60 | |
| 61 const UInt32 kDefaultLimit = (1 << 24); | |
| 62 | |
| 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; | |
| 73 | |
| 74 if (!Create()) | |
| 75 return E_OUTOFMEMORY; | |
| 76 | |
| 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 } | |
| 86 | |
| 87 ISequentialInStream *inStream = inStreams[0]; | |
| 88 | |
| 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); | |
| 100 | |
| 101 CMyComPtr<ICompressGetSubStreamSize> getSubStreamSize; | |
| 102 { | |
| 103 inStream->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStre
amSize); | |
| 104 } | |
| 105 | |
| 106 UInt32 nowPos = 0; | |
| 107 UInt64 nowPos64 = 0; | |
| 108 UInt32 bufferPos = 0; | |
| 109 | |
| 110 Byte prevByte = 0; | |
| 111 | |
| 112 UInt64 subStreamIndex = 0; | |
| 113 UInt64 subStreamStartPos = 0; | |
| 114 UInt64 subStreamEndPos = 0; | |
| 115 | |
| 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, &processed
SizeLoc)); | |
| 126 if (processedSizeLoc == 0) | |
| 127 break; | |
| 128 processedSize += processedSizeLoc; | |
| 129 } | |
| 130 UInt32 endPos = bufferPos + processedSize; | |
| 131 | |
| 132 if (endPos < 5) | |
| 133 { | |
| 134 // change it | |
| 135 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 else | |
| 147 { | |
| 148 prevByte = b; | |
| 149 continue; | |
| 150 } | |
| 151 _statusEncoder[index].Encode(&_rangeEncoder, 0); | |
| 152 prevByte = b; | |
| 153 } | |
| 154 return Flush(); | |
| 155 } | |
| 156 | |
| 157 bufferPos = 0; | |
| 158 | |
| 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, &s
ubStreamSize); | |
| 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 else | |
| 199 return result; | |
| 200 } | |
| 201 if (getSubStreamSize == NULL) | |
| 202 { | |
| 203 if (sizeIsDefined) | |
| 204 convert = (dest < inSize); | |
| 205 else | |
| 206 convert = Test86MSByte(nextByte); | |
| 207 } | |
| 208 else if (subStreamEndPos - subStreamStartPos > kDefaultLimit) | |
| 209 convert = Test86MSByte(nextByte); | |
| 210 else | |
| 211 { | |
| 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 else | |
| 219 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 else | |
| 231 { | |
| 232 _statusEncoder[index].Encode(&_rangeEncoder, 0); | |
| 233 bufferPos++; | |
| 234 prevByte = b; | |
| 235 } | |
| 236 } | |
| 237 nowPos += bufferPos; | |
| 238 nowPos64 += bufferPos; | |
| 239 | |
| 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 } | |
| 251 | |
| 252 UInt32 i = 0; | |
| 253 while(bufferPos < endPos) | |
| 254 _buffer[i++] = _buffer[bufferPos++]; | |
| 255 bufferPos = i; | |
| 256 } | |
| 257 } | |
| 258 | |
| 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 try | |
| 268 { | |
| 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 } | |
| 275 | |
| 276 #endif | |
| 277 | |
| 278 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; | |
| 288 | |
| 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; | |
| 299 | |
| 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]); | |
| 305 | |
| 306 _mainInStream.Init(); | |
| 307 _callStream.Init(); | |
| 308 _jumpStream.Init(); | |
| 309 _rangeDecoder.Init(); | |
| 310 _outStream.Init(); | |
| 311 | |
| 312 for (int i = 0; i < 256 + 2; i++) | |
| 313 _statusDecoder[i].Init(); | |
| 314 | |
| 315 CCoderReleaser releaser(this); | |
| 316 | |
| 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 else | |
| 371 prevByte = b; | |
| 372 } | |
| 373 } | |
| 374 | |
| 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 try | |
| 384 { | |
| 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 } | |
| 392 | |
| 393 }} | |
| OLD | NEW |