Src/Languages/Slovak: MergeSlovak.rc
Synchronizing Swedish translation to English where feasible.
Src/Languages/Swedish: MergeSwedish.rc
+ PATCH: [ 1392413 ] Track lossy encodings & warn user
+ Src: FileFilterMgr.cpp Merge.rc MergeDoc.cpp files.h resource.h
+ Src/Common: UniFile.cpp UniFile.h unicoder.cpp
2006-02-05 Perry
PATCH: [ 1414201 ] Cleanup Merge Line Flags
/**
* @file UniFile.cpp
- * @author Perry Rapp, Creator, 2003-2005
+ * @author Perry Rapp, Creator, 2003-2006
* @author Kimmo Varis, 2004-2005
* @date Created: 2003-10
- * @date Edited: 2005-07-25 (Perry Rapp)
+ * @date Edited: 2006-02-06 (Perry Rapp)
*
* @brief Implementation of Unicode enabled file classes (Memory-mapped reader class, and Stdio replacement class)
*/
/**
* @brief Read one (DOS or UNIX or Mac) line. Do not include eol chars.
*/
-BOOL UniMemFile::ReadString(CString & line)
+BOOL UniMemFile::ReadString(CString & line, bool * lossy)
{
CString eol;
- BOOL ok = ReadString(line, eol);
+ BOOL ok = ReadString(line, eol, lossy);
return ok;
}
/**
* @brief Read one (DOS or UNIX or Mac) line
*/
-BOOL UniMemFile::ReadString(CString & line, CString & eol)
+BOOL UniMemFile::ReadString(CString & line, CString & eol, bool * lossy)
{
line = _T("");
eol = _T("");
RecordZero(m_txtstats, offset);
}
}
- bool lossy=false;
- line = ucr::maketstring((LPCSTR)m_current, eolptr-m_current, m_codepage, &lossy);
+ line = ucr::maketstring((LPCSTR)m_current, eolptr-m_current, m_codepage, lossy);
+ if (lossy && *lossy)
+ ++m_txtstats.nlosses;
if (!eof)
{
eol += (TCHAR)*eolptr;
return (m_data != 0);
}
-BOOL UniStdioFile::ReadString(CString & line)
+BOOL UniStdioFile::ReadString(CString & line, bool * lossy)
{
ASSERT(0); // unimplemented -- currently cannot read from a UniStdioFile!
return FALSE;
}
-BOOL UniStdioFile::ReadString(CString & line, CString & eol)
+BOOL UniStdioFile::ReadString(CString & line, CString & eol, bool * lossy)
{
ASSERT(0); // unimplemented -- currently cannot read from a UniStdioFile!
return FALSE;
}
-BOOL UniStdioFile::ReadString(sbuffer & sline)
+BOOL UniStdioFile::ReadString(sbuffer & sline, bool * lossy)
{
ASSERT(0); // unimplemented -- currently cannot read from a UniStdioFile!
return FALSE;
}
-BOOL UniStdioFile::ReadString(sbuffer & sline, CString & eol)
+BOOL UniStdioFile::ReadString(sbuffer & sline, CString & eol, bool * lossy)
{
ASSERT(0); // unimplemented -- currently cannot read from a UniStdioFile!
return FALSE;
/**
* @file UniFile.h
- * @author Perry Rapp, Creator, 2003
+ * @author Perry Rapp, Creator, 2003-2006
* @date Created: 2003-10
- * @date Edited: 2006-01-13 (Perry Rapp)
+ * @date Edited: 2006-02-06 (Perry Rapp)
*
* @brief Declaration of Memory-Mapped Unicode enabled file class
*/
virtual void SetCodepage(int codepage) = 0;
public:
- virtual BOOL ReadString(CString & line) = 0;
- virtual BOOL ReadString(CString & line, CString & eol) = 0;
+ virtual BOOL ReadString(CString & line, bool * lossy) = 0;
+ virtual BOOL ReadString(CString & line, CString & eol, bool * lossy) = 0;
virtual int GetLineNumber() const = 0;
virtual __int64 GetPosition() const = 0;
virtual bool ReadBom();
public:
- virtual BOOL ReadString(CString & line);
- virtual BOOL ReadString(CString & line, CString & eol);
+ virtual BOOL ReadString(CString & line, bool * lossy);
+ virtual BOOL ReadString(CString & line, CString & eol, bool * lossy);
virtual __int64 GetPosition() const { return m_current - m_base; }
virtual bool ReadBom();
protected:
- virtual BOOL ReadString(CString & line);
- virtual BOOL ReadString(CString & line, CString & eol);
+ virtual BOOL ReadString(CString & line, bool * lossy);
+ virtual BOOL ReadString(CString & line, CString & eol, bool * lossy);
public:
- virtual BOOL ReadString(sbuffer & line);
- virtual BOOL ReadString(sbuffer & line, CString & eol);
+ virtual BOOL ReadString(sbuffer & line, bool * lossy);
+ virtual BOOL ReadString(sbuffer & line, CString & eol, bool * lossy);
virtual __int64 GetPosition() const;
/**
* @file unicoder.cpp
- * @author Perry Rapp, Creator, 2003-2004
+ * @author Perry Rapp, Creator, 2003-2006
* @date Created: 2003-10
- * @date Edited: 2005-12-15 (Perry Rapp)
+ * @date Edited: 2006-02-06 (Perry Rapp)
*
* @brief Implementation of utility unicode conversion routines
*/
// Convert input to Unicode, using specified codepage
// TCHAR is wchar_t, so convert into CString (str)
CString str;
- DWORD flags = 0;
+ DWORD flags = MB_ERR_INVALID_CHARS;
int wlen = len*2+6;
LPWSTR wbuff = str.GetBuffer(wlen);
int n = MultiByteToWideChar(codepage, flags, lpd, len, wbuff, wlen-1);
if (n)
{
str.ReleaseBuffer(n);
+ return str;
}
else
{
+ *lossy = true;
+ if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION)
+ {
+ flags = 0;
+ // wlen & wbuff are still fine
+ n = MultiByteToWideChar(codepage, flags, lpd, len, wbuff, wlen-1);
+ if (n)
+ {
+ str.ReleaseBuffer(n);
+ return str;
+ }
+ }
str = _T("?");
+ return str;
}
- return str;
#else
if (EqualCodepages(codepage, getDefaultCodepage()))
pfilter->fullpath = szFilepath;
pfilter->name = szFilename; // default if no name
CString sLine;
- while (file.ReadString(sLine))
+ bool lossy=false;
+ while (file.ReadString(sLine, &lossy))
{
sLine.TrimLeft();
sLine.TrimRight();
BEGIN
IDS_SUGGEST_IGNORECODEPAGE "Different codepages found in left (cp%d) and right (cp%d) files. \nDisplaying each file in its codepage will give a better display but merging/copying will be dangerous.\nWould you like to treat both files as being in the default windows codepage (recommended)?"
IDS_DIFFERENT_UNICODINGS "Warning: Files use different encodings, left=%s and right=%s, and merging may lead to information loss."
+ IDS_LOSSY_TRANSCODING_BOTH "Information lost due to encoding errors: both files"
+ IDS_LOSSY_TRANSCODING_RIGHT "Information lost due to encoding errors: right file"
+ IDS_LOSSY_TRANSCODING_LEFT "Information lost due to encoding errors: left file"
END
// EDITOR : SHOW LINE DIFF
if (!FileTransform_Unpacking(sFileName, sToFindUnpacker, infoUnpacker, &unpackerSubcode))
{
InitNew(); // leave crystal editor in valid, empty state
- return FRESULT_ERROR_UNPACK;
+ return FileLoadResult::FRESULT_ERROR_UNPACK;
}
}
else
if (!FileTransform_Unpacking(sFileName, infoUnpacker, &unpackerSubcode))
{
InitNew(); // leave crystal editor in valid, empty state
- return FRESULT_ERROR_UNPACK;
+ return FileLoadResult::FRESULT_ERROR_UNPACK;
}
}
// we use the same unpacker for both files, so it must be defined after first file
LPCTSTR pszFileName = sFileName;
CString sExt;
- int nRetVal = FRESULT_OK;
+ DWORD nRetVal = FileLoadResult::FRESULT_OK;
// Set encoding based on extension, if we know one
SplitFilename(pszFileName, NULL, NULL, &sExt);
if (!pufile->OpenReadOnly(pszFileName))
{
- nRetVal = FRESULT_ERROR;
+ nRetVal = FileLoadResult::FRESULT_ERROR;
UniFile::UniError uniErr = pufile->GetLastUniError();
if (uniErr.hasError())
{
preveol = "\n";
do {
- done = !pufile->ReadString(sline, eol);
+ bool lossy=false;
+ done = !pufile->ReadString(sline, eol, &lossy);
const UniFile::txtstats & tstats = pufile->GetTxtStats();
if (tstats.nzeros)
{
- nRetVal = FRESULT_BINARY;
+ nRetVal = FileLoadResult::FRESULT_BINARY;
ResetInit(); // leave crystal editor in valid, empty state
goto LoadFromFileExit;
}
}
sline += eol; // TODO: opportunity for optimization, as CString append is terrible
+ if (lossy)
+ {
+ // TODO: Should record lossy status of line
+ }
AppendLine(lineno, sline, sline.GetLength());
++lineno;
preveol = eol;
// WinMerge may display impure files, but the default option is to unify the EOL
// We return this info to the caller, so it may display a confirmation box
if (IsTextFileStylePure(pufile->GetTxtStats()))
- nRetVal = FRESULT_OK;
+ nRetVal = FileLoadResult::FRESULT_OK;
else
- nRetVal = FRESULT_OK_IMPURE;
+ nRetVal = FileLoadResult::FRESULT_OK_IMPURE;
// stash original encoding away
m_unicoding = pufile->GetUnicoding();
m_codepage = pufile->GetCodepage();
if (pufile->GetTxtStats().nlosses)
+ {
+ FileLoadResult::AddModifier(nRetVal, FileLoadResult::FRESULT_LOSSY);
readOnly = TRUE;
+ }
}
LoadFromFileExit:
{
CDiffTextBuffer *pBuf;
CString sError;
- int retVal = FRESULT_ERROR;
+ DWORD retVal = FileLoadResult::FRESULT_ERROR;
pBuf = m_ptBuf[nBuffer];
nBuffer == 0 ? m_filePaths.SetLeft(sFileName) : m_filePaths.SetRight(sFileName);
// if CMergeDoc::CDiffTextBuffer::LoadFromFile failed,
// it left the pBuf in a valid (but empty) state via a call to InitNew
- if (retVal == FRESULT_OK_IMPURE)
+ if (FileLoadResult::IsErrorUnpack(retVal))
{
// File loaded, and multiple EOL types in this file
- retVal = FRESULT_OK;
+ FileLoadResult::SetMainOk(retVal);
// By default, WinMerge unifies EOL to the most used type (when diffing or saving)
// As some info are lost, we request a confirmation from the user
if (!GetOptionsMgr()->GetBool(OPT_ALLOW_MIXED_EOL))
}
}
- if (retVal == FRESULT_ERROR)
+ if (FileLoadResult::IsError(retVal))
{
// Error from Unifile/system
if (!sOpenError.IsEmpty())
AfxFormatString1(sError, IDS_ERROR_FILE_NOT_FOUND, sFileName);
AfxMessageBox(sError, MB_OK | MB_ICONSTOP);
}
- else if (retVal == FRESULT_ERROR_UNPACK)
+ else if (FileLoadResult::IsErrorUnpack(retVal))
{
AfxFormatString1(sError, IDS_ERROR_FILE_NOT_UNPACKED, sFileName);
AfxMessageBox(sError, MB_OK | MB_ICONSTOP);
m_strBothFilenames = sLeftFile + _T("|") + sRightFile;
// Load left side file
- int nLeftSuccess = FRESULT_ERROR;
+ DWORD nLeftSuccess = FileLoadResult::FRESULT_ERROR;
if (!sLeftFile.IsEmpty())
{
if (GetMainFrame()->m_strLeftDesc.IsEmpty())
m_ptBuf[0]->InitNew();
m_strDesc[0] = GetMainFrame()->m_strLeftDesc;
- nLeftSuccess = FRESULT_OK;
+ nLeftSuccess = FileLoadResult::FRESULT_OK;
}
// Load right side only if left side was succesfully loaded
- int nRightSuccess = FRESULT_ERROR;
+ DWORD nRightSuccess = FileLoadResult::FRESULT_ERROR;
if (!sRightFile.IsEmpty())
{
if (GetMainFrame()->m_strRightDesc.IsEmpty())
m_pSaveFileInfo[1]->Update(sRightFile);
m_pRescanFileInfo[1]->Update(sRightFile);
- if (nLeftSuccess == FRESULT_OK || nLeftSuccess == FRESULT_BINARY)
+ if (FileLoadResult::IsOk(nLeftSuccess) || FileLoadResult::IsBinary(nLeftSuccess))
+ {
nRightSuccess = LoadFile(sRightFile, 1, bRORight, filelocRight.codepage);
+ }
}
else
{
m_ptBuf[1]->InitNew();
m_strDesc[1] = GetMainFrame()->m_strRightDesc;
- nRightSuccess = FRESULT_OK;
+ nRightSuccess = FileLoadResult::FRESULT_OK;
}
// scratchpad : we don't call LoadFile, so
m_pInfoUnpacker->Initialize(PLUGIN_MANUAL);
// Bail out if either side failed
- if (nLeftSuccess != FRESULT_OK || nRightSuccess != FRESULT_OK)
+ if (!FileLoadResult::IsOk(nLeftSuccess) || !FileLoadResult::IsOk(nRightSuccess))
{
- if (nLeftSuccess == FRESULT_BINARY || nRightSuccess == FRESULT_BINARY)
+ if (FileLoadResult::IsBinary(nLeftSuccess) || FileLoadResult::IsBinary(nRightSuccess))
{
CompareBinaries(sLeftFile, sRightFile, nLeftSuccess, nRightSuccess);
return OPENRESULTS_FAILED_BINARY;
return OPENRESULTS_FAILED_MISC;
}
+ // Warn user if file load was lossy (bad encoding)
+ if (FileLoadResult::IsLossy(nLeftSuccess) || FileLoadResult::IsLossy(nRightSuccess))
+ {
+ // TODO: It would be nice to report how many lines were lossy
+ // we did calculate those numbers when we loaded the files, in the text stats
+
+ int idres=0;
+ if (FileLoadResult::IsLossy(nLeftSuccess) && FileLoadResult::IsLossy(nRightSuccess))
+ {
+ idres = IDS_LOSSY_TRANSCODING_BOTH;
+ }
+ else if (FileLoadResult::IsLossy(nLeftSuccess))
+ {
+ idres = IDS_LOSSY_TRANSCODING_LEFT;
+ }
+ else
+ {
+ idres = IDS_LOSSY_TRANSCODING_RIGHT;
+ }
+ AfxMessageBox(idres, MB_ICONSTOP);
+ }
+
// Now buffers data are valid
m_pView[0]->AttachToBuffer();
m_pView[1]->AttachToBuffer();
BOOL bIdentical = FALSE;
// Compare binary files
- if (nLeftSuccess == FRESULT_BINARY && nRightSuccess == FRESULT_BINARY)
+ if (FileLoadResult::IsBinary(nLeftSuccess) && FileLoadResult::IsBinary(nRightSuccess))
{
bBinary = TRUE; // Compare binary files
nRescanResult = Rescan(bBinary, bIdentical);
if (nRescanResult == RESCAN_OK)
{
// Format message shown to user: both files are binaries
- if (nLeftSuccess == FRESULT_BINARY && nRightSuccess == FRESULT_BINARY)
+ if (FileLoadResult::IsBinary(nLeftSuccess) && FileLoadResult::IsBinary(nRightSuccess))
{
CString msg;
CString msg2;
msg += msg2;
AfxMessageBox(msg, MB_ICONINFORMATION);
}
- else if (nLeftSuccess == FRESULT_BINARY || nRightSuccess == FRESULT_BINARY)
+ else if (FileLoadResult::IsBinary(nLeftSuccess) || FileLoadResult::IsBinary(nRightSuccess))
{
// Other file binary, other text
CString msg;
CString msg2;
- if (nLeftSuccess == FRESULT_BINARY)
+ if (FileLoadResult::IsBinary(nLeftSuccess))
AfxFormatString1(msg, IDS_OTHER_IS_BINARY, sLeftFile);
else
AfxFormatString1(msg, IDS_OTHER_IS_BINARY, sRightFile);
/**
* @brief File-operation return-statuses
+ * Note that FileLoadResult class has no instance data or methods.
+ * It is only a namespace for static methods & constants.
+ * Everything is public.
*/
-enum
+class FileLoadResult
{
- FRESULT_ERROR = 0,
- FRESULT_OK,
- FRESULT_OK_IMPURE,
- FRESULT_BINARY,
- FRESULT_ERROR_UNPACK
+public:
+// Checking results
+ // main results
+ static bool IsError(DWORD flr) { return Main(flr) == FRESULT_ERROR; }
+ static bool IsOk(DWORD flr) { return Main(flr) == FRESULT_OK; }
+ static bool IsOkImpure(DWORD flr) { return Main(flr) == FRESULT_OK_IMPURE; }
+ static bool IsBinary(DWORD flr) { return Main(flr) == FRESULT_BINARY; }
+ static bool IsErrorUnpack(DWORD flr) { return Main(flr) == FRESULT_ERROR_UNPACK; }
+ // modifiers
+ static bool IsLossy(DWORD flr) { return IsModifier(flr, FRESULT_LOSSY); }
+
+// Assigning results
+ // main results
+ static void SetMainOk(DWORD & flr) { SetMain(flr, FRESULT_OK); }
+ // modifiers
+ static void AddModifier(DWORD & flr, DWORD modifier) { flr = (flr | modifier); }
+
+ // bit manipulations
+ static void SetMain(DWORD & flr, DWORD newmain) { flr = flr & ~FRESULT_MAIN_MASK; flr = flr | newmain; }
+ static DWORD Main(DWORD flr) { return flr & FRESULT_MAIN_MASK; }
+ static bool IsModifier(DWORD flr, DWORD modifier) { return !!(flr & modifier); }
+
+ enum
+ {
+ FRESULT_MAIN_MASK = 0xF,
+ // main results
+ FRESULT_ERROR = 0x0,
+ FRESULT_OK = 0x1,
+ FRESULT_OK_IMPURE = 0x2,
+ FRESULT_BINARY = 0x3,
+ FRESULT_ERROR_UNPACK = 0x4,
+ // modifiers
+ FRESULT_LOSSY = 0x10000,
+ };
};
/**
#define IDS_DIFFERENT_UNICODINGS 18011
#define IDS_INVALID_DIRECTORY 18012
#define IDS_CANNOT_OPEN_BINARYFILE 18013
-#define IDS_LINEDIFF_NODIFF 18016
-#define IDS_LINEDIFF_NODIFF_CAPTION 18017
+#define IDS_LOSSY_TRANSCODING_BOTH 18014
+#define IDS_LOSSY_TRANSCODING_RIGHT 18015
+#define IDS_LOSSY_TRANSCODING_LEFT 18016
+#define IDS_LINEDIFF_NODIFF 18026
+#define IDS_LINEDIFF_NODIFF_CAPTION 18027
#define IDS_NUM_REPLACED 18032
#define IDS_EDIT_TEXT_NOT_FOUND 18033
#define ID_EDITOR_COPY_PATH 18048