bool InitName(const UString &name, bool newStyle) { _first = true; _newStyle = newStyle; int dotPos = name.ReverseFind('.'); UString basePart = name; if (dotPos >= 0) { UString ext = name.Mid(dotPos + 1); if (ext.CompareNoCase(L"rar") == 0) { _afterPart = name.Mid(dotPos); basePart = name.Left(dotPos); } else if (ext.CompareNoCase(L"exe") == 0) { _afterPart = L".rar"; basePart = name.Left(dotPos); } else if (!_newStyle) { if (ext.CompareNoCase(L"000") == 0 || ext.CompareNoCase(L"001") == 0 || ext.CompareNoCase(L"r00") == 0 || ext.CompareNoCase(L"r01") == 0) { _afterPart.Empty(); _first = false; _changedPart = ext; _unchangedPart = name.Left(dotPos + 1); return true; } } } if (!_newStyle) { _afterPart.Empty(); _unchangedPart = basePart + UString(L"."); _changedPart = L"r00"; return true; } int numLetters = 1; if (basePart.Right(numLetters) == L"1" || basePart.Right(numLetters) == L"0") { while (numLetters < basePart.Length()) { if (basePart[basePart.Length() - numLetters - 1] != '0') break; numLetters++; } } else return false; _unchangedPart = basePart.Left(basePart.Length() - numLetters); _changedPart = basePart.Right(numLetters); return true; }
int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData) { if (lpData == NULL) return 0; CPanel *panel = (CPanel*)lpData; switch(panel->_sortID) { // if (panel->_sortIndex == 0) case kpidName: { const UString name1 = panel->GetItemName((int)lParam1); const UString name2 = panel->GetItemName((int)lParam2); int res = name1.CompareNoCase(name2); /* if (res != 0 || !panel->_flatMode) return res; const UString prefix1 = panel->GetItemPrefix(lParam1); const UString prefix2 = panel->GetItemPrefix(lParam2); return res = prefix1.CompareNoCase(prefix2); */ return res; } case kpidNoProperty: { return MyCompare(lParam1, lParam2); } case kpidExtension: { const UString ext1 = GetExtension(panel->GetItemName((int)lParam1)); const UString ext2 = GetExtension(panel->GetItemName((int)lParam2)); return ext1.CompareNoCase(ext2); } } /* if (panel->_sortIndex == 1) return MyCompare(file1.Size, file2.Size); return ::CompareFileTime(&file1.MTime, &file2.MTime); */ // PROPID propID = panel->_properties[panel->_sortIndex].ID; PROPID propID = panel->_sortID; NCOM::CPropVariant propVariant1, propVariant2; // Name must be first property panel->_folder->GetProperty((UINT32)lParam1, propID, &propVariant1); panel->_folder->GetProperty((UINT32)lParam2, propID, &propVariant2); if (propVariant1.vt != propVariant2.vt) return 0; // It means some BUG if (propVariant1.vt == VT_BSTR) { return _wcsicmp(propVariant1.bstrVal, propVariant2.bstrVal); } return propVariant1.Compare(propVariant2); // return 0; }
bool StringToBool(const UString &s, bool &res) { if (s.IsEmpty() || s.CompareNoCase(L"ON") == 0 || s.Compare(L"+") == 0) { res = true; return true; } if (s.CompareNoCase(L"OFF") == 0 || s.Compare(L"-") == 0) { res = false; return true; } return false; }
bool FindMethod( #ifdef EXTERNAL_CODECS ICompressCodecsInfo * /* codecsInfo */, const CObjectVector<CCodecInfoEx> *externalCodecs, #endif const UString &name, CMethodId &methodId, UInt32 &numInStreams, UInt32 &numOutStreams) { UInt32 i; for (i = 0; i < g_NumCodecs; i++) { const CCodecInfo &codec = *g_Codecs[i]; if (name.CompareNoCase(codec.Name) == 0) { methodId = codec.Id; numInStreams = codec.NumInStreams; numOutStreams = 1; return true; } } #ifdef EXTERNAL_CODECS if (externalCodecs) for (i = 0; i < (UInt32)externalCodecs->Size(); i++) { const CCodecInfoEx &codec = (*externalCodecs)[i]; if (codec.Name.CompareNoCase(name) == 0) { methodId = codec.Id; numInStreams = codec.NumInStreams; numOutStreams = codec.NumOutStreams; return true; } } #endif return false; }
static UString GetIconPath(const UString &filePath, const CLSID &clsID, const UString &extension, Int32 &iconIndex) { CPluginLibrary library; CMyComPtr<IFolderManager> folderManager; CMyComPtr<IFolderFolder> folder; if (filePath.IsEmpty()) folderManager = new CArchiveFolderManager; else if (library.LoadAndCreateManager(filePath, clsID, &folderManager) != S_OK) return UString(); CMyComBSTR extBSTR; if (folderManager->GetExtensions(&extBSTR) != S_OK) return UString(); const UString ext2 = (const wchar_t *)extBSTR; UStringVector exts; SplitString(ext2, exts); for (int i = 0; i < exts.Size(); i++) { const UString &plugExt = exts[i]; if (extension.CompareNoCase((const wchar_t *)plugExt) == 0) { CMyComBSTR iconPathTemp; if (folderManager->GetIconPath(plugExt, &iconPathTemp, &iconIndex) != S_OK) break; if (iconPathTemp != 0) return (const wchar_t *)iconPathTemp; } } return UString(); }
static bool IsExeExt(const UString &ext) { for (int i = 0; i < sizeof(g_ExeExts) / sizeof(g_ExeExts[0]); i++) if (ext.CompareNoCase(g_ExeExts[i]) == 0) return true; return false; }
void AddUniqueString(UStringVector &list, const UString &s) { for (int i = 0; i < list.Size(); i++) if (s.CompareNoCase(list[i]) == 0) return; list.Add(s); }
int COpenCallbackImp::FindName(const UString &name) { for (int i = 0; i < FileNames.Size(); i++) if (name.CompareNoCase(FileNames[i]) == 0) return i; return -1; }
int CArchiveFolderManager::FindFormat(const UString &type) { for (int i = 0; i < _codecs->Formats.Size(); i++) if (type.CompareNoCase(_codecs->Formats[i].Name) == 0) return i; return -1; }
static inline int MyFileNameCompare(const UString &s1, const UString &s2) { return #ifdef _WIN32 s1.CompareNoCase(s2); #else s1.Compare(s2); #endif }
int CCodecLib::FindIconIndex(const UString &ext) const { for (int i = 0; i < IconPairs.Size(); i++) { const CIconPair &pair = IconPairs[i]; if (ext.CompareNoCase(pair.Ext) == 0) return pair.IconIndex; } return -1; }
HRESULT MyMoveFolder( const UString &srcPath, const UString &destPathSpec, IFolderOperationsExtractCallback *callback, UInt64 &completedSize) { UString destPath = destPathSpec; int len = srcPath.Length(); if (destPath.Length() >= len && srcPath.CompareNoCase(destPath.Left(len)) == 0) { if (destPath.Length() == len || destPath[len] == WCHAR_PATH_SEPARATOR) { UString message = UString(L"can not move folder \'") + destPath + UString(L"\' onto itself"); RINOK(callback->ShowMessage(message)); return E_ABORT; } } if (MyMoveFile(srcPath, destPath, callback, completedSize)) return S_OK; if (!NDirectory::CreateComplexDirectory(destPath)) { UString message = UString(L"can not create folder ") + destPath; RINOK(callback->ShowMessage(message)); return E_ABORT; } { CEnumeratorW enumerator(CombinePath(srcPath, L"*")); CFileInfoEx fi; while (enumerator.Next(fi)) { const UString srcPath2 = CombinePath(srcPath, fi.Name); const UString destPath2 = CombinePath(destPath, fi.Name); if (fi.IsDir()) { RINOK(MyMoveFolder(srcPath2, destPath2, callback, completedSize)); } else { RINOK(MyMoveFile(srcPath2, fi, destPath2, callback, completedSize)); } } } if (!NDirectory::MyRemoveDirectory(srcPath)) { UString message = UString(L"can not remove folder") + srcPath; RINOK(callback->ShowMessage(message)); return E_ABORT; } return S_OK; }
static UString GetSubFolderNameForExtract(const UString &archiveName) { int dotPos = archiveName.ReverseFind(L'.'); if (dotPos < 0) return archiveName + UString(L"~"); const UString ext = archiveName.Mid(dotPos + 1); UString res = archiveName.Left(dotPos); res.TrimRight(); dotPos = res.ReverseFind(L'.'); if (dotPos > 0) { const UString ext2 = res.Mid(dotPos + 1); if (ext.CompareNoCase(L"rar") == 0 && (ext2.CompareNoCase(L"part001") == 0 || ext2.CompareNoCase(L"part01") == 0 || ext2.CompareNoCase(L"part1") == 0) || IsItArcExt(ext2) && ext.CompareNoCase(L"001") == 0) res = res.Left(dotPos); res.TrimRight(); } return GetCorrectFullFsPath(res); }
bool CCodecIcons::FindIconIndex(const UString &ext, int &iconIndex) const { iconIndex = -1; for (int i = 0; i < IconPairs.Size(); i++) { const CIconPair &pair = IconPairs[i]; if (ext.CompareNoCase(pair.Ext) == 0) { iconIndex = pair.IconIndex; return true; } } return false; }
HRESULT CCodecs::CreateCoder(const UString &name, bool encode, CMyComPtr<ICompressCoder> &coder) const { for (int i = 0; i < Codecs.Size(); i++) { const CDllCodecInfo &codec = Codecs[i]; if (encode && !codec.EncoderIsAssigned || !encode && !codec.DecoderIsAssigned) continue; const CCodecLib &lib = Libs[codec.LibIndex]; UString res; NWindows::NCOM::CPropVariant prop; RINOK(lib.GetMethodProperty(codec.CodecIndex, NMethodPropID::kName, &prop)); if (prop.vt == VT_BSTR) res = prop.bstrVal; else if (prop.vt != VT_EMPTY) continue; if (name.CompareNoCase(res) == 0) return lib.CreateObject(encode ? &codec.Encoder : &codec.Decoder, &IID_ICompressCoder, (void **)&coder); } return CLASS_E_CLASSNOTAVAILABLE; }
int CProxyFolder::FindDirSubItemIndex(const UString &name, int &insertPos) const { int left = 0, right = Folders.Size(); for (;;) { if (left == right) { insertPos = left; return -1; } int mid = (left + right) / 2; int compare = name.CompareNoCase(Folders[mid].Name); if (compare == 0) return mid; if (compare < 0) right = mid; else left = mid + 1; } }
int CCodecs::FindFormatForArchiveName(const UString &archivePath) const { int slashPos1 = archivePath.ReverseFind(L'\\'); int slashPos2 = archivePath.ReverseFind(L'.'); int dotPos = archivePath.ReverseFind(L'.'); if (dotPos < 0 || dotPos < slashPos1 || dotPos < slashPos2) return -1; UString ext = archivePath.Mid(dotPos + 1); for (int i = 0; i < Formats.Size(); i++) { const CArcInfoEx &arc = Formats[i]; if (!arc.UpdateEnabled) continue; // if (arc.FindExtension(ext) >= 0) UString mainExt = arc.GetMainExt(); if (!mainExt.IsEmpty() && ext.CompareNoCase(mainExt) == 0) return i; } return -1; }
static HRESULT MyCopyFile( const UString &srcPath, const CFileInfoW &srcFileInfo, const UString &destPathSpec, IFolderOperationsExtractCallback *callback, UInt64 &completedSize) { UString destPath = destPathSpec; if (destPath.CompareNoCase(srcPath) == 0) { UString message = UString(L"can not move file \'") + destPath + UString(L"\' onto itself"); RINOK(callback->ShowMessage(message)); return E_ABORT; } Int32 writeAskResult; CMyComBSTR destPathResult; RINOK(callback->AskWrite( srcPath, BoolToInt(false), &srcFileInfo.MTime, &srcFileInfo.Size, destPath, &destPathResult, &writeAskResult)); if (IntToBool(writeAskResult)) { UString destPathNew = UString(destPathResult); RINOK(callback->SetCurrentFilePath(srcPath)); if (!MyCopyFile(srcPath, destPathNew, callback, completedSize)) { UString message = NError::MyFormatMessageW(GetLastError()) + UString(L" \'") + UString(destPathNew) + UString(L"\'"); RINOK(callback->ShowMessage(message)); return E_ABORT; } } completedSize += srcFileInfo.Size; return callback->SetCompleted(&completedSize); }
HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) { UString name = nameSpec; name.MakeUpper(); if (name.IsEmpty()) return E_INVALIDARG; if (name[0] == L'S') { name.Delete(0); if (name.IsEmpty()) return SetSolidFromPROPVARIANT(value); if (value.vt != VT_EMPTY) return E_INVALIDARG; return SetSolidFromString(name); } UInt32 number; int index = ParseStringToUInt32(name, number); UString realName = name.Mid(index); if (index == 0) { if (name.CompareNoCase(L"RSFX") == 0) return PROPVARIANT_to_bool(value, _removeSfxBlock); if (name.CompareNoCase(L"HC") == 0) return PROPVARIANT_to_bool(value, _compressHeaders); if (name.CompareNoCase(L"HCF") == 0) { bool compressHeadersFull = true; RINOK(PROPVARIANT_to_bool(value, compressHeadersFull)); return compressHeadersFull ? S_OK: E_INVALIDARG; } if (name.CompareNoCase(L"HE") == 0) { RINOK(PROPVARIANT_to_bool(value, _encryptHeaders)); _encryptHeadersSpecified = true; return S_OK; } if (name.CompareNoCase(L"TC") == 0) return PROPVARIANT_to_bool(value, WriteCTime); if (name.CompareNoCase(L"TA") == 0) return PROPVARIANT_to_bool(value, WriteATime); if (name.CompareNoCase(L"TM") == 0) return PROPVARIANT_to_bool(value, WriteMTime); if (name.CompareNoCase(L"V") == 0) return PROPVARIANT_to_bool(value, _volumeMode); } return CMultiMethodProps::SetProperty(name, value); }
static bool CheckShellExtensionInfo2(const CSysString &extension, UString &iconPath, int &iconIndex) { iconIndex = -1; iconPath.Empty(); NSynchronization::CCriticalSectionLock lock(g_CriticalSection); CKey extKey; if (extKey.Open(HKEY_CLASSES_ROOT, GetExtensionKeyName(extension), KEY_READ) != ERROR_SUCCESS) return false; CSysString programNameValue; if (extKey.QueryValue(NULL, programNameValue) != ERROR_SUCCESS) return false; CSysString extProgramKeyName = GetExtProgramKeyName(extension); UString programNameValueU = GetUnicodeString(programNameValue); if (programNameValueU.CompareNoCase(GetUnicodeString(extProgramKeyName)) != 0) return false; CKey iconKey; if (extKey.Open(HKEY_CLASSES_ROOT, extProgramKeyName + CSysString(TEXT(CHAR_PATH_SEPARATOR)) + kDefaultIconKeyName, KEY_READ) != ERROR_SUCCESS) return false; UString value; if (extKey.QueryValue(NULL, value) == ERROR_SUCCESS) { int pos = value.ReverseFind(L','); iconPath = value; if (pos >= 0) { const wchar_t *end; UInt64 index = ConvertStringToUInt64((const wchar_t *)value + pos + 1, &end); if (*end == 0) { iconIndex = (int)index; iconPath = value.Left(pos); } } } return true; }
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, LPSTR /* lpCmdLine */,int /* nCmdShow */) { g_hInstance = (HINSTANCE)hInstance; #ifndef _UNICODE g_IsNT = IsItWindowsNT(); #endif InitCommonControls(); UString archiveName, switches; #ifdef _SHELL_EXECUTE UString executeFile, executeParameters; #endif NCommandLineParser::SplitCommandLine(GetCommandLineW(), archiveName, switches); UString fullPath; NDLL::MyGetModuleFileName(g_hInstance, fullPath); switches.Trim(); bool assumeYes = false; if (switches.Left(2).CompareNoCase(UString(L"-y")) == 0) { assumeYes = true; switches = switches.Mid(2); switches.Trim(); } AString config; if (!ReadDataString(fullPath, kStartID, kEndID, config)) { if (!assumeYes) ShowErrorMessage(L"Can't load config info"); return 1; } UString dirPrefix = L"." WSTRING_PATH_SEPARATOR; UString appLaunched; bool showProgress = true; if (!config.IsEmpty()) { CObjectVector<CTextConfigPair> pairs; if (!GetTextConfig(config, pairs)) { if (!assumeYes) ShowErrorMessage(L"Config failed"); return 1; } UString friendlyName = GetTextConfigValue(pairs, L"Title"); UString installPrompt = GetTextConfigValue(pairs, L"BeginPrompt"); UString progress = GetTextConfigValue(pairs, L"Progress"); if (progress.CompareNoCase(L"no") == 0) showProgress = false; int index = FindTextConfigItem(pairs, L"Directory"); if (index >= 0) dirPrefix = pairs[index].String; if (!installPrompt.IsEmpty() && !assumeYes) { if (MessageBoxW(0, installPrompt, friendlyName, MB_YESNO | MB_ICONQUESTION) != IDYES) return 0; } appLaunched = GetTextConfigValue(pairs, L"RunProgram"); #ifdef _SHELL_EXECUTE executeFile = GetTextConfigValue(pairs, L"ExecuteFile"); executeParameters = GetTextConfigValue(pairs, L"ExecuteParameters") + switches; #endif } NFile::NDirectory::CTempDirectory tempDir; if (!tempDir.Create(kTempDirPrefix)) { if (!assumeYes) ShowErrorMessage(L"Can not create temp folder archive"); return 1; } CCodecs *codecs = new CCodecs; CMyComPtr<IUnknown> compressCodecsInfo = codecs; HRESULT result = codecs->Load(); if (result != S_OK) { ShowErrorMessage(L"Can not load codecs"); return 1; } UString tempDirPath = GetUnicodeString(tempDir.GetPath()); { bool isCorrupt = false; UString errorMessage; HRESULT result = ExtractArchive(codecs, fullPath, tempDirPath, showProgress, isCorrupt, errorMessage); if (result != S_OK) { if (!assumeYes) { if (result == S_FALSE || isCorrupt) { errorMessage = NWindows::MyLoadStringW(IDS_EXTRACTION_ERROR_MESSAGE); result = E_FAIL; } if (result != E_ABORT && !errorMessage.IsEmpty()) ::MessageBoxW(0, errorMessage, NWindows::MyLoadStringW(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR); } return 1; } } CCurrentDirRestorer currentDirRestorer; if (!SetCurrentDirectory(tempDir.GetPath())) return 1; HANDLE hProcess = 0; #ifdef _SHELL_EXECUTE if (!executeFile.IsEmpty()) { CSysString filePath = GetSystemString(executeFile); SHELLEXECUTEINFO execInfo; execInfo.cbSize = sizeof(execInfo); execInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT; execInfo.hwnd = NULL; execInfo.lpVerb = NULL; execInfo.lpFile = filePath; if (!switches.IsEmpty()) executeParameters += switches; CSysString parametersSys = GetSystemString(executeParameters); if (parametersSys.IsEmpty()) execInfo.lpParameters = NULL; else execInfo.lpParameters = parametersSys; execInfo.lpDirectory = NULL; execInfo.nShow = SW_SHOWNORMAL; execInfo.hProcess = 0; /* BOOL success = */ ::ShellExecuteEx(&execInfo); UINT32 result = (UINT32)(UINT_PTR)execInfo.hInstApp; if(result <= 32) { if (!assumeYes) ShowErrorMessage(L"Can not open file"); return 1; } hProcess = execInfo.hProcess; } else #endif { if (appLaunched.IsEmpty()) { appLaunched = L"setup.exe"; if (!NFile::NFind::DoesFileExist(GetSystemString(appLaunched))) { if (!assumeYes) ShowErrorMessage(L"Can not find setup.exe"); return 1; } } { UString s2 = tempDirPath; NFile::NName::NormalizeDirPathPrefix(s2); appLaunched.Replace(L"%%T" WSTRING_PATH_SEPARATOR, s2); } appLaunched.Replace(L"%%T", tempDirPath); if (!switches.IsEmpty()) { appLaunched += L' '; appLaunched += switches; } STARTUPINFO startupInfo; startupInfo.cb = sizeof(startupInfo); startupInfo.lpReserved = 0; startupInfo.lpDesktop = 0; startupInfo.lpTitle = 0; startupInfo.dwFlags = 0; startupInfo.cbReserved2 = 0; startupInfo.lpReserved2 = 0; PROCESS_INFORMATION processInformation; CSysString appLaunchedSys = GetSystemString(dirPrefix + appLaunched); BOOL createResult = CreateProcess(NULL, (LPTSTR)(LPCTSTR)appLaunchedSys, NULL, NULL, FALSE, 0, NULL, NULL /*tempDir.GetPath() */, &startupInfo, &processInformation); if (createResult == 0) { if (!assumeYes) ShowLastErrorMessage(); return 1; } ::CloseHandle(processInformation.hThread); hProcess = processInformation.hProcess; } if (hProcess != 0) { WaitForSingleObject(hProcess, INFINITE); ::CloseHandle(hProcess); } return 0; }
STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties) { #ifndef _7ZIP_ST const UInt32 numProcessors = NSystem::GetNumberOfProcessors(); _numThreads = numProcessors; #endif InitMethodProperties(); for (int i = 0; i < numProperties; i++) { UString name = UString(names[i]); name.MakeUpper(); if (name.IsEmpty()) return E_INVALIDARG; const PROPVARIANT &prop = values[i]; if (name[0] == L'X') { UInt32 level = 9; RINOK(ParsePropValue(name.Mid(1), prop, level)); m_Level = level; continue; } else if (name == L"M") { if (prop.vt == VT_BSTR) { UString m = prop.bstrVal; m.MakeUpper(); if (m == L"COPY") m_MainMethod = NFileHeader::NCompressionMethod::kStored; else if (m == L"DEFLATE") m_MainMethod = NFileHeader::NCompressionMethod::kDeflated; else if (m == L"DEFLATE64") m_MainMethod = NFileHeader::NCompressionMethod::kDeflated64; else if (m == L"BZIP2") m_MainMethod = NFileHeader::NCompressionMethod::kBZip2; else if (m == L"LZMA") m_MainMethod = NFileHeader::NCompressionMethod::kLZMA; else if (m == L"PPMD") m_MainMethod = NFileHeader::NCompressionMethod::kPPMd; else return E_INVALIDARG; } else if (prop.vt == VT_UI4) { switch(prop.ulVal) { case NFileHeader::NCompressionMethod::kStored: case NFileHeader::NCompressionMethod::kDeflated: case NFileHeader::NCompressionMethod::kDeflated64: case NFileHeader::NCompressionMethod::kBZip2: case NFileHeader::NCompressionMethod::kLZMA: m_MainMethod = (Byte)prop.ulVal; break; default: return E_INVALIDARG; } } else return E_INVALIDARG; } else if (name.Left(2) == L"EM") { if (prop.vt == VT_BSTR) { UString valueString = prop.bstrVal; valueString.MakeUpper(); if (valueString.Left(3) == L"AES") { valueString = valueString.Mid(3); if (valueString == L"128") m_AesKeyMode = 1; else if (valueString == L"192") m_AesKeyMode = 2; else if (valueString == L"256" || valueString.IsEmpty()) m_AesKeyMode = 3; else return E_INVALIDARG; m_IsAesMode = true; m_ForceAesMode = true; } else if (valueString == L"ZIPCRYPTO") { m_IsAesMode = false; m_ForceAesMode = true; } else return E_INVALIDARG; } else return E_INVALIDARG; } else if (name[0] == L'D') { UInt32 dicSize = kBZip2DicSizeX5; RINOK(ParsePropDictionaryValue(name.Mid(1), prop, dicSize)); m_DicSize = dicSize; } else if (name.Left(3) == L"MEM") { UInt32 memSize = 1 << 24; RINOK(ParsePropDictionaryValue(name.Mid(3), prop, memSize)); m_MemSize = memSize; } else if (name[0] == L'O') { UInt32 order = 8; RINOK(ParsePropValue(name.Mid(1), prop, order)); m_Order = order; } else if (name.Left(4) == L"PASS") { UInt32 num = kDeflateNumPassesX9; RINOK(ParsePropValue(name.Mid(4), prop, num)); m_NumPasses = num; } else if (name.Left(2) == L"FB") { UInt32 num = kDeflateNumFastBytesX9; RINOK(ParsePropValue(name.Mid(2), prop, num)); m_NumFastBytes = num; } else if (name.Left(2) == L"MC") { UInt32 num = 0xFFFFFFFF; RINOK(ParsePropValue(name.Mid(2), prop, num)); m_NumMatchFinderCycles = num; m_NumMatchFinderCyclesDefined = true; } else if (name.Left(2) == L"MT") { #ifndef _7ZIP_ST RINOK(ParseMtProp(name.Mid(2), prop, numProcessors, _numThreads)); #endif } else if (name.Left(1) == L"A") { UInt32 num = kLzAlgoX5; RINOK(ParsePropValue(name.Mid(1), prop, num)); m_Algo = num; } else if (name.CompareNoCase(L"TC") == 0) { RINOK(SetBoolProperty(m_WriteNtfsTimeExtra, prop)); } else if (name.CompareNoCase(L"CL") == 0) { RINOK(SetBoolProperty(m_ForceLocal, prop)); if (m_ForceLocal) m_ForceUtf8 = false; } else if (name.CompareNoCase(L"CU") == 0) { RINOK(SetBoolProperty(m_ForceUtf8, prop)); if (m_ForceUtf8) m_ForceLocal = false; } else return E_INVALIDARG; } return S_OK; }
HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) { UInt64 endPos = 0; { RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); } _phySizeDefined = true; for (;;) { CItemEx item; bool filled; RINOK(ReadItem2(stream, filled, item)); if (!filled) break; _items.Add(item); RINOK(stream->Seek(item.GetPackSizeAligned(), STREAM_SEEK_CUR, &_phySize)); if (_phySize > endPos) { _errorMessage = kUnexpectedEnd; break; } /* if (_phySize == endPos) { _errorMessage = "There are no trailing zero-filled records"; break; } */ if (callback != NULL) { if (_items.Size() == 1) { RINOK(callback->SetTotal(NULL, &endPos)); } if (_items.Size() % 100 == 0) { UInt64 numFiles = _items.Size(); RINOK(callback->SetCompleted(&numFiles, &_phySize)); } } } if (_items.Size() == 0) { CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; if (!callback) return S_FALSE; callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); if (!openVolumeCallback) return S_FALSE; NCOM::CPropVariant prop; if (openVolumeCallback->GetProperty(kpidName, &prop) != S_OK) return S_FALSE; if (prop.vt != VT_BSTR) return S_FALSE; UString baseName = prop.bstrVal; baseName = baseName.Right(4); if (baseName.CompareNoCase(L".tar") != 0) return S_FALSE; } return S_OK; }
HRESULT DecompressArchives( CCodecs *codecs, const CIntVector &formatIndices, UStringVector &archivePaths, UStringVector &archivePathsFull, const NWildcard::CCensorNode &wildcardCensor, const CExtractOptions &optionsSpec, IOpenCallbackUI *openCallback, IExtractCallbackUI *extractCallback, UString &errorMessage, CDecompressStat &stat) { stat.Clear(); CExtractOptions options = optionsSpec; int i; UInt64 totalPackSize = 0; CRecordVector<UInt64> archiveSizes; for (i = 0; i < archivePaths.Size(); i++) { const UString &archivePath = archivePaths[i]; NFile::NFind::CFileInfoW fi; if (!NFile::NFind::FindFile(archivePath, fi)) throw "there is no such archive"; if (fi.IsDir()) throw "can't decompress folder"; archiveSizes.Add(fi.Size); totalPackSize += fi.Size; } CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; CMyComPtr<IArchiveExtractCallback> ec(extractCallbackSpec); bool multi = (archivePaths.Size() > 1); extractCallbackSpec->InitForMulti(multi, options.PathMode, options.OverwriteMode); if (multi) { RINOK(extractCallback->SetTotal(totalPackSize)); } for (i = 0; i < archivePaths.Size(); i++) { const UString &archivePath = archivePaths[i]; NFile::NFind::CFileInfoW fi; if (!NFile::NFind::FindFile(archivePath, fi)) throw "there is no such archive"; if (fi.IsDir()) throw "there is no such archive"; options.ArchiveFileInfo = fi; #ifndef _NO_CRYPTO openCallback->Open_ClearPasswordWasAskedFlag(); #endif RINOK(extractCallback->BeforeOpen(archivePath)); CArchiveLink archiveLink; CIntVector formatIndices2 = formatIndices; #ifndef _SFX if (formatIndices.IsEmpty()) { int pos = archivePath.ReverseFind(L'.'); if (pos >= 0) { UString s = archivePath.Mid(pos + 1); int index = codecs->FindFormatForExtension(s); if (index >= 0 && s == L"001") { s = archivePath.Left(pos); pos = s.ReverseFind(L'.'); if (pos >= 0) { int index2 = codecs->FindFormatForExtension(s.Mid(pos + 1)); if (index2 >= 0 && s.CompareNoCase(L"rar") != 0) { formatIndices2.Add(index2); formatIndices2.Add(index); } } } } } #endif HRESULT result = MyOpenArchive(codecs, formatIndices2, archivePath, archiveLink, openCallback); if (result == E_ABORT) return result; bool crypted = false; #ifndef _NO_CRYPTO crypted = openCallback->Open_WasPasswordAsked(); #endif RINOK(extractCallback->OpenResult(archivePath, result, crypted)); if (result != S_OK) continue; for (int v = 0; v < archiveLink.VolumePaths.Size(); v++) { int index = archivePathsFull.FindInSorted(archiveLink.VolumePaths[v]); if (index >= 0 && index > i) { archivePaths.Delete(index); archivePathsFull.Delete(index); totalPackSize -= archiveSizes[index]; archiveSizes.Delete(index); } } if (archiveLink.VolumePaths.Size() != 0) { totalPackSize += archiveLink.VolumesSize; RINOK(extractCallback->SetTotal(totalPackSize)); } #ifndef _NO_CRYPTO UString password; RINOK(openCallback->Open_GetPasswordIfAny(password)); if (!password.IsEmpty()) { RINOK(extractCallback->SetPassword(password)); } #endif options.DefaultItemName = archiveLink.GetDefaultItemName(); RINOK(DecompressArchive( archiveLink.GetArchive(), fi.Size + archiveLink.VolumesSize, wildcardCensor, options, extractCallback, extractCallbackSpec, errorMessage)); extractCallbackSpec->LocalProgressSpec->InSize += fi.Size + archiveLink.VolumesSize; extractCallbackSpec->LocalProgressSpec->OutSize = extractCallbackSpec->UnpackSize; if (!errorMessage.IsEmpty()) return E_FAIL; } stat.NumFolders = extractCallbackSpec->NumFolders; stat.NumFiles = extractCallbackSpec->NumFiles; stat.UnpackSize = extractCallbackSpec->UnpackSize; stat.NumArchives = archivePaths.Size(); stat.PackSize = extractCallbackSpec->LocalProgressSpec->InSize; return S_OK; }
HRESULT CAgent::RenameItem( const wchar_t *newArchiveName, const UInt32 *indices, UInt32 numItems, const wchar_t *newItemName, IFolderArchiveUpdateCallback *updateCallback100) { if (!CanUpdate()) return E_NOTIMPL; if (numItems != 1) return E_INVALIDARG; CUpdateCallbackAgent updateCallbackAgent; updateCallbackAgent.SetCallback(updateCallback100); CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec); CUIntVector realIndices; _agentFolder->GetRealIndices(indices, numItems, realIndices); UString fullPrefix = _agentFolder->GetFullPathPrefixPlusPrefix(indices[0]); UString oldItemPath = fullPrefix + _agentFolder->GetName(indices[0]); UString newItemPath = fullPrefix + newItemName; CRecordVector<CUpdatePair2> updatePairs; UStringVector newNames; int curIndex = 0; UInt32 numItemsInArchive; RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive)); for (UInt32 i = 0; i < numItemsInArchive; i++) { if (curIndex < realIndices.Size()) if (realIndices[curIndex] == i) { CUpdatePair2 up2; up2.NewData = false; up2.NewProps = true; RINOK(IsArchiveItemAnti(GetArchive(), i, up2.IsAnti)); up2.ArcIndex = i; UString oldFullPath; RINOK(GetArchiveItemPath(GetArchive(), i, DefaultName, oldFullPath)); if (oldItemPath.CompareNoCase(oldFullPath.Left(oldItemPath.Length())) != 0) return E_INVALIDARG; up2.NewNameIndex = newNames.Add(newItemPath + oldFullPath.Mid(oldItemPath.Length())); updatePairs.Add(up2); curIndex++; continue; } CUpdatePair2 up2; up2.NewData = up2.NewProps = false; up2.IsAnti = false; up2.ArcIndex = i; updatePairs.Add(up2); } updateCallbackSpec->Callback = &updateCallbackAgent; updateCallbackSpec->UpdatePairs = &updatePairs; updateCallbackSpec->NewNames = &newNames; updateCallbackSpec->Archive = GetArchive(); return CommonUpdate(newArchiveName, updatePairs.Size(), updateCallback); }
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // Disable current directory from being in the search path. // This call does not help with implicitly loaded DLLs. if (!RemoveCurrentDirFromSearchPath()) { WCHAR minOSTitle[512] = { '\0' }; WCHAR minOSText[512] = { '\0' }; LoadStringW(NULL, IDS_MIN_OS_TITLE, minOSTitle, sizeof(minOSTitle) / sizeof(minOSTitle[0])); LoadStringW(NULL, IDS_MIN_OS_TEXT, minOSText, sizeof(minOSText) / sizeof(minOSText[0])); MessageBoxW(NULL, minOSText, minOSTitle, MB_OK | MB_ICONERROR); return 1; } g_hInstance = (HINSTANCE)hInstance; #ifndef _UNICODE g_IsNT = IsItWindowsNT(); #endif InitCommonControls(); UString archiveName, switches; #ifdef _SHELL_EXECUTE UString executeFile, executeParameters; #endif NCommandLineParser::SplitCommandLine(GetCommandLineW(), archiveName, switches); UString fullPath; NDLL::MyGetModuleFileName(g_hInstance, fullPath); switches.Trim(); bool assumeYes = false; if (switches.Left(2).CompareNoCase(UString(L"-y")) == 0) { assumeYes = true; switches = switches.Mid(2); switches.Trim(); } /* BEGIN Mozilla customizations */ bool showProgress = true; if (switches.Left(3).CompareNoCase(UString(L"-ms")) == 0 || switches.Left(4).CompareNoCase(UString(L"/INI")) == 0 || switches.Left(2).CompareNoCase(UString(L"/S")) == 0) showProgress = false; /* END Mozilla customizations */ AString config; if (!ReadDataString(fullPath, kStartID, kEndID, config)) { if (!assumeYes) MyMessageBox(L"Can't load config info"); return 1; } UString dirPrefix = L".\\"; UString appLaunched; if (!config.IsEmpty()) { CObjectVector<CTextConfigPair> pairs; if (!GetTextConfig(config, pairs)) { if (!assumeYes) MyMessageBox(L"Config failed"); return 1; } UString friendlyName = GetTextConfigValue(pairs, L"Title"); UString installPrompt = GetTextConfigValue(pairs, L"BeginPrompt"); UString progress = GetTextConfigValue(pairs, L"Progress"); if (progress.CompareNoCase(L"no") == 0) showProgress = false; int index = FindTextConfigItem(pairs, L"Directory"); if (index >= 0) dirPrefix = pairs[index].String; if (!installPrompt.IsEmpty() && !assumeYes) { if (MessageBoxW(0, installPrompt, friendlyName, MB_YESNO | MB_ICONQUESTION) != IDYES) return 0; } appLaunched = GetTextConfigValue(pairs, L"RunProgram"); #ifdef _SHELL_EXECUTE executeFile = GetTextConfigValue(pairs, L"ExecuteFile"); executeParameters = GetTextConfigValue(pairs, L"ExecuteParameters") + switches; #endif } NFile::NDirectory::CTempDirectory tempDir; if (!tempDir.Create(kTempDirPrefix)) { if (!assumeYes) MyMessageBox(L"Can not create temp folder archive"); return 1; } COpenCallbackGUI openCallback; UString tempDirPath = GetUnicodeString(tempDir.GetPath()); bool isCorrupt = false; UString errorMessage; HRESULT result = ExtractArchive(fullPath, tempDirPath, &openCallback, showProgress, isCorrupt, errorMessage); if (result != S_OK) { if (!assumeYes) { if (result == S_FALSE || isCorrupt) { errorMessage = NWindows::MyLoadStringW(IDS_EXTRACTION_ERROR_MESSAGE); result = E_FAIL; } if (result != E_ABORT && !errorMessage.IsEmpty()) ::MessageBoxW(0, errorMessage, NWindows::MyLoadStringW(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR); } return 1; } CCurrentDirRestorer currentDirRestorer; if (!SetCurrentDirectory(tempDir.GetPath())) return 1; HANDLE hProcess = 0; #ifdef _SHELL_EXECUTE if (!executeFile.IsEmpty()) { CSysString filePath = GetSystemString(executeFile); SHELLEXECUTEINFO execInfo; execInfo.cbSize = sizeof(execInfo); execInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT; execInfo.hwnd = NULL; execInfo.lpVerb = NULL; execInfo.lpFile = filePath; if (!switches.IsEmpty()) executeParameters += switches; CSysString parametersSys = GetSystemString(executeParameters); if (parametersSys.IsEmpty()) execInfo.lpParameters = NULL; else execInfo.lpParameters = parametersSys; execInfo.lpDirectory = NULL; execInfo.nShow = SW_SHOWNORMAL; execInfo.hProcess = 0; bool success = BOOLToBool(::ShellExecuteEx(&execInfo)); result = (UINT32)execInfo.hInstApp; if(result <= 32) { if (!assumeYes) MyMessageBox(L"Can not open file"); return 1; } hProcess = execInfo.hProcess; } else #endif { if (appLaunched.IsEmpty()) { appLaunched = L"setup.exe"; if (!NFile::NFind::DoesFileExist(GetSystemString(appLaunched))) { if (!assumeYes) MyMessageBox(L"Can not find setup.exe"); return 1; } } { UString s2 = tempDirPath; NFile::NName::NormalizeDirPathPrefix(s2); appLaunched.Replace(L"%%T\\", s2); } appLaunched.Replace(L"%%T", tempDirPath); if (!switches.IsEmpty()) { appLaunched += L' '; appLaunched += switches; } STARTUPINFO startupInfo; startupInfo.cb = sizeof(startupInfo); startupInfo.lpReserved = 0; startupInfo.lpDesktop = 0; startupInfo.lpTitle = 0; startupInfo.dwFlags = 0; startupInfo.cbReserved2 = 0; startupInfo.lpReserved2 = 0; PROCESS_INFORMATION processInformation; CSysString appLaunchedSys = GetSystemString(dirPrefix + appLaunched); BOOL createResult = CreateProcess(NULL, (LPTSTR)(LPCTSTR)appLaunchedSys, NULL, NULL, FALSE, 0, NULL, NULL /*tempDir.GetPath() */, &startupInfo, &processInformation); if (createResult == 0) { if (!assumeYes) ShowLastErrorMessage(); return 1; } ::CloseHandle(processInformation.hThread); hProcess = processInformation.hProcess; } if (hProcess != 0) { WaitForSingleObject(hProcess, INFINITE); ::CloseHandle(hProcess); } return 0; }
// if string contains switch then function updates switch structures // out: (string is a switch) bool CParser::ParseString(const UString &s, const CSwitchForm *switchForms) { int len = s.Length(); if (len == 0) return false; int pos = 0; if (!IsItSwitchChar(s[pos])) return false; while(pos < len) { if (IsItSwitchChar(s[pos])) pos++; const int kNoLen = -1; int matchedSwitchIndex = 0; // GCC Warning int maxLen = kNoLen; for(int switchIndex = 0; switchIndex < _numSwitches; switchIndex++) { int switchLen = MyStringLen(switchForms[switchIndex].IDString); if (switchLen <= maxLen || pos + switchLen > len) continue; UString temp = s + pos; temp = temp.Left(switchLen); if(temp.CompareNoCase(switchForms[switchIndex].IDString) == 0) // if(_strnicmp(switchForms[switchIndex].IDString, LPCSTR(s) + pos, switchLen) == 0) { matchedSwitchIndex = switchIndex; maxLen = switchLen; } } if (maxLen == kNoLen) throw "maxLen == kNoLen"; CSwitchResult &matchedSwitch = _switches[matchedSwitchIndex]; const CSwitchForm &switchForm = switchForms[matchedSwitchIndex]; if ((!switchForm.Multi) && matchedSwitch.ThereIs) throw "switch must be single"; matchedSwitch.ThereIs = true; pos += maxLen; int tailSize = len - pos; NSwitchType::EEnum type = switchForm.Type; switch(type) { case NSwitchType::kPostMinus: { if (tailSize == 0) matchedSwitch.WithMinus = false; else { matchedSwitch.WithMinus = (s[pos] == kSwitchMinus); if (matchedSwitch.WithMinus) pos++; } break; } case NSwitchType::kPostChar: { if (tailSize < switchForm.MinLen) throw "switch is not full"; UString set = switchForm.PostCharSet; const int kEmptyCharValue = -1; if (tailSize == 0) matchedSwitch.PostCharIndex = kEmptyCharValue; else { int index = set.Find(s[pos]); if (index < 0) matchedSwitch.PostCharIndex = kEmptyCharValue; else { matchedSwitch.PostCharIndex = index; pos++; } } break; } case NSwitchType::kLimitedPostString: case NSwitchType::kUnLimitedPostString: { int minLen = switchForm.MinLen; if (tailSize < minLen) throw "switch is not full"; if (type == NSwitchType::kUnLimitedPostString) { matchedSwitch.PostStrings.Add(s.Mid(pos)); return true; } int maxLen = switchForm.MaxLen; UString stringSwitch = s.Mid(pos, minLen); pos += minLen; for(int i = minLen; i < maxLen && pos < len; i++, pos++) { wchar_t c = s[pos]; if (IsItSwitchChar(c)) break; stringSwitch += c; } matchedSwitch.PostStrings.Add(stringSwitch); break; } case NSwitchType::kSimple: break; } } return true; }
int main2(int n, const char *args[]) { fprintf(stderr, "\nLZMA 4.27 Copyright (c) 1999-2005 Igor Pavlov 2005-08-07\n"); if (n == 1) { PrintHelp(); return 0; } if (sizeof(Byte) != 1 || sizeof(UInt32) < 4 || sizeof(UInt64) < 4) { fprintf(stderr, "Unsupported base types. Edit Common/Types.h and recompile"); return 1; } UStringVector commandStrings; WriteArgumentsToStringList(n, args, commandStrings); CParser parser(kNumSwitches); try { parser.ParseStrings(kSwitchForms, commandStrings); } catch(...) { IncorrectCommand(); } if(parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs) { PrintHelp(); return 0; } const UStringVector &nonSwitchStrings = parser.NonSwitchStrings; int paramIndex = 0; if (paramIndex >= nonSwitchStrings.Size()) IncorrectCommand(); const UString &command = nonSwitchStrings[paramIndex++]; bool dictionaryIsDefined = false; UInt32 dictionary = 1 << 21; if(parser[NKey::kDictionary].ThereIs) { UInt32 dicLog; if (!GetNumber(parser[NKey::kDictionary].PostStrings[0], dicLog)) IncorrectCommand(); dictionary = 1 << dicLog; dictionaryIsDefined = true; } UString mf = L"BT4"; if (parser[NKey::kMatchFinder].ThereIs) mf = parser[NKey::kMatchFinder].PostStrings[0]; if (command.CompareNoCase(L"b") == 0) { const UInt32 kNumDefaultItereations = 10; UInt32 numIterations = kNumDefaultItereations; { if (paramIndex < nonSwitchStrings.Size()) if (!GetNumber(nonSwitchStrings[paramIndex++], numIterations)) numIterations = kNumDefaultItereations; } return LzmaBenchmark(stderr, numIterations, dictionary, mf.CompareNoCase(L"BT4") == 0); } bool encodeMode = false; if (command.CompareNoCase(L"e") == 0) encodeMode = true; else if (command.CompareNoCase(L"d") == 0) encodeMode = false; else IncorrectCommand(); bool stdInMode = parser[NKey::kStdIn].ThereIs; bool stdOutMode = parser[NKey::kStdOut].ThereIs; CMyComPtr<ISequentialInStream> inStream; CInFileStream *inStreamSpec = 0; if (stdInMode) { inStream = new CStdInFileStream; MY_SET_BINARY_MODE(stdin); } else { if (paramIndex >= nonSwitchStrings.Size()) IncorrectCommand(); const UString &inputName = nonSwitchStrings[paramIndex++]; inStreamSpec = new CInFileStream; inStream = inStreamSpec; if (!inStreamSpec->Open(GetSystemString(inputName))) { fprintf(stderr, "\nError: can not open input file %s\n", (const char *)GetOemString(inputName)); return 1; } } CMyComPtr<ISequentialOutStream> outStream; if (stdOutMode) { outStream = new CStdOutFileStream; MY_SET_BINARY_MODE(stdout); } else { if (paramIndex >= nonSwitchStrings.Size()) IncorrectCommand(); const UString &outputName = nonSwitchStrings[paramIndex++]; COutFileStream *outStreamSpec = new COutFileStream; outStream = outStreamSpec; if (!outStreamSpec->Create(GetSystemString(outputName), true)) { fprintf(stderr, "\nError: can not open output file %s\n", (const char *)GetOemString(outputName)); return 1; } } if (parser[NKey::kFilter86].ThereIs) { // -f86 switch is for x86 filtered mode: BCJ + LZMA. if (parser[NKey::kEOS].ThereIs || stdInMode) throw "Can not use stdin in this mode"; UInt64 fileSize; inStreamSpec->File.GetLength(fileSize); if (fileSize > 0xF0000000) throw "File is too big"; UInt32 inSize = (UInt32)fileSize; Byte *inBuffer = 0; if (inSize != 0) { inBuffer = (Byte *)MyAlloc((size_t)inSize); if (inBuffer == 0) throw kCantAllocate; } UInt32 processedSize; if (inStream->Read(inBuffer, (UInt32)inSize, &processedSize) != S_OK) throw "Can not read"; if ((UInt32)inSize != processedSize) throw "Read size error"; Byte *outBuffer = 0; size_t outSizeProcessed; if (encodeMode) { // we allocate 105% of original size for output buffer size_t outSize = (size_t)fileSize / 20 * 21 + (1 << 16); if (outSize != 0) { outBuffer = (Byte *)MyAlloc((size_t)outSize); if (outBuffer == 0) throw kCantAllocate; } if (!dictionaryIsDefined) dictionary = 1 << 23; int res = LzmaRamEncode(inBuffer, inSize, outBuffer, outSize, &outSizeProcessed, dictionary, SZ_FILTER_AUTO); if (res != 0) { fprintf(stderr, "\nEncoder error = %d\n", (int)res); return 1; } } else { size_t outSize; if (LzmaRamGetUncompressedSize(inBuffer, inSize, &outSize) != 0) throw "data error"; if (outSize != 0) { outBuffer = (Byte *)MyAlloc(outSize); if (outBuffer == 0) throw kCantAllocate; } int res = LzmaRamDecompress(inBuffer, inSize, outBuffer, outSize, &outSizeProcessed, malloc, free); if (res != 0) throw "LzmaDecoder error"; } if (outStream->Write(outBuffer, (UInt32)outSizeProcessed, &processedSize) != S_OK) throw "Can not write"; MyFree(outBuffer); MyFree(inBuffer); return 0; } UInt64 fileSize; if (encodeMode) { NCompress::NLZMA::CEncoder *encoderSpec = new NCompress::NLZMA::CEncoder; CMyComPtr<ICompressCoder> encoder = encoderSpec; if (!dictionaryIsDefined) dictionary = 1 << 23; UInt32 posStateBits = 2; UInt32 litContextBits = 3; // for normal files // UInt32 litContextBits = 0; // for 32-bit data UInt32 litPosBits = 0; // UInt32 litPosBits = 2; // for 32-bit data UInt32 algorithm = 2; UInt32 numFastBytes = 128; bool eos = parser[NKey::kEOS].ThereIs || stdInMode; if(parser[NKey::kMode].ThereIs) if (!GetNumber(parser[NKey::kMode].PostStrings[0], algorithm)) IncorrectCommand(); if(parser[NKey::kFastBytes].ThereIs) if (!GetNumber(parser[NKey::kFastBytes].PostStrings[0], numFastBytes)) IncorrectCommand(); if(parser[NKey::kLitContext].ThereIs) if (!GetNumber(parser[NKey::kLitContext].PostStrings[0], litContextBits)) IncorrectCommand(); if(parser[NKey::kLitPos].ThereIs) if (!GetNumber(parser[NKey::kLitPos].PostStrings[0], litPosBits)) IncorrectCommand(); if(parser[NKey::kPosBits].ThereIs) if (!GetNumber(parser[NKey::kPosBits].PostStrings[0], posStateBits)) IncorrectCommand(); PROPID propIDs[] = { NCoderPropID::kDictionarySize, NCoderPropID::kPosStateBits, NCoderPropID::kLitContextBits, NCoderPropID::kLitPosBits, NCoderPropID::kAlgorithm, NCoderPropID::kNumFastBytes, NCoderPropID::kMatchFinder, NCoderPropID::kEndMarker }; const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]); /* NWindows::NCOM::CPropVariant properties[kNumProps]; properties[0] = UInt32(dictionary); properties[1] = UInt32(posStateBits); properties[2] = UInt32(litContextBits); properties[3] = UInt32(litPosBits); properties[4] = UInt32(algorithm); properties[5] = UInt32(numFastBytes); properties[6] = mf; properties[7] = eos; */ PROPVARIANT properties[kNumProps]; for (int p = 0; p < 6; p++) properties[p].vt = VT_UI4; properties[0].ulVal = UInt32(dictionary); properties[1].ulVal = UInt32(posStateBits); properties[2].ulVal = UInt32(litContextBits); properties[3].ulVal = UInt32(litPosBits); properties[4].ulVal = UInt32(algorithm); properties[5].ulVal = UInt32(numFastBytes); properties[6].vt = VT_BSTR; properties[6].bstrVal = (BSTR)(const wchar_t *)mf; properties[7].vt = VT_BOOL; properties[7].boolVal = eos ? VARIANT_TRUE : VARIANT_FALSE; if (encoderSpec->SetCoderProperties(propIDs, properties, kNumProps) != S_OK) IncorrectCommand(); encoderSpec->WriteCoderProperties(outStream); if (eos || stdInMode) fileSize = (UInt64)(Int64)-1; else inStreamSpec->File.GetLength(fileSize); for (int i = 0; i < 8; i++) { Byte b = Byte(fileSize >> (8 * i)); if (outStream->Write(&b, sizeof(b), 0) != S_OK) { fprintf(stderr, "Write error"); return 1; } } HRESULT result = encoder->Code(inStream, outStream, 0, 0, 0); if (result == E_OUTOFMEMORY) { fprintf(stderr, "\nError: Can not allocate memory\n"); return 1; } else if (result != S_OK) { fprintf(stderr, "\nEncoder error = %X\n", (unsigned int)result); return 1; } } else {
HRESULT CArc::OpenStream( CCodecs *codecs, int formatIndex, IInStream *stream, ISequentialInStream *seqStream, IArchiveOpenCallback *callback) { Archive.Release(); ErrorMessage.Empty(); const UString fileName = ExtractFileNameFromPath(Path); UString extension; { int dotPos = fileName.ReverseFind(L'.'); if (dotPos >= 0) extension = fileName.Mid(dotPos + 1); } CIntVector orderIndices; if (formatIndex >= 0) orderIndices.Add(formatIndex); else { int i; int numFinded = 0; for (i = 0; i < codecs->Formats.Size(); i++) if (codecs->Formats[i].FindExtension(extension) >= 0) orderIndices.Insert(numFinded++, i); else orderIndices.Add(i); if (!stream) { if (numFinded != 1) return E_NOTIMPL; orderIndices.DeleteFrom(1); } #ifndef _SFX if (orderIndices.Size() >= 2 && (numFinded == 0 || extension.CompareNoCase(L"exe") == 0)) { CIntVector orderIndices2; CByteBuffer byteBuffer; const size_t kBufferSize = (1 << 21); byteBuffer.SetCapacity(kBufferSize); RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); size_t processedSize = kBufferSize; RINOK(ReadStream(stream, byteBuffer, &processedSize)); if (processedSize == 0) return S_FALSE; const Byte *buf = byteBuffer; CByteBuffer hashBuffer; const UInt32 kNumVals = 1 << (kNumHashBytes * 8); hashBuffer.SetCapacity(kNumVals); Byte *hash = hashBuffer; memset(hash, 0xFF, kNumVals); Byte prevs[256]; if (orderIndices.Size() >= 256) return S_FALSE; int i; for (i = 0; i < orderIndices.Size(); i++) { const CArcInfoEx &ai = codecs->Formats[orderIndices[i]]; const CByteBuffer &sig = ai.StartSignature; if (sig.GetCapacity() < kNumHashBytes) continue; UInt32 v = HASH_VAL(sig, 0); prevs[i] = hash[v]; hash[v] = (Byte)i; } processedSize -= (kNumHashBytes - 1); for (UInt32 pos = 0; pos < processedSize; pos++) { for (; pos < processedSize && hash[HASH_VAL(buf, pos)] == 0xFF; pos++); if (pos == processedSize) break; UInt32 v = HASH_VAL(buf, pos); Byte *ptr = &hash[v]; int i = *ptr; do { int index = orderIndices[i]; const CArcInfoEx &ai = codecs->Formats[index]; const CByteBuffer &sig = ai.StartSignature; if (sig.GetCapacity() != 0 && pos + sig.GetCapacity() <= processedSize + (kNumHashBytes - 1) && TestSignature(buf + pos, sig, sig.GetCapacity())) { orderIndices2.Add(index); orderIndices[i] = 0xFF; *ptr = prevs[i]; } else ptr = &prevs[i]; i = *ptr; } while (i != 0xFF); } for (i = 0; i < orderIndices.Size(); i++) { int val = orderIndices[i]; if (val != 0xFF) orderIndices2.Add(val); } orderIndices = orderIndices2; } else if (extension == L"000" || extension == L"001") { CByteBuffer byteBuffer; const size_t kBufferSize = (1 << 10); byteBuffer.SetCapacity(kBufferSize); Byte *buffer = byteBuffer; RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); size_t processedSize = kBufferSize; RINOK(ReadStream(stream, buffer, &processedSize)); if (processedSize >= 16) { Byte kRarHeader[] = {0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00}; if (TestSignature(buffer, kRarHeader, 7) && buffer[9] == 0x73 && (buffer[10] & 1) != 0) { for (int i = 0; i < orderIndices.Size(); i++) { int index = orderIndices[i]; const CArcInfoEx &ai = codecs->Formats[index]; if (ai.Name.CompareNoCase(L"rar") != 0) continue; orderIndices.Delete(i--); orderIndices.Insert(0, index); break; } } } } if (orderIndices.Size() >= 2) { int isoIndex = codecs->FindFormatForArchiveType(L"iso"); int udfIndex = codecs->FindFormatForArchiveType(L"udf"); int iIso = -1; int iUdf = -1; for (int i = 0; i < orderIndices.Size(); i++) { if (orderIndices[i] == isoIndex) iIso = i; if (orderIndices[i] == udfIndex) iUdf = i; } if (iUdf > iIso && iIso >= 0) { orderIndices[iUdf] = isoIndex; orderIndices[iIso] = udfIndex; } } #endif } for (int i = 0; i < orderIndices.Size(); i++) { if (stream) { RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); } CMyComPtr<IInArchive> archive; FormatIndex = orderIndices[i]; RINOK(codecs->CreateInArchive(FormatIndex, archive)); if (!archive) continue; #ifdef EXTERNAL_CODECS { CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo; archive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); if (setCompressCodecsInfo) { RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs)); } } #endif // OutputDebugStringW(codecs->Formats[FormatIndex].Name); HRESULT result; if (stream) result = archive->Open(stream, &kMaxCheckStartPosition, callback); else { CMyComPtr<IArchiveOpenSeq> openSeq; archive.QueryInterface(IID_IArchiveOpenSeq, (void **)&openSeq); if (!openSeq) return E_NOTIMPL; result = openSeq->OpenSeq(seqStream); } if (result == S_FALSE) continue; RINOK(result); { NCOM::CPropVariant prop; archive->GetArchiveProperty(kpidError, &prop); if (prop.vt != VT_EMPTY) ErrorMessage = (prop.vt == VT_BSTR) ? prop.bstrVal : L"Unknown error"; } Archive = archive; const CArcInfoEx &format = codecs->Formats[FormatIndex]; if (format.Exts.Size() == 0) DefaultName = GetDefaultName2(fileName, L"", L""); else { int subExtIndex = format.FindExtension(extension); if (subExtIndex < 0) subExtIndex = 0; const CArcExtInfo &extInfo = format.Exts[subExtIndex]; DefaultName = GetDefaultName2(fileName, extInfo.Ext, extInfo.AddExt); } return S_OK; } return S_FALSE; }
static HRESULT Update2( DECL_EXTERNAL_CODECS_LOC_VARS IInStream *inStream, const CArchiveDatabaseEx *database, const CObjectVector<CUpdateItem> &updateItems, ISequentialOutStream *seqOutStream, IArchiveUpdateCallback *updateCallback, const CUpdateOptions &options) { UInt64 numSolidFiles = options.NumSolidFiles; if (numSolidFiles == 0) numSolidFiles = 1; /* CMyComPtr<IOutStream> outStream; RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream)); if (!outStream) return E_NOTIMPL; */ UInt64 startBlockSize = database != 0 ? database->ArchiveInfo.StartPosition: 0; if (startBlockSize > 0 && !options.RemoveSfxBlock) { RINOK(WriteRange(inStream, seqOutStream, 0, startBlockSize, NULL)); } CRecordVector<int> fileIndexToUpdateIndexMap; if (database != 0) { fileIndexToUpdateIndexMap.Reserve(database->Files.Size()); for (int i = 0; i < database->Files.Size(); i++) fileIndexToUpdateIndexMap.Add(-1); } int i; for(i = 0; i < updateItems.Size(); i++) { int index = updateItems[i].IndexInArchive; if (index != -1) fileIndexToUpdateIndexMap[index] = i; } CRecordVector<int> folderRefs; if (database != 0) { for(i = 0; i < database->Folders.Size(); i++) { CNum indexInFolder = 0; CNum numCopyItems = 0; CNum numUnPackStreams = database->NumUnPackStreamsVector[i]; for (CNum fileIndex = database->FolderStartFileIndex[i]; indexInFolder < numUnPackStreams; fileIndex++) { if (database->Files[fileIndex].HasStream) { indexInFolder++; int updateIndex = fileIndexToUpdateIndexMap[fileIndex]; if (updateIndex >= 0) if (!updateItems[updateIndex].NewData) numCopyItems++; } } if (numCopyItems != numUnPackStreams && numCopyItems != 0) return E_NOTIMPL; // It needs repacking !!! if (numCopyItems > 0) folderRefs.Add(i); } folderRefs.Sort(CompareFolderRefs, (void *)database); } CArchiveDatabase newDatabase; //////////////////////////// COutArchive archive; RINOK(archive.Create(seqOutStream, false)); RINOK(archive.SkeepPrefixArchiveHeader()); UInt64 complexity = 0; for(i = 0; i < folderRefs.Size(); i++) complexity += database->GetFolderFullPackSize(folderRefs[i]); UInt64 inSizeForReduce = 0; for(i = 0; i < updateItems.Size(); i++) { const CUpdateItem &updateItem = updateItems[i]; if (updateItem.NewData) { complexity += updateItem.Size; if (numSolidFiles == 1) { if (updateItem.Size > inSizeForReduce) inSizeForReduce = updateItem.Size; } else inSizeForReduce += updateItem.Size; } } RINOK(updateCallback->SetTotal(complexity)); complexity = 0; RINOK(updateCallback->SetCompleted(&complexity)); CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(updateCallback, true); ///////////////////////////////////////// // Write Copy Items for(i = 0; i < folderRefs.Size(); i++) { int folderIndex = folderRefs[i]; lps->ProgressOffset = complexity; UInt64 packSize = database->GetFolderFullPackSize(folderIndex); RINOK(WriteRange(inStream, archive.SeqStream, database->GetFolderStreamPos(folderIndex, 0), packSize, progress)); complexity += packSize; const CFolder &folder = database->Folders[folderIndex]; CNum startIndex = database->FolderStartPackStreamIndex[folderIndex]; for (int j = 0; j < folder.PackStreams.Size(); j++) { newDatabase.PackSizes.Add(database->PackSizes[startIndex + j]); // newDatabase.PackCRCsDefined.Add(database.PackCRCsDefined[startIndex + j]); // newDatabase.PackCRCs.Add(database.PackCRCs[startIndex + j]); } newDatabase.Folders.Add(folder); CNum numUnPackStreams = database->NumUnPackStreamsVector[folderIndex]; newDatabase.NumUnPackStreamsVector.Add(numUnPackStreams); CNum indexInFolder = 0; for (CNum fi = database->FolderStartFileIndex[folderIndex]; indexInFolder < numUnPackStreams; fi++) { CFileItem file = database->Files[fi]; if (file.HasStream) { indexInFolder++; int updateIndex = fileIndexToUpdateIndexMap[fi]; if (updateIndex >= 0) { const CUpdateItem &updateItem = updateItems[updateIndex]; if (updateItem.NewProperties) { CFileItem file2; FromUpdateItemToFileItem(updateItem, file2); file2.UnPackSize = file.UnPackSize; file2.FileCRC = file.FileCRC; file2.IsFileCRCDefined = file.IsFileCRCDefined; file2.HasStream = file.HasStream; file = file2; } } newDatabase.Files.Add(file); } } } ///////////////////////////////////////// // Compress New Files CObjectVector<CSolidGroup> groups; SplitFilesToGroups(*options.Method, options.UseFilters, options.MaxFilter, updateItems, groups); const UInt32 kMinReduceSize = (1 << 16); if (inSizeForReduce < kMinReduceSize) inSizeForReduce = kMinReduceSize; for (int groupIndex = 0; groupIndex < groups.Size(); groupIndex++) { const CSolidGroup &group = groups[groupIndex]; int numFiles = group.Indices.Size(); if (numFiles == 0) continue; CRecordVector<CRefItem> refItems; refItems.Reserve(numFiles); bool sortByType = (numSolidFiles > 1); for (i = 0; i < numFiles; i++) refItems.Add(CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType)); refItems.Sort(CompareUpdateItems, (void *)&sortByType); CRecordVector<UInt32> indices; indices.Reserve(numFiles); for (i = 0; i < numFiles; i++) { UInt32 index = refItems[i].Index; indices.Add(index); /* const CUpdateItem &updateItem = updateItems[index]; CFileItem file; if (updateItem.NewProperties) FromUpdateItemToFileItem(updateItem, file); else file = database.Files[updateItem.IndexInArchive]; if (file.IsAnti || file.IsDirectory) return E_FAIL; newDatabase.Files.Add(file); */ } CEncoder encoder(group.Method); for (i = 0; i < numFiles;) { UInt64 totalSize = 0; int numSubFiles; UString prevExtension; for (numSubFiles = 0; i + numSubFiles < numFiles && numSubFiles < numSolidFiles; numSubFiles++) { const CUpdateItem &updateItem = updateItems[indices[i + numSubFiles]]; totalSize += updateItem.Size; if (totalSize > options.NumSolidBytes) break; if (options.SolidExtension) { UString ext = updateItem.GetExtension(); if (numSubFiles == 0) prevExtension = ext; else if (ext.CompareNoCase(prevExtension) != 0) break; } } if (numSubFiles < 1) numSubFiles = 1; CFolderInStream *inStreamSpec = new CFolderInStream; CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec); inStreamSpec->Init(updateCallback, &indices[i], numSubFiles); CFolder folderItem; int startPackIndex = newDatabase.PackSizes.Size(); RINOK(encoder.Encode( EXTERNAL_CODECS_LOC_VARS solidInStream, NULL, &inSizeForReduce, folderItem, archive.SeqStream, newDatabase.PackSizes, progress)); for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++) lps->OutSize += newDatabase.PackSizes[startPackIndex]; lps->InSize += folderItem.GetUnPackSize(); // for() // newDatabase.PackCRCsDefined.Add(false); // newDatabase.PackCRCs.Add(0); newDatabase.Folders.Add(folderItem); CNum numUnPackStreams = 0; for (int subIndex = 0; subIndex < numSubFiles; subIndex++) { const CUpdateItem &updateItem = updateItems[indices[i + subIndex]]; CFileItem file; if (updateItem.NewProperties) FromUpdateItemToFileItem(updateItem, file); else file = database->Files[updateItem.IndexInArchive]; if (file.IsAnti || file.IsDirectory) return E_FAIL; /* CFileItem &file = newDatabase.Files[ startFileIndexInDatabase + i + subIndex]; */ if (!inStreamSpec->Processed[subIndex]) { continue; // file.Name += L".locked"; } file.FileCRC = inStreamSpec->CRCs[subIndex]; file.UnPackSize = inStreamSpec->Sizes[subIndex]; if (file.UnPackSize != 0) { file.IsFileCRCDefined = true; file.HasStream = true; numUnPackStreams++; } else { file.IsFileCRCDefined = false; file.HasStream = false; } newDatabase.Files.Add(file); } // numUnPackStreams = 0 is very bad case for locked files // v3.13 doesn't understand it. newDatabase.NumUnPackStreamsVector.Add(numUnPackStreams); i += numSubFiles; } } { ///////////////////////////////////////// // Write Empty Files & Folders CRecordVector<int> emptyRefs; for(i = 0; i < updateItems.Size(); i++) { const CUpdateItem &updateItem = updateItems[i]; if (updateItem.NewData) { if (updateItem.HasStream()) continue; } else if (updateItem.IndexInArchive != -1) if (database->Files[updateItem.IndexInArchive].HasStream) continue; emptyRefs.Add(i); } emptyRefs.Sort(CompareEmptyItems, (void *)&updateItems); for(i = 0; i < emptyRefs.Size(); i++) { const CUpdateItem &updateItem = updateItems[emptyRefs[i]]; CFileItem file; if (updateItem.NewProperties) FromUpdateItemToFileItem(updateItem, file); else file = database->Files[updateItem.IndexInArchive]; newDatabase.Files.Add(file); } } /* if (newDatabase.Files.Size() != updateItems.Size()) return E_FAIL; */ return archive.WriteDatabase(EXTERNAL_CODECS_LOC_VARS newDatabase, options.HeaderMethod, options.HeaderOptions); }