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 wcsncpyz(NextName,Arc.FileName,ASIZE(NextName));
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(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 wcsncpyz(AltNextName,Arc.FileName,ASIZE(AltNextName));
71 NextVolumeName(AltNextName,ASIZE(AltNextName),true);
72 OldSchemeTested=true;
73 if (Arc.Open(AltNextName,OpenMode))
74 {
75 wcsncpyz(NextName,AltNextName,ASIZE(NextName));
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 if (!Cmd->VolumePause && !IsRemovable(NextName))
97 {
98 FailedOpen=true;
99 break;
100 }
101 #ifndef SILENT
102 if (Cmd->AllYes || !uiAskNextVolume(NextName,ASIZE(NextName)))
103 #endif
104 {
105 FailedOpen=true;
106 break;
107 }
108
109 #endif // RARDLL
110 }
111
112 if (FailedOpen)
113 {
114 uiMsg(UIERROR_MISSINGVOL,NextName);
115 Arc.Open(Arc.FileName,OpenMode);
116 Arc.Seek(PosBeforeClose,SEEK_SET);
117 return false;
118 }
119
120 if (Command=='T' || Command=='X' || Command=='E')
121 mprintf(St(Command=='T' ? MTestVol:MExtrVol),Arc.FileName);
122
123
124 Arc.CheckArc(true);
125 #ifdef RARDLL
126 if (!DllVolNotify(Cmd,NextName))
127 return false;
128 #endif
129
130 if (SplitHeader)
131 Arc.SearchBlock(HeaderType);
132 else
133 Arc.ReadHeader();
134 if (Arc.GetHeaderType()==HEAD_FILE)
135 {
136 Arc.ConvertAttributes();
137 Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET);
138 }
139 if (ShowFileName && !Cmd->DisableNames)
140 {
141 mprintf(St(MExtrPoints),Arc.FileHead.FileName);
142 if (!Cmd->DisablePercentage)
143 mprintf(L" ");
144 }
145 if (DataIO!=NULL)
146 {
147 if (HeaderType==HEAD_ENDARC)
148 DataIO->UnpVolume=false;
149 else
150 {
151 DataIO->UnpVolume=hd->SplitAfter;
152 DataIO->SetPackedSizeToRead(hd->PackSize);
153 }
154 #ifdef SFX_MODULE
155 DataIO->UnpArcSize=Arc.FileLength();
156 #endif
157
158 // Reset the size of packed data read from current volume. It is used
159 // to display the total progress and preceding volumes are already
160 // compensated with ProcessedArcSize, so we need to reset this variable.
161 DataIO->CurUnpRead=0;
162
163 DataIO->PackedDataHash.Init(hd->FileHash.Type,Cmd->Threads);
164 }
165 return true;
166 }
167
168
169
170
171
172
173 #ifdef RARDLL
174 #if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
175 // Disable the run time stack check for unrar.dll, so we can manipulate
176 // with ChangeVolProc call type below. Run time check would intercept
177 // a wrong ESP before we restore it.
178 #pragma runtime_checks( "s", off )
179 #endif
180
DllVolChange(RAROptions * Cmd,wchar * NextName,size_t NameSize)181 bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize)
182 {
183 bool DllVolChanged=false,DllVolAborted=false;
184
185 if (Cmd->Callback!=NULL)
186 {
187 wchar OrgNextName[NM];
188 wcsncpyz(OrgNextName,NextName,ASIZE(OrgNextName));
189 if (Cmd->Callback(UCM_CHANGEVOLUMEW,Cmd->UserData,(LPARAM)NextName,RAR_VOL_ASK)==-1)
190 DllVolAborted=true;
191 else
192 if (wcscmp(OrgNextName,NextName)!=0)
193 DllVolChanged=true;
194 else
195 {
196 char NextNameA[NM],OrgNextNameA[NM];
197 WideToChar(NextName,NextNameA,ASIZE(NextNameA));
198 strncpyz(OrgNextNameA,NextNameA,ASIZE(OrgNextNameA));
199 if (Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextNameA,RAR_VOL_ASK)==-1)
200 DllVolAborted=true;
201 else
202 if (strcmp(OrgNextNameA,NextNameA)!=0)
203 {
204 // We can damage some Unicode characters by U->A->U conversion,
205 // so set Unicode name only if we see that ANSI name is changed.
206 CharToWide(NextNameA,NextName,NameSize);
207 DllVolChanged=true;
208 }
209 }
210 }
211 if (!DllVolChanged && Cmd->ChangeVolProc!=NULL)
212 {
213 char NextNameA[NM];
214 WideToChar(NextName,NextNameA,ASIZE(NextNameA));
215 // Here we preserve ESP value. It is necessary for those developers,
216 // who still define ChangeVolProc callback as "C" type function,
217 // even though in year 2001 we announced in unrar.dll whatsnew.txt
218 // that it will be PASCAL type (for compatibility with Visual Basic).
219 #if defined(_MSC_VER)
220 #ifndef _WIN_64
221 __asm mov ebx,esp
222 #endif
223 #elif defined(_WIN_ALL) && defined(__BORLANDC__)
224 _EBX=_ESP;
225 #endif
226 int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_ASK);
227
228 // Restore ESP after ChangeVolProc with wrongly defined calling
229 // convention broken it.
230 #if defined(_MSC_VER)
231 #ifndef _WIN_64
232 __asm mov esp,ebx
233 #endif
234 #elif defined(_WIN_ALL) && defined(__BORLANDC__)
235 _ESP=_EBX;
236 #endif
237 if (RetCode==0)
238 DllVolAborted=true;
239 else
240 CharToWide(NextNameA,NextName,NameSize);
241 }
242
243 // We quit only on 'abort' condition, but not on 'name not changed'.
244 // It is legitimate for program to return the same name when waiting
245 // for currently non-existent volume.
246 // Also we quit to prevent an infinite loop if no callback is defined.
247 if (DllVolAborted || Cmd->Callback==NULL && Cmd->ChangeVolProc==NULL)
248 {
249 Cmd->DllError=ERAR_EOPEN;
250 return false;
251 }
252 return true;
253 }
254 #endif
255
256
257 #ifdef RARDLL
DllVolNotify(RAROptions * Cmd,wchar * NextName)258 bool DllVolNotify(RAROptions *Cmd,wchar *NextName)
259 {
260 char NextNameA[NM];
261 WideToChar(NextName,NextNameA,ASIZE(NextNameA));
262 if (Cmd->Callback!=NULL)
263 {
264 if (Cmd->Callback(UCM_CHANGEVOLUMEW,Cmd->UserData,(LPARAM)NextName,RAR_VOL_NOTIFY)==-1)
265 return false;
266 if (Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextNameA,RAR_VOL_NOTIFY)==-1)
267 return false;
268 }
269 if (Cmd->ChangeVolProc!=NULL)
270 {
271 #if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__)
272 _EBX=_ESP;
273 #endif
274 int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_NOTIFY);
275 #if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__)
276 _ESP=_EBX;
277 #endif
278 if (RetCode==0)
279 return false;
280 }
281 return true;
282 }
283
284 #if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
285 // Restore the run time stack check for unrar.dll.
286 #pragma runtime_checks( "s", restore )
287 #endif
288 #endif
289