Mercurial > vba-linux
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.cpp2 // According to unRAR license, this code may not be used to develop3 // a program that creates RAR archives5 /*6 Note:7 Due to performance considerations Rar VM may set Flags C incorrectly8 for some operands (SHL x, 0, ... ).9 Check implementation of concrete VM command10 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_OP0106 };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_FILTERS141 if (prg->StandardFilterIndex >= 0)142 ExecuteStandardFilter(prg->StandardFilterIndex);143 else144 #endif145 {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_S179 #define FLAGS_UPDATE_SZ_B Flags = (res & 0xFF) == 0 ? FLAG_Z : GET_FLAG_S_B(res)181 UInt32 CVm::GetOperand32(const COperand *op) const182 {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) const201 {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) const220 {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 else231 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_VM246 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 #endif612 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 program633 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 else645 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 else667 op.Data = ReadEncodedUInt32(inp);668 }669 else670 {671 op.Type = OP_TYPE_REGMEM;672 if (inp.ReadBit() == 0)673 {674 op.Data = inp.ReadBits(kNumRegBits);675 op.Base = 0;676 }677 else678 {679 if (inp.ReadBit() == 0)680 op.Data = inp.ReadBits(kNumRegBits);681 else682 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 else707 cmd->OpCode = (ECommand)(8 + inp.ReadBits(5));708 if (kCmdFlags[cmd->OpCode] & CF_BYTEMODE)709 cmd->ByteMode = (inp.ReadBit()) ? true : false;710 else711 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 else719 {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 else726 {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_FILTERS765 enum EStandardFilter766 {767 SF_E8,768 SF_E8E9,769 SF_ITANIUM,770 SF_RGB,771 SF_AUDIO,772 SF_DELTA,773 SF_UPCASE774 };776 struct StandardFilterSignature777 {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_UPCASE791 };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 #endif807 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_FILTERS815 prg->StandardFilterIndex = -1;816 #endif818 if (xorSum == code[0] && codeSize > 0)819 {820 #ifdef RARVM_STANDARD_FILTERS821 prg->StandardFilterIndex = FindStandardFilter(code, codeSize);822 if (prg->StandardFilterIndex >= 0)823 return;824 #endif825 // 1 byte for checksum826 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_FILTERS841 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 else939 {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 else949 if (pb <= pc)950 predicted = upperByte;951 else952 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)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 }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 }1043 void CVm::ExecuteStandardFilter(int filterIndex)1044 {1045 UInt32 dataSize = R[4];1046 if (dataSize >= kGlobalOffset)1047 return;1048 EStandardFilter filterType = kStdFilters[filterIndex].Type;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 }1092 #endif1094 }}}