rlm@1
|
1 // Rar3Vm.cpp
|
rlm@1
|
2 // According to unRAR license, this code may not be used to develop
|
rlm@1
|
3 // a program that creates RAR archives
|
rlm@1
|
4
|
rlm@1
|
5 /*
|
rlm@1
|
6 Note:
|
rlm@1
|
7 Due to performance considerations Rar VM may set Flags C incorrectly
|
rlm@1
|
8 for some operands (SHL x, 0, ... ).
|
rlm@1
|
9 Check implementation of concrete VM command
|
rlm@1
|
10 to see if it sets flags right.
|
rlm@1
|
11 */
|
rlm@1
|
12
|
rlm@1
|
13 #include "StdAfx.h"
|
rlm@1
|
14
|
rlm@1
|
15 extern "C"
|
rlm@1
|
16 {
|
rlm@1
|
17 #include "../../../C/7zCrc.h"
|
rlm@1
|
18 #include "../../../C/Alloc.h"
|
rlm@1
|
19 }
|
rlm@1
|
20
|
rlm@1
|
21 #include "Rar3Vm.h"
|
rlm@1
|
22
|
rlm@1
|
23 namespace NCompress {
|
rlm@1
|
24 namespace NRar3 {
|
rlm@1
|
25
|
rlm@1
|
26 UInt32 CMemBitDecoder::ReadBits(int numBits)
|
rlm@1
|
27 {
|
rlm@1
|
28 UInt32 res = 0;
|
rlm@1
|
29 for (;;)
|
rlm@1
|
30 {
|
rlm@1
|
31 Byte b = _bitPos < _bitSize ? _data[_bitPos >> 3] : 0;
|
rlm@1
|
32 int avail = (int)(8 - (_bitPos & 7));
|
rlm@1
|
33 if (numBits <= avail)
|
rlm@1
|
34 {
|
rlm@1
|
35 _bitPos += numBits;
|
rlm@1
|
36 return res | (b >> (avail - numBits)) & ((1 << numBits) - 1);
|
rlm@1
|
37 }
|
rlm@1
|
38 numBits -= avail;
|
rlm@1
|
39 res |= (UInt32)(b & ((1 << avail) - 1)) << numBits;
|
rlm@1
|
40 _bitPos += avail;
|
rlm@1
|
41 }
|
rlm@1
|
42 }
|
rlm@1
|
43
|
rlm@1
|
44 UInt32 CMemBitDecoder::ReadBit() { return ReadBits(1); }
|
rlm@1
|
45
|
rlm@1
|
46 namespace NVm {
|
rlm@1
|
47
|
rlm@1
|
48 static const UInt32 kStackRegIndex = kNumRegs - 1;
|
rlm@1
|
49
|
rlm@1
|
50 static const UInt32 FLAG_C = 1;
|
rlm@1
|
51 static const UInt32 FLAG_Z = 2;
|
rlm@1
|
52 static const UInt32 FLAG_S = 0x80000000;
|
rlm@1
|
53
|
rlm@1
|
54 static const Byte CF_OP0 = 0;
|
rlm@1
|
55 static const Byte CF_OP1 = 1;
|
rlm@1
|
56 static const Byte CF_OP2 = 2;
|
rlm@1
|
57 static const Byte CF_OPMASK = 3;
|
rlm@1
|
58 static const Byte CF_BYTEMODE = 4;
|
rlm@1
|
59 static const Byte CF_JUMP = 8;
|
rlm@1
|
60 static const Byte CF_PROC = 16;
|
rlm@1
|
61 static const Byte CF_USEFLAGS = 32;
|
rlm@1
|
62 static const Byte CF_CHFLAGS = 64;
|
rlm@1
|
63
|
rlm@1
|
64 static Byte kCmdFlags[]=
|
rlm@1
|
65 {
|
rlm@1
|
66 /* CMD_MOV */ CF_OP2 | CF_BYTEMODE,
|
rlm@1
|
67 /* CMD_CMP */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
|
rlm@1
|
68 /* CMD_ADD */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
|
rlm@1
|
69 /* CMD_SUB */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
|
rlm@1
|
70 /* CMD_JZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
|
rlm@1
|
71 /* CMD_JNZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
|
rlm@1
|
72 /* CMD_INC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
|
rlm@1
|
73 /* CMD_DEC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
|
rlm@1
|
74 /* CMD_JMP */ CF_OP1 | CF_JUMP,
|
rlm@1
|
75 /* CMD_XOR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
|
rlm@1
|
76 /* CMD_AND */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
|
rlm@1
|
77 /* CMD_OR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
|
rlm@1
|
78 /* CMD_TEST */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
|
rlm@1
|
79 /* CMD_JS */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
|
rlm@1
|
80 /* CMD_JNS */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
|
rlm@1
|
81 /* CMD_JB */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
|
rlm@1
|
82 /* CMD_JBE */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
|
rlm@1
|
83 /* CMD_JA */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
|
rlm@1
|
84 /* CMD_JAE */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
|
rlm@1
|
85 /* CMD_PUSH */ CF_OP1,
|
rlm@1
|
86 /* CMD_POP */ CF_OP1,
|
rlm@1
|
87 /* CMD_CALL */ CF_OP1 | CF_PROC,
|
rlm@1
|
88 /* CMD_RET */ CF_OP0 | CF_PROC,
|
rlm@1
|
89 /* CMD_NOT */ CF_OP1 | CF_BYTEMODE,
|
rlm@1
|
90 /* CMD_SHL */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
|
rlm@1
|
91 /* CMD_SHR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
|
rlm@1
|
92 /* CMD_SAR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
|
rlm@1
|
93 /* CMD_NEG */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
|
rlm@1
|
94 /* CMD_PUSHA */ CF_OP0,
|
rlm@1
|
95 /* CMD_POPA */ CF_OP0,
|
rlm@1
|
96 /* CMD_PUSHF */ CF_OP0 | CF_USEFLAGS,
|
rlm@1
|
97 /* CMD_POPF */ CF_OP0 | CF_CHFLAGS,
|
rlm@1
|
98 /* CMD_MOVZX */ CF_OP2,
|
rlm@1
|
99 /* CMD_MOVSX */ CF_OP2,
|
rlm@1
|
100 /* CMD_XCHG */ CF_OP2 | CF_BYTEMODE,
|
rlm@1
|
101 /* CMD_MUL */ CF_OP2 | CF_BYTEMODE,
|
rlm@1
|
102 /* CMD_DIV */ CF_OP2 | CF_BYTEMODE,
|
rlm@1
|
103 /* CMD_ADC */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS ,
|
rlm@1
|
104 /* CMD_SBB */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS ,
|
rlm@1
|
105 /* CMD_PRINT */ CF_OP0
|
rlm@1
|
106 };
|
rlm@1
|
107
|
rlm@1
|
108 CVm::CVm(): Mem(NULL) {}
|
rlm@1
|
109
|
rlm@1
|
110 bool CVm::Create()
|
rlm@1
|
111 {
|
rlm@1
|
112 if (Mem == NULL)
|
rlm@1
|
113 Mem = (Byte *)::MyAlloc(kSpaceSize + 4);
|
rlm@1
|
114 return (Mem != NULL);
|
rlm@1
|
115 }
|
rlm@1
|
116
|
rlm@1
|
117 CVm::~CVm()
|
rlm@1
|
118 {
|
rlm@1
|
119 ::MyFree(Mem);
|
rlm@1
|
120 }
|
rlm@1
|
121
|
rlm@1
|
122 // CVm::Execute can change CProgram object: it clears progarm if VM returns error.
|
rlm@1
|
123
|
rlm@1
|
124 bool CVm::Execute(CProgram *prg, const CProgramInitState *initState,
|
rlm@1
|
125 CBlockRef &outBlockRef, CRecordVector<Byte> &outGlobalData)
|
rlm@1
|
126 {
|
rlm@1
|
127 memcpy(R, initState->InitR, sizeof(initState->InitR));
|
rlm@1
|
128 R[kStackRegIndex] = kSpaceSize;
|
rlm@1
|
129 R[kNumRegs] = 0;
|
rlm@1
|
130 Flags = 0;
|
rlm@1
|
131
|
rlm@1
|
132 UInt32 globalSize = MyMin((UInt32)initState->GlobalData.Size(), kGlobalSize);
|
rlm@1
|
133 if (globalSize != 0)
|
rlm@1
|
134 memcpy(Mem + kGlobalOffset, &initState->GlobalData[0], globalSize);
|
rlm@1
|
135 UInt32 staticSize = MyMin((UInt32)prg->StaticData.Size(), kGlobalSize - globalSize);
|
rlm@1
|
136 if (staticSize != 0)
|
rlm@1
|
137 memcpy(Mem + kGlobalOffset + globalSize, &prg->StaticData[0], staticSize);
|
rlm@1
|
138
|
rlm@1
|
139 bool res = true;
|
rlm@1
|
140 #ifdef RARVM_STANDARD_FILTERS
|
rlm@1
|
141 if (prg->StandardFilterIndex >= 0)
|
rlm@1
|
142 ExecuteStandardFilter(prg->StandardFilterIndex);
|
rlm@1
|
143 else
|
rlm@1
|
144 #endif
|
rlm@1
|
145 {
|
rlm@1
|
146 res = ExecuteCode(prg);
|
rlm@1
|
147 if (!res)
|
rlm@1
|
148 prg->Commands[0].OpCode = CMD_RET;
|
rlm@1
|
149 }
|
rlm@1
|
150 UInt32 newBlockPos = GetFixedGlobalValue32(NGlobalOffset::kBlockPos) & kSpaceMask;
|
rlm@1
|
151 UInt32 newBlockSize = GetFixedGlobalValue32(NGlobalOffset::kBlockSize) & kSpaceMask;
|
rlm@1
|
152 if (newBlockPos + newBlockSize >= kSpaceSize)
|
rlm@1
|
153 newBlockPos = newBlockSize = 0;
|
rlm@1
|
154 outBlockRef.Offset = newBlockPos;
|
rlm@1
|
155 outBlockRef.Size = newBlockSize;
|
rlm@1
|
156
|
rlm@1
|
157 outGlobalData.Clear();
|
rlm@1
|
158 UInt32 dataSize = GetFixedGlobalValue32(NGlobalOffset::kGlobalMemOutSize);
|
rlm@1
|
159 dataSize = MyMin(dataSize, kGlobalSize - kFixedGlobalSize);
|
rlm@1
|
160 if (dataSize != 0)
|
rlm@1
|
161 {
|
rlm@1
|
162 dataSize += kFixedGlobalSize;
|
rlm@1
|
163 outGlobalData.Reserve(dataSize);
|
rlm@1
|
164 for (UInt32 i = 0; i < dataSize; i++)
|
rlm@1
|
165 outGlobalData.Add(Mem[kGlobalOffset + i]);
|
rlm@1
|
166 }
|
rlm@1
|
167 return res;
|
rlm@1
|
168 }
|
rlm@1
|
169
|
rlm@1
|
170
|
rlm@1
|
171 #define SET_IP(IP) \
|
rlm@1
|
172 if ((IP) >= numCommands) return true; \
|
rlm@1
|
173 if (--maxOpCount <= 0) return false; \
|
rlm@1
|
174 cmd = commands + (IP);
|
rlm@1
|
175
|
rlm@1
|
176 #define GET_FLAG_S_B(res) (((res) & 0x80) ? FLAG_S : 0)
|
rlm@1
|
177 #define SET_IP_OP1 { UInt32 val = GetOperand32(&cmd->Op1); SET_IP(val); }
|
rlm@1
|
178 #define FLAGS_UPDATE_SZ Flags = res == 0 ? FLAG_Z : res & FLAG_S
|
rlm@1
|
179 #define FLAGS_UPDATE_SZ_B Flags = (res & 0xFF) == 0 ? FLAG_Z : GET_FLAG_S_B(res)
|
rlm@1
|
180
|
rlm@1
|
181 UInt32 CVm::GetOperand32(const COperand *op) const
|
rlm@1
|
182 {
|
rlm@1
|
183 switch(op->Type)
|
rlm@1
|
184 {
|
rlm@1
|
185 case OP_TYPE_REG: return R[op->Data];
|
rlm@1
|
186 case OP_TYPE_REGMEM: return GetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask]);
|
rlm@1
|
187 default: return op->Data;
|
rlm@1
|
188 }
|
rlm@1
|
189 }
|
rlm@1
|
190
|
rlm@1
|
191 void CVm::SetOperand32(const COperand *op, UInt32 val)
|
rlm@1
|
192 {
|
rlm@1
|
193 switch(op->Type)
|
rlm@1
|
194 {
|
rlm@1
|
195 case OP_TYPE_REG: R[op->Data] = val; return;
|
rlm@1
|
196 case OP_TYPE_REGMEM: SetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask], val); return;
|
rlm@1
|
197 }
|
rlm@1
|
198 }
|
rlm@1
|
199
|
rlm@1
|
200 Byte CVm::GetOperand8(const COperand *op) const
|
rlm@1
|
201 {
|
rlm@1
|
202 switch(op->Type)
|
rlm@1
|
203 {
|
rlm@1
|
204 case OP_TYPE_REG: return (Byte)R[op->Data];
|
rlm@1
|
205 case OP_TYPE_REGMEM: return Mem[(op->Base + R[op->Data]) & kSpaceMask];;
|
rlm@1
|
206 default: return (Byte)op->Data;
|
rlm@1
|
207 }
|
rlm@1
|
208 }
|
rlm@1
|
209
|
rlm@1
|
210 void CVm::SetOperand8(const COperand *op, Byte val)
|
rlm@1
|
211 {
|
rlm@1
|
212 switch(op->Type)
|
rlm@1
|
213 {
|
rlm@1
|
214 case OP_TYPE_REG: R[op->Data] = (R[op->Data] & 0xFFFFFF00) | val; return;
|
rlm@1
|
215 case OP_TYPE_REGMEM: Mem[(op->Base + R[op->Data]) & kSpaceMask] = val; return;
|
rlm@1
|
216 }
|
rlm@1
|
217 }
|
rlm@1
|
218
|
rlm@1
|
219 UInt32 CVm::GetOperand(bool byteMode, const COperand *op) const
|
rlm@1
|
220 {
|
rlm@1
|
221 if (byteMode)
|
rlm@1
|
222 return GetOperand8(op);
|
rlm@1
|
223 return GetOperand32(op);
|
rlm@1
|
224 }
|
rlm@1
|
225
|
rlm@1
|
226 void CVm::SetOperand(bool byteMode, const COperand *op, UInt32 val)
|
rlm@1
|
227 {
|
rlm@1
|
228 if (byteMode)
|
rlm@1
|
229 SetOperand8(op, (Byte)(val & 0xFF));
|
rlm@1
|
230 else
|
rlm@1
|
231 SetOperand32(op, val);
|
rlm@1
|
232 }
|
rlm@1
|
233
|
rlm@1
|
234 bool CVm::ExecuteCode(const CProgram *prg)
|
rlm@1
|
235 {
|
rlm@1
|
236 Int32 maxOpCount = 25000000;
|
rlm@1
|
237 const CCommand *commands = &prg->Commands[0];
|
rlm@1
|
238 const CCommand *cmd = commands;
|
rlm@1
|
239 UInt32 numCommands = prg->Commands.Size();
|
rlm@1
|
240 for (;;)
|
rlm@1
|
241 {
|
rlm@1
|
242 switch(cmd->OpCode)
|
rlm@1
|
243 {
|
rlm@1
|
244 #ifndef RARVM_NO_VM
|
rlm@1
|
245
|
rlm@1
|
246 case CMD_MOV:
|
rlm@1
|
247 SetOperand32(&cmd->Op1, GetOperand32(&cmd->Op2));
|
rlm@1
|
248 break;
|
rlm@1
|
249 case CMD_MOVB:
|
rlm@1
|
250 SetOperand8(&cmd->Op1, GetOperand8(&cmd->Op2));
|
rlm@1
|
251 break;
|
rlm@1
|
252 case CMD_CMP:
|
rlm@1
|
253 {
|
rlm@1
|
254 UInt32 v1 = GetOperand32(&cmd->Op1);
|
rlm@1
|
255 UInt32 res = v1 - GetOperand32(&cmd->Op2);
|
rlm@1
|
256 Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
|
rlm@1
|
257 }
|
rlm@1
|
258 break;
|
rlm@1
|
259 case CMD_CMPB:
|
rlm@1
|
260 {
|
rlm@1
|
261 Byte v1 = GetOperand8(&cmd->Op1);
|
rlm@1
|
262 Byte res = v1 - GetOperand8(&cmd->Op2);
|
rlm@1
|
263 res &= 0xFF;
|
rlm@1
|
264 Flags = res == 0 ? FLAG_Z : (res > v1) | GET_FLAG_S_B(res);
|
rlm@1
|
265 }
|
rlm@1
|
266 break;
|
rlm@1
|
267 case CMD_ADD:
|
rlm@1
|
268 {
|
rlm@1
|
269 UInt32 v1 = GetOperand32(&cmd->Op1);
|
rlm@1
|
270 UInt32 res = v1 + GetOperand32(&cmd->Op2);
|
rlm@1
|
271 SetOperand32(&cmd->Op1, res);
|
rlm@1
|
272 Flags = (res < v1) | (res == 0 ? FLAG_Z : (res & FLAG_S));
|
rlm@1
|
273 }
|
rlm@1
|
274 break;
|
rlm@1
|
275 case CMD_ADDB:
|
rlm@1
|
276 {
|
rlm@1
|
277 Byte v1 = GetOperand8(&cmd->Op1);
|
rlm@1
|
278 Byte res = v1 + GetOperand8(&cmd->Op2);
|
rlm@1
|
279 res &= 0xFF;
|
rlm@1
|
280 SetOperand8(&cmd->Op1, (Byte)res);
|
rlm@1
|
281 Flags = (res < v1) | (res == 0 ? FLAG_Z : GET_FLAG_S_B(res));
|
rlm@1
|
282 }
|
rlm@1
|
283 break;
|
rlm@1
|
284 case CMD_ADC:
|
rlm@1
|
285 {
|
rlm@1
|
286 UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
|
rlm@1
|
287 UInt32 FC = (Flags & FLAG_C);
|
rlm@1
|
288 UInt32 res = v1 + GetOperand(cmd->ByteMode, &cmd->Op2) + FC;
|
rlm@1
|
289 if (cmd->ByteMode)
|
rlm@1
|
290 res &= 0xFF;
|
rlm@1
|
291 SetOperand(cmd->ByteMode, &cmd->Op1, res);
|
rlm@1
|
292 Flags = (res < v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S));
|
rlm@1
|
293 }
|
rlm@1
|
294 break;
|
rlm@1
|
295 case CMD_SUB:
|
rlm@1
|
296 {
|
rlm@1
|
297 UInt32 v1 = GetOperand32(&cmd->Op1);
|
rlm@1
|
298 UInt32 res = v1 - GetOperand32(&cmd->Op2);
|
rlm@1
|
299 SetOperand32(&cmd->Op1, res);
|
rlm@1
|
300 Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
|
rlm@1
|
301 }
|
rlm@1
|
302 break;
|
rlm@1
|
303 case CMD_SUBB:
|
rlm@1
|
304 {
|
rlm@1
|
305 UInt32 v1 = GetOperand8(&cmd->Op1);
|
rlm@1
|
306 UInt32 res = v1 - GetOperand8(&cmd->Op2);
|
rlm@1
|
307 SetOperand8(&cmd->Op1, (Byte)res);
|
rlm@1
|
308 Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
|
rlm@1
|
309 }
|
rlm@1
|
310 break;
|
rlm@1
|
311 case CMD_SBB:
|
rlm@1
|
312 {
|
rlm@1
|
313 UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
|
rlm@1
|
314 UInt32 FC = (Flags & FLAG_C);
|
rlm@1
|
315 UInt32 res = v1 - GetOperand(cmd->ByteMode, &cmd->Op2) - FC;
|
rlm@1
|
316 // Flags = res == 0 ? FLAG_Z : (res > v1 || res == v1 && FC) | (res & FLAG_S);
|
rlm@1
|
317 if (cmd->ByteMode)
|
rlm@1
|
318 res &= 0xFF;
|
rlm@1
|
319 SetOperand(cmd->ByteMode, &cmd->Op1, res);
|
rlm@1
|
320 Flags = (res > v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S));
|
rlm@1
|
321 }
|
rlm@1
|
322 break;
|
rlm@1
|
323 case CMD_INC:
|
rlm@1
|
324 {
|
rlm@1
|
325 UInt32 res = GetOperand32(&cmd->Op1) + 1;
|
rlm@1
|
326 SetOperand32(&cmd->Op1, res);
|
rlm@1
|
327 FLAGS_UPDATE_SZ;
|
rlm@1
|
328 }
|
rlm@1
|
329 break;
|
rlm@1
|
330 case CMD_INCB:
|
rlm@1
|
331 {
|
rlm@1
|
332 Byte res = GetOperand8(&cmd->Op1) + 1;
|
rlm@1
|
333 SetOperand8(&cmd->Op1, res);;
|
rlm@1
|
334 FLAGS_UPDATE_SZ_B;
|
rlm@1
|
335 }
|
rlm@1
|
336 break;
|
rlm@1
|
337 case CMD_DEC:
|
rlm@1
|
338 {
|
rlm@1
|
339 UInt32 res = GetOperand32(&cmd->Op1) - 1;
|
rlm@1
|
340 SetOperand32(&cmd->Op1, res);
|
rlm@1
|
341 FLAGS_UPDATE_SZ;
|
rlm@1
|
342 }
|
rlm@1
|
343 break;
|
rlm@1
|
344 case CMD_DECB:
|
rlm@1
|
345 {
|
rlm@1
|
346 Byte res = GetOperand8(&cmd->Op1) - 1;
|
rlm@1
|
347 SetOperand8(&cmd->Op1, res);;
|
rlm@1
|
348 FLAGS_UPDATE_SZ_B;
|
rlm@1
|
349 }
|
rlm@1
|
350 break;
|
rlm@1
|
351 case CMD_XOR:
|
rlm@1
|
352 {
|
rlm@1
|
353 UInt32 res = GetOperand32(&cmd->Op1) ^ GetOperand32(&cmd->Op2);
|
rlm@1
|
354 SetOperand32(&cmd->Op1, res);
|
rlm@1
|
355 FLAGS_UPDATE_SZ;
|
rlm@1
|
356 }
|
rlm@1
|
357 break;
|
rlm@1
|
358 case CMD_XORB:
|
rlm@1
|
359 {
|
rlm@1
|
360 Byte res = GetOperand8(&cmd->Op1) ^ GetOperand8(&cmd->Op2);
|
rlm@1
|
361 SetOperand8(&cmd->Op1, res);
|
rlm@1
|
362 FLAGS_UPDATE_SZ_B;
|
rlm@1
|
363 }
|
rlm@1
|
364 break;
|
rlm@1
|
365 case CMD_AND:
|
rlm@1
|
366 {
|
rlm@1
|
367 UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2);
|
rlm@1
|
368 SetOperand32(&cmd->Op1, res);
|
rlm@1
|
369 FLAGS_UPDATE_SZ;
|
rlm@1
|
370 }
|
rlm@1
|
371 break;
|
rlm@1
|
372 case CMD_ANDB:
|
rlm@1
|
373 {
|
rlm@1
|
374 Byte res = GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2);
|
rlm@1
|
375 SetOperand8(&cmd->Op1, res);
|
rlm@1
|
376 FLAGS_UPDATE_SZ_B;
|
rlm@1
|
377 }
|
rlm@1
|
378 break;
|
rlm@1
|
379 case CMD_OR:
|
rlm@1
|
380 {
|
rlm@1
|
381 UInt32 res = GetOperand32(&cmd->Op1) | GetOperand32(&cmd->Op2);
|
rlm@1
|
382 SetOperand32(&cmd->Op1, res);
|
rlm@1
|
383 FLAGS_UPDATE_SZ;
|
rlm@1
|
384 }
|
rlm@1
|
385 break;
|
rlm@1
|
386 case CMD_ORB:
|
rlm@1
|
387 {
|
rlm@1
|
388 Byte res = GetOperand8(&cmd->Op1) | GetOperand8(&cmd->Op2);
|
rlm@1
|
389 SetOperand8(&cmd->Op1, res);
|
rlm@1
|
390 FLAGS_UPDATE_SZ_B;
|
rlm@1
|
391 }
|
rlm@1
|
392 break;
|
rlm@1
|
393 case CMD_TEST:
|
rlm@1
|
394 {
|
rlm@1
|
395 UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2);
|
rlm@1
|
396 FLAGS_UPDATE_SZ;
|
rlm@1
|
397 }
|
rlm@1
|
398 break;
|
rlm@1
|
399 case CMD_TESTB:
|
rlm@1
|
400 {
|
rlm@1
|
401 Byte res = GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2);
|
rlm@1
|
402 FLAGS_UPDATE_SZ_B;
|
rlm@1
|
403 }
|
rlm@1
|
404 break;
|
rlm@1
|
405 case CMD_NOT:
|
rlm@1
|
406 SetOperand(cmd->ByteMode, &cmd->Op1, ~GetOperand(cmd->ByteMode, &cmd->Op1));
|
rlm@1
|
407 break;
|
rlm@1
|
408 case CMD_NEG:
|
rlm@1
|
409 {
|
rlm@1
|
410 UInt32 res = 0 - GetOperand32(&cmd->Op1);
|
rlm@1
|
411 SetOperand32(&cmd->Op1, res);
|
rlm@1
|
412 Flags = res == 0 ? FLAG_Z : FLAG_C | (res & FLAG_S);
|
rlm@1
|
413 }
|
rlm@1
|
414 break;
|
rlm@1
|
415 case CMD_NEGB:
|
rlm@1
|
416 {
|
rlm@1
|
417 Byte res = (Byte)(0 - GetOperand8(&cmd->Op1));
|
rlm@1
|
418 SetOperand8(&cmd->Op1, res);
|
rlm@1
|
419 Flags = res == 0 ? FLAG_Z : FLAG_C | GET_FLAG_S_B(res);
|
rlm@1
|
420 }
|
rlm@1
|
421 break;
|
rlm@1
|
422
|
rlm@1
|
423 case CMD_SHL:
|
rlm@1
|
424 {
|
rlm@1
|
425 UInt32 v1 = GetOperand32(&cmd->Op1);
|
rlm@1
|
426 int v2 = (int)GetOperand32(&cmd->Op2);
|
rlm@1
|
427 UInt32 res = v1 << v2;
|
rlm@1
|
428 SetOperand32(&cmd->Op1, res);
|
rlm@1
|
429 Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 << (v2 - 1)) & 0x80000000 ? FLAG_C : 0);
|
rlm@1
|
430 }
|
rlm@1
|
431 break;
|
rlm@1
|
432 case CMD_SHLB:
|
rlm@1
|
433 {
|
rlm@1
|
434 Byte v1 = GetOperand8(&cmd->Op1);
|
rlm@1
|
435 int v2 = (int)GetOperand8(&cmd->Op2);
|
rlm@1
|
436 Byte res = (Byte)(v1 << v2);
|
rlm@1
|
437 SetOperand8(&cmd->Op1, res);
|
rlm@1
|
438 Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 << (v2 - 1)) & 0x80 ? FLAG_C : 0);
|
rlm@1
|
439 }
|
rlm@1
|
440 break;
|
rlm@1
|
441 case CMD_SHR:
|
rlm@1
|
442 {
|
rlm@1
|
443 UInt32 v1 = GetOperand32(&cmd->Op1);
|
rlm@1
|
444 int v2 = (int)GetOperand32(&cmd->Op2);
|
rlm@1
|
445 UInt32 res = v1 >> v2;
|
rlm@1
|
446 SetOperand32(&cmd->Op1, res);
|
rlm@1
|
447 Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C);
|
rlm@1
|
448 }
|
rlm@1
|
449 break;
|
rlm@1
|
450 case CMD_SHRB:
|
rlm@1
|
451 {
|
rlm@1
|
452 Byte v1 = GetOperand8(&cmd->Op1);
|
rlm@1
|
453 int v2 = (int)GetOperand8(&cmd->Op2);
|
rlm@1
|
454 Byte res = (Byte)(v1 >> v2);
|
rlm@1
|
455 SetOperand8(&cmd->Op1, res);
|
rlm@1
|
456 Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C);
|
rlm@1
|
457 }
|
rlm@1
|
458 break;
|
rlm@1
|
459 case CMD_SAR:
|
rlm@1
|
460 {
|
rlm@1
|
461 UInt32 v1 = GetOperand32(&cmd->Op1);
|
rlm@1
|
462 int v2 = (int)GetOperand32(&cmd->Op2);
|
rlm@1
|
463 UInt32 res = UInt32(((Int32)v1) >> v2);
|
rlm@1
|
464 SetOperand32(&cmd->Op1, res);
|
rlm@1
|
465 Flags= (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C);
|
rlm@1
|
466 }
|
rlm@1
|
467 break;
|
rlm@1
|
468 case CMD_SARB:
|
rlm@1
|
469 {
|
rlm@1
|
470 Byte v1 = GetOperand8(&cmd->Op1);
|
rlm@1
|
471 int v2 = (int)GetOperand8(&cmd->Op2);
|
rlm@1
|
472 Byte res = (Byte)(((signed char)v1) >> v2);
|
rlm@1
|
473 SetOperand8(&cmd->Op1, res);
|
rlm@1
|
474 Flags= (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C);
|
rlm@1
|
475 }
|
rlm@1
|
476 break;
|
rlm@1
|
477
|
rlm@1
|
478 case CMD_JMP:
|
rlm@1
|
479 SET_IP_OP1;
|
rlm@1
|
480 continue;
|
rlm@1
|
481 case CMD_JZ:
|
rlm@1
|
482 if ((Flags & FLAG_Z) != 0)
|
rlm@1
|
483 {
|
rlm@1
|
484 SET_IP_OP1;
|
rlm@1
|
485 continue;
|
rlm@1
|
486 }
|
rlm@1
|
487 break;
|
rlm@1
|
488 case CMD_JNZ:
|
rlm@1
|
489 if ((Flags & FLAG_Z) == 0)
|
rlm@1
|
490 {
|
rlm@1
|
491 SET_IP_OP1;
|
rlm@1
|
492 continue;
|
rlm@1
|
493 }
|
rlm@1
|
494 break;
|
rlm@1
|
495 case CMD_JS:
|
rlm@1
|
496 if ((Flags & FLAG_S) != 0)
|
rlm@1
|
497 {
|
rlm@1
|
498 SET_IP_OP1;
|
rlm@1
|
499 continue;
|
rlm@1
|
500 }
|
rlm@1
|
501 break;
|
rlm@1
|
502 case CMD_JNS:
|
rlm@1
|
503 if ((Flags & FLAG_S) == 0)
|
rlm@1
|
504 {
|
rlm@1
|
505 SET_IP_OP1;
|
rlm@1
|
506 continue;
|
rlm@1
|
507 }
|
rlm@1
|
508 break;
|
rlm@1
|
509 case CMD_JB:
|
rlm@1
|
510 if ((Flags & FLAG_C) != 0)
|
rlm@1
|
511 {
|
rlm@1
|
512 SET_IP_OP1;
|
rlm@1
|
513 continue;
|
rlm@1
|
514 }
|
rlm@1
|
515 break;
|
rlm@1
|
516 case CMD_JBE:
|
rlm@1
|
517 if ((Flags & (FLAG_C | FLAG_Z)) != 0)
|
rlm@1
|
518 {
|
rlm@1
|
519 SET_IP_OP1;
|
rlm@1
|
520 continue;
|
rlm@1
|
521 }
|
rlm@1
|
522 break;
|
rlm@1
|
523 case CMD_JA:
|
rlm@1
|
524 if ((Flags & (FLAG_C | FLAG_Z)) == 0)
|
rlm@1
|
525 {
|
rlm@1
|
526 SET_IP_OP1;
|
rlm@1
|
527 continue;
|
rlm@1
|
528 }
|
rlm@1
|
529 break;
|
rlm@1
|
530 case CMD_JAE:
|
rlm@1
|
531 if ((Flags & FLAG_C) == 0)
|
rlm@1
|
532 {
|
rlm@1
|
533 SET_IP_OP1;
|
rlm@1
|
534 continue;
|
rlm@1
|
535 }
|
rlm@1
|
536 break;
|
rlm@1
|
537
|
rlm@1
|
538 case CMD_PUSH:
|
rlm@1
|
539 R[kStackRegIndex] -= 4;
|
rlm@1
|
540 SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], GetOperand32(&cmd->Op1));
|
rlm@1
|
541 break;
|
rlm@1
|
542 case CMD_POP:
|
rlm@1
|
543 SetOperand32(&cmd->Op1, GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]));
|
rlm@1
|
544 R[kStackRegIndex] += 4;
|
rlm@1
|
545 break;
|
rlm@1
|
546 case CMD_CALL:
|
rlm@1
|
547 R[kStackRegIndex] -= 4;
|
rlm@1
|
548 SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], (UInt32)(cmd - commands + 1));
|
rlm@1
|
549 SET_IP_OP1;
|
rlm@1
|
550 continue;
|
rlm@1
|
551
|
rlm@1
|
552 case CMD_PUSHA:
|
rlm@1
|
553 {
|
rlm@1
|
554 for (UInt32 i = 0, SP = R[kStackRegIndex] - 4; i < kNumRegs; i++, SP -= 4)
|
rlm@1
|
555 SetValue32(&Mem[SP & kSpaceMask], R[i]);
|
rlm@1
|
556 R[kStackRegIndex] -= kNumRegs * 4;
|
rlm@1
|
557 }
|
rlm@1
|
558 break;
|
rlm@1
|
559 case CMD_POPA:
|
rlm@1
|
560 {
|
rlm@1
|
561 for (UInt32 i = 0, SP = R[kStackRegIndex]; i < kNumRegs; i++, SP += 4)
|
rlm@1
|
562 R[kStackRegIndex - i] = GetValue32(&Mem[SP & kSpaceMask]);
|
rlm@1
|
563 }
|
rlm@1
|
564 break;
|
rlm@1
|
565 case CMD_PUSHF:
|
rlm@1
|
566 R[kStackRegIndex] -= 4;
|
rlm@1
|
567 SetValue32(&Mem[R[kStackRegIndex]&kSpaceMask], Flags);
|
rlm@1
|
568 break;
|
rlm@1
|
569 case CMD_POPF:
|
rlm@1
|
570 Flags = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]);
|
rlm@1
|
571 R[kStackRegIndex] += 4;
|
rlm@1
|
572 break;
|
rlm@1
|
573
|
rlm@1
|
574 case CMD_MOVZX:
|
rlm@1
|
575 SetOperand32(&cmd->Op1, GetOperand8(&cmd->Op2));
|
rlm@1
|
576 break;
|
rlm@1
|
577 case CMD_MOVSX:
|
rlm@1
|
578 SetOperand32(&cmd->Op1, (UInt32)(Int32)(signed char)GetOperand8(&cmd->Op2));
|
rlm@1
|
579 break;
|
rlm@1
|
580 case CMD_XCHG:
|
rlm@1
|
581 {
|
rlm@1
|
582 UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
|
rlm@1
|
583 SetOperand(cmd->ByteMode, &cmd->Op1, GetOperand(cmd->ByteMode, &cmd->Op2));
|
rlm@1
|
584 SetOperand(cmd->ByteMode, &cmd->Op2, v1);
|
rlm@1
|
585 }
|
rlm@1
|
586 break;
|
rlm@1
|
587 case CMD_MUL:
|
rlm@1
|
588 {
|
rlm@1
|
589 UInt32 res = GetOperand32(&cmd->Op1) * GetOperand32(&cmd->Op2);
|
rlm@1
|
590 SetOperand32(&cmd->Op1, res);
|
rlm@1
|
591 }
|
rlm@1
|
592 break;
|
rlm@1
|
593 case CMD_MULB:
|
rlm@1
|
594 {
|
rlm@1
|
595 Byte res = GetOperand8(&cmd->Op1) * GetOperand8(&cmd->Op2);
|
rlm@1
|
596 SetOperand8(&cmd->Op1, res);
|
rlm@1
|
597 }
|
rlm@1
|
598 break;
|
rlm@1
|
599 case CMD_DIV:
|
rlm@1
|
600 {
|
rlm@1
|
601 UInt32 divider = GetOperand(cmd->ByteMode, &cmd->Op2);
|
rlm@1
|
602 if (divider != 0)
|
rlm@1
|
603 {
|
rlm@1
|
604 UInt32 res = GetOperand(cmd->ByteMode, &cmd->Op1) / divider;
|
rlm@1
|
605 SetOperand(cmd->ByteMode, &cmd->Op1, res);
|
rlm@1
|
606 }
|
rlm@1
|
607 }
|
rlm@1
|
608 break;
|
rlm@1
|
609
|
rlm@1
|
610 #endif
|
rlm@1
|
611
|
rlm@1
|
612 case CMD_RET:
|
rlm@1
|
613 {
|
rlm@1
|
614 if (R[kStackRegIndex] >= kSpaceSize)
|
rlm@1
|
615 return true;
|
rlm@1
|
616 UInt32 ip = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]);
|
rlm@1
|
617 SET_IP(ip);
|
rlm@1
|
618 R[kStackRegIndex] += 4;
|
rlm@1
|
619 continue;
|
rlm@1
|
620 }
|
rlm@1
|
621 case CMD_PRINT:
|
rlm@1
|
622 break;
|
rlm@1
|
623 }
|
rlm@1
|
624 cmd++;
|
rlm@1
|
625 --maxOpCount;
|
rlm@1
|
626 }
|
rlm@1
|
627 }
|
rlm@1
|
628
|
rlm@1
|
629
|
rlm@1
|
630 //////////////////////////////////////////////////////
|
rlm@1
|
631 // Read program
|
rlm@1
|
632
|
rlm@1
|
633 UInt32 ReadEncodedUInt32(CMemBitDecoder &inp)
|
rlm@1
|
634 {
|
rlm@1
|
635 switch(inp.ReadBits(2))
|
rlm@1
|
636 {
|
rlm@1
|
637 case 0:
|
rlm@1
|
638 return inp.ReadBits(4);
|
rlm@1
|
639 case 1:
|
rlm@1
|
640 {
|
rlm@1
|
641 UInt32 v = inp.ReadBits(4);
|
rlm@1
|
642 if (v == 0)
|
rlm@1
|
643 return 0xFFFFFF00 | inp.ReadBits(8);
|
rlm@1
|
644 else
|
rlm@1
|
645 return (v << 4) | inp.ReadBits(4);
|
rlm@1
|
646 }
|
rlm@1
|
647 case 2:
|
rlm@1
|
648 return inp.ReadBits(16);
|
rlm@1
|
649 default:
|
rlm@1
|
650 return inp.ReadBits(32);
|
rlm@1
|
651 }
|
rlm@1
|
652 }
|
rlm@1
|
653
|
rlm@1
|
654 void CVm::DecodeArg(CMemBitDecoder &inp, COperand &op, bool byteMode)
|
rlm@1
|
655 {
|
rlm@1
|
656 if (inp.ReadBit())
|
rlm@1
|
657 {
|
rlm@1
|
658 op.Type = OP_TYPE_REG;
|
rlm@1
|
659 op.Data = inp.ReadBits(kNumRegBits);
|
rlm@1
|
660 }
|
rlm@1
|
661 else if (inp.ReadBit() == 0)
|
rlm@1
|
662 {
|
rlm@1
|
663 op.Type = OP_TYPE_INT;
|
rlm@1
|
664 if (byteMode)
|
rlm@1
|
665 op.Data = inp.ReadBits(8);
|
rlm@1
|
666 else
|
rlm@1
|
667 op.Data = ReadEncodedUInt32(inp);
|
rlm@1
|
668 }
|
rlm@1
|
669 else
|
rlm@1
|
670 {
|
rlm@1
|
671 op.Type = OP_TYPE_REGMEM;
|
rlm@1
|
672 if (inp.ReadBit() == 0)
|
rlm@1
|
673 {
|
rlm@1
|
674 op.Data = inp.ReadBits(kNumRegBits);
|
rlm@1
|
675 op.Base = 0;
|
rlm@1
|
676 }
|
rlm@1
|
677 else
|
rlm@1
|
678 {
|
rlm@1
|
679 if (inp.ReadBit() == 0)
|
rlm@1
|
680 op.Data = inp.ReadBits(kNumRegBits);
|
rlm@1
|
681 else
|
rlm@1
|
682 op.Data = kNumRegs;
|
rlm@1
|
683 op.Base = ReadEncodedUInt32(inp);
|
rlm@1
|
684 }
|
rlm@1
|
685 }
|
rlm@1
|
686 }
|
rlm@1
|
687
|
rlm@1
|
688 void CVm::ReadVmProgram(const Byte *code, UInt32 codeSize, CProgram *prg)
|
rlm@1
|
689 {
|
rlm@1
|
690 CMemBitDecoder inp;
|
rlm@1
|
691 inp.Init(code, codeSize);
|
rlm@1
|
692
|
rlm@1
|
693 prg->StaticData.Clear();
|
rlm@1
|
694 if (inp.ReadBit())
|
rlm@1
|
695 {
|
rlm@1
|
696 UInt32 dataSize = ReadEncodedUInt32(inp) + 1;
|
rlm@1
|
697 for (UInt32 i = 0; inp.Avail() && i < dataSize; i++)
|
rlm@1
|
698 prg->StaticData.Add((Byte)inp.ReadBits(8));
|
rlm@1
|
699 }
|
rlm@1
|
700 while (inp.Avail())
|
rlm@1
|
701 {
|
rlm@1
|
702 prg->Commands.Add(CCommand());
|
rlm@1
|
703 CCommand *cmd = &prg->Commands.Back();
|
rlm@1
|
704 if (inp.ReadBit() == 0)
|
rlm@1
|
705 cmd->OpCode = (ECommand)inp.ReadBits(3);
|
rlm@1
|
706 else
|
rlm@1
|
707 cmd->OpCode = (ECommand)(8 + inp.ReadBits(5));
|
rlm@1
|
708 if (kCmdFlags[cmd->OpCode] & CF_BYTEMODE)
|
rlm@1
|
709 cmd->ByteMode = (inp.ReadBit()) ? true : false;
|
rlm@1
|
710 else
|
rlm@1
|
711 cmd->ByteMode = 0;
|
rlm@1
|
712 int opNum = (kCmdFlags[cmd->OpCode] & CF_OPMASK);
|
rlm@1
|
713 if (opNum > 0)
|
rlm@1
|
714 {
|
rlm@1
|
715 DecodeArg(inp, cmd->Op1, cmd->ByteMode);
|
rlm@1
|
716 if (opNum == 2)
|
rlm@1
|
717 DecodeArg(inp, cmd->Op2, cmd->ByteMode);
|
rlm@1
|
718 else
|
rlm@1
|
719 {
|
rlm@1
|
720 if (cmd->Op1.Type == OP_TYPE_INT && (kCmdFlags[cmd->OpCode] & (CF_JUMP | CF_PROC)))
|
rlm@1
|
721 {
|
rlm@1
|
722 int Distance = cmd->Op1.Data;
|
rlm@1
|
723 if (Distance >= 256)
|
rlm@1
|
724 Distance -= 256;
|
rlm@1
|
725 else
|
rlm@1
|
726 {
|
rlm@1
|
727 if (Distance >= 136)
|
rlm@1
|
728 Distance -= 264;
|
rlm@1
|
729 else if (Distance >= 16)
|
rlm@1
|
730 Distance -= 8;
|
rlm@1
|
731 else if (Distance >= 8)
|
rlm@1
|
732 Distance -= 16;
|
rlm@1
|
733 Distance += prg->Commands.Size() - 1;
|
rlm@1
|
734 }
|
rlm@1
|
735 cmd->Op1.Data = Distance;
|
rlm@1
|
736 }
|
rlm@1
|
737 }
|
rlm@1
|
738 }
|
rlm@1
|
739 if (cmd->ByteMode)
|
rlm@1
|
740 {
|
rlm@1
|
741 switch (cmd->OpCode)
|
rlm@1
|
742 {
|
rlm@1
|
743 case CMD_MOV: cmd->OpCode = CMD_MOVB; break;
|
rlm@1
|
744 case CMD_CMP: cmd->OpCode = CMD_CMPB; break;
|
rlm@1
|
745 case CMD_ADD: cmd->OpCode = CMD_ADDB; break;
|
rlm@1
|
746 case CMD_SUB: cmd->OpCode = CMD_SUBB; break;
|
rlm@1
|
747 case CMD_INC: cmd->OpCode = CMD_INCB; break;
|
rlm@1
|
748 case CMD_DEC: cmd->OpCode = CMD_DECB; break;
|
rlm@1
|
749 case CMD_XOR: cmd->OpCode = CMD_XORB; break;
|
rlm@1
|
750 case CMD_AND: cmd->OpCode = CMD_ANDB; break;
|
rlm@1
|
751 case CMD_OR: cmd->OpCode = CMD_ORB; break;
|
rlm@1
|
752 case CMD_TEST: cmd->OpCode = CMD_TESTB; break;
|
rlm@1
|
753 case CMD_NEG: cmd->OpCode = CMD_NEGB; break;
|
rlm@1
|
754 case CMD_SHL: cmd->OpCode = CMD_SHLB; break;
|
rlm@1
|
755 case CMD_SHR: cmd->OpCode = CMD_SHRB; break;
|
rlm@1
|
756 case CMD_SAR: cmd->OpCode = CMD_SARB; break;
|
rlm@1
|
757 case CMD_MUL: cmd->OpCode = CMD_MULB; break;
|
rlm@1
|
758 }
|
rlm@1
|
759 }
|
rlm@1
|
760 }
|
rlm@1
|
761 }
|
rlm@1
|
762
|
rlm@1
|
763 #ifdef RARVM_STANDARD_FILTERS
|
rlm@1
|
764
|
rlm@1
|
765 enum EStandardFilter
|
rlm@1
|
766 {
|
rlm@1
|
767 SF_E8,
|
rlm@1
|
768 SF_E8E9,
|
rlm@1
|
769 SF_ITANIUM,
|
rlm@1
|
770 SF_RGB,
|
rlm@1
|
771 SF_AUDIO,
|
rlm@1
|
772 SF_DELTA,
|
rlm@1
|
773 SF_UPCASE
|
rlm@1
|
774 };
|
rlm@1
|
775
|
rlm@1
|
776 struct StandardFilterSignature
|
rlm@1
|
777 {
|
rlm@1
|
778 UInt32 Length;
|
rlm@1
|
779 UInt32 CRC;
|
rlm@1
|
780 EStandardFilter Type;
|
rlm@1
|
781 }
|
rlm@1
|
782 kStdFilters[]=
|
rlm@1
|
783 {
|
rlm@1
|
784 53, 0xad576887, SF_E8,
|
rlm@1
|
785 57, 0x3cd7e57e, SF_E8E9,
|
rlm@1
|
786 120, 0x3769893f, SF_ITANIUM,
|
rlm@1
|
787 29, 0x0e06077d, SF_DELTA,
|
rlm@1
|
788 149, 0x1c2c5dc8, SF_RGB,
|
rlm@1
|
789 216, 0xbc85e701, SF_AUDIO,
|
rlm@1
|
790 40, 0x46b9c560, SF_UPCASE
|
rlm@1
|
791 };
|
rlm@1
|
792
|
rlm@1
|
793 static int FindStandardFilter(const Byte *code, UInt32 codeSize)
|
rlm@1
|
794 {
|
rlm@1
|
795 UInt32 crc = CrcCalc(code, codeSize);
|
rlm@1
|
796 for (int i = 0; i < sizeof(kStdFilters) / sizeof(kStdFilters[0]); i++)
|
rlm@1
|
797 {
|
rlm@1
|
798 StandardFilterSignature &sfs = kStdFilters[i];
|
rlm@1
|
799 if (sfs.CRC == crc && sfs.Length == codeSize)
|
rlm@1
|
800 return i;
|
rlm@1
|
801 }
|
rlm@1
|
802 return -1;
|
rlm@1
|
803 }
|
rlm@1
|
804
|
rlm@1
|
805 #endif
|
rlm@1
|
806
|
rlm@1
|
807 void CVm::PrepareProgram(const Byte *code, UInt32 codeSize, CProgram *prg)
|
rlm@1
|
808 {
|
rlm@1
|
809 Byte xorSum = 0;
|
rlm@1
|
810 for (UInt32 i = 1; i < codeSize; i++)
|
rlm@1
|
811 xorSum ^= code[i];
|
rlm@1
|
812
|
rlm@1
|
813 prg->Commands.Clear();
|
rlm@1
|
814 #ifdef RARVM_STANDARD_FILTERS
|
rlm@1
|
815 prg->StandardFilterIndex = -1;
|
rlm@1
|
816 #endif
|
rlm@1
|
817
|
rlm@1
|
818 if (xorSum == code[0] && codeSize > 0)
|
rlm@1
|
819 {
|
rlm@1
|
820 #ifdef RARVM_STANDARD_FILTERS
|
rlm@1
|
821 prg->StandardFilterIndex = FindStandardFilter(code, codeSize);
|
rlm@1
|
822 if (prg->StandardFilterIndex >= 0)
|
rlm@1
|
823 return;
|
rlm@1
|
824 #endif
|
rlm@1
|
825 // 1 byte for checksum
|
rlm@1
|
826 ReadVmProgram(code + 1, codeSize - 1, prg);
|
rlm@1
|
827 }
|
rlm@1
|
828 prg->Commands.Add(CCommand());
|
rlm@1
|
829 CCommand *cmd = &prg->Commands.Back();
|
rlm@1
|
830 cmd->OpCode = CMD_RET;
|
rlm@1
|
831 }
|
rlm@1
|
832
|
rlm@1
|
833 void CVm::SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize)
|
rlm@1
|
834 {
|
rlm@1
|
835 if (pos < kSpaceSize && data != Mem + pos)
|
rlm@1
|
836 memmove(Mem + pos, data, MyMin(dataSize, kSpaceSize - pos));
|
rlm@1
|
837 }
|
rlm@1
|
838
|
rlm@1
|
839 #ifdef RARVM_STANDARD_FILTERS
|
rlm@1
|
840
|
rlm@1
|
841 static void E8E9Decode(Byte *data, UInt32 dataSize, UInt32 fileOffset, bool e9)
|
rlm@1
|
842 {
|
rlm@1
|
843 if (dataSize <= 4)
|
rlm@1
|
844 return;
|
rlm@1
|
845 dataSize -= 4;
|
rlm@1
|
846 const UInt32 kFileSize = 0x1000000;
|
rlm@1
|
847 Byte cmpByte2 = (e9 ? 0xE9 : 0xE8);
|
rlm@1
|
848 for (UInt32 curPos = 0; curPos < dataSize;)
|
rlm@1
|
849 {
|
rlm@1
|
850 Byte curByte = *(data++);
|
rlm@1
|
851 curPos++;
|
rlm@1
|
852 if (curByte == 0xE8 || curByte == cmpByte2)
|
rlm@1
|
853 {
|
rlm@1
|
854 UInt32 offset = curPos + fileOffset;
|
rlm@1
|
855 UInt32 addr = (Int32)GetValue32(data);
|
rlm@1
|
856 if (addr < kFileSize)
|
rlm@1
|
857 SetValue32(data, addr - offset);
|
rlm@1
|
858 else if ((Int32)addr < 0 && (Int32)(addr + offset) >= 0)
|
rlm@1
|
859 SetValue32(data, addr + kFileSize);
|
rlm@1
|
860 data += 4;
|
rlm@1
|
861 curPos += 4;
|
rlm@1
|
862 }
|
rlm@1
|
863 }
|
rlm@1
|
864 }
|
rlm@1
|
865
|
rlm@1
|
866 static inline UInt32 ItaniumGetOpType(const Byte *data, int bitPos)
|
rlm@1
|
867 {
|
rlm@1
|
868 return (data[(unsigned int)bitPos >> 3] >> (bitPos & 7)) & 0xF;
|
rlm@1
|
869 }
|
rlm@1
|
870
|
rlm@1
|
871
|
rlm@1
|
872 static void ItaniumDecode(Byte *data, UInt32 dataSize, UInt32 fileOffset)
|
rlm@1
|
873 {
|
rlm@1
|
874 UInt32 curPos = 0;
|
rlm@1
|
875 fileOffset >>= 4;
|
rlm@1
|
876 while (curPos < dataSize - 21)
|
rlm@1
|
877 {
|
rlm@1
|
878 int b = (data[0] & 0x1F) - 0x10;
|
rlm@1
|
879 if (b >= 0)
|
rlm@1
|
880 {
|
rlm@1
|
881 static Byte kCmdMasks[16] = {4,4,6,6,0,0,7,7,4,4,0,0,4,4,0,0};
|
rlm@1
|
882 Byte cmdMask = kCmdMasks[b];
|
rlm@1
|
883 if (cmdMask != 0)
|
rlm@1
|
884 for (int i = 0; i < 3; i++)
|
rlm@1
|
885 if (cmdMask & (1 << i))
|
rlm@1
|
886 {
|
rlm@1
|
887 int startPos = i * 41 + 18;
|
rlm@1
|
888 if (ItaniumGetOpType(data, startPos + 24) == 5)
|
rlm@1
|
889 {
|
rlm@1
|
890 const UInt32 kMask = 0xFFFFF;
|
rlm@1
|
891 Byte *p = data + ((unsigned int)startPos >> 3);
|
rlm@1
|
892 UInt32 bitField = ((UInt32)p[0]) | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16);
|
rlm@1
|
893 int inBit = (startPos & 7);
|
rlm@1
|
894 UInt32 offset = (bitField >> inBit) & kMask;
|
rlm@1
|
895 UInt32 andMask = ~(kMask << inBit);
|
rlm@1
|
896 bitField = ((offset - fileOffset) & kMask) << inBit;
|
rlm@1
|
897 for (int j = 0; j < 3; j++)
|
rlm@1
|
898 {
|
rlm@1
|
899 p[j] &= andMask;
|
rlm@1
|
900 p[j] |= bitField;
|
rlm@1
|
901 andMask >>= 8;
|
rlm@1
|
902 bitField >>= 8;
|
rlm@1
|
903 }
|
rlm@1
|
904 }
|
rlm@1
|
905 }
|
rlm@1
|
906 }
|
rlm@1
|
907 data += 16;
|
rlm@1
|
908 curPos += 16;
|
rlm@1
|
909 fileOffset++;
|
rlm@1
|
910 }
|
rlm@1
|
911 }
|
rlm@1
|
912
|
rlm@1
|
913 static void DeltaDecode(Byte *data, UInt32 dataSize, UInt32 numChannels)
|
rlm@1
|
914 {
|
rlm@1
|
915 UInt32 srcPos = 0;
|
rlm@1
|
916 UInt32 border = dataSize * 2;
|
rlm@1
|
917 for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
|
rlm@1
|
918 {
|
rlm@1
|
919 Byte prevByte = 0;
|
rlm@1
|
920 for (UInt32 destPos = dataSize + curChannel; destPos < border; destPos += numChannels)
|
rlm@1
|
921 data[destPos] = (prevByte = prevByte - data[srcPos++]);
|
rlm@1
|
922 }
|
rlm@1
|
923 }
|
rlm@1
|
924
|
rlm@1
|
925 static void RgbDecode(Byte *srcData, UInt32 dataSize, UInt32 width, UInt32 posR)
|
rlm@1
|
926 {
|
rlm@1
|
927 Byte *destData = srcData + dataSize;
|
rlm@1
|
928 const UInt32 numChannels = 3;
|
rlm@1
|
929 for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
|
rlm@1
|
930 {
|
rlm@1
|
931 Byte prevByte = 0;
|
rlm@1
|
932
|
rlm@1
|
933 for (UInt32 i = curChannel; i < dataSize; i+= numChannels)
|
rlm@1
|
934 {
|
rlm@1
|
935 unsigned int predicted;
|
rlm@1
|
936 if (i < width)
|
rlm@1
|
937 predicted = prevByte;
|
rlm@1
|
938 else
|
rlm@1
|
939 {
|
rlm@1
|
940 unsigned int upperLeftByte = destData[i - width];
|
rlm@1
|
941 unsigned int upperByte = destData[i - width + 3];
|
rlm@1
|
942 predicted = prevByte + upperByte - upperLeftByte;
|
rlm@1
|
943 int pa = abs((int)(predicted - prevByte));
|
rlm@1
|
944 int pb = abs((int)(predicted - upperByte));
|
rlm@1
|
945 int pc = abs((int)(predicted - upperLeftByte));
|
rlm@1
|
946 if (pa <= pb && pa <= pc)
|
rlm@1
|
947 predicted = prevByte;
|
rlm@1
|
948 else
|
rlm@1
|
949 if (pb <= pc)
|
rlm@1
|
950 predicted = upperByte;
|
rlm@1
|
951 else
|
rlm@1
|
952 predicted = upperLeftByte;
|
rlm@1
|
953 }
|
rlm@1
|
954 destData[i] = prevByte = (Byte)(predicted - *(srcData++));
|
rlm@1
|
955 }
|
rlm@1
|
956 }
|
rlm@1
|
957 if (dataSize < 3)
|
rlm@1
|
958 return;
|
rlm@1
|
959 for (UInt32 i = posR, border = dataSize - 2; i < border; i += 3)
|
rlm@1
|
960 {
|
rlm@1
|
961 Byte g = destData[i + 1];
|
rlm@1
|
962 destData[i] = destData[i] + g;
|
rlm@1
|
963 destData[i + 2] = destData[i + 2] + g;
|
rlm@1
|
964 }
|
rlm@1
|
965 }
|
rlm@1
|
966
|
rlm@1
|
967 static void AudioDecode(Byte *srcData, UInt32 dataSize, UInt32 numChannels)
|
rlm@1
|
968 {
|
rlm@1
|
969 Byte *destData = srcData + dataSize;
|
rlm@1
|
970 for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
|
rlm@1
|
971 {
|
rlm@1
|
972 UInt32 prevByte = 0, prevDelta = 0, dif[7];
|
rlm@1
|
973 Int32 D1 = 0, D2 = 0, D3;
|
rlm@1
|
974 Int32 K1 = 0, K2 = 0, K3 = 0;
|
rlm@1
|
975 memset(dif, 0, sizeof(dif));
|
rlm@1
|
976
|
rlm@1
|
977 for (UInt32 i = curChannel, byteCount = 0; i < dataSize; i += numChannels, byteCount++)
|
rlm@1
|
978 {
|
rlm@1
|
979 D3 = D2;
|
rlm@1
|
980 D2 = prevDelta - D1;
|
rlm@1
|
981 D1 = prevDelta;
|
rlm@1
|
982
|
rlm@1
|
983 UInt32 predicted = 8 * prevByte + K1 * D1 + K2 * D2 + K3 * D3;
|
rlm@1
|
984 predicted = (predicted >> 3) & 0xFF;
|
rlm@1
|
985
|
rlm@1
|
986 UInt32 curByte = *(srcData++);
|
rlm@1
|
987
|
rlm@1
|
988 predicted -= curByte;
|
rlm@1
|
989 destData[i] = (Byte)predicted;
|
rlm@1
|
990 prevDelta = (UInt32)(Int32)(signed char)(predicted - prevByte);
|
rlm@1
|
991 prevByte = predicted;
|
rlm@1
|
992
|
rlm@1
|
993 Int32 D = ((Int32)(signed char)curByte) << 3;
|
rlm@1
|
994
|
rlm@1
|
995 dif[0] += abs(D);
|
rlm@1
|
996 dif[1] += abs(D - D1);
|
rlm@1
|
997 dif[2] += abs(D + D1);
|
rlm@1
|
998 dif[3] += abs(D - D2);
|
rlm@1
|
999 dif[4] += abs(D + D2);
|
rlm@1
|
1000 dif[5] += abs(D - D3);
|
rlm@1
|
1001 dif[6] += abs(D + D3);
|
rlm@1
|
1002
|
rlm@1
|
1003 if ((byteCount & 0x1F) == 0)
|
rlm@1
|
1004 {
|
rlm@1
|
1005 UInt32 minDif = dif[0], numMinDif = 0;
|
rlm@1
|
1006 dif[0] = 0;
|
rlm@1
|
1007 for (int j = 1; j < sizeof(dif) / sizeof(dif[0]); j++)
|
rlm@1
|
1008 {
|
rlm@1
|
1009 if (dif[j] < minDif)
|
rlm@1
|
1010 {
|
rlm@1
|
1011 minDif = dif[j];
|
rlm@1
|
1012 numMinDif = j;
|
rlm@1
|
1013 }
|
rlm@1
|
1014 dif[j] = 0;
|
rlm@1
|
1015 }
|
rlm@1
|
1016 switch (numMinDif)
|
rlm@1
|
1017 {
|
rlm@1
|
1018 case 1: if (K1 >= -16) K1--; break;
|
rlm@1
|
1019 case 2: if (K1 < 16) K1++; break;
|
rlm@1
|
1020 case 3: if (K2 >= -16) K2--; break;
|
rlm@1
|
1021 case 4: if (K2 < 16) K2++; break;
|
rlm@1
|
1022 case 5: if (K3 >= -16) K3--; break;
|
rlm@1
|
1023 case 6: if (K3 < 16) K3++; break;
|
rlm@1
|
1024 }
|
rlm@1
|
1025 }
|
rlm@1
|
1026 }
|
rlm@1
|
1027 }
|
rlm@1
|
1028 }
|
rlm@1
|
1029
|
rlm@1
|
1030 static UInt32 UpCaseDecode(Byte *data, UInt32 dataSize)
|
rlm@1
|
1031 {
|
rlm@1
|
1032 UInt32 srcPos = 0, destPos = dataSize;
|
rlm@1
|
1033 while (srcPos < dataSize)
|
rlm@1
|
1034 {
|
rlm@1
|
1035 Byte curByte = data[srcPos++];
|
rlm@1
|
1036 if (curByte == 2 && (curByte = data[srcPos++]) != 2)
|
rlm@1
|
1037 curByte -= 32;
|
rlm@1
|
1038 data[destPos++] = curByte;
|
rlm@1
|
1039 }
|
rlm@1
|
1040 return destPos - dataSize;
|
rlm@1
|
1041 }
|
rlm@1
|
1042
|
rlm@1
|
1043 void CVm::ExecuteStandardFilter(int filterIndex)
|
rlm@1
|
1044 {
|
rlm@1
|
1045 UInt32 dataSize = R[4];
|
rlm@1
|
1046 if (dataSize >= kGlobalOffset)
|
rlm@1
|
1047 return;
|
rlm@1
|
1048 EStandardFilter filterType = kStdFilters[filterIndex].Type;
|
rlm@1
|
1049
|
rlm@1
|
1050 switch (filterType)
|
rlm@1
|
1051 {
|
rlm@1
|
1052 case SF_E8:
|
rlm@1
|
1053 case SF_E8E9:
|
rlm@1
|
1054 E8E9Decode(Mem, dataSize, R[6], (filterType == SF_E8E9));
|
rlm@1
|
1055 break;
|
rlm@1
|
1056 case SF_ITANIUM:
|
rlm@1
|
1057 ItaniumDecode(Mem, dataSize, R[6]);
|
rlm@1
|
1058 break;
|
rlm@1
|
1059 case SF_DELTA:
|
rlm@1
|
1060 if (dataSize >= kGlobalOffset / 2)
|
rlm@1
|
1061 break;
|
rlm@1
|
1062 SetBlockPos(dataSize);
|
rlm@1
|
1063 DeltaDecode(Mem, dataSize, R[0]);
|
rlm@1
|
1064 break;
|
rlm@1
|
1065 case SF_RGB:
|
rlm@1
|
1066 if (dataSize >= kGlobalOffset / 2)
|
rlm@1
|
1067 break;
|
rlm@1
|
1068 {
|
rlm@1
|
1069 UInt32 width = R[0];
|
rlm@1
|
1070 if (width <= 3)
|
rlm@1
|
1071 break;
|
rlm@1
|
1072 SetBlockPos(dataSize);
|
rlm@1
|
1073 RgbDecode(Mem, dataSize, width, R[1]);
|
rlm@1
|
1074 }
|
rlm@1
|
1075 break;
|
rlm@1
|
1076 case SF_AUDIO:
|
rlm@1
|
1077 if (dataSize >= kGlobalOffset / 2)
|
rlm@1
|
1078 break;
|
rlm@1
|
1079 SetBlockPos(dataSize);
|
rlm@1
|
1080 AudioDecode(Mem, dataSize, R[0]);
|
rlm@1
|
1081 break;
|
rlm@1
|
1082 case SF_UPCASE:
|
rlm@1
|
1083 if (dataSize >= kGlobalOffset / 2)
|
rlm@1
|
1084 break;
|
rlm@1
|
1085 UInt32 destSize = UpCaseDecode(Mem, dataSize);
|
rlm@1
|
1086 SetBlockSize(destSize);
|
rlm@1
|
1087 SetBlockPos(dataSize);
|
rlm@1
|
1088 break;
|
rlm@1
|
1089 }
|
rlm@1
|
1090 }
|
rlm@1
|
1091
|
rlm@1
|
1092 #endif
|
rlm@1
|
1093
|
rlm@1
|
1094 }}}
|