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