/// Saves given path to registry for ShellExtension, and Context Menu settings void PropShell::SaveMergePath() { TCHAR temp[MAX_PATH] = {0}; LONG retVal = 0; GetModuleFileName(AfxGetInstanceHandle(), temp, MAX_PATH); CRegKeyEx reg; retVal = reg.Open(HKEY_CURRENT_USER, f_RegDir); if (retVal != ERROR_SUCCESS) { CString msg; msg.Format(_T("Failed to open registry key HKCU/%s:\n\t%d : %s"), f_RegDir, retVal, GetSysError(retVal).c_str()); LogErrorString(msg); return; } // Save path to WinMerge(U).exe retVal = reg.WriteString(f_RegValuePath, temp); if (retVal != ERROR_SUCCESS) { CString msg; msg.Format(_T("Failed to set registry value %s:\n\t%d : %s"), f_RegValuePath, retVal, GetSysError(retVal).c_str()); LogErrorString(msg); } // Determine bitmask for shell extension DWORD dwContextEnabled = reg.ReadDword(f_RegValueEnabled, 0); if (m_bContextAdded) dwContextEnabled |= CONTEXT_F_ENABLED; else dwContextEnabled &= ~CONTEXT_F_ENABLED; if (m_bContextAdvanced) dwContextEnabled |= CONTEXT_F_ADVANCED; else dwContextEnabled &= ~CONTEXT_F_ADVANCED; if (m_bContextSubfolders) dwContextEnabled |= CONTEXT_F_SUBFOLDERS; else dwContextEnabled &= ~CONTEXT_F_SUBFOLDERS; retVal = reg.WriteDword(f_RegValueEnabled, dwContextEnabled); if (retVal != ERROR_SUCCESS) { CString msg; msg.Format(_T("Failed to set registry value %s to %d:\n\t%d : %s"), f_RegValueEnabled, dwContextEnabled, retVal, GetSysError(retVal).c_str()); LogErrorString(msg); } }
/// Get registry values for ShellExtension void PropShell::GetContextRegValues() { CRegKeyEx reg; LONG retVal = 0; retVal = reg.Open(HKEY_CURRENT_USER, f_RegDir); if (retVal != ERROR_SUCCESS) { CString msg; msg.Format(_T("Failed to open registry key HKCU/%s:\n\t%d : %s"), f_RegDir, retVal, GetSysError(retVal).c_str()); LogErrorString(msg); return; } // Read bitmask for shell extension settings DWORD dwContextEnabled = reg.ReadDword(f_RegValueEnabled, 0); if (dwContextEnabled & CONTEXT_F_ENABLED) m_bContextAdded = TRUE; if (dwContextEnabled & CONTEXT_F_ADVANCED) m_bContextAdvanced = TRUE; if (dwContextEnabled & CONTEXT_F_SUBFOLDERS) m_bContextSubfolders = TRUE; }
/** * @brief Get folder for temporary files. * This function returns system temp folder. * @param [out] pnerr Error code if erorr happened. * @return Temp path, or empty string if error happened. * @note Temp path is cached after first call. * @todo Should we return NULL for error case? */ LPCTSTR env_GetTempPath(int * pnerr) { if (strTempPath.empty()) { if (GetOptionsMgr()->GetBool(OPT_USE_SYSTEM_TEMP_PATH)) { int cchTempPath = GetTempPath(0, 0); strTempPath.resize(cchTempPath - 1); if (!GetTempPath(cchTempPath, &*strTempPath.begin())) { int err = GetLastError(); if (pnerr) *pnerr = err; #ifdef _DEBUG String sysErr = GetSysError(err); // for debugging #endif return strTempPath.c_str(); // empty } } else { strTempPath = GetOptionsMgr()->GetString(OPT_CUSTOM_TEMP_PATH); if (!paths_EndsWithSlash(strTempPath.c_str())) strTempPath += '\\'; } strTempPath = paths_GetLongPath(strTempPath.c_str()); } return strTempPath.c_str(); }
/** * @brief Get the error string. * @return Error string. */ String UniFile::UniError::GetError() const { String sError; if (apiname.empty()) sError = desc; else sError = GetSysError(syserrnum); return sError; }
// for OLECHAR files, transform to UTF8 for diffutils // TODO : convert Ansi to UTF8 if other file is unicode or uses a different codepage BOOL FileTransform_UCS2ToUTF8(String & filepath, BOOL bMayOverwrite) { String tempDir = env_GetTempPath(); if (tempDir.empty()) return FALSE; String tempFilepath = env_GetTempFileName(tempDir.c_str(), _T("_WM")); if (tempFilepath.empty()) return FALSE; // TODO : is it better with the BOM or without (just change the last argument) int nFileChanged = 0; BOOL bSuccess = OlecharToUTF8(filepath.c_str(), tempFilepath.c_str(), nFileChanged, FALSE); if (!bSuccess) return FALSE; if (nFileChanged) { // we do not overwrite so we delete the old file if (bMayOverwrite) { if (!::DeleteFile(filepath.c_str())) { LogErrorString(Fmt(_T("DeleteFile(%s) failed: %s"), filepath.c_str(), GetSysError(GetLastError()).c_str())); } } // and change the filepath if everything works filepath = tempFilepath; } else { if (!::DeleteFile(tempFilepath.c_str())) { LogErrorString(Fmt(_T("DeleteFile(%s) failed: %s"), tempFilepath.c_str(), GetSysError(GetLastError()).c_str())); } } return TRUE; }
BOOL FileTransform_NormalizeUnicode(String & filepath, BOOL bMayOverwrite) { String tempDir = env_GetTempPath(); if (tempDir.empty()) return FALSE; String tempFilepath = env_GetTempFileName(tempDir.c_str(), _T("_WM")); if (tempFilepath.empty()) return FALSE; int nFileChanged = 0; BOOL bSuccess = UnicodeFileToOlechar(filepath.c_str(), tempFilepath.c_str(), nFileChanged); if (!bSuccess) return FALSE; if (nFileChanged) { // we do not overwrite so we delete the old file if (bMayOverwrite) { if (!::DeleteFile(filepath.c_str())) { LogErrorString(Fmt(_T("DeleteFile(%s) failed: %s"), filepath.c_str(), GetSysError(GetLastError()).c_str())); } } // and change the filepath if everything works filepath = tempFilepath; } else { if (!::DeleteFile(tempFilepath.c_str())) { LogErrorString(Fmt(_T("DeleteFile(%s) failed: %s"), tempFilepath.c_str(), GetSysError(GetLastError()).c_str())); } } return TRUE; }
/** * @brief Get filename for temporary file. * @param [in] lpPathName Temporary file folder. * @param [in] lpPrefixString Prefix to use for filename. * @param [out] pnerr Error code if error happened. * @return Full path for temporary file or empty string if error happened. */ String env_GetTempFileName(LPCTSTR lpPathName, LPCTSTR lpPrefixString, int * pnerr) { TCHAR buffer[MAX_PATH] = {0}; if (_tcslen(lpPathName) > MAX_PATH-14) return _T(""); // failure int rtn = GetTempFileName(lpPathName, lpPrefixString, 0, buffer); if (!rtn) { int err = GetLastError(); if (pnerr) *pnerr = err; #ifdef _DEBUG String sysErr = GetSysError(err); // for debugging #endif return _T(""); } return buffer; }
/** * @brief Open file as memory-mapped file. * @param [in,out] fileData Memory-mapped file's info. * @return TRUE if opening succeeded, FALSE otherwise. */ BOOL files_openFileMapped(MAPPEDFILEDATA *fileData) { DWORD dwProtectFlag = 0; DWORD dwMapAccess = 0; DWORD dwOpenAccess = 0; DWORD dwFileSizeHigh = 0; DWORD dwSharedMode = FILE_SHARE_READ; HANDLE hTemplateFile = NULL; // for creating new file BOOL bSuccess = TRUE; if (fileData->bWritable) { dwProtectFlag = PAGE_READWRITE; dwMapAccess = FILE_MAP_ALL_ACCESS; dwOpenAccess = GENERIC_READ | GENERIC_WRITE; } else { dwProtectFlag = PAGE_READONLY; dwMapAccess = FILE_MAP_READ; dwOpenAccess = GENERIC_READ; } fileData->hFile = CreateFile(fileData->fileName, dwOpenAccess, dwSharedMode, NULL, fileData->dwOpenFlags, FILE_ATTRIBUTE_NORMAL, hTemplateFile); if (fileData->hFile == INVALID_HANDLE_VALUE) { bSuccess = FALSE; LogErrorString(Fmt(_T("CreateFile(%s) failed in files_openFileMapped: %s") , fileData->fileName, GetSysError(GetLastError()).c_str())); } else { if (fileData->dwSize == 0) { fileData->dwSize = GetFileSize(fileData->hFile, &dwFileSizeHigh); if (fileData->dwSize == 0xFFFFFFFF || dwFileSizeHigh) { fileData->dwSize = 0; bSuccess = FALSE; } } } if (bSuccess) { if (fileData->dwSize == 0 && dwFileSizeHigh == 0) // Empty file (but should be accepted anyway) return bSuccess; fileData->hMapping = CreateFileMapping(fileData->hFile, NULL, dwProtectFlag, 0, fileData->dwSize, NULL); if (!fileData->hMapping) { bSuccess = FALSE; LogErrorString(Fmt(_T("CreateFileMapping(%s) failed: %s") , fileData->fileName, GetSysError(GetLastError()).c_str())); } else { fileData->pMapBase = MapViewOfFile(fileData->hMapping, dwMapAccess, 0, 0, 0); if (!fileData->pMapBase) { bSuccess = FALSE; LogErrorString(Fmt(_T("MapViewOfFile(%s) failed: %s") , fileData->fileName, GetSysError(GetLastError()).c_str())); } } } if (!bSuccess) { UnmapViewOfFile(fileData->pMapBase); fileData->pMapBase = NULL; CloseHandle(fileData->hMapping); fileData->hMapping = NULL; CloseHandle(fileData->hFile); fileData->hFile = NULL; } return bSuccess; }
/** * @brief Runs diff-engine. */ BOOL CDiffWrapper::RunFileDiff() { String filepath1(m_s1File); String filepath2(m_s2File); replace_char(&*filepath1.begin(), '/', '\\'); replace_char(&*filepath2.begin(), '/', '\\'); BOOL bRet = TRUE; String strFile1Temp(filepath1); String strFile2Temp(filepath2); m_options.SetToDiffUtils(); if (m_bUseDiffList) m_nDiffs = m_pDiffList->GetSize(); if (m_bPluginsEnabled) { // Do the preprocessing now, overwrite the temp files // NOTE: FileTransform_UCS2ToUTF8() may create new temp // files and return new names, those created temp files // are deleted in end of function. if (m_infoPrediffer->bToBeScanned) { // this can only fail if the data can not be saved back (no more // place on disk ???) What to do then ?? FileTransform_Prediffing(strFile1Temp, m_sToFindPrediffer.c_str(), m_infoPrediffer, m_bPathsAreTemp); } else { // This can fail if the prediffer has a problem if (FileTransform_Prediffing(strFile1Temp, *m_infoPrediffer, m_bPathsAreTemp) == FALSE) { // display a message box CString sError; LangFormatString2(sError, IDS_PREDIFFER_ERROR, strFile1Temp.c_str(), m_infoPrediffer->pluginName.c_str()); AfxMessageBox(sError, MB_OK | MB_ICONSTOP); // don't use any more this prediffer m_infoPrediffer->bToBeScanned = FALSE; m_infoPrediffer->pluginName.erase(); } } // We use the same plugin for both files, so it must be defined before // second file ASSERT(m_infoPrediffer->bToBeScanned == FALSE); if (FileTransform_Prediffing(strFile2Temp, *m_infoPrediffer, m_bPathsAreTemp) == FALSE) { // display a message box CString sError; LangFormatString2(sError, IDS_PREDIFFER_ERROR, strFile2Temp.c_str(), m_infoPrediffer->pluginName.c_str()); AfxMessageBox(sError, MB_OK | MB_ICONSTOP); // don't use any more this prediffer m_infoPrediffer->bToBeScanned = FALSE; m_infoPrediffer->pluginName.erase(); } } // Comparing UTF-8 files seems to require this conversion? // I'm still very confused about why, as what the functions // document doing is UCS2 to UTF-8 conversion, nothing else. // Something is wrong here. - Kimmo FileTransform_UCS2ToUTF8(strFile1Temp, m_bPathsAreTemp); FileTransform_UCS2ToUTF8(strFile2Temp, m_bPathsAreTemp); DiffFileData diffdata; diffdata.SetDisplayFilepaths(filepath1.c_str(), filepath2.c_str()); // store true names for diff utils patch file // This opens & fstats both files (if it succeeds) if (!diffdata.OpenFiles(strFile1Temp.c_str(), strFile2Temp.c_str())) { return FALSE; } // Compare the files, if no error was found. // Last param (bin_file) is NULL since we don't // (yet) need info about binary sides. int bin_flag = 0; struct change *script = NULL; bRet = Diff2Files(&script, &diffdata, &bin_flag, NULL); // We don't anymore create diff-files for every rescan. // User can create patch-file whenever one wants to. // We don't need to waste time. But lets keep this as // debugging aid. Sometimes it is very useful to see // what differences diff-engine sees! #ifdef _DEBUG // throw the diff into a temp file String sTempPath = env_GetTempPath(); // get path to Temp folder String path = paths_ConcatPath(sTempPath, _T("Diff.txt")); outfile = _tfopen(path.c_str(), _T("w+")); if (outfile != NULL) { print_normal_script(script); fclose(outfile); outfile = NULL; } #endif // First determine what happened during comparison // If there were errors or files were binaries, don't bother // creating diff-lists or patches // diff_2_files set bin_flag to -1 if different binary // diff_2_files set bin_flag to +1 if same binary if (bin_flag != 0) { m_status.bBinaries = TRUE; if (bin_flag == -1) m_status.bIdentical = FALSE; else m_status.bIdentical = TRUE; } else { // text files according to diffutils, so change script exists m_status.bIdentical = (script == 0); m_status.bBinaries = FALSE; } file_data * inf = diffdata.m_inf; m_status.bLeftMissingNL = inf[0].missing_newline; m_status.bRightMissingNL = inf[1].missing_newline; // Create patch file if (!m_status.bBinaries && m_bCreatePatchFile) { WritePatchFile(script, &inf[0]); } // Go through diffs adding them to WinMerge's diff list // This is done on every WinMerge's doc rescan! if (!m_status.bBinaries && m_bUseDiffList) { LoadWinMergeDiffsFromDiffUtilsScript(script, diffdata.m_inf); } FreeDiffUtilsScript(script); // Done with diffutils filedata diffdata.Close(); if (m_bPluginsEnabled) { // Delete temp files transformation functions possibly created if (lstrcmpi(filepath1.c_str(), strFile1Temp.c_str()) != 0) { if (!::DeleteFile(strFile1Temp.c_str())) { LogErrorString(Fmt(_T("DeleteFile(%s) failed: %s"), strFile1Temp.c_str(), GetSysError(GetLastError()).c_str())); } strFile1Temp.erase(); } if (lstrcmpi(filepath2.c_str(), strFile2Temp.c_str()) != 0) { if (!::DeleteFile(strFile2Temp.c_str())) { LogErrorString(Fmt(_T("DeleteFile(%s) failed: %s"), strFile2Temp.c_str(), GetSysError(GetLastError()).c_str())); } strFile2Temp.erase(); } } return bRet; }