1 #include "rar.hpp"
2
3 #ifdef RARDLL
4 static bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize);
5 static bool DllVolNotify(RAROptions *Cmd,wchar *NextName);
6 #endif
7
8
9
MergeArchive(Archive & Arc,ComprDataIO * DataIO,bool ShowFileName,wchar Command)10 bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Command)
11 {
12 RAROptions *Cmd=Arc.GetRAROptions();
13
14 HEADER_TYPE HeaderType=Arc.GetHeaderType();
15 FileHeader *hd=HeaderType==HEAD_SERVICE ? &Arc.SubHead:&Arc.FileHead;
16 bool SplitHeader=(HeaderType==HEAD_FILE || HeaderType==HEAD_SERVICE) &&
17 hd->SplitAfter;
18
19 if (DataIO!=NULL && SplitHeader)
20 {
21 bool PackedHashPresent=Arc.Format==RARFMT50 ||
22 hd->UnpVer>=20 && hd->FileHash.CRC32!=0xffffffff;
23 if (PackedHashPresent &&
24 !DataIO->PackedDataHash.Cmp(&hd->FileHash,hd->UseHashKey ? hd->HashKey:NULL))
25 uiMsg(UIERROR_CHECKSUMPACKED, Arc.FileName, hd->FileName);
26 }
27
28 int64 PosBeforeClose=Arc.Tell();
29
30 if (DataIO!=NULL)
31 DataIO->ProcessedArcSize+=Arc.FileLength();
32
33
34 Arc.Close();
35
36 wchar NextName[NM];
37 wcscpy(NextName,Arc.FileName);
38 NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering);
39
40 #if !defined(SFX_MODULE) && !defined(RARDLL)
41 bool RecoveryDone=false;
42 #endif
43 bool FailedOpen=false,OldSchemeTested=false;
44
45 #if !defined(GUI) && !defined(SILENT)
46 // In -vp mode we force the pause before next volume even if it is present
47 // and even if we are on the hard disk. It is important when user does not
48 // want to process partially downloaded volumes preliminary.
49 if (Cmd->VolumePause && !uiAskNextVolume(NextName,ASIZE(NextName)))
50 FailedOpen=true;
51 #endif
52
53 uint OpenMode = Cmd->OpenShared ? FMF_OPENSHARED : 0;
54
55 if (!FailedOpen)
56 while (!Arc.Open(NextName,OpenMode))
57 {
58 // We need to open a new volume which size was not calculated
59 // in total size before, so we cannot calculate the total progress
60 // anymore. Let's reset the total size to zero and stop
61 // the total progress.
62 if (DataIO!=NULL)
63 DataIO->TotalArcSize=0;
64
65 if (!OldSchemeTested)
66 {
67 // Checking for new style volumes renamed by user to old style
68 // name format. Some users did it for unknown reason.
69 wchar AltNextName[NM];
70 wcscpy(AltNextName,Arc.FileName);
71 NextVolumeName(AltNextName,ASIZE(AltNextName),true);
72 OldSchemeTested=true;
73 if (Arc.Open(AltNextName,OpenMode))
74 {
75 wcscpy(NextName,AltNextName);
76 break;
77 }
78 }
79 #ifdef RARDLL
80 if (!DllVolChange(Cmd,NextName,ASIZE(NextName)))
81 {
82 FailedOpen=true;
83 break;
84 }
85 #else // !RARDLL
86
87 #ifndef SFX_MODULE
88 if (!RecoveryDone)
89 {
90 RecVolumesRestore(Cmd,Arc.FileName,true);
91 RecoveryDone=true;
92 continue;
93 }
94 #endif
95
96 #ifndef GUI
97 if (!Cmd->VolumePause && !IsRemovable(NextName))
98 {
99 FailedOpen=true;
100 break;
101 }
102 #endif
103 #ifndef SILENT
104 if (Cmd->AllYes || !uiAskNextVolume(NextName,ASIZE(NextName)))
105 #endif
106 {
107 FailedOpen=true;
108 break;
109 }
110
111 #endif // RARDLL
112 }
113
114 if (FailedOpen)
115 {
116 uiMsg(UIERROR_MISSINGVOL,NextName);
117 Arc.Open(Arc.FileName,OpenMode);
118 Arc.Seek(PosBeforeClose,SEEK_SET);
119 return false;
120 }
121
122 if (Command=='T' || Command=='X' || Command=='E')
123 mprintf(St(Command=='T' ? MTestVol:MExtrVol),Arc.FileName);
124
125
126 Arc.CheckArc(true);
127 #ifdef RARDLL
128 if (!DllVolNotify(Cmd,NextName))
129 return false;
130 #endif
131
132 if (SplitHeader)
133 Arc.SearchBlock(HeaderType);
134 else
135 Arc.ReadHeader();
136 if (Arc.GetHeaderType()==HEAD_FILE)
137 {
138 Arc.ConvertAttributes();
139 Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET);
140 }
141 #ifndef GUI
142 if (ShowFileName)
143 {
144 mprintf(St(MExtrPoints),Arc.FileHead.FileName);
145 if (!Cmd->DisablePercentage)
146 mprintf(L" ");
147 }
148 #endif
149 if (DataIO!=NULL)
150 {
151 if (HeaderType==HEAD_ENDARC)
152 DataIO->UnpVolume=false;
153 else
154 {
155 DataIO->UnpVolume=hd->SplitAfter;
156 DataIO->SetPackedSizeToRead(hd->PackSize);
157 }
158 #ifdef SFX_MODULE
159 DataIO->UnpArcSize=Arc.FileLength();
160 #endif
161
162 // Reset the size of packed data read from current volume. It is used
163 // to display the total progress and preceding volumes are already
164 // compensated with ProcessedArcSize, so we need to reset this variable.
165 DataIO->CurUnpRead=0;
166
167 DataIO->PackedDataHash.Init(hd->FileHash.Type,Cmd->Threads);
168 }
169 return true;
170 }
171
172
173
174
175
176
177 #ifdef RARDLL
178 #if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
179 // Disable the run time stack check for unrar.dll, so we can manipulate
180 // with ChangeVolProc call type below. Run time check would intercept
181 // a wrong ESP before we restore it.
182 #pragma runtime_checks( "s", off )
183 #endif
184
DllVolChange(RAROptions * Cmd,wchar * NextName,size_t NameSize)185 bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize)
186 {
187 bool DllVolChanged=false,DllVolAborted=false;
188
189 if (Cmd->Callback!=NULL)
190 {
191 wchar OrgNextName[NM];
192 wcscpy(OrgNextName,NextName);
193 if (Cmd->Callback(UCM_CHANGEVOLUMEW,Cmd->UserData,(LPARAM)NextName,RAR_VOL_ASK)==-1)
194 DllVolAborted=true;
195 else
196 if (wcscmp(OrgNextName,NextName)!=0)
197 DllVolChanged=true;
198 else
199 {
200 char NextNameA[NM],OrgNextNameA[NM];
201 WideToChar(NextName,NextNameA,ASIZE(NextNameA));
202 strcpy(OrgNextNameA,NextNameA);
203 if (Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextNameA,RAR_VOL_ASK)==-1)
204 DllVolAborted=true;
205 else
206 if (strcmp(OrgNextNameA,NextNameA)!=0)
207 {
208 // We can damage some Unicode characters by U->A->U conversion,
209 // so set Unicode name only if we see that ANSI name is changed.
210 CharToWide(NextNameA,NextName,NameSize);
211 DllVolChanged=true;
212 }
213 }
214 }
215 if (!DllVolChanged && Cmd->ChangeVolProc!=NULL)
216 {
217 char NextNameA[NM];
218 WideToChar(NextName,NextNameA,ASIZE(NextNameA));
219 // Here we preserve ESP value. It is necessary for those developers,
220 // who still define ChangeVolProc callback as "C" type function,
221 // even though in year 2001 we announced in unrar.dll whatsnew.txt
222 // that it will be PASCAL type (for compatibility with Visual Basic).
223 #if defined(_MSC_VER)
224 #ifndef _WIN_64
225 __asm mov ebx,esp
226 #endif
227 #elif defined(_WIN_ALL) && defined(__BORLANDC__)
228 _EBX=_ESP;
229 #endif
230 int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_ASK);
231
232 // Restore ESP after ChangeVolProc with wrongly defined calling
233 // convention broken it.
234 #if defined(_MSC_VER)
235 #ifndef _WIN_64
236 __asm mov esp,ebx
237 #endif
238 #elif defined(_WIN_ALL) && defined(__BORLANDC__)
239 _ESP=_EBX;
240 #endif
241 if (RetCode==0)
242 DllVolAborted=true;
243 else
244 CharToWide(NextNameA,NextName,NameSize);
245 }
246
247 // We quit only on 'abort' condition, but not on 'name not changed'.
248 // It is legitimate for program to return the same name when waiting
249 // for currently non-existent volume.
250 if (DllVolAborted)
251 {
252 Cmd->DllError=ERAR_EOPEN;
253 return false;
254 }
255 return true;
256 }
257 #endif
258
259
260 #ifdef RARDLL
DllVolNotify(RAROptions * Cmd,wchar * NextName)261 bool DllVolNotify(RAROptions *Cmd,wchar *NextName)
262 {
263 char NextNameA[NM];
264 WideToChar(NextName,NextNameA,ASIZE(NextNameA));
265 if (Cmd->Callback!=NULL)
266 {
267 if (Cmd->Callback(UCM_CHANGEVOLUMEW,Cmd->UserData,(LPARAM)NextName,RAR_VOL_NOTIFY)==-1)
268 return false;
269 if (Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextNameA,RAR_VOL_NOTIFY)==-1)
270 return false;
271 }
272 if (Cmd->ChangeVolProc!=NULL)
273 {
274 #if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__)
275 _EBX=_ESP;
276 #endif
277 int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_NOTIFY);
278 #if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__)
279 _ESP=_EBX;
280 #endif
281 if (RetCode==0)
282 return false;
283 }
284 return true;
285 }
286
287 #if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
288 // Restore the run time stack check for unrar.dll.
289 #pragma runtime_checks( "s", restore )
290 #endif
291 #endif
292