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