1 #include "rar.hpp"
2 
3 
4 
5 
6 #if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
7 // Disable the run time stack check for unrar.dll, so we can manipulate
8 // with ChangeVolProc call type below. Run time check would intercept
9 // a wrong ESP before we restore it.
10 #pragma runtime_checks( "s", off )
11 #endif
12 
MergeArchive(Archive & Arc,ComprDataIO * DataIO,bool ShowFileName,char Command)13 bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,char Command)
14 {
15   RAROptions *Cmd=Arc.GetRAROptions();
16 
17   int HeaderType=Arc.GetHeaderType();
18   FileHeader *hd=HeaderType==NEWSUB_HEAD ? &Arc.SubHead:&Arc.NewLhd;
19   bool SplitHeader=(HeaderType==FILE_HEAD || HeaderType==NEWSUB_HEAD) &&
20                    (hd->Flags & LHD_SPLIT_AFTER)!=0;
21 
22   if (DataIO!=NULL && SplitHeader && hd->UnpVer>=20 &&
23       hd->FileCRC!=0xffffffff && DataIO->PackedCRC!=~hd->FileCRC)
24   {
25     Log(Arc.FileName,St(MDataBadCRC),hd->FileName,Arc.FileName);
26   }
27 
28   int64 PosBeforeClose=Arc.Tell();
29 
30   if (DataIO!=NULL)
31     DataIO->ProcessedArcSize+=Arc.FileLength();
32 
33   Arc.Close();
34 
35   char NextName[NM];
36   wchar NextNameW[NM];
37   strcpy(NextName,Arc.FileName);
38   wcscpy(NextNameW,Arc.FileNameW);
39   NextVolumeName(NextName,NextNameW,ASIZE(NextName),(Arc.NewMhd.Flags & MHD_NEWNUMBERING)==0 || Arc.OldFormat);
40 
41 #if !defined(SFX_MODULE) && !defined(RARDLL)
42   bool RecoveryDone=false;
43 #endif
44   bool FailedOpen=false,OldSchemeTested=false;
45 
46 #if !defined(GUI) && !defined(SILENT)
47   // In -vp mode we force the pause before next volume even if it is present
48   // and even if we are on the hard disk. It is important when user does not
49   // want to process partially downloaded volumes preliminary.
50   if (Cmd->VolumePause && !AskNextVol(NextName,NextNameW))
51     FailedOpen=true;
52 #endif
53 
54   if (!FailedOpen)
55     while (!Arc.Open(NextName,NextNameW))
56     {
57       // We need to open a new volume which size was not calculated
58       // in total size before, so we cannot calculate the total progress
59       // anymore. Let's reset the total size to zero and stop
60       // the total progress.
61       if (DataIO!=NULL)
62         DataIO->TotalArcSize=0;
63 
64       if (!OldSchemeTested)
65       {
66         // Checking for new style volumes renamed by user to old style
67         // name format. Some users did it for unknown reason.
68         char AltNextName[NM];
69         wchar AltNextNameW[NM];
70         strcpy(AltNextName,Arc.FileName);
71         wcscpy(AltNextNameW,Arc.FileNameW);
72         NextVolumeName(AltNextName,AltNextNameW,ASIZE(AltNextName),true);
73         OldSchemeTested=true;
74         if (Arc.Open(AltNextName,AltNextNameW))
75         {
76           strcpy(NextName,AltNextName);
77           wcscpy(NextNameW,AltNextNameW);
78           break;
79         }
80       }
81 #ifdef RARDLL
82       if (Cmd->Callback==NULL && Cmd->ChangeVolProc==NULL ||
83           Cmd->Callback!=NULL && Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextName,RAR_VOL_ASK)==-1)
84       {
85         Cmd->DllError=ERAR_EOPEN;
86         FailedOpen=true;
87         break;
88       }
89       if (Cmd->ChangeVolProc!=NULL)
90       {
91         // Here we preserve ESP value. It is necessary for those developers,
92         // who still define ChangeVolProc callback as "C" type function,
93         // even though in year 2001 we announced in unrar.dll whatsnew.txt
94         // that it will be PASCAL type (for compatibility with Visual Basic).
95 #if defined(_MSC_VER)
96 #ifndef _WIN_64
97         __asm mov ebx,esp
98 #endif
99 #elif defined(_WIN_ALL) && defined(__BORLANDC__)
100         _EBX=_ESP;
101 #endif
102         int RetCode=Cmd->ChangeVolProc(NextName,RAR_VOL_ASK);
103 
104         // Restore ESP after ChangeVolProc with wrongly defined calling
105         // convention broken it.
106 #if defined(_MSC_VER)
107 #ifndef _WIN_64
108         __asm mov esp,ebx
109 #endif
110 #elif defined(_WIN_ALL) && defined(__BORLANDC__)
111         _ESP=_EBX;
112 #endif
113         if (RetCode==0)
114         {
115           Cmd->DllError=ERAR_EOPEN;
116           FailedOpen=true;
117           break;
118         }
119       }
120 #else // RARDLL
121 
122 #if !defined(SFX_MODULE) && !defined(_WIN_CE)
123       if (!RecoveryDone)
124       {
125         RecVolumes RecVol;
126         RecVol.Restore(Cmd,Arc.FileName,Arc.FileNameW,true);
127         RecoveryDone=true;
128         continue;
129       }
130 #endif
131 
132 #ifndef GUI
133       if (!Cmd->VolumePause && !IsRemovable(NextName))
134       {
135         FailedOpen=true;
136         break;
137       }
138 #endif
139 #ifndef SILENT
140       if (Cmd->AllYes || !AskNextVol(NextName,NextNameW))
141 #endif
142       {
143         FailedOpen=true;
144         break;
145       }
146 
147 #endif // RARDLL
148     }
149 
150   if (FailedOpen)
151   {
152 #if !defined(SILENT) && !defined(_WIN_CE)
153       Log(Arc.FileName,St(MAbsNextVol),NextName);
154 #endif
155     Arc.Open(Arc.FileName,Arc.FileNameW);
156     Arc.Seek(PosBeforeClose,SEEK_SET);
157     return(false);
158   }
159   Arc.CheckArc(true);
160 #ifdef RARDLL
161   if (Cmd->Callback!=NULL &&
162       Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextName,RAR_VOL_NOTIFY)==-1)
163     return(false);
164   if (Cmd->ChangeVolProc!=NULL)
165   {
166 #if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__)
167     _EBX=_ESP;
168 #endif
169     int RetCode=Cmd->ChangeVolProc(NextName,RAR_VOL_NOTIFY);
170 #if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__)
171     _ESP=_EBX;
172 #endif
173     if (RetCode==0)
174       return(false);
175   }
176 #endif
177 
178   if (Command=='T' || Command=='X' || Command=='E')
179     mprintf(St(Command=='T' ? MTestVol:MExtrVol),Arc.FileName);
180 
181 
182   if (SplitHeader)
183     Arc.SearchBlock(HeaderType);
184   else
185     Arc.ReadHeader();
186   if (Arc.GetHeaderType()==FILE_HEAD)
187   {
188     Arc.ConvertAttributes();
189     Arc.Seek(Arc.NextBlockPos-Arc.NewLhd.FullPackSize,SEEK_SET);
190   }
191 #ifndef GUI
192   if (ShowFileName)
193   {
194     char OutName[NM];
195     IntToExt(Arc.NewLhd.FileName,OutName);
196 #ifdef UNICODE_SUPPORTED
197     bool WideName=(Arc.NewLhd.Flags & LHD_UNICODE) && UnicodeEnabled();
198     if (WideName)
199     {
200       wchar NameW[NM];
201       ConvertPath(Arc.NewLhd.FileNameW,NameW);
202       char Name[NM];
203       if (WideToChar(NameW,Name) && IsNameUsable(Name))
204         strcpy(OutName,Name);
205     }
206 #endif
207     mprintf(St(MExtrPoints),OutName);
208     if (!Cmd->DisablePercentage)
209       mprintf("     ");
210   }
211 #endif
212   if (DataIO!=NULL)
213   {
214     if (HeaderType==ENDARC_HEAD)
215       DataIO->UnpVolume=false;
216     else
217     {
218       DataIO->UnpVolume=(hd->Flags & LHD_SPLIT_AFTER)!=0;
219       DataIO->SetPackedSizeToRead(hd->FullPackSize);
220     }
221 #ifdef SFX_MODULE
222     DataIO->UnpArcSize=Arc.FileLength();
223 #endif
224 
225     // Reset the size of packed data read from current volume. It is used
226     // to display the total progress and preceding volumes are already
227     // compensated with ProcessedArcSize, so we need to reset this variable.
228     DataIO->CurUnpRead=0;
229 
230     DataIO->PackedCRC=0xffffffff;
231 //    DataIO->SetFiles(&Arc,NULL);
232   }
233   return(true);
234 }
235 
236 #if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
237 // Restore the run time stack check for unrar.dll.
238 #pragma runtime_checks( "s", restore )
239 #endif
240 
241 
242 
243 
244 
245 
246 #ifndef SILENT
AskNextVol(char * ArcName,wchar * ArcNameW)247 bool AskNextVol(char *ArcName,wchar *ArcNameW)
248 {
249   eprintf(St(MAskNextVol),ArcName);
250   if (Ask(St(MContinueQuit))==2)
251     return(false);
252   return(true);
253 }
254 #endif
255