other-licenses/7zstub/src/7zip/UI/Common/OpenArchive.cpp

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:dc3674d7066d
1 // OpenArchive.cpp
2
3 #include "StdAfx.h"
4
5 #include "OpenArchive.h"
6
7 #include "Common/Wildcard.h"
8
9 #include "Windows/FileName.h"
10 #include "Windows/FileDir.h"
11 #include "Windows/Defs.h"
12 #include "Windows/PropVariant.h"
13
14 #include "../../Common/FileStreams.h"
15 #include "../../Common/StreamUtils.h"
16
17 #include "Common/StringConvert.h"
18
19 #ifdef FORMAT_7Z
20 #include "../../Archive/7z/7zHandler.h"
21 #endif
22
23 #ifdef FORMAT_BZIP2
24 #include "../../Archive/BZip2/BZip2Handler.h"
25 #endif
26
27 #ifdef FORMAT_GZIP
28 #include "../../Archive/GZip/GZipHandler.h"
29 #endif
30
31 #ifdef FORMAT_SPLIT
32 #include "../../Archive/Split/SplitHandler.h"
33 #endif
34
35 #ifdef FORMAT_TAR
36 #include "../../Archive/Tar/TarHandler.h"
37 #endif
38
39 #ifdef FORMAT_ZIP
40 #include "../../Archive/Zip/ZipHandler.h"
41 #endif
42
43 #ifdef FORMAT_Z
44 #include "../../Archive/Z/ZHandler.h"
45 #endif
46
47 #ifndef EXCLUDE_COM
48 #include "HandlerLoader.h"
49 #endif
50
51 #include "DefaultName.h"
52
53 using namespace NWindows;
54
55 HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, UString &result)
56 {
57 NCOM::CPropVariant prop;
58 RINOK(archive->GetProperty(index, kpidPath, &prop));
59 if(prop.vt == VT_BSTR)
60 result = prop.bstrVal;
61 else if (prop.vt == VT_EMPTY)
62 result.Empty();
63 else
64 return E_FAIL;
65 return S_OK;
66 }
67
68 HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, const UString &defaultName, UString &result)
69 {
70 RINOK(GetArchiveItemPath(archive, index, result));
71 if (result.IsEmpty())
72 result = defaultName;
73 return S_OK;
74 }
75
76 HRESULT GetArchiveItemFileTime(IInArchive *archive, UInt32 index,
77 const FILETIME &defaultFileTime, FILETIME &fileTime)
78 {
79 NCOM::CPropVariant prop;
80 RINOK(archive->GetProperty(index, kpidLastWriteTime, &prop));
81 if (prop.vt == VT_FILETIME)
82 fileTime = prop.filetime;
83 else if (prop.vt == VT_EMPTY)
84 fileTime = defaultFileTime;
85 else
86 return E_FAIL;
87 return S_OK;
88 }
89
90 static HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result)
91 {
92 NCOM::CPropVariant prop;
93 RINOK(archive->GetProperty(index, propID, &prop));
94 if(prop.vt == VT_BOOL)
95 result = VARIANT_BOOLToBool(prop.boolVal);
96 else if (prop.vt == VT_EMPTY)
97 result = false;
98 else
99 return E_FAIL;
100 return S_OK;
101 }
102
103 HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result)
104 {
105 return IsArchiveItemProp(archive, index, kpidIsFolder, result);
106 }
107
108 HRESULT IsArchiveItemAnti(IInArchive *archive, UInt32 index, bool &result)
109 {
110 return IsArchiveItemProp(archive, index, kpidIsAnti, result);
111 }
112
113 // Static-SFX (for Linux) can be big
114 const UInt64 kMaxCheckStartPosition =
115 #ifdef _WIN32
116 1 << 20;
117 #else
118 1 << 22;
119 #endif
120
121
122 HRESULT ReOpenArchive(IInArchive *archive, const UString &fileName)
123 {
124 CInFileStream *inStreamSpec = new CInFileStream;
125 CMyComPtr<IInStream> inStream(inStreamSpec);
126 inStreamSpec->Open(fileName);
127 return archive->Open(inStream, &kMaxCheckStartPosition, NULL);
128 }
129
130 #ifndef _SFX
131 static inline bool TestSignature(const Byte *p1, const Byte *p2, size_t size)
132 {
133 for (size_t i = 0; i < size; i++)
134 if (p1[i] != p2[i])
135 return false;
136 return true;
137 }
138 #endif
139
140 HRESULT OpenArchive(
141 IInStream *inStream,
142 const UString &fileName,
143 #ifndef EXCLUDE_COM
144 HMODULE *module,
145 #endif
146 IInArchive **archiveResult,
147 CArchiverInfo &archiverInfoResult,
148 UString &defaultItemName,
149 IArchiveOpenCallback *openArchiveCallback)
150 {
151 *archiveResult = NULL;
152 CObjectVector<CArchiverInfo> archiverInfoList;
153 ReadArchiverInfoList(archiverInfoList);
154 UString extension;
155 {
156 int dotPos = fileName.ReverseFind(L'.');
157 if (dotPos >= 0)
158 extension = fileName.Mid(dotPos + 1);
159 }
160 CIntVector orderIndices;
161 int i;
162 bool finded = false;
163 for(i = 0; i < archiverInfoList.Size(); i++)
164 {
165 if (archiverInfoList[i].FindExtension(extension) >= 0)
166 {
167 orderIndices.Insert(0, i);
168 finded = true;
169 }
170 else
171 orderIndices.Add(i);
172 }
173
174 #ifndef _SFX
175 if (!finded)
176 {
177 CByteBuffer byteBuffer;
178 const UInt32 kBufferSize = (200 << 10);
179 byteBuffer.SetCapacity(kBufferSize);
180 Byte *buffer = byteBuffer;
181 RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
182 UInt32 processedSize;
183 RINOK(ReadStream(inStream, buffer, kBufferSize, &processedSize));
184 int numFinded = 0;
185 for (int pos = (int)processedSize; pos >= 0 ; pos--)
186 {
187 for(int i = numFinded; i < orderIndices.Size(); i++)
188 {
189 int index = orderIndices[i];
190 const CArchiverInfo &ai = archiverInfoList[index];
191 const CByteBuffer &sig = ai.StartSignature;
192 if (sig.GetCapacity() == 0)
193 continue;
194 if (pos + sig.GetCapacity() > processedSize)
195 continue;
196 if (TestSignature(buffer + pos, sig, sig.GetCapacity()))
197 {
198 orderIndices.Delete(i);
199 orderIndices.Insert(0, index);
200 numFinded++;
201 }
202 }
203 }
204 }
205 #endif
206
207 HRESULT badResult = S_OK;
208 for(i = 0; i < orderIndices.Size(); i++)
209 {
210 inStream->Seek(0, STREAM_SEEK_SET, NULL);
211 const CArchiverInfo &archiverInfo = archiverInfoList[orderIndices[i]];
212 #ifndef EXCLUDE_COM
213 CHandlerLoader loader;
214 #endif
215 CMyComPtr<IInArchive> archive;
216
217 #ifdef FORMAT_7Z
218 if (archiverInfo.Name.CompareNoCase(L"7z") == 0)
219 archive = new NArchive::N7z::CHandler;
220 #endif
221
222 #ifdef FORMAT_BZIP2
223 if (archiverInfo.Name.CompareNoCase(L"BZip2") == 0)
224 archive = new NArchive::NBZip2::CHandler;
225 #endif
226
227 #ifdef FORMAT_GZIP
228 if (archiverInfo.Name.CompareNoCase(L"GZip") == 0)
229 archive = new NArchive::NGZip::CHandler;
230 #endif
231
232 #ifdef FORMAT_SPLIT
233 if (archiverInfo.Name.CompareNoCase(L"Split") == 0)
234 archive = new NArchive::NSplit::CHandler;
235 #endif
236
237 #ifdef FORMAT_TAR
238 if (archiverInfo.Name.CompareNoCase(L"Tar") == 0)
239 archive = new NArchive::NTar::CHandler;
240 #endif
241
242 #ifdef FORMAT_ZIP
243 if (archiverInfo.Name.CompareNoCase(L"Zip") == 0)
244 archive = new NArchive::NZip::CHandler;
245 #endif
246
247 #ifdef FORMAT_Z
248 if (archiverInfo.Name.CompareNoCase(L"Z") == 0)
249 archive = new NArchive::NZ::CHandler;
250 #endif
251
252
253 #ifndef EXCLUDE_COM
254 if (!archive)
255 {
256 HRESULT result = loader.CreateHandler(archiverInfo.FilePath,
257 archiverInfo.ClassID, (void **)&archive, false);
258 if (result != S_OK)
259 continue;
260 }
261 #endif
262
263 if (!archive)
264 return E_FAIL;
265
266 HRESULT result = archive->Open(inStream, &kMaxCheckStartPosition, openArchiveCallback);
267 if(result == S_FALSE)
268 continue;
269 if(result != S_OK)
270 {
271 badResult = result;
272 if(result == E_ABORT)
273 break;
274 continue;
275 }
276 *archiveResult = archive.Detach();
277 #ifndef EXCLUDE_COM
278 *module = loader.Detach();
279 #endif
280 archiverInfoResult = archiverInfo;
281 int subExtIndex = archiverInfo.FindExtension(extension);
282 if (subExtIndex < 0)
283 subExtIndex = 0;
284 defaultItemName = GetDefaultName2(fileName,
285 archiverInfo.Extensions[subExtIndex].Ext,
286 archiverInfo.Extensions[subExtIndex].AddExt);
287
288 return S_OK;
289 }
290 if (badResult != S_OK)
291 return badResult;
292 return S_FALSE;
293 }
294
295 HRESULT OpenArchive(const UString &filePath,
296 #ifndef EXCLUDE_COM
297 HMODULE *module,
298 #endif
299 IInArchive **archiveResult,
300 CArchiverInfo &archiverInfo,
301 UString &defaultItemName,
302 IArchiveOpenCallback *openArchiveCallback)
303 {
304 CInFileStream *inStreamSpec = new CInFileStream;
305 CMyComPtr<IInStream> inStream(inStreamSpec);
306 if (!inStreamSpec->Open(filePath))
307 return GetLastError();
308 return OpenArchive(inStream, ExtractFileNameFromPath(filePath),
309 #ifndef EXCLUDE_COM
310 module,
311 #endif
312 archiveResult, archiverInfo,
313 defaultItemName, openArchiveCallback);
314 }
315
316 static void MakeDefaultName(UString &name)
317 {
318 int dotPos = name.ReverseFind(L'.');
319 if (dotPos < 0)
320 return;
321 UString ext = name.Mid(dotPos + 1);
322 if (ext.IsEmpty())
323 return;
324 for (int pos = 0; pos < ext.Length(); pos++)
325 if (ext[pos] < L'0' || ext[pos] > L'9')
326 return;
327 name = name.Left(dotPos);
328 }
329
330 HRESULT OpenArchive(const UString &fileName,
331 #ifndef EXCLUDE_COM
332 HMODULE *module0,
333 HMODULE *module1,
334 #endif
335 IInArchive **archive0,
336 IInArchive **archive1,
337 CArchiverInfo &archiverInfo0,
338 CArchiverInfo &archiverInfo1,
339 UString &defaultItemName0,
340 UString &defaultItemName1,
341 IArchiveOpenCallback *openArchiveCallback)
342 {
343 HRESULT result = OpenArchive(fileName,
344 #ifndef EXCLUDE_COM
345 module0,
346 #endif
347 archive0, archiverInfo0, defaultItemName0, openArchiveCallback);
348 RINOK(result);
349 CMyComPtr<IInArchiveGetStream> getStream;
350 result = (*archive0)->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream);
351 if (result != S_OK || getStream == 0)
352 return S_OK;
353
354 CMyComPtr<ISequentialInStream> subSeqStream;
355 result = getStream->GetStream(0, &subSeqStream);
356 if (result != S_OK)
357 return S_OK;
358
359 CMyComPtr<IInStream> subStream;
360 if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK)
361 return S_OK;
362 if (!subStream)
363 return S_OK;
364
365 UInt32 numItems;
366 RINOK((*archive0)->GetNumberOfItems(&numItems));
367 if (numItems < 1)
368 return S_OK;
369
370 UString subPath;
371 RINOK(GetArchiveItemPath(*archive0, 0, subPath))
372 if (subPath.IsEmpty())
373 {
374 MakeDefaultName(defaultItemName0);
375 subPath = defaultItemName0;
376 if (archiverInfo0.Name.CompareNoCase(L"7z") == 0)
377 {
378 if (subPath.Right(3).CompareNoCase(L".7z") != 0)
379 subPath += L".7z";
380 }
381 }
382 else
383 subPath = ExtractFileNameFromPath(subPath);
384
385 CMyComPtr<IArchiveOpenSetSubArchiveName> setSubArchiveName;
386 openArchiveCallback->QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void **)&setSubArchiveName);
387 if (setSubArchiveName)
388 setSubArchiveName->SetSubArchiveName(subPath);
389
390 result = OpenArchive(subStream, subPath,
391 #ifndef EXCLUDE_COM
392 module1,
393 #endif
394 archive1, archiverInfo1, defaultItemName1, openArchiveCallback);
395 return S_OK;
396 }
397
398 HRESULT MyOpenArchive(const UString &archiveName,
399 #ifndef EXCLUDE_COM
400 HMODULE *module,
401 #endif
402 IInArchive **archive,
403 UString &defaultItemName,
404 IOpenCallbackUI *openCallbackUI)
405 {
406 COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
407 CMyComPtr<IArchiveOpenCallback> openCallback = openCallbackSpec;
408 openCallbackSpec->Callback = openCallbackUI;
409
410 UString fullName;
411 int fileNamePartStartIndex;
412 NFile::NDirectory::MyGetFullPathName(archiveName, fullName, fileNamePartStartIndex);
413 openCallbackSpec->Init(
414 fullName.Left(fileNamePartStartIndex),
415 fullName.Mid(fileNamePartStartIndex));
416
417 CArchiverInfo archiverInfo;
418 return OpenArchive(archiveName,
419 #ifndef EXCLUDE_COM
420 module,
421 #endif
422 archive,
423 archiverInfo,
424 defaultItemName,
425 openCallback);
426 }
427
428 HRESULT MyOpenArchive(const UString &archiveName,
429 #ifndef EXCLUDE_COM
430 HMODULE *module0,
431 HMODULE *module1,
432 #endif
433 IInArchive **archive0,
434 IInArchive **archive1,
435 UString &defaultItemName0,
436 UString &defaultItemName1,
437 UStringVector &volumePaths,
438 IOpenCallbackUI *openCallbackUI)
439 {
440 COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
441 CMyComPtr<IArchiveOpenCallback> openCallback = openCallbackSpec;
442 openCallbackSpec->Callback = openCallbackUI;
443
444 UString fullName;
445 int fileNamePartStartIndex;
446 NFile::NDirectory::MyGetFullPathName(archiveName, fullName, fileNamePartStartIndex);
447 UString prefix = fullName.Left(fileNamePartStartIndex);
448 UString name = fullName.Mid(fileNamePartStartIndex);
449 openCallbackSpec->Init(prefix, name);
450
451 CArchiverInfo archiverInfo0, archiverInfo1;
452 HRESULT result = OpenArchive(archiveName,
453 #ifndef EXCLUDE_COM
454 module0,
455 module1,
456 #endif
457 archive0,
458 archive1,
459 archiverInfo0,
460 archiverInfo1,
461 defaultItemName0,
462 defaultItemName1,
463 openCallback);
464 RINOK(result);
465 volumePaths.Add(prefix + name);
466 for (int i = 0; i < openCallbackSpec->FileNames.Size(); i++)
467 volumePaths.Add(prefix + openCallbackSpec->FileNames[i]);
468 return S_OK;
469 }
470
471 HRESULT CArchiveLink::Close()
472 {
473 if (Archive1 != 0)
474 RINOK(Archive1->Close());
475 if (Archive0 != 0)
476 RINOK(Archive0->Close());
477 return S_OK;
478 }
479
480 void CArchiveLink::Release()
481 {
482 if (Archive1 != 0)
483 Archive1.Release();
484 if (Archive0 != 0)
485 Archive0.Release();
486 #ifndef EXCLUDE_COM
487 Library1.Free();
488 Library0.Free();
489 #endif
490 }
491
492 HRESULT OpenArchive(const UString &archiveName,
493 CArchiveLink &archiveLink,
494 IArchiveOpenCallback *openCallback)
495 {
496 return OpenArchive(archiveName,
497 #ifndef EXCLUDE_COM
498 &archiveLink.Library0, &archiveLink.Library1,
499 #endif
500 &archiveLink.Archive0, &archiveLink.Archive1,
501 archiveLink.ArchiverInfo0, archiveLink.ArchiverInfo1,
502 archiveLink.DefaultItemName0, archiveLink.DefaultItemName1,
503 openCallback);
504 }
505
506 HRESULT MyOpenArchive(const UString &archiveName,
507 CArchiveLink &archiveLink,
508 IOpenCallbackUI *openCallbackUI)
509 {
510 return MyOpenArchive(archiveName,
511 #ifndef EXCLUDE_COM
512 &archiveLink.Library0, &archiveLink.Library1,
513 #endif
514 &archiveLink.Archive0, &archiveLink.Archive1,
515 archiveLink.DefaultItemName0, archiveLink.DefaultItemName1,
516 archiveLink.VolumePaths,
517 openCallbackUI);
518 }
519
520 HRESULT ReOpenArchive(CArchiveLink &archiveLink,
521 const UString &fileName)
522 {
523 if (archiveLink.GetNumLevels() > 1)
524 return E_NOTIMPL;
525 if (archiveLink.GetNumLevels() == 0)
526 return MyOpenArchive(fileName, archiveLink, 0);
527 return ReOpenArchive(archiveLink.GetArchive(), fileName);
528 }

mercurial