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