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