1 // TortoiseMerge - a Diff/Patch program
3 // Copyright (C) 2006-2008 - 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.
22 #include "SVNLineDiff.h"
24 const svn_diff_fns_t
SVNLineDiff::SVNLineDiff_vtable
=
26 SVNLineDiff::datasource_open
,
27 SVNLineDiff::datasource_close
,
28 SVNLineDiff::next_token
,
29 SVNLineDiff::compare_token
,
30 SVNLineDiff::discard_token
,
31 SVNLineDiff::discard_all_token
34 #define SVNLINEDIFF_CHARTYPE_NONE 0
35 #define SVNLINEDIFF_CHARTYPE_ALPHANUMERIC 1
36 #define SVNLINEDIFF_CHARTYPE_SPACE 2
37 #define SVNLINEDIFF_CHARTYPE_OTHER 3
39 typedef void (*LineParser
)(LPCTSTR line
, unsigned long lineLength
, std::vector
<std::wstring
> &tokens
);
41 void SVNLineDiff::ParseLineWords(
42 LPCTSTR line
, unsigned long lineLength
, std::vector
<std::wstring
> &tokens
)
45 int prevCharType
= SVNLINEDIFF_CHARTYPE_NONE
;
46 for (unsigned long i
= 0; i
< lineLength
; ++i
)
49 IsCharAlphaNumeric(line
[i
]) ? SVNLINEDIFF_CHARTYPE_ALPHANUMERIC
:
50 IsCharWhiteSpace(line
[i
]) ? SVNLINEDIFF_CHARTYPE_SPACE
:
51 SVNLINEDIFF_CHARTYPE_OTHER
;
53 // Token is a sequence of either alphanumeric or whitespace characters.
54 // Treat all other characters as a separate tokens.
55 if (charType
== prevCharType
&& charType
!= SVNLINEDIFF_CHARTYPE_OTHER
)
60 tokens
.push_back(token
);
63 prevCharType
= charType
;
66 tokens
.push_back(token
);
69 void SVNLineDiff::ParseLineChars(
70 LPCTSTR line
, unsigned long lineLength
, std::vector
<std::wstring
> &tokens
)
73 for (unsigned long i
= 0; i
< lineLength
; ++i
)
76 tokens
.push_back(token
);
80 svn_error_t
* SVNLineDiff::datasource_open(void * baton
, svn_diff_datasource_e datasource
)
82 SVNLineDiff
* linediff
= (SVNLineDiff
*)baton
;
83 LineParser parser
= linediff
->m_bWordDiff
? ParseLineWords
: ParseLineChars
;
86 case svn_diff_datasource_original
:
87 parser(linediff
->m_line1
, linediff
->m_line1length
, linediff
->m_line1tokens
);
89 case svn_diff_datasource_modified
:
90 parser(linediff
->m_line2
, linediff
->m_line2length
, linediff
->m_line2tokens
);
96 svn_error_t
* SVNLineDiff::datasource_close(void * /*baton*/, svn_diff_datasource_e
/*datasource*/)
101 void SVNLineDiff::NextTokenWords(
102 apr_uint32_t
* hash
, void** token
, unsigned long& linePos
, const std::vector
<std::wstring
>& tokens
)
104 if (linePos
< tokens
.size())
106 *token
= (void*)tokens
[linePos
].c_str();
107 *hash
= SVNLineDiff::Adler32(0, tokens
[linePos
].c_str(), tokens
[linePos
].size());
112 void SVNLineDiff::NextTokenChars(
113 apr_uint32_t
* hash
, void** token
, unsigned long& linePos
, LPCTSTR line
, unsigned long lineLength
)
115 if (linePos
< lineLength
)
117 *token
= (void*)&line
[linePos
];
118 *hash
= line
[linePos
];
123 svn_error_t
* SVNLineDiff::next_token(
124 apr_uint32_t
* hash
, void ** token
, void * baton
, svn_diff_datasource_e datasource
)
126 SVNLineDiff
* linediff
= (SVNLineDiff
*)baton
;
130 case svn_diff_datasource_original
:
131 if (linediff
->m_bWordDiff
)
132 NextTokenWords(hash
, token
, linediff
->m_line1pos
, linediff
->m_line1tokens
);
134 NextTokenChars(hash
, token
, linediff
->m_line1pos
, linediff
->m_line1
, linediff
->m_line1length
);
136 case svn_diff_datasource_modified
:
137 if (linediff
->m_bWordDiff
)
138 NextTokenWords(hash
, token
, linediff
->m_line2pos
, linediff
->m_line2tokens
);
140 NextTokenChars(hash
, token
, linediff
->m_line2pos
, linediff
->m_line2
, linediff
->m_line2length
);
146 svn_error_t
* SVNLineDiff::compare_token(void * baton
, void * token1
, void * token2
, int * compare
)
148 SVNLineDiff
* linediff
= (SVNLineDiff
*)baton
;
149 if (linediff
->m_bWordDiff
)
151 LPCTSTR s1
= (LPCTSTR
)token1
;
152 LPCTSTR s2
= (LPCTSTR
)token2
;
155 *compare
= _tcscmp(s1
, s2
);
160 TCHAR
* c1
= (TCHAR
*)token1
;
161 TCHAR
* c2
= (TCHAR
*)token2
;
175 void SVNLineDiff::discard_token(void * /*baton*/, void * /*token*/)
179 void SVNLineDiff::discard_all_token(void * /*baton*/)
183 SVNLineDiff::SVNLineDiff()
194 m_pool
= svn_pool_create(NULL
);
197 SVNLineDiff::~SVNLineDiff()
199 svn_pool_destroy(m_pool
);
202 bool SVNLineDiff::Diff(svn_diff_t
**diff
, LPCTSTR line1
, int len1
, LPCTSTR line2
, int len2
, bool bWordDiff
)
205 svn_pool_clear(m_subpool
);
207 m_subpool
= svn_pool_create(m_pool
);
209 if (m_subpool
== NULL
)
212 m_bWordDiff
= bWordDiff
;
215 m_line1length
= len1
? len1
: _tcslen(m_line1
);
216 m_line2length
= len2
? len2
: _tcslen(m_line2
);
220 m_line1tokens
.clear();
221 m_line2tokens
.clear();
222 svn_error_t
* err
= svn_diff_diff(diff
, this, &SVNLineDiff_vtable
, m_subpool
);
225 svn_error_clear(err
);
226 svn_pool_clear(m_subpool
);
232 #define ADLER_MOD_BASE 65521
233 #define ADLER_MOD_BLOCK_SIZE 5552
235 apr_uint32_t
SVNLineDiff::Adler32(apr_uint32_t checksum
, const WCHAR
*data
, apr_size_t len
)
237 const unsigned char * input
= (const unsigned char *)data
;
238 apr_uint32_t s1
= checksum
& 0xFFFF;
239 apr_uint32_t s2
= checksum
>> 16;
242 apr_size_t blocks
= len
/ ADLER_MOD_BLOCK_SIZE
;
244 len
%= ADLER_MOD_BLOCK_SIZE
;
248 int count
= ADLER_MOD_BLOCK_SIZE
;
256 s1
%= ADLER_MOD_BASE
;
257 s2
%= ADLER_MOD_BASE
;
267 return ((s2
% ADLER_MOD_BASE
) << 16) | (s1
% ADLER_MOD_BASE
);
270 bool SVNLineDiff::IsCharWhiteSpace(TCHAR c
)
272 return (c
== ' ') || (c
== '\t');
275 bool SVNLineDiff::ShowInlineDiff(svn_diff_t
* diff
)
277 svn_diff_t
* tempdiff
= diff
;
280 apr_off_t origsize
= 0;
281 apr_off_t diffsize
= 0;
284 if (tempdiff
->type
== svn_diff__type_common
)
287 origsize
+= tempdiff
->original_length
;
292 diffsize
+= tempdiff
->original_length
;
293 diffsize
+= tempdiff
->modified_length
;
295 tempdiff
= tempdiff
->next
;
297 return (origcounts
>= diffcounts
) && (origsize
> diffsize
);