Fixed issue #1507: Submodule Diff Dialog should show dirty state only on working...
[TortoiseGit.git] / src / TortoiseMerge / DiffData.cpp
blobac33c28a722ef07f3a13165f3236c312f50ad642
1 // TortoiseMerge - a Diff/Patch program
3 // Copyright (C) 2006-2009 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "StdAfx.h"
20 #include "svn_version.h"
21 #include "svn_io.h"
22 #include "diff.h"
23 #include "TempFiles.h"
24 #include "registry.h"
25 #include "Resource.h"
26 #include "Diffdata.h"
27 #include "UnicodeUtils.h"
28 #include "GitAdminDir.h"
29 #include "svn_dso.h"
31 #pragma warning(push)
32 #pragma warning(disable: 4702) // unreachable code
33 int CDiffData::abort_on_pool_failure (int /*retcode*/)
35 abort ();
36 return -1;
38 #pragma warning(pop)
40 CDiffData::CDiffData(void)
41 : m_bBlame(false)
43 apr_initialize();
44 svn_dso_initialize2();
46 m_sPatchOriginal = _T(": original");
47 m_sPatchPatched = _T(": patched");
50 CDiffData::~CDiffData(void)
52 apr_terminate();
55 int CDiffData::GetLineCount()
57 int count = 0;
58 count = (int)m_arBaseFile.GetCount();
59 count = (int)(count > m_arTheirFile.GetCount() ? count : m_arTheirFile.GetCount());
60 count = (int)(count > m_arYourFile.GetCount() ? count : m_arYourFile.GetCount());
61 return count;
64 int CDiffData::GetLineActualLength(int index)
66 int count = 0;
67 if (index < m_arBaseFile.GetCount())
68 count = (count > m_arBaseFile.GetAt(index).GetLength() ? count : m_arBaseFile.GetAt(index).GetLength());
69 if (index < m_arTheirFile.GetCount())
70 count = (count > m_arTheirFile.GetAt(index).GetLength() ? count : m_arTheirFile.GetAt(index).GetLength());
71 if (index < m_arYourFile.GetCount())
72 count = (count > m_arYourFile.GetAt(index).GetLength() ? count : m_arYourFile.GetAt(index).GetLength());
73 return count;
76 LPCTSTR CDiffData::GetLineChars(int index)
78 if (index < m_arBaseFile.GetCount())
79 return m_arBaseFile.GetAt(index);
80 if (index < m_arTheirFile.GetCount())
81 return m_arTheirFile.GetAt(index);
82 if (index < m_arYourFile.GetCount())
83 return m_arYourFile.GetAt(index);
84 return NULL;
87 BOOL CDiffData::Load()
89 CString sConvertedBaseFilename, sConvertedTheirFilename, sConvertedYourFilename;
90 apr_pool_t * pool;
92 apr_pool_create_ex (&pool, NULL, abort_on_pool_failure, NULL);
94 m_arBaseFile.RemoveAll();
95 m_arYourFile.RemoveAll();
96 m_arTheirFile.RemoveAll();
98 m_YourBaseBoth.Clear();
99 m_YourBaseLeft.Clear();
100 m_YourBaseRight.Clear();
102 m_TheirBaseBoth.Clear();
103 m_TheirBaseLeft.Clear();
104 m_TheirBaseRight.Clear();
106 m_Diff3.Clear();
108 m_arDiff3LinesBase.RemoveAll();
109 m_arDiff3LinesYour.RemoveAll();
110 m_arDiff3LinesTheir.RemoveAll();
112 CTempFiles tempfiles;
113 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseMerge\\IgnoreWS"));
114 CRegDWORD regIgnoreEOL = CRegDWORD(_T("Software\\TortoiseMerge\\IgnoreEOL"), TRUE);
115 CRegDWORD regIgnoreCase = CRegDWORD(_T("Software\\TortoiseMerge\\CaseInsensitive"), FALSE);
116 DWORD dwIgnoreWS = regIgnoreWS;
117 bool bIgnoreEOL = ((DWORD)regIgnoreEOL)!=0;
118 BOOL bIgnoreCase = ((DWORD)regIgnoreCase)!=0;
120 // The Subversion diff API only can ignore whitespaces and eol styles.
121 // It also can only handle one-byte charsets.
122 // To ignore case changes or to handle UTF-16 files, we have to
123 // save the original file in UTF-8 and/or the letters changed to lowercase
124 // so the Subversion diff can handle those.
125 sConvertedBaseFilename = m_baseFile.GetFilename();
126 sConvertedYourFilename = m_yourFile.GetFilename();
127 sConvertedTheirFilename = m_theirFile.GetFilename();
128 if (IsBaseFileInUse())
130 if (!m_arBaseFile.Load(m_baseFile.GetFilename()))
132 m_sError = m_arBaseFile.GetErrorString();
133 return FALSE;
135 if ((bIgnoreCase)||(m_arBaseFile.GetUnicodeType() == CFileTextLines::UNICODE_LE)||(m_arBaseFile.GetUnicodeType() == CFileTextLines::UNICODE_BE))
137 CFileTextLines converted(m_arBaseFile);
138 sConvertedBaseFilename = tempfiles.GetTempFilePath();
139 converted.Save(sConvertedBaseFilename, m_arBaseFile.GetUnicodeType() == CFileTextLines::UNICODE_LE || m_arBaseFile.GetUnicodeType() == CFileTextLines::UNICODE_BE, dwIgnoreWS, bIgnoreCase, m_bBlame);
143 if (IsTheirFileInUse())
145 // m_arBaseFile.GetCount() is passed as a hint for the number of lines in this file
146 // It's a fair guess that the files will be roughly the same size
147 if (!m_arTheirFile.Load(m_theirFile.GetFilename(),m_arBaseFile.GetCount()))
149 m_sError = m_arTheirFile.GetErrorString();
150 return FALSE;
152 if ((bIgnoreCase)||(m_arTheirFile.GetUnicodeType() == CFileTextLines::UNICODE_LE)||(m_arTheirFile.GetUnicodeType() == CFileTextLines::UNICODE_BE))
154 CFileTextLines converted(m_arTheirFile);
155 sConvertedTheirFilename = tempfiles.GetTempFilePath();
156 converted.Save(sConvertedTheirFilename, m_arTheirFile.GetUnicodeType() == CFileTextLines::UNICODE_LE || m_arTheirFile.GetUnicodeType() == CFileTextLines::UNICODE_BE, dwIgnoreWS, bIgnoreCase, m_bBlame);
160 if (IsYourFileInUse())
162 // m_arBaseFile.GetCount() is passed as a hint for the number of lines in this file
163 // It's a fair guess that the files will be roughly the same size
164 if (!m_arYourFile.Load(m_yourFile.GetFilename(),m_arBaseFile.GetCount()))
166 m_sError = m_arYourFile.GetErrorString();
167 return FALSE;
169 if ((bIgnoreCase)||(m_arYourFile.GetUnicodeType() == CFileTextLines::UNICODE_LE)||(m_arYourFile.GetUnicodeType() == CFileTextLines::UNICODE_BE))
171 CFileTextLines converted(m_arYourFile);
172 sConvertedYourFilename = tempfiles.GetTempFilePath();
173 converted.Save(sConvertedYourFilename, m_arYourFile.GetUnicodeType() == CFileTextLines::UNICODE_LE || m_arYourFile.GetUnicodeType() == CFileTextLines::UNICODE_BE, dwIgnoreWS, bIgnoreCase, m_bBlame);
177 // Calculate the number of lines in the largest of the three files
178 int lengthHint = max(m_arBaseFile.GetCount(), m_arTheirFile.GetCount());
179 lengthHint = max(lengthHint, m_arYourFile.GetCount());
183 m_YourBaseBoth.Reserve(lengthHint);
184 m_YourBaseLeft.Reserve(lengthHint);
185 m_YourBaseRight.Reserve(lengthHint);
187 m_TheirBaseBoth.Reserve(lengthHint);
188 m_TheirBaseLeft.Reserve(lengthHint);
189 m_TheirBaseRight.Reserve(lengthHint);
191 m_arDiff3LinesBase.Reserve(lengthHint);
192 m_arDiff3LinesYour.Reserve(lengthHint);
193 m_arDiff3LinesTheir.Reserve(lengthHint);
195 catch (CMemoryException* e)
197 e->GetErrorMessage(m_sError.GetBuffer(255), 255);
198 m_sError.ReleaseBuffer();
199 return FALSE;
202 // Is this a two-way diff?
203 if (IsBaseFileInUse() && IsYourFileInUse() && !IsTheirFileInUse())
205 if (!DoTwoWayDiff(sConvertedBaseFilename, sConvertedYourFilename, dwIgnoreWS, bIgnoreEOL, pool))
207 apr_pool_destroy (pool); // free the allocated memory
208 return FALSE;
212 if (IsBaseFileInUse() && IsTheirFileInUse() && !IsYourFileInUse())
214 ASSERT(FALSE);
217 if (IsBaseFileInUse() && IsTheirFileInUse() && IsYourFileInUse())
219 m_Diff3.Reserve(lengthHint);
221 if (!DoThreeWayDiff(sConvertedBaseFilename, sConvertedYourFilename, sConvertedTheirFilename, dwIgnoreWS, bIgnoreEOL, !!bIgnoreCase, pool))
223 apr_pool_destroy (pool); // free the allocated memory
224 return FALSE;
228 apr_pool_destroy (pool); // free the allocated memory
229 return TRUE;
233 bool
234 CDiffData::DoTwoWayDiff(const CString& sBaseFilename, const CString& sYourFilename, DWORD dwIgnoreWS, bool bIgnoreEOL, apr_pool_t * pool)
236 // convert CString filenames (UTF-16 or ANSI) to UTF-8
237 CStringA sBaseFilenameUtf8 = CUnicodeUtils::GetUTF8(sBaseFilename);
238 CStringA sYourFilenameUtf8 = CUnicodeUtils::GetUTF8(sYourFilename);
240 svn_diff_t * diffYourBase = NULL;
241 svn_error_t * svnerr = NULL;
242 svn_diff_file_options_t * options = svn_diff_file_options_create(pool);
243 options->ignore_eol_style = bIgnoreEOL;
244 options->ignore_space = svn_diff_file_ignore_space_none;
245 switch (dwIgnoreWS)
247 case 0:
248 options->ignore_space = svn_diff_file_ignore_space_none;
249 break;
250 case 1:
251 options->ignore_space = svn_diff_file_ignore_space_all;
252 break;
253 case 2:
254 options->ignore_space = svn_diff_file_ignore_space_change;
255 break;
258 svnerr = svn_diff_file_diff_2(&diffYourBase, sBaseFilenameUtf8, sYourFilenameUtf8, options, pool);
259 if (svnerr)
261 TRACE(_T("diff-error in CDiffData::Load()\n"));
262 CStringA sMsg = CStringA(svnerr->message);
263 while (svnerr->child)
265 svnerr = svnerr->child;
266 sMsg += _T("\n");
267 sMsg += CStringA(svnerr->message);
269 CString readableMsg = CUnicodeUtils::GetUnicode(sMsg);
270 m_sError.Format(IDS_ERR_DIFF_DIFF, (LPCTSTR)readableMsg);
271 svn_error_clear(svnerr);
272 return false;
274 svn_diff_t * tempdiff = diffYourBase;
275 LONG baseline = 0;
276 LONG yourline = 0;
278 while (tempdiff)
280 for (int i=0; i<tempdiff->original_length; i++)
282 if (baseline >= m_arBaseFile.GetCount())
284 m_sError.LoadString(IDS_ERR_DIFF_NEWLINES);
285 return false;
287 const CString& sCurrentBaseLine = m_arBaseFile.GetAt(baseline);
288 EOL endingBase = m_arBaseFile.GetLineEnding(baseline);
289 if (tempdiff->type == svn_diff__type_common)
291 if (yourline >= m_arYourFile.GetCount())
293 m_sError.LoadString(IDS_ERR_DIFF_NEWLINES);
294 return false;
296 const CString& sCurrentYourLine = m_arYourFile.GetAt(yourline);
297 EOL endingYours = m_arYourFile.GetLineEnding(yourline);
298 if (sCurrentBaseLine != sCurrentYourLine)
300 if (dwIgnoreWS == 2 || dwIgnoreWS == 3)
302 CString s1 = m_arBaseFile.GetAt(baseline);
303 CString s2 = sCurrentYourLine;
305 if ( dwIgnoreWS == 2 )
307 s1.TrimLeft(_T(" \t"));
308 s2.TrimLeft(_T(" \t"));
310 else
312 s1.TrimRight(_T(" \t"));
313 s2.TrimRight(_T(" \t"));
316 if (s1 != s2)
318 // one-pane view: two lines, one 'removed' and one 'added'
319 m_YourBaseBoth.AddData(sCurrentBaseLine, DIFFSTATE_REMOVEDWHITESPACE, yourline, endingBase);
320 m_YourBaseBoth.AddData(sCurrentYourLine, DIFFSTATE_ADDEDWHITESPACE, yourline, endingYours);
322 else
324 m_YourBaseBoth.AddData(sCurrentBaseLine, DIFFSTATE_NORMAL, yourline, endingBase);
327 else if (dwIgnoreWS == 0)
329 m_YourBaseBoth.AddData(sCurrentBaseLine, DIFFSTATE_REMOVEDWHITESPACE, yourline, endingBase);
330 m_YourBaseBoth.AddData(sCurrentYourLine, DIFFSTATE_ADDEDWHITESPACE, yourline, endingYours);
332 else
334 m_YourBaseBoth.AddData(sCurrentBaseLine, DIFFSTATE_NORMAL, yourline, endingBase);
337 else
339 m_YourBaseBoth.AddData(sCurrentBaseLine, DIFFSTATE_NORMAL, yourline, endingBase);
341 yourline++; //in both files
343 else
345 m_YourBaseBoth.AddData(sCurrentBaseLine, DIFFSTATE_REMOVED, yourline, endingBase);
347 baseline++;
349 if (tempdiff->type == svn_diff__type_diff_modified)
351 for (int i=0; i<tempdiff->modified_length; i++)
353 if (m_arYourFile.GetCount() > yourline)
355 m_YourBaseBoth.AddData(m_arYourFile.GetAt(yourline), DIFFSTATE_ADDED, yourline, m_arYourFile.GetLineEnding(yourline));
357 yourline++;
360 tempdiff = tempdiff->next;
363 tempdiff = diffYourBase;
364 baseline = 0;
365 yourline = 0;
366 while (tempdiff)
368 if (tempdiff->type == svn_diff__type_common)
370 for (int i=0; i<tempdiff->original_length; i++)
372 const CString& sCurrentYourLine = m_arYourFile.GetAt(yourline);
373 EOL endingYours = m_arYourFile.GetLineEnding(yourline);
374 const CString& sCurrentBaseLine = m_arBaseFile.GetAt(baseline);
375 EOL endingBase = m_arBaseFile.GetLineEnding(baseline);
376 if (sCurrentBaseLine != sCurrentYourLine)
378 if (dwIgnoreWS == 2 || dwIgnoreWS == 3)
380 CString s1 = sCurrentBaseLine;
381 CString s2 = sCurrentYourLine;
382 if ( dwIgnoreWS == 2 )
384 s1 = s1.TrimLeft(_T(" \t"));
385 s2 = s2.TrimLeft(_T(" \t"));
387 else
389 s1 = s1.TrimRight(_T(" \t"));
390 s2 = s2.TrimRight(_T(" \t"));
393 if (s1 != s2)
395 m_YourBaseLeft.AddData(sCurrentBaseLine, DIFFSTATE_WHITESPACE, baseline, endingBase);
396 m_YourBaseRight.AddData(sCurrentYourLine, DIFFSTATE_WHITESPACE, yourline, endingYours);
398 else
400 m_YourBaseLeft.AddData(sCurrentBaseLine, DIFFSTATE_NORMAL, baseline, endingBase);
401 m_YourBaseRight.AddData(sCurrentYourLine, DIFFSTATE_NORMAL, yourline, endingYours);
404 else if (dwIgnoreWS == 0)
406 m_YourBaseLeft.AddData(sCurrentBaseLine, DIFFSTATE_WHITESPACE, baseline, endingBase);
407 m_YourBaseRight.AddData(sCurrentYourLine, DIFFSTATE_WHITESPACE, yourline, endingYours);
409 else
411 m_YourBaseLeft.AddData(sCurrentBaseLine, DIFFSTATE_NORMAL, baseline, endingBase);
412 m_YourBaseRight.AddData(sCurrentYourLine, DIFFSTATE_NORMAL, yourline, endingYours);
415 else
417 m_YourBaseLeft.AddData(sCurrentBaseLine, DIFFSTATE_NORMAL, baseline, endingBase);
418 m_YourBaseRight.AddData(sCurrentYourLine, DIFFSTATE_NORMAL, yourline, endingYours);
420 baseline++;
421 yourline++;
424 if (tempdiff->type == svn_diff__type_diff_modified)
426 apr_off_t original_length = tempdiff->original_length;
427 for (int i=0; i<tempdiff->modified_length; i++)
429 if (m_arYourFile.GetCount() > yourline)
431 EOL endingYours = m_arYourFile.GetLineEnding(yourline);
432 if (original_length-- <= 0)
434 m_YourBaseLeft.AddData(_T(""), DIFFSTATE_EMPTY, DIFF_EMPTYLINENUMBER, EOL_NOENDING);
435 m_YourBaseRight.AddData(m_arYourFile.GetAt(yourline), DIFFSTATE_ADDED, yourline, endingYours);
437 else
439 EOL endingBase = m_arBaseFile.GetLineEnding(baseline);
440 m_YourBaseLeft.AddData(m_arBaseFile.GetAt(baseline), DIFFSTATE_REMOVED, baseline, endingBase);
441 m_YourBaseRight.AddData(m_arYourFile.GetAt(yourline), DIFFSTATE_ADDED, yourline, endingYours);
442 baseline++;
444 yourline++;
447 apr_off_t modified_length = tempdiff->modified_length;
448 for (int i=0; i<tempdiff->original_length; i++)
450 if (modified_length-- <= 0)
452 if (m_arBaseFile.GetCount() > baseline)
454 EOL endingBase = m_arBaseFile.GetLineEnding(baseline);
455 m_YourBaseLeft.AddData(m_arBaseFile.GetAt(baseline), DIFFSTATE_REMOVED, baseline, endingBase);
456 m_YourBaseRight.AddData(_T(""), DIFFSTATE_EMPTY, DIFF_EMPTYLINENUMBER, EOL_NOENDING);
457 baseline++;
462 tempdiff = tempdiff->next;
464 TRACE(_T("done with 2-way diff\n"));
466 return true;
469 bool
470 CDiffData::DoThreeWayDiff(const CString& sBaseFilename, const CString& sYourFilename, const CString& sTheirFilename, DWORD dwIgnoreWS, bool bIgnoreEOL, bool bIgnoreCase, apr_pool_t * pool)
472 // convert CString filenames (UTF-16 or ANSI) to UTF-8
473 CStringA sBaseFilenameUtf8 = CUnicodeUtils::GetUTF8(sBaseFilename);
474 CStringA sYourFilenameUtf8 = CUnicodeUtils::GetUTF8(sYourFilename);
475 CStringA sTheirFilenameUtf8 = CUnicodeUtils::GetUTF8(sTheirFilename);
476 svn_diff_t * diffTheirYourBase = NULL;
477 svn_diff_file_options_t * options = svn_diff_file_options_create(pool);
478 options->ignore_eol_style = bIgnoreEOL;
479 options->ignore_space = svn_diff_file_ignore_space_none;
480 switch (dwIgnoreWS)
482 case 0:
483 options->ignore_space = svn_diff_file_ignore_space_none;
484 break;
485 case 1:
486 options->ignore_space = svn_diff_file_ignore_space_all;
487 break;
488 case 2:
489 options->ignore_space = svn_diff_file_ignore_space_change;
490 break;
492 svn_error_t * svnerr = svn_diff_file_diff3_2(&diffTheirYourBase, sBaseFilenameUtf8, sTheirFilenameUtf8, sYourFilenameUtf8, options, pool);
493 if (svnerr)
495 TRACE(_T("diff-error in CDiffData::Load()\n"));
496 CStringA sMsg = CStringA(svnerr->message);
497 while (svnerr->child)
499 svnerr = svnerr->child;
500 sMsg += _T("\n");
501 sMsg += CStringA(svnerr->message);
503 CString readableMsg = CUnicodeUtils::GetUnicode(sMsg);
504 m_sError.Format(IDS_ERR_DIFF_DIFF, (LPCTSTR)readableMsg);
505 svn_error_clear(svnerr);
506 return false;
509 svn_diff_t * tempdiff = diffTheirYourBase;
510 LONG baseline = 0;
511 LONG yourline = 0;
512 LONG theirline = 0;
513 LONG resline = 0;
514 while (tempdiff)
516 if (tempdiff->type == svn_diff__type_common)
518 ASSERT((tempdiff->latest_length == tempdiff->modified_length) && (tempdiff->modified_length == tempdiff->original_length));
519 for (int i=0; i<tempdiff->original_length; i++)
521 if ((m_arYourFile.GetCount() > yourline)&&(m_arTheirFile.GetCount() > theirline))
523 m_Diff3.AddData(m_arYourFile.GetAt(yourline), DIFFSTATE_NORMAL, resline, m_arYourFile.GetLineEnding(yourline));
525 m_arDiff3LinesBase.Add(baseline);
526 m_arDiff3LinesYour.Add(yourline);
527 m_arDiff3LinesTheir.Add(theirline);
529 m_YourBaseBoth.AddData(m_arYourFile.GetAt(yourline), DIFFSTATE_NORMAL, yourline, m_arYourFile.GetLineEnding(yourline));
530 m_TheirBaseBoth.AddData(m_arTheirFile.GetAt(theirline), DIFFSTATE_NORMAL, theirline, m_arTheirFile.GetLineEnding(theirline));
532 baseline++;
533 yourline++;
534 theirline++;
535 resline++;
539 else if (tempdiff->type == svn_diff__type_diff_common)
541 ASSERT(tempdiff->latest_length == tempdiff->modified_length);
542 //both theirs and yours have lines replaced
543 for (int i=0; i<tempdiff->original_length; i++)
545 if (m_arBaseFile.GetCount() > baseline)
547 m_Diff3.AddData(m_arBaseFile.GetAt(baseline), DIFFSTATE_IDENTICALREMOVED, DIFF_EMPTYLINENUMBER, m_arBaseFile.GetLineEnding(baseline));
549 m_arDiff3LinesBase.Add(baseline);
550 m_arDiff3LinesYour.Add(yourline);
551 m_arDiff3LinesTheir.Add(theirline);
553 m_YourBaseBoth.AddData(m_arBaseFile.GetAt(baseline), DIFFSTATE_IDENTICALREMOVED, DIFF_EMPTYLINENUMBER, EOL_NOENDING);
554 m_TheirBaseBoth.AddData(m_arBaseFile.GetAt(baseline), DIFFSTATE_IDENTICALREMOVED, DIFF_EMPTYLINENUMBER, EOL_NOENDING);
556 baseline++;
559 for (int i=0; i<tempdiff->modified_length; i++)
561 if ((m_arYourFile.GetCount() > yourline)&&(m_arTheirFile.GetCount() > theirline))
563 m_Diff3.AddData(m_arYourFile.GetAt(yourline), DIFFSTATE_IDENTICALADDED, resline, m_arYourFile.GetLineEnding(yourline));
565 m_arDiff3LinesBase.Add(baseline);
566 m_arDiff3LinesYour.Add(yourline);
567 m_arDiff3LinesTheir.Add(theirline);
569 m_YourBaseBoth.AddData(m_arYourFile.GetAt(yourline), DIFFSTATE_IDENTICALADDED, yourline, m_arYourFile.GetLineEnding(yourline));
570 m_TheirBaseBoth.AddData(m_arTheirFile.GetAt(theirline), DIFFSTATE_IDENTICALADDED, resline, m_arTheirFile.GetLineEnding(theirline));
572 yourline++;
573 theirline++;
574 resline++;
578 else if (tempdiff->type == svn_diff__type_conflict)
580 apr_off_t length = max(tempdiff->original_length, tempdiff->modified_length);
581 length = max(tempdiff->latest_length, length);
582 apr_off_t original = tempdiff->original_length;
583 apr_off_t modified = tempdiff->modified_length;
584 apr_off_t latest = tempdiff->latest_length;
586 apr_off_t originalresolved = 0;
587 apr_off_t modifiedresolved = 0;
588 apr_off_t latestresolved = 0;
590 LONG base = baseline;
591 LONG your = yourline;
592 LONG their = theirline;
593 if (tempdiff->resolved_diff)
595 originalresolved = tempdiff->resolved_diff->original_length;
596 modifiedresolved = tempdiff->resolved_diff->modified_length;
597 latestresolved = tempdiff->resolved_diff->latest_length;
599 for (int i=0; i<length; i++)
601 if (original)
603 if (m_arBaseFile.GetCount() > baseline)
605 m_Diff3.AddData(m_arBaseFile.GetAt(baseline), DIFFSTATE_IDENTICALREMOVED, DIFF_EMPTYLINENUMBER, m_arBaseFile.GetLineEnding(baseline));
607 m_arDiff3LinesBase.Add(baseline);
608 m_arDiff3LinesYour.Add(yourline);
609 m_arDiff3LinesTheir.Add(theirline);
612 else if ((originalresolved)||((modifiedresolved)&&(latestresolved)))
614 m_Diff3.AddData(_T(""), DIFFSTATE_IDENTICALREMOVED, DIFF_EMPTYLINENUMBER, EOL_NOENDING);
616 m_arDiff3LinesBase.Add(baseline);
617 m_arDiff3LinesYour.Add(yourline);
618 m_arDiff3LinesTheir.Add(theirline);
621 if ((latest)&&(original))
623 if (m_arBaseFile.GetCount() > baseline)
625 m_YourBaseBoth.AddData(m_arBaseFile.GetAt(baseline), DIFFSTATE_IDENTICALREMOVED, DIFF_EMPTYLINENUMBER, m_arBaseFile.GetLineEnding(baseline));
628 else
630 if (original)
632 if (m_arBaseFile.GetCount() > baseline)
634 m_YourBaseBoth.AddData(m_arBaseFile.GetAt(baseline), DIFFSTATE_IDENTICALREMOVED, DIFF_EMPTYLINENUMBER, m_arBaseFile.GetLineEnding(baseline));
637 else if ((latestresolved)&&(modifiedresolved))
639 m_YourBaseBoth.AddData(_T(""), DIFFSTATE_IDENTICALREMOVED, DIFF_EMPTYLINENUMBER, EOL_NOENDING);
642 if ((modified)&&(original))
644 if (m_arBaseFile.GetCount() > baseline)
646 m_TheirBaseBoth.AddData(m_arBaseFile.GetAt(baseline), DIFFSTATE_IDENTICALREMOVED, DIFF_EMPTYLINENUMBER, m_arBaseFile.GetLineEnding(baseline));
649 else
651 if (original)
653 if (m_arBaseFile.GetCount() > baseline)
655 m_TheirBaseBoth.AddData(m_arBaseFile.GetAt(baseline), DIFFSTATE_IDENTICALREMOVED, DIFF_EMPTYLINENUMBER, m_arBaseFile.GetLineEnding(baseline));
658 else if ((modifiedresolved)&&(latestresolved))
660 m_TheirBaseBoth.AddData(_T(""), DIFFSTATE_IDENTICALREMOVED, DIFF_EMPTYLINENUMBER, EOL_NOENDING);
663 if (original)
665 original--;
666 baseline++;
668 if (originalresolved)
669 originalresolved--;
671 if (modified)
673 modified--;
674 theirline++;
676 if (modifiedresolved)
677 modifiedresolved--;
678 if (latest)
680 latest--;
681 yourline++;
683 if (latestresolved)
684 latestresolved--;
686 original = tempdiff->original_length;
687 modified = tempdiff->modified_length;
688 latest = tempdiff->latest_length;
689 baseline = base;
690 yourline = your;
691 theirline = their;
692 if (tempdiff->resolved_diff)
694 originalresolved = tempdiff->resolved_diff->original_length;
695 modifiedresolved = tempdiff->resolved_diff->modified_length;
696 latestresolved = tempdiff->resolved_diff->latest_length;
698 for (int i=0; i<length; i++)
700 if ((latest)||(modified))
702 m_Diff3.AddData(_T(""), DIFFSTATE_CONFLICTED, resline, EOL_NOENDING);
704 m_arDiff3LinesBase.Add(baseline);
705 m_arDiff3LinesYour.Add(yourline);
706 m_arDiff3LinesTheir.Add(theirline);
708 resline++;
711 if (latest)
713 if (m_arYourFile.GetCount() > yourline)
715 m_YourBaseBoth.AddData(m_arYourFile.GetAt(yourline), DIFFSTATE_CONFLICTADDED, yourline, m_arYourFile.GetLineEnding(yourline));
718 else if ((latestresolved)||(modified)||(modifiedresolved))
720 m_YourBaseBoth.AddData(_T(""), DIFFSTATE_CONFLICTEMPTY, DIFF_EMPTYLINENUMBER, EOL_NOENDING);
722 if (modified)
724 if (m_arTheirFile.GetCount() > theirline)
726 m_TheirBaseBoth.AddData(m_arTheirFile.GetAt(theirline), DIFFSTATE_CONFLICTADDED, theirline, m_arTheirFile.GetLineEnding(theirline));
729 else if ((modifiedresolved)||(latest)||(latestresolved))
731 m_TheirBaseBoth.AddData(_T(""), DIFFSTATE_CONFLICTEMPTY, DIFF_EMPTYLINENUMBER, EOL_NOENDING);
733 if (original)
735 original--;
736 baseline++;
738 if (originalresolved)
739 originalresolved--;
740 if (modified)
742 modified--;
743 theirline++;
745 if (modifiedresolved)
746 modifiedresolved--;
747 if (latest)
749 latest--;
750 yourline++;
752 if (latestresolved)
753 latestresolved--;
756 else if (tempdiff->type == svn_diff__type_diff_modified)
758 //deleted!
759 for (int i=0; i<tempdiff->original_length; i++)
761 if ((m_arBaseFile.GetCount() > baseline)&&(m_arYourFile.GetCount() > yourline))
763 m_Diff3.AddData(m_arBaseFile.GetAt(baseline), DIFFSTATE_THEIRSREMOVED, DIFF_EMPTYLINENUMBER, m_arBaseFile.GetLineEnding(baseline));
765 m_arDiff3LinesBase.Add(baseline);
766 m_arDiff3LinesYour.Add(yourline);
767 m_arDiff3LinesTheir.Add(theirline);
769 m_YourBaseBoth.AddData(m_arYourFile.GetAt(yourline), DIFFSTATE_NORMAL, yourline, m_arYourFile.GetLineEnding(yourline));
770 m_TheirBaseBoth.AddData(m_arBaseFile.GetAt(baseline), DIFFSTATE_THEIRSREMOVED, DIFF_EMPTYLINENUMBER, EOL_NOENDING);
771 baseline++;
772 yourline++;
775 //added
776 for (int i=0; i<tempdiff->modified_length; i++)
778 if (m_arTheirFile.GetCount() > theirline)
780 m_Diff3.AddData(m_arTheirFile.GetAt(theirline), DIFFSTATE_THEIRSADDED, resline, m_arTheirFile.GetLineEnding(theirline));
782 m_arDiff3LinesBase.Add(baseline);
783 m_arDiff3LinesYour.Add(yourline);
784 m_arDiff3LinesTheir.Add(theirline);
786 m_YourBaseBoth.AddData(_T(""), DIFFSTATE_EMPTY, DIFF_EMPTYLINENUMBER, EOL_NOENDING);
787 m_TheirBaseBoth.AddData(m_arTheirFile.GetAt(theirline), DIFFSTATE_THEIRSADDED, theirline, m_arTheirFile.GetLineEnding(theirline));
789 theirline++;
790 resline++;
794 else if (tempdiff->type == svn_diff__type_diff_latest)
796 //YOURS differs from base
798 for (int i=0; i<tempdiff->original_length; i++)
800 if ((m_arBaseFile.GetCount() > baseline)&&(m_arTheirFile.GetCount() > theirline))
802 m_Diff3.AddData(m_arBaseFile.GetAt(baseline), DIFFSTATE_YOURSREMOVED, DIFF_EMPTYLINENUMBER, m_arBaseFile.GetLineEnding(baseline));
804 m_arDiff3LinesBase.Add(baseline);
805 m_arDiff3LinesYour.Add(yourline);
806 m_arDiff3LinesTheir.Add(theirline);
808 m_YourBaseBoth.AddData(m_arBaseFile.GetAt(baseline), DIFFSTATE_YOURSREMOVED, DIFF_EMPTYLINENUMBER, m_arBaseFile.GetLineEnding(baseline));
809 m_TheirBaseBoth.AddData(m_arTheirFile.GetAt(theirline), DIFFSTATE_NORMAL, theirline, m_arTheirFile.GetLineEnding(theirline));
811 baseline++;
812 theirline++;
815 for (int i=0; i<tempdiff->latest_length; i++)
817 if (m_arYourFile.GetCount() > yourline)
819 m_Diff3.AddData(m_arYourFile.GetAt(yourline), DIFFSTATE_YOURSADDED, resline, m_arYourFile.GetLineEnding(yourline));
821 m_arDiff3LinesBase.Add(baseline);
822 m_arDiff3LinesYour.Add(yourline);
823 m_arDiff3LinesTheir.Add(theirline);
825 m_YourBaseBoth.AddData(m_arYourFile.GetAt(yourline), DIFFSTATE_IDENTICALADDED, yourline, m_arYourFile.GetLineEnding(yourline));
826 m_TheirBaseBoth.AddData(_T(""), DIFFSTATE_EMPTY, DIFF_EMPTYLINENUMBER, EOL_NOENDING);
828 yourline++;
829 resline++;
833 else
835 TRACE(_T("something bad happened during diff!\n"));
837 tempdiff = tempdiff->next;
839 } // while (tempdiff)
841 if ((options->ignore_space != svn_diff_file_ignore_space_none)||(bIgnoreCase)||(bIgnoreEOL))
843 // If whitespaces are ignored, a conflict could have been missed
844 // We now go through all lines again and check if they're identical.
845 // If they're not, then that means it is a conflict, and we
846 // mark the conflict with the proper colors.
847 for (long i=0; i<m_Diff3.GetCount(); ++i)
849 DiffStates state1 = m_YourBaseBoth.GetState(i);
850 DiffStates state2 = m_TheirBaseBoth.GetState(i);
852 if (((state1 == DIFFSTATE_IDENTICALADDED)||(state1 == DIFFSTATE_NORMAL))&&
853 ((state2 == DIFFSTATE_IDENTICALADDED)||(state2 == DIFFSTATE_NORMAL)))
855 LONG lineyour = m_arDiff3LinesYour.GetAt(i);
856 LONG linetheir = m_arDiff3LinesTheir.GetAt(i);
857 LONG linebase = m_arDiff3LinesBase.GetAt(i);
858 if ((lineyour < m_arYourFile.GetCount()) &&
859 (linetheir < m_arTheirFile.GetCount()) &&
860 (linebase < m_arBaseFile.GetCount()))
862 if (((m_arYourFile.GetLineEnding(lineyour)!=m_arBaseFile.GetLineEnding(linebase))&&
863 (m_arTheirFile.GetLineEnding(linetheir)!=m_arBaseFile.GetLineEnding(linebase))&&
864 (m_arYourFile.GetLineEnding(lineyour)!=m_arTheirFile.GetLineEnding(linetheir))) ||
865 ((m_arYourFile.GetAt(lineyour).Compare(m_arBaseFile.GetAt(linebase))!=0)&&
866 (m_arTheirFile.GetAt(linetheir).Compare(m_arBaseFile.GetAt(linebase))!=0)&&
867 (m_arYourFile.GetAt(lineyour).Compare(m_arTheirFile.GetAt(linetheir))!=0)))
869 m_Diff3.SetState(i, DIFFSTATE_CONFLICTED_IGNORED);
870 m_YourBaseBoth.SetState(i, DIFFSTATE_CONFLICTADDED);
871 m_TheirBaseBoth.SetState(i, DIFFSTATE_CONFLICTADDED);
877 ASSERT(m_Diff3.GetCount() == m_YourBaseBoth.GetCount());
878 ASSERT(m_TheirBaseBoth.GetCount() == m_YourBaseBoth.GetCount());
880 TRACE(_T("done with 3-way diff\n"));
881 return true;