Source code

Revision control

Copy as Markdown

Other Tools

/* Bcj2.c -- BCJ2 Decoder (Converter for x86 code)↩
2018-04-28 : Igor Pavlov : Public domain */
#include "Precomp.h"
#include "Bcj2.h"
#include "CpuArch.h"
#define CProb UInt16↩
#define kTopValue ((UInt32)1 << 24)↩
#define kNumModelBits 11↩
#define kBitModelTotal (1 << kNumModelBits)↩
#define kNumMoveBits 5↩
#define _IF_BIT_0 ttt = *prob; bound = (p->range >> kNumModelBits) * ttt; if (p->code < bound)↩
#define _UPDATE_0 p->range = bound; *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));↩
#define _UPDATE_1 p->range -= bound; p->code -= bound; *prob = (CProb)(ttt - (ttt >> kNumMoveBits));↩
void Bcj2Dec_Init(CBcj2Dec *p)↩
{↩
unsigned i;↩
p->state = BCJ2_DEC_STATE_OK;↩
p->ip = 0;↩
p->temp[3] = 0;↩
p->range = 0;↩
p->code = 0;↩
for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++)↩
p->probs[i] = kBitModelTotal >> 1;↩
}↩
SRes Bcj2Dec_Decode(CBcj2Dec *p)↩
{↩
if (p->range <= 5)↩
{↩
p->state = BCJ2_DEC_STATE_OK;↩
for (; p->range != 5; p->range++)↩
{↩
if (p->range == 1 && p->code != 0)↩
return SZ_ERROR_DATA;↩
if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC])↩
{↩
p->state = BCJ2_STREAM_RC;↩
return SZ_OK;↩
}↩
p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;↩
}↩
if (p->code == 0xFFFFFFFF)↩
return SZ_ERROR_DATA;↩
p->range = 0xFFFFFFFF;↩
}↩
else if (p->state >= BCJ2_DEC_STATE_ORIG_0)↩
{↩
while (p->state <= BCJ2_DEC_STATE_ORIG_3)↩
{↩
Byte *dest = p->dest;↩
if (dest == p->destLim)↩
return SZ_OK;↩
*dest = p->temp[(size_t)p->state - BCJ2_DEC_STATE_ORIG_0];↩
p->state++;↩
p->dest = dest + 1;↩
}↩
}↩
/*↩
if (BCJ2_IS_32BIT_STREAM(p->state))↩
{↩
const Byte *cur = p->bufs[p->state];↩
if (cur == p->lims[p->state])↩
return SZ_OK;↩
p->bufs[p->state] = cur + 4;↩
{↩
UInt32 val;↩
Byte *dest;↩
SizeT rem;↩
p->ip += 4;↩
val = GetBe32(cur) - p->ip;↩
dest = p->dest;↩
rem = p->destLim - dest;↩
if (rem < 4)↩
{↩
SizeT i;↩
SetUi32(p->temp, val);↩
for (i = 0; i < rem; i++)↩
dest[i] = p->temp[i];↩
p->dest = dest + rem;↩
p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem;↩
return SZ_OK;↩
}↩
SetUi32(dest, val);↩
p->temp[3] = (Byte)(val >> 24);↩
p->dest = dest + 4;↩
p->state = BCJ2_DEC_STATE_OK;↩
}↩
}↩
*/
for (;;)↩
{↩
if (BCJ2_IS_32BIT_STREAM(p->state))↩
p->state = BCJ2_DEC_STATE_OK;↩
else
{↩
if (p->range < kTopValue)↩
{↩
if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC])↩
{↩
p->state = BCJ2_STREAM_RC;↩
return SZ_OK;↩
}↩
p->range <<= 8;↩
p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;↩
}↩
{↩
const Byte *src = p->bufs[BCJ2_STREAM_MAIN];↩
const Byte *srcLim;↩
Byte *dest;↩
SizeT num = p->lims[BCJ2_STREAM_MAIN] - src;↩
if (num == 0)↩
{↩
p->state = BCJ2_STREAM_MAIN;↩
return SZ_OK;↩
}↩
dest = p->dest;↩
if (num > (SizeT)(p->destLim - dest))↩
{↩
num = p->destLim - dest;↩
if (num == 0)↩
{↩
p->state = BCJ2_DEC_STATE_ORIG;↩
return SZ_OK;↩
}↩
}↩
srcLim = src + num;↩
if (p->temp[3] == 0x0F && (src[0] & 0xF0) == 0x80)↩
*dest = src[0];↩
else for (;;)↩
{↩
Byte b = *src;↩
*dest = b;↩
if (b != 0x0F)↩
{↩
if ((b & 0xFE) == 0xE8)↩
break;↩
dest++;↩
if (++src != srcLim)↩
continue;↩
break;↩
}↩
dest++;↩
if (++src == srcLim)↩
break;↩
if ((*src & 0xF0) != 0x80)↩
continue;↩
*dest = *src;↩
break;↩
}↩
num = src - p->bufs[BCJ2_STREAM_MAIN];↩
if (src == srcLim)↩
{↩
p->temp[3] = src[-1];↩
p->bufs[BCJ2_STREAM_MAIN] = src;↩
p->ip += (UInt32)num;↩
p->dest += num;↩
p->state =↩
p->bufs[BCJ2_STREAM_MAIN] ==↩
p->lims[BCJ2_STREAM_MAIN] ?↩
(unsigned)BCJ2_STREAM_MAIN :↩
(unsigned)BCJ2_DEC_STATE_ORIG;↩
return SZ_OK;↩
}↩
{↩
UInt32 bound, ttt;↩
CProb *prob;↩
Byte b = src[0];↩
Byte prev = (Byte)(num == 0 ? p->temp[3] : src[-1]);↩
p->temp[3] = b;↩
p->bufs[BCJ2_STREAM_MAIN] = src + 1;↩
num++;↩
p->ip += (UInt32)num;↩
p->dest += num;↩
prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)prev : (b == 0xE9 ? 1 : 0));↩
_IF_BIT_0↩
{↩
_UPDATE_0↩
continue;↩
}↩
_UPDATE_1↩
}↩
}↩
}↩
{↩
UInt32 val;↩
unsigned cj = (p->temp[3] == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP;↩
const Byte *cur = p->bufs[cj];↩
Byte *dest;↩
SizeT rem;↩
if (cur == p->lims[cj])↩
{↩
p->state = cj;↩
break;↩
}↩
val = GetBe32(cur);↩
p->bufs[cj] = cur + 4;↩
p->ip += 4;↩
val -= p->ip;↩
dest = p->dest;↩
rem = p->destLim - dest;↩
if (rem < 4)↩
{↩
p->temp[0] = (Byte)val; if (rem > 0) dest[0] = (Byte)val; val >>= 8;↩
p->temp[1] = (Byte)val; if (rem > 1) dest[1] = (Byte)val; val >>= 8;↩
p->temp[2] = (Byte)val; if (rem > 2) dest[2] = (Byte)val; val >>= 8;↩
p->temp[3] = (Byte)val;↩
p->dest = dest + rem;↩
p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem;↩
break;↩
}↩
SetUi32(dest, val);↩
p->temp[3] = (Byte)(val >> 24);↩
p->dest = dest + 4;↩
}↩
}↩
if (p->range < kTopValue && p->bufs[BCJ2_STREAM_RC] != p->lims[BCJ2_STREAM_RC])↩
{↩
p->range <<= 8;↩
p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;↩
}↩
return SZ_OK;↩
}↩