/src/clamav/libclamunrar/rdwrfn.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include "rar.hpp" |
2 | | |
3 | | ComprDataIO::ComprDataIO() |
4 | 1.95M | { |
5 | 1.95M | #ifndef RAR_NOCRYPT |
6 | 1.95M | Crypt=new CryptData; |
7 | 1.95M | Decrypt=new CryptData; |
8 | 1.95M | #endif |
9 | | |
10 | 1.95M | Init(); |
11 | 1.95M | } |
12 | | |
13 | | |
14 | | void ComprDataIO::Init() |
15 | 1.95M | { |
16 | 1.95M | UnpackFromMemory=false; |
17 | 1.95M | UnpackToMemory=false; |
18 | 1.95M | UnpPackedSize=0; |
19 | 1.95M | UnpPackedLeft=0; |
20 | 1.95M | ShowProgress=true; |
21 | 1.95M | TestMode=false; |
22 | 1.95M | SkipUnpCRC=false; |
23 | 1.95M | NoFileHeader=false; |
24 | 1.95M | PackVolume=false; |
25 | 1.95M | UnpVolume=false; |
26 | 1.95M | NextVolumeMissing=false; |
27 | 1.95M | SrcFile=NULL; |
28 | 1.95M | DestFile=NULL; |
29 | 1.95M | UnpWrAddr=NULL; |
30 | 1.95M | UnpWrSize=0; |
31 | 1.95M | Command=NULL; |
32 | 1.95M | Encryption=false; |
33 | 1.95M | Decryption=false; |
34 | 1.95M | CurPackRead=CurPackWrite=CurUnpRead=CurUnpWrite=0; |
35 | 1.95M | LastPercent=-1; |
36 | 1.95M | SubHead=NULL; |
37 | 1.95M | SubHeadPos=NULL; |
38 | 1.95M | CurrentCommand=0; |
39 | 1.95M | ProcessedArcSize=0; |
40 | 1.95M | LastArcSize=0; |
41 | 1.95M | TotalArcSize=0; |
42 | 1.95M | } |
43 | | |
44 | | |
45 | | ComprDataIO::~ComprDataIO() |
46 | 1.95M | { |
47 | 1.95M | #ifndef RAR_NOCRYPT |
48 | 1.95M | delete Crypt; |
49 | 1.95M | delete Decrypt; |
50 | 1.95M | #endif |
51 | 1.95M | } |
52 | | |
53 | | |
54 | | |
55 | | |
56 | | int ComprDataIO::UnpRead(byte *Addr,size_t Count) |
57 | 8.28M | { |
58 | 8.28M | #ifndef RAR_NOCRYPT |
59 | | // In case of encryption we need to align read size to encryption |
60 | | // block size. We can do it by simple masking, because unpack read code |
61 | | // always reads more than CRYPT_BLOCK_SIZE, so we do not risk to make it 0. |
62 | 8.28M | if (Decryption) |
63 | 112k | Count &= ~CRYPT_BLOCK_MASK; |
64 | 8.28M | #endif |
65 | | |
66 | 8.28M | int ReadSize=0,TotalRead=0; |
67 | 8.28M | byte *ReadAddr; |
68 | 8.28M | ReadAddr=Addr; |
69 | 8.28M | while (Count > 0) |
70 | 8.28M | { |
71 | 8.28M | Archive *SrcArc=(Archive *)SrcFile; |
72 | | |
73 | 8.28M | if (UnpackFromMemory) |
74 | 0 | { |
75 | 0 | memcpy(Addr,UnpackFromMemoryAddr,UnpackFromMemorySize); |
76 | 0 | ReadSize=(int)UnpackFromMemorySize; |
77 | 0 | UnpackFromMemorySize=0; |
78 | 0 | } |
79 | 8.28M | else |
80 | 8.28M | { |
81 | 8.28M | size_t SizeToRead=((int64)Count>UnpPackedLeft) ? (size_t)UnpPackedLeft:Count; |
82 | 8.28M | if (SizeToRead > 0) |
83 | 7.98M | { |
84 | 7.98M | if (UnpVolume && Decryption && (int64)Count>UnpPackedLeft) |
85 | 0 | { |
86 | | // We need aligned blocks for decryption and we want "Keep broken |
87 | | // files" to work efficiently with missing encrypted volumes. |
88 | | // So for last data block in volume we adjust the size to read to |
89 | | // next equal or smaller block producing aligned total block size. |
90 | | // So we'll ask for next volume only when processing few unaligned |
91 | | // bytes left in the end, when most of data is already extracted. |
92 | 0 | size_t NewTotalRead = TotalRead + SizeToRead; |
93 | 0 | size_t Adjust = NewTotalRead - (NewTotalRead & ~CRYPT_BLOCK_MASK); |
94 | 0 | size_t NewSizeToRead = SizeToRead - Adjust; |
95 | 0 | if ((int)NewSizeToRead > 0) |
96 | 0 | SizeToRead = NewSizeToRead; |
97 | 0 | } |
98 | | |
99 | 7.98M | if (!SrcFile->IsOpened()) |
100 | 0 | return -1; |
101 | 7.98M | ReadSize=SrcFile->Read(ReadAddr,SizeToRead); |
102 | 7.98M | FileHeader *hd=SubHead!=NULL ? SubHead:&SrcArc->FileHead; |
103 | 7.98M | if (!NoFileHeader && hd->SplitAfter) |
104 | 1.86M | PackedDataHash.Update(ReadAddr,ReadSize); |
105 | 7.98M | } |
106 | 8.28M | } |
107 | 8.28M | CurUnpRead+=ReadSize; |
108 | 8.28M | TotalRead+=ReadSize; |
109 | 8.28M | #ifndef NOVOLUME |
110 | | // These variable are not used in NOVOLUME mode, so it is better |
111 | | // to exclude commands below to avoid compiler warnings. |
112 | 8.28M | ReadAddr+=ReadSize; |
113 | 8.28M | Count-=ReadSize; |
114 | 8.28M | #endif |
115 | 8.28M | UnpPackedLeft-=ReadSize; |
116 | | |
117 | | // Do not ask for next volume if we read something from current volume. |
118 | | // If next volume is missing, we need to process all data from current |
119 | | // volume before aborting. It helps to recover all possible data |
120 | | // in "Keep broken files" mode. But if we process encrypted data, |
121 | | // we ask for next volume also if we have non-aligned encryption block. |
122 | | // Since we adjust data size for decryption earlier above, |
123 | | // it does not hurt "Keep broken files" mode efficiency. |
124 | 8.28M | if (UnpVolume && UnpPackedLeft == 0 && |
125 | 8.28M | (ReadSize==0 || Decryption && (TotalRead & CRYPT_BLOCK_MASK) != 0) ) |
126 | 8.50k | { |
127 | 8.50k | #ifndef NOVOLUME |
128 | 8.50k | if (!MergeArchive(*SrcArc,this,true,CurrentCommand)) |
129 | 8.50k | #endif |
130 | 8.50k | { |
131 | 8.50k | NextVolumeMissing=true; |
132 | 8.50k | return -1; |
133 | 8.50k | } |
134 | 8.50k | } |
135 | 8.27M | else |
136 | 8.27M | break; |
137 | 8.28M | } |
138 | 8.27M | Archive *SrcArc=(Archive *)SrcFile; |
139 | 8.27M | if (SrcArc!=NULL) |
140 | 8.27M | ShowUnpRead(SrcArc->NextBlockPos-UnpPackedSize+CurUnpRead,TotalArcSize); |
141 | 8.27M | if (ReadSize!=-1) |
142 | 8.27M | { |
143 | 8.27M | ReadSize=TotalRead; |
144 | 8.27M | #ifndef RAR_NOCRYPT |
145 | 8.27M | if (Decryption) |
146 | 112k | Decrypt->DecryptBlock(Addr,ReadSize); |
147 | 8.27M | #endif |
148 | 8.27M | } |
149 | 8.27M | Wait(); |
150 | 8.27M | return ReadSize; |
151 | 8.28M | } |
152 | | |
153 | | |
154 | | void ComprDataIO::UnpWrite(byte *Addr,size_t Count) |
155 | 401k | { |
156 | | |
157 | 401k | #ifdef RARDLL |
158 | 401k | CommandData *Cmd=((Archive *)SrcFile)->GetCommandData(); |
159 | 401k | if (Cmd->DllOpMode!=RAR_SKIP) |
160 | 395k | { |
161 | 395k | if (Cmd->Callback!=NULL && |
162 | 395k | Cmd->Callback(UCM_PROCESSDATA,Cmd->UserData,(LPARAM)Addr,Count)==-1) |
163 | 0 | ErrHandler.Exit(RARX_USERBREAK); |
164 | 395k | if (Cmd->ProcessDataProc!=NULL) |
165 | 0 | { |
166 | 0 | int RetCode=Cmd->ProcessDataProc(Addr,(int)Count); |
167 | 0 | if (RetCode==0) |
168 | 0 | ErrHandler.Exit(RARX_USERBREAK); |
169 | 0 | } |
170 | 395k | } |
171 | 401k | #endif // RARDLL |
172 | | |
173 | 401k | UnpWrAddr=Addr; |
174 | 401k | UnpWrSize=Count; |
175 | 401k | if (UnpackToMemory) |
176 | 0 | { |
177 | 0 | if (Count <= UnpackToMemorySize) |
178 | 0 | { |
179 | 0 | memcpy(UnpackToMemoryAddr,Addr,Count); |
180 | 0 | UnpackToMemoryAddr+=Count; |
181 | 0 | UnpackToMemorySize-=Count; |
182 | 0 | } |
183 | 0 | } |
184 | 401k | else |
185 | 401k | if (!TestMode) |
186 | 385k | DestFile->Write(Addr,Count); |
187 | 401k | CurUnpWrite+=Count; |
188 | 401k | if (!SkipUnpCRC) |
189 | 391k | UnpHash.Update(Addr,Count); |
190 | 401k | ShowUnpWrite(); |
191 | 401k | Wait(); |
192 | 401k | } |
193 | | |
194 | | |
195 | | |
196 | | |
197 | | |
198 | | |
199 | | void ComprDataIO::ShowUnpRead(int64 ArcPos,int64 ArcSize) |
200 | 8.27M | { |
201 | 8.27M | if (ShowProgress && SrcFile!=NULL) |
202 | 8.16M | { |
203 | | // Important when processing several archives or multivolume archive. |
204 | 8.16M | ArcPos+=ProcessedArcSize; |
205 | | |
206 | 8.16M | Archive *SrcArc=(Archive *)SrcFile; |
207 | 8.16M | CommandData *Cmd=SrcArc->GetCommandData(); |
208 | | |
209 | 8.16M | int CurPercent=ToPercent(ArcPos,ArcSize); |
210 | 8.16M | if (!Cmd->DisablePercentage && CurPercent!=LastPercent) |
211 | 423k | { |
212 | 423k | uiExtractProgress(CurUnpWrite,SrcArc->FileHead.UnpSize,ArcPos,ArcSize); |
213 | 423k | LastPercent=CurPercent; |
214 | 423k | } |
215 | 8.16M | } |
216 | 8.27M | } |
217 | | |
218 | | |
219 | | void ComprDataIO::ShowUnpWrite() |
220 | 401k | { |
221 | 401k | } |
222 | | |
223 | | |
224 | | |
225 | | |
226 | | |
227 | | |
228 | | |
229 | | |
230 | | |
231 | | |
232 | | void ComprDataIO::SetFiles(File *SrcFile,File *DestFile) |
233 | 442k | { |
234 | 442k | if (SrcFile!=NULL) |
235 | 442k | ComprDataIO::SrcFile=SrcFile; |
236 | 442k | if (DestFile!=NULL) |
237 | 435k | ComprDataIO::DestFile=DestFile; |
238 | 442k | LastPercent=-1; |
239 | 442k | } |
240 | | |
241 | | |
242 | | void ComprDataIO::GetUnpackedData(byte **Data,size_t *Size) |
243 | 6.57k | { |
244 | 6.57k | *Data=UnpWrAddr; |
245 | 6.57k | *Size=UnpWrSize; |
246 | 6.57k | } |
247 | | |
248 | | |
249 | | void ComprDataIO::SetEncryption(bool Encrypt,CRYPT_METHOD Method, |
250 | | SecPassword *Password,const byte *Salt,const byte *InitV, |
251 | | uint Lg2Cnt,byte *HashKey,byte *PswCheck) |
252 | 450k | { |
253 | 450k | #ifndef RAR_NOCRYPT |
254 | 450k | if (Encrypt) |
255 | 0 | Encryption=Crypt->SetCryptKeys(true,Method,Password,Salt,InitV,Lg2Cnt,HashKey,PswCheck); |
256 | 450k | else |
257 | 450k | Decryption=Decrypt->SetCryptKeys(false,Method,Password,Salt,InitV,Lg2Cnt,HashKey,PswCheck); |
258 | 450k | #endif |
259 | 450k | } |
260 | | |
261 | | |
262 | | #if !defined(SFX_MODULE) && !defined(RAR_NOCRYPT) |
263 | | void ComprDataIO::SetAV15Encryption() |
264 | 0 | { |
265 | 0 | Decryption=true; |
266 | 0 | Decrypt->SetAV15Encryption(); |
267 | 0 | } |
268 | | #endif |
269 | | |
270 | | |
271 | | #if !defined(SFX_MODULE) && !defined(RAR_NOCRYPT) |
272 | | void ComprDataIO::SetCmt13Encryption() |
273 | 6.57k | { |
274 | 6.57k | Decryption=true; |
275 | 6.57k | Decrypt->SetCmt13Encryption(); |
276 | 6.57k | } |
277 | | #endif |
278 | | |
279 | | |
280 | | |
281 | | |
282 | | void ComprDataIO::SetUnpackToMemory(byte *Addr,uint Size) |
283 | 0 | { |
284 | 0 | UnpackToMemory=true; |
285 | 0 | UnpackToMemoryAddr=Addr; |
286 | 0 | UnpackToMemorySize=Size; |
287 | 0 | } |
288 | | |
289 | | |
290 | | // Extraction progress is based on the position in archive and we adjust |
291 | | // the total archives size here, so trailing blocks do not prevent progress |
292 | | // reaching 100% at the end of extraction. Alternatively we could print "100%" |
293 | | // after completing the entire archive extraction, but then we would need |
294 | | // to take into account possible messages like the checksum error after |
295 | | // last file percent progress. |
296 | | void ComprDataIO::AdjustTotalArcSize(Archive *Arc) |
297 | 944k | { |
298 | | // If we know a position of QO or RR blocks, use them to adjust the total |
299 | | // packed size to beginning of these blocks. Earlier we already calculated |
300 | | // the total size based on entire archive sizes. We also set LastArcSize |
301 | | // to start of first trailing block, to add it later to ProcessedArcSize. |
302 | 944k | int64 ArcLength=Arc->IsSeekable() ? Arc->FileLength() : 0; |
303 | 944k | if (Arc->MainHead.QOpenOffset!=0) // QO is always preceding RR record. |
304 | 285 | LastArcSize=Arc->MainHead.QOpenOffset; |
305 | 944k | else |
306 | 944k | if (Arc->MainHead.RROffset!=0) |
307 | 599 | LastArcSize=Arc->MainHead.RROffset; |
308 | 943k | else |
309 | 943k | { |
310 | | // If neither QO nor RR are found, exclude the approximate size of |
311 | | // end of archive block. |
312 | | // We select EndBlock to be larger than typical 8 bytes HEAD_ENDARC, |
313 | | // but to not exceed the smallest 22 bytes HEAD_FILE with 1 byte file |
314 | | // name, so we do not have two files with 100% at the end of archive. |
315 | 943k | const uint EndBlock=23; |
316 | | |
317 | 943k | if (ArcLength>EndBlock) |
318 | 939k | LastArcSize=ArcLength-EndBlock; |
319 | 943k | } |
320 | | |
321 | 944k | TotalArcSize-=ArcLength-LastArcSize; |
322 | 944k | } |