1 // TortoiseMerge - a Diff/Patch program
\r
3 // Copyright (C) 2006-2008 - TortoiseSVN
\r
5 // This program is free software; you can redistribute it and/or
\r
6 // modify it under the terms of the GNU General Public License
\r
7 // as published by the Free Software Foundation; either version 2
\r
8 // of the License, or (at your option) any later version.
\r
10 // This program is distributed in the hope that it will be useful,
\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 // GNU General Public License for more details.
\r
15 // You should have received a copy of the GNU General Public License
\r
16 // along with this program; if not, write to the Free Software Foundation,
\r
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\r
20 #include "SVNLineDiff.h"
\r
22 const svn_diff_fns_t SVNLineDiff::SVNLineDiff_vtable =
\r
24 SVNLineDiff::datasource_open,
\r
25 SVNLineDiff::datasource_close,
\r
26 SVNLineDiff::next_token,
\r
27 SVNLineDiff::compare_token,
\r
28 SVNLineDiff::discard_token,
\r
29 SVNLineDiff::discard_all_token
\r
32 #define SVNLINEDIFF_CHARTYPE_NONE 0
\r
33 #define SVNLINEDIFF_CHARTYPE_ALPHANUMERIC 1
\r
34 #define SVNLINEDIFF_CHARTYPE_SPACE 2
\r
35 #define SVNLINEDIFF_CHARTYPE_OTHER 3
\r
37 typedef void (*LineParser)(LPCTSTR line, unsigned long lineLength, std::vector<std::wstring> &tokens);
\r
39 void SVNLineDiff::ParseLineWords(
\r
40 LPCTSTR line, unsigned long lineLength, std::vector<std::wstring> &tokens)
\r
43 int prevCharType = SVNLINEDIFF_CHARTYPE_NONE;
\r
44 for (unsigned long i = 0; i < lineLength; ++i)
\r
47 IsCharAlphaNumeric(line[i]) ? SVNLINEDIFF_CHARTYPE_ALPHANUMERIC :
\r
48 IsCharWhiteSpace(line[i]) ? SVNLINEDIFF_CHARTYPE_SPACE :
\r
49 SVNLINEDIFF_CHARTYPE_OTHER;
\r
51 // Token is a sequence of either alphanumeric or whitespace characters.
\r
52 // Treat all other characters as a separate tokens.
\r
53 if (charType == prevCharType && charType != SVNLINEDIFF_CHARTYPE_OTHER)
\r
58 tokens.push_back(token);
\r
61 prevCharType = charType;
\r
64 tokens.push_back(token);
\r
67 void SVNLineDiff::ParseLineChars(
\r
68 LPCTSTR line, unsigned long lineLength, std::vector<std::wstring> &tokens)
\r
71 for (unsigned long i = 0; i < lineLength; ++i)
\r
74 tokens.push_back(token);
\r
78 svn_error_t * SVNLineDiff::datasource_open(void * baton, svn_diff_datasource_e datasource)
\r
80 SVNLineDiff * linediff = (SVNLineDiff *)baton;
\r
81 LineParser parser = linediff->m_bWordDiff ? ParseLineWords : ParseLineChars;
\r
84 case svn_diff_datasource_original:
\r
85 parser(linediff->m_line1, linediff->m_line1length, linediff->m_line1tokens);
\r
87 case svn_diff_datasource_modified:
\r
88 parser(linediff->m_line2, linediff->m_line2length, linediff->m_line2tokens);
\r
91 return SVN_NO_ERROR;
\r
94 svn_error_t * SVNLineDiff::datasource_close(void * /*baton*/, svn_diff_datasource_e /*datasource*/)
\r
96 return SVN_NO_ERROR;
\r
99 void SVNLineDiff::NextTokenWords(
\r
100 apr_uint32_t* hash, void** token, unsigned long& linePos, const std::vector<std::wstring>& tokens)
\r
102 if (linePos < tokens.size())
\r
104 *token = (void*)tokens[linePos].c_str();
\r
105 *hash = SVNLineDiff::Adler32(0, tokens[linePos].c_str(), tokens[linePos].size());
\r
110 void SVNLineDiff::NextTokenChars(
\r
111 apr_uint32_t* hash, void** token, unsigned long& linePos, LPCTSTR line, unsigned long lineLength)
\r
113 if (linePos < lineLength)
\r
115 *token = (void*)&line[linePos];
\r
116 *hash = line[linePos];
\r
121 svn_error_t * SVNLineDiff::next_token(
\r
122 apr_uint32_t * hash, void ** token, void * baton, svn_diff_datasource_e datasource)
\r
124 SVNLineDiff * linediff = (SVNLineDiff *)baton;
\r
126 switch (datasource)
\r
128 case svn_diff_datasource_original:
\r
129 if (linediff->m_bWordDiff)
\r
130 NextTokenWords(hash, token, linediff->m_line1pos, linediff->m_line1tokens);
\r
132 NextTokenChars(hash, token, linediff->m_line1pos, linediff->m_line1, linediff->m_line1length);
\r
134 case svn_diff_datasource_modified:
\r
135 if (linediff->m_bWordDiff)
\r
136 NextTokenWords(hash, token, linediff->m_line2pos, linediff->m_line2tokens);
\r
138 NextTokenChars(hash, token, linediff->m_line2pos, linediff->m_line2, linediff->m_line2length);
\r
141 return SVN_NO_ERROR;
\r
144 svn_error_t * SVNLineDiff::compare_token(void * baton, void * token1, void * token2, int * compare)
\r
146 SVNLineDiff * linediff = (SVNLineDiff *)baton;
\r
147 if (linediff->m_bWordDiff)
\r
149 LPCTSTR s1 = (LPCTSTR)token1;
\r
150 LPCTSTR s2 = (LPCTSTR)token2;
\r
153 *compare = _tcscmp(s1, s2);
\r
158 TCHAR * c1 = (TCHAR *)token1;
\r
159 TCHAR * c2 = (TCHAR *)token2;
\r
164 else if (*c1 < *c2)
\r
170 return SVN_NO_ERROR;
\r
173 void SVNLineDiff::discard_token(void * /*baton*/, void * /*token*/)
\r
177 void SVNLineDiff::discard_all_token(void * /*baton*/)
\r
181 SVNLineDiff::SVNLineDiff()
\r
190 , m_bWordDiff(false)
\r
192 m_pool = svn_pool_create(NULL);
\r
195 SVNLineDiff::~SVNLineDiff()
\r
197 svn_pool_destroy(m_pool);
\r
200 bool SVNLineDiff::Diff(svn_diff_t **diff, LPCTSTR line1, int len1, LPCTSTR line2, int len2, bool bWordDiff)
\r
203 svn_pool_clear(m_subpool);
\r
205 m_subpool = svn_pool_create(m_pool);
\r
207 if (m_subpool == NULL)
\r
210 m_bWordDiff = bWordDiff;
\r
213 m_line1length = len1 ? len1 : _tcslen(m_line1);
\r
214 m_line2length = len2 ? len2 : _tcslen(m_line2);
\r
218 m_line1tokens.clear();
\r
219 m_line2tokens.clear();
\r
220 svn_error_t * err = svn_diff_diff(diff, this, &SVNLineDiff_vtable, m_subpool);
\r
223 svn_error_clear(err);
\r
224 svn_pool_clear(m_subpool);
\r
230 #define ADLER_MOD_BASE 65521
\r
231 #define ADLER_MOD_BLOCK_SIZE 5552
\r
233 apr_uint32_t SVNLineDiff::Adler32(apr_uint32_t checksum, const WCHAR *data, apr_size_t len)
\r
235 const unsigned char * input = (const unsigned char *)data;
\r
236 apr_uint32_t s1 = checksum & 0xFFFF;
\r
237 apr_uint32_t s2 = checksum >> 16;
\r
240 apr_size_t blocks = len / ADLER_MOD_BLOCK_SIZE;
\r
242 len %= ADLER_MOD_BLOCK_SIZE;
\r
246 int count = ADLER_MOD_BLOCK_SIZE;
\r
254 s1 %= ADLER_MOD_BASE;
\r
255 s2 %= ADLER_MOD_BASE;
\r
265 return ((s2 % ADLER_MOD_BASE) << 16) | (s1 % ADLER_MOD_BASE);
\r
268 bool SVNLineDiff::IsCharWhiteSpace(TCHAR c)
\r
270 return (c == ' ') || (c == '\t');
\r
273 bool SVNLineDiff::ShowInlineDiff(svn_diff_t* diff)
\r
275 svn_diff_t* tempdiff = diff;
\r
276 int diffcounts = 0;
\r
277 int origcounts = 0;
\r
278 apr_off_t origsize = 0;
\r
279 apr_off_t diffsize = 0;
\r
282 if (tempdiff->type == svn_diff__type_common)
\r
285 origsize += tempdiff->original_length;
\r
290 diffsize += tempdiff->original_length;
\r
291 diffsize += tempdiff->modified_length;
\r
293 tempdiff = tempdiff->next;
\r
295 return (origcounts >= diffcounts) && (origsize > diffsize);
\r