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