Welcome to mirror list, hosted at ThFree Co, Russian Federation.

Rar3Vm.h « Rar « Compress « 7zip « CPP - github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: d0a4f82cdabeeb405e93a117362751e1e61fcb5e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
// 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

}}}