diff --git a/Src/CompareEngines/Wrap_DiffUtils.cpp b/Src/CompareEngines/Wrap_DiffUtils.cpp index d02b00a0595..a0a22e9f009 100644 --- a/Src/CompareEngines/Wrap_DiffUtils.cpp +++ b/Src/CompareEngines/Wrap_DiffUtils.cpp @@ -271,7 +271,7 @@ bool DiffUtils::Diff2Files(struct change ** diffs, int depth, if (m_pOptions->m_diffAlgorithm != DIFF_ALGORITHM_DEFAULT) { const unsigned xdl_flags = make_xdl_flags(*m_pOptions); - *diffs = diff_2_files_xdiff(m_inf, bin_status, 0, xdl_flags); + *diffs = diff_2_files_xdiff(m_inf, bin_status, bMovedBlocks, bin_file, xdl_flags); files[0] = m_inf[0]; files[1] = m_inf[1]; } diff --git a/Src/DiffTextBuffer.cpp b/Src/DiffTextBuffer.cpp index 39562a82057..27310165741 100644 --- a/Src/DiffTextBuffer.cpp +++ b/Src/DiffTextBuffer.cpp @@ -414,7 +414,7 @@ int CDiffTextBuffer::SaveToFile (const String& pszFileName, if (bTempFile) { file.SetUnicoding(ucr::UTF8); - file.SetBom(GetOptionsMgr()->GetInt(OPT_CMP_DIFF_ALGORITHM) == 0); + file.SetBom(true); bOpenSuccess = !!file.OpenCreate(pszFileName); } else diff --git a/Src/DiffWrapper.cpp b/Src/DiffWrapper.cpp index fa741fc0fbd..aec9f19d3c5 100644 --- a/Src/DiffWrapper.cpp +++ b/Src/DiffWrapper.cpp @@ -892,7 +892,8 @@ bool CDiffWrapper::Diff2Files(struct change ** diffs, DiffFileData *diffData, if (m_options.m_diffAlgorithm != DIFF_ALGORITHM_DEFAULT) { const unsigned xdl_flags = make_xdl_flags(m_options); - *diffs = diff_2_files_xdiff(diffData->m_inf, bin_status, (m_pMovedLines[0] != nullptr), xdl_flags); + *diffs = diff_2_files_xdiff(diffData->m_inf, bin_status, + (m_pMovedLines[0] != nullptr), bin_file, xdl_flags); files[0] = diffData->m_inf[0]; files[1] = diffData->m_inf[1]; } diff --git a/Src/xdiff_gnudiff_compat.cpp b/Src/xdiff_gnudiff_compat.cpp index 20f198955b5..d352e590feb 100644 --- a/Src/xdiff_gnudiff_compat.cpp +++ b/Src/xdiff_gnudiff_compat.cpp @@ -70,7 +70,7 @@ static int hunk_func(long start_a, long count_a, long start_b, long count_b, voi return 0; } -struct change * diff_2_files_xdiff (struct file_data filevec[], int* bin_status, int bMoved_blocks_flag, unsigned xdl_flags) +struct change * diff_2_files_xdiff (struct file_data filevec[], int* bin_status, int bMoved_blocks_flag, int* bin_file, unsigned xdl_flags) { mmfile_t mmfile1 = { 0 }, mmfile2 = { 0 }; change *script = nullptr; @@ -79,46 +79,118 @@ struct change * diff_2_files_xdiff (struct file_data filevec[], int* bin_status, xpparam_t xpp = { 0 }; xdemitconf_t xecfg = { 0 }; xdemitcb_t ecb = { 0 }; - int bin_flag = 0; - read_files(filevec, no_details_flag & ~ignore_some_changes, &bin_flag); + if (read_files(filevec, no_details_flag & ~ignore_some_changes, bin_file)) + { + int i; + int changes; + // copy from analyze.c + // We can now safely assume to have a pair of Binary files. + + // Are both files Open and Regular (no Pipes, Directories, Devices (e.g. NUL)) + if (filevec[0].desc < 0 || filevec[1].desc < 0 || + !(S_ISREG (filevec[0].stat.st_mode)) || !(S_ISREG (filevec[1].stat.st_mode)) ) + changes = 1; + else + // Files with different lengths must be different. + if (filevec[0].stat.st_size != filevec[1].stat.st_size) + changes = 1; + else + // Identical descriptor implies identical files + if (filevec[0].desc == filevec[1].desc) + changes = 0; + // Scan both files, a buffer at a time, looking for a difference. + else + { + // Same-sized buffers for both files were allocated in read_files(). + size_t buffer_size = filevec[0].bufsize; + + for (;;) + { + // Read a buffer's worth from both files. + for (i = 0; i < 2; i++) + while (filevec[i].buffered_chars < buffer_size) + { + int r = _read (filevec[i].desc, + filevec[i].buffer + filevec[i].buffered_chars, + (int)(buffer_size - filevec[i].buffered_chars)); + if (r == 0) + break; + if (r < 0) + pfatal_with_name (filevec[i].name); + filevec[i].buffered_chars += r; + } + + // If the buffers have different number of chars, the files differ. + if (filevec[0].buffered_chars != filevec[1].buffered_chars) + { + changes = 1; + break; + } - mmfile1.ptr = const_cast(filevec[0].prefix_end); - mmfile1.size = static_cast(filevec[0].suffix_begin - filevec[0].prefix_end) - filevec[0].missing_newline; - mmfile2.ptr = const_cast(filevec[1].prefix_end); - mmfile2.size = static_cast(filevec[1].suffix_begin - filevec[1].prefix_end) - filevec[1].missing_newline; + // If we reach end-of-file, the files are the same. + if (filevec[0].buffered_chars==0) // therefore: filevec[1].buffered_chars==0 + { + changes = 0; + break; + } - xpp.flags = xdl_flags; - xecfg.hunk_func = hunk_func; - if (xdl_diff_modified(&mmfile1, &mmfile2, &xpp, &xecfg, &ecb, &xe, &xscr) == 0) + // If buffers have different contents, the files are different. + if (memcmp (filevec[0].buffer, + filevec[1].buffer, + filevec[0].buffered_chars) != 0) + { + changes = 1; + break; + } + + // Files appear identical so far... + // Prepare to loop again for the next pair of buffers. + filevec[0].buffered_chars = filevec[1].buffered_chars = 0; + } + } + if (bin_status != NULL) + *bin_status = (changes != 0 ? -1 : 1); + } + else { - change *prev = nullptr; - for (xdchange_t* xcur = xscr; xcur; xcur = xcur->next) + mmfile1.ptr = const_cast(filevec[0].prefix_end); + mmfile1.size = static_cast(filevec[0].suffix_begin - filevec[0].prefix_end) - filevec[0].missing_newline; + mmfile2.ptr = const_cast(filevec[1].prefix_end); + mmfile2.size = static_cast(filevec[1].suffix_begin - filevec[1].prefix_end) - filevec[1].missing_newline; + + xpp.flags = xdl_flags; + xecfg.hunk_func = hunk_func; + if (xdl_diff_modified(&mmfile1, &mmfile2, &xpp, &xecfg, &ecb, &xe, &xscr) == 0) { - change* e = static_cast(malloc(sizeof(change))); - if (!e) - goto abort; - if (!script) - script = e; - e->line0 = xcur->i1; - e->line1 = xcur->i2; - e->deleted = xcur->chg1; - e->inserted = xcur->chg2; - e->match0 = -1; - e->match1 = -1; - e->trivial = static_cast(xcur->ignore); - e->link = nullptr; - e->ignore = 0; - if (prev) - prev->link = e; - prev = e; - } + change *prev = nullptr; + for (xdchange_t* xcur = xscr; xcur; xcur = xcur->next) + { + change* e = static_cast(malloc(sizeof(change))); + if (!e) + goto abort; + if (!script) + script = e; + e->line0 = xcur->i1; + e->line1 = xcur->i2; + e->deleted = xcur->chg1; + e->inserted = xcur->chg2; + e->match0 = -1; + e->match1 = -1; + e->trivial = static_cast(xcur->ignore); + e->link = nullptr; + e->ignore = 0; + if (prev) + prev->link = e; + prev = e; + } - if (bMoved_blocks_flag) - moved_block_analysis(&script, filevec); + if (bMoved_blocks_flag) + moved_block_analysis(&script, filevec); - xdl_free_script(xscr); - xdl_free_env(&xe); + xdl_free_script(xscr); + xdl_free_env(&xe); + } } return script; diff --git a/Src/xdiff_gnudiff_compat.h b/Src/xdiff_gnudiff_compat.h index 394370a87f6..5dfa542c067 100644 --- a/Src/xdiff_gnudiff_compat.h +++ b/Src/xdiff_gnudiff_compat.h @@ -2,4 +2,4 @@ class DiffutilsOptions; unsigned long make_xdl_flags(const DiffutilsOptions& options); -struct change * diff_2_files_xdiff(struct file_data filevec[], int* bin_status, int bMoved_blocks_flag, unsigned xdl_flags); +struct change * diff_2_files_xdiff(struct file_data filevec[], int* bin_status, int bMoved_blocks_flag, int* bin_file, unsigned xdl_flags);