1 krisbash 1.1 #include "like.h"
2 #include <ctype.h>
|
3 krisbash 1.2 #include <pal/intsafe.h>
|
4 krisbash 1.1
5 #if defined(CONFIG_POSIX)
6 # include <wctype.h>
7 #endif
8
9 #include <pal/strings.h>
10
11 #define WILDCARD MI_T('%')
12 #define ANYSINGLECHAR MI_T('_')
13
14 #ifdef _PREFAST_
15 #pragma prefast (push)
16 #pragma prefast (disable: 26018)
17 #pragma prefast (disable: 26001)
18 #endif
19
20 enum
21 {
22 NO_MATCH = 0,
23 MATCHED_WITH_WILDCARD_CHAR = 1,
24 MATCHED_WITH_ONE_CHAR = 2,
25 krisbash 1.1 };
26
27 MI_INLINE ZChar _Toupper(ZChar c)
28 {
29 #if (MI_CHAR_TYPE == 1)
30 return toupper(c);
31 #else
32 return towupper(c);
33 #endif
34 }
35
36 MI_INLINE void _FinalizeMatchState(
37 unsigned char** matchState)
38 {
39 if (*matchState != NULL)
40 {
41 PAL_Free(*matchState);
42 *matchState = NULL;
43 }
44 }
45
46 krisbash 1.1 static int _EnsureMatchState(
47 size_t stringLength,
48 unsigned char** matchState)
49 {
|
50 krisbash 1.2 size_t buffersize = 0;
|
51 krisbash 1.1
52 _FinalizeMatchState(matchState);
53
|
54 krisbash 1.2 if (SizeTMult(stringLength + (size_t) 1, 2, &buffersize) != S_OK)
55 return MI_FALSE;
56
57 if (SizeTMult(buffersize, sizeof(unsigned char), &buffersize) != S_OK)
58 return MI_FALSE;
59
|
60 krisbash 1.1 /* allocate buffer, which is 2 times (the string length + 1) */
|
61 krisbash 1.2 *matchState = PAL_Malloc(buffersize);
|
62 krisbash 1.1
63 if ( *matchState == NULL )
64 return MI_FALSE;
65
66 /* cleanup the memory */
67 memset(*matchState, 0, sizeof(unsigned char) * buffersize);
68
69 /* start from [0,0], which is always matched */
70 (*matchState)[0] = MATCHED_WITH_ONE_CHAR;
71
72 return MI_TRUE;
73 }
74
75 static void _SwitchRow(
|
76 krisbash 1.2 size_t rowSize,
77 unsigned char** currentRow,
|
78 krisbash 1.1 unsigned char** previousRow)
79 {
80 unsigned char* tempRow = *currentRow;
81
82 *currentRow = *previousRow;
83 *previousRow = tempRow;
84 /* cleanup the current row */
85 memset(*currentRow, 0, rowSize);
86 }
87
88 static int _MatchSet (
|
89 krisbash 1.2 const ZChar* pattern,
90 const ZChar* string,
|
91 krisbash 1.1 int *skip)
92 {
93 int bFnd;
94 const ZChar* pos;
95 int notinset;
96 int matched;
97 ZChar lastchar;
98
99 /*this tells whether ']' is found or not */
100 bFnd = MI_FALSE;
101
102 /* Skip the opening '['. */
103 pos = pattern+1;
104
105 /* See if we are matching a [^] set. */
106 notinset = (*pos == '^');
|
107 krisbash 1.2 if (notinset)
|
108 krisbash 1.1 pos++;
109
110 /* See if the target character matches any character in the set. */
111 matched = MI_FALSE;
112 lastchar = '\0';
113
114 while (*pos && *pos != ']' && !matched)
115 {
116 /* A range of characters is indicated by a '-' unless it's the first */
117 /* character in the set (in which case it's just a character to be */
118 /* matched. */
119 if (*pos == '-' && lastchar != '\0')
120 {
121 pos++;
122 if (*pos && *pos != ']')
123 {
|
124 krisbash 1.2 matched = (_Toupper(*string) >= lastchar &&
|
125 krisbash 1.1 _Toupper(*string) <= _Toupper(*pos));
126 lastchar = _Toupper(*pos);
127 pos++;
128 }
129 }
130 else
131 {
132 /* Match a normal character in the set. */
133 lastchar = _Toupper(*pos);
134 matched = (_Toupper(*pos) == _Toupper(*string));
|
135 krisbash 1.2 if (!matched)
|
136 krisbash 1.1 pos++;
137 }
138 }
139
140 /* Find the trailing ']'. If the set did not contain a closing ']' */
141 /* we return a failed match. */
142 while (*pos && *pos != ']') pos++;
143 if (*pos == ']')
144 {
145 pos++;
146 bFnd = MI_TRUE;
147 }
148 /*If ']' is not found and we reach end of string match is false */
149 /*since this is invalid pattern */
|
150 krisbash 1.2 if (!*pos && !bFnd)
|
151 krisbash 1.1 matched = MI_FALSE;
152
153 /* Done. */
154 *skip = (int)(pos-pattern);
155 return matched == !notinset;
156 }
157
158 MI_Boolean WQL_MatchLike(
159 _In_z_ const ZChar* pattern,
160 _In_z_ const ZChar* string,
161 ZChar escape)
162 {
163 size_t stringLength;
164 size_t rowLength;
165 const ZChar* orgString;
166 unsigned char* matchState = NULL;
167 unsigned char* currentRow;
168 unsigned char* previousRow;
169
170 if (!(*pattern) || !(*string))
171 {
172 krisbash 1.1 /* skip any trailing wildcard characters */
173 while (*pattern == WILDCARD) pattern++;
|
174 krisbash 1.2 if (!(*pattern) && !(*string))
|
175 krisbash 1.1 return MI_TRUE;
176 return MI_FALSE;
177 }
178
179 stringLength = Tcslen(string);
180 rowLength = stringLength + 1;
181 orgString = string;
182
183 if (!_EnsureMatchState(stringLength, &matchState))
184 return MI_FALSE;
185
186 currentRow = matchState + rowLength;
187 previousRow = matchState;
188 while (*pattern)
189 {
190 /* Wildcard match. */
191 if (*pattern == WILDCARD)
192 {
193 size_t c;
194
195 /* skip any continuous wildcard characters */
196 krisbash 1.1 while (*(pattern + 1) == WILDCARD) pattern++;
197
198 for (c = 0; c <= stringLength; c++)
199 {
200 unsigned char match = previousRow[c];
201 size_t matchedPos;
202
203 if (match == NO_MATCH)
204 {
205 continue;
206 }
207 /* found a prior pattern char matched, */
208 /* then mark that the current wildcard */
209 /* matching the remaining part of target string */
210 if (match == MATCHED_WITH_ONE_CHAR)
211 {
212 matchedPos = c + 1;
213 /* current wild char still match, but it should be */
214 /* the same as its preivous pattern char, I.E., */
215 /* matched one char */
216 currentRow[c] = MATCHED_WITH_ONE_CHAR;
217 krisbash 1.1 }
218 else
219 {
220 /* if previous one is a wildcard match, */
221 /* then this wildcard has the same matching result */
222 /* with preivous char */
223 matchedPos = c;
224 }
225 for (; matchedPos <= stringLength; matchedPos++)
226 {
227 currentRow[matchedPos] = MATCHED_WITH_WILDCARD_CHAR;
228 }
229 break;
230 }
231 _SwitchRow(rowLength, ¤tRow, &previousRow);
232 pattern++;
233 }
234 /* Set match. */
235 else if (*pattern == '[')
236 {
237 size_t c;
238 krisbash 1.1 int foundMatch = MI_FALSE;
239 int foundSkip = 0;
240
241 /* find all matching points based on the */
242 /* previous matching result */
243 for (c = 0; c <= stringLength; c++)
244 {
245 unsigned char match = previousRow[c];
246 int skip;
247 const ZChar* currentString;
248
249 if (match == NO_MATCH)
250 {
251 continue;
252 }
253 currentString = orgString + c;
254 if (match == MATCHED_WITH_WILDCARD_CHAR)
255 {
256 /* match the current char if preivous is a wildchar match */
257 /* otherwise match the next char */
258 currentString --;
259 krisbash 1.1 }
260 else if (c == stringLength)
261 {
262 /* no match since no char left in target string */
263 break;
264 }
265 if (_MatchSet (pattern, currentString, &skip))
266 {
267 size_t matchedPos;
268
269 if (!foundMatch)
270 {
271 foundMatch = MI_TRUE;
272 foundSkip = skip;
273 }
274 /* mark the current pattern char mataching result */
275 matchedPos = (size_t)(currentString - orgString) + 1;
276 currentRow[matchedPos] = MATCHED_WITH_ONE_CHAR;
277 }
278 }
279 _SwitchRow(rowLength, ¤tRow, &previousRow);
280 krisbash 1.1 /* no match */
281 if (!foundMatch)
282 {
283 break;
284 }
285 pattern += foundSkip;
286 }
287 /* Single character match. */
288 else
289 {
290 size_t c;
291 int foundMatch = MI_FALSE;
292
293 if (escape != '\0' && *pattern == escape)
294 {
295 pattern++;
296 }
297
298 /* find all matching points based on the */
299 /* previous matching result */
300 for (c = 0; c <= stringLength; c++)
301 krisbash 1.1 {
302 unsigned char match = previousRow[c];
303 const ZChar* currentString;
304
305 if (match == NO_MATCH)
306 {
307 continue;
308 }
309 currentString = orgString + c;
310 if (match == MATCHED_WITH_WILDCARD_CHAR)
311 {
312 /* match the current char if preivous is a wildchar match, */
313 /* otherwise match the next char */
314 currentString --;
315 }
316 else if (c == stringLength)
317 {
318 /* no match since no char left in target string */
319 break;
320 }
321
|
322 krisbash 1.2 if (_Toupper(*pattern) == _Toupper(*currentString) ||
|
323 krisbash 1.1 *pattern == ANYSINGLECHAR)
324 {
325 size_t matchedPos;
326
327 if (!foundMatch)
328 {
329 foundMatch = MI_TRUE;
330 }
331
332 /* mark the current pattern char mataching result */
333 matchedPos = (size_t)(currentString - orgString) + 1;
334 currentRow[matchedPos] = MATCHED_WITH_ONE_CHAR;
335 }
336 }
337 _SwitchRow(rowLength, ¤tRow, &previousRow);
338 /* no match */
339 if (!foundMatch)
340 {
341 break;
342 }
343
344 krisbash 1.1 pattern ++;
345 }
346 }
347
348 /* Matched if the last pattern char mattached the last target string char */
349 /* NoMatch otherwise */
350 {
351 MI_Boolean flag = (previousRow[stringLength] != 0) ? MI_TRUE : MI_FALSE;
352 PAL_Free(matchState);
353 return flag;
354 }
355 }
356
357 #ifdef _PREFAST_
358 #pragma prefast (pop)
359 #endif
|