x86_2.cpp 9.9 KB

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