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