1 #include "rar.hpp"
2 
ComprDataIO()3 ComprDataIO::ComprDataIO()
4 {
5 #ifndef RAR_NOCRYPT
6   Crypt=new CryptData;
7   Decrypt=new CryptData;
8 #endif
9 
10   Init();
11 }
12 
13 
Init()14 void ComprDataIO::Init()
15 {
16   UnpackFromMemory=false;
17   UnpackToMemory=false;
18   UnpPackedSize=0;
19   ShowProgress=true;
20   TestMode=false;
21   SkipUnpCRC=false;
22   NoFileHeader=false;
23   PackVolume=false;
24   UnpVolume=false;
25   NextVolumeMissing=false;
26   SrcFile=NULL;
27   DestFile=NULL;
28   UnpWrAddr=NULL;
29   UnpWrSize=0;
30   Command=NULL;
31   Encryption=false;
32   Decryption=false;
33   CurPackRead=CurPackWrite=CurUnpRead=CurUnpWrite=0;
34   LastPercent=-1;
35   SubHead=NULL;
36   SubHeadPos=NULL;
37   CurrentCommand=0;
38   ProcessedArcSize=TotalArcSize=0;
39 }
40 
41 
~ComprDataIO()42 ComprDataIO::~ComprDataIO()
43 {
44 #ifndef RAR_NOCRYPT
45   delete Crypt;
46   delete Decrypt;
47 #endif
48 }
49 
50 
51 
52 
UnpRead(byte * Addr,size_t Count)53 int ComprDataIO::UnpRead(byte *Addr,size_t Count)
54 {
55 #ifndef RAR_NOCRYPT
56   // In case of encryption we need to align read size to encryption
57   // block size. We can do it by simple masking, because unpack read code
58   // always reads more than CRYPT_BLOCK_SIZE, so we do not risk to make it 0.
59   if (Decryption)
60     Count &= ~CRYPT_BLOCK_MASK;
61 #endif
62 
63   int ReadSize=0,TotalRead=0;
64   byte *ReadAddr;
65   ReadAddr=Addr;
66   while (Count > 0)
67   {
68     Archive *SrcArc=(Archive *)SrcFile;
69 
70     if (UnpackFromMemory)
71     {
72       memcpy(Addr,UnpackFromMemoryAddr,UnpackFromMemorySize);
73       ReadSize=(int)UnpackFromMemorySize;
74       UnpackFromMemorySize=0;
75     }
76     else
77     {
78       size_t SizeToRead=((int64)Count>UnpPackedSize) ? (size_t)UnpPackedSize:Count;
79       if (SizeToRead > 0)
80       {
81         if (UnpVolume && Decryption && (int64)Count>UnpPackedSize)
82         {
83           // We need aligned blocks for decryption and we want "Keep broken
84           // files" to work efficiently with missing encrypted volumes.
85           // So for last data block in volume we adjust the size to read to
86           // next equal or smaller block producing aligned total block size.
87           // So we'll ask for next volume only when processing few unaligned
88           // bytes left in the end, when most of data is already extracted.
89           size_t NewTotalRead = TotalRead + SizeToRead;
90           size_t Adjust = NewTotalRead - (NewTotalRead  & ~CRYPT_BLOCK_MASK);
91           size_t NewSizeToRead = SizeToRead - Adjust;
92           if ((int)NewSizeToRead > 0)
93             SizeToRead = NewSizeToRead;
94         }
95 
96         if (!SrcFile->IsOpened())
97           return -1;
98         ReadSize=SrcFile->Read(ReadAddr,SizeToRead);
99         FileHeader *hd=SubHead!=NULL ? SubHead:&SrcArc->FileHead;
100         if (!NoFileHeader && hd->SplitAfter)
101           PackedDataHash.Update(ReadAddr,ReadSize);
102       }
103     }
104     CurUnpRead+=ReadSize;
105     TotalRead+=ReadSize;
106 #ifndef NOVOLUME
107     // These variable are not used in NOVOLUME mode, so it is better
108     // to exclude commands below to avoid compiler warnings.
109     ReadAddr+=ReadSize;
110     Count-=ReadSize;
111 #endif
112     UnpPackedSize-=ReadSize;
113 
114     // Do not ask for next volume if we read something from current volume.
115     // If next volume is missing, we need to process all data from current
116     // volume before aborting. It helps to recover all possible data
117     // in "Keep broken files" mode. But if we process encrypted data,
118     // we ask for next volume also if we have non-aligned encryption block.
119     // Since we adjust data size for decryption earlier above,
120     // it does not hurt "Keep broken files" mode efficiency.
121     if (UnpVolume && UnpPackedSize == 0 &&
122         (ReadSize==0 || Decryption && (TotalRead & CRYPT_BLOCK_MASK) != 0) )
123     {
124 #ifndef NOVOLUME
125       if (!MergeArchive(*SrcArc,this,true,CurrentCommand))
126 #endif
127       {
128         NextVolumeMissing=true;
129         return -1;
130       }
131     }
132     else
133       break;
134   }
135   Archive *SrcArc=(Archive *)SrcFile;
136   if (SrcArc!=NULL)
137     ShowUnpRead(SrcArc->CurBlockPos+CurUnpRead,UnpArcSize);
138   if (ReadSize!=-1)
139   {
140     ReadSize=TotalRead;
141 #ifndef RAR_NOCRYPT
142     if (Decryption)
143       Decrypt->DecryptBlock(Addr,ReadSize);
144 #endif
145   }
146   Wait();
147   return ReadSize;
148 }
149 
150 
151 #if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
152 // Disable the run time stack check for unrar.dll, so we can manipulate
153 // with ProcessDataProc call type below. Run time check would intercept
154 // a wrong ESP before we restore it.
155 #pragma runtime_checks( "s", off )
156 #endif
157 
UnpWrite(byte * Addr,size_t Count)158 void ComprDataIO::UnpWrite(byte *Addr,size_t Count)
159 {
160 
161 #ifdef RARDLL
162   RAROptions *Cmd=((Archive *)SrcFile)->GetRAROptions();
163   if (Cmd->DllOpMode!=RAR_SKIP)
164   {
165     if (Cmd->Callback!=NULL &&
166         Cmd->Callback(UCM_PROCESSDATA,Cmd->UserData,(LPARAM)Addr,Count)==-1)
167       ErrHandler.Exit(RARX_USERBREAK);
168     if (Cmd->ProcessDataProc!=NULL)
169     {
170       // Here we preserve ESP value. It is necessary for those developers,
171       // who still define ProcessDataProc callback as "C" type function,
172       // even though in year 2001 we announced in unrar.dll whatsnew.txt
173       // that it will be PASCAL type (for compatibility with Visual Basic).
174 #if defined(_MSC_VER)
175 #ifndef _WIN_64
176       __asm mov ebx,esp
177 #endif
178 #elif defined(_WIN_ALL) && defined(__BORLANDC__)
179       _EBX=_ESP;
180 #endif
181       int RetCode=Cmd->ProcessDataProc(Addr,(int)Count);
182 
183       // Restore ESP after ProcessDataProc with wrongly defined calling
184       // convention broken it.
185 #if defined(_MSC_VER)
186 #ifndef _WIN_64
187       __asm mov esp,ebx
188 #endif
189 #elif defined(_WIN_ALL) && defined(__BORLANDC__)
190       _ESP=_EBX;
191 #endif
192       if (RetCode==0)
193         ErrHandler.Exit(RARX_USERBREAK);
194     }
195   }
196 #endif // RARDLL
197 
198   UnpWrAddr=Addr;
199   UnpWrSize=Count;
200   if (UnpackToMemory)
201   {
202     if (Count <= UnpackToMemorySize)
203     {
204       //memcpy(UnpackToMemoryAddr,Addr,Count);
205       UnpackToMemoryAddr+=Count;
206       UnpackToMemorySize-=Count;
207     }
208   }
209   else
210     if (!TestMode)
211       DestFile->Write(Addr,Count);
212   CurUnpWrite+=Count;
213   if (!SkipUnpCRC)
214     UnpHash.Update(Addr,Count);
215   ShowUnpWrite();
216   Wait();
217 }
218 
219 #if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
220 // Restore the run time stack check for unrar.dll.
221 #pragma runtime_checks( "s", restore )
222 #endif
223 
224 
225 
226 
227 
228 
ShowUnpRead(int64 ArcPos,int64 ArcSize)229 void ComprDataIO::ShowUnpRead(int64 ArcPos,int64 ArcSize)
230 {
231   if (ShowProgress && SrcFile!=NULL)
232   {
233     if (TotalArcSize!=0)
234     {
235       // important when processing several archives or multivolume archive
236       ArcSize=TotalArcSize;
237       ArcPos+=ProcessedArcSize;
238     }
239 
240     Archive *SrcArc=(Archive *)SrcFile;
241     RAROptions *Cmd=SrcArc->GetRAROptions();
242 
243     int CurPercent=ToPercent(ArcPos,ArcSize);
244     if (!Cmd->DisablePercentage && CurPercent!=LastPercent)
245     {
246       uiExtractProgress(CurUnpWrite,SrcArc->FileHead.UnpSize,ArcPos,ArcSize);
247       LastPercent=CurPercent;
248     }
249   }
250 }
251 
252 
ShowUnpWrite()253 void ComprDataIO::ShowUnpWrite()
254 {
255 }
256 
257 
258 
259 
260 
261 
262 
263 
264 
265 
SetFiles(File * SrcFile,File * DestFile)266 void ComprDataIO::SetFiles(File *SrcFile,File *DestFile)
267 {
268   if (SrcFile!=NULL)
269     ComprDataIO::SrcFile=SrcFile;
270   if (DestFile!=NULL)
271     ComprDataIO::DestFile=DestFile;
272   LastPercent=-1;
273 }
274 
275 
GetUnpackedData(byte ** Data,size_t * Size)276 void ComprDataIO::GetUnpackedData(byte **Data,size_t *Size)
277 {
278   *Data=UnpWrAddr;
279   *Size=UnpWrSize;
280 }
281 
282 
SetEncryption(bool Encrypt,CRYPT_METHOD Method,SecPassword * Password,const byte * Salt,const byte * InitV,uint Lg2Cnt,byte * HashKey,byte * PswCheck)283 void ComprDataIO::SetEncryption(bool Encrypt,CRYPT_METHOD Method,
284      SecPassword *Password,const byte *Salt,const byte *InitV,
285      uint Lg2Cnt,byte *HashKey,byte *PswCheck)
286 {
287 #ifndef RAR_NOCRYPT
288   if (Encrypt)
289     Encryption=Crypt->SetCryptKeys(true,Method,Password,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
290   else
291     Decryption=Decrypt->SetCryptKeys(false,Method,Password,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
292 #endif
293 }
294 
InitRijindal(byte * Key,byte * InitV)295 void ComprDataIO::InitRijindal(byte *Key,byte *InitV)
296 {
297 #ifndef RAR_NOCRYPT
298   Decryption=true;
299   Decrypt->SetRijndalDecryptKey(Key,InitV);
300 #endif
301 }
302 
303 #if !defined(SFX_MODULE) && !defined(RAR_NOCRYPT)
SetAV15Encryption()304 void ComprDataIO::SetAV15Encryption()
305 {
306   Decryption=true;
307   Decrypt->SetAV15Encryption();
308 }
309 #endif
310 
311 
312 #if !defined(SFX_MODULE) && !defined(RAR_NOCRYPT)
SetCmt13Encryption()313 void ComprDataIO::SetCmt13Encryption()
314 {
315   Decryption=true;
316   Decrypt->SetCmt13Encryption();
317 }
318 #endif
319 
320 
321 
322 
SetUnpackToMemory(byte * Addr,uint Size)323 void ComprDataIO::SetUnpackToMemory(byte *Addr,uint Size)
324 {
325   UnpackToMemory=true;
326   UnpackToMemoryAddr=Addr;
327   UnpackToMemorySize=Size;
328 }
329 
SetUnpackFromMemory(byte * Addr,uint Size)330 void ComprDataIO::SetUnpackFromMemory(byte *Addr,uint Size)
331 {
332   UnpackFromMemory=true;
333   UnpackFromMemoryAddr=Addr;
334   UnpackFromMemorySize=Size;
335 }
336