Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / other-licenses / 7zstub / src / 7zip / Archive / 7z / 7zHandler.cpp
blobb6f492aea8b8419280f6a4fbb4c947ab57dd9771
1 // 7zHandler.cpp
3 #include "StdAfx.h"
5 #include "7zHandler.h"
6 #include "7zProperties.h"
8 #include "../../../Common/IntToString.h"
9 #include "../../../Common/ComTry.h"
10 #include "../../../Windows/Defs.h"
12 #include "../Common/ItemNameUtils.h"
13 #ifdef _7Z_VOL
14 #include "../Common/MultiStream.h"
15 #endif
17 #ifdef __7Z_SET_PROPERTIES
18 #ifdef EXTRACT_ONLY
19 #include "../Common/ParseProperties.h"
20 #endif
21 #endif
23 using namespace NWindows;
25 namespace NArchive {
26 namespace N7z {
28 CHandler::CHandler()
30 #ifdef COMPRESS_MT
31 _numThreads = NWindows::NSystem::GetNumberOfProcessors();
32 #endif
33 #ifndef EXTRACT_ONLY
34 Init();
35 #endif
36 #ifndef EXCLUDE_COM
37 LoadMethodMap();
38 #endif
41 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
43 COM_TRY_BEGIN
44 *numItems =
45 #ifdef _7Z_VOL
46 _refs.Size();
47 #else
48 *numItems = _database.Files.Size();
49 #endif
50 return S_OK;
51 COM_TRY_END
54 STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
56 value->vt = VT_EMPTY;
57 return S_OK;
60 #ifdef _SFX
62 STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties)
64 return E_NOTIMPL;
67 STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index,
68 BSTR *name, PROPID *propID, VARTYPE *varType)
70 return E_NOTIMPL;
73 #endif
76 STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties)
78 *numProperties = 0;
79 return S_OK;
82 STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32 index,
83 BSTR *name, PROPID *propID, VARTYPE *varType)
85 return E_NOTIMPL;
89 static void MySetFileTime(bool timeDefined, FILETIME unixTime,
90 NWindows::NCOM::CPropVariant &propVariant)
92 if (timeDefined)
93 propVariant = unixTime;
97 inline static wchar_t GetHex(Byte value)
99 return (value < 10) ? ('0' + value) : ('A' + (value - 10));
102 static UString ConvertBytesToHexString(const Byte *data, UInt32 size)
104 UString result;
105 for (UInt32 i = 0; i < size; i++)
107 Byte b = data[i];
108 result += GetHex(b >> 4);
109 result += GetHex(b & 0xF);
111 return result;
116 #ifndef _SFX
118 static UString ConvertUInt32ToString(UInt32 value)
120 wchar_t buffer[32];
121 ConvertUInt64ToString(value, buffer);
122 return buffer;
125 static UString GetStringForSizeValue(UInt32 value)
127 for (int i = 31; i >= 0; i--)
128 if ((UInt32(1) << i) == value)
129 return ConvertUInt32ToString(i);
130 UString result;
131 if (value % (1 << 20) == 0)
133 result += ConvertUInt32ToString(value >> 20);
134 result += L"m";
136 else if (value % (1 << 10) == 0)
138 result += ConvertUInt32ToString(value >> 10);
139 result += L"k";
141 else
143 result += ConvertUInt32ToString(value);
144 result += L"b";
146 return result;
149 static CMethodID k_Copy = { { 0x0 }, 1 };
150 static CMethodID k_LZMA = { { 0x3, 0x1, 0x1 }, 3 };
151 static CMethodID k_BCJ = { { 0x3, 0x3, 0x1, 0x3 }, 4 };
152 static CMethodID k_BCJ2 = { { 0x3, 0x3, 0x1, 0x1B }, 4 };
153 static CMethodID k_PPMD = { { 0x3, 0x4, 0x1 }, 3 };
154 static CMethodID k_Deflate = { { 0x4, 0x1, 0x8 }, 3 };
155 static CMethodID k_BZip2 = { { 0x4, 0x2, 0x2 }, 3 };
157 static inline char GetHex(Byte value)
159 return (value < 10) ? ('0' + value) : ('A' + (value - 10));
161 static inline UString GetHex2(Byte value)
163 UString result;
164 result += GetHex(value >> 4);
165 result += GetHex(value & 0xF);
166 return result;
169 #endif
171 static inline UInt32 GetUInt32FromMemLE(const Byte *p)
173 return p[0] | (((UInt32)p[1]) << 8) | (((UInt32)p[2]) << 16) | (((UInt32)p[3]) << 24);
176 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
178 COM_TRY_BEGIN
179 NWindows::NCOM::CPropVariant propVariant;
182 const CRef2 &ref2 = _refs[index];
183 if (ref2.Refs.IsEmpty())
184 return E_FAIL;
185 const CRef &ref = ref2.Refs.Front();
188 #ifdef _7Z_VOL
189 const CRef &ref = _refs[index];
190 const CVolume &volume = _volumes[ref.VolumeIndex];
191 const CArchiveDatabaseEx &_database = volume.Database;
192 UInt32 index2 = ref.ItemIndex;
193 const CFileItem &item = _database.Files[index2];
194 #else
195 const CFileItem &item = _database.Files[index];
196 UInt32 index2 = index;
197 #endif
199 switch(propID)
201 case kpidPath:
203 if (!item.Name.IsEmpty())
204 propVariant = NItemName::GetOSName(item.Name);
205 break;
207 case kpidIsFolder:
208 propVariant = item.IsDirectory;
209 break;
210 case kpidSize:
212 propVariant = item.UnPackSize;
213 // propVariant = ref2.UnPackSize;
214 break;
216 case kpidPosition:
219 if (ref2.Refs.Size() > 1)
220 propVariant = ref2.StartPos;
221 else
223 if (item.IsStartPosDefined)
224 propVariant = item.StartPos;
225 break;
227 case kpidPackedSize:
229 // propVariant = ref2.PackSize;
231 CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
232 if (folderIndex != kNumNoIndex)
234 if (_database.FolderStartFileIndex[folderIndex] == (CNum)index2)
235 propVariant = _database.GetFolderFullPackSize(folderIndex);
237 else
238 propVariant = UInt64(0);
241 else
242 propVariant = UInt64(0);
244 break;
246 case kpidLastAccessTime:
247 MySetFileTime(item.IsLastAccessTimeDefined, item.LastAccessTime, propVariant);
248 break;
249 case kpidCreationTime:
250 MySetFileTime(item.IsCreationTimeDefined, item.CreationTime, propVariant);
251 break;
252 case kpidLastWriteTime:
253 MySetFileTime(item.IsLastWriteTimeDefined, item.LastWriteTime, propVariant);
254 break;
255 case kpidAttributes:
256 if (item.AreAttributesDefined)
257 propVariant = item.Attributes;
258 break;
259 case kpidCRC:
260 if (item.IsFileCRCDefined)
261 propVariant = item.FileCRC;
262 break;
263 #ifndef _SFX
264 case kpidMethod:
266 CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
267 if (folderIndex != kNumNoIndex)
269 const CFolder &folderInfo = _database.Folders[folderIndex];
270 UString methodsString;
271 for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--)
273 const CCoderInfo &coderInfo = folderInfo.Coders[i];
274 if (!methodsString.IsEmpty())
275 methodsString += L' ';
276 CMethodInfo methodInfo;
278 bool methodIsKnown;
280 for (int j = 0; j < coderInfo.AltCoders.Size(); j++)
282 if (j > 0)
283 methodsString += L"|";
284 const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders[j];
286 UString methodName;
287 #ifdef NO_REGISTRY
289 methodIsKnown = true;
290 if (altCoderInfo.MethodID == k_Copy)
291 methodName = L"Copy";
292 else if (altCoderInfo.MethodID == k_LZMA)
293 methodName = L"LZMA";
294 else if (altCoderInfo.MethodID == k_BCJ)
295 methodName = L"BCJ";
296 else if (altCoderInfo.MethodID == k_BCJ2)
297 methodName = L"BCJ2";
298 else if (altCoderInfo.MethodID == k_PPMD)
299 methodName = L"PPMD";
300 else if (altCoderInfo.MethodID == k_Deflate)
301 methodName = L"Deflate";
302 else if (altCoderInfo.MethodID == k_BZip2)
303 methodName = L"BZip2";
304 else
305 methodIsKnown = false;
307 #else
309 methodIsKnown = GetMethodInfo(
310 altCoderInfo.MethodID, methodInfo);
311 methodName = methodInfo.Name;
313 #endif
315 if (methodIsKnown)
317 methodsString += methodName;
318 if (altCoderInfo.MethodID == k_LZMA)
320 if (altCoderInfo.Properties.GetCapacity() >= 5)
322 methodsString += L":";
323 UInt32 dicSize = GetUInt32FromMemLE(
324 ((const Byte *)altCoderInfo.Properties + 1));
325 methodsString += GetStringForSizeValue(dicSize);
328 else if (altCoderInfo.MethodID == k_PPMD)
330 if (altCoderInfo.Properties.GetCapacity() >= 5)
332 Byte order = *(const Byte *)altCoderInfo.Properties;
333 methodsString += L":o";
334 methodsString += ConvertUInt32ToString(order);
335 methodsString += L":mem";
336 UInt32 dicSize = GetUInt32FromMemLE(
337 ((const Byte *)altCoderInfo.Properties + 1));
338 methodsString += GetStringForSizeValue(dicSize);
341 else
343 if (altCoderInfo.Properties.GetCapacity() > 0)
345 methodsString += L":[";
346 for (size_t bi = 0; bi < altCoderInfo.Properties.GetCapacity(); bi++)
348 if (bi > 2 && bi + 1 < altCoderInfo.Properties.GetCapacity())
350 methodsString += L"..";
351 break;
353 else
354 methodsString += GetHex2(altCoderInfo.Properties[bi]);
356 methodsString += L"]";
360 else
362 methodsString += altCoderInfo.MethodID.ConvertToString();
366 propVariant = methodsString;
369 break;
370 case kpidBlock:
372 CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
373 if (folderIndex != kNumNoIndex)
374 propVariant = (UInt32)folderIndex;
376 break;
377 case kpidPackedSize0:
378 case kpidPackedSize1:
379 case kpidPackedSize2:
380 case kpidPackedSize3:
381 case kpidPackedSize4:
383 CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
384 if (folderIndex != kNumNoIndex)
386 const CFolder &folderInfo = _database.Folders[folderIndex];
387 if (_database.FolderStartFileIndex[folderIndex] == (CNum)index2 &&
388 folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0))
390 propVariant = _database.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0);
392 else
393 propVariant = UInt64(0);
395 else
396 propVariant = UInt64(0);
398 break;
399 #endif
400 case kpidIsAnti:
401 propVariant = item.IsAnti;
402 break;
404 propVariant.Detach(value);
405 return S_OK;
406 COM_TRY_END
409 static const wchar_t *kExt = L"7z";
410 static const wchar_t *kAfterPart = L".7z";
412 #ifdef _7Z_VOL
414 class CVolumeName
416 bool _first;
417 UString _unchangedPart;
418 UString _changedPart;
419 UString _afterPart;
420 public:
421 bool InitName(const UString &name)
423 _first = true;
424 int dotPos = name.ReverseFind('.');
425 UString basePart = name;
426 if (dotPos >= 0)
428 UString ext = name.Mid(dotPos + 1);
429 if (ext.CompareNoCase(kExt)==0 ||
430 ext.CompareNoCase(L"EXE") == 0)
432 _afterPart = kAfterPart;
433 basePart = name.Left(dotPos);
437 int numLetters = 1;
438 bool splitStyle = false;
439 if (basePart.Right(numLetters) == L"1")
441 while (numLetters < basePart.Length())
443 if (basePart[basePart.Length() - numLetters - 1] != '0')
444 break;
445 numLetters++;
448 else
449 return false;
450 _unchangedPart = basePart.Left(basePart.Length() - numLetters);
451 _changedPart = basePart.Right(numLetters);
452 return true;
455 UString GetNextName()
457 UString newName;
458 // if (_newStyle || !_first)
460 int i;
461 int numLetters = _changedPart.Length();
462 for (i = numLetters - 1; i >= 0; i--)
464 wchar_t c = _changedPart[i];
465 if (c == L'9')
467 c = L'0';
468 newName = c + newName;
469 if (i == 0)
470 newName = UString(L'1') + newName;
471 continue;
473 c++;
474 newName = UString(c) + newName;
475 i--;
476 for (; i >= 0; i--)
477 newName = _changedPart[i] + newName;
478 break;
480 _changedPart = newName;
482 _first = false;
483 return _unchangedPart + _changedPart + _afterPart;
487 #endif
489 STDMETHODIMP CHandler::Open(IInStream *stream,
490 const UInt64 *maxCheckStartPosition,
491 IArchiveOpenCallback *openArchiveCallback)
493 COM_TRY_BEGIN
494 Close();
495 #ifndef _SFX
496 _fileInfoPopIDs.Clear();
497 #endif
500 CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback;
501 #ifdef _7Z_VOL
502 CVolumeName seqName;
504 CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
505 #endif
507 #ifndef _NO_CRYPTO
508 CMyComPtr<ICryptoGetTextPassword> getTextPassword;
509 if (openArchiveCallback)
511 openArchiveCallbackTemp.QueryInterface(
512 IID_ICryptoGetTextPassword, &getTextPassword);
514 #endif
515 #ifdef _7Z_VOL
516 if (openArchiveCallback)
518 openArchiveCallbackTemp.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback);
520 while(true)
522 CMyComPtr<IInStream> inStream;
523 if (!_volumes.IsEmpty())
525 if (!openVolumeCallback)
526 break;
527 if(_volumes.Size() == 1)
529 UString baseName;
531 NCOM::CPropVariant propVariant;
532 RINOK(openVolumeCallback->GetProperty(kpidName, &propVariant));
533 if (propVariant.vt != VT_BSTR)
534 break;
535 baseName = propVariant.bstrVal;
537 seqName.InitName(baseName);
540 UString fullName = seqName.GetNextName();
541 HRESULT result = openVolumeCallback->GetStream(fullName, &inStream);
542 if (result == S_FALSE)
543 break;
544 if (result != S_OK)
545 return result;
546 if (!stream)
547 break;
549 else
550 inStream = stream;
552 CInArchive archive;
553 RINOK(archive.Open(inStream, maxCheckStartPosition));
555 _volumes.Add(CVolume());
556 CVolume &volume = _volumes.Back();
557 CArchiveDatabaseEx &database = volume.Database;
558 volume.Stream = inStream;
559 volume.StartRef2Index = _refs.Size();
561 HRESULT result = archive.ReadDatabase(database
562 #ifndef _NO_CRYPTO
563 , getTextPassword
564 #endif
566 if (result != S_OK)
568 _volumes.Clear();
569 return result;
571 database.Fill();
572 for(int i = 0; i < database.Files.Size(); i++)
574 CRef refNew;
575 refNew.VolumeIndex = _volumes.Size() - 1;
576 refNew.ItemIndex = i;
577 _refs.Add(refNew);
579 const CFileItem &file = database.Files[i];
580 int j;
583 for (j = _refs.Size() - 1; j >= 0; j--)
585 CRef2 &ref2 = _refs[j];
586 const CRef &ref = ref2.Refs.Back();
587 const CVolume &volume2 = _volumes[ref.VolumeIndex];
588 const CArchiveDatabaseEx &database2 = volume2.Database;
589 const CFileItem &file2 = database2.Files[ref.ItemIndex];
590 if (file2.Name.CompareNoCase(file.Name) == 0)
592 if (!file.IsStartPosDefined)
593 continue;
594 if (file.StartPos != ref2.StartPos + ref2.UnPackSize)
595 continue;
596 ref2.Refs.Add(refNew);
597 break;
602 j = -1;
603 if (j < 0)
605 CRef2 ref2New;
606 ref2New.Refs.Add(refNew);
607 j = _refs.Add(ref2New);
609 CRef2 &ref2 = _refs[j];
610 ref2.UnPackSize += file.UnPackSize;
611 ref2.PackSize += database.GetFilePackSize(i);
612 if (ref2.Refs.Size() == 1 && file.IsStartPosDefined)
613 ref2.StartPos = file.StartPos;
616 if (database.Files.Size() != 1)
617 break;
618 const CFileItem &file = database.Files.Front();
619 if (!file.IsStartPosDefined)
620 break;
622 #else
623 CInArchive archive;
624 RINOK(archive.Open(stream, maxCheckStartPosition));
625 HRESULT result = archive.ReadDatabase(_database
626 #ifndef _NO_CRYPTO
627 , getTextPassword
628 #endif
630 RINOK(result);
631 _database.Fill();
632 _inStream = stream;
633 #endif
635 catch(...)
637 Close();
638 return S_FALSE;
640 // _inStream = stream;
641 #ifndef _SFX
642 FillPopIDs();
643 #endif
644 return S_OK;
645 COM_TRY_END
648 STDMETHODIMP CHandler::Close()
650 COM_TRY_BEGIN
651 #ifdef _7Z_VOL
652 _volumes.Clear();
653 _refs.Clear();
654 #else
655 _inStream.Release();
656 _database.Clear();
657 #endif
658 return S_OK;
659 COM_TRY_END
662 #ifdef _7Z_VOL
663 STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
665 if (index != 0)
666 return E_INVALIDARG;
667 *stream = 0;
668 CMultiStream *streamSpec = new CMultiStream;
669 CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
671 UInt64 pos = 0;
672 const UString *fileName;
673 for (int i = 0; i < _refs.Size(); i++)
675 const CRef &ref = _refs[i];
676 const CVolume &volume = _volumes[ref.VolumeIndex];
677 const CArchiveDatabaseEx &database = volume.Database;
678 const CFileItem &file = database.Files[ref.ItemIndex];
679 if (i == 0)
680 fileName = &file.Name;
681 else
682 if (fileName->Compare(file.Name) != 0)
683 return S_FALSE;
684 if (!file.IsStartPosDefined)
685 return S_FALSE;
686 if (file.StartPos != pos)
687 return S_FALSE;
688 CNum folderIndex = database.FileIndexToFolderIndexMap[ref.ItemIndex];
689 if (folderIndex == kNumNoIndex)
691 if (file.UnPackSize != 0)
692 return E_FAIL;
693 continue;
695 if (database.NumUnPackStreamsVector[folderIndex] != 1)
696 return S_FALSE;
697 const CFolder &folder = database.Folders[folderIndex];
698 if (folder.Coders.Size() != 1)
699 return S_FALSE;
700 const CCoderInfo &coder = folder.Coders.Front();
701 if (coder.NumInStreams != 1 || coder.NumOutStreams != 1)
702 return S_FALSE;
703 const CAltCoderInfo &altCoder = coder.AltCoders.Front();
704 if (altCoder.MethodID.IDSize != 1 || altCoder.MethodID.ID[0] != 0)
705 return S_FALSE;
707 pos += file.UnPackSize;
708 CMultiStream::CSubStreamInfo subStreamInfo;
709 subStreamInfo.Stream = volume.Stream;
710 subStreamInfo.Pos = database.GetFolderStreamPos(folderIndex, 0);
711 subStreamInfo.Size = file.UnPackSize;
712 streamSpec->Streams.Add(subStreamInfo);
714 streamSpec->Init();
715 *stream = streamTemp.Detach();
716 return S_OK;
718 #endif
721 #ifdef __7Z_SET_PROPERTIES
722 #ifdef EXTRACT_ONLY
724 STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
726 COM_TRY_BEGIN
727 const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
728 _numThreads = numProcessors;
730 for (int i = 0; i < numProperties; i++)
732 UString name = names[i];
733 name.MakeUpper();
734 if (name.IsEmpty())
735 return E_INVALIDARG;
736 const PROPVARIANT &value = values[i];
737 UInt32 number;
738 int index = ParseStringToUInt32(name, number);
739 if (index == 0)
741 if(name.Left(2).CompareNoCase(L"MT") == 0)
743 RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
744 continue;
746 else
747 return E_INVALIDARG;
750 return S_OK;
751 COM_TRY_END
754 #endif
755 #endif