"Fossies" - the Fresh Open Source Software Archive 
Member "unrar/rarvm.cpp" (4 May 2022, 9735 Bytes) of package /linux/misc/unrarsrc-6.1.7.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "rarvm.cpp" see the
Fossies "Dox" file reference documentation.
1 #include "rar.hpp"
2
3 RarVM::RarVM()
4 {
5 Mem=NULL;
6 }
7
8
9 RarVM::~RarVM()
10 {
11 delete[] Mem;
12 }
13
14
15 void RarVM::Init()
16 {
17 if (Mem==NULL)
18 Mem=new byte[VM_MEMSIZE+4];
19 }
20
21
22 void RarVM::Execute(VM_PreparedProgram *Prg)
23 {
24 memcpy(R,Prg->InitR,sizeof(Prg->InitR));
25 Prg->FilteredData=NULL;
26 if (Prg->Type!=VMSF_NONE)
27 {
28 bool Success=ExecuteStandardFilter(Prg->Type);
29 uint BlockSize=Prg->InitR[4] & VM_MEMMASK;
30 Prg->FilteredDataSize=BlockSize;
31 if (Prg->Type==VMSF_DELTA || Prg->Type==VMSF_RGB || Prg->Type==VMSF_AUDIO)
32 Prg->FilteredData=2*BlockSize>VM_MEMSIZE || !Success ? Mem:Mem+BlockSize;
33 else
34 Prg->FilteredData=Mem;
35 }
36 }
37
38
39 void RarVM::Prepare(byte *Code,uint CodeSize,VM_PreparedProgram *Prg)
40 {
41 // Calculate the single byte XOR checksum to check validity of VM code.
42 byte XorSum=0;
43 for (uint I=1;I<CodeSize;I++)
44 XorSum^=Code[I];
45
46 if (XorSum!=Code[0])
47 return;
48
49 struct StandardFilters
50 {
51 uint Length;
52 uint CRC;
53 VM_StandardFilters Type;
54 } static StdList[]={
55 53, 0xad576887, VMSF_E8,
56 57, 0x3cd7e57e, VMSF_E8E9,
57 120, 0x3769893f, VMSF_ITANIUM,
58 29, 0x0e06077d, VMSF_DELTA,
59 149, 0x1c2c5dc8, VMSF_RGB,
60 216, 0xbc85e701, VMSF_AUDIO
61 };
62 uint CodeCRC=CRC32(0xffffffff,Code,CodeSize)^0xffffffff;
63 for (uint I=0;I<ASIZE(StdList);I++)
64 if (StdList[I].CRC==CodeCRC && StdList[I].Length==CodeSize)
65 {
66 Prg->Type=StdList[I].Type;
67 break;
68 }
69 }
70
71
72 uint RarVM::ReadData(BitInput &Inp)
73 {
74 uint Data=Inp.fgetbits();
75 switch(Data&0xc000)
76 {
77 case 0:
78 Inp.faddbits(6);
79 return (Data>>10)&0xf;
80 case 0x4000:
81 if ((Data&0x3c00)==0)
82 {
83 Data=0xffffff00|((Data>>2)&0xff);
84 Inp.faddbits(14);
85 }
86 else
87 {
88 Data=(Data>>6)&0xff;
89 Inp.faddbits(10);
90 }
91 return Data;
92 case 0x8000:
93 Inp.faddbits(2);
94 Data=Inp.fgetbits();
95 Inp.faddbits(16);
96 return Data;
97 default:
98 Inp.faddbits(2);
99 Data=(Inp.fgetbits()<<16);
100 Inp.faddbits(16);
101 Data|=Inp.fgetbits();
102 Inp.faddbits(16);
103 return Data;
104 }
105 }
106
107
108 void RarVM::SetMemory(size_t Pos,byte *Data,size_t DataSize)
109 {
110 if (Pos<VM_MEMSIZE && Data!=Mem+Pos)
111 {
112 // We can have NULL Data for invalid filters with DataSize==0. While most
113 // sensible memmove implementations do not care about data if size is 0,
114 // let's follow the standard and check the size first.
115 size_t CopySize=Min(DataSize,VM_MEMSIZE-Pos);
116 if (CopySize!=0)
117 memmove(Mem+Pos,Data,CopySize);
118 }
119 }
120
121
122 bool RarVM::ExecuteStandardFilter(VM_StandardFilters FilterType)
123 {
124 switch(FilterType)
125 {
126 case VMSF_E8:
127 case VMSF_E8E9:
128 {
129 byte *Data=Mem;
130 uint DataSize=R[4],FileOffset=R[6];
131
132 if (DataSize>VM_MEMSIZE || DataSize<4)
133 return false;
134
135 const uint FileSize=0x1000000;
136 byte CmpByte2=FilterType==VMSF_E8E9 ? 0xe9:0xe8;
137 for (uint CurPos=0;CurPos<DataSize-4;)
138 {
139 byte CurByte=*(Data++);
140 CurPos++;
141 if (CurByte==0xe8 || CurByte==CmpByte2)
142 {
143 uint Offset=CurPos+FileOffset;
144 uint Addr=RawGet4(Data);
145
146 // We check 0x80000000 bit instead of '< 0' comparison
147 // not assuming int32 presence or uint size and endianness.
148 if ((Addr & 0x80000000)!=0) // Addr<0
149 {
150 if (((Addr+Offset) & 0x80000000)==0) // Addr+Offset>=0
151 RawPut4(Addr+FileSize,Data);
152 }
153 else
154 if (((Addr-FileSize) & 0x80000000)!=0) // Addr<FileSize
155 RawPut4(Addr-Offset,Data);
156 Data+=4;
157 CurPos+=4;
158 }
159 }
160 }
161 break;
162 case VMSF_ITANIUM:
163 {
164 byte *Data=Mem;
165 uint DataSize=R[4],FileOffset=R[6];
166
167 if (DataSize>VM_MEMSIZE || DataSize<21)
168 return false;
169
170 uint CurPos=0;
171
172 FileOffset>>=4;
173
174 while (CurPos<DataSize-21)
175 {
176 int Byte=(Data[0]&0x1f)-0x10;
177 if (Byte>=0)
178 {
179 static byte Masks[16]={4,4,6,6,0,0,7,7,4,4,0,0,4,4,0,0};
180 byte CmdMask=Masks[Byte];
181 if (CmdMask!=0)
182 for (uint I=0;I<=2;I++)
183 if (CmdMask & (1<<I))
184 {
185 uint StartPos=I*41+5;
186 uint OpType=FilterItanium_GetBits(Data,StartPos+37,4);
187 if (OpType==5)
188 {
189 uint Offset=FilterItanium_GetBits(Data,StartPos+13,20);
190 FilterItanium_SetBits(Data,(Offset-FileOffset)&0xfffff,StartPos+13,20);
191 }
192 }
193 }
194 Data+=16;
195 CurPos+=16;
196 FileOffset++;
197 }
198 }
199 break;
200 case VMSF_DELTA:
201 {
202 uint DataSize=R[4],Channels=R[0],SrcPos=0,Border=DataSize*2;
203 if (DataSize>VM_MEMSIZE/2 || Channels>MAX3_UNPACK_CHANNELS || Channels==0)
204 return false;
205
206 // Bytes from same channels are grouped to continual data blocks,
207 // so we need to place them back to their interleaving positions.
208 for (uint CurChannel=0;CurChannel<Channels;CurChannel++)
209 {
210 byte PrevByte=0;
211 for (uint DestPos=DataSize+CurChannel;DestPos<Border;DestPos+=Channels)
212 Mem[DestPos]=(PrevByte-=Mem[SrcPos++]);
213 }
214 }
215 break;
216 case VMSF_RGB:
217 {
218 uint DataSize=R[4],Width=R[0]-3,PosR=R[1];
219 if (DataSize>VM_MEMSIZE/2 || DataSize<3 || Width>DataSize || PosR>2)
220 return false;
221 byte *SrcData=Mem,*DestData=SrcData+DataSize;
222 const uint Channels=3;
223 for (uint CurChannel=0;CurChannel<Channels;CurChannel++)
224 {
225 uint PrevByte=0;
226
227 for (uint I=CurChannel;I<DataSize;I+=Channels)
228 {
229 uint Predicted;
230 if (I>=Width+3)
231 {
232 byte *UpperData=DestData+I-Width;
233 uint UpperByte=*UpperData;
234 uint UpperLeftByte=*(UpperData-3);
235 Predicted=PrevByte+UpperByte-UpperLeftByte;
236 int pa=abs((int)(Predicted-PrevByte));
237 int pb=abs((int)(Predicted-UpperByte));
238 int pc=abs((int)(Predicted-UpperLeftByte));
239 if (pa<=pb && pa<=pc)
240 Predicted=PrevByte;
241 else
242 if (pb<=pc)
243 Predicted=UpperByte;
244 else
245 Predicted=UpperLeftByte;
246 }
247 else
248 Predicted=PrevByte;
249 DestData[I]=PrevByte=(byte)(Predicted-*(SrcData++));
250 }
251 }
252 for (uint I=PosR,Border=DataSize-2;I<Border;I+=3)
253 {
254 byte G=DestData[I+1];
255 DestData[I]+=G;
256 DestData[I+2]+=G;
257 }
258 }
259 break;
260 case VMSF_AUDIO:
261 {
262 uint DataSize=R[4],Channels=R[0];
263 byte *SrcData=Mem,*DestData=SrcData+DataSize;
264 // In fact, audio channels never exceed 4.
265 if (DataSize>VM_MEMSIZE/2 || Channels>128 || Channels==0)
266 return false;
267 for (uint CurChannel=0;CurChannel<Channels;CurChannel++)
268 {
269 uint PrevByte=0,PrevDelta=0,Dif[7];
270 int D1=0,D2=0,D3;
271 int K1=0,K2=0,K3=0;
272 memset(Dif,0,sizeof(Dif));
273
274 for (uint I=CurChannel,ByteCount=0;I<DataSize;I+=Channels,ByteCount++)
275 {
276 D3=D2;
277 D2=PrevDelta-D1;
278 D1=PrevDelta;
279
280 uint Predicted=8*PrevByte+K1*D1+K2*D2+K3*D3;
281 Predicted=(Predicted>>3) & 0xff;
282
283 uint CurByte=*(SrcData++);
284
285 Predicted-=CurByte;
286 DestData[I]=Predicted;
287 PrevDelta=(signed char)(Predicted-PrevByte);
288 PrevByte=Predicted;
289
290 int D=(signed char)CurByte;
291 // Left shift of negative value is undefined behavior in C++,
292 // so we cast it to unsigned to follow the standard.
293 D=(uint)D<<3;
294
295 Dif[0]+=abs(D);
296 Dif[1]+=abs(D-D1);
297 Dif[2]+=abs(D+D1);
298 Dif[3]+=abs(D-D2);
299 Dif[4]+=abs(D+D2);
300 Dif[5]+=abs(D-D3);
301 Dif[6]+=abs(D+D3);
302
303 if ((ByteCount & 0x1f)==0)
304 {
305 uint MinDif=Dif[0],NumMinDif=0;
306 Dif[0]=0;
307 for (uint J=1;J<ASIZE(Dif);J++)
308 {
309 if (Dif[J]<MinDif)
310 {
311 MinDif=Dif[J];
312 NumMinDif=J;
313 }
314 Dif[J]=0;
315 }
316 switch(NumMinDif)
317 {
318 case 1: if (K1>=-16) K1--; break;
319 case 2: if (K1 < 16) K1++; break;
320 case 3: if (K2>=-16) K2--; break;
321 case 4: if (K2 < 16) K2++; break;
322 case 5: if (K3>=-16) K3--; break;
323 case 6: if (K3 < 16) K3++; break;
324 }
325 }
326 }
327 }
328 }
329 break;
330 }
331 return true;
332 }
333
334
335 uint RarVM::FilterItanium_GetBits(byte *Data,uint BitPos,uint BitCount)
336 {
337 uint InAddr=BitPos/8;
338 uint InBit=BitPos&7;
339 uint BitField=(uint)Data[InAddr++];
340 BitField|=(uint)Data[InAddr++] << 8;
341 BitField|=(uint)Data[InAddr++] << 16;
342 BitField|=(uint)Data[InAddr] << 24;
343 BitField >>= InBit;
344 return BitField & (0xffffffff>>(32-BitCount));
345 }
346
347
348 void RarVM::FilterItanium_SetBits(byte *Data,uint BitField,uint BitPos,uint BitCount)
349 {
350 uint InAddr=BitPos/8;
351 uint InBit=BitPos&7;
352 uint AndMask=0xffffffff>>(32-BitCount);
353 AndMask=~(AndMask<<InBit);
354
355 BitField<<=InBit;
356
357 for (uint I=0;I<4;I++)
358 {
359 Data[InAddr+I]&=AndMask;
360 Data[InAddr+I]|=BitField;
361 AndMask=(AndMask>>8)|0xff000000;
362 BitField>>=8;
363 }
364 }