OSDN Git Service

PATCH: [ 1392413 ] Track lossy encodings & warn user
authorPerry Rapp <elsapo@users.sourceforge.net>
Mon, 6 Feb 2006 23:09:58 +0000 (23:09 +0000)
committerPerry Rapp <elsapo@users.sourceforge.net>
Mon, 6 Feb 2006 23:09:58 +0000 (23:09 +0000)
  Src: FileFilterMgr.cpp Merge.rc MergeDoc.cpp files.h resource.h
  Src/Common: UniFile.cpp UniFile.h unicoder.cpp

Src/Changes.txt
Src/Common/UniFile.cpp
Src/Common/UniFile.h
Src/Common/unicoder.cpp
Src/FileFilterMgr.cpp
Src/Merge.rc
Src/MergeDoc.cpp
Src/files.h
Src/resource.h

index a7b29fa..a7f8e91 100644 (file)
@@ -3,6 +3,9 @@
   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
index a3c4887..8642292 100644 (file)
@@ -1,9 +1,9 @@
 /**
  *  @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)
  */
@@ -352,10 +352,10 @@ bool UniMemFile::ReadBom()
 /**
  * @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;
 }
 
@@ -390,7 +390,7 @@ static void RecordZero(UniFile::txtstats & txstats, int offset)
 /**
  * @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("");
@@ -515,8 +515,9 @@ BOOL UniMemFile::ReadString(CString & line, CString & eol)
                                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;
@@ -820,23 +821,23 @@ bool UniStdioFile::ReadBom()
        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;
index 970392c..c4690ed 100644 (file)
@@ -1,8 +1,8 @@
 /** 
  *  @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
  */
@@ -49,8 +49,8 @@ public:
        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;
@@ -139,8 +139,8 @@ public:
        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; }
 
@@ -184,11 +184,11 @@ public:
        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;
 
index 6680ae4..c2872b7 100644 (file)
@@ -1,8 +1,8 @@
 /**
  *  @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
  */
@@ -490,19 +490,32 @@ CString maketstring(LPCSTR lpd, UINT len, int codepage, bool * lossy)
        // 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()))
index b673a8d..357fe32 100644 (file)
@@ -222,7 +222,8 @@ FileFilter * FileFilterMgr::LoadFilterFile(LPCTSTR szFilepath, LPCTSTR szFilenam
        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();
index b901c50..e7e099d 100644 (file)
@@ -2152,6 +2152,9 @@ STRINGTABLE
 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
index 71493dc..d27a1a0 100644 (file)
@@ -1448,7 +1448,7 @@ int CMergeDoc::CDiffTextBuffer::LoadFromFile(LPCTSTR pszFileNameInit,
                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
@@ -1456,7 +1456,7 @@ int CMergeDoc::CDiffTextBuffer::LoadFromFile(LPCTSTR pszFileNameInit,
                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
@@ -1465,7 +1465,7 @@ int CMergeDoc::CDiffTextBuffer::LoadFromFile(LPCTSTR pszFileNameInit,
        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);
@@ -1482,7 +1482,7 @@ int CMergeDoc::CDiffTextBuffer::LoadFromFile(LPCTSTR pszFileNameInit,
 
        if (!pufile->OpenReadOnly(pszFileName))
        {
-               nRetVal = FRESULT_ERROR;
+               nRetVal = FileLoadResult::FRESULT_ERROR;
                UniFile::UniError uniErr = pufile->GetLastUniError();
                if (uniErr.hasError())
                {
@@ -1516,13 +1516,14 @@ int CMergeDoc::CDiffTextBuffer::LoadFromFile(LPCTSTR pszFileNameInit,
                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;
                        }
@@ -1540,6 +1541,10 @@ int CMergeDoc::CDiffTextBuffer::LoadFromFile(LPCTSTR pszFileNameInit,
                        }
 
                        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;
@@ -1607,16 +1612,19 @@ int CMergeDoc::CDiffTextBuffer::LoadFromFile(LPCTSTR pszFileNameInit,
                // 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:
@@ -2495,7 +2503,7 @@ int CMergeDoc::LoadFile(CString sFileName, int nBuffer, BOOL & readOnly, int cod
 {
        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);
@@ -2508,10 +2516,10 @@ int CMergeDoc::LoadFile(CString sFileName, int nBuffer, BOOL & readOnly, int cod
        // 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))
@@ -2528,7 +2536,7 @@ int CMergeDoc::LoadFile(CString sFileName, int nBuffer, BOOL & readOnly, int cod
                }
        }
 
-       if (retVal == FRESULT_ERROR)
+       if (FileLoadResult::IsError(retVal))
        {
                // Error from Unifile/system
                if (!sOpenError.IsEmpty())
@@ -2537,7 +2545,7 @@ int CMergeDoc::LoadFile(CString sFileName, int nBuffer, BOOL & readOnly, int cod
                        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);
@@ -2610,7 +2618,7 @@ CMergeDoc::OpenDocs(FileLocation filelocLeft, FileLocation filelocRight,
        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())
@@ -2634,11 +2642,11 @@ CMergeDoc::OpenDocs(FileLocation filelocLeft, FileLocation filelocRight,
 
                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())
@@ -2652,8 +2660,10 @@ CMergeDoc::OpenDocs(FileLocation filelocLeft, FileLocation filelocRight,
 
                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
        {
@@ -2661,7 +2671,7 @@ CMergeDoc::OpenDocs(FileLocation filelocLeft, FileLocation filelocRight,
 
                m_ptBuf[1]->InitNew();
                m_strDesc[1] = GetMainFrame()->m_strRightDesc;
-               nRightSuccess = FRESULT_OK;
+               nRightSuccess = FileLoadResult::FRESULT_OK;
        }
 
        // scratchpad : we don't call LoadFile, so
@@ -2670,9 +2680,9 @@ CMergeDoc::OpenDocs(FileLocation filelocLeft, FileLocation filelocRight,
                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;
@@ -2680,6 +2690,28 @@ CMergeDoc::OpenDocs(FileLocation filelocLeft, FileLocation filelocRight,
                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();
@@ -2860,7 +2892,7 @@ void CMergeDoc::CompareBinaries(CString sLeftFile, CString sRightFile, int nLeft
        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);
@@ -2869,7 +2901,7 @@ void CMergeDoc::CompareBinaries(CString sLeftFile, CString sRightFile, int nLeft
        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;
@@ -2882,12 +2914,12 @@ void CMergeDoc::CompareBinaries(CString sLeftFile, CString sRightFile, int nLeft
                        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);
index 23f46fd..37b6a36 100644 (file)
 
 /**
  * @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,
+       };
 };
 
 /**
index aad73b6..4602699 100644 (file)
 #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