michael@0: // 7zHandler.cpp michael@0: michael@0: #include "StdAfx.h" michael@0: michael@0: #include "7zHandler.h" michael@0: #include "7zProperties.h" michael@0: michael@0: #include "../../../Common/IntToString.h" michael@0: #include "../../../Common/ComTry.h" michael@0: #include "../../../Windows/Defs.h" michael@0: michael@0: #include "../Common/ItemNameUtils.h" michael@0: #ifdef _7Z_VOL michael@0: #include "../Common/MultiStream.h" michael@0: #endif michael@0: michael@0: #ifdef __7Z_SET_PROPERTIES michael@0: #ifdef EXTRACT_ONLY michael@0: #include "../Common/ParseProperties.h" michael@0: #endif michael@0: #endif michael@0: michael@0: using namespace NWindows; michael@0: michael@0: namespace NArchive { michael@0: namespace N7z { michael@0: michael@0: CHandler::CHandler() michael@0: { michael@0: #ifdef COMPRESS_MT michael@0: _numThreads = NWindows::NSystem::GetNumberOfProcessors(); michael@0: #endif michael@0: #ifndef EXTRACT_ONLY michael@0: Init(); michael@0: #endif michael@0: #ifndef EXCLUDE_COM michael@0: LoadMethodMap(); michael@0: #endif michael@0: } michael@0: michael@0: STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) michael@0: { michael@0: COM_TRY_BEGIN michael@0: *numItems = michael@0: #ifdef _7Z_VOL michael@0: _refs.Size(); michael@0: #else michael@0: *numItems = _database.Files.Size(); michael@0: #endif michael@0: return S_OK; michael@0: COM_TRY_END michael@0: } michael@0: michael@0: STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) michael@0: { michael@0: value->vt = VT_EMPTY; michael@0: return S_OK; michael@0: } michael@0: michael@0: #ifdef _SFX michael@0: michael@0: STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties) michael@0: { michael@0: return E_NOTIMPL; michael@0: } michael@0: michael@0: STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index, michael@0: BSTR *name, PROPID *propID, VARTYPE *varType) michael@0: { michael@0: return E_NOTIMPL; michael@0: } michael@0: michael@0: #endif michael@0: michael@0: michael@0: STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties) michael@0: { michael@0: *numProperties = 0; michael@0: return S_OK; michael@0: } michael@0: michael@0: STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32 index, michael@0: BSTR *name, PROPID *propID, VARTYPE *varType) michael@0: { michael@0: return E_NOTIMPL; michael@0: } michael@0: michael@0: michael@0: static void MySetFileTime(bool timeDefined, FILETIME unixTime, michael@0: NWindows::NCOM::CPropVariant &propVariant) michael@0: { michael@0: if (timeDefined) michael@0: propVariant = unixTime; michael@0: } michael@0: michael@0: /* michael@0: inline static wchar_t GetHex(Byte value) michael@0: { michael@0: return (value < 10) ? ('0' + value) : ('A' + (value - 10)); michael@0: } michael@0: michael@0: static UString ConvertBytesToHexString(const Byte *data, UInt32 size) michael@0: { michael@0: UString result; michael@0: for (UInt32 i = 0; i < size; i++) michael@0: { michael@0: Byte b = data[i]; michael@0: result += GetHex(b >> 4); michael@0: result += GetHex(b & 0xF); michael@0: } michael@0: return result; michael@0: } michael@0: */ michael@0: michael@0: michael@0: #ifndef _SFX michael@0: michael@0: static UString ConvertUInt32ToString(UInt32 value) michael@0: { michael@0: wchar_t buffer[32]; michael@0: ConvertUInt64ToString(value, buffer); michael@0: return buffer; michael@0: } michael@0: michael@0: static UString GetStringForSizeValue(UInt32 value) michael@0: { michael@0: for (int i = 31; i >= 0; i--) michael@0: if ((UInt32(1) << i) == value) michael@0: return ConvertUInt32ToString(i); michael@0: UString result; michael@0: if (value % (1 << 20) == 0) michael@0: { michael@0: result += ConvertUInt32ToString(value >> 20); michael@0: result += L"m"; michael@0: } michael@0: else if (value % (1 << 10) == 0) michael@0: { michael@0: result += ConvertUInt32ToString(value >> 10); michael@0: result += L"k"; michael@0: } michael@0: else michael@0: { michael@0: result += ConvertUInt32ToString(value); michael@0: result += L"b"; michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: static CMethodID k_Copy = { { 0x0 }, 1 }; michael@0: static CMethodID k_LZMA = { { 0x3, 0x1, 0x1 }, 3 }; michael@0: static CMethodID k_BCJ = { { 0x3, 0x3, 0x1, 0x3 }, 4 }; michael@0: static CMethodID k_BCJ2 = { { 0x3, 0x3, 0x1, 0x1B }, 4 }; michael@0: static CMethodID k_PPMD = { { 0x3, 0x4, 0x1 }, 3 }; michael@0: static CMethodID k_Deflate = { { 0x4, 0x1, 0x8 }, 3 }; michael@0: static CMethodID k_BZip2 = { { 0x4, 0x2, 0x2 }, 3 }; michael@0: michael@0: static inline char GetHex(Byte value) michael@0: { michael@0: return (value < 10) ? ('0' + value) : ('A' + (value - 10)); michael@0: } michael@0: static inline UString GetHex2(Byte value) michael@0: { michael@0: UString result; michael@0: result += GetHex(value >> 4); michael@0: result += GetHex(value & 0xF); michael@0: return result; michael@0: } michael@0: michael@0: #endif michael@0: michael@0: static inline UInt32 GetUInt32FromMemLE(const Byte *p) michael@0: { michael@0: return p[0] | (((UInt32)p[1]) << 8) | (((UInt32)p[2]) << 16) | (((UInt32)p[3]) << 24); michael@0: } michael@0: michael@0: STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) michael@0: { michael@0: COM_TRY_BEGIN michael@0: NWindows::NCOM::CPropVariant propVariant; michael@0: michael@0: /* michael@0: const CRef2 &ref2 = _refs[index]; michael@0: if (ref2.Refs.IsEmpty()) michael@0: return E_FAIL; michael@0: const CRef &ref = ref2.Refs.Front(); michael@0: */ michael@0: michael@0: #ifdef _7Z_VOL michael@0: const CRef &ref = _refs[index]; michael@0: const CVolume &volume = _volumes[ref.VolumeIndex]; michael@0: const CArchiveDatabaseEx &_database = volume.Database; michael@0: UInt32 index2 = ref.ItemIndex; michael@0: const CFileItem &item = _database.Files[index2]; michael@0: #else michael@0: const CFileItem &item = _database.Files[index]; michael@0: UInt32 index2 = index; michael@0: #endif michael@0: michael@0: switch(propID) michael@0: { michael@0: case kpidPath: michael@0: { michael@0: if (!item.Name.IsEmpty()) michael@0: propVariant = NItemName::GetOSName(item.Name); michael@0: break; michael@0: } michael@0: case kpidIsFolder: michael@0: propVariant = item.IsDirectory; michael@0: break; michael@0: case kpidSize: michael@0: { michael@0: propVariant = item.UnPackSize; michael@0: // propVariant = ref2.UnPackSize; michael@0: break; michael@0: } michael@0: case kpidPosition: michael@0: { michael@0: /* michael@0: if (ref2.Refs.Size() > 1) michael@0: propVariant = ref2.StartPos; michael@0: else michael@0: */ michael@0: if (item.IsStartPosDefined) michael@0: propVariant = item.StartPos; michael@0: break; michael@0: } michael@0: case kpidPackedSize: michael@0: { michael@0: // propVariant = ref2.PackSize; michael@0: { michael@0: CNum folderIndex = _database.FileIndexToFolderIndexMap[index2]; michael@0: if (folderIndex != kNumNoIndex) michael@0: { michael@0: if (_database.FolderStartFileIndex[folderIndex] == (CNum)index2) michael@0: propVariant = _database.GetFolderFullPackSize(folderIndex); michael@0: /* michael@0: else michael@0: propVariant = UInt64(0); michael@0: */ michael@0: } michael@0: else michael@0: propVariant = UInt64(0); michael@0: } michael@0: break; michael@0: } michael@0: case kpidLastAccessTime: michael@0: MySetFileTime(item.IsLastAccessTimeDefined, item.LastAccessTime, propVariant); michael@0: break; michael@0: case kpidCreationTime: michael@0: MySetFileTime(item.IsCreationTimeDefined, item.CreationTime, propVariant); michael@0: break; michael@0: case kpidLastWriteTime: michael@0: MySetFileTime(item.IsLastWriteTimeDefined, item.LastWriteTime, propVariant); michael@0: break; michael@0: case kpidAttributes: michael@0: if (item.AreAttributesDefined) michael@0: propVariant = item.Attributes; michael@0: break; michael@0: case kpidCRC: michael@0: if (item.IsFileCRCDefined) michael@0: propVariant = item.FileCRC; michael@0: break; michael@0: #ifndef _SFX michael@0: case kpidMethod: michael@0: { michael@0: CNum folderIndex = _database.FileIndexToFolderIndexMap[index2]; michael@0: if (folderIndex != kNumNoIndex) michael@0: { michael@0: const CFolder &folderInfo = _database.Folders[folderIndex]; michael@0: UString methodsString; michael@0: for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--) michael@0: { michael@0: const CCoderInfo &coderInfo = folderInfo.Coders[i]; michael@0: if (!methodsString.IsEmpty()) michael@0: methodsString += L' '; michael@0: CMethodInfo methodInfo; michael@0: michael@0: bool methodIsKnown; michael@0: michael@0: for (int j = 0; j < coderInfo.AltCoders.Size(); j++) michael@0: { michael@0: if (j > 0) michael@0: methodsString += L"|"; michael@0: const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders[j]; michael@0: michael@0: UString methodName; michael@0: #ifdef NO_REGISTRY michael@0: michael@0: methodIsKnown = true; michael@0: if (altCoderInfo.MethodID == k_Copy) michael@0: methodName = L"Copy"; michael@0: else if (altCoderInfo.MethodID == k_LZMA) michael@0: methodName = L"LZMA"; michael@0: else if (altCoderInfo.MethodID == k_BCJ) michael@0: methodName = L"BCJ"; michael@0: else if (altCoderInfo.MethodID == k_BCJ2) michael@0: methodName = L"BCJ2"; michael@0: else if (altCoderInfo.MethodID == k_PPMD) michael@0: methodName = L"PPMD"; michael@0: else if (altCoderInfo.MethodID == k_Deflate) michael@0: methodName = L"Deflate"; michael@0: else if (altCoderInfo.MethodID == k_BZip2) michael@0: methodName = L"BZip2"; michael@0: else michael@0: methodIsKnown = false; michael@0: michael@0: #else michael@0: michael@0: methodIsKnown = GetMethodInfo( michael@0: altCoderInfo.MethodID, methodInfo); michael@0: methodName = methodInfo.Name; michael@0: michael@0: #endif michael@0: michael@0: if (methodIsKnown) michael@0: { michael@0: methodsString += methodName; michael@0: if (altCoderInfo.MethodID == k_LZMA) michael@0: { michael@0: if (altCoderInfo.Properties.GetCapacity() >= 5) michael@0: { michael@0: methodsString += L":"; michael@0: UInt32 dicSize = GetUInt32FromMemLE( michael@0: ((const Byte *)altCoderInfo.Properties + 1)); michael@0: methodsString += GetStringForSizeValue(dicSize); michael@0: } michael@0: } michael@0: else if (altCoderInfo.MethodID == k_PPMD) michael@0: { michael@0: if (altCoderInfo.Properties.GetCapacity() >= 5) michael@0: { michael@0: Byte order = *(const Byte *)altCoderInfo.Properties; michael@0: methodsString += L":o"; michael@0: methodsString += ConvertUInt32ToString(order); michael@0: methodsString += L":mem"; michael@0: UInt32 dicSize = GetUInt32FromMemLE( michael@0: ((const Byte *)altCoderInfo.Properties + 1)); michael@0: methodsString += GetStringForSizeValue(dicSize); michael@0: } michael@0: } michael@0: else michael@0: { michael@0: if (altCoderInfo.Properties.GetCapacity() > 0) michael@0: { michael@0: methodsString += L":["; michael@0: for (size_t bi = 0; bi < altCoderInfo.Properties.GetCapacity(); bi++) michael@0: { michael@0: if (bi > 2 && bi + 1 < altCoderInfo.Properties.GetCapacity()) michael@0: { michael@0: methodsString += L".."; michael@0: break; michael@0: } michael@0: else michael@0: methodsString += GetHex2(altCoderInfo.Properties[bi]); michael@0: } michael@0: methodsString += L"]"; michael@0: } michael@0: } michael@0: } michael@0: else michael@0: { michael@0: methodsString += altCoderInfo.MethodID.ConvertToString(); michael@0: } michael@0: } michael@0: } michael@0: propVariant = methodsString; michael@0: } michael@0: } michael@0: break; michael@0: case kpidBlock: michael@0: { michael@0: CNum folderIndex = _database.FileIndexToFolderIndexMap[index2]; michael@0: if (folderIndex != kNumNoIndex) michael@0: propVariant = (UInt32)folderIndex; michael@0: } michael@0: break; michael@0: case kpidPackedSize0: michael@0: case kpidPackedSize1: michael@0: case kpidPackedSize2: michael@0: case kpidPackedSize3: michael@0: case kpidPackedSize4: michael@0: { michael@0: CNum folderIndex = _database.FileIndexToFolderIndexMap[index2]; michael@0: if (folderIndex != kNumNoIndex) michael@0: { michael@0: const CFolder &folderInfo = _database.Folders[folderIndex]; michael@0: if (_database.FolderStartFileIndex[folderIndex] == (CNum)index2 && michael@0: folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0)) michael@0: { michael@0: propVariant = _database.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0); michael@0: } michael@0: else michael@0: propVariant = UInt64(0); michael@0: } michael@0: else michael@0: propVariant = UInt64(0); michael@0: } michael@0: break; michael@0: #endif michael@0: case kpidIsAnti: michael@0: propVariant = item.IsAnti; michael@0: break; michael@0: } michael@0: propVariant.Detach(value); michael@0: return S_OK; michael@0: COM_TRY_END michael@0: } michael@0: michael@0: static const wchar_t *kExt = L"7z"; michael@0: static const wchar_t *kAfterPart = L".7z"; michael@0: michael@0: #ifdef _7Z_VOL michael@0: michael@0: class CVolumeName michael@0: { michael@0: bool _first; michael@0: UString _unchangedPart; michael@0: UString _changedPart; michael@0: UString _afterPart; michael@0: public: michael@0: bool InitName(const UString &name) michael@0: { michael@0: _first = true; michael@0: int dotPos = name.ReverseFind('.'); michael@0: UString basePart = name; michael@0: if (dotPos >= 0) michael@0: { michael@0: UString ext = name.Mid(dotPos + 1); michael@0: if (ext.CompareNoCase(kExt)==0 || michael@0: ext.CompareNoCase(L"EXE") == 0) michael@0: { michael@0: _afterPart = kAfterPart; michael@0: basePart = name.Left(dotPos); michael@0: } michael@0: } michael@0: michael@0: int numLetters = 1; michael@0: bool splitStyle = false; michael@0: if (basePart.Right(numLetters) == L"1") michael@0: { michael@0: while (numLetters < basePart.Length()) michael@0: { michael@0: if (basePart[basePart.Length() - numLetters - 1] != '0') michael@0: break; michael@0: numLetters++; michael@0: } michael@0: } michael@0: else michael@0: return false; michael@0: _unchangedPart = basePart.Left(basePart.Length() - numLetters); michael@0: _changedPart = basePart.Right(numLetters); michael@0: return true; michael@0: } michael@0: michael@0: UString GetNextName() michael@0: { michael@0: UString newName; michael@0: // if (_newStyle || !_first) michael@0: { michael@0: int i; michael@0: int numLetters = _changedPart.Length(); michael@0: for (i = numLetters - 1; i >= 0; i--) michael@0: { michael@0: wchar_t c = _changedPart[i]; michael@0: if (c == L'9') michael@0: { michael@0: c = L'0'; michael@0: newName = c + newName; michael@0: if (i == 0) michael@0: newName = UString(L'1') + newName; michael@0: continue; michael@0: } michael@0: c++; michael@0: newName = UString(c) + newName; michael@0: i--; michael@0: for (; i >= 0; i--) michael@0: newName = _changedPart[i] + newName; michael@0: break; michael@0: } michael@0: _changedPart = newName; michael@0: } michael@0: _first = false; michael@0: return _unchangedPart + _changedPart + _afterPart; michael@0: } michael@0: }; michael@0: michael@0: #endif michael@0: michael@0: STDMETHODIMP CHandler::Open(IInStream *stream, michael@0: const UInt64 *maxCheckStartPosition, michael@0: IArchiveOpenCallback *openArchiveCallback) michael@0: { michael@0: COM_TRY_BEGIN michael@0: Close(); michael@0: #ifndef _SFX michael@0: _fileInfoPopIDs.Clear(); michael@0: #endif michael@0: try michael@0: { michael@0: CMyComPtr openArchiveCallbackTemp = openArchiveCallback; michael@0: #ifdef _7Z_VOL michael@0: CVolumeName seqName; michael@0: michael@0: CMyComPtr openVolumeCallback; michael@0: #endif michael@0: michael@0: #ifndef _NO_CRYPTO michael@0: CMyComPtr getTextPassword; michael@0: if (openArchiveCallback) michael@0: { michael@0: openArchiveCallbackTemp.QueryInterface( michael@0: IID_ICryptoGetTextPassword, &getTextPassword); michael@0: } michael@0: #endif michael@0: #ifdef _7Z_VOL michael@0: if (openArchiveCallback) michael@0: { michael@0: openArchiveCallbackTemp.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback); michael@0: } michael@0: while(true) michael@0: { michael@0: CMyComPtr inStream; michael@0: if (!_volumes.IsEmpty()) michael@0: { michael@0: if (!openVolumeCallback) michael@0: break; michael@0: if(_volumes.Size() == 1) michael@0: { michael@0: UString baseName; michael@0: { michael@0: NCOM::CPropVariant propVariant; michael@0: RINOK(openVolumeCallback->GetProperty(kpidName, &propVariant)); michael@0: if (propVariant.vt != VT_BSTR) michael@0: break; michael@0: baseName = propVariant.bstrVal; michael@0: } michael@0: seqName.InitName(baseName); michael@0: } michael@0: michael@0: UString fullName = seqName.GetNextName(); michael@0: HRESULT result = openVolumeCallback->GetStream(fullName, &inStream); michael@0: if (result == S_FALSE) michael@0: break; michael@0: if (result != S_OK) michael@0: return result; michael@0: if (!stream) michael@0: break; michael@0: } michael@0: else michael@0: inStream = stream; michael@0: michael@0: CInArchive archive; michael@0: RINOK(archive.Open(inStream, maxCheckStartPosition)); michael@0: michael@0: _volumes.Add(CVolume()); michael@0: CVolume &volume = _volumes.Back(); michael@0: CArchiveDatabaseEx &database = volume.Database; michael@0: volume.Stream = inStream; michael@0: volume.StartRef2Index = _refs.Size(); michael@0: michael@0: HRESULT result = archive.ReadDatabase(database michael@0: #ifndef _NO_CRYPTO michael@0: , getTextPassword michael@0: #endif michael@0: ); michael@0: if (result != S_OK) michael@0: { michael@0: _volumes.Clear(); michael@0: return result; michael@0: } michael@0: database.Fill(); michael@0: for(int i = 0; i < database.Files.Size(); i++) michael@0: { michael@0: CRef refNew; michael@0: refNew.VolumeIndex = _volumes.Size() - 1; michael@0: refNew.ItemIndex = i; michael@0: _refs.Add(refNew); michael@0: /* michael@0: const CFileItem &file = database.Files[i]; michael@0: int j; michael@0: */ michael@0: /* michael@0: for (j = _refs.Size() - 1; j >= 0; j--) michael@0: { michael@0: CRef2 &ref2 = _refs[j]; michael@0: const CRef &ref = ref2.Refs.Back(); michael@0: const CVolume &volume2 = _volumes[ref.VolumeIndex]; michael@0: const CArchiveDatabaseEx &database2 = volume2.Database; michael@0: const CFileItem &file2 = database2.Files[ref.ItemIndex]; michael@0: if (file2.Name.CompareNoCase(file.Name) == 0) michael@0: { michael@0: if (!file.IsStartPosDefined) michael@0: continue; michael@0: if (file.StartPos != ref2.StartPos + ref2.UnPackSize) michael@0: continue; michael@0: ref2.Refs.Add(refNew); michael@0: break; michael@0: } michael@0: } michael@0: */ michael@0: /* michael@0: j = -1; michael@0: if (j < 0) michael@0: { michael@0: CRef2 ref2New; michael@0: ref2New.Refs.Add(refNew); michael@0: j = _refs.Add(ref2New); michael@0: } michael@0: CRef2 &ref2 = _refs[j]; michael@0: ref2.UnPackSize += file.UnPackSize; michael@0: ref2.PackSize += database.GetFilePackSize(i); michael@0: if (ref2.Refs.Size() == 1 && file.IsStartPosDefined) michael@0: ref2.StartPos = file.StartPos; michael@0: */ michael@0: } michael@0: if (database.Files.Size() != 1) michael@0: break; michael@0: const CFileItem &file = database.Files.Front(); michael@0: if (!file.IsStartPosDefined) michael@0: break; michael@0: } michael@0: #else michael@0: CInArchive archive; michael@0: RINOK(archive.Open(stream, maxCheckStartPosition)); michael@0: HRESULT result = archive.ReadDatabase(_database michael@0: #ifndef _NO_CRYPTO michael@0: , getTextPassword michael@0: #endif michael@0: ); michael@0: RINOK(result); michael@0: _database.Fill(); michael@0: _inStream = stream; michael@0: #endif michael@0: } michael@0: catch(...) michael@0: { michael@0: Close(); michael@0: return S_FALSE; michael@0: } michael@0: // _inStream = stream; michael@0: #ifndef _SFX michael@0: FillPopIDs(); michael@0: #endif michael@0: return S_OK; michael@0: COM_TRY_END michael@0: } michael@0: michael@0: STDMETHODIMP CHandler::Close() michael@0: { michael@0: COM_TRY_BEGIN michael@0: #ifdef _7Z_VOL michael@0: _volumes.Clear(); michael@0: _refs.Clear(); michael@0: #else michael@0: _inStream.Release(); michael@0: _database.Clear(); michael@0: #endif michael@0: return S_OK; michael@0: COM_TRY_END michael@0: } michael@0: michael@0: #ifdef _7Z_VOL michael@0: STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) michael@0: { michael@0: if (index != 0) michael@0: return E_INVALIDARG; michael@0: *stream = 0; michael@0: CMultiStream *streamSpec = new CMultiStream; michael@0: CMyComPtr streamTemp = streamSpec; michael@0: michael@0: UInt64 pos = 0; michael@0: const UString *fileName; michael@0: for (int i = 0; i < _refs.Size(); i++) michael@0: { michael@0: const CRef &ref = _refs[i]; michael@0: const CVolume &volume = _volumes[ref.VolumeIndex]; michael@0: const CArchiveDatabaseEx &database = volume.Database; michael@0: const CFileItem &file = database.Files[ref.ItemIndex]; michael@0: if (i == 0) michael@0: fileName = &file.Name; michael@0: else michael@0: if (fileName->Compare(file.Name) != 0) michael@0: return S_FALSE; michael@0: if (!file.IsStartPosDefined) michael@0: return S_FALSE; michael@0: if (file.StartPos != pos) michael@0: return S_FALSE; michael@0: CNum folderIndex = database.FileIndexToFolderIndexMap[ref.ItemIndex]; michael@0: if (folderIndex == kNumNoIndex) michael@0: { michael@0: if (file.UnPackSize != 0) michael@0: return E_FAIL; michael@0: continue; michael@0: } michael@0: if (database.NumUnPackStreamsVector[folderIndex] != 1) michael@0: return S_FALSE; michael@0: const CFolder &folder = database.Folders[folderIndex]; michael@0: if (folder.Coders.Size() != 1) michael@0: return S_FALSE; michael@0: const CCoderInfo &coder = folder.Coders.Front(); michael@0: if (coder.NumInStreams != 1 || coder.NumOutStreams != 1) michael@0: return S_FALSE; michael@0: const CAltCoderInfo &altCoder = coder.AltCoders.Front(); michael@0: if (altCoder.MethodID.IDSize != 1 || altCoder.MethodID.ID[0] != 0) michael@0: return S_FALSE; michael@0: michael@0: pos += file.UnPackSize; michael@0: CMultiStream::CSubStreamInfo subStreamInfo; michael@0: subStreamInfo.Stream = volume.Stream; michael@0: subStreamInfo.Pos = database.GetFolderStreamPos(folderIndex, 0); michael@0: subStreamInfo.Size = file.UnPackSize; michael@0: streamSpec->Streams.Add(subStreamInfo); michael@0: } michael@0: streamSpec->Init(); michael@0: *stream = streamTemp.Detach(); michael@0: return S_OK; michael@0: } michael@0: #endif michael@0: michael@0: michael@0: #ifdef __7Z_SET_PROPERTIES michael@0: #ifdef EXTRACT_ONLY michael@0: michael@0: STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties) michael@0: { michael@0: COM_TRY_BEGIN michael@0: const UInt32 numProcessors = NSystem::GetNumberOfProcessors(); michael@0: _numThreads = numProcessors; michael@0: michael@0: for (int i = 0; i < numProperties; i++) michael@0: { michael@0: UString name = names[i]; michael@0: name.MakeUpper(); michael@0: if (name.IsEmpty()) michael@0: return E_INVALIDARG; michael@0: const PROPVARIANT &value = values[i]; michael@0: UInt32 number; michael@0: int index = ParseStringToUInt32(name, number); michael@0: if (index == 0) michael@0: { michael@0: if(name.Left(2).CompareNoCase(L"MT") == 0) michael@0: { michael@0: RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads)); michael@0: continue; michael@0: } michael@0: else michael@0: return E_INVALIDARG; michael@0: } michael@0: } michael@0: return S_OK; michael@0: COM_TRY_END michael@0: } michael@0: michael@0: #endif michael@0: #endif michael@0: michael@0: }}