1 // Copyright (C) 1996 - 2002 Florian Schintke
2 // Modified 2002 by Opera, opera@home.se
3 //
4 // This is free software; you can redistribute it and/or modify it under
5 // the terms of the GNU General Public License as published by the Free
6 // Software Foundation; either version 2, or (at your option) any later
7 // version.
8 //
9 // Thanks to the E.S.O. - ACS project that has done this C++ interface
10 // to the wildcards pttern matching algorithm
11
12 #include "stdinc.h"
13
14 #include "Wildcards.h"
15 using namespace std;
16 using namespace dcpp;
wildcardfit(const char * wildcard,const char * test,bool useSet)17 int Wildcard::wildcardfit(const char *wildcard, const char *test, bool useSet)
18 {
19 int fit = 1;
20
21 for (; ('\000' != *wildcard) && (1 == fit) && ('\000' != *test); wildcard++)
22 {
23 switch (*wildcard)
24 {
25 case '?':
26 test++;
27 break;
28 case '*':
29 fit = asterisk(&wildcard, &test);
30 // the asterisk was skipped by asterisk() but the loop will
31 // increment by itself. So we have to decrement
32 wildcard--;
33 break;
34 case '[':
35 if (useSet)
36 {
37 wildcard++; // leave out the opening square bracket
38 fit = set(&wildcard, &test);
39 // we don't need to decrement the wildcard as in case
40 // of asterisk because the closing ] is still there
41 break;
42 } //if we're not using the set option, fall through
43 default:
44 fit = (int)(*wildcard == *test);
45 test++;
46 }
47 }
48 while ((*wildcard == '*') && (1 == fit))
49 // here the teststring is empty otherwise you cannot
50 // leave the previous loop
51 wildcard++;
52 return (int)((1 == fit) && ('\0' == *test) && ('\0' == *wildcard));
53 }
54
wildcardfit(const wchar_t * wildcard,const wchar_t * test,bool useSet)55 int Wildcard::wildcardfit(const wchar_t *wildcard, const wchar_t *test, bool useSet)
56 {
57 int fit = 1;
58
59 for (; (L'\000' != *wildcard) && (1 == fit) && (L'\000' != *test); wildcard++)
60 {
61 switch (*wildcard)
62 {
63 case L'?':
64 test++;
65 break;
66 case L'*':
67 fit = asterisk(&wildcard, &test);
68 // the asterisk was skipped by asterisk() but the loop will
69 // increment by itself. So we have to decrement
70 wildcard--;
71 break;
72 case L'[':
73 if (useSet)
74 {
75 wildcard++; // leave out the opening square bracket
76 fit = set(&wildcard, &test);
77 // we don't need to decrement the wildcard as in case
78 // of asterisk because the closing ] is still there
79 break;
80 }//if we're not using the set option, fall through
81 default:
82 fit = (int)(*wildcard == *test);
83 test++;
84 }
85 }
86 while ((*wildcard == L'*') && (1 == fit))
87 // here the teststring is empty otherwise you cannot
88 // leave the previous loop
89 wildcard++;
90 return (int)((1 == fit) && (L'\0' == *test) && (L'\0' == *wildcard));
91 }
92
set(const char ** wildcard,const char ** test)93 int Wildcard::set(const char **wildcard, const char **test)
94 {
95 int fit = 0;
96 int negation = 0;
97 int at_beginning = 1;
98
99 if ('!' == **wildcard)
100 {
101 negation = 1;
102 (*wildcard)++;
103 }
104 while ((']' != **wildcard) || (1 == at_beginning))
105 {
106 if (0 == fit)
107 {
108 if (('-' == **wildcard)
109 && ((*(*wildcard - 1)) < (*(*wildcard + 1)))
110 && (']' != *(*wildcard + 1))
111 && (0 == at_beginning))
112 {
113 if (((**test) >= (*(*wildcard - 1)))
114 && ((**test) <= (*(*wildcard + 1))))
115 {
116 fit = 1;
117 (*wildcard)++;
118 }
119 }
120 else if ((**wildcard) == (**test))
121 {
122 fit = 1;
123 }
124 }
125 (*wildcard)++;
126 at_beginning = 0;
127 }
128 if (1 == negation)
129 /* change from zero to one and vice versa */
130 fit = 1 - fit;
131 if (1 == fit)
132 (*test)++;
133
134 return (fit);
135 }
136
set(const wchar_t ** wildcard,const wchar_t ** test)137 int Wildcard::set(const wchar_t **wildcard, const wchar_t **test)
138 {
139 int fit = 0;
140 int negation = 0;
141 int at_beginning = 1;
142
143 if (L'!' == **wildcard)
144 {
145 negation = 1;
146 (*wildcard)++;
147 }
148 while ((L']' != **wildcard) || (1 == at_beginning))
149 {
150 if (0 == fit)
151 {
152 if ((L'-' == **wildcard)
153 && ((*(*wildcard - 1)) < (*(*wildcard + 1)))
154 && (L']' != *(*wildcard + 1))
155 && (0 == at_beginning))
156 {
157 if (((**test) >= (*(*wildcard - 1)))
158 && ((**test) <= (*(*wildcard + 1))))
159 {
160 fit = 1;
161 (*wildcard)++;
162 }
163 }
164 else if ((**wildcard) == (**test))
165 {
166 fit = 1;
167 }
168 }
169 (*wildcard)++;
170 at_beginning = 0;
171 }
172 if (1 == negation)
173 // change from zero to one and vice versa
174 fit = 1 - fit;
175 if (1 == fit)
176 (*test)++;
177
178 return (fit);
179 }
180
asterisk(const char ** wildcard,const char ** test)181 int Wildcard::asterisk(const char **wildcard, const char **test) {
182 /* Warning: uses multiple returns */
183 int fit = 1;
184
185 /* erase the leading asterisk */
186 (*wildcard)++;
187 while (('\000' != (**test))
188 && (('?' == **wildcard)
189 || ('*' == **wildcard))) {
190 if ('?' == **wildcard)
191 (*test)++;
192 (*wildcard)++;
193 }
194 /* Now it could be that test is empty and wildcard contains */
195 /* aterisks. Then we delete them to get a proper state */
196 while ('*' == (**wildcard))
197 (*wildcard)++;
198
199 if (('\0' == (**test)) && ('\0' != (**wildcard)))
200 return (fit = 0);
201 if (('\0' == (**test)) && ('\0' == (**wildcard)))
202 return (fit = 1);
203 else {
204 /* Neither test nor wildcard are empty! */
205 /* the first character of wildcard isn't in [*?] */
206 if (0 == wildcardfit(*wildcard, (*test))) {
207 do {
208 (*test)++;
209 /* skip as much characters as possible in the teststring */
210 /* stop if a character match occurs */
211 while (((**wildcard) != (**test))
212 && ('[' != (**wildcard))
213 && ('\0' != (**test)))
214 (*test)++;
215 }
216 while ((('\0' != **test)) ?
217 (0 == wildcardfit(*wildcard, (*test)))
218 : (0 != (fit = 0)));
219 }
220 if (('\0' == **test) && ('\0' == **wildcard))
221 fit = 1;
222 return (fit);
223 }
224 }
225
asterisk(const wchar_t ** wildcard,const wchar_t ** test)226 int Wildcard::asterisk(const wchar_t **wildcard, const wchar_t **test) {
227 // Warning: uses multiple returns
228 int fit = 1;
229
230 // erase the leading asterisk
231 (*wildcard)++;
232 while ((L'\000' != (**test))
233 && ((L'?' == **wildcard)
234 || (L'*' == **wildcard))) {
235 if (L'?' == **wildcard)
236 (*test)++;
237 (*wildcard)++;
238 }
239 // Now it could be that test is empty and wildcard contains
240 // aterisks. Then we delete them to get a proper state
241 while ('*' == (**wildcard))
242 (*wildcard)++;
243
244 if ((L'\0' == (**test)) && (L'\0' != (**wildcard)))
245 return (fit = 0);
246 if ((L'\0' == (**test)) && (L'\0' == (**wildcard)))
247 return (fit = 1);
248 else {
249 // Neither test nor wildcard are empty!
250 // the first character of wildcard isn't in [*?]
251 if (0 == wildcardfit(*wildcard, (*test))) {
252 do {
253 (*test)++;
254 // skip as much characters as possible in the teststring
255 // stop if a character match occurs
256 while (((**wildcard) != (**test))
257 && (L'[' != (**wildcard))
258 && (L'\0' != (**test)))
259 (*test)++;
260 }
261 while (((L'\0' != **test)) ?
262 (0 == wildcardfit(*wildcard, (*test)))
263 : (0 != (fit = 0)));
264 }
265 if ((L'\0' == **test) && (L'\0' == **wildcard))
266 fit = 1;
267 return (fit);
268 }
269 }
270
271
patternMatch(const string & text,const string & pattern,bool useSet)272 bool Wildcard::patternMatch(const string& text, const string& pattern, bool useSet) {
273 string sText = Text::toLower(text);
274 string sPattern = Text::toLower(pattern);
275 return (wildcardfit(sPattern.c_str(), sText.c_str(), useSet) == 1);
276 }
277
patternMatch(const wstring & text,const wstring & pattern,bool useSet)278 bool Wildcard::patternMatch(const wstring& text, const wstring& pattern, bool useSet) {
279 wstring sText = Text::toLower(text);
280 wstring sPattern = Text::toLower(pattern);
281 return (wildcardfit(sPattern.c_str(), sText.c_str(), useSet) == 1);
282 }
283
patternMatch(const string & text,const string & patternlist,char delimiter,bool useSet)284 bool Wildcard::patternMatch(const string& text, const string& patternlist, char delimiter, bool useSet) {
285 StringTokenizer<string> st(patternlist, delimiter);
286 bool bMatched = false;
287 for (StringIter i = st.getTokens().begin(); i != st.getTokens().end(); ++i) {
288 bMatched = patternMatch(text, *i, useSet);
289 if (bMatched)
290 return true;
291 }
292 return bMatched;
293 }
294
patternMatch(const wstring & text,const wstring & patternlist,wchar_t delimiter,bool useSet)295 bool Wildcard::patternMatch(const wstring& text, const wstring& patternlist, wchar_t delimiter, bool useSet) {
296 StringTokenizer<wstring> st(patternlist, delimiter);
297 bool bMatched = false;
298 for (WStringIter i = st.getTokens().begin(); i != st.getTokens().end(); ++i) {
299 bMatched = patternMatch(text, *i, useSet);
300 if (bMatched)
301 return true;
302 }
303 return bMatched;
304 }
305