"Fossies" - the Fresh Open Source Software Archive

Member "unrar/qopen.cpp" (4 May 2022, 6905 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 "qopen.cpp" see the Fossies "Dox" file reference documentation.

    1 #include "rar.hpp"
    2 
    3 QuickOpen::QuickOpen()
    4 {
    5   Buf=NULL;
    6   Init(NULL,false);
    7 }
    8 
    9 
   10 QuickOpen::~QuickOpen()
   11 {
   12   Close();
   13   delete[] Buf;
   14 }
   15 
   16 
   17 void QuickOpen::Init(Archive *Arc,bool WriteMode)
   18 {
   19   if (Arc!=NULL) // Unless called from constructor.
   20     Close();
   21 
   22   QuickOpen::Arc=Arc;
   23   QuickOpen::WriteMode=WriteMode;
   24 
   25   ListStart=NULL;
   26   ListEnd=NULL;
   27 
   28   if (Buf==NULL)
   29     Buf=new byte[MaxBufSize];
   30 
   31   CurBufSize=0; // Current size of buffered data in write mode.
   32 
   33   Loaded=false;
   34 }
   35 
   36 
   37 void QuickOpen::Close()
   38 {
   39   QuickOpenItem *Item=ListStart;
   40   while (Item!=NULL)
   41   {
   42     QuickOpenItem *Next=Item->Next;
   43     delete[] Item->Header;
   44     delete Item;
   45     Item=Next;
   46   }
   47 }
   48 
   49 
   50 
   51 
   52 
   53 
   54 
   55 
   56 
   57 
   58 
   59 
   60 
   61 
   62 void QuickOpen::Load(uint64 BlockPos)
   63 {
   64   if (!Loaded)
   65   {
   66     // If loading for the first time, perform additional intialization.
   67     SeekPos=Arc->Tell();
   68     UnsyncSeekPos=false;
   69 
   70     int64 SavePos=SeekPos;
   71     Arc->Seek(BlockPos,SEEK_SET);
   72 
   73     // If BlockPos points to original main header, we'll have the infinite
   74     // recursion, because ReadHeader() for main header will attempt to load
   75     // QOpen and call QuickOpen::Load again. If BlockPos points to long chain
   76     // of other main headers, we'll have multiple recursive calls of this
   77     // function wasting resources. So we prohibit QOpen temporarily to
   78     // prevent this. ReadHeader() calls QOpen.Init and sets MainHead Locator
   79     // and QOpenOffset fields, so we cannot use them to prohibit QOpen.
   80     Arc->SetProhibitQOpen(true);
   81     size_t ReadSize=Arc->ReadHeader();
   82     Arc->SetProhibitQOpen(false);
   83 
   84     if (ReadSize==0 || Arc->GetHeaderType()!=HEAD_SERVICE ||
   85         !Arc->SubHead.CmpName(SUBHEAD_TYPE_QOPEN))
   86     {
   87       Arc->Seek(SavePos,SEEK_SET);
   88       return;
   89     }
   90     QOHeaderPos=Arc->CurBlockPos;
   91     RawDataStart=Arc->Tell();
   92     RawDataSize=Arc->SubHead.UnpSize;
   93     Arc->Seek(SavePos,SEEK_SET);
   94 
   95     Loaded=true; // Set only after all file processing calls like Tell, Seek, ReadHeader.
   96   }
   97 
   98   if (Arc->SubHead.Encrypted)
   99   {
  100     RAROptions *Cmd=Arc->GetRAROptions();
  101 #ifndef RAR_NOCRYPT
  102     if (Cmd->Password.IsSet())
  103       Crypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,Arc->SubHead.Salt,
  104                          Arc->SubHead.InitV,Arc->SubHead.Lg2Count,
  105                          Arc->SubHead.HashKey,Arc->SubHead.PswCheck);
  106     else
  107 #endif
  108     {
  109       Loaded=false;
  110       return;
  111     }
  112   }
  113 
  114   RawDataPos=0;
  115   ReadBufSize=0;
  116   ReadBufPos=0;
  117   LastReadHeader.Reset();
  118   LastReadHeaderPos=0;
  119 
  120   ReadBuffer();
  121 }
  122 
  123 
  124 bool QuickOpen::Read(void *Data,size_t Size,size_t &Result)
  125 {
  126   if (!Loaded)
  127     return false;
  128   // Find next suitable cached block.
  129   while (LastReadHeaderPos+LastReadHeader.Size()<=SeekPos)
  130     if (!ReadNext())
  131       break;
  132   if (!Loaded)
  133   {
  134     // If something wrong happened, let's set the correct file pointer
  135     // and stop further quick open processing.
  136     if (UnsyncSeekPos)
  137       Arc->File::Seek(SeekPos,SEEK_SET);
  138     return false;
  139   }
  140 
  141   if (SeekPos>=LastReadHeaderPos && SeekPos+Size<=LastReadHeaderPos+LastReadHeader.Size())
  142   {
  143     memcpy(Data,LastReadHeader+size_t(SeekPos-LastReadHeaderPos),Size);
  144     Result=Size;
  145     SeekPos+=Size;
  146     UnsyncSeekPos=true;
  147   }
  148   else
  149   {
  150     if (UnsyncSeekPos)
  151     {
  152       Arc->File::Seek(SeekPos,SEEK_SET);
  153       UnsyncSeekPos=false;
  154     }
  155     int ReadSize=Arc->File::Read(Data,Size);
  156     if (ReadSize<0)
  157     {
  158       Loaded=false;
  159       return false;
  160     }
  161     Result=ReadSize;
  162     SeekPos+=ReadSize;
  163   }
  164   
  165   return true;
  166 }
  167 
  168 
  169 bool QuickOpen::Seek(int64 Offset,int Method)
  170 {
  171   if (!Loaded)
  172     return false;
  173 
  174   // Normally we process an archive sequentially from beginning to end,
  175   // so we read quick open data sequentially. But some operations like
  176   // archive updating involve several passes. So if we detect that file
  177   // pointer is moved back, we reload quick open data from beginning.
  178   if (Method==SEEK_SET && (uint64)Offset<SeekPos && (uint64)Offset<LastReadHeaderPos)
  179     Load(QOHeaderPos);
  180 
  181   if (Method==SEEK_SET)
  182     SeekPos=Offset;
  183   if (Method==SEEK_CUR)
  184     SeekPos+=Offset;
  185   UnsyncSeekPos=true;
  186 
  187   if (Method==SEEK_END)
  188   {
  189     Arc->File::Seek(Offset,SEEK_END);
  190     SeekPos=Arc->File::Tell();
  191     UnsyncSeekPos=false;
  192   }
  193   return true;
  194 }
  195 
  196 
  197 bool QuickOpen::Tell(int64 *Pos)
  198 {
  199   if (!Loaded)
  200     return false;
  201   *Pos=SeekPos;
  202   return true;
  203 }
  204 
  205 
  206 uint QuickOpen::ReadBuffer()
  207 {
  208   int64 SavePos=Arc->Tell();
  209   Arc->File::Seek(RawDataStart+RawDataPos,SEEK_SET);
  210   size_t SizeToRead=(size_t)Min(RawDataSize-RawDataPos,MaxBufSize-ReadBufSize);
  211   if (Arc->SubHead.Encrypted)
  212     SizeToRead &= ~CRYPT_BLOCK_MASK;
  213   int ReadSize=0;
  214   if (SizeToRead!=0)
  215   {
  216     ReadSize=Arc->File::Read(Buf+ReadBufSize,SizeToRead);
  217     if (ReadSize<=0)
  218       ReadSize=0;
  219     else
  220     {
  221 #ifndef RAR_NOCRYPT
  222       if (Arc->SubHead.Encrypted)
  223         Crypt.DecryptBlock(Buf+ReadBufSize,ReadSize & ~CRYPT_BLOCK_MASK);
  224 #endif
  225       RawDataPos+=ReadSize;
  226       ReadBufSize+=ReadSize;
  227     }
  228   }
  229   Arc->Seek(SavePos,SEEK_SET);
  230   return ReadSize;
  231 }
  232 
  233 
  234 // Fill RawRead object from buffer.
  235 bool QuickOpen::ReadRaw(RawRead &Raw)
  236 {
  237   if (MaxBufSize-ReadBufPos<0x100) // We are close to end of buffer.
  238   {
  239     // Ensure that we have enough data to read CRC and header size.
  240     size_t DataLeft=ReadBufSize-ReadBufPos;
  241     memcpy(Buf,Buf+ReadBufPos,DataLeft);
  242     ReadBufPos=0;
  243     ReadBufSize=DataLeft;
  244     ReadBuffer();
  245   }
  246   const size_t FirstReadSize=7;
  247   if (ReadBufPos+FirstReadSize>ReadBufSize)
  248     return false;
  249   Raw.Read(Buf+ReadBufPos,FirstReadSize);
  250   ReadBufPos+=FirstReadSize;
  251 
  252   uint SavedCRC=Raw.Get4();
  253   uint SizeBytes=Raw.GetVSize(4);
  254   uint64 BlockSize=Raw.GetV();
  255   int SizeToRead=int(BlockSize);
  256   SizeToRead-=FirstReadSize-SizeBytes-4; // Adjust overread size bytes if any.
  257   if (SizeToRead<0 || SizeBytes==0 || BlockSize==0)
  258   {
  259     Loaded=false; // Invalid data.
  260     return false;
  261   }
  262 
  263   // If rest of block data crosses Buf boundary, read it in loop.
  264   while (SizeToRead>0)
  265   {
  266     size_t DataLeft=ReadBufSize-ReadBufPos;
  267     size_t CurSizeToRead=Min(DataLeft,(size_t)SizeToRead);
  268     Raw.Read(Buf+ReadBufPos,CurSizeToRead);
  269     ReadBufPos+=CurSizeToRead;
  270     SizeToRead-=int(CurSizeToRead);
  271     if (SizeToRead>0) // We read the entire buffer and still need more data.
  272     {
  273       ReadBufPos=0;
  274       ReadBufSize=0;
  275       if (ReadBuffer()==0)
  276         return false;
  277     }
  278   }
  279 
  280   return SavedCRC==Raw.GetCRC50();
  281 }
  282 
  283 
  284 // Read next cached header.
  285 bool QuickOpen::ReadNext()
  286 {
  287   RawRead Raw(NULL);
  288   if (!ReadRaw(Raw)) // Read internal quick open header preceding stored block.
  289     return false;
  290   uint Flags=(uint)Raw.GetV();
  291   uint64 Offset=Raw.GetV();
  292   size_t HeaderSize=(size_t)Raw.GetV();
  293   if (HeaderSize>MAX_HEADER_SIZE_RAR5)
  294     return false;
  295   LastReadHeader.Alloc(HeaderSize);
  296   Raw.GetB(&LastReadHeader[0],HeaderSize);
  297   // Calculate the absolute position as offset from quick open service header.
  298   LastReadHeaderPos=QOHeaderPos-Offset;
  299   return true;
  300 }