"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 }