OSDN Git Service

FileTransform: Remove m_subcode from PackingInfo class
[winmerge-jp/winmerge-jp.git] / Src / DiffTextBuffer.cpp
index a9e0344..019b950 100644 (file)
@@ -29,7 +29,6 @@ using Poco::Exception;
 #endif
 
 static bool IsTextFileStylePure(const UniMemFile::txtstats & stats);
-static void EscapeControlChars(String &s);
 static CRLFSTYLE GetTextFileStyle(const UniMemFile::txtstats & stats);
 
 /**
@@ -50,55 +49,6 @@ static bool IsTextFileStylePure(const UniMemFile::txtstats & stats)
 }
 
 /**
- * @brief Escape control characters.
- * @param [in,out] s Line of text excluding eol chars.
- *
- * @note Escape sequences follow the pattern
- * (leadin character, high nibble, low nibble, leadout character).
- * The leadin character is '\x0F'. The leadout character is a backslash.
- */
-static void EscapeControlChars(String &s)
-{
-       // Compute buffer length required for escaping
-       size_t n = s.length();
-       LPCTSTR q = s.c_str();
-       size_t i = n;
-       while (i)
-       {
-               TCHAR c = q[--i];
-               // Is it a control character in the range 0..31 except TAB?
-               if (!(c & ~_T('\x1F')) && c != _T('\t'))
-               {
-                       n += 3; // Need 3 extra characters to escape
-               }
-       }
-       // Reallocate accordingly
-       i = s.length();
-       s.reserve(n + 1);
-       s.resize(n + 1);
-       LPTSTR p = &s[0];
-       // Copy/translate characters starting at end of string
-       while (i)
-       {
-               TCHAR c = p[--i];
-               // Is it a control character in the range 0..31 except TAB?
-               if (!(c & ~_T('\x1F')) && c != _T('\t'))
-               {
-                       // TODO: speed this up via table lookup
-                       // Bitwise OR with 0x100 so _itot_s() will output 3 hex digits
-                       _itot_s(0x100 | c, p + n - 4, 4, 16);
-                       // Replace terminating zero with leadout character
-                       p[n - 1] = _T('\\');
-                       // Prepare to replace 1st hex digit with leadin character
-                       c = _T('\x0F');
-                       n -= 3;
-               }
-               p[--n] = c;
-       }
-       s.resize(s.length() - 1);
-}
-
-/**
  * @brief Get file's EOL type.
  * @param [in] stats File's text stats.
  * @return EOL type.
@@ -107,20 +57,20 @@ static CRLFSTYLE GetTextFileStyle(const UniMemFile::txtstats & stats)
 {
        // Check if file has more than one EOL type.
        if (!IsTextFileStylePure(stats))
-                       return CRLF_STYLE_MIXED;
+                       return CRLFSTYLE::MIXED;
        else if (stats.ncrlfs >= stats.nlfs)
        {
                if (stats.ncrlfs >= stats.ncrs)
-                       return CRLF_STYLE_DOS;
+                       return CRLFSTYLE::DOS;
                else
-                       return CRLF_STYLE_MAC;
+                       return CRLFSTYLE::MAC;
        }
        else
        {
                if (stats.nlfs >= stats.ncrs)
-                       return CRLF_STYLE_UNIX;
+                       return CRLFSTYLE::UNIX;
                else
-                       return CRLF_STYLE_MAC;
+                       return CRLFSTYLE::MAC;
        }
 }
 
@@ -163,7 +113,8 @@ bool CDiffTextBuffer::GetLine(int nLineIndex, CString &strLine) const
  * @param [in] bModified New modified status, true if buffer has been
  *   modified since last saving.
  */
-void CDiffTextBuffer::SetModified(bool bModified /*= true*/)
+void CDiffTextBuffer::                 /* virtual override */
+SetModified(bool bModified /*= true*/) 
 {
        CCrystalTextBuffer::SetModified (bModified);
        m_pOwnerDoc->SetModifiedFlag (bModified);
@@ -190,10 +141,11 @@ bool CDiffTextBuffer::GetFullLine(int nLineIndex, CString &strLine) const
        return true;
 }
 
-void CDiffTextBuffer::AddUndoRecord(bool bInsert, const CPoint & ptStartPos,
+void CDiffTextBuffer::                 /* virtual override */
+AddUndoRecord(bool bInsert, const CPoint & ptStartPos,
                const CPoint & ptEndPos, LPCTSTR pszText, size_t cchText,
                int nActionType /*= CE_ACTION_UNKNOWN*/,
-               CDWordArray *paSavedRevisionNumbers)
+               CDWordArray *paSavedRevisionNumbers /*= nullptr*/)
 {
        CGhostTextBuffer::AddUndoRecord(bInsert, ptStartPos, ptEndPos, pszText,
                cchText, nActionType, paSavedRevisionNumbers);
@@ -204,6 +156,7 @@ void CDiffTextBuffer::AddUndoRecord(bool bInsert, const CPoint & ptStartPos,
                m_pOwnerDoc->curUndo = m_pOwnerDoc->undoTgt.end();
        }
 }
+
 /**
  * @brief Checks if a flag is set for line.
  * @param [in] line Index (0-based) for line.
@@ -236,12 +189,13 @@ void CDiffTextBuffer::prepareForRescan()
 /** 
  * @brief Called when line has been edited.
  * After editing a line, we don't know if there is a diff or not.
- * So we clear the LF_DIFF flag (and it is more easy to read during edition).
+ * So we clear the LF_DIFF flag (and it is more easy to read during editing).
  * Rescan will set the proper color.
  * @param [in] nLine Line that has been edited.
  */
 
-void CDiffTextBuffer::OnNotifyLineHasBeenEdited(int nLine)
+void CDiffTextBuffer::                 /* virtual override */
+OnNotifyLineHasBeenEdited(int nLine)
 {
        SetLineFlag(nLine, LF_DIFF, false, false, false);
        SetLineFlag(nLine, LF_TRIVIAL, false, false, false);
@@ -251,24 +205,6 @@ void CDiffTextBuffer::OnNotifyLineHasBeenEdited(int nLine)
 }
 
 /**
- * @brief Set the folder for temp files.
- * @param [in] path Temp files folder.
- */
-void CDiffTextBuffer::SetTempPath(const String &path)
-{
-       m_strTempPath = path;
-}
-
-/**
- * @brief Is the buffer initialized?
- * @return true if the buffer is initialized, false otherwise.
- */
-bool CDiffTextBuffer::IsInitialized() const
-{
-       return !!m_bInit;
-}
-
-/**
  * @brief Load file from disk into buffer
  *
  * @param [in] pszFileNameInit File to load
@@ -293,31 +229,30 @@ int CDiffTextBuffer::LoadFromFile(LPCTSTR pszFileNameInit,
        ASSERT(m_aLines.size() == 0);
 
        // Unpacking the file here, save the result in a temporary file
-       String sFileName(pszFileNameInit);
-       if (!FileTransform::Unpacking(infoUnpacker, sFileName, sToFindUnpacker))
+       m_strTempFileName = pszFileNameInit;
+       if (!FileTransform::Unpacking(infoUnpacker, &m_unpackerSubcode, m_strTempFileName, sToFindUnpacker))
        {
                InitNew(); // leave crystal editor in valid, empty state
                return FileLoadResult::FRESULT_ERROR_UNPACK;
        }
-       m_unpackerSubcode = infoUnpacker->subcode;
 
        // we use the same unpacker for both files, so it must be defined after first file
-       ASSERT(infoUnpacker->bToBeScanned != PLUGIN_AUTO);
+       ASSERT(infoUnpacker->m_PluginOrPredifferMode != PLUGIN_MODE::PLUGIN_AUTO);
        // we will load the transformed file
-       LPCTSTR pszFileName = sFileName.c_str();
+       LPCTSTR pszFileName = m_strTempFileName.c_str();
 
        String sExt;
        DWORD nRetVal = FileLoadResult::FRESULT_OK;
 
        // Set encoding based on extension, if we know one
-       paths::SplitFilename(pszFileName, NULL, NULL, &sExt);
-       CCrystalTextView::TextDefinition *def = 
-               CCrystalTextView::GetTextType(sExt.c_str());
+       paths::SplitFilename(pszFileName, nullptr, nullptr, &sExt);
+       CrystalLineParser::TextDefinition *def = 
+               CrystalLineParser::GetTextType(sExt.c_str());
        if (def && def->encoding != -1)
                m_nSourceEncoding = def->encoding;
        
-       UniFile *pufile = infoUnpacker->pufile;
-       if (pufile == 0)
+       UniFile *pufile = infoUnpacker->m_pufile;
+       if (pufile == nullptr)
                pufile = new UniMemFile;
 
        // Now we only use the UniFile interface
@@ -335,11 +270,11 @@ int CDiffTextBuffer::LoadFromFile(LPCTSTR pszFileNameInit,
        }
        else
        {
-               if (infoUnpacker->pluginName.length() > 0)
+               if (infoUnpacker->m_PluginName.length() > 0)
                {
                        // re-detect codepage
                        int iGuessEncodingType = GetOptionsMgr()->GetInt(OPT_CP_DETECT);
-                       FileTextEncoding encoding2 = GuessCodepageEncoding(pszFileName, iGuessEncodingType);
+                       FileTextEncoding encoding2 = codepage_detect::Guess(pszFileName, iGuessEncodingType);
                        pufile->SetUnicoding(encoding2.m_unicoding);
                        pufile->SetCodepage(encoding2.m_codepage);
                        pufile->SetBom(encoding2.m_bom);
@@ -405,11 +340,11 @@ int CDiffTextBuffer::LoadFromFile(LPCTSTR pszFileNameInit,
        
                
                //Try to determine current CRLF mode (most frequent)
-               if (nCrlfStyle == CRLF_STYLE_AUTOMATIC)
+               if (nCrlfStyle == CRLFSTYLE::AUTOMATIC)
                {
                        nCrlfStyle = GetTextFileStyle(pufile->GetTxtStats());
                }
-               ASSERT(nCrlfStyle >= 0 && nCrlfStyle <= 3);
+               ASSERT (nCrlfStyle != CRLFSTYLE::AUTOMATIC);
                SetCRLFMode(nCrlfStyle);
                
                //  At least one empty line must present
@@ -471,18 +406,18 @@ int CDiffTextBuffer::LoadFromFile(LPCTSTR pszFileNameInit,
  * @brief Saves file from buffer to disk
  *
  * @param bTempFile : false if we are saving user files and
- * true if we are saving workin-temp-files for diff-engine
+ * true if we are saving working-temp-files for diff-engine
  *
  * @return SAVE_DONE or an error code (list in MergeDoc.h)
  */
 int CDiffTextBuffer::SaveToFile (const String& pszFileName,
-               bool bTempFile, String & sError, PackingInfo * infoUnpacker /*= NULL*/,
-               CRLFSTYLE nCrlfStyle /*= CRLF_STYLE_AUTOMATIC*/,
+               bool bTempFile, String & sError, PackingInfo * infoUnpacker /*= nullptr*/,
+               CRLFSTYLE nCrlfStyle /*= CRLFSTYLE::AUTOMATIC*/,
                bool bClearModifiedFlag /*= true*/,
                int nStartLine /*= 0*/, int nLines /*= -1*/)
 {
-       ASSERT (nCrlfStyle == CRLF_STYLE_AUTOMATIC || nCrlfStyle == CRLF_STYLE_DOS ||
-               nCrlfStyle == CRLF_STYLE_UNIX || nCrlfStyle == CRLF_STYLE_MAC);
+       ASSERT (nCrlfStyle == CRLFSTYLE::AUTOMATIC || nCrlfStyle == CRLFSTYLE::DOS ||
+               nCrlfStyle == CRLFSTYLE::UNIX || nCrlfStyle == CRLFSTYLE::MAC);
        ASSERT (m_bInit);
 
        if (nLines == -1)
@@ -491,33 +426,35 @@ int CDiffTextBuffer::SaveToFile (const String& pszFileName,
        if (pszFileName.empty())
                return SAVE_FAILED;     // No filename, cannot save...
 
-       if (nCrlfStyle == CRLF_STYLE_AUTOMATIC &&
+       if (nCrlfStyle == CRLFSTYLE::AUTOMATIC &&
                !GetOptionsMgr()->GetBool(OPT_ALLOW_MIXED_EOL) ||
-               infoUnpacker && infoUnpacker->disallowMixedEOL)
+               infoUnpacker!=nullptr && infoUnpacker->m_bDisallowMixedEOL)
        {
                        // get the default nCrlfStyle of the CDiffTextBuffer
                nCrlfStyle = GetCRLFMode();
-               ASSERT(nCrlfStyle >= 0 && nCrlfStyle <= 3);
+               ASSERT(nCrlfStyle != CRLFSTYLE::AUTOMATIC);
        }
 
        bool bOpenSuccess = true;
        bool bSaveSuccess = false;
 
        UniStdioFile file;
-       file.SetUnicoding(m_encoding.m_unicoding);
-       file.SetBom(m_encoding.m_bom);
-       file.SetCodepage(m_encoding.m_codepage);
 
        String sIntermediateFilename; // used when !bTempFile
 
        if (bTempFile)
        {
+               file.SetUnicoding(ucr::UTF8);
+               file.SetBom(GetOptionsMgr()->GetInt(OPT_CMP_DIFF_ALGORITHM) == 0);
                bOpenSuccess = !!file.OpenCreate(pszFileName);
        }
        else
        {
+               file.SetUnicoding(m_encoding.m_unicoding);
+               file.SetBom(m_encoding.m_bom);
+               file.SetCodepage(m_encoding.m_codepage);
                sIntermediateFilename = env::GetTemporaryFileName(m_strTempPath,
-                       _T("MRG_"), NULL);
+                       _T("MRG_"), nullptr);
                if (sIntermediateFilename.empty())
                        return SAVE_FAILED;  //Nothing to do if even tempfile name fails
                bOpenSuccess = !!file.OpenCreate(sIntermediateFilename);
@@ -531,10 +468,10 @@ int CDiffTextBuffer::SaveToFile (const String& pszFileName,
                        sError = uniErr.GetError();
                        if (bTempFile)
                                LogErrorString(strutils::format(_T("Opening file %s failed: %s"),
-                                       pszFileName.c_str(), sError.c_str()));
+                                       pszFileName, sError));
                        else
                                LogErrorString(strutils::format(_T("Opening file %s failed: %s"),
-                                       sIntermediateFilename.c_str(), sError.c_str()));
+                                       sIntermediateFilename, sError));
                }
                return SAVE_FAILED;
        }
@@ -544,6 +481,7 @@ int CDiffTextBuffer::SaveToFile (const String& pszFileName,
        // line loop : get each real line and write it in the file
        String sLine;
        String sEol = GetStringEol(nCrlfStyle);
+       int lastRealLine = ApparentLastRealLine();
        for (int line = nStartLine; line < nStartLine + nLines; ++line)
        {
                if (GetLineFlags(line) & LF_GHOST)
@@ -560,21 +498,27 @@ int CDiffTextBuffer::SaveToFile (const String& pszFileName,
                else
                        sLine = _T("");
 
-               if (bTempFile)
-                       EscapeControlChars(sLine);
+               if (bTempFile && m_bTableEditing && m_bAllowNewlinesInQuotes)
+               {
+                       strutils::replace(sLine, _T("\x1b"), _T("\x1b\x1b"));
+                       strutils::replace(sLine, _T("\r"), _T("\x1br"));
+                       strutils::replace(sLine, _T("\n"), _T("\x1bn"));
+               }
+
                // last real line ?
-               int lastRealLine = ApparentLastRealLine();
                if (line == lastRealLine || lastRealLine == -1 )
                {
-                       // last real line is never EOL terminated
-                       ASSERT (_tcslen(GetLineEol(line)) == 0);
-                       // write the line and exit loop
-                       file.WriteString(sLine);
-                       break;
+                       // If original last line had no EOL, then we are done
+                       if( !m_aLines[line].HasEol() )
+                       {
+                               file.WriteString(sLine);
+                               break;
+                       }
+                       // Otherwise, add the appropriate EOL to the last line ...
                }
 
-               // normal real line : append an EOL
-               if (nCrlfStyle == CRLF_STYLE_AUTOMATIC || nCrlfStyle == CRLF_STYLE_MIXED)
+               // normal line : append an EOL
+               if (nCrlfStyle == CRLFSTYLE::AUTOMATIC || nCrlfStyle == CRLFSTYLE::MIXED)
                {
                        // either the EOL of the line (when preserve original EOL chars is on)
                        sLine += GetLineEol(line);
@@ -587,6 +531,12 @@ int CDiffTextBuffer::SaveToFile (const String& pszFileName,
 
                // write this line to the file (codeset or unicode conversions are done there
                file.WriteString(sLine);
+
+               if (line == lastRealLine || lastRealLine == -1)
+               {
+                       // Last line, so now done
+                       break;
+               }
        }
        file.Close();
 
@@ -594,60 +544,34 @@ int CDiffTextBuffer::SaveToFile (const String& pszFileName,
        {
                // If we are saving user files
                // we need an unpacker/packer, at least a "do nothing" one
-               ASSERT(infoUnpacker != NULL);
+               ASSERT(infoUnpacker != nullptr);
                // repack the file here, overwrite the temporary file we did save in
-               String csTempFileName = sIntermediateFilename;
-               infoUnpacker->subcode = m_unpackerSubcode;
-               if (!FileTransform::Packing(csTempFileName, *infoUnpacker))
+               bSaveSuccess = FileTransform::Packing(sIntermediateFilename, pszFileName, *infoUnpacker, m_unpackerSubcode);
+               try
                {
-                       try
-                       {
-                               TFile(sIntermediateFilename).remove();
-                       }
-                       catch (Exception& e)
-                       {
-                               LogErrorStringUTF8(e.displayText());
-                       }
-                       // returns now, don't overwrite the original file
-                       return SAVE_PACK_FAILED;
+                       TFile(sIntermediateFilename).remove();
                }
-               // the temp filename may have changed during packing
-               if (csTempFileName != sIntermediateFilename)
+               catch (Exception& e)
                {
-                       try
-                       {
-                               TFile(sIntermediateFilename).remove();
-                       }
-                       catch (Exception& e)
-                       {
-                               LogErrorStringUTF8(e.displayText());
-                       }
-                       sIntermediateFilename = csTempFileName;
+                       LogErrorStringUTF8(e.displayText());
                }
-
-               // Write tempfile over original file
-               try
+               if (!bSaveSuccess)
                {
-                       TFile file1(sIntermediateFilename);
-                       file1.copyTo(pszFileName);
-                       file1.remove();
-                       if (bClearModifiedFlag)
-                       {
-                               SetModified(false);
-                               m_nSyncPosition = m_nUndoPosition;
-                       }
-                       bSaveSuccess = true;
-
-                       // remember revision number on save
-                       m_dwRevisionNumberOnSave = m_dwCurrentRevisionNumber;
-
-                       // redraw line revision marks
-                       UpdateViews (NULL, NULL, UPDATE_FLAGSONLY);     
+                       // returns now, don't overwrite the original file
+                       return SAVE_PACK_FAILED;
                }
-               catch (Exception& e)
+
+               if (bClearModifiedFlag)
                {
-                       LogErrorStringUTF8(e.displayText());
+                       SetModified(false);
+                       m_nSyncPosition = m_nUndoPosition;
                }
+
+               // remember revision number on save
+               m_dwRevisionNumberOnSave = m_dwCurrentRevisionNumber;
+
+               // redraw line revision marks
+               UpdateViews (nullptr, nullptr, UPDATE_FLAGSONLY);       
        }
        else
        {
@@ -694,9 +618,9 @@ bool CDiffTextBuffer::curUndoGroup()
        return (m_aUndoBuf.size() != 0 && m_aUndoBuf[0].m_dwFlags&UNDO_BEGINGROUP);
 }
 
-bool CDiffTextBuffer::
+bool CDiffTextBuffer::                 /* virtual override */
 DeleteText2(CCrystalTextView * pSource, int nStartLine, int nStartChar,
-       int nEndLine, int nEndChar, int nAction, bool bHistory /*=true*/)
+       int nEndLine, int nEndChar, int nAction /*= CE_ACTION_UNKNOWN*/, bool bHistory /*= true*/)
 {
        for (auto syncpnt : m_pOwnerDoc->GetSyncPointList())
        {