From 4e8f211179b54051743c59a6bad28d308ee7b903 Mon Sep 17 00:00:00 2001 From: Kimmo Varis Date: Tue, 21 Aug 2007 14:11:04 +0000 Subject: [PATCH] PATCH: [ 1777732 ] Separate Quick compare code to CompareEngine --- Src/{ => CompareEngines}/ByteComparator.cpp | 1 + Src/{ => CompareEngines}/ByteComparator.h | 4 + Src/CompareEngines/ByteCompare.cpp | 290 ++++++++++++++++++++++++++++ Src/CompareEngines/ByteCompare.h | 47 +++++ Src/CompareOptions.cpp | 6 + Src/CompareOptions.h | 1 + Src/FolderCmp.cpp | 185 +++--------------- Src/FolderCmp.h | 2 + Src/Merge.dsp | 24 ++- 9 files changed, 394 insertions(+), 166 deletions(-) rename Src/{ => CompareEngines}/ByteComparator.cpp (99%) rename Src/{ => CompareEngines}/ByteComparator.h (97%) create mode 100644 Src/CompareEngines/ByteCompare.cpp create mode 100644 Src/CompareEngines/ByteCompare.h diff --git a/Src/ByteComparator.cpp b/Src/CompareEngines/ByteComparator.cpp similarity index 99% rename from Src/ByteComparator.cpp rename to Src/CompareEngines/ByteComparator.cpp index 7e5e3f0cb..db82256cf 100644 --- a/Src/ByteComparator.cpp +++ b/Src/CompareEngines/ByteComparator.cpp @@ -17,6 +17,7 @@ static char THIS_FILE[] = __FILE__; #endif +using namespace CompareEngines; /** * @brief Returns if given char is EOL byte. diff --git a/Src/ByteComparator.h b/Src/CompareEngines/ByteComparator.h similarity index 97% rename from Src/ByteComparator.h rename to Src/CompareEngines/ByteComparator.h index b08e9d019..5d860fc07 100644 --- a/Src/ByteComparator.h +++ b/Src/CompareEngines/ByteComparator.h @@ -12,6 +12,8 @@ class QuickCompareOptions; struct FileTextStats; +namespace CompareEngines +{ /** * @brief Byte per byte compare class implementing Quick Compare. @@ -59,4 +61,6 @@ private: bool m_bol1; /**< 1-side is at beginning of line (!ignore_eol_differences & ignore_blank_lines) */ }; +} // namespace CompareEngines + #endif // ByteComparator_h_included diff --git a/Src/CompareEngines/ByteCompare.cpp b/Src/CompareEngines/ByteCompare.cpp new file mode 100644 index 000000000..36e71b5e9 --- /dev/null +++ b/Src/CompareEngines/ByteCompare.cpp @@ -0,0 +1,290 @@ +/** + * @file ByteCompare.cpp + * + * @brief Implementation file for ByteCompare + */ +// ID line follows -- this is updated by SVN +// $Id$ + +#include "stdafx.h" +#include "UnicodeString.h" +#include "IAbortable.h" +#include "CompareOptions.h" +#include "FilterList.h" +#include "DiffContext.h" +#include "FileTransform.h" +#include "diff.h" +#include "ByteComparator.h" +#include "ByteCompare.h" + +namespace CompareEngines +{ + +static const int KILO = 1024; // Kilo(byte) + +/** @brief Quick contents compare's file buffer size. */ +static const int WMCMPBUFF = 32 * KILO; + +static void CopyTextStats(const FileTextStats * stats, FileTextStats * myTextStats); + +struct FileHandle +{ + FileHandle() : m_fp(0) { } + void Assign(FILE * fp) { Close(); m_fp = fp; } + void Close() { if (m_fp) { fclose(m_fp); m_fp = 0; } } + ~FileHandle() { Close(); } + FILE * m_fp; +}; + +/** + * @brief Default constructor. + */ +ByteCompare::ByteCompare() +: m_pOptions(NULL) +, m_piAbortable(NULL) +, m_inf(NULL) +{ +} + +/** + * @brief Default destructor. + */ +ByteCompare::~ByteCompare() +{ + ClearCompareOptions(); +} + +/** + * @brief Set compare options from general compare options. + * @param [in ]options General compare options. + * @return true if succeeded, false otherwise. + */ +bool ByteCompare::SetCompareOptions(const CompareOptions & options) +{ + if (m_pOptions != NULL) + ClearCompareOptions(); + + m_pOptions = new QuickCompareOptions(options); + if (m_pOptions == NULL) + return false; + return true; +} + +/** + * @brief Clear current compare options. + */ +void ByteCompare::ClearCompareOptions() +{ + delete m_pOptions; + m_pOptions = NULL; +} + +/** + * @brief Set compare-type specific options. + * @param [in] stopAfterFirstDiff Do we stop compare after first found diff. + */ +void ByteCompare::SetAdditionalOptions(BOOL stopAfterFirstDiff) +{ + m_pOptions->m_bStopAfterFirstDiff = stopAfterFirstDiff; +} + +/** + * @brief Set Abortable-interface. + * @param [in] piAbortable Pointer to abortable interface. + */ +void ByteCompare::SetAbortable(const IAbortable * piAbortable) +{ + m_piAbortable = const_cast(piAbortable); +} + +/** + * @brief Set compared paths. + * @param [in] path1 First path to compare. + * @param [in] path2 Second path to compare. + */ +void ByteCompare::SetPaths(LPCTSTR path1, LPCTSTR path2) +{ + m_paths[0] = path1; + m_paths[1] = path2; +} + +/** + * @brief Set filedata. + * @param [in] items Count of filedata items to set. + * @param [in] data File data. + * @note Path names are set by SetPaths() function. + */ +void ByteCompare::SetFileData(int items, file_data *data) +{ + // We support only two files currently! + ASSERT(items == 2); + m_inf = data; +} + + +/** + * @brief Compare two specified files, byte-by-byte + * @param [in] bStopAfterFirstDiff Stop compare after we find first difference? + * @param [in] piAbortable Interface allowing to abort compare + * @return DIFFCODE + */ +int ByteCompare::CompareFiles() +{ + // TODO + // Right now, we assume files are in 8-bit encoding + // because transform code converted any UCS-2 files to UTF-8 + // We could compare directly in UCS-2LE here, as an optimization, in that case + char buff[2][WMCMPBUFF]; // buffered access to files + FILE * fp[2]; // for files to compare + FileHandle fhd[2]; // to ensure file handles fp get closed + int i; + int diffcode = 0; + + // Open both files + for (i = 0; i < 2; ++i) + { + //fp[i] = _tfopen(m_diffFileData.m_FileLocation[i].filepath, _T("rb")); + fp[i] = _tfopen(m_paths[i].c_str(), _T("rb")); + if (!fp[i]) + return DIFFCODE::CMPERR; + fhd[i].Assign(fp[i]); + } + + // area of buffer currently holding data + __int64 bfstart[2]; // offset into buff[i] where current data resides + __int64 bfend[2]; // past-the-end pointer into buff[i], giving end of current data + // buff[0] has bytes to process from buff[0][bfstart[0]] to buff[0][bfend[0]-1] + + bool eof[2]; // if we've finished file + + // initialize our buffer pointers and end of file flags + for (i=0; i<2; ++i) + { + bfstart[i] = bfend[i] = 0; + eof[i] = false; + } + + ByteComparator comparator(m_pOptions); + + // Begin loop + // we handle the files in WMCMPBUFF sized buffers (variable buff[][]) + // That is, we do one buffer full at a time + // or even less, as we process until one side buffer is empty, then reload that one + // and continue + while (!eof[0] || !eof[1]) + { + if (m_piAbortable && m_piAbortable->ShouldAbort()) + return DIFFCODE::CMPABORT; + + // load or update buffers as appropriate + for (i=0; i<2; ++i) + { + if (!eof[i] && bfstart[i]==countof(buff[i])) + { + bfstart[i]=bfend[i] = 0; + } + if (!eof[i] && bfend[i]m_bStopAfterFirstDiff) + { + // By bailing out here + // we leave our text statistics incomplete + return diffcode | DIFFCODE::DIFF; + } + else + { + diffcode |= DIFFCODE::DIFF; + ptr0 = end0; + ptr1 = end1; + } + } + else + { + ptr0 = end0; + ptr1 = end1; + } + + + // did we finish both files? + if (eof[0] && eof[1]) + { + + BOOL bBin0 = (m_textStats[0].nzeros>0); + BOOL bBin1 = (m_textStats[1].nzeros>0); + + if (bBin0 && bBin1) + diffcode |= DIFFCODE::BIN; + else if (bBin0) + diffcode |= DIFFCODE::BINSIDE1; + else if (bBin1) + diffcode |= DIFFCODE::BINSIDE2; + + // If either unfinished, they differ + if (ptr0 != end0 || ptr1 != end1) + diffcode = (diffcode & DIFFCODE::DIFF); + + if (diffcode & DIFFCODE::DIFF) + return diffcode | DIFFCODE::DIFF; + else + return diffcode | DIFFCODE::SAME; + } + + // move our current pointers over what we just compared + ASSERT(ptr0 >= orig0); + ASSERT(ptr1 >= orig1); + bfstart[0] += ptr0-orig0; + bfstart[1] += ptr1-orig1; + } + return diffcode; +} + +/** + * @brief Copy text stat results from diffutils back into the FileTextStats structure + */ +static void CopyTextStats(const FileTextStats * stats, FileTextStats * myTextStats) +{ + myTextStats->ncrlfs = stats->ncrlfs; + myTextStats->ncrs = stats->ncrs; + myTextStats->nlfs = stats->nlfs; +} + +/** + * @brief Return text statistics for last compare. + * @param [in] side For which file to return statistics. + * @param [out] stats Stats as asked. + */ +void ByteCompare::GetTextStats(int side, FileTextStats *stats) +{ + CopyTextStats(&m_textStats[side], stats); +} + +} // namespace CompareEngines diff --git a/Src/CompareEngines/ByteCompare.h b/Src/CompareEngines/ByteCompare.h new file mode 100644 index 000000000..0a520775a --- /dev/null +++ b/Src/CompareEngines/ByteCompare.h @@ -0,0 +1,47 @@ +/** + * @file ByteCompare.h + * + * @brief Declaration file for ByteCompare + */ +// ID line follows -- this is updated by SVN +// $Id$ + +#ifndef _BYTE_COMPARE_H_ +#define _BYTE_COMPARE_H_ + +#include "UnicodeString.h" +#include "FileTextStats.h" + +class QuickCompareOptions; +class IAbortable; + +namespace CompareEngines +{ + +class ByteCompare +{ +public: + ByteCompare(); + ~ByteCompare(); + + bool SetCompareOptions(const CompareOptions & options); + void ClearCompareOptions(); + void SetAdditionalOptions(BOOL stopAfterFirstDiff); + void SetAbortable(const IAbortable * piAbortable); + void SetPaths(LPCTSTR path1, LPCTSTR path2); + void SetFileData(int items, file_data *data); + int CompareFiles(); + void GetTextStats(int side, FileTextStats *stats); + +private: + QuickCompareOptions *m_pOptions; /**< Compare options for diffutils. */ + IAbortable * m_piAbortable; + file_data * m_inf; /**< Compared files data (for diffutils). */ + String m_paths[2]; + FileTextStats m_textStats[2]; + +}; + +} // namespace CompareEngines + +#endif // _BYTE_COMPARE_H_ diff --git a/Src/CompareOptions.cpp b/Src/CompareOptions.cpp index 5c8514dc6..2847ac350 100644 --- a/Src/CompareOptions.cpp +++ b/Src/CompareOptions.cpp @@ -199,3 +199,9 @@ void DiffutilsOptions::GetAsDiffOptions(DIFFOPTIONS &options) break; } } + +QuickCompareOptions::QuickCompareOptions(const CompareOptions& options) +: CompareOptions(options) +, m_bStopAfterFirstDiff(FALSE) +{ +} diff --git a/Src/CompareOptions.h b/Src/CompareOptions.h index 3a3223cd2..2ae25324c 100644 --- a/Src/CompareOptions.h +++ b/Src/CompareOptions.h @@ -122,6 +122,7 @@ class QuickCompareOptions : public CompareOptions { public: QuickCompareOptions(); + QuickCompareOptions(const CompareOptions& options); BOOL m_bStopAfterFirstDiff; /**< Optimize compare by stopping after first difference? */ }; diff --git a/Src/FolderCmp.cpp b/Src/FolderCmp.cpp index ae5cc6e40..84723db6b 100644 --- a/Src/FolderCmp.cpp +++ b/Src/FolderCmp.cpp @@ -8,6 +8,7 @@ #include "stdafx.h" #include "DiffUtils.h" +#include "ByteCompare.h" #include "LogFile.h" #include "Merge.h" #include "paths.h" @@ -22,17 +23,13 @@ using namespace CompareEngines; -static const int KILO = 1024; // Kilo(byte) - -/** @brief Quick contents compare's file buffer size. */ -static const int WMCMPBUFF = 32 * KILO; - static void GetComparePaths(CDiffContext * pCtxt, const DIFFITEM &di, CString & left, CString & right); static bool Unpack(CString & filepathTransformed, const CString & filteredFilenames, PackingInfo * infoUnpacker); FolderCmp::FolderCmp() : m_pDiffUtilsEngine(NULL) +, m_pByteCompare(NULL) , m_ndiffs(CDiffContext::DIFFS_UNKNOWN) , m_ntrivialdiffs(CDiffContext::DIFFS_UNKNOWN) { @@ -41,6 +38,7 @@ FolderCmp::FolderCmp() FolderCmp::~FolderCmp() { delete m_pDiffUtilsEngine; + delete m_pByteCompare; } bool FolderCmp::RunPlugins(CDiffContext * pCtxt, PluginsContext * plugCtxt, CString &errStr) @@ -236,8 +234,30 @@ int FolderCmp::prepAndCompareTwoFiles(CDiffContext * pCtxt, DIFFITEM &di) } else if (nCompMethod == CMP_QUICK_CONTENT) { - // use our own byte-by-byte compare - code = byte_compare_files(pCtxt->m_bStopAfterFirstDiff, pCtxt->GetAbortable()); + if (m_pByteCompare == NULL) + m_pByteCompare = new ByteCompare(); + bool success = m_pByteCompare->SetCompareOptions( + *m_pCtx->GetCompareOptions(CMP_QUICK_CONTENT)); + + if (success) + { + m_pByteCompare->SetAdditionalOptions(pCtxt->m_bStopAfterFirstDiff); + m_pByteCompare->SetAbortable(pCtxt->GetAbortable()); + m_pByteCompare->SetPaths(m_diffFileData.m_FileLocation[0].filepath, + m_diffFileData.m_FileLocation[1].filepath); + m_pByteCompare->SetFileData(2, m_diffFileData.m_inf); + + // Close any descriptors open for diffutils + m_diffFileData.Reset(); + // use our own byte-by-byte compare + code = m_pByteCompare->CompareFiles(); + + m_pByteCompare->GetTextStats(0, &m_diffFileData.m_textStats0); + m_pByteCompare->GetTextStats(1, &m_diffFileData.m_textStats1); + } + else + code = DIFFCODE::FILE | DIFFCODE::TEXT | DIFFCODE::CMPERR; + // Quick contents doesn't know about diff counts // Set to special value to indicate invalid m_ndiffs = CDiffContext::DIFFS_UNKNOWN_QUICKCOMPARE; @@ -318,157 +338,6 @@ int FolderCmp::prepAndCompareTwoFiles(CDiffContext * pCtxt, DIFFITEM &di) return code; } -/** - * @brief Compare two specified files, byte-by-byte - * @param [in] bStopAfterFirstDiff Stop compare after we find first difference? - * @param [in] piAbortable Interface allowing to abort compare - * @return DIFFCODE - */ -int FolderCmp::byte_compare_files(BOOL bStopAfterFirstDiff, const IAbortable * piAbortable) -{ - QuickCompareOptions *pOptions = - dynamic_cast(m_pCtx->GetCompareOptions(CMP_QUICK_CONTENT)); - if (pOptions == NULL) - return DIFFCODE::FILE | DIFFCODE::TEXT | DIFFCODE::CMPERR; - - // Close any descriptors open for diffutils - m_diffFileData.Reset(); - - // TODO - // Right now, we assume files are in 8-bit encoding - // because transform code converted any UCS-2 files to UTF-8 - // We could compare directly in UCS-2LE here, as an optimization, in that case - char buff[2][WMCMPBUFF]; // buffered access to files - FILE * fp[2]; // for files to compare - FileHandle fhd[2]; // to ensure file handles fp get closed - int i; - int diffcode = 0; - - // Open both files - for (i=0; i<2; ++i) - { - fp[i] = _tfopen(m_diffFileData.m_FileLocation[i].filepath, _T("rb")); - if (!fp[i]) - return DIFFCODE::CMPERR; - fhd[i].Assign(fp[i]); - } - - // area of buffer currently holding data - __int64 bfstart[2]; // offset into buff[i] where current data resides - __int64 bfend[2]; // past-the-end pointer into buff[i], giving end of current data - // buff[0] has bytes to process from buff[0][bfstart[0]] to buff[0][bfend[0]-1] - - bool eof[2]; // if we've finished file - - // initialize our buffer pointers and end of file flags - for (i=0; i<2; ++i) - { - bfstart[i] = bfend[i] = 0; - eof[i] = false; - } - - ByteComparator comparator(pOptions); - - // Begin loop - // we handle the files in WMCMPBUFF sized buffers (variable buff[][]) - // That is, we do one buffer full at a time - // or even less, as we process until one side buffer is empty, then reload that one - // and continue - while (!eof[0] || !eof[1]) - { - if (piAbortable && piAbortable->ShouldAbort()) - return DIFFCODE::CMPABORT; - - // load or update buffers as appropriate - for (i=0; i<2; ++i) - { - if (!eof[i] && bfstart[i]==countof(buff[i])) - { - bfstart[i]=bfend[i] = 0; - } - if (!eof[i] && bfend[i]0); - BOOL bBin1 = (m_diffFileData.m_textStats1.nzeros>0); - - if (bBin0 && bBin1) - diffcode |= DIFFCODE::BIN; - else if (bBin0) - diffcode |= DIFFCODE::BINSIDE1; - else if (bBin1) - diffcode |= DIFFCODE::BINSIDE2; - - // If either unfinished, they differ - if (ptr0 != end0 || ptr1 != end1) - diffcode = (diffcode & DIFFCODE::DIFF); - - if (diffcode & DIFFCODE::DIFF) - return diffcode | DIFFCODE::DIFF; - else - return diffcode | DIFFCODE::SAME; - } - - // move our current pointers over what we just compared - ASSERT(ptr0 >= orig0); - ASSERT(ptr1 >= orig1); - bfstart[0] += ptr0-orig0; - bfstart[1] += ptr1-orig1; - } - return diffcode; -} /** * @brief Get actual compared paths from DIFFITEM. diff --git a/Src/FolderCmp.h b/Src/FolderCmp.h index ccee0a9b2..6ab8c0271 100644 --- a/Src/FolderCmp.h +++ b/Src/FolderCmp.h @@ -11,6 +11,7 @@ #include "DiffFileData.h" #include "DiffUtils.h" +#include "ByteCompare.h" //using namespace CompareEngines; @@ -59,6 +60,7 @@ public: private: CompareEngines::DiffUtils *m_pDiffUtilsEngine; + CompareEngines::ByteCompare *m_pByteCompare; }; diff --git a/Src/Merge.dsp b/Src/Merge.dsp index a59be7ae1..81d423c2f 100644 --- a/Src/Merge.dsp +++ b/Src/Merge.dsp @@ -167,10 +167,6 @@ SOURCE=.\BCMenu.cpp # End Source File # Begin Source File -SOURCE=.\ByteComparator.cpp -# End Source File -# Begin Source File - SOURCE=.\CCPrompt.cpp # End Source File # Begin Source File @@ -985,10 +981,6 @@ SOURCE=.\BCMenu.h # End Source File # Begin Source File -SOURCE=.\ByteComparator.h -# End Source File -# Begin Source File - SOURCE=.\CCPrompt.h # End Source File # Begin Source File @@ -2531,6 +2523,22 @@ SOURCE=.\ReadMe.txt # PROP Default_Filter "cpp;c;h" # Begin Source File +SOURCE=.\CompareEngines\ByteComparator.cpp +# End Source File +# Begin Source File + +SOURCE=.\CompareEngines\ByteComparator.h +# End Source File +# Begin Source File + +SOURCE=.\CompareEngines\ByteCompare.cpp +# End Source File +# Begin Source File + +SOURCE=.\CompareEngines\ByteCompare.h +# End Source File +# Begin Source File + SOURCE=.\CompareEngines\DiffUtils.cpp # End Source File # Begin Source File -- 2.11.0