// PanelItemOpen.cpp #include "StdAfx.h" // For compilers that support precompilation, includes "wx/wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include "wx/wx.h" #endif #include "wx/mimetype.h" #undef _WIN32 // #include #include "../../../Common/AutoPtr.h" #include "../../../Common/StringConvert.h" // #include "../../../Windows/ProcessUtils.h" #include "../../../Windows/FileName.h" #include "../../../Windows/PropVariant.h" #include "../../../Windows/PropVariantConv.h" #include "../../Common/FileStreams.h" #include "../../Common/StreamObjects.h" #include "../Common/ExtractingFilePath.h" #include "App.h" #include "FileFolderPluginOpen.h" #include "FormatUtils.h" #include "LangUtils.h" #include "RegistryUtils.h" #include "UpdateCallback100.h" #include "resource.h" using namespace NWindows; using namespace NSynchronization; using namespace NFile; using namespace NDir; extern UInt64 g_RAM_Size; #ifndef _UNICODE extern bool g_IsNT; #endif static CFSTR kTempDirPrefix = FTEXT("7zO"); #if 0 // ifndef UNDER_CE class CProcessSnapshot { HANDLE _handle; public: CProcessSnapshot(): _handle(INVALID_HANDLE_VALUE) {}; ~CProcessSnapshot() { Close(); } bool Close() { if (_handle == INVALID_HANDLE_VALUE) return true; if (!::CloseHandle(_handle)) return false; _handle = INVALID_HANDLE_VALUE; return true; } bool Create() { _handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); return (_handle != INVALID_HANDLE_VALUE); } bool GetFirstProcess(PROCESSENTRY32 *pe) { return BOOLToBool(Process32First(_handle, pe)); } bool GetNextProcess(PROCESSENTRY32 *pe) { return BOOLToBool(Process32Next(_handle, pe)); } }; typedef DWORD (WINAPI *GetProcessIdFunc)(HANDLE process); class CChildProcesses { #ifndef UNDER_CE CRecordVector _ids; #endif public: CRecordVector Handles; CRecordVector NeedWait; ~CChildProcesses() { CloseAll(); } void DisableWait(int index) { NeedWait[index] = false; } void CloseAll() { FOR_VECTOR (i, Handles) { HANDLE h = Handles[i]; if (h != NULL) CloseHandle(h); } Handles.Clear(); NeedWait.Clear(); } void AddProcess(HANDLE h) { #ifndef UNDER_CE GetProcessIdFunc func = (GetProcessIdFunc)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "GetProcessId"); if (func) _ids.AddToUniqueSorted(func(h)); #endif Handles.Add(h); NeedWait.Add(true); } void Update() { #ifndef UNDER_CE CRecordVector ids, parents; { CProcessSnapshot snapshot; if (snapshot.Create()) { PROCESSENTRY32 pe; memset(&pe, 0, sizeof(pe)); pe.dwSize = sizeof(pe); BOOL res = snapshot.GetFirstProcess(&pe); while (res) { ids.Add(pe.th32ProcessID); parents.Add(pe.th32ParentProcessID); res = snapshot.GetNextProcess(&pe); } } } for (;;) { unsigned i; for (i = 0; i < ids.Size(); i++) { DWORD id = ids[i]; if (_ids.FindInSorted(parents[i]) >= 0 && _ids.FindInSorted(id) < 0) { HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, id); if (hProcess) { _ids.AddToUniqueSorted(id); Handles.Add(hProcess); NeedWait.Add(true); break; } } } if (i == ids.Size()) break; } #endif } }; #endif struct CTmpProcessInfo: public CTempFileInfo { HANDLE ProcessHandle; // CChildProcesses Processes; HWND Window; UString FullPathFolderPrefix; bool UsePassword; UString Password; CTmpProcessInfo(): UsePassword(false) {} }; class CTmpProcessInfoRelease { CTmpProcessInfo *_tmpProcessInfo; public: bool _needDelete; CTmpProcessInfoRelease(CTmpProcessInfo &tpi): _tmpProcessInfo(&tpi), _needDelete(true) {} ~CTmpProcessInfoRelease() { if (_needDelete) _tmpProcessInfo->DeleteDirAndFile(); } }; HRESULT CPanel::OpenItemAsArchive(IInStream *inStream, const CTempFileInfo &tempFileInfo, const UString &virtualFilePath, const UString &arcFormat, bool &encrypted) { encrypted = false; CFolderLink folderLink; (CTempFileInfo &)folderLink = tempFileInfo; if (inStream) folderLink.IsVirtual = true; else { if (!folderLink.FileInfo.Find(folderLink.FilePath)) return ::GetLastError(); if (folderLink.FileInfo.IsDir()) return S_FALSE; folderLink.IsVirtual = false; } folderLink.VirtualPath = virtualFilePath; CMyComPtr newFolder; // _passwordIsDefined = false; // _password.Empty(); NDLL::CLibrary library; UString password; RINOK(OpenFileFolderPlugin(inStream, folderLink.FilePath.IsEmpty() ? us2fs(virtualFilePath) : folderLink.FilePath, arcFormat, &library, &newFolder, GetParent(), encrypted, password)); folderLink.Password = password; folderLink.UsePassword = encrypted; if (_folder) folderLink.ParentFolderPath = GetFolderPath(_folder); else folderLink.ParentFolderPath = _currentFolderPrefix; if (!_parentFolders.IsEmpty()) folderLink.ParentFolder = _folder; _parentFolders.Add(folderLink); _parentFolders.Back().Library.Attach(_library.Detach()); ReleaseFolder(); _library.Free(); SetNewFolder(newFolder); _library.Attach(library.Detach()); _flatMode = _flatModeForArc; CMyComPtr getFolderArcProps; _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); _thereAreDeletedItems = false; if (getFolderArcProps) { CMyComPtr arcProps; getFolderArcProps->GetFolderArcProps(&arcProps); if (arcProps) { /* UString s; UInt32 numLevels; if (arcProps->GetArcNumLevels(&numLevels) != S_OK) numLevels = 0; for (UInt32 level2 = 0; level2 <= numLevels; level2++) { UInt32 level = numLevels - level2; PROPID propIDs[] = { kpidError, kpidPath, kpidType, kpidErrorType } ; UString values[4]; for (Int32 i = 0; i < 4; i++) { CMyComBSTR name; NCOM::CPropVariant prop; if (arcProps->GetArcProp(level, propIDs[i], &prop) != S_OK) continue; if (prop.vt != VT_EMPTY) values[i] = (prop.vt == VT_BSTR) ? prop.bstrVal : L"?"; } UString s2; if (!values[3].IsEmpty()) { s2 = L"Can not open the file as [" + values[3] + L"] archive"; if (level2 != 0) s2 += L"\nThe file is open as [" + values[2] + L"] archive"; } if (!values[0].IsEmpty()) { if (!s2.IsEmpty()) s2.Add_LF(); s2 += L"["; s2 += values[2]; s2 += L"] Error: "; s2 += values[0]; } if (!s2.IsEmpty()) { if (!s.IsEmpty()) s += L"--------------------\n"; s += values[1]; s.Add_LF(); s += s2; } } */ /* if (!s.IsEmpty()) MessageBoxWarning(s); else */ // after MessageBoxWarning it throws exception in nested archives in Debug Mode. why ?. // MessageBoxWarning(L"test error"); } } return S_OK; } HRESULT CPanel::OpenItemAsArchive(const UString &relPath, const UString &arcFormat, bool &encrypted) { CTempFileInfo tfi; tfi.RelPath = relPath; tfi.FolderPath = us2fs(GetFsPath()); const UString fullPath = GetFsPath() + relPath; tfi.FilePath = us2fs(fullPath); return OpenItemAsArchive(NULL, tfi, fullPath, arcFormat, encrypted); } HRESULT CPanel::OpenItemAsArchive(int index, const wchar_t *type) { CDisableTimerProcessing disableTimerProcessing1(*this); CDisableNotify disableNotify(*this); bool encrypted; HRESULT res = OpenItemAsArchive(GetItemRelPath2(index), type ? type : L"", encrypted); if (res != S_OK) { RefreshTitle(true); // in case of error we must refresh changed title of 7zFM return res; } RefreshListCtrl(); return S_OK; } HRESULT CPanel::OpenParentArchiveFolder() { CDisableTimerProcessing disableTimerProcessing(*this); CDisableNotify disableNotify(*this); if (_parentFolders.Size() < 2) return S_OK; const CFolderLink &folderLinkPrev = _parentFolders[_parentFolders.Size() - 2]; const CFolderLink &folderLink = _parentFolders.Back(); NFind::CFileInfo newFileInfo; if (newFileInfo.Find(folderLink.FilePath)) { if (folderLink.WasChanged(newFileInfo)) { UString message = MyFormatNew(IDS_WANT_UPDATE_MODIFIED_FILE, folderLink.RelPath); if (::MessageBoxW((HWND)*this, message, L"7-Zip", MB_OKCANCEL | MB_ICONQUESTION) == IDOK) { if (OnOpenItemChanged(folderLink.FileIndex, fs2us(folderLink.FilePath), folderLinkPrev.UsePassword, folderLinkPrev.Password) != S_OK) { ::MessageBoxW((HWND)*this, MyFormatNew(IDS_CANNOT_UPDATE_FILE, fs2us(folderLink.FilePath)), L"7-Zip", MB_OK | MB_ICONSTOP); return S_OK; } } } } folderLink.DeleteDirAndFile(); return S_OK; } static const char *kStartExtensions = #ifdef UNDER_CE " cab" #endif " exe bat com" " chm" " msi doc xls ppt pps wps wpt wks xlr wdb vsd pub" " docx docm dotx dotm xlsx xlsm xltx xltm xlsb xps" " xlam pptx pptm potx potm ppam ppsx ppsm xsn" " mpp" " msg" " dwf" " flv swf" " odt ods" " wb3" " pdf" " "; static bool FindExt(const char *p, const UString &name) { int dotPos = name.ReverseFind_Dot(); if (dotPos < 0 || dotPos == (int)name.Len() - 1) return false; AString s; for (unsigned pos = dotPos + 1;; pos++) { wchar_t c = name[pos]; if (c == 0) break; if (c >= 0x80) return false; s += (char)MyCharLower_Ascii((char)c); } for (unsigned i = 0; p[i] != 0;) { unsigned j; for (j = i; p[j] != ' '; j++); if (s.Len() == j - i && memcmp(p + i, (const char *)s, s.Len()) == 0) return true; i = j + 1; } return false; } static bool DoItemAlwaysStart(const UString &name) { return FindExt(kStartExtensions, name); } UString GetQuotedString(const UString &s); static void StartEditApplication(const UString &path, bool useEditor, HWND window /* , CProcess &process */ ) { UString command; ReadRegEditor(useEditor, command); if (command.IsEmpty()) { #ifdef _WIN32 #ifdef UNDER_CE command = L"\\Windows\\"; #else FString winDir; if (!GetWindowsDir(winDir)) return 0; NName::NormalizeDirPathPrefix(winDir); command = fs2us(winDir); #endif command += L"notepad.exe"; #else command += L"vi"; #endif } #ifdef _WIN32 HRESULT res = process.Create(command, GetQuotedString(path), NULL); if (res != SZ_OK) ::MessageBoxW(window, LangString(IDS_CANNOT_START_EDITOR), L"7-Zip", MB_OK | MB_ICONSTOP); return res; #else wxString cmd = (const wchar_t *)command; long pid = wxExecute(cmd, wxEXEC_ASYNC); if (pid) return ; ::MessageBoxW(window, LangString(IDS_CANNOT_START_EDITOR), L"7-Zip", MB_OK | MB_ICONSTOP); #endif } void CApp::DiffFiles() { const CPanel &panel = GetFocusedPanel(); CRecordVector indices; panel.GetSelectedItemsIndices(indices); UString path1, path2; if (indices.Size() == 2) { path1 = panel.GetItemFullPath(indices[0]); path2 = panel.GetItemFullPath(indices[1]); } else if (indices.Size() == 1 && NumPanels >= 2) { const CPanel &destPanel = Panels[1 - LastFocusedPanel]; path1 = panel.GetItemFullPath(indices[0]); CRecordVector indices2; destPanel.GetSelectedItemsIndices(indices2); if (indices2.Size() == 1) path2 = destPanel.GetItemFullPath(indices2[0]); else { UString relPath = panel.GetItemRelPath2(indices[0]); if (panel._flatMode && !destPanel._flatMode) relPath = panel.GetItemName(indices[0]); path2 = destPanel._currentFolderPrefix + relPath; } } else return; UString command; ReadRegDiff(command); if (command.IsEmpty()) return; UString param = GetQuotedString(path1); param.Add_Space(); param += GetQuotedString(path2); #ifdef _WIN32 HRESULT res = MyCreateProcess(command, param); if (res == SZ_OK) return; #else wxString cmd = (const wchar_t *)command; cmd += L" "; cmd += (const wchar_t *)param; long pid = wxExecute(cmd, wxEXEC_ASYNC); if (pid) return ; #endif ::MessageBoxW(_window, LangString(IDS_CANNOT_START_EDITOR), L"7-Zip", MB_OK | MB_ICONSTOP); } #ifndef _UNICODE typedef BOOL (WINAPI * ShellExecuteExWP)(LPSHELLEXECUTEINFOW lpExecInfo); #endif static void StartApplication(const UString &dir, const UString &path, HWND window /* , CProcess &process */ ) { // FIXME extern const TCHAR * nameWindowToUnix(const TCHAR * lpFileName); UString tmpPath = path; wxString filename(nameWindowToUnix(tmpPath)); wxString ext = filename.AfterLast(_T('.')); printf("StartApplication(%ls) ext='%ls'\n",(const wchar_t *)filename,(const wchar_t *)ext); if ( ! ext.empty() ) { wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext); // printf("StartApplication(%ls) ft=%p\n",(const wchar_t *)filename,ft); if (ft) { wxString cmd; // wxString type; ft->GetMimeType(&type); wxFileType::MessageParameters params(filename); // , type); bool ok = ft->GetOpenCommand(&cmd, params); // printf("StartApplication(%ls) ok=%d\n",(const wchar_t *)filename,(int)ok); delete ft; if ( ok ) { printf("StartApplication(%ls) cmd='%ls'\n",(const wchar_t *)filename,(const wchar_t *)cmd); long pid = wxExecute(cmd, wxEXEC_ASYNC); if (pid) return ; } } } ::MessageBoxW(window, // NError::MyFormatMessageW(::GetLastError()), L"There is no application associated with the given file name extension", L"7-Zip", MB_OK | MB_ICONSTOP); } static void StartApplicationDontWait(const UString &dir, const UString &path, HWND window) { // CProcess process; StartApplication(dir, path, window /* , process */ ); } void CPanel::EditItem(int index, bool useEditor) { if (!_parentFolders.IsEmpty()) { OpenItemInArchive(index, false, true, true, useEditor); return; } // CProcess process; StartEditApplication(GetItemFullPath(index), useEditor, (HWND)*this /* , process */ ); } void CPanel::OpenFolderExternal(int index) { UString fsPrefix = GetFsPath(); UString name; if (index == kParentIndex) { int pos = fsPrefix.ReverseFind_PathSepar(); if (pos >= 0 && pos == (int)fsPrefix.Len() - 1) { UString s = fsPrefix.Left(pos); pos = s.ReverseFind_PathSepar(); if (pos >= 0) fsPrefix.SetFrom(s, pos + 1); } name = fsPrefix; } else name = fsPrefix + GetItemRelPath(index) + WCHAR_PATH_SEPARATOR; StartApplicationDontWait(fsPrefix, name, (HWND)*this); } bool CPanel::IsVirus_Message(const UString &name) { UString name2; const wchar_t cRLO = (wchar_t)0x202E; bool isVirus = false; bool isSpaceError = false; name2 = name; if (name2.Find(cRLO) >= 0) { UString badString = cRLO; name2.Replace(badString, L"[RLO]"); isVirus = true; } { const wchar_t *kVirusSpaces = L" "; // const unsigned kNumSpaces = strlen(kVirusSpaces); for (;;) { int pos = name2.Find(kVirusSpaces); if (pos < 0) break; isVirus = true; isSpaceError = true; name2.Replace(kVirusSpaces, L" "); } } if (!isVirus) return false; UString s = LangString(IDS_VIRUS); if (!isSpaceError) { int pos1 = s.Find(L'('); if (pos1 >= 0) { int pos2 = s.Find(L')', pos1 + 1); if (pos2 >= 0) { s.Delete(pos1, pos2 + 1 - pos1); if (pos1 > 0 && s[pos1 - 1] == ' ' && s[pos1] == '.') s.Delete(pos1 - 1); } } } UString name3 = name; name3.Replace(L'\n', L'_'); name2.Replace(L'\n', L'_'); s.Add_LF(); s += name2; s.Add_LF(); s += name3; MessageBoxMyError(s); return true; } void CPanel::OpenItem(int index, bool tryInternal, bool tryExternal, const wchar_t *type) { CDisableTimerProcessing disableTimerProcessing(*this); UString name = GetItemRelPath2(index); if (IsVirus_Message(name)) return; if (!_parentFolders.IsEmpty()) { OpenItemInArchive(index, tryInternal, tryExternal, false, false, type); return; } CDisableNotify disableNotify(*this); UString prefix = GetFsPath(); UString fullPath = prefix + name; if (tryInternal) if (!tryExternal || !DoItemAlwaysStart(name)) { HRESULT res = OpenItemAsArchive(index, type); disableNotify.Restore(); // we must restore to allow text notification update InvalidateList(); if (res == S_OK || res == E_ABORT) return; if (res != S_FALSE) { MessageBoxError(res); return; } } if (tryExternal) { // SetCurrentDirectory opens HANDLE to folder!!! // NDirectory::MySetCurrentDirectory(prefix); StartApplicationDontWait(prefix, fullPath, (HWND)*this); } } class CThreadCopyFrom: public CProgressThreadVirt { HRESULT ProcessVirt(); public: UString FullPath; UInt32 ItemIndex; CMyComPtr FolderOperations; CMyComPtr UpdateCallback; CUpdateCallback100Imp *UpdateCallbackSpec; }; HRESULT CThreadCopyFrom::ProcessVirt() { return FolderOperations->CopyFromFile(ItemIndex, FullPath, UpdateCallback); } HRESULT CPanel::OnOpenItemChanged(UInt32 index, const wchar_t *fullFilePath, bool usePassword, const UString &password) { if (!_folderOperations) { MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED); return E_FAIL; } CThreadCopyFrom t; t.UpdateCallbackSpec = new CUpdateCallback100Imp; t.UpdateCallback = t.UpdateCallbackSpec; t.UpdateCallbackSpec->ProgressDialog = &t.ProgressDialog; t.ItemIndex = index; t.FullPath = fullFilePath; t.FolderOperations = _folderOperations; t.UpdateCallbackSpec->Init(); t.UpdateCallbackSpec->PasswordIsDefined = usePassword; t.UpdateCallbackSpec->Password = password; RINOK(t.Create(GetItemName(index), (HWND)*this)); return t.Result; } LRESULT CPanel::OnOpenItemChanged(LPARAM lParam) { CTmpProcessInfo &tpi = *(CTmpProcessInfo *)lParam; if (tpi.FullPathFolderPrefix != _currentFolderPrefix) return 0; UInt32 fileIndex = tpi.FileIndex; UInt32 numItems; _folder->GetNumberOfItems(&numItems); // This code is not 100% OK for cases when there are several files with // tpi.RelPath name and there are changes in archive before update. // So tpi.FileIndex can point to another file. if (fileIndex >= numItems || GetItemRelPath(fileIndex) != tpi.RelPath) { UInt32 i; for (i = 0; i < numItems; i++) if (GetItemRelPath(i) == tpi.RelPath) break; if (i == numItems) return 0; fileIndex = i; } CSelectedState state; SaveSelectedState(state); CDisableNotify disableNotify(*this); // do we need it?? HRESULT result = OnOpenItemChanged(fileIndex, fs2us(tpi.FilePath), tpi.UsePassword, tpi.Password); RefreshListCtrl(state); if (result != S_OK) return 0; return 1; } class CExitEventLauncher { public: NWindows::NSynchronization::CManualResetEvent _exitEvent; CExitEventLauncher() { if (_exitEvent.Create(false) != S_OK) throw 9387173; }; ~CExitEventLauncher() { _exitEvent.Set(); } } g_ExitEventLauncher; #ifdef _WIN32 static THREAD_FUNC_DECL MyThreadFunction(void *param) { CMyAutoPtr tmpProcessInfoPtr((CTmpProcessInfo *)param); CTmpProcessInfo *tpi = tmpProcessInfoPtr.get(); CChildProcesses &processes = tpi->Processes; for (;;) { CRecordVector handles; CRecordVector indices; FOR_VECTOR (i, processes.Handles) { if (processes.NeedWait[i]) { handles.Add(processes.Handles[i]); indices.Add(i); } } if (handles.IsEmpty()) break; handles.Add(g_ExitEventLauncher._exitEvent); DWORD waitResult = ::WaitForMultipleObjects(handles.Size(), &handles.Front(), FALSE, INFINITE); if (waitResult >= (DWORD)handles.Size() - 1) { processes.CloseAll(); return waitResult >= (DWORD)handles.Size() ? 1 : 0; } processes.Update(); processes.DisableWait(indices[waitResult]); } NFind::CFileInfo newFileInfo; if (newFileInfo.Find(tpi->FilePath)) { if (tpi->WasChanged(newFileInfo)) { UString message = MyFormatNew(IDS_WANT_UPDATE_MODIFIED_FILE, tpi->RelPath); if (::MessageBoxW(g_HWND, message, L"7-Zip", MB_OKCANCEL | MB_ICONQUESTION) == IDOK) { if (SendMessage(tpi->Window, kOpenItemChanged, 0, (LONG_PTR)tpi) != 1) { ::MessageBoxW(g_HWND, MyFormatNew(IDS_CANNOT_UPDATE_FILE, fs2us(tpi->FilePath)), L"7-Zip", MB_OK | MB_ICONSTOP); return 0; } } } } tpi->DeleteDirAndFile(); return 0; } #endif #if defined(_WIN32) && !defined(UNDER_CE) static const FChar *k_ZoneId_StreamName = FTEXT(":Zone.Identifier"); #endif #ifndef UNDER_CE static void ReadZoneFile(CFSTR fileName, CByteBuffer &buf) { buf.Free(); NIO::CInFile file; if (!file.Open(fileName)) return; UInt64 fileSize; if (!file.GetLength(fileSize)) return; if (fileSize == 0 || fileSize >= ((UInt32)1 << 20)) return; buf.Alloc((size_t)fileSize); UInt32 processed; if (file.Read(buf, (UInt32)fileSize, processed) && processed == fileSize) return; buf.Free(); } static bool WriteZoneFile(CFSTR fileName, const CByteBuffer &buf) { NIO::COutFile file; if (!file.Create(fileName, true)) return false; UInt32 processed; if (!file.Write(buf, (UInt32)buf.Size(), processed)) return false; return processed == buf.Size(); } #endif /* class CBufSeqOutStream_WithFile: public ISequentialOutStream, public CMyUnknownImp { Byte *_buffer; size_t _size; size_t _pos; size_t _fileWritePos; bool fileMode; public: bool IsStreamInMem() const { return !fileMode; } size_t GetMemStreamWrittenSize() const { return _pos; } // ISequentialOutStream *FileStream; FString FilePath; COutFileStream *outFileStreamSpec; CMyComPtr outFileStream; CBufSeqOutStream_WithFile(): outFileStreamSpec(NULL) {} void Init(Byte *buffer, size_t size) { fileMode = false; _buffer = buffer; _pos = 0; _size = size; _fileWritePos = 0; } HRESULT FlushToFile(); size_t GetPos() const { return _pos; } MY_UNKNOWN_IMP STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; static const UInt32 kBlockSize = ((UInt32)1 << 31); STDMETHODIMP CBufSeqOutStream_WithFile::Write(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (!fileMode) { if (_size - _pos >= size) { if (size != 0) { memcpy(_buffer + _pos, data, size); _pos += size; } if (processedSize) *processedSize = (UInt32)size; return S_OK; } fileMode = true; } RINOK(FlushToFile()); return outFileStream->Write(data, size, processedSize); } HRESULT CBufSeqOutStream_WithFile::FlushToFile() { if (!outFileStream) { outFileStreamSpec = new COutFileStream; outFileStream = outFileStreamSpec; if (!outFileStreamSpec->Create(FilePath, false)) { outFileStream.Release(); return E_FAIL; // MessageBoxMyError(UString(L"Can't create file ") + fs2us(tempFilePath)); } } while (_fileWritePos != _pos) { size_t cur = _pos - _fileWritePos; UInt32 curSize = (cur < kBlockSize) ? (UInt32)cur : kBlockSize; UInt32 processedSizeLoc = 0; HRESULT res = outFileStream->Write(_buffer + _fileWritePos, curSize, &processedSizeLoc); _fileWritePos += processedSizeLoc; RINOK(res); if (processedSizeLoc == 0) return E_FAIL; } return S_OK; } */ /* static HRESULT GetTime(IFolderFolder *folder, UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined) { filetimeIsDefined = false; NCOM::CPropVariant prop; RINOK(folder->GetProperty(index, propID, &prop)); if (prop.vt == VT_FILETIME) { filetime = prop.filetime; filetimeIsDefined = (filetime.dwHighDateTime != 0 || filetime.dwLowDateTime != 0); } else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } */ void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bool editMode, bool useEditor, const wchar_t *type) { const UString name = GetItemName(index); const UString relPath = GetItemRelPath(index); if (IsVirus_Message(name)) return; if (!_folderOperations) { MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED); return; } bool tryAsArchive = tryInternal && (!tryExternal || !DoItemAlwaysStart(name)); UString fullVirtPath = _currentFolderPrefix + relPath; CTempDir tempDirectory; if (!tempDirectory.Create(kTempDirPrefix)) { MessageBoxLastError(); return; } FString tempDir = tempDirectory.GetPath(); FString tempDirNorm = tempDir; NName::NormalizeDirPathPrefix(tempDirNorm); const FString tempFilePath = tempDirNorm + us2fs(Get_Correct_FsFile_Name(name)); CTempFileInfo tempFileInfo; tempFileInfo.FileIndex = index; tempFileInfo.RelPath = relPath; tempFileInfo.FolderPath = tempDir; tempFileInfo.FilePath = tempFilePath; tempFileInfo.NeedDelete = true; if (tryAsArchive) { CMyComPtr getStream; _folder.QueryInterface(IID_IInArchiveGetStream, &getStream); if (getStream) { CMyComPtr subSeqStream; getStream->GetStream(index, &subSeqStream); if (subSeqStream) { CMyComPtr subStream; subSeqStream.QueryInterface(IID_IInStream, &subStream); if (subStream) { bool encrypted; HRESULT res = OpenItemAsArchive(subStream, tempFileInfo, fullVirtPath, type ? type : L"", encrypted); if (res == S_OK) { tempDirectory.DisableDeleting(); RefreshListCtrl(); return; } if (res == E_ABORT) return; if (res != S_FALSE) { // probably we must show some message here // return; } } } } } CRecordVector indices; indices.Add(index); UStringVector messages; bool usePassword = false; UString password; if (_parentFolders.Size() > 0) { const CFolderLink &fl = _parentFolders.Back(); usePassword = fl.UsePassword; password = fl.Password; } #if defined(_WIN32) && !defined(UNDER_CE) CByteBuffer zoneBuf; #ifndef _UNICODE if (g_IsNT) #endif if (_parentFolders.Size() > 0) { const CFolderLink &fl = _parentFolders.Front(); if (!fl.IsVirtual && !fl.FilePath.IsEmpty()) ReadZoneFile(fl.FilePath + k_ZoneId_StreamName, zoneBuf); } #endif CVirtFileSystem *virtFileSystemSpec = NULL; CMyComPtr virtFileSystem; bool isAltStream = IsItem_AltStream(index); CCopyToOptions options; options.includeAltStreams = true; options.replaceAltStreamChars = isAltStream; if (tryAsArchive) { NCOM::CPropVariant prop; _folder->GetProperty(index, kpidSize, &prop); UInt64 fileLimit = g_RAM_Size / 4; UInt64 fileSize = 0; if (!ConvertPropVariantToUInt64(prop, fileSize)) fileSize = fileLimit; if (fileSize <= fileLimit && fileSize > 0) { options.streamMode = true; virtFileSystemSpec = new CVirtFileSystem; virtFileSystem = virtFileSystemSpec; // we allow additional total size for small alt streams; virtFileSystemSpec->MaxTotalAllocSize = fileSize + (1 << 10); virtFileSystemSpec->DirPrefix = tempDirNorm; virtFileSystemSpec->Init(); options.VirtFileSystem = virtFileSystem; options.VirtFileSystemSpec = virtFileSystemSpec; } } options.folder = fs2us(tempDirNorm); options.showErrorMessages = true; HRESULT result = CopyTo(options, indices, &messages, usePassword, password); if (_parentFolders.Size() > 0) { CFolderLink &fl = _parentFolders.Back(); fl.UsePassword = usePassword; fl.Password = password; } if (!messages.IsEmpty()) return; if (result != S_OK) { if (result != E_ABORT) MessageBoxError(result); return; } if (options.VirtFileSystem) { if (virtFileSystemSpec->IsStreamInMem()) { const CVirtFile &file = virtFileSystemSpec->Files[0]; size_t streamSize = (size_t)file.Size; CBufInStream *bufInStreamSpec = new CBufInStream; CMyComPtr bufInStream = bufInStreamSpec; bufInStreamSpec->Init(file.Data, streamSize, virtFileSystem); bool encrypted; if (OpenItemAsArchive(bufInStream, tempFileInfo, fullVirtPath, type ? type : L"", encrypted) == S_OK) { tempDirectory.DisableDeleting(); RefreshListCtrl(); return; } if (virtFileSystemSpec->FlushToDisk(true) != S_OK) return; } } #if defined(_WIN32) && !defined(UNDER_CE) if (zoneBuf.Size() != 0) { if (NFind::DoesFileExist(tempFilePath)) { WriteZoneFile(tempFilePath + k_ZoneId_StreamName, zoneBuf); } } #endif if (tryAsArchive) { bool encrypted; if (OpenItemAsArchive(NULL, tempFileInfo, fullVirtPath, type ? type : L"", encrypted) == S_OK) { tempDirectory.DisableDeleting(); RefreshListCtrl(); return; } } CMyAutoPtr tmpProcessInfoPtr(new CTmpProcessInfo()); CTmpProcessInfo *tpi = tmpProcessInfoPtr.get(); tpi->FolderPath = tempDir; tpi->FilePath = tempFilePath; tpi->NeedDelete = true; tpi->UsePassword = usePassword; tpi->Password = password; if (!tpi->FileInfo.Find(tempFilePath)) return; CTmpProcessInfoRelease tmpProcessInfoRelease(*tpi); if (!tryExternal) return; // CProcess process; // HRESULT res; if (editMode) /* res = */ StartEditApplication(fs2us(tempFilePath), useEditor, (HWND)*this /* , process */ ); else /* res = */ StartApplication(fs2us(tempDirNorm), fs2us(tempFilePath), (HWND)*this /* , process */ ); #ifdef _WIN32 if ((HANDLE)process == 0) return; tpi->Window = (HWND)(*this); tpi->FullPathFolderPrefix = _currentFolderPrefix; tpi->FileIndex = index; tpi->RelPath = relPath; tpi->Processes.AddProcess(process.Detach()); NWindows::CThread thread; if (thread.Create(MyThreadFunction, tpi) != S_OK) throw 271824; #endif tempDirectory.DisableDeleting(); tmpProcessInfoPtr.release(); tmpProcessInfoRelease._needDelete = false; } /* static const UINT64 kTimeLimit = UINT64(10000000) * 3600 * 24; static bool CheckDeleteItem(UINT64 currentFileTime, UINT64 folderFileTime) { return (currentFileTime - folderFileTime > kTimeLimit && folderFileTime - currentFileTime > kTimeLimit); } void DeleteOldTempFiles() { UString tempPath; if(!MyGetTempPath(tempPath)) throw 1; UINT64 currentFileTime; NTime::GetCurUtcFileTime(currentFileTime); UString searchWildCard = tempPath + kTempDirPrefix + L"*.tmp"; searchWildCard += WCHAR(NName::kAnyStringWildcard); NFind::CEnumeratorW enumerator(searchWildCard); NFind::CFileInfo fileInfo; while(enumerator.Next(fileInfo)) { if (!fileInfo.IsDir()) continue; const UINT64 &cTime = *(const UINT64 *)(&fileInfo.CTime); if(CheckDeleteItem(cTime, currentFileTime)) RemoveDirectoryWithSubItems(tempPath + fileInfo.Name); } } */