1baa3858d3f5d128a5c8466b700098109edcad5f2repo sync/* Bcj2.c -- Converter for x86 code (BCJ2)
2baa3858d3f5d128a5c8466b700098109edcad5f2repo sync2008-10-04 : Igor Pavlov : Public domain */
3baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
4baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#include "Bcj2.h"
5baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
6baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#ifdef _LZMA_PROB32
7baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define CProb UInt32
8baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#else
9baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define CProb UInt16
10baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#endif
11baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
12baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define IsJcc(b0, b1) ((b0) == 0x0F && ((b1) & 0xF0) == 0x80)
13baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define IsJ(b0, b1) ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1))
14baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
15baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define kNumTopBits 24
16baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define kTopValue ((UInt32)1 << kNumTopBits)
17baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
18baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define kNumBitModelTotalBits 11
19baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define kBitModelTotal (1 << kNumBitModelTotalBits)
20baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define kNumMoveBits 5
21baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
22baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define RC_READ_BYTE (*buffer++)
23baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; }
24baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define RC_INIT2 code = 0; range = 0xFFFFFFFF; \
25baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  { int i; for (i = 0; i < 5; i++) { RC_TEST; code = (code << 8) | RC_READ_BYTE; }}
26baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
27baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define NORMALIZE if (range < kTopValue) { RC_TEST; range <<= 8; code = (code << 8) | RC_READ_BYTE; }
28baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
29baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define IF_BIT_0(p) ttt = *(p); bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
30baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define UPDATE_0(p) range = bound; *(p) = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); NORMALIZE;
31baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CProb)(ttt - (ttt >> kNumMoveBits)); NORMALIZE;
32baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
33baa3858d3f5d128a5c8466b700098109edcad5f2repo syncint Bcj2_Decode(
34baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    const Byte *buf0, SizeT size0,
35baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    const Byte *buf1, SizeT size1,
36baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    const Byte *buf2, SizeT size2,
37baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    const Byte *buf3, SizeT size3,
38baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    Byte *outBuf, SizeT outSize)
39baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
40baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  CProb p[256 + 2];
41baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  SizeT inPos = 0, outPos = 0;
42baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
43baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  const Byte *buffer, *bufferLim;
44baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  UInt32 range, code;
45baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  Byte prevByte = 0;
46baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
47baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  unsigned int i;
48baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  for (i = 0; i < sizeof(p) / sizeof(p[0]); i++)
49baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    p[i] = kBitModelTotal >> 1;
50baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
51baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  buffer = buf3;
52baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  bufferLim = buffer + size3;
53baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  RC_INIT2
54baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
55baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  if (outSize == 0)
56baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    return SZ_OK;
57baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
58baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  for (;;)
59baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  {
60baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    Byte b;
61baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    CProb *prob;
62baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    UInt32 bound;
63baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    UInt32 ttt;
64baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
65baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    SizeT limit = size0 - inPos;
66baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    if (outSize - outPos < limit)
67baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      limit = outSize - outPos;
68baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    while (limit != 0)
69baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    {
70baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      Byte b = buf0[inPos];
71baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      outBuf[outPos++] = b;
72baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      if (IsJ(prevByte, b))
73baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        break;
74baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      inPos++;
75baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      prevByte = b;
76baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      limit--;
77baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    }
78baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
79baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    if (limit == 0 || outPos == outSize)
80baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      break;
81baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
82baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    b = buf0[inPos++];
83baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
84baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    if (b == 0xE8)
85baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      prob = p + prevByte;
86baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    else if (b == 0xE9)
87baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      prob = p + 256;
88baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    else
89baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      prob = p + 257;
90baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
91baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    IF_BIT_0(prob)
92baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    {
93baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      UPDATE_0(prob)
94baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      prevByte = b;
95baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    }
96baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    else
97baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    {
98baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      UInt32 dest;
99baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      const Byte *v;
100baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      UPDATE_1(prob)
101baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      if (b == 0xE8)
102baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      {
103baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        v = buf1;
104baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        if (size1 < 4)
105baa3858d3f5d128a5c8466b700098109edcad5f2repo sync          return SZ_ERROR_DATA;
106baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        buf1 += 4;
107baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        size1 -= 4;
108baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      }
109baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      else
110baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      {
111baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        v = buf2;
112baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        if (size2 < 4)
113baa3858d3f5d128a5c8466b700098109edcad5f2repo sync          return SZ_ERROR_DATA;
114baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        buf2 += 4;
115baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        size2 -= 4;
116baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      }
117baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      dest = (((UInt32)v[0] << 24) | ((UInt32)v[1] << 16) |
118baa3858d3f5d128a5c8466b700098109edcad5f2repo sync          ((UInt32)v[2] << 8) | ((UInt32)v[3])) - ((UInt32)outPos + 4);
119baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      outBuf[outPos++] = (Byte)dest;
120baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      if (outPos == outSize)
121baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        break;
122baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      outBuf[outPos++] = (Byte)(dest >> 8);
123baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      if (outPos == outSize)
124baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        break;
125baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      outBuf[outPos++] = (Byte)(dest >> 16);
126baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      if (outPos == outSize)
127baa3858d3f5d128a5c8466b700098109edcad5f2repo sync        break;
128baa3858d3f5d128a5c8466b700098109edcad5f2repo sync      outBuf[outPos++] = prevByte = (Byte)(dest >> 24);
129baa3858d3f5d128a5c8466b700098109edcad5f2repo sync    }
130baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  }
131baa3858d3f5d128a5c8466b700098109edcad5f2repo sync  return (outPos == outSize) ? SZ_OK : SZ_ERROR_DATA;
132baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
133