Files
easy7zip/CPP/7zip/Compress/Rar/Rar3Vm.h
Igor Pavlov d9666cf046 4.44 beta
2016-05-28 00:15:49 +01:00

220 lines
5.7 KiB
C++
Executable File

// Rar3Vm.h
// According to unRAR license,
// this code may not be used to develop a
// RAR (WinRAR) compatible archiver
#ifndef __RAR3VM_H
#define __RAR3VM_H
#include "Common/Types.h"
#include "Common/Vector.h"
#define RARVM_STANDARD_FILTERS
#if defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || defined(__i386__) || defined(__x86_64__) // || defined(_M_IA64) || defined(__ia64__)
// Define RARVM_LITTLE_ENDIAN_UNALIGN, if CPU is LITTLE_ENDIAN and if it supports
// unaligned 32-bit memory accesses.
// It's for speed optimization, if you are not sure, just don't define it.
#define RARVM_LITTLE_ENDIAN_UNALIGN
#endif
namespace NCompress {
namespace NRar3 {
class CMemBitDecoder
{
const Byte *_data;
UInt32 _bitSize;
UInt32 _bitPos;
public:
void Init(const Byte *data, UInt32 byteSize)
{
_data = data;
_bitSize = (byteSize << 3);
_bitPos = 0;
}
UInt32 ReadBits(int numBits);
UInt32 ReadBit();
bool Avail() const { return (_bitPos < _bitSize); }
};
namespace NVm {
inline UInt32 GetValue32(const void *addr)
{
#ifdef RARVM_LITTLE_ENDIAN_UNALIGN
return *(const UInt32 *)addr;
#else
const Byte *b = (const Byte *)addr;
return UInt32((UInt32)b[0]|((UInt32)b[1]<<8)|((UInt32)b[2]<<16)|((UInt32)b[3]<<24));
#endif
}
inline void SetValue32(void *addr, UInt32 value)
{
#ifdef RARVM_LITTLE_ENDIAN_UNALIGN
*(UInt32 *)addr = value;
#else
((Byte *)addr)[0] = (Byte)value;
((Byte *)addr)[1] = (Byte)(value >> 8);
((Byte *)addr)[2] = (Byte)(value >> 16);
((Byte *)addr)[3] = (Byte)(value >> 24);
#endif
}
UInt32 ReadEncodedUInt32(CMemBitDecoder &inp);
const int kNumRegBits = 3;
const UInt32 kNumRegs = 1 << kNumRegBits;
const UInt32 kNumGpRegs = kNumRegs - 1;
const UInt32 kSpaceSize = 0x40000;
const UInt32 kSpaceMask = kSpaceSize -1;
const UInt32 kGlobalOffset = 0x3C000;
const UInt32 kGlobalSize = 0x2000;
const UInt32 kFixedGlobalSize = 64;
namespace NGlobalOffset
{
const UInt32 kBlockSize = 0x1C;
const UInt32 kBlockPos = 0x20;
const UInt32 kExecCount = 0x2C;
const UInt32 kGlobalMemOutSize = 0x30;
};
enum ECommand
{
CMD_MOV, CMD_CMP, CMD_ADD, CMD_SUB, CMD_JZ, CMD_JNZ, CMD_INC, CMD_DEC,
CMD_JMP, CMD_XOR, CMD_AND, CMD_OR, CMD_TEST, CMD_JS, CMD_JNS, CMD_JB,
CMD_JBE, CMD_JA, CMD_JAE, CMD_PUSH, CMD_POP, CMD_CALL, CMD_RET, CMD_NOT,
CMD_SHL, CMD_SHR, CMD_SAR, CMD_NEG, CMD_PUSHA,CMD_POPA, CMD_PUSHF,CMD_POPF,
CMD_MOVZX,CMD_MOVSX,CMD_XCHG, CMD_MUL, CMD_DIV, CMD_ADC, CMD_SBB, CMD_PRINT,
CMD_MOVB, CMD_CMPB, CMD_ADDB, CMD_SUBB, CMD_INCB, CMD_DECB,
CMD_XORB, CMD_ANDB, CMD_ORB, CMD_TESTB,CMD_NEGB,
CMD_SHLB, CMD_SHRB, CMD_SARB, CMD_MULB
};
enum EOpType {OP_TYPE_REG, OP_TYPE_INT, OP_TYPE_REGMEM, OP_TYPE_NONE};
// Addr in COperand object can link (point) to CVm object!!!
struct COperand
{
EOpType Type;
UInt32 Data;
UInt32 Base;
COperand(): Type(OP_TYPE_NONE), Data(0), Base(0) {}
};
struct CCommand
{
ECommand OpCode;
bool ByteMode;
COperand Op1, Op2;
};
struct CBlockRef
{
UInt32 Offset;
UInt32 Size;
};
struct CProgram
{
CRecordVector<CCommand> Commands;
#ifdef RARVM_STANDARD_FILTERS
int StandardFilterIndex;
#endif
CRecordVector<Byte> StaticData;
};
struct CProgramInitState
{
UInt32 InitR[kNumGpRegs];
CRecordVector<Byte> GlobalData;
void AllocateEmptyFixedGlobal()
{
GlobalData.Clear();
GlobalData.Reserve(NVm::kFixedGlobalSize);
for (UInt32 i = 0; i < NVm::kFixedGlobalSize; i++)
GlobalData.Add(0);
}
};
class CVm
{
static UInt32 GetValue(bool byteMode, const void *addr)
{
if (byteMode)
return(*(const Byte *)addr);
else
{
#ifdef RARVM_LITTLE_ENDIAN_UNALIGN
return *(const UInt32 *)addr;
#else
const Byte *b = (const Byte *)addr;
return UInt32((UInt32)b[0]|((UInt32)b[1]<<8)|((UInt32)b[2]<<16)|((UInt32)b[3]<<24));
#endif
}
}
static void SetValue(bool byteMode, void *addr, UInt32 value)
{
if (byteMode)
*(Byte *)addr = (Byte)value;
else
{
#ifdef RARVM_LITTLE_ENDIAN_UNALIGN
*(UInt32 *)addr = value;
#else
((Byte *)addr)[0] = (Byte)value;
((Byte *)addr)[1] = (Byte)(value >> 8);
((Byte *)addr)[2] = (Byte)(value >> 16);
((Byte *)addr)[3] = (Byte)(value >> 24);
#endif
}
}
UInt32 GetFixedGlobalValue32(UInt32 globalOffset) { return GetValue(false, &Mem[kGlobalOffset + globalOffset]); }
void SetBlockSize(UInt32 v) { SetValue(&Mem[kGlobalOffset + NGlobalOffset::kBlockSize], v); }
void SetBlockPos(UInt32 v) { SetValue(&Mem[kGlobalOffset + NGlobalOffset::kBlockPos], v); }
public:
static void SetValue(void *addr, UInt32 value) { SetValue(false, addr, value); }
private:
UInt32 GetOperand32(const COperand *op) const;
void SetOperand32(const COperand *op, UInt32 val);
Byte GetOperand8(const COperand *op) const;
void SetOperand8(const COperand *op, Byte val);
UInt32 GetOperand(bool byteMode, const COperand *op) const;
void SetOperand(bool byteMode, const COperand *op, UInt32 val);
void DecodeArg(CMemBitDecoder &inp, COperand &op, bool byteMode);
bool ExecuteCode(const CProgram *prg);
#ifdef RARVM_STANDARD_FILTERS
void ExecuteStandardFilter(int filterIndex);
#endif
Byte *Mem;
UInt32 R[kNumRegs + 1]; // R[kNumRegs] = 0 always (speed optimization)
UInt32 Flags;
void ReadVmProgram(const Byte *code, UInt32 codeSize, CProgram *prg);
public:
CVm();
~CVm();
bool Create();
void PrepareProgram(const Byte *code, UInt32 codeSize, CProgram *prg);
void SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize);
bool Execute(CProgram *prg, const CProgramInitState *initState,
CBlockRef &outBlockRef, CRecordVector<Byte> &outGlobalData);
const Byte *GetDataPointer(UInt32 offset) const { return Mem + offset; }
};
#endif
}}}