view 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
line wrap: on
line source
1 // Rar3Vm.cpp
2 // According to unRAR license, this code may not be used to develop
3 // a program that creates RAR archives
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 */
13 #include "StdAfx.h"
15 extern "C"
16 {
17 #include "../../../C/7zCrc.h"
18 #include "../../../C/Alloc.h"
19 }
21 #include "Rar3Vm.h"
23 namespace NCompress {
24 namespace NRar3 {
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 }
44 UInt32 CMemBitDecoder::ReadBit() { return ReadBits(1); }
46 namespace NVm {
48 static const UInt32 kStackRegIndex = kNumRegs - 1;
50 static const UInt32 FLAG_C = 1;
51 static const UInt32 FLAG_Z = 2;
52 static const UInt32 FLAG_S = 0x80000000;
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;
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 };
108 CVm::CVm(): Mem(NULL) {}
110 bool CVm::Create()
111 {
112 if (Mem == NULL)
113 Mem = (Byte *)::MyAlloc(kSpaceSize + 4);
114 return (Mem != NULL);
115 }
117 CVm::~CVm()
118 {
119 ::MyFree(Mem);
120 }
122 // CVm::Execute can change CProgram object: it clears progarm if VM returns error.
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;
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);
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;
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 }
171 #define SET_IP(IP) \
172 if ((IP) >= numCommands) return true; \
173 if (--maxOpCount <= 0) return false; \
174 cmd = commands + (IP);
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)
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 }
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 }
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 }
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 }
219 UInt32 CVm::GetOperand(bool byteMode, const COperand *op) const
220 {
221 if (byteMode)
222 return GetOperand8(op);
223 return GetOperand32(op);
224 }
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 }
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
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;
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;
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;
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;
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;
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;
610 #endif
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 }
630 //////////////////////////////////////////////////////
631 // Read program
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 }
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 }
688 void CVm::ReadVmProgram(const Byte *code, UInt32 codeSize, CProgram *prg)
689 {
690 CMemBitDecoder inp;
691 inp.Init(code, codeSize);
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 }
763 #ifdef RARVM_STANDARD_FILTERS
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 };
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 };
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 }
805 #endif
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];
813 prg->Commands.Clear();
814 #ifdef RARVM_STANDARD_FILTERS
815 prg->StandardFilterIndex = -1;
816 #endif
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 }
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 }
839 #ifdef RARVM_STANDARD_FILTERS
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 }
866 static inline UInt32 ItaniumGetOpType(const Byte *data, int bitPos)
867 {
868 return (data[(unsigned int)bitPos >> 3] >> (bitPos & 7)) & 0xF;
869 }
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 }
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 }
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;
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 }
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));
977 for (UInt32 i = curChannel, byteCount = 0; i < dataSize; i += numChannels, byteCount++)
978 {
979 D3 = D2;
980 D2 = prevDelta - D1;
981 D1 = prevDelta;
983 UInt32 predicted = 8 * prevByte + K1 * D1 + K2 * D2 + K3 * D3;
984 predicted = (predicted >> 3) & 0xFF;
986 UInt32 curByte = *(srcData++);
988 predicted -= curByte;
989 destData[i] = (Byte)predicted;
990 prevDelta = (UInt32)(Int32)(signed char)(predicted - prevByte);
991 prevByte = predicted;
993 Int32 D = ((Int32)(signed char)curByte) << 3;
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);
1003 if ((byteCount & 0x1F) == 0)
1005 UInt32 minDif = dif[0], numMinDif = 0;
1006 dif[0] = 0;
1007 for (int j = 1; j < sizeof(dif) / sizeof(dif[0]); j++)
1009 if (dif[j] < minDif)
1011 minDif = dif[j];
1012 numMinDif = j;
1014 dif[j] = 0;
1016 switch (numMinDif)
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;
1030 static UInt32 UpCaseDecode(Byte *data, UInt32 dataSize)
1032 UInt32 srcPos = 0, destPos = dataSize;
1033 while (srcPos < dataSize)
1035 Byte curByte = data[srcPos++];
1036 if (curByte == 2 && (curByte = data[srcPos++]) != 2)
1037 curByte -= 32;
1038 data[destPos++] = curByte;
1040 return destPos - dataSize;
1043 void CVm::ExecuteStandardFilter(int filterIndex)
1045 UInt32 dataSize = R[4];
1046 if (dataSize >= kGlobalOffset)
1047 return;
1048 EStandardFilter filterType = kStdFilters[filterIndex].Type;
1050 switch (filterType)
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;
1069 UInt32 width = R[0];
1070 if (width <= 3)
1071 break;
1072 SetBlockPos(dataSize);
1073 RgbDecode(Mem, dataSize, width, R[1]);
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;
1092 #endif
1094 }}}