"Fossies" - the Fresh Open Source Software Archive 
Member "unrar/recvol3.cpp" (4 May 2022, 13399 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 "recvol3.cpp" see the
Fossies "Dox" file reference documentation.
1 // Buffer size for all volumes involved.
2 static const size_t TotalBufferSize=0x4000000;
3
4 class RSEncode // Encode or decode data area, one object per one thread.
5 {
6 private:
7 RSCoder RSC;
8 public:
9 void EncodeBuf();
10 void DecodeBuf();
11
12 void Init(int RecVolNumber) {RSC.Init(RecVolNumber);}
13 byte *Buf;
14 byte *OutBuf;
15 int BufStart;
16 int BufEnd;
17 int FileNumber;
18 int RecVolNumber;
19 size_t RecBufferSize;
20 int *Erasures;
21 int EraSize;
22 };
23
24
25 #ifdef RAR_SMP
26 THREAD_PROC(RSEncodeThread)
27 {
28 RSEncode *rs=(RSEncode *)Data;
29 rs->EncodeBuf();
30 }
31
32 THREAD_PROC(RSDecodeThread)
33 {
34 RSEncode *rs=(RSEncode *)Data;
35 rs->DecodeBuf();
36 }
37 #endif
38
39 RecVolumes3::RecVolumes3(RAROptions *Cmd,bool TestOnly)
40 {
41 memset(SrcFile,0,sizeof(SrcFile));
42 if (TestOnly)
43 {
44 #ifdef RAR_SMP
45 RSThreadPool=NULL;
46 #endif
47 }
48 else
49 {
50 Buf.Alloc(TotalBufferSize);
51 memset(SrcFile,0,sizeof(SrcFile));
52 #ifdef RAR_SMP
53 RSThreadPool=new ThreadPool(Cmd->Threads);
54 #endif
55 }
56 }
57
58
59 RecVolumes3::~RecVolumes3()
60 {
61 for (size_t I=0;I<ASIZE(SrcFile);I++)
62 delete SrcFile[I];
63 #ifdef RAR_SMP
64 delete RSThreadPool;
65 #endif
66 }
67
68
69
70
71 void RSEncode::EncodeBuf()
72 {
73 for (int BufPos=BufStart;BufPos<BufEnd;BufPos++)
74 {
75 byte Data[256],Code[256];
76 for (int I=0;I<FileNumber;I++)
77 Data[I]=Buf[I*RecBufferSize+BufPos];
78 RSC.Encode(Data,FileNumber,Code);
79 for (int I=0;I<RecVolNumber;I++)
80 OutBuf[I*RecBufferSize+BufPos]=Code[I];
81 }
82 }
83
84
85 // Check for names like arc5_3_1.rev created by RAR 3.0.
86 static bool IsNewStyleRev(const wchar *Name)
87 {
88 wchar *Ext=GetExt(Name);
89 if (Ext==NULL)
90 return true;
91 int DigitGroup=0;
92 for (Ext--;Ext>Name;Ext--)
93 if (!IsDigit(*Ext))
94 if (*Ext=='_' && IsDigit(*(Ext-1)))
95 DigitGroup++;
96 else
97 break;
98 return DigitGroup<2;
99 }
100
101
102 bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
103 {
104 wchar ArcName[NM];
105 wcsncpyz(ArcName,Name,ASIZE(ArcName));
106 wchar *Ext=GetExt(ArcName);
107 bool NewStyle=false; // New style .rev volumes are supported since RAR 3.10.
108 bool RevName=Ext!=NULL && wcsicomp(Ext,L".rev")==0;
109 if (RevName)
110 {
111 NewStyle=IsNewStyleRev(ArcName);
112 while (Ext>ArcName+1 && (IsDigit(*(Ext-1)) || *(Ext-1)=='_'))
113 Ext--;
114 wcsncpyz(Ext,L"*.*",ASIZE(ArcName)-(Ext-ArcName));
115
116 FindFile Find;
117 Find.SetMask(ArcName);
118 FindData fd;
119 while (Find.Next(&fd))
120 {
121 Archive Arc(Cmd);
122 if (Arc.WOpen(fd.Name) && Arc.IsArchive(true))
123 {
124 wcsncpyz(ArcName,fd.Name,ASIZE(ArcName));
125 break;
126 }
127 }
128 }
129
130 Archive Arc(Cmd);
131 if (!Arc.WCheckOpen(ArcName))
132 return false;
133 if (!Arc.Volume)
134 {
135 uiMsg(UIERROR_NOTVOLUME,ArcName);
136 return false;
137 }
138 bool NewNumbering=Arc.NewNumbering;
139 Arc.Close();
140
141 wchar *VolNumStart=VolNameToFirstName(ArcName,ArcName,ASIZE(ArcName),NewNumbering);
142 wchar RecVolMask[NM];
143 wcsncpyz(RecVolMask,ArcName,ASIZE(RecVolMask));
144 size_t BaseNamePartLength=VolNumStart-ArcName;
145 wcsncpyz(RecVolMask+BaseNamePartLength,L"*.rev",ASIZE(RecVolMask)-BaseNamePartLength);
146
147 int64 RecFileSize=0;
148
149 // We cannot display "Calculating CRC..." message here, because we do not
150 // know if we'll find any recovery volumes. We'll display it after finding
151 // the first recovery volume.
152 bool CalcCRCMessageDone=false;
153
154 FindFile Find;
155 Find.SetMask(RecVolMask);
156 FindData RecData;
157 int FileNumber=0,RecVolNumber=0,FoundRecVolumes=0,MissingVolumes=0;
158 wchar PrevName[NM];
159 while (Find.Next(&RecData))
160 {
161 wchar *CurName=RecData.Name;
162 int P[3];
163 if (!RevName && !NewStyle)
164 {
165 NewStyle=true;
166
167 wchar *Dot=GetExt(CurName);
168 if (Dot!=NULL)
169 {
170 int LineCount=0;
171 Dot--;
172 while (Dot>CurName && *Dot!='.')
173 {
174 if (*Dot=='_')
175 LineCount++;
176 Dot--;
177 }
178 if (LineCount==2)
179 NewStyle=false;
180 }
181 }
182 if (NewStyle)
183 {
184 if (!CalcCRCMessageDone)
185 {
186 uiMsg(UIMSG_RECVOLCALCCHECKSUM);
187 CalcCRCMessageDone=true;
188 }
189
190 uiMsg(UIMSG_STRING,CurName);
191
192 File CurFile;
193 CurFile.TOpen(CurName);
194 CurFile.Seek(0,SEEK_END);
195 int64 Length=CurFile.Tell();
196 CurFile.Seek(Length-7,SEEK_SET);
197 for (int I=0;I<3;I++)
198 P[2-I]=CurFile.GetByte()+1;
199 uint FileCRC=0;
200 for (int I=0;I<4;I++)
201 FileCRC|=CurFile.GetByte()<<(I*8);
202 uint CalcCRC;
203 CalcFileSum(&CurFile,&CalcCRC,NULL,Cmd->Threads,Length-4);
204 if (FileCRC!=CalcCRC)
205 {
206 uiMsg(UIMSG_CHECKSUM,CurName);
207 continue;
208 }
209 }
210 else
211 {
212 wchar *Dot=GetExt(CurName);
213 if (Dot==NULL)
214 continue;
215 bool WrongParam=false;
216 for (size_t I=0;I<ASIZE(P);I++)
217 {
218 do
219 {
220 Dot--;
221 } while (IsDigit(*Dot) && Dot>=CurName+BaseNamePartLength);
222 P[I]=atoiw(Dot+1);
223 if (P[I]==0 || P[I]>255)
224 WrongParam=true;
225 }
226 if (WrongParam)
227 continue;
228 }
229 if (P[1]+P[2]>255)
230 continue;
231 if (RecVolNumber!=0 && RecVolNumber!=P[1] || FileNumber!=0 && FileNumber!=P[2])
232 {
233 uiMsg(UIERROR_RECVOLDIFFSETS,CurName,PrevName);
234 return false;
235 }
236 RecVolNumber=P[1];
237 FileNumber=P[2];
238 wcsncpyz(PrevName,CurName,ASIZE(PrevName));
239 File *NewFile=new File;
240 NewFile->TOpen(CurName);
241 SrcFile[FileNumber+P[0]-1]=NewFile;
242 FoundRecVolumes++;
243
244 if (RecFileSize==0)
245 RecFileSize=NewFile->FileLength();
246 }
247 if (!Silent || FoundRecVolumes!=0)
248 uiMsg(UIMSG_RECVOLFOUND,FoundRecVolumes);
249 if (FoundRecVolumes==0)
250 return false;
251
252 bool WriteFlags[256];
253 memset(WriteFlags,0,sizeof(WriteFlags));
254
255 wchar LastVolName[NM];
256 *LastVolName=0;
257
258 for (int CurArcNum=0;CurArcNum<FileNumber;CurArcNum++)
259 {
260 Archive *NewFile=new Archive(Cmd);
261 bool ValidVolume=FileExist(ArcName);
262 if (ValidVolume)
263 {
264 NewFile->TOpen(ArcName);
265 ValidVolume=NewFile->IsArchive(false);
266 if (ValidVolume)
267 {
268 while (NewFile->ReadHeader()!=0)
269 {
270 if (NewFile->GetHeaderType()==HEAD_ENDARC)
271 {
272 uiMsg(UIMSG_STRING,ArcName);
273
274 if (NewFile->EndArcHead.DataCRC)
275 {
276 uint CalcCRC;
277 CalcFileSum(NewFile,&CalcCRC,NULL,Cmd->Threads,NewFile->CurBlockPos);
278 if (NewFile->EndArcHead.ArcDataCRC!=CalcCRC)
279 {
280 ValidVolume=false;
281 uiMsg(UIMSG_CHECKSUM,ArcName);
282 }
283 }
284 break;
285 }
286 NewFile->SeekToNext();
287 }
288 }
289 if (!ValidVolume)
290 {
291 NewFile->Close();
292 wchar NewName[NM];
293 wcsncpyz(NewName,ArcName,ASIZE(NewName));
294 wcsncatz(NewName,L".bad",ASIZE(NewName));
295
296 uiMsg(UIMSG_BADARCHIVE,ArcName);
297 uiMsg(UIMSG_RENAMING,ArcName,NewName);
298 RenameFile(ArcName,NewName);
299 }
300 NewFile->Seek(0,SEEK_SET);
301 }
302 if (!ValidVolume)
303 {
304 // It is important to return 'false' instead of aborting here,
305 // so if we are called from extraction, we will be able to continue
306 // extracting. It may happen if .rar and .rev are on read-only disks
307 // like CDs.
308 if (!NewFile->Create(ArcName,FMF_WRITE|FMF_SHAREREAD))
309 {
310 // We need to display the title of operation before the error message,
311 // to make clear for user that create error is related to recovery
312 // volumes. This is why we cannot use WCreate call here. Title must be
313 // before create error, not after that.
314
315 uiMsg(UIERROR_RECVOLFOUND,FoundRecVolumes); // Intentionally not displayed in console mode.
316 uiMsg(UIERROR_RECONSTRUCTING);
317 ErrHandler.CreateErrorMsg(ArcName);
318 return false;
319 }
320
321 WriteFlags[CurArcNum]=true;
322 MissingVolumes++;
323
324 if (CurArcNum==FileNumber-1)
325 wcsncpyz(LastVolName,ArcName,ASIZE(LastVolName));
326
327 uiMsg(UIMSG_MISSINGVOL,ArcName);
328 uiMsg(UIEVENT_NEWARCHIVE,ArcName);
329 }
330 SrcFile[CurArcNum]=(File*)NewFile;
331 NextVolumeName(ArcName,ASIZE(ArcName),!NewNumbering);
332 }
333
334 uiMsg(UIMSG_RECVOLMISSING,MissingVolumes);
335
336 if (MissingVolumes==0)
337 {
338 uiMsg(UIERROR_RECVOLALLEXIST);
339 return false;
340 }
341
342 if (MissingVolumes>FoundRecVolumes)
343 {
344 uiMsg(UIERROR_RECVOLFOUND,FoundRecVolumes); // Intentionally not displayed in console mode.
345 uiMsg(UIERROR_RECVOLCANNOTFIX);
346 return false;
347 }
348
349 uiMsg(UIMSG_RECONSTRUCTING);
350
351 int TotalFiles=FileNumber+RecVolNumber;
352 int Erasures[256],EraSize=0;
353
354 for (int I=0;I<TotalFiles;I++)
355 if (WriteFlags[I] || SrcFile[I]==NULL)
356 Erasures[EraSize++]=I;
357
358 int64 ProcessedSize=0;
359 int LastPercent=-1;
360 mprintf(L" ");
361 // Size of per file buffer.
362 size_t RecBufferSize=TotalBufferSize/TotalFiles;
363
364 #ifdef RAR_SMP
365 uint ThreadNumber=Cmd->Threads;
366 #else
367 uint ThreadNumber=1;
368 #endif
369 RSEncode *rse=new RSEncode[ThreadNumber];
370 for (uint I=0;I<ThreadNumber;I++)
371 rse[I].Init(RecVolNumber);
372
373 while (true)
374 {
375 Wait();
376 int MaxRead=0;
377 for (int I=0;I<TotalFiles;I++)
378 if (WriteFlags[I] || SrcFile[I]==NULL)
379 memset(&Buf[I*RecBufferSize],0,RecBufferSize);
380 else
381 {
382 int ReadSize=SrcFile[I]->Read(&Buf[I*RecBufferSize],RecBufferSize);
383 if ((size_t)ReadSize!=RecBufferSize)
384 memset(&Buf[I*RecBufferSize+ReadSize],0,RecBufferSize-ReadSize);
385 if (ReadSize>MaxRead)
386 MaxRead=ReadSize;
387 }
388 if (MaxRead==0)
389 break;
390
391 int CurPercent=ToPercent(ProcessedSize,RecFileSize);
392 if (!Cmd->DisablePercentage && CurPercent!=LastPercent)
393 {
394 uiProcessProgress("RC",ProcessedSize,RecFileSize);
395 LastPercent=CurPercent;
396 }
397 ProcessedSize+=MaxRead;
398
399 int BlockStart=0;
400 int BlockSize=MaxRead/ThreadNumber;
401 if (BlockSize<0x100)
402 BlockSize=MaxRead;
403
404 for (uint CurThread=0;BlockStart<MaxRead;CurThread++)
405 {
406 // Last thread processes all left data including increasement
407 // from rounding error.
408 if (CurThread==ThreadNumber-1)
409 BlockSize=MaxRead-BlockStart;
410
411 RSEncode *curenc=rse+CurThread;
412 curenc->Buf=&Buf[0];
413 curenc->BufStart=BlockStart;
414 curenc->BufEnd=BlockStart+BlockSize;
415 curenc->FileNumber=TotalFiles;
416 curenc->RecBufferSize=RecBufferSize;
417 curenc->Erasures=Erasures;
418 curenc->EraSize=EraSize;
419
420 #ifdef RAR_SMP
421 if (ThreadNumber>1)
422 RSThreadPool->AddTask(RSDecodeThread,(void*)curenc);
423 else
424 curenc->DecodeBuf();
425 #else
426 curenc->DecodeBuf();
427 #endif
428
429 BlockStart+=BlockSize;
430 }
431
432 #ifdef RAR_SMP
433 RSThreadPool->WaitDone();
434 #endif // RAR_SMP
435
436 for (int I=0;I<FileNumber;I++)
437 if (WriteFlags[I])
438 SrcFile[I]->Write(&Buf[I*RecBufferSize],MaxRead);
439 }
440 delete[] rse;
441
442 for (int I=0;I<RecVolNumber+FileNumber;I++)
443 if (SrcFile[I]!=NULL)
444 {
445 File *CurFile=SrcFile[I];
446 if (NewStyle && WriteFlags[I])
447 {
448 int64 Length=CurFile->Tell();
449 CurFile->Seek(Length-7,SEEK_SET);
450 for (int J=0;J<7;J++)
451 CurFile->PutByte(0);
452 }
453 CurFile->Close();
454 SrcFile[I]=NULL;
455 }
456 if (*LastVolName!=0)
457 {
458 // Truncate the last volume to its real size.
459 Archive Arc(Cmd);
460 if (Arc.Open(LastVolName,FMF_UPDATE) && Arc.IsArchive(true) &&
461 Arc.SearchBlock(HEAD_ENDARC))
462 {
463 Arc.Seek(Arc.NextBlockPos,SEEK_SET);
464 char Buf[8192];
465 int ReadSize=Arc.Read(Buf,sizeof(Buf));
466 int ZeroCount=0;
467 while (ZeroCount<ReadSize && Buf[ZeroCount]==0)
468 ZeroCount++;
469 if (ZeroCount==ReadSize)
470 {
471 Arc.Seek(Arc.NextBlockPos,SEEK_SET);
472 Arc.Truncate();
473 }
474 }
475 }
476 #if !defined(SILENT)
477 if (!Cmd->DisablePercentage)
478 mprintf(L"\b\b\b\b100%%");
479 if (!Silent && !Cmd->DisableDone)
480 mprintf(St(MDone));
481 #endif
482 return true;
483 }
484
485
486 void RSEncode::DecodeBuf()
487 {
488 for (int BufPos=BufStart;BufPos<BufEnd;BufPos++)
489 {
490 byte Data[256];
491 for (int I=0;I<FileNumber;I++)
492 Data[I]=Buf[I*RecBufferSize+BufPos];
493 RSC.Decode(Data,FileNumber,Erasures,EraSize);
494 for (int I=0;I<EraSize;I++)
495 Buf[Erasures[I]*RecBufferSize+BufPos]=Data[Erasures[I]];
496 }
497 }
498
499
500 void RecVolumes3::Test(RAROptions *Cmd,const wchar *Name)
501 {
502 if (!IsNewStyleRev(Name)) // RAR 3.0 name#_#_#.rev do not include CRC32.
503 {
504 ErrHandler.UnknownMethodMsg(Name,Name);
505 return;
506 }
507
508 wchar VolName[NM];
509 wcsncpyz(VolName,Name,ASIZE(VolName));
510
511 while (FileExist(VolName))
512 {
513 File CurFile;
514 if (!CurFile.Open(VolName))
515 {
516 ErrHandler.OpenErrorMsg(VolName); // It also sets RARX_OPEN.
517 continue;
518 }
519 if (!uiStartFileExtract(VolName,false,true,false))
520 return;
521 mprintf(St(MExtrTestFile),VolName);
522 mprintf(L" ");
523 CurFile.Seek(0,SEEK_END);
524 int64 Length=CurFile.Tell();
525 CurFile.Seek(Length-4,SEEK_SET);
526 uint FileCRC=0;
527 for (int I=0;I<4;I++)
528 FileCRC|=CurFile.GetByte()<<(I*8);
529
530 uint CalcCRC;
531 CalcFileSum(&CurFile,&CalcCRC,NULL,1,Length-4,Cmd->DisablePercentage ? 0 : CALCFSUM_SHOWPROGRESS);
532 if (FileCRC==CalcCRC)
533 {
534 mprintf(L"%s%s ",L"\b\b\b\b\b ",St(MOk));
535 }
536 else
537 {
538 uiMsg(UIERROR_CHECKSUM,VolName,VolName);
539 ErrHandler.SetErrorCode(RARX_CRC);
540 }
541
542 NextVolumeName(VolName,ASIZE(VolName),false);
543 }
544 }