diff 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 diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/win32/7zip/7z/CPP/7zip/Compress/Rar3Vm.cpp	Sat Mar 03 10:31:27 2012 -0600
     1.3 @@ -0,0 +1,1094 @@
     1.4 +// Rar3Vm.cpp
     1.5 +// According to unRAR license, this code may not be used to develop
     1.6 +// a program that creates RAR archives
     1.7 +
     1.8 +/*
     1.9 +Note:
    1.10 +  Due to performance considerations Rar VM may set Flags C incorrectly
    1.11 +  for some operands (SHL x, 0, ... ).
    1.12 +  Check implementation of concrete VM command
    1.13 +  to see if it sets flags right.
    1.14 +*/
    1.15 +
    1.16 +#include "StdAfx.h"
    1.17 +
    1.18 +extern "C"
    1.19 +{
    1.20 +#include "../../../C/7zCrc.h"
    1.21 +#include "../../../C/Alloc.h"
    1.22 +}
    1.23 +
    1.24 +#include "Rar3Vm.h"
    1.25 +
    1.26 +namespace NCompress {
    1.27 +namespace NRar3 {
    1.28 +
    1.29 +UInt32 CMemBitDecoder::ReadBits(int numBits)
    1.30 +{
    1.31 +  UInt32 res = 0;
    1.32 +  for (;;)
    1.33 +  {
    1.34 +    Byte b = _bitPos < _bitSize ? _data[_bitPos >> 3] : 0;
    1.35 +    int avail = (int)(8 - (_bitPos & 7));
    1.36 +    if (numBits <= avail)
    1.37 +    {
    1.38 +      _bitPos += numBits;
    1.39 +      return res | (b >> (avail - numBits)) & ((1 << numBits) - 1);
    1.40 +    }
    1.41 +    numBits -= avail;
    1.42 +    res |= (UInt32)(b & ((1 << avail) - 1)) << numBits;
    1.43 +    _bitPos += avail;
    1.44 +  }
    1.45 +}
    1.46 +
    1.47 +UInt32 CMemBitDecoder::ReadBit() { return ReadBits(1); }
    1.48 +
    1.49 +namespace NVm {
    1.50 +
    1.51 +static const UInt32 kStackRegIndex = kNumRegs - 1;
    1.52 +
    1.53 +static const UInt32 FLAG_C = 1;
    1.54 +static const UInt32 FLAG_Z = 2;
    1.55 +static const UInt32 FLAG_S = 0x80000000;
    1.56 +
    1.57 +static const Byte CF_OP0 = 0;
    1.58 +static const Byte CF_OP1 = 1;
    1.59 +static const Byte CF_OP2 = 2;
    1.60 +static const Byte CF_OPMASK = 3;
    1.61 +static const Byte CF_BYTEMODE = 4;
    1.62 +static const Byte CF_JUMP = 8;
    1.63 +static const Byte CF_PROC = 16;
    1.64 +static const Byte CF_USEFLAGS = 32;
    1.65 +static const Byte CF_CHFLAGS = 64;
    1.66 +
    1.67 +static Byte kCmdFlags[]=
    1.68 +{
    1.69 +  /* CMD_MOV   */ CF_OP2 | CF_BYTEMODE,
    1.70 +  /* CMD_CMP   */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
    1.71 +  /* CMD_ADD   */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
    1.72 +  /* CMD_SUB   */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
    1.73 +  /* CMD_JZ    */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
    1.74 +  /* CMD_JNZ   */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
    1.75 +  /* CMD_INC   */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
    1.76 +  /* CMD_DEC   */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
    1.77 +  /* CMD_JMP   */ CF_OP1 | CF_JUMP,
    1.78 +  /* CMD_XOR   */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
    1.79 +  /* CMD_AND   */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
    1.80 +  /* CMD_OR    */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
    1.81 +  /* CMD_TEST  */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
    1.82 +  /* CMD_JS    */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
    1.83 +  /* CMD_JNS   */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
    1.84 +  /* CMD_JB    */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
    1.85 +  /* CMD_JBE   */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
    1.86 +  /* CMD_JA    */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
    1.87 +  /* CMD_JAE   */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
    1.88 +  /* CMD_PUSH  */ CF_OP1,
    1.89 +  /* CMD_POP   */ CF_OP1,
    1.90 +  /* CMD_CALL  */ CF_OP1 | CF_PROC,
    1.91 +  /* CMD_RET   */ CF_OP0 | CF_PROC,
    1.92 +  /* CMD_NOT   */ CF_OP1 | CF_BYTEMODE,
    1.93 +  /* CMD_SHL   */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
    1.94 +  /* CMD_SHR   */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
    1.95 +  /* CMD_SAR   */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
    1.96 +  /* CMD_NEG   */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
    1.97 +  /* CMD_PUSHA */ CF_OP0,
    1.98 +  /* CMD_POPA  */ CF_OP0,
    1.99 +  /* CMD_PUSHF */ CF_OP0 | CF_USEFLAGS,
   1.100 +  /* CMD_POPF  */ CF_OP0 | CF_CHFLAGS,
   1.101 +  /* CMD_MOVZX */ CF_OP2,
   1.102 +  /* CMD_MOVSX */ CF_OP2,
   1.103 +  /* CMD_XCHG  */ CF_OP2 | CF_BYTEMODE,
   1.104 +  /* CMD_MUL   */ CF_OP2 | CF_BYTEMODE,
   1.105 +  /* CMD_DIV   */ CF_OP2 | CF_BYTEMODE,
   1.106 +  /* CMD_ADC   */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS ,
   1.107 +  /* CMD_SBB   */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS ,
   1.108 +  /* CMD_PRINT */ CF_OP0
   1.109 +};
   1.110 +
   1.111 +CVm::CVm(): Mem(NULL) {}
   1.112 +
   1.113 +bool CVm::Create()
   1.114 +{
   1.115 +  if (Mem == NULL)
   1.116 +    Mem = (Byte *)::MyAlloc(kSpaceSize + 4);
   1.117 +  return (Mem != NULL);
   1.118 +}
   1.119 +
   1.120 +CVm::~CVm()
   1.121 +{
   1.122 +  ::MyFree(Mem);
   1.123 +}
   1.124 +
   1.125 +// CVm::Execute can change CProgram object: it clears progarm if VM returns error.
   1.126 +
   1.127 +bool CVm::Execute(CProgram *prg, const CProgramInitState *initState,
   1.128 +    CBlockRef &outBlockRef, CRecordVector<Byte> &outGlobalData)
   1.129 +{
   1.130 +  memcpy(R, initState->InitR, sizeof(initState->InitR));
   1.131 +  R[kStackRegIndex] = kSpaceSize;
   1.132 +  R[kNumRegs] = 0;
   1.133 +  Flags = 0;
   1.134 +
   1.135 +  UInt32 globalSize = MyMin((UInt32)initState->GlobalData.Size(), kGlobalSize);
   1.136 +  if (globalSize != 0)
   1.137 +    memcpy(Mem + kGlobalOffset, &initState->GlobalData[0], globalSize);
   1.138 +  UInt32 staticSize = MyMin((UInt32)prg->StaticData.Size(), kGlobalSize - globalSize);
   1.139 +  if (staticSize != 0)
   1.140 +    memcpy(Mem + kGlobalOffset + globalSize, &prg->StaticData[0], staticSize);
   1.141 +
   1.142 +  bool res = true;
   1.143 +  #ifdef RARVM_STANDARD_FILTERS
   1.144 +  if (prg->StandardFilterIndex >= 0)
   1.145 +    ExecuteStandardFilter(prg->StandardFilterIndex);
   1.146 +  else
   1.147 +  #endif
   1.148 +  {
   1.149 +    res = ExecuteCode(prg);
   1.150 +    if (!res)
   1.151 +      prg->Commands[0].OpCode = CMD_RET;
   1.152 +  }
   1.153 +  UInt32 newBlockPos = GetFixedGlobalValue32(NGlobalOffset::kBlockPos) & kSpaceMask;
   1.154 +  UInt32 newBlockSize = GetFixedGlobalValue32(NGlobalOffset::kBlockSize) & kSpaceMask;
   1.155 +  if (newBlockPos + newBlockSize >= kSpaceSize)
   1.156 +    newBlockPos = newBlockSize = 0;
   1.157 +  outBlockRef.Offset = newBlockPos;
   1.158 +  outBlockRef.Size = newBlockSize;
   1.159 +
   1.160 +  outGlobalData.Clear();
   1.161 +  UInt32 dataSize = GetFixedGlobalValue32(NGlobalOffset::kGlobalMemOutSize);
   1.162 +  dataSize = MyMin(dataSize, kGlobalSize - kFixedGlobalSize);
   1.163 +  if (dataSize != 0)
   1.164 +  {
   1.165 +    dataSize += kFixedGlobalSize;
   1.166 +    outGlobalData.Reserve(dataSize);
   1.167 +    for (UInt32 i = 0; i < dataSize; i++)
   1.168 +      outGlobalData.Add(Mem[kGlobalOffset + i]);
   1.169 +  }
   1.170 +  return res;
   1.171 +}
   1.172 +
   1.173 +
   1.174 +#define SET_IP(IP) \
   1.175 +  if ((IP) >= numCommands) return true; \
   1.176 +  if (--maxOpCount <= 0) return false; \
   1.177 +  cmd = commands + (IP);
   1.178 +
   1.179 +#define GET_FLAG_S_B(res) (((res) & 0x80) ? FLAG_S : 0)
   1.180 +#define SET_IP_OP1 { UInt32 val = GetOperand32(&cmd->Op1); SET_IP(val); }
   1.181 +#define FLAGS_UPDATE_SZ Flags = res == 0 ? FLAG_Z : res & FLAG_S
   1.182 +#define FLAGS_UPDATE_SZ_B Flags = (res & 0xFF) == 0 ? FLAG_Z : GET_FLAG_S_B(res)
   1.183 +
   1.184 +UInt32 CVm::GetOperand32(const COperand *op) const
   1.185 +{
   1.186 +  switch(op->Type)
   1.187 +  {
   1.188 +    case OP_TYPE_REG: return R[op->Data];
   1.189 +    case OP_TYPE_REGMEM: return GetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask]);
   1.190 +    default: return op->Data;
   1.191 +  }
   1.192 +}
   1.193 +
   1.194 +void CVm::SetOperand32(const COperand *op, UInt32 val)
   1.195 +{
   1.196 +  switch(op->Type)
   1.197 +  {
   1.198 +    case OP_TYPE_REG: R[op->Data] = val; return;
   1.199 +    case OP_TYPE_REGMEM: SetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask], val); return;
   1.200 +  }
   1.201 +}
   1.202 +
   1.203 +Byte CVm::GetOperand8(const COperand *op) const
   1.204 +{
   1.205 +  switch(op->Type)
   1.206 +  {
   1.207 +    case OP_TYPE_REG: return (Byte)R[op->Data];
   1.208 +    case OP_TYPE_REGMEM: return Mem[(op->Base + R[op->Data]) & kSpaceMask];;
   1.209 +    default: return (Byte)op->Data;
   1.210 +  }
   1.211 +}
   1.212 +
   1.213 +void CVm::SetOperand8(const COperand *op, Byte val)
   1.214 +{
   1.215 +  switch(op->Type)
   1.216 +  {
   1.217 +    case OP_TYPE_REG: R[op->Data] = (R[op->Data] & 0xFFFFFF00) | val; return;
   1.218 +    case OP_TYPE_REGMEM: Mem[(op->Base + R[op->Data]) & kSpaceMask] = val; return;
   1.219 +  }
   1.220 +}
   1.221 +
   1.222 +UInt32 CVm::GetOperand(bool byteMode, const COperand *op) const
   1.223 +{
   1.224 +  if (byteMode)
   1.225 +    return GetOperand8(op);
   1.226 +  return GetOperand32(op);
   1.227 +}
   1.228 +
   1.229 +void CVm::SetOperand(bool byteMode, const COperand *op, UInt32 val)
   1.230 +{
   1.231 +  if (byteMode)
   1.232 +    SetOperand8(op, (Byte)(val & 0xFF));
   1.233 +  else
   1.234 +    SetOperand32(op, val);
   1.235 +}
   1.236 +
   1.237 +bool CVm::ExecuteCode(const CProgram *prg)
   1.238 +{
   1.239 +  Int32 maxOpCount = 25000000;
   1.240 +  const CCommand *commands = &prg->Commands[0];
   1.241 +  const CCommand *cmd = commands;
   1.242 +  UInt32 numCommands = prg->Commands.Size();
   1.243 +  for (;;)
   1.244 +  {
   1.245 +    switch(cmd->OpCode)
   1.246 +    {
   1.247 +      #ifndef RARVM_NO_VM
   1.248 +      
   1.249 +      case CMD_MOV:
   1.250 +        SetOperand32(&cmd->Op1, GetOperand32(&cmd->Op2));
   1.251 +        break;
   1.252 +      case CMD_MOVB:
   1.253 +        SetOperand8(&cmd->Op1, GetOperand8(&cmd->Op2));
   1.254 +        break;
   1.255 +      case CMD_CMP:
   1.256 +        {
   1.257 +          UInt32 v1 = GetOperand32(&cmd->Op1);
   1.258 +          UInt32 res = v1 - GetOperand32(&cmd->Op2);
   1.259 +          Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
   1.260 +        }
   1.261 +        break;
   1.262 +      case CMD_CMPB:
   1.263 +        {
   1.264 +          Byte v1 = GetOperand8(&cmd->Op1);
   1.265 +          Byte res = v1 - GetOperand8(&cmd->Op2);
   1.266 +          res &= 0xFF;
   1.267 +          Flags = res == 0 ? FLAG_Z : (res > v1) | GET_FLAG_S_B(res);
   1.268 +        }
   1.269 +        break;
   1.270 +      case CMD_ADD:
   1.271 +        {
   1.272 +          UInt32 v1 = GetOperand32(&cmd->Op1);
   1.273 +          UInt32 res = v1 + GetOperand32(&cmd->Op2);
   1.274 +          SetOperand32(&cmd->Op1, res);
   1.275 +          Flags = (res < v1) | (res == 0 ? FLAG_Z : (res & FLAG_S));
   1.276 +        }
   1.277 +        break;
   1.278 +      case CMD_ADDB:
   1.279 +        {
   1.280 +          Byte v1 = GetOperand8(&cmd->Op1);
   1.281 +          Byte res = v1 + GetOperand8(&cmd->Op2);
   1.282 +          res &= 0xFF;
   1.283 +          SetOperand8(&cmd->Op1, (Byte)res);
   1.284 +          Flags = (res < v1) | (res == 0 ? FLAG_Z : GET_FLAG_S_B(res));
   1.285 +        }
   1.286 +        break;
   1.287 +      case CMD_ADC:
   1.288 +        {
   1.289 +          UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
   1.290 +          UInt32 FC = (Flags & FLAG_C);
   1.291 +          UInt32 res = v1 + GetOperand(cmd->ByteMode, &cmd->Op2) + FC;
   1.292 +          if (cmd->ByteMode)
   1.293 +            res &= 0xFF;
   1.294 +          SetOperand(cmd->ByteMode, &cmd->Op1, res);
   1.295 +          Flags = (res < v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S));
   1.296 +        }
   1.297 +        break;
   1.298 +      case CMD_SUB:
   1.299 +        {
   1.300 +          UInt32 v1 = GetOperand32(&cmd->Op1);
   1.301 +          UInt32 res = v1 - GetOperand32(&cmd->Op2);
   1.302 +          SetOperand32(&cmd->Op1, res);
   1.303 +          Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
   1.304 +        }
   1.305 +        break;
   1.306 +      case CMD_SUBB:
   1.307 +        {
   1.308 +          UInt32 v1 = GetOperand8(&cmd->Op1);
   1.309 +          UInt32 res = v1 - GetOperand8(&cmd->Op2);
   1.310 +          SetOperand8(&cmd->Op1, (Byte)res);
   1.311 +          Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
   1.312 +        }
   1.313 +        break;
   1.314 +      case CMD_SBB:
   1.315 +        {
   1.316 +          UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
   1.317 +          UInt32 FC = (Flags & FLAG_C);
   1.318 +          UInt32 res = v1 - GetOperand(cmd->ByteMode, &cmd->Op2) - FC;
   1.319 +          // Flags = res == 0 ? FLAG_Z : (res > v1 || res == v1 && FC) | (res & FLAG_S);
   1.320 +          if (cmd->ByteMode)
   1.321 +            res &= 0xFF;
   1.322 +          SetOperand(cmd->ByteMode, &cmd->Op1, res);
   1.323 +          Flags = (res > v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S));
   1.324 +        }
   1.325 +        break;
   1.326 +      case CMD_INC:
   1.327 +        {
   1.328 +          UInt32 res = GetOperand32(&cmd->Op1) + 1;
   1.329 +          SetOperand32(&cmd->Op1, res);
   1.330 +          FLAGS_UPDATE_SZ;
   1.331 +        }
   1.332 +        break;
   1.333 +      case CMD_INCB:
   1.334 +        {
   1.335 +          Byte res = GetOperand8(&cmd->Op1) + 1;
   1.336 +          SetOperand8(&cmd->Op1, res);;
   1.337 +          FLAGS_UPDATE_SZ_B;
   1.338 +        }
   1.339 +        break;
   1.340 +      case CMD_DEC:
   1.341 +        {
   1.342 +          UInt32 res = GetOperand32(&cmd->Op1) - 1;
   1.343 +          SetOperand32(&cmd->Op1, res);
   1.344 +          FLAGS_UPDATE_SZ;
   1.345 +        }
   1.346 +        break;
   1.347 +      case CMD_DECB:
   1.348 +        {
   1.349 +          Byte res = GetOperand8(&cmd->Op1) - 1;
   1.350 +          SetOperand8(&cmd->Op1, res);;
   1.351 +          FLAGS_UPDATE_SZ_B;
   1.352 +        }
   1.353 +        break;
   1.354 +      case CMD_XOR:
   1.355 +        {
   1.356 +          UInt32 res = GetOperand32(&cmd->Op1) ^ GetOperand32(&cmd->Op2);
   1.357 +          SetOperand32(&cmd->Op1, res);
   1.358 +          FLAGS_UPDATE_SZ;
   1.359 +        }
   1.360 +        break;
   1.361 +      case CMD_XORB:
   1.362 +        {
   1.363 +          Byte res = GetOperand8(&cmd->Op1) ^ GetOperand8(&cmd->Op2);
   1.364 +          SetOperand8(&cmd->Op1, res);
   1.365 +          FLAGS_UPDATE_SZ_B;
   1.366 +        }
   1.367 +        break;
   1.368 +      case CMD_AND:
   1.369 +        {
   1.370 +          UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2);
   1.371 +          SetOperand32(&cmd->Op1, res);
   1.372 +          FLAGS_UPDATE_SZ;
   1.373 +        }
   1.374 +        break;
   1.375 +      case CMD_ANDB:
   1.376 +        {
   1.377 +          Byte res = GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2);
   1.378 +          SetOperand8(&cmd->Op1, res);
   1.379 +          FLAGS_UPDATE_SZ_B;
   1.380 +        }
   1.381 +        break;
   1.382 +      case CMD_OR:
   1.383 +        {
   1.384 +          UInt32 res = GetOperand32(&cmd->Op1) | GetOperand32(&cmd->Op2);
   1.385 +          SetOperand32(&cmd->Op1, res);
   1.386 +          FLAGS_UPDATE_SZ;
   1.387 +        }
   1.388 +        break;
   1.389 +      case CMD_ORB:
   1.390 +        {
   1.391 +          Byte res = GetOperand8(&cmd->Op1) | GetOperand8(&cmd->Op2);
   1.392 +          SetOperand8(&cmd->Op1, res);
   1.393 +          FLAGS_UPDATE_SZ_B;
   1.394 +        }
   1.395 +        break;
   1.396 +      case CMD_TEST:
   1.397 +        {
   1.398 +          UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2);
   1.399 +          FLAGS_UPDATE_SZ;
   1.400 +        }
   1.401 +        break;
   1.402 +      case CMD_TESTB:
   1.403 +        {
   1.404 +          Byte res = GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2);
   1.405 +          FLAGS_UPDATE_SZ_B;
   1.406 +        }
   1.407 +        break;
   1.408 +      case CMD_NOT:
   1.409 +        SetOperand(cmd->ByteMode, &cmd->Op1, ~GetOperand(cmd->ByteMode, &cmd->Op1));
   1.410 +        break;
   1.411 +      case CMD_NEG:
   1.412 +        {
   1.413 +          UInt32 res = 0 - GetOperand32(&cmd->Op1);
   1.414 +          SetOperand32(&cmd->Op1, res);
   1.415 +          Flags = res == 0 ? FLAG_Z : FLAG_C | (res & FLAG_S);
   1.416 +        }
   1.417 +        break;
   1.418 +      case CMD_NEGB:
   1.419 +        {
   1.420 +          Byte res = (Byte)(0 - GetOperand8(&cmd->Op1));
   1.421 +          SetOperand8(&cmd->Op1, res);
   1.422 +          Flags = res == 0 ? FLAG_Z : FLAG_C | GET_FLAG_S_B(res);
   1.423 +        }
   1.424 +        break;
   1.425 +
   1.426 +      case CMD_SHL:
   1.427 +        {
   1.428 +          UInt32 v1 = GetOperand32(&cmd->Op1);
   1.429 +          int v2 = (int)GetOperand32(&cmd->Op2);
   1.430 +          UInt32 res = v1 << v2;
   1.431 +          SetOperand32(&cmd->Op1, res);
   1.432 +          Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 << (v2 - 1)) & 0x80000000 ? FLAG_C : 0);
   1.433 +        }
   1.434 +        break;
   1.435 +      case CMD_SHLB:
   1.436 +        {
   1.437 +          Byte v1 = GetOperand8(&cmd->Op1);
   1.438 +          int v2 = (int)GetOperand8(&cmd->Op2);
   1.439 +          Byte res = (Byte)(v1 << v2);
   1.440 +          SetOperand8(&cmd->Op1, res);
   1.441 +          Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 << (v2 - 1)) & 0x80 ? FLAG_C : 0);
   1.442 +        }
   1.443 +        break;
   1.444 +      case CMD_SHR:
   1.445 +        {
   1.446 +          UInt32 v1 = GetOperand32(&cmd->Op1);
   1.447 +          int v2 = (int)GetOperand32(&cmd->Op2);
   1.448 +          UInt32 res = v1 >> v2;
   1.449 +          SetOperand32(&cmd->Op1, res);
   1.450 +          Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C);
   1.451 +        }
   1.452 +        break;
   1.453 +      case CMD_SHRB:
   1.454 +        {
   1.455 +          Byte v1 = GetOperand8(&cmd->Op1);
   1.456 +          int v2 = (int)GetOperand8(&cmd->Op2);
   1.457 +          Byte res = (Byte)(v1 >> v2);
   1.458 +          SetOperand8(&cmd->Op1, res);
   1.459 +          Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C);
   1.460 +        }
   1.461 +        break;
   1.462 +      case CMD_SAR:
   1.463 +        {
   1.464 +          UInt32 v1 = GetOperand32(&cmd->Op1);
   1.465 +          int v2 = (int)GetOperand32(&cmd->Op2);
   1.466 +          UInt32 res = UInt32(((Int32)v1) >> v2);
   1.467 +          SetOperand32(&cmd->Op1, res);
   1.468 +          Flags= (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C);
   1.469 +        }
   1.470 +        break;
   1.471 +      case CMD_SARB:
   1.472 +        {
   1.473 +          Byte v1 = GetOperand8(&cmd->Op1);
   1.474 +          int v2 = (int)GetOperand8(&cmd->Op2);
   1.475 +          Byte res = (Byte)(((signed char)v1) >> v2);
   1.476 +          SetOperand8(&cmd->Op1, res);
   1.477 +          Flags= (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C);
   1.478 +        }
   1.479 +        break;
   1.480 +
   1.481 +      case CMD_JMP:
   1.482 +        SET_IP_OP1;
   1.483 +        continue;
   1.484 +      case CMD_JZ:
   1.485 +        if ((Flags & FLAG_Z) != 0)
   1.486 +        {
   1.487 +          SET_IP_OP1;
   1.488 +          continue;
   1.489 +        }
   1.490 +        break;
   1.491 +      case CMD_JNZ:
   1.492 +        if ((Flags & FLAG_Z) == 0)
   1.493 +        {
   1.494 +          SET_IP_OP1;
   1.495 +          continue;
   1.496 +        }
   1.497 +        break;
   1.498 +      case CMD_JS:
   1.499 +        if ((Flags & FLAG_S) != 0)
   1.500 +        {
   1.501 +          SET_IP_OP1;
   1.502 +          continue;
   1.503 +        }
   1.504 +        break;
   1.505 +      case CMD_JNS:
   1.506 +        if ((Flags & FLAG_S) == 0)
   1.507 +        {
   1.508 +          SET_IP_OP1;
   1.509 +          continue;
   1.510 +        }
   1.511 +        break;
   1.512 +      case CMD_JB:
   1.513 +        if ((Flags & FLAG_C) != 0)
   1.514 +        {
   1.515 +          SET_IP_OP1;
   1.516 +          continue;
   1.517 +        }
   1.518 +        break;
   1.519 +      case CMD_JBE:
   1.520 +        if ((Flags & (FLAG_C | FLAG_Z)) != 0)
   1.521 +        {
   1.522 +          SET_IP_OP1;
   1.523 +          continue;
   1.524 +        }
   1.525 +        break;
   1.526 +      case CMD_JA:
   1.527 +        if ((Flags & (FLAG_C | FLAG_Z)) == 0)
   1.528 +        {
   1.529 +          SET_IP_OP1;
   1.530 +          continue;
   1.531 +        }
   1.532 +        break;
   1.533 +      case CMD_JAE:
   1.534 +        if ((Flags & FLAG_C) == 0)
   1.535 +        {
   1.536 +          SET_IP_OP1;
   1.537 +          continue;
   1.538 +        }
   1.539 +        break;
   1.540 +      
   1.541 +      case CMD_PUSH:
   1.542 +        R[kStackRegIndex] -= 4;
   1.543 +        SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], GetOperand32(&cmd->Op1));
   1.544 +        break;
   1.545 +      case CMD_POP:
   1.546 +        SetOperand32(&cmd->Op1, GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]));
   1.547 +        R[kStackRegIndex] += 4;
   1.548 +        break;
   1.549 +      case CMD_CALL:
   1.550 +        R[kStackRegIndex] -= 4;
   1.551 +        SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], (UInt32)(cmd - commands + 1));
   1.552 +        SET_IP_OP1;
   1.553 +        continue;
   1.554 +
   1.555 +      case CMD_PUSHA:
   1.556 +        {
   1.557 +          for (UInt32 i = 0, SP = R[kStackRegIndex] - 4; i < kNumRegs; i++, SP -= 4)
   1.558 +            SetValue32(&Mem[SP & kSpaceMask], R[i]);
   1.559 +          R[kStackRegIndex] -= kNumRegs * 4;
   1.560 +        }
   1.561 +        break;
   1.562 +      case CMD_POPA:
   1.563 +        {
   1.564 +          for (UInt32 i = 0, SP = R[kStackRegIndex]; i < kNumRegs; i++, SP += 4)
   1.565 +            R[kStackRegIndex - i] = GetValue32(&Mem[SP & kSpaceMask]);
   1.566 +        }
   1.567 +        break;
   1.568 +      case CMD_PUSHF:
   1.569 +        R[kStackRegIndex] -= 4;
   1.570 +        SetValue32(&Mem[R[kStackRegIndex]&kSpaceMask], Flags);
   1.571 +        break;
   1.572 +      case CMD_POPF:
   1.573 +        Flags = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]);
   1.574 +        R[kStackRegIndex] += 4;
   1.575 +        break;
   1.576 +      
   1.577 +      case CMD_MOVZX:
   1.578 +        SetOperand32(&cmd->Op1, GetOperand8(&cmd->Op2));
   1.579 +        break;
   1.580 +      case CMD_MOVSX:
   1.581 +        SetOperand32(&cmd->Op1, (UInt32)(Int32)(signed char)GetOperand8(&cmd->Op2));
   1.582 +        break;
   1.583 +      case CMD_XCHG:
   1.584 +        {
   1.585 +          UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
   1.586 +          SetOperand(cmd->ByteMode, &cmd->Op1, GetOperand(cmd->ByteMode, &cmd->Op2));
   1.587 +          SetOperand(cmd->ByteMode, &cmd->Op2, v1);
   1.588 +        }
   1.589 +        break;
   1.590 +      case CMD_MUL:
   1.591 +        {
   1.592 +          UInt32 res = GetOperand32(&cmd->Op1) * GetOperand32(&cmd->Op2);
   1.593 +          SetOperand32(&cmd->Op1, res);
   1.594 +        }
   1.595 +        break;
   1.596 +      case CMD_MULB:
   1.597 +        {
   1.598 +          Byte res = GetOperand8(&cmd->Op1) * GetOperand8(&cmd->Op2);
   1.599 +          SetOperand8(&cmd->Op1, res);
   1.600 +        }
   1.601 +        break;
   1.602 +      case CMD_DIV:
   1.603 +        {
   1.604 +          UInt32 divider = GetOperand(cmd->ByteMode, &cmd->Op2);
   1.605 +          if (divider != 0)
   1.606 +          {
   1.607 +            UInt32 res = GetOperand(cmd->ByteMode, &cmd->Op1) / divider;
   1.608 +            SetOperand(cmd->ByteMode, &cmd->Op1, res);
   1.609 +          }
   1.610 +        }
   1.611 +        break;
   1.612 +      
   1.613 +      #endif
   1.614 +      
   1.615 +      case CMD_RET:
   1.616 +        {
   1.617 +          if (R[kStackRegIndex] >= kSpaceSize)
   1.618 +            return true;
   1.619 +          UInt32 ip = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]);
   1.620 +          SET_IP(ip);
   1.621 +          R[kStackRegIndex] += 4;
   1.622 +          continue;
   1.623 +        }
   1.624 +      case CMD_PRINT:
   1.625 +        break;
   1.626 +    }
   1.627 +    cmd++;
   1.628 +    --maxOpCount;
   1.629 +  }
   1.630 +}
   1.631 +
   1.632 +
   1.633 +//////////////////////////////////////////////////////
   1.634 +// Read program
   1.635 +
   1.636 +UInt32 ReadEncodedUInt32(CMemBitDecoder &inp)
   1.637 +{
   1.638 +  switch(inp.ReadBits(2))
   1.639 +  {
   1.640 +    case 0:
   1.641 +      return inp.ReadBits(4);
   1.642 +    case 1:
   1.643 +    {
   1.644 +      UInt32 v = inp.ReadBits(4);
   1.645 +      if (v == 0)
   1.646 +        return 0xFFFFFF00 | inp.ReadBits(8);
   1.647 +      else
   1.648 +        return (v << 4) | inp.ReadBits(4);
   1.649 +    }
   1.650 +    case 2:
   1.651 +      return inp.ReadBits(16);
   1.652 +    default:
   1.653 +      return inp.ReadBits(32);
   1.654 +  }
   1.655 +}
   1.656 +
   1.657 +void CVm::DecodeArg(CMemBitDecoder &inp, COperand &op, bool byteMode)
   1.658 +{
   1.659 +  if (inp.ReadBit())
   1.660 +  {
   1.661 +    op.Type = OP_TYPE_REG;
   1.662 +    op.Data = inp.ReadBits(kNumRegBits);
   1.663 +  }
   1.664 +  else if (inp.ReadBit() == 0)
   1.665 +  {
   1.666 +    op.Type = OP_TYPE_INT;
   1.667 +    if (byteMode)
   1.668 +      op.Data = inp.ReadBits(8);
   1.669 +    else
   1.670 +      op.Data = ReadEncodedUInt32(inp);
   1.671 +  }
   1.672 +  else
   1.673 +  {
   1.674 +    op.Type = OP_TYPE_REGMEM;
   1.675 +    if (inp.ReadBit() == 0)
   1.676 +    {
   1.677 +      op.Data = inp.ReadBits(kNumRegBits);
   1.678 +      op.Base = 0;
   1.679 +    }
   1.680 +    else
   1.681 +    {
   1.682 +      if (inp.ReadBit() == 0)
   1.683 +        op.Data = inp.ReadBits(kNumRegBits);
   1.684 +      else
   1.685 +        op.Data = kNumRegs;
   1.686 +      op.Base = ReadEncodedUInt32(inp);
   1.687 +    }
   1.688 +  }
   1.689 +}
   1.690 +
   1.691 +void CVm::ReadVmProgram(const Byte *code, UInt32 codeSize, CProgram *prg)
   1.692 +{
   1.693 +  CMemBitDecoder inp;
   1.694 +  inp.Init(code, codeSize);
   1.695 +
   1.696 +  prg->StaticData.Clear();
   1.697 +  if (inp.ReadBit())
   1.698 +  {
   1.699 +    UInt32 dataSize = ReadEncodedUInt32(inp) + 1;
   1.700 +    for (UInt32 i = 0; inp.Avail() && i < dataSize; i++)
   1.701 +      prg->StaticData.Add((Byte)inp.ReadBits(8));
   1.702 +  }
   1.703 +  while (inp.Avail())
   1.704 +  {
   1.705 +    prg->Commands.Add(CCommand());
   1.706 +    CCommand *cmd = &prg->Commands.Back();
   1.707 +    if (inp.ReadBit() == 0)
   1.708 +      cmd->OpCode = (ECommand)inp.ReadBits(3);
   1.709 +    else
   1.710 +      cmd->OpCode = (ECommand)(8 + inp.ReadBits(5));
   1.711 +    if (kCmdFlags[cmd->OpCode] & CF_BYTEMODE)
   1.712 +      cmd->ByteMode = (inp.ReadBit()) ? true : false;
   1.713 +    else
   1.714 +      cmd->ByteMode = 0;
   1.715 +    int opNum = (kCmdFlags[cmd->OpCode] & CF_OPMASK);
   1.716 +    if (opNum > 0)
   1.717 +    {
   1.718 +      DecodeArg(inp, cmd->Op1, cmd->ByteMode);
   1.719 +      if (opNum == 2)
   1.720 +        DecodeArg(inp, cmd->Op2, cmd->ByteMode);
   1.721 +      else
   1.722 +      {
   1.723 +        if (cmd->Op1.Type == OP_TYPE_INT && (kCmdFlags[cmd->OpCode] & (CF_JUMP | CF_PROC)))
   1.724 +        {
   1.725 +          int Distance = cmd->Op1.Data;
   1.726 +          if (Distance >= 256)
   1.727 +            Distance -= 256;
   1.728 +          else
   1.729 +          {
   1.730 +            if (Distance >= 136)
   1.731 +              Distance -= 264;
   1.732 +            else if (Distance >= 16)
   1.733 +              Distance -= 8;
   1.734 +            else if (Distance >= 8)
   1.735 +              Distance -= 16;
   1.736 +            Distance += prg->Commands.Size() - 1;
   1.737 +          }
   1.738 +          cmd->Op1.Data = Distance;
   1.739 +        }
   1.740 +      }
   1.741 +    }
   1.742 +    if (cmd->ByteMode)
   1.743 +    {
   1.744 +      switch (cmd->OpCode)
   1.745 +      {
   1.746 +        case CMD_MOV: cmd->OpCode = CMD_MOVB; break;
   1.747 +        case CMD_CMP: cmd->OpCode = CMD_CMPB; break;
   1.748 +        case CMD_ADD: cmd->OpCode = CMD_ADDB; break;
   1.749 +        case CMD_SUB: cmd->OpCode = CMD_SUBB; break;
   1.750 +        case CMD_INC: cmd->OpCode = CMD_INCB; break;
   1.751 +        case CMD_DEC: cmd->OpCode = CMD_DECB; break;
   1.752 +        case CMD_XOR: cmd->OpCode = CMD_XORB; break;
   1.753 +        case CMD_AND: cmd->OpCode = CMD_ANDB; break;
   1.754 +        case CMD_OR: cmd->OpCode = CMD_ORB; break;
   1.755 +        case CMD_TEST: cmd->OpCode = CMD_TESTB; break;
   1.756 +        case CMD_NEG: cmd->OpCode = CMD_NEGB; break;
   1.757 +        case CMD_SHL: cmd->OpCode = CMD_SHLB; break;
   1.758 +        case CMD_SHR: cmd->OpCode = CMD_SHRB; break;
   1.759 +        case CMD_SAR: cmd->OpCode = CMD_SARB; break;
   1.760 +        case CMD_MUL: cmd->OpCode = CMD_MULB; break;
   1.761 +      }
   1.762 +    }
   1.763 +  }
   1.764 +}
   1.765 +
   1.766 +#ifdef RARVM_STANDARD_FILTERS
   1.767 +
   1.768 +enum EStandardFilter
   1.769 +{
   1.770 +  SF_E8,
   1.771 +  SF_E8E9,
   1.772 +  SF_ITANIUM,
   1.773 +  SF_RGB,
   1.774 +  SF_AUDIO,
   1.775 +  SF_DELTA,
   1.776 +  SF_UPCASE
   1.777 +};
   1.778 +
   1.779 +struct StandardFilterSignature
   1.780 +{
   1.781 +  UInt32 Length;
   1.782 +  UInt32 CRC;
   1.783 +  EStandardFilter Type;
   1.784 +}
   1.785 +kStdFilters[]=
   1.786 +{
   1.787 +   53, 0xad576887, SF_E8,
   1.788 +   57, 0x3cd7e57e, SF_E8E9,
   1.789 +  120, 0x3769893f, SF_ITANIUM,
   1.790 +   29, 0x0e06077d, SF_DELTA,
   1.791 +  149, 0x1c2c5dc8, SF_RGB,
   1.792 +  216, 0xbc85e701, SF_AUDIO,
   1.793 +   40, 0x46b9c560, SF_UPCASE
   1.794 +};
   1.795 +
   1.796 +static int FindStandardFilter(const Byte *code, UInt32 codeSize)
   1.797 +{
   1.798 +  UInt32 crc = CrcCalc(code, codeSize);
   1.799 +  for (int i = 0; i < sizeof(kStdFilters) / sizeof(kStdFilters[0]); i++)
   1.800 +  {
   1.801 +    StandardFilterSignature &sfs = kStdFilters[i];
   1.802 +    if (sfs.CRC == crc && sfs.Length == codeSize)
   1.803 +      return i;
   1.804 +  }
   1.805 +  return -1;
   1.806 +}
   1.807 +
   1.808 +#endif
   1.809 +
   1.810 +void CVm::PrepareProgram(const Byte *code, UInt32 codeSize, CProgram *prg)
   1.811 +{
   1.812 +  Byte xorSum = 0;
   1.813 +  for (UInt32 i = 1; i < codeSize; i++)
   1.814 +    xorSum ^= code[i];
   1.815 +
   1.816 +  prg->Commands.Clear();
   1.817 +  #ifdef RARVM_STANDARD_FILTERS
   1.818 +  prg->StandardFilterIndex = -1;
   1.819 +  #endif
   1.820 +
   1.821 +  if (xorSum == code[0] && codeSize > 0)
   1.822 +  {
   1.823 +    #ifdef RARVM_STANDARD_FILTERS
   1.824 +    prg->StandardFilterIndex = FindStandardFilter(code, codeSize);
   1.825 +    if (prg->StandardFilterIndex >= 0)
   1.826 +      return;
   1.827 +    #endif
   1.828 +    // 1 byte for checksum
   1.829 +    ReadVmProgram(code + 1, codeSize - 1, prg);
   1.830 +  }
   1.831 +  prg->Commands.Add(CCommand());
   1.832 +  CCommand *cmd = &prg->Commands.Back();
   1.833 +  cmd->OpCode = CMD_RET;
   1.834 +}
   1.835 +
   1.836 +void CVm::SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize)
   1.837 +{
   1.838 +  if (pos < kSpaceSize && data != Mem + pos)
   1.839 +    memmove(Mem + pos, data, MyMin(dataSize, kSpaceSize - pos));
   1.840 +}
   1.841 +
   1.842 +#ifdef RARVM_STANDARD_FILTERS
   1.843 +
   1.844 +static void E8E9Decode(Byte *data, UInt32 dataSize, UInt32 fileOffset, bool e9)
   1.845 +{
   1.846 +  if (dataSize <= 4)
   1.847 +    return;
   1.848 +  dataSize -= 4;
   1.849 +  const UInt32 kFileSize = 0x1000000;
   1.850 +  Byte cmpByte2 = (e9 ? 0xE9 : 0xE8);
   1.851 +  for (UInt32 curPos = 0; curPos < dataSize;)
   1.852 +  {
   1.853 +    Byte curByte = *(data++);
   1.854 +    curPos++;
   1.855 +    if (curByte == 0xE8 || curByte == cmpByte2)
   1.856 +    {
   1.857 +      UInt32 offset = curPos + fileOffset;
   1.858 +      UInt32 addr = (Int32)GetValue32(data);
   1.859 +      if (addr < kFileSize)
   1.860 +        SetValue32(data, addr - offset);
   1.861 +      else if ((Int32)addr < 0 && (Int32)(addr + offset) >= 0)
   1.862 +        SetValue32(data, addr + kFileSize);
   1.863 +      data += 4;
   1.864 +      curPos += 4;
   1.865 +    }
   1.866 +  }
   1.867 +}
   1.868 +
   1.869 +static inline UInt32 ItaniumGetOpType(const Byte *data, int bitPos)
   1.870 +{
   1.871 +  return (data[(unsigned int)bitPos >> 3] >> (bitPos & 7)) & 0xF;
   1.872 +}
   1.873 +
   1.874 +
   1.875 +static void ItaniumDecode(Byte *data, UInt32 dataSize, UInt32 fileOffset)
   1.876 +{
   1.877 +  UInt32 curPos = 0;
   1.878 +  fileOffset >>= 4;
   1.879 +  while (curPos < dataSize - 21)
   1.880 +  {
   1.881 +    int b = (data[0] & 0x1F) - 0x10;
   1.882 +    if (b >= 0)
   1.883 +    {
   1.884 +      static Byte kCmdMasks[16] = {4,4,6,6,0,0,7,7,4,4,0,0,4,4,0,0};
   1.885 +      Byte cmdMask = kCmdMasks[b];
   1.886 +      if (cmdMask != 0)
   1.887 +        for (int i = 0; i < 3; i++)
   1.888 +          if (cmdMask & (1 << i))
   1.889 +          {
   1.890 +            int startPos = i * 41 + 18;
   1.891 +            if (ItaniumGetOpType(data, startPos + 24) == 5)
   1.892 +            {
   1.893 +              const UInt32 kMask = 0xFFFFF;
   1.894 +              Byte *p = data + ((unsigned int)startPos >> 3);
   1.895 +              UInt32 bitField =  ((UInt32)p[0]) | ((UInt32)p[1] <<  8) | ((UInt32)p[2] << 16);
   1.896 +              int inBit = (startPos & 7);
   1.897 +              UInt32 offset = (bitField >> inBit) & kMask;
   1.898 +              UInt32 andMask = ~(kMask << inBit);
   1.899 +              bitField = ((offset - fileOffset) & kMask) << inBit;
   1.900 +              for (int j = 0; j < 3; j++)
   1.901 +              {
   1.902 +                p[j] &= andMask;
   1.903 +                p[j] |= bitField;
   1.904 +                andMask >>= 8;
   1.905 +                bitField >>= 8;
   1.906 +              }
   1.907 +            }
   1.908 +          }
   1.909 +    }
   1.910 +    data += 16;
   1.911 +    curPos += 16;
   1.912 +    fileOffset++;
   1.913 +  }
   1.914 +}
   1.915 +
   1.916 +static void DeltaDecode(Byte *data, UInt32 dataSize, UInt32 numChannels)
   1.917 +{
   1.918 +  UInt32 srcPos = 0;
   1.919 +  UInt32 border = dataSize * 2;
   1.920 +  for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
   1.921 +  {
   1.922 +    Byte prevByte = 0;
   1.923 +    for (UInt32 destPos = dataSize + curChannel; destPos < border; destPos += numChannels)
   1.924 +      data[destPos] = (prevByte = prevByte - data[srcPos++]);
   1.925 +  }
   1.926 +}
   1.927 +
   1.928 +static void RgbDecode(Byte *srcData, UInt32 dataSize, UInt32 width, UInt32 posR)
   1.929 +{
   1.930 +  Byte *destData = srcData + dataSize;
   1.931 +  const UInt32 numChannels = 3;
   1.932 +  for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
   1.933 +  {
   1.934 +    Byte prevByte = 0;
   1.935 +    
   1.936 +    for (UInt32 i = curChannel; i < dataSize; i+= numChannels)
   1.937 +    {
   1.938 +      unsigned int predicted;
   1.939 +      if (i < width)
   1.940 +        predicted = prevByte;
   1.941 +      else
   1.942 +      {
   1.943 +        unsigned int upperLeftByte = destData[i - width];
   1.944 +        unsigned int upperByte = destData[i - width + 3];
   1.945 +        predicted = prevByte + upperByte - upperLeftByte;
   1.946 +        int pa = abs((int)(predicted - prevByte));
   1.947 +        int pb = abs((int)(predicted - upperByte));
   1.948 +        int pc = abs((int)(predicted - upperLeftByte));
   1.949 +        if (pa <= pb && pa <= pc)
   1.950 +          predicted = prevByte;
   1.951 +        else
   1.952 +          if (pb <= pc)
   1.953 +            predicted = upperByte;
   1.954 +          else
   1.955 +            predicted = upperLeftByte;
   1.956 +      }
   1.957 +      destData[i] = prevByte = (Byte)(predicted - *(srcData++));
   1.958 +    }
   1.959 +  }
   1.960 +  if (dataSize < 3)
   1.961 +    return;
   1.962 +  for (UInt32 i = posR, border = dataSize - 2; i < border; i += 3)
   1.963 +  {
   1.964 +    Byte g = destData[i + 1];
   1.965 +    destData[i] = destData[i] + g;
   1.966 +    destData[i + 2] = destData[i + 2] + g;
   1.967 +  }
   1.968 +}
   1.969 +
   1.970 +static void AudioDecode(Byte *srcData, UInt32 dataSize, UInt32 numChannels)
   1.971 +{
   1.972 +  Byte *destData = srcData + dataSize;
   1.973 +  for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
   1.974 +  {
   1.975 +    UInt32 prevByte = 0, prevDelta = 0, dif[7];
   1.976 +    Int32 D1 = 0, D2 = 0, D3;
   1.977 +    Int32 K1 = 0, K2 = 0, K3 = 0;
   1.978 +    memset(dif, 0, sizeof(dif));
   1.979 +    
   1.980 +    for (UInt32 i = curChannel, byteCount = 0; i < dataSize; i += numChannels, byteCount++)
   1.981 +    {
   1.982 +      D3 = D2;
   1.983 +      D2 = prevDelta - D1;
   1.984 +      D1 = prevDelta;
   1.985 +      
   1.986 +      UInt32 predicted = 8 * prevByte + K1 * D1 + K2 * D2 + K3 * D3;
   1.987 +      predicted = (predicted >> 3) & 0xFF;
   1.988 +      
   1.989 +      UInt32 curByte = *(srcData++);
   1.990 +      
   1.991 +      predicted -= curByte;
   1.992 +      destData[i] = (Byte)predicted;
   1.993 +      prevDelta = (UInt32)(Int32)(signed char)(predicted - prevByte);
   1.994 +      prevByte = predicted;
   1.995 +      
   1.996 +      Int32 D = ((Int32)(signed char)curByte) << 3;
   1.997 +      
   1.998 +      dif[0] += abs(D);
   1.999 +      dif[1] += abs(D - D1);
  1.1000 +      dif[2] += abs(D + D1);
  1.1001 +      dif[3] += abs(D - D2);
  1.1002 +      dif[4] += abs(D + D2);
  1.1003 +      dif[5] += abs(D - D3);
  1.1004 +      dif[6] += abs(D + D3);
  1.1005 +      
  1.1006 +      if ((byteCount & 0x1F) == 0)
  1.1007 +      {
  1.1008 +        UInt32 minDif = dif[0], numMinDif = 0;
  1.1009 +        dif[0] = 0;
  1.1010 +        for (int j = 1; j < sizeof(dif) / sizeof(dif[0]); j++)
  1.1011 +        {
  1.1012 +          if (dif[j] < minDif)
  1.1013 +          {
  1.1014 +            minDif = dif[j];
  1.1015 +            numMinDif = j;
  1.1016 +          }
  1.1017 +          dif[j] = 0;
  1.1018 +        }
  1.1019 +        switch (numMinDif)
  1.1020 +        {
  1.1021 +          case 1: if (K1 >= -16) K1--; break;
  1.1022 +          case 2: if (K1 <   16) K1++; break;
  1.1023 +          case 3: if (K2 >= -16) K2--; break;
  1.1024 +          case 4: if (K2 <   16) K2++; break;
  1.1025 +          case 5: if (K3 >= -16) K3--; break;
  1.1026 +          case 6: if (K3 <   16) K3++; break;
  1.1027 +        }
  1.1028 +      }
  1.1029 +    }
  1.1030 +  }
  1.1031 +}
  1.1032 +
  1.1033 +static UInt32 UpCaseDecode(Byte *data, UInt32 dataSize)
  1.1034 +{
  1.1035 +  UInt32 srcPos = 0, destPos = dataSize;
  1.1036 +  while (srcPos < dataSize)
  1.1037 +  {
  1.1038 +    Byte curByte = data[srcPos++];
  1.1039 +    if (curByte == 2 && (curByte = data[srcPos++]) != 2)
  1.1040 +      curByte -= 32;
  1.1041 +    data[destPos++] = curByte;
  1.1042 +  }
  1.1043 +  return destPos - dataSize;
  1.1044 +}
  1.1045 +
  1.1046 +void CVm::ExecuteStandardFilter(int filterIndex)
  1.1047 +{
  1.1048 +  UInt32 dataSize = R[4];
  1.1049 +  if (dataSize >= kGlobalOffset)
  1.1050 +    return;
  1.1051 +  EStandardFilter filterType = kStdFilters[filterIndex].Type;
  1.1052 +
  1.1053 +  switch (filterType)
  1.1054 +  {
  1.1055 +    case SF_E8:
  1.1056 +    case SF_E8E9:
  1.1057 +      E8E9Decode(Mem, dataSize, R[6], (filterType == SF_E8E9));
  1.1058 +      break;
  1.1059 +    case SF_ITANIUM:
  1.1060 +      ItaniumDecode(Mem, dataSize, R[6]);
  1.1061 +      break;
  1.1062 +    case SF_DELTA:
  1.1063 +      if (dataSize >= kGlobalOffset / 2)
  1.1064 +        break;
  1.1065 +      SetBlockPos(dataSize);
  1.1066 +      DeltaDecode(Mem, dataSize, R[0]);
  1.1067 +      break;
  1.1068 +    case SF_RGB:
  1.1069 +      if (dataSize >= kGlobalOffset / 2)
  1.1070 +        break;
  1.1071 +      {
  1.1072 +        UInt32 width = R[0];
  1.1073 +        if (width <= 3)
  1.1074 +          break;
  1.1075 +        SetBlockPos(dataSize);
  1.1076 +        RgbDecode(Mem, dataSize, width, R[1]);
  1.1077 +      }
  1.1078 +      break;
  1.1079 +    case SF_AUDIO:
  1.1080 +      if (dataSize >= kGlobalOffset / 2)
  1.1081 +        break;
  1.1082 +      SetBlockPos(dataSize);
  1.1083 +      AudioDecode(Mem, dataSize, R[0]);
  1.1084 +      break;
  1.1085 +    case SF_UPCASE:
  1.1086 +      if (dataSize >= kGlobalOffset / 2)
  1.1087 +        break;
  1.1088 +      UInt32 destSize = UpCaseDecode(Mem, dataSize);
  1.1089 +      SetBlockSize(destSize);
  1.1090 +      SetBlockPos(dataSize);
  1.1091 +      break;
  1.1092 +  }
  1.1093 +}
  1.1094 +
  1.1095 +#endif
  1.1096 +
  1.1097 +}}}