2 // According to unRAR license, this code may not be used to develop
\r
3 // a program that creates RAR archives
\r
7 Due to performance considerations Rar VM may set Flags C incorrectly
\r
8 for some operands (SHL x, 0, ... ).
\r
9 Check implementation of concrete VM command
\r
10 to see if it sets flags right.
\r
15 #include "../../../C/7zCrc.h"
\r
16 #include "../../../C/Alloc.h"
\r
20 namespace NCompress {
\r
23 UInt32 CMemBitDecoder::ReadBits(int numBits)
\r
28 Byte b = _bitPos < _bitSize ? _data[_bitPos >> 3] : 0;
\r
29 int avail = (int)(8 - (_bitPos & 7));
\r
30 if (numBits <= avail)
\r
33 return res | (b >> (avail - numBits)) & ((1 << numBits) - 1);
\r
36 res |= (UInt32)(b & ((1 << avail) - 1)) << numBits;
\r
41 UInt32 CMemBitDecoder::ReadBit() { return ReadBits(1); }
\r
45 static const UInt32 kStackRegIndex = kNumRegs - 1;
\r
47 static const UInt32 FLAG_C = 1;
\r
48 static const UInt32 FLAG_Z = 2;
\r
49 static const UInt32 FLAG_S = 0x80000000;
\r
51 static const Byte CF_OP0 = 0;
\r
52 static const Byte CF_OP1 = 1;
\r
53 static const Byte CF_OP2 = 2;
\r
54 static const Byte CF_OPMASK = 3;
\r
55 static const Byte CF_BYTEMODE = 4;
\r
56 static const Byte CF_JUMP = 8;
\r
57 static const Byte CF_PROC = 16;
\r
58 static const Byte CF_USEFLAGS = 32;
\r
59 static const Byte CF_CHFLAGS = 64;
\r
61 static Byte kCmdFlags[]=
\r
63 /* CMD_MOV */ CF_OP2 | CF_BYTEMODE,
\r
64 /* CMD_CMP */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
\r
65 /* CMD_ADD */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
\r
66 /* CMD_SUB */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
\r
67 /* CMD_JZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
\r
68 /* CMD_JNZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
\r
69 /* CMD_INC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
\r
70 /* CMD_DEC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
\r
71 /* CMD_JMP */ CF_OP1 | CF_JUMP,
\r
72 /* CMD_XOR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
\r
73 /* CMD_AND */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
\r
74 /* CMD_OR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
\r
75 /* CMD_TEST */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
\r
76 /* CMD_JS */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
\r
77 /* CMD_JNS */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
\r
78 /* CMD_JB */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
\r
79 /* CMD_JBE */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
\r
80 /* CMD_JA */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
\r
81 /* CMD_JAE */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
\r
82 /* CMD_PUSH */ CF_OP1,
\r
83 /* CMD_POP */ CF_OP1,
\r
84 /* CMD_CALL */ CF_OP1 | CF_PROC,
\r
85 /* CMD_RET */ CF_OP0 | CF_PROC,
\r
86 /* CMD_NOT */ CF_OP1 | CF_BYTEMODE,
\r
87 /* CMD_SHL */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
\r
88 /* CMD_SHR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
\r
89 /* CMD_SAR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
\r
90 /* CMD_NEG */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
\r
91 /* CMD_PUSHA */ CF_OP0,
\r
92 /* CMD_POPA */ CF_OP0,
\r
93 /* CMD_PUSHF */ CF_OP0 | CF_USEFLAGS,
\r
94 /* CMD_POPF */ CF_OP0 | CF_CHFLAGS,
\r
95 /* CMD_MOVZX */ CF_OP2,
\r
96 /* CMD_MOVSX */ CF_OP2,
\r
97 /* CMD_XCHG */ CF_OP2 | CF_BYTEMODE,
\r
98 /* CMD_MUL */ CF_OP2 | CF_BYTEMODE,
\r
99 /* CMD_DIV */ CF_OP2 | CF_BYTEMODE,
\r
100 /* CMD_ADC */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS ,
\r
101 /* CMD_SBB */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS ,
\r
102 /* CMD_PRINT */ CF_OP0
\r
105 CVm::CVm(): Mem(NULL) {}
\r
110 Mem = (Byte *)::MyAlloc(kSpaceSize + 4);
\r
111 return (Mem != NULL);
\r
119 // CVm::Execute can change CProgram object: it clears progarm if VM returns error.
\r
121 bool CVm::Execute(CProgram *prg, const CProgramInitState *initState,
\r
122 CBlockRef &outBlockRef, CRecordVector<Byte> &outGlobalData)
\r
124 memcpy(R, initState->InitR, sizeof(initState->InitR));
\r
125 R[kStackRegIndex] = kSpaceSize;
\r
129 UInt32 globalSize = MyMin((UInt32)initState->GlobalData.Size(), kGlobalSize);
\r
130 if (globalSize != 0)
\r
131 memcpy(Mem + kGlobalOffset, &initState->GlobalData[0], globalSize);
\r
132 UInt32 staticSize = MyMin((UInt32)prg->StaticData.Size(), kGlobalSize - globalSize);
\r
133 if (staticSize != 0)
\r
134 memcpy(Mem + kGlobalOffset + globalSize, &prg->StaticData[0], staticSize);
\r
137 #ifdef RARVM_STANDARD_FILTERS
\r
138 if (prg->StandardFilterIndex >= 0)
\r
139 ExecuteStandardFilter(prg->StandardFilterIndex);
\r
143 res = ExecuteCode(prg);
\r
145 prg->Commands[0].OpCode = CMD_RET;
\r
147 UInt32 newBlockPos = GetFixedGlobalValue32(NGlobalOffset::kBlockPos) & kSpaceMask;
\r
148 UInt32 newBlockSize = GetFixedGlobalValue32(NGlobalOffset::kBlockSize) & kSpaceMask;
\r
149 if (newBlockPos + newBlockSize >= kSpaceSize)
\r
150 newBlockPos = newBlockSize = 0;
\r
151 outBlockRef.Offset = newBlockPos;
\r
152 outBlockRef.Size = newBlockSize;
\r
154 outGlobalData.Clear();
\r
155 UInt32 dataSize = GetFixedGlobalValue32(NGlobalOffset::kGlobalMemOutSize);
\r
156 dataSize = MyMin(dataSize, kGlobalSize - kFixedGlobalSize);
\r
159 dataSize += kFixedGlobalSize;
\r
160 outGlobalData.Reserve(dataSize);
\r
161 for (UInt32 i = 0; i < dataSize; i++)
\r
162 outGlobalData.Add(Mem[kGlobalOffset + i]);
\r
168 #define SET_IP(IP) \
\r
169 if ((IP) >= numCommands) return true; \
\r
170 if (--maxOpCount <= 0) return false; \
\r
171 cmd = commands + (IP);
\r
173 #define GET_FLAG_S_B(res) (((res) & 0x80) ? FLAG_S : 0)
\r
174 #define SET_IP_OP1 { UInt32 val = GetOperand32(&cmd->Op1); SET_IP(val); }
\r
175 #define FLAGS_UPDATE_SZ Flags = res == 0 ? FLAG_Z : res & FLAG_S
\r
176 #define FLAGS_UPDATE_SZ_B Flags = (res & 0xFF) == 0 ? FLAG_Z : GET_FLAG_S_B(res)
\r
178 UInt32 CVm::GetOperand32(const COperand *op) const
\r
182 case OP_TYPE_REG: return R[op->Data];
\r
183 case OP_TYPE_REGMEM: return GetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask]);
\r
184 default: return op->Data;
\r
188 void CVm::SetOperand32(const COperand *op, UInt32 val)
\r
192 case OP_TYPE_REG: R[op->Data] = val; return;
\r
193 case OP_TYPE_REGMEM: SetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask], val); return;
\r
197 Byte CVm::GetOperand8(const COperand *op) const
\r
201 case OP_TYPE_REG: return (Byte)R[op->Data];
\r
202 case OP_TYPE_REGMEM: return Mem[(op->Base + R[op->Data]) & kSpaceMask];;
\r
203 default: return (Byte)op->Data;
\r
207 void CVm::SetOperand8(const COperand *op, Byte val)
\r
211 case OP_TYPE_REG: R[op->Data] = (R[op->Data] & 0xFFFFFF00) | val; return;
\r
212 case OP_TYPE_REGMEM: Mem[(op->Base + R[op->Data]) & kSpaceMask] = val; return;
\r
216 UInt32 CVm::GetOperand(bool byteMode, const COperand *op) const
\r
219 return GetOperand8(op);
\r
220 return GetOperand32(op);
\r
223 void CVm::SetOperand(bool byteMode, const COperand *op, UInt32 val)
\r
226 SetOperand8(op, (Byte)(val & 0xFF));
\r
228 SetOperand32(op, val);
\r
231 bool CVm::ExecuteCode(const CProgram *prg)
\r
233 Int32 maxOpCount = 25000000;
\r
234 const CCommand *commands = &prg->Commands[0];
\r
235 const CCommand *cmd = commands;
\r
236 UInt32 numCommands = prg->Commands.Size();
\r
239 switch(cmd->OpCode)
\r
241 #ifndef RARVM_NO_VM
\r
244 SetOperand32(&cmd->Op1, GetOperand32(&cmd->Op2));
\r
247 SetOperand8(&cmd->Op1, GetOperand8(&cmd->Op2));
\r
251 UInt32 v1 = GetOperand32(&cmd->Op1);
\r
252 UInt32 res = v1 - GetOperand32(&cmd->Op2);
\r
253 Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
\r
258 Byte v1 = GetOperand8(&cmd->Op1);
\r
259 Byte res = v1 - GetOperand8(&cmd->Op2);
\r
261 Flags = res == 0 ? FLAG_Z : (res > v1) | GET_FLAG_S_B(res);
\r
266 UInt32 v1 = GetOperand32(&cmd->Op1);
\r
267 UInt32 res = v1 + GetOperand32(&cmd->Op2);
\r
268 SetOperand32(&cmd->Op1, res);
\r
269 Flags = (res < v1) | (res == 0 ? FLAG_Z : (res & FLAG_S));
\r
274 Byte v1 = GetOperand8(&cmd->Op1);
\r
275 Byte res = v1 + GetOperand8(&cmd->Op2);
\r
277 SetOperand8(&cmd->Op1, (Byte)res);
\r
278 Flags = (res < v1) | (res == 0 ? FLAG_Z : GET_FLAG_S_B(res));
\r
283 UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
\r
284 UInt32 FC = (Flags & FLAG_C);
\r
285 UInt32 res = v1 + GetOperand(cmd->ByteMode, &cmd->Op2) + FC;
\r
288 SetOperand(cmd->ByteMode, &cmd->Op1, res);
\r
289 Flags = (res < v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S));
\r
294 UInt32 v1 = GetOperand32(&cmd->Op1);
\r
295 UInt32 res = v1 - GetOperand32(&cmd->Op2);
\r
296 SetOperand32(&cmd->Op1, res);
\r
297 Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
\r
302 UInt32 v1 = GetOperand8(&cmd->Op1);
\r
303 UInt32 res = v1 - GetOperand8(&cmd->Op2);
\r
304 SetOperand8(&cmd->Op1, (Byte)res);
\r
305 Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
\r
310 UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
\r
311 UInt32 FC = (Flags & FLAG_C);
\r
312 UInt32 res = v1 - GetOperand(cmd->ByteMode, &cmd->Op2) - FC;
\r
313 // Flags = res == 0 ? FLAG_Z : (res > v1 || res == v1 && FC) | (res & FLAG_S);
\r
316 SetOperand(cmd->ByteMode, &cmd->Op1, res);
\r
317 Flags = (res > v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S));
\r
322 UInt32 res = GetOperand32(&cmd->Op1) + 1;
\r
323 SetOperand32(&cmd->Op1, res);
\r
329 Byte res = GetOperand8(&cmd->Op1) + 1;
\r
330 SetOperand8(&cmd->Op1, res);;
\r
336 UInt32 res = GetOperand32(&cmd->Op1) - 1;
\r
337 SetOperand32(&cmd->Op1, res);
\r
343 Byte res = GetOperand8(&cmd->Op1) - 1;
\r
344 SetOperand8(&cmd->Op1, res);;
\r
350 UInt32 res = GetOperand32(&cmd->Op1) ^ GetOperand32(&cmd->Op2);
\r
351 SetOperand32(&cmd->Op1, res);
\r
357 Byte res = GetOperand8(&cmd->Op1) ^ GetOperand8(&cmd->Op2);
\r
358 SetOperand8(&cmd->Op1, res);
\r
364 UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2);
\r
365 SetOperand32(&cmd->Op1, res);
\r
371 Byte res = GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2);
\r
372 SetOperand8(&cmd->Op1, res);
\r
378 UInt32 res = GetOperand32(&cmd->Op1) | GetOperand32(&cmd->Op2);
\r
379 SetOperand32(&cmd->Op1, res);
\r
385 Byte res = GetOperand8(&cmd->Op1) | GetOperand8(&cmd->Op2);
\r
386 SetOperand8(&cmd->Op1, res);
\r
392 UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2);
\r
398 Byte res = GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2);
\r
403 SetOperand(cmd->ByteMode, &cmd->Op1, ~GetOperand(cmd->ByteMode, &cmd->Op1));
\r
407 UInt32 res = 0 - GetOperand32(&cmd->Op1);
\r
408 SetOperand32(&cmd->Op1, res);
\r
409 Flags = res == 0 ? FLAG_Z : FLAG_C | (res & FLAG_S);
\r
414 Byte res = (Byte)(0 - GetOperand8(&cmd->Op1));
\r
415 SetOperand8(&cmd->Op1, res);
\r
416 Flags = res == 0 ? FLAG_Z : FLAG_C | GET_FLAG_S_B(res);
\r
422 UInt32 v1 = GetOperand32(&cmd->Op1);
\r
423 int v2 = (int)GetOperand32(&cmd->Op2);
\r
424 UInt32 res = v1 << v2;
\r
425 SetOperand32(&cmd->Op1, res);
\r
426 Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 << (v2 - 1)) & 0x80000000 ? FLAG_C : 0);
\r
431 Byte v1 = GetOperand8(&cmd->Op1);
\r
432 int v2 = (int)GetOperand8(&cmd->Op2);
\r
433 Byte res = (Byte)(v1 << v2);
\r
434 SetOperand8(&cmd->Op1, res);
\r
435 Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 << (v2 - 1)) & 0x80 ? FLAG_C : 0);
\r
440 UInt32 v1 = GetOperand32(&cmd->Op1);
\r
441 int v2 = (int)GetOperand32(&cmd->Op2);
\r
442 UInt32 res = v1 >> v2;
\r
443 SetOperand32(&cmd->Op1, res);
\r
444 Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C);
\r
449 Byte v1 = GetOperand8(&cmd->Op1);
\r
450 int v2 = (int)GetOperand8(&cmd->Op2);
\r
451 Byte res = (Byte)(v1 >> v2);
\r
452 SetOperand8(&cmd->Op1, res);
\r
453 Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C);
\r
458 UInt32 v1 = GetOperand32(&cmd->Op1);
\r
459 int v2 = (int)GetOperand32(&cmd->Op2);
\r
460 UInt32 res = UInt32(((Int32)v1) >> v2);
\r
461 SetOperand32(&cmd->Op1, res);
\r
462 Flags= (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C);
\r
467 Byte v1 = GetOperand8(&cmd->Op1);
\r
468 int v2 = (int)GetOperand8(&cmd->Op2);
\r
469 Byte res = (Byte)(((signed char)v1) >> v2);
\r
470 SetOperand8(&cmd->Op1, res);
\r
471 Flags= (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C);
\r
479 if ((Flags & FLAG_Z) != 0)
\r
486 if ((Flags & FLAG_Z) == 0)
\r
493 if ((Flags & FLAG_S) != 0)
\r
500 if ((Flags & FLAG_S) == 0)
\r
507 if ((Flags & FLAG_C) != 0)
\r
514 if ((Flags & (FLAG_C | FLAG_Z)) != 0)
\r
521 if ((Flags & (FLAG_C | FLAG_Z)) == 0)
\r
528 if ((Flags & FLAG_C) == 0)
\r
536 R[kStackRegIndex] -= 4;
\r
537 SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], GetOperand32(&cmd->Op1));
\r
540 SetOperand32(&cmd->Op1, GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]));
\r
541 R[kStackRegIndex] += 4;
\r
544 R[kStackRegIndex] -= 4;
\r
545 SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], (UInt32)(cmd - commands + 1));
\r
551 for (UInt32 i = 0, SP = R[kStackRegIndex] - 4; i < kNumRegs; i++, SP -= 4)
\r
552 SetValue32(&Mem[SP & kSpaceMask], R[i]);
\r
553 R[kStackRegIndex] -= kNumRegs * 4;
\r
558 for (UInt32 i = 0, SP = R[kStackRegIndex]; i < kNumRegs; i++, SP += 4)
\r
559 R[kStackRegIndex - i] = GetValue32(&Mem[SP & kSpaceMask]);
\r
563 R[kStackRegIndex] -= 4;
\r
564 SetValue32(&Mem[R[kStackRegIndex]&kSpaceMask], Flags);
\r
567 Flags = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]);
\r
568 R[kStackRegIndex] += 4;
\r
572 SetOperand32(&cmd->Op1, GetOperand8(&cmd->Op2));
\r
575 SetOperand32(&cmd->Op1, (UInt32)(Int32)(signed char)GetOperand8(&cmd->Op2));
\r
579 UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
\r
580 SetOperand(cmd->ByteMode, &cmd->Op1, GetOperand(cmd->ByteMode, &cmd->Op2));
\r
581 SetOperand(cmd->ByteMode, &cmd->Op2, v1);
\r
586 UInt32 res = GetOperand32(&cmd->Op1) * GetOperand32(&cmd->Op2);
\r
587 SetOperand32(&cmd->Op1, res);
\r
592 Byte res = GetOperand8(&cmd->Op1) * GetOperand8(&cmd->Op2);
\r
593 SetOperand8(&cmd->Op1, res);
\r
598 UInt32 divider = GetOperand(cmd->ByteMode, &cmd->Op2);
\r
601 UInt32 res = GetOperand(cmd->ByteMode, &cmd->Op1) / divider;
\r
602 SetOperand(cmd->ByteMode, &cmd->Op1, res);
\r
611 if (R[kStackRegIndex] >= kSpaceSize)
\r
613 UInt32 ip = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]);
\r
615 R[kStackRegIndex] += 4;
\r
627 //////////////////////////////////////////////////////
\r
630 UInt32 ReadEncodedUInt32(CMemBitDecoder &inp)
\r
632 switch(inp.ReadBits(2))
\r
635 return inp.ReadBits(4);
\r
638 UInt32 v = inp.ReadBits(4);
\r
640 return 0xFFFFFF00 | inp.ReadBits(8);
\r
642 return (v << 4) | inp.ReadBits(4);
\r
645 return inp.ReadBits(16);
\r
647 return inp.ReadBits(32);
\r
651 void CVm::DecodeArg(CMemBitDecoder &inp, COperand &op, bool byteMode)
\r
655 op.Type = OP_TYPE_REG;
\r
656 op.Data = inp.ReadBits(kNumRegBits);
\r
658 else if (inp.ReadBit() == 0)
\r
660 op.Type = OP_TYPE_INT;
\r
662 op.Data = inp.ReadBits(8);
\r
664 op.Data = ReadEncodedUInt32(inp);
\r
668 op.Type = OP_TYPE_REGMEM;
\r
669 if (inp.ReadBit() == 0)
\r
671 op.Data = inp.ReadBits(kNumRegBits);
\r
676 if (inp.ReadBit() == 0)
\r
677 op.Data = inp.ReadBits(kNumRegBits);
\r
679 op.Data = kNumRegs;
\r
680 op.Base = ReadEncodedUInt32(inp);
\r
685 void CVm::ReadVmProgram(const Byte *code, UInt32 codeSize, CProgram *prg)
\r
687 CMemBitDecoder inp;
\r
688 inp.Init(code, codeSize);
\r
690 prg->StaticData.Clear();
\r
693 UInt32 dataSize = ReadEncodedUInt32(inp) + 1;
\r
694 for (UInt32 i = 0; inp.Avail() && i < dataSize; i++)
\r
695 prg->StaticData.Add((Byte)inp.ReadBits(8));
\r
697 while (inp.Avail())
\r
699 prg->Commands.Add(CCommand());
\r
700 CCommand *cmd = &prg->Commands.Back();
\r
701 if (inp.ReadBit() == 0)
\r
702 cmd->OpCode = (ECommand)inp.ReadBits(3);
\r
704 cmd->OpCode = (ECommand)(8 + inp.ReadBits(5));
\r
705 if (kCmdFlags[cmd->OpCode] & CF_BYTEMODE)
\r
706 cmd->ByteMode = (inp.ReadBit()) ? true : false;
\r
709 int opNum = (kCmdFlags[cmd->OpCode] & CF_OPMASK);
\r
712 DecodeArg(inp, cmd->Op1, cmd->ByteMode);
\r
714 DecodeArg(inp, cmd->Op2, cmd->ByteMode);
\r
717 if (cmd->Op1.Type == OP_TYPE_INT && (kCmdFlags[cmd->OpCode] & (CF_JUMP | CF_PROC)))
\r
719 int Distance = cmd->Op1.Data;
\r
720 if (Distance >= 256)
\r
724 if (Distance >= 136)
\r
726 else if (Distance >= 16)
\r
728 else if (Distance >= 8)
\r
730 Distance += prg->Commands.Size() - 1;
\r
732 cmd->Op1.Data = Distance;
\r
738 switch (cmd->OpCode)
\r
740 case CMD_MOV: cmd->OpCode = CMD_MOVB; break;
\r
741 case CMD_CMP: cmd->OpCode = CMD_CMPB; break;
\r
742 case CMD_ADD: cmd->OpCode = CMD_ADDB; break;
\r
743 case CMD_SUB: cmd->OpCode = CMD_SUBB; break;
\r
744 case CMD_INC: cmd->OpCode = CMD_INCB; break;
\r
745 case CMD_DEC: cmd->OpCode = CMD_DECB; break;
\r
746 case CMD_XOR: cmd->OpCode = CMD_XORB; break;
\r
747 case CMD_AND: cmd->OpCode = CMD_ANDB; break;
\r
748 case CMD_OR: cmd->OpCode = CMD_ORB; break;
\r
749 case CMD_TEST: cmd->OpCode = CMD_TESTB; break;
\r
750 case CMD_NEG: cmd->OpCode = CMD_NEGB; break;
\r
751 case CMD_SHL: cmd->OpCode = CMD_SHLB; break;
\r
752 case CMD_SHR: cmd->OpCode = CMD_SHRB; break;
\r
753 case CMD_SAR: cmd->OpCode = CMD_SARB; break;
\r
754 case CMD_MUL: cmd->OpCode = CMD_MULB; break;
\r
760 #ifdef RARVM_STANDARD_FILTERS
\r
762 enum EStandardFilter
\r
773 struct StandardFilterSignature
\r
777 EStandardFilter Type;
\r
781 { 53, 0xad576887, SF_E8 },
\r
782 { 57, 0x3cd7e57e, SF_E8E9 },
\r
783 { 120, 0x3769893f, SF_ITANIUM },
\r
784 { 29, 0x0e06077d, SF_DELTA },
\r
785 { 149, 0x1c2c5dc8, SF_RGB },
\r
786 { 216, 0xbc85e701, SF_AUDIO },
\r
787 { 40, 0x46b9c560, SF_UPCASE }
\r
790 static int FindStandardFilter(const Byte *code, UInt32 codeSize)
\r
792 UInt32 crc = CrcCalc(code, codeSize);
\r
793 for (int i = 0; i < sizeof(kStdFilters) / sizeof(kStdFilters[0]); i++)
\r
795 StandardFilterSignature &sfs = kStdFilters[i];
\r
796 if (sfs.CRC == crc && sfs.Length == codeSize)
\r
804 void CVm::PrepareProgram(const Byte *code, UInt32 codeSize, CProgram *prg)
\r
807 for (UInt32 i = 1; i < codeSize; i++)
\r
810 prg->Commands.Clear();
\r
811 #ifdef RARVM_STANDARD_FILTERS
\r
812 prg->StandardFilterIndex = -1;
\r
815 if (xorSum == code[0] && codeSize > 0)
\r
817 #ifdef RARVM_STANDARD_FILTERS
\r
818 prg->StandardFilterIndex = FindStandardFilter(code, codeSize);
\r
819 if (prg->StandardFilterIndex >= 0)
\r
822 // 1 byte for checksum
\r
823 ReadVmProgram(code + 1, codeSize - 1, prg);
\r
825 prg->Commands.Add(CCommand());
\r
826 CCommand *cmd = &prg->Commands.Back();
\r
827 cmd->OpCode = CMD_RET;
\r
830 void CVm::SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize)
\r
832 if (pos < kSpaceSize && data != Mem + pos)
\r
833 memmove(Mem + pos, data, MyMin(dataSize, kSpaceSize - pos));
\r
836 #ifdef RARVM_STANDARD_FILTERS
\r
838 static void E8E9Decode(Byte *data, UInt32 dataSize, UInt32 fileOffset, bool e9)
\r
843 const UInt32 kFileSize = 0x1000000;
\r
844 Byte cmpByte2 = (e9 ? 0xE9 : 0xE8);
\r
845 for (UInt32 curPos = 0; curPos < dataSize;)
\r
847 Byte curByte = *(data++);
\r
849 if (curByte == 0xE8 || curByte == cmpByte2)
\r
851 UInt32 offset = curPos + fileOffset;
\r
852 UInt32 addr = (Int32)GetValue32(data);
\r
853 if (addr < kFileSize)
\r
854 SetValue32(data, addr - offset);
\r
855 else if ((Int32)addr < 0 && (Int32)(addr + offset) >= 0)
\r
856 SetValue32(data, addr + kFileSize);
\r
863 static inline UInt32 ItaniumGetOpType(const Byte *data, int bitPos)
\r
865 return (data[(unsigned int)bitPos >> 3] >> (bitPos & 7)) & 0xF;
\r
869 static void ItaniumDecode(Byte *data, UInt32 dataSize, UInt32 fileOffset)
\r
873 while (curPos < dataSize - 21)
\r
875 int b = (data[0] & 0x1F) - 0x10;
\r
878 static Byte kCmdMasks[16] = {4,4,6,6,0,0,7,7,4,4,0,0,4,4,0,0};
\r
879 Byte cmdMask = kCmdMasks[b];
\r
881 for (int i = 0; i < 3; i++)
\r
882 if (cmdMask & (1 << i))
\r
884 int startPos = i * 41 + 18;
\r
885 if (ItaniumGetOpType(data, startPos + 24) == 5)
\r
887 const UInt32 kMask = 0xFFFFF;
\r
888 Byte *p = data + ((unsigned int)startPos >> 3);
\r
889 UInt32 bitField = ((UInt32)p[0]) | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16);
\r
890 int inBit = (startPos & 7);
\r
891 UInt32 offset = (bitField >> inBit) & kMask;
\r
892 UInt32 andMask = ~(kMask << inBit);
\r
893 bitField = ((offset - fileOffset) & kMask) << inBit;
\r
894 for (int j = 0; j < 3; j++)
\r
910 static void DeltaDecode(Byte *data, UInt32 dataSize, UInt32 numChannels)
\r
913 UInt32 border = dataSize * 2;
\r
914 for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
\r
917 for (UInt32 destPos = dataSize + curChannel; destPos < border; destPos += numChannels)
\r
918 data[destPos] = (prevByte = prevByte - data[srcPos++]);
\r
922 static void RgbDecode(Byte *srcData, UInt32 dataSize, UInt32 width, UInt32 posR)
\r
924 Byte *destData = srcData + dataSize;
\r
925 const UInt32 numChannels = 3;
\r
926 for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
\r
930 for (UInt32 i = curChannel; i < dataSize; i+= numChannels)
\r
932 unsigned int predicted;
\r
934 predicted = prevByte;
\r
937 unsigned int upperLeftByte = destData[i - width];
\r
938 unsigned int upperByte = destData[i - width + 3];
\r
939 predicted = prevByte + upperByte - upperLeftByte;
\r
940 int pa = abs((int)(predicted - prevByte));
\r
941 int pb = abs((int)(predicted - upperByte));
\r
942 int pc = abs((int)(predicted - upperLeftByte));
\r
943 if (pa <= pb && pa <= pc)
\r
944 predicted = prevByte;
\r
947 predicted = upperByte;
\r
949 predicted = upperLeftByte;
\r
951 destData[i] = prevByte = (Byte)(predicted - *(srcData++));
\r
956 for (UInt32 i = posR, border = dataSize - 2; i < border; i += 3)
\r
958 Byte g = destData[i + 1];
\r
959 destData[i] = destData[i] + g;
\r
960 destData[i + 2] = destData[i + 2] + g;
\r
964 static void AudioDecode(Byte *srcData, UInt32 dataSize, UInt32 numChannels)
\r
966 Byte *destData = srcData + dataSize;
\r
967 for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
\r
969 UInt32 prevByte = 0, prevDelta = 0, dif[7];
\r
970 Int32 D1 = 0, D2 = 0, D3;
\r
971 Int32 K1 = 0, K2 = 0, K3 = 0;
\r
972 memset(dif, 0, sizeof(dif));
\r
974 for (UInt32 i = curChannel, byteCount = 0; i < dataSize; i += numChannels, byteCount++)
\r
977 D2 = prevDelta - D1;
\r
980 UInt32 predicted = 8 * prevByte + K1 * D1 + K2 * D2 + K3 * D3;
\r
981 predicted = (predicted >> 3) & 0xFF;
\r
983 UInt32 curByte = *(srcData++);
\r
985 predicted -= curByte;
\r
986 destData[i] = (Byte)predicted;
\r
987 prevDelta = (UInt32)(Int32)(signed char)(predicted - prevByte);
\r
988 prevByte = predicted;
\r
990 Int32 D = ((Int32)(signed char)curByte) << 3;
\r
993 dif[1] += abs(D - D1);
\r
994 dif[2] += abs(D + D1);
\r
995 dif[3] += abs(D - D2);
\r
996 dif[4] += abs(D + D2);
\r
997 dif[5] += abs(D - D3);
\r
998 dif[6] += abs(D + D3);
\r
1000 if ((byteCount & 0x1F) == 0)
\r
1002 UInt32 minDif = dif[0], numMinDif = 0;
\r
1004 for (int j = 1; j < sizeof(dif) / sizeof(dif[0]); j++)
\r
1006 if (dif[j] < minDif)
\r
1013 switch (numMinDif)
\r
1015 case 1: if (K1 >= -16) K1--; break;
\r
1016 case 2: if (K1 < 16) K1++; break;
\r
1017 case 3: if (K2 >= -16) K2--; break;
\r
1018 case 4: if (K2 < 16) K2++; break;
\r
1019 case 5: if (K3 >= -16) K3--; break;
\r
1020 case 6: if (K3 < 16) K3++; break;
\r
1027 static UInt32 UpCaseDecode(Byte *data, UInt32 dataSize)
\r
1029 UInt32 srcPos = 0, destPos = dataSize;
\r
1030 while (srcPos < dataSize)
\r
1032 Byte curByte = data[srcPos++];
\r
1033 if (curByte == 2 && (curByte = data[srcPos++]) != 2)
\r
1035 data[destPos++] = curByte;
\r
1037 return destPos - dataSize;
\r
1040 void CVm::ExecuteStandardFilter(int filterIndex)
\r
1042 UInt32 dataSize = R[4];
\r
1043 if (dataSize >= kGlobalOffset)
\r
1045 EStandardFilter filterType = kStdFilters[filterIndex].Type;
\r
1047 switch (filterType)
\r
1051 E8E9Decode(Mem, dataSize, R[6], (filterType == SF_E8E9));
\r
1054 ItaniumDecode(Mem, dataSize, R[6]);
\r
1057 if (dataSize >= kGlobalOffset / 2)
\r
1059 SetBlockPos(dataSize);
\r
1060 DeltaDecode(Mem, dataSize, R[0]);
\r
1063 if (dataSize >= kGlobalOffset / 2)
\r
1066 UInt32 width = R[0];
\r
1069 SetBlockPos(dataSize);
\r
1070 RgbDecode(Mem, dataSize, width, R[1]);
\r
1074 if (dataSize >= kGlobalOffset / 2)
\r
1076 SetBlockPos(dataSize);
\r
1077 AudioDecode(Mem, dataSize, R[0]);
\r
1080 if (dataSize >= kGlobalOffset / 2)
\r
1082 UInt32 destSize = UpCaseDecode(Mem, dataSize);
\r
1083 SetBlockSize(destSize);
\r
1084 SetBlockPos(dataSize);
\r