// CompressCall.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 #undef _WIN32 #include #include "../../../Common/IntToString.h" #include "../../../Common/MyCom.h" #include "../../../Common/Random.h" #include "../../../Common/StringConvert.h" #include "../../../Windows/DLL.h" #include "../../../Windows/ErrorMsg.h" #include "../../../Windows/FileDir.h" // #include "../../../Windows/FileMapping.h" // #include "../../../Windows/ProcessUtils.h" #include "../../../Windows/Synchronization.h" #include "../FileManager/RegistryUtils.h" #include "CompressCall.h" using namespace NWindows; #define MY_TRY_BEGIN try { #define MY_TRY_FINISH } \ catch(...) { ErrorMessageHRESULT(E_FAIL); return E_FAIL; } #define MY_TRY_FINISH_VOID } \ catch(...) { ErrorMessageHRESULT(E_FAIL); } #ifdef _WIN32 static const char *k7zGui = "7zG.exe"; #else static const char *k7zGui = "7zG"; #endif static const char *kShowDialogSwitch = " -ad"; static const char *kEmailSwitch = " -seml."; static const char *kIncludeSwitch = " -i"; static const char *kArchiveTypeSwitch = " -t"; static const char *kArcIncludeSwitches = " -an -ai"; static const char *kHashIncludeSwitches = " -i"; static const char *kStopSwitchParsing = " --"; static const char *kLargePagesDisable = " -slp-"; extern HWND g_HWND; UString GetQuotedString(const UString &s) { UString s2 = L'\"'; s2 += s; s2 += L'\"'; return s2; } static void ErrorMessage(LPCWSTR message) { MessageBoxW(g_HWND, message, L"7-Zip", MB_ICONERROR | MB_OK); } static void ErrorMessageHRESULT(HRESULT res, LPCWSTR s = NULL) { UString s2 = NError::MyFormatMessage(res); if (s) { s2.Add_LF(); s2 += s; } ErrorMessage(s2); } static HRESULT Call7zGui(const UString ¶ms, // LPCWSTR curDir, bool waitFinish, NSynchronization::CBaseEvent *event) { UString imageName = fs2us(NWindows::NDLL::GetModuleDirPrefix()); imageName.AddAscii(k7zGui); #ifdef _WIN32 CProcess process; WRes res = process.Create(imageName, params, NULL); // curDir); if (res != 0) { ErrorMessageHRESULT(res, imageName); return res; } if (waitFinish) process.Wait(); else if (event != NULL) { HANDLE handles[] = { process, *event }; ::WaitForMultipleObjects(ARRAY_SIZE(handles), handles, FALSE, INFINITE); } #else printf("MyCreateProcess: waitFinish=%d event=%p\n",(unsigned)waitFinish,event); printf("\timageName : %ls\n",(const wchar_t*)imageName); printf("\tparams : %ls\n",(const wchar_t*)params); // printf("\tcurDir : %ls\n",(const wchar_t*)curDir); wxString cmd; cmd = (const wchar_t*)imageName; cmd += L" "; cmd += (const wchar_t*)params; wxString memoCurDir = wxGetCwd(); /* if (curDir) { // FIXME wxSetWorkingDirectory(wxString(curDir)); // under MacOSX, a bundle does not keep the current directory // between 7zFM and 7zG ... // So, try to use the environment variable P7ZIP_CURRENT_DIR char p7zip_current_dir[MAX_PATH]; AString aCurPath = GetAnsiString(curDir); const char *dir2 = nameWindowToUnix((const char *)aCurPath); snprintf(p7zip_current_dir,sizeof(p7zip_current_dir),"P7ZIP_CURRENT_DIR=%s/",dir2); p7zip_current_dir[sizeof(p7zip_current_dir)-1] = 0; putenv(p7zip_current_dir); printf("putenv(%s)\n",p7zip_current_dir); } */ printf("MyCreateProcess: cmd='%ls'\n",(const wchar_t *)cmd); long pid = 0; if (waitFinish) pid = wxExecute(cmd, wxEXEC_SYNC); // FIXME process never ends and stays zombie ... else pid = wxExecute(cmd, wxEXEC_ASYNC); // if (curDir) wxSetWorkingDirectory(memoCurDir); // FIXME if (pid == 0) return E_FAIL; #endif return S_OK; } static void AddLagePagesSwitch(UString ¶ms) { if (!ReadLockMemoryEnable()) params.AddAscii(kLargePagesDisable); } class CRandNameGenerator { CRandom _random; public: CRandNameGenerator() { _random.Init(); } void GenerateName(UString &s, const char *prefix) { s.AddAscii(prefix); char temp[16]; ConvertUInt32ToString((UInt32)(unsigned)_random.Generate(), temp); s.AddAscii(temp); } }; #ifdef _WIN32 static HRESULT CreateMap(const UStringVector &names, CFileMapping &fileMapping, NSynchronization::CManualResetEvent &event, UString ¶ms) { size_t totalSize = 1; { FOR_VECTOR (i, names) totalSize += (names[i].Len() + 1); } totalSize *= sizeof(wchar_t); CRandNameGenerator random; UString mappingName; for (;;) { random.GenerateName(mappingName, "7zMap"); WRes res = fileMapping.Create(PAGE_READWRITE, totalSize, GetSystemString(mappingName)); if (fileMapping.IsCreated() && res == 0) break; if (res != ERROR_ALREADY_EXISTS) return res; fileMapping.Close(); } UString eventName; for (;;) { random.GenerateName(eventName, "7zEvent"); WRes res = event.CreateWithName(false, GetSystemString(eventName)); if (event.IsCreated() && res == 0) break; if (res != ERROR_ALREADY_EXISTS) return res; event.Close(); } params += L'#'; params += mappingName; params += L':'; char temp[32]; ConvertUInt64ToString(totalSize, temp); params.AddAscii(temp); params += L':'; params += eventName; LPVOID data = fileMapping.Map(FILE_MAP_WRITE, 0, totalSize); if (!data) return E_FAIL; CFileUnmapper unmapper(data); { wchar_t *cur = (wchar_t *)data; *cur++ = 0; // it means wchar_t strings (UTF-16 in WIN32) FOR_VECTOR (i, names) { const UString &s = names[i]; unsigned len = s.Len() + 1; wmemcpy(cur, (const wchar_t *)s, len); cur += len; } } return S_OK; } #endif HRESULT CompressFiles( const UString &arcPathPrefix, const UString &arcName, const UString &arcType, bool addExtension, const UStringVector &names, bool email, bool showDialog, bool waitFinish) { MY_TRY_BEGIN UString params = L'a'; #ifdef _WIN32 CFileMapping fileMapping; NSynchronization::CManualResetEvent event; params.AddAscii(kIncludeSwitch); RINOK(CreateMap(names, fileMapping, event, params)); #else NSynchronization::CManualResetEvent event; char tempFile[256]; static int count = 1000; sprintf(tempFile,"/tmp/7zCompress_%d_%d.tmp",(int)getpid(),count++); FILE * file = fopen(tempFile,"w"); if (file) { for (int i = 0; i < names.Size(); i++) { fprintf(file,"%ls\n",(const wchar_t *)names[i]); printf(" TMP_%d : '%ls'\n",i,(const wchar_t *)names[i]); } fclose(file); } params += L" -i@"; params += GetUnicodeString(tempFile); #endif if (!arcType.IsEmpty()) { params.AddAscii(kArchiveTypeSwitch); params += arcType; } if (email) params.AddAscii(kEmailSwitch); if (showDialog) params.AddAscii(kShowDialogSwitch); AddLagePagesSwitch(params); if (arcName.IsEmpty()) params.AddAscii(" -an"); if (addExtension) params.AddAscii(" -saa"); else params.AddAscii(" -sae"); params.AddAscii(kStopSwitchParsing); params.Add_Space(); if (!arcName.IsEmpty()) { params += GetQuotedString( // #ifdef UNDER_CE arcPathPrefix + // #endif arcName); } return Call7zGui(params, // (arcPathPrefix.IsEmpty()? 0: (LPCWSTR)arcPathPrefix), waitFinish, &event); MY_TRY_FINISH } static void ExtractGroupCommand(const UStringVector &arcPaths, UString ¶ms, bool isHash) { AddLagePagesSwitch(params); params.AddAscii(isHash ? kHashIncludeSwitches : kArcIncludeSwitches); #ifdef _WIN32 CFileMapping fileMapping; NSynchronization::CManualResetEvent event; HRESULT result = CreateMap(arcPaths, fileMapping, event, params); if (result == S_OK) result = Call7zGui(params, false, &event); if (result != S_OK) ErrorMessageHRESULT(result); #else HRESULT result = S_OK; NSynchronization::CManualResetEvent event; char tempFile[256]; static int count = 1000; sprintf(tempFile,"/tmp/7zExtract_%d_%d.tmp",(int)getpid(),count++); FILE * file = fopen(tempFile,"w"); if (file) { for (int i = 0; i < arcPaths.Size(); i++) { fprintf(file,"%ls\n",(const wchar_t *)arcPaths[i]); printf(" TMP_%d : '%ls'\n",i,(const wchar_t *)arcPaths[i]); } fclose(file); } params += L"@"; params += GetUnicodeString(tempFile); printf("ExtractGroupCommand : -%ls-\n",(const wchar_t *)params); if (result == S_OK) result = Call7zGui(params, true, &event); // FIXME false => true printf("ExtractGroupCommand : END\n"); remove(tempFile); if (result != S_OK) ErrorMessageHRESULT(result); #endif } void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup) { MY_TRY_BEGIN UString params = L'x'; if (!outFolder.IsEmpty()) { params.AddAscii(" -o"); params += GetQuotedString(outFolder); } if (elimDup) params.AddAscii(" -spe"); if (showDialog) params.AddAscii(kShowDialogSwitch); ExtractGroupCommand(arcPaths, params, false); MY_TRY_FINISH_VOID } void TestArchives(const UStringVector &arcPaths) { MY_TRY_BEGIN UString params = L't'; ExtractGroupCommand(arcPaths, params, false); MY_TRY_FINISH_VOID } void CalcChecksum(const UStringVector &paths, const UString &methodName) { MY_TRY_BEGIN UString params = L'h'; if (!methodName.IsEmpty()) { params.AddAscii(" -scrc"); params += methodName; } ExtractGroupCommand(paths, params, true); MY_TRY_FINISH_VOID } void Benchmark(bool totalMode) { MY_TRY_BEGIN HRESULT result = Call7zGui(totalMode ? L"b -mm=*" : L"b", false, NULL); if (result != S_OK) ErrorMessageHRESULT(result); MY_TRY_FINISH_VOID }