OSDN Git Service

PATCH: [ 1526918 ] Detect which side file is binary file
authorKimmo Varis <kimmov@gmail.com>
Mon, 24 Jul 2006 11:18:43 +0000 (11:18 +0000)
committerKimmo Varis <kimmov@gmail.com>
Mon, 24 Jul 2006 11:18:43 +0000 (11:18 +0000)
Src/Changes.txt
Src/DiffItem.h
Src/DiffWrapper.cpp
Src/DiffWrapper.h
Src/diffutils/src/DIFF.H
Src/diffutils/src/IO.C
Src/diffutils/src/analyze.c

index 1c4fec7..ba8e41b 100644 (file)
@@ -2,6 +2,11 @@ Src\Changes.txt
 Add new items to top.
 (This summarizes all changes to all files under Src, including Src\Languages.)
 
+2006-07-24 Kimmo
+ PATCH: [ 1526918 ] Detect which side file is binary file
+  Src: DiffItem.h DiffWrapper.cpp DiffWrapper.h
+  Src/diffutils/src: DIFF.H IO.c analyze.c
+
 2006-07-20 WinMerge experimental release 2.5.5.4 (cvs)
 
 2006-07-20 Kimmo
index d1b52ea..5d10efa 100644 (file)
 #endif
 
 /**
+ * @brief Bitfield values for binary file sides.
+ * These values are used as bitfield values when determining which file(s)
+ * are binary files. There is no "both" -value since in bitfield "both" is
+ * when side1- and side2- bits are set (BINFILE_SIDE1 | BINFILE_SIDE2).
+ */
+enum BINFILE_SIDE
+{
+       BINFILE_NONE = 0, /**< No binary files detected. */
+       BINFILE_SIDE1, /**< First file was detected as binary file. */
+       BINFILE_SIDE2, /**< Second file was detected as binart file. */
+};
+
+/**
  * @brief Status of one item comparison, stored as bitfields
  *
  * Bitmask can be seen as a 4 dimensional space; that is, there are four
@@ -41,7 +54,7 @@ struct DIFFCODE
                // and each set of flags is in a different hex digit
                // to make debugging easier
                // These can always be packed down in the future
-               TEXTFLAGS=0x3, TEXT=0x1, BIN=0x2,
+               TEXTFLAGS=0x7, TEXT=0x1, BINSIDE1=0x2, BINSIDE2=0x3, BIN=0x4,
                DIRFLAGS=0x30, FILE=0x10, DIR=0x20,
                SIDEFLAGS=0x300, LEFT=0x100, RIGHT=0x200, BOTH=0x300,
                COMPAREFLAGS=0x7000, NOCMP=0x0000, SAME=0x1000, DIFF=0x2000, CMPERR=0x3000, CMPABORT=0x4000,
@@ -53,7 +66,7 @@ struct DIFFCODE
 
        DIFFCODE(int diffcode = 0) : diffcode(diffcode) { }
 
-private:
+protected:
        static bool Check(int code, int mask, int result) { return ((code & mask) == result); }
        static bool CheckCompare(int code, int result) { return Check(code, DIFFCODE::COMPAREFLAGS, result); }
        static bool CheckFilter(int code, int result) { return Check(code, DIFFCODE::FILTERFLAGS, result); }
@@ -86,7 +99,9 @@ public:
        // filter status
        bool isResultFiltered() const { return CheckFilter(diffcode, DIFFCODE::SKIPPED); }
        // type
-       bool isBin() const { return Check(diffcode, DIFFCODE::TEXTFLAGS, DIFFCODE::BIN); }
+       bool isBin() const { return Check(diffcode, DIFFCODE::TEXTFLAGS, DIFFCODE::BIN) ||
+                       Check(diffcode, DIFFCODE::TEXTFLAGS, DIFFCODE::BINSIDE1) ||
+                       Check(diffcode, DIFFCODE::TEXTFLAGS, DIFFCODE::BINSIDE2); }
        void setBin() { Set(DIFFCODE::TEXTFLAGS, DIFFCODE::BIN); }
        // rescan
        bool isScanNeeded() const { return ((diffcode & DIFFCODE::SCANFLAGS) == DIFFCODE::NEEDSCAN); }
index 141facf..398e6c3 100644 (file)
@@ -846,10 +846,12 @@ BOOL CDiffWrapper::RunFileDiff(ARETEMPFILES areTempFiles)
                return FALSE;
        }
 
-       /* Compare the files, if no error was found.  */
+       // 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);
+       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.
@@ -1403,16 +1405,17 @@ void DiffFileData::GuessEncoding_from_FileLocation(FileLocation & fpenc)
 /**
  * @brief Compare two specified files.
  *
- * @param [in] Current directory depth.
+ * @param [in] depth Current directory depth.
  * @return Compare result as DIFFCODE.
  */
 int DiffFileData::diffutils_compare_files(int depth)
 {
        int bin_flag = 0;
+       int bin_file = 0; // bitmap for binary files
 
        // Do the actual comparison (generating a change script)
        struct change *script = NULL;
-       BOOL success = Diff2Files(&script, depth, &bin_flag, FALSE);
+       BOOL success = Diff2Files(&script, depth, &bin_flag, FALSE, &bin_file);
        if (!success)
        {
                return DIFFCODE::FILE | DIFFCODE::TEXT | DIFFCODE::CMPERR;
@@ -1447,7 +1450,19 @@ int DiffFileData::diffutils_compare_files(int depth)
        {
                // Clear text-flag, set binary flag
                // We don't know diff counts for binary files
-               code = code & ~DIFFCODE::TEXT | DIFFCODE::BIN;
+               code = code & ~DIFFCODE::TEXT;
+               switch (bin_file)
+               {
+               case BINFILE_SIDE1: code |= DIFFCODE::BINSIDE1;
+                       break;
+               case BINFILE_SIDE2: code |= DIFFCODE::BINSIDE2;
+                       break;
+               case BINFILE_SIDE1 | BINFILE_SIDE2: code |= DIFFCODE::BIN;
+                       break;
+               default:
+                       _RPTF1(_CRT_ERROR, "Invalid bin_file value: %d", bin_file);
+                       break;
+               }
                m_ndiffs = DiffFileData::DIFFS_UNKNOWN;
        }
 
@@ -1807,16 +1822,21 @@ static void CopyDiffutilTextStats(file_data *inf, DiffFileData * diffData)
  * @param [out] diffs Pointer to list of change structs where diffdata is stored.
  * @param [in] diffData files to compare.
  * @param [out] bin_status used to return binary status from compare.
+ * @param [out] bin_file Returns which file was binary file as bitmap.
+    So if first file is binary, first bit is set etc. Can be NULL if binary file
+    info is not needed (faster compare since diffutils don't bother checking
+    second file if first is binary).
  * @return TRUE when compare succeeds, FALSE if error happened during compare.
  */
 BOOL CDiffWrapper::Diff2Files(struct change ** diffs, DiffFileData *diffData,
-       int * bin_status)
+       int * bin_status, int * bin_file)
 {
        BOOL bRet = TRUE;
        __try
        {
                // Diff files. depth is zero because we are not comparing dirs
-               *diffs = diff_2_files (diffData->m_inf, 0, bin_status, m_bDetectMovedBlocks);
+               *diffs = diff_2_files (diffData->m_inf, 0, bin_status,
+                               m_bDetectMovedBlocks, bin_file);
                CopyDiffutilTextStats(diffData->m_inf, diffData);
        }
        __except (EXCEPTION_EXECUTE_HANDLER)
@@ -1827,13 +1847,29 @@ BOOL CDiffWrapper::Diff2Files(struct change ** diffs, DiffFileData *diffData,
        return bRet;
 }
 
+/**
+ * @brief Compare two files using diffutils.
+ *
+ * Compare two files (in DiffFileData param) using diffutils. Run diffutils
+ * inside SEH so we can trap possible error and exceptions. If error or
+ * execption is trapped, return compare failure.
+ * @param [out] diffs Pointer to list of change structs where diffdata is stored.
+ * @param [in] depth Depth in folder compare (we use 0).
+ * @param [out] bin_status used to return binary status from compare.
+ * @param [in] bMovedBlocks If TRUE moved blocks are analyzed.
+ * @param [out] bin_file Returns which file was binary file as bitmap.
+    So if first file is binary, first bit is set etc. Can be NULL if binary file
+    info is not needed (faster compare since diffutils don't bother checking
+    second file if first is binary).
+ * @return TRUE when compare succeeds, FALSE if error happened during compare.
+ */
 BOOL DiffFileData::Diff2Files(struct change ** diffs, int depth,
-       int * bin_status, BOOL bMovedBlocks)
+       int * bin_status, BOOL bMovedBlocks, int * bin_file)
 {
        BOOL bRet = TRUE;
        __try
        {
-               *diffs = diff_2_files (m_inf, depth, bin_status, bMovedBlocks);
+               *diffs = diff_2_files (m_inf, depth, bin_status, bMovedBlocks, bin_file);
                CopyDiffutilTextStats(m_inf, this);
        }
        __except (EXCEPTION_EXECUTE_HANDLER)
@@ -1973,10 +2009,13 @@ int DiffFileData::byte_compare_files(BOOL bStopAfterFirstDiff, const IAbortable
 
                        BOOL bBin0 = (m_textStats0.nzeros>0);
                        BOOL bBin1 = (m_textStats1.nzeros>0);
-                       if (bBin0 || bBin1)
-                       {
+
+                       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)
index d2226bf..7e058a2 100644 (file)
@@ -232,7 +232,7 @@ protected:
        void SwapToGlobalSettings();
        CString FormatSwitchString();
        BOOL Diff2Files(struct change ** diffs, DiffFileData *diffData,
-               int * bin_status);
+               int * bin_status, int * bin_file);
        void LoadWinMergeDiffsFromDiffUtilsScript(struct change * script, const file_data * inf);
        void WritePatchFile(struct change * script, file_data * inf);
 
@@ -295,7 +295,7 @@ struct DiffFileData
        int byte_compare_files(BOOL bStopAfterFirstDiff, const IAbortable * piAbortable);
        int prepAndCompareTwoFiles(CDiffContext * pCtxt, DIFFITEM &di);
        BOOL Diff2Files(struct change ** diffs, int depth,
-               int * bin_status, BOOL bMovedBlocks);
+               int * bin_status, BOOL bMovedBlocks, int * bin_file);
        bool Filepath_Transform(FileLocation & fpenc, const CString & filepath, CString & filepathTransformed,
                const CString & filteredFilenames, PrediffingInfo * infoPrediffer, int fd);
        void GuessEncoding_from_buffer_in_DiffContext(int side, CDiffContext * pCtxt);
index 0ddd54d..9953423 100644 (file)
@@ -299,7 +299,8 @@ EXTERN FILE *outfile;
 /* Declare various functions.  */
 
 /* analyze.c */
-struct change * diff_2_files PARAMS((struct file_data[], int, int *, int));
+/* WinMerge: add last two params */
+struct change * diff_2_files PARAMS((struct file_data[], int, int *, int, int*));
 
 /* context.c */
 void print_context_header PARAMS((struct file_data[], int));
@@ -319,7 +320,8 @@ void pr_forward_ed_script PARAMS((struct change *));
 void print_ifdef_script PARAMS((struct change *));
 
 /* io.c */
-int read_files PARAMS((struct file_data[], int));
+/* WinMerge: add last pointer param */
+int read_files PARAMS((struct file_data[], int, int *));
 int sip PARAMS((struct file_data *, int));
 void slurp PARAMS((struct file_data *));
 
index 441cf3e..e8d7197 100644 (file)
@@ -798,25 +798,45 @@ static int const primes[] =
    with each one, and build the table of equivalence classes.
    Return 1 if either file appears to be a binary file.
    If PRETEND_BINARY is nonzero, pretend they are binary regardless.  */
-
+/* WinMerge: Add int * bin_file param for getting actual binary file
+   If bin_file is given, then check both files for binary files,
+   otherwise check second file only if first wasn't binary */
 int
-read_files (filevec, pretend_binary)
+read_files (filevec, pretend_binary, bin_file)
      struct file_data filevec[];
      int pretend_binary;
+        int * bin_file;
 {
   int i;
   int skip_test = always_text_flag | pretend_binary;
-  int appears_binary = pretend_binary | sip (&filevec[0], skip_test);
+  int appears_binary = 0;
+
+  if (bin_file)
+    *bin_file = 0;
+  appears_binary = pretend_binary | sip (&filevec[0], skip_test);
+  if (bin_file && appears_binary)
+    {
+      *bin_file = 1;
+    }
 
   if (filevec[0].desc != filevec[1].desc)
-    appears_binary |= sip (&filevec[1], skip_test | appears_binary);
+    {
+      if (bin_file)
+        {
+          appears_binary = pretend_binary | sip (&filevec[1], skip_test);
+          if (appears_binary)
+            *bin_file |= 0x2; // set second bit for second file
+        }
+      else
+        appears_binary |= sip (&filevec[1], skip_test | appears_binary);
+    }
   else
     {
       filevec[1].buffer = filevec[0].buffer;
       filevec[1].bufsize = filevec[0].bufsize;
       filevec[1].buffered_chars = filevec[0].buffered_chars;
     }
-  if (appears_binary)
+  if (appears_binary || (bin_file && *bin_file > 0))
     return 1;
 
   find_identical_ends (filevec);
index 1825852..34de8cd 100644 (file)
@@ -837,7 +837,10 @@ briefly_report (changes, filevec)
 
 //  Report the differences of two files.  DEPTH is the current directory
 // depth. 
-struct change * diff_2_files (struct file_data filevec[], int depth, int * bin_status, int moved_blocks_flag)
+// WinMerge: add moved_blocks_flag for detecting moved blocks and
+// bin_file for getting info which file is binary file (can be NULL)
+struct change * diff_2_files (struct file_data filevec[], int depth, int * bin_status,
+       int moved_blocks_flag, int * bin_file)
 {
        int diags;
        int i;
@@ -851,7 +854,7 @@ struct change * diff_2_files (struct file_data filevec[], int depth, int * bin_s
        // Also, --brief without any --ignore-* options means
        // we can speed things up by treating the files as binary.  
        
-       if (read_files (filevec, no_details_flag & ~ignore_some_changes))
+       if (read_files (filevec, no_details_flag & ~ignore_some_changes, bin_file))
        {
                //  Files with different lengths must be different.  
                if (filevec[0].stat.st_size != filevec[1].stat.st_size