FreeRDP
Loading...
Searching...
No Matches
pattern.c
1
20#include <winpr/config.h>
21
22#include <winpr/crt.h>
23#include <winpr/handle.h>
24
25#include <winpr/file.h>
26
27#ifdef WINPR_HAVE_UNISTD_H
28#include <unistd.h>
29#endif
30
31#ifdef WINPR_HAVE_FCNTL_H
32#include <fcntl.h>
33#endif
34
35#include "../log.h"
36#define TAG WINPR_TAG("file")
37
43LPSTR FilePatternFindNextWildcardA(LPCSTR lpPattern, DWORD* pFlags)
44{
45 LPSTR lpWildcard = NULL;
46 *pFlags = 0;
47 lpWildcard = strpbrk(lpPattern, "*?~");
48
49 if (lpWildcard)
50 {
51 if (*lpWildcard == '*')
52 {
53 *pFlags = WILDCARD_STAR;
54 return lpWildcard;
55 }
56 else if (*lpWildcard == '?')
57 {
58 *pFlags = WILDCARD_QM;
59 return lpWildcard;
60 }
61 else if (*lpWildcard == '~')
62 {
63 if (lpWildcard[1] == '*')
64 {
65 *pFlags = WILDCARD_DOS_STAR;
66 return lpWildcard;
67 }
68 else if (lpWildcard[1] == '?')
69 {
70 *pFlags = WILDCARD_DOS_QM;
71 return lpWildcard;
72 }
73 else if (lpWildcard[1] == '.')
74 {
75 *pFlags = WILDCARD_DOS_DOT;
76 return lpWildcard;
77 }
78 }
79 }
80
81 return NULL;
82}
83
84static BOOL FilePatternMatchSubExpressionA(LPCSTR lpFileName, size_t cchFileName, LPCSTR lpX,
85 size_t cchX, LPCSTR lpY, size_t cchY, LPCSTR lpWildcard,
86 LPCSTR* ppMatchEnd)
87{
88 LPCSTR lpMatch = NULL;
89
90 if (!lpFileName)
91 return FALSE;
92
93 if (*lpWildcard == '*')
94 {
95 /*
96 * S
97 * <-----<
98 * X | | e Y
99 * X * Y == (0)----->-(1)->-----(2)-----(3)
100 */
101
102 /*
103 * State 0: match 'X'
104 */
105 if (_strnicmp(lpFileName, lpX, cchX) != 0)
106 return FALSE;
107
108 /*
109 * State 1: match 'S' or 'e'
110 *
111 * We use 'e' to transition to state 2
112 */
113
118 if (cchY != 0)
119 {
120 /* TODO: case insensitive character search */
121 lpMatch = strchr(&lpFileName[cchX], *lpY);
122
123 if (!lpMatch)
124 return FALSE;
125
126 if (_strnicmp(lpMatch, lpY, cchY) != 0)
127 return FALSE;
128 }
129 else
130 {
131 lpMatch = &lpFileName[cchFileName];
132 }
133
137 *ppMatchEnd = &lpMatch[cchY];
138 return TRUE;
139 }
140 else if (*lpWildcard == '?')
141 {
147 /*
148 * State 0: match 'X'
149 */
150 if (cchFileName < cchX)
151 return FALSE;
152
153 if (_strnicmp(lpFileName, lpX, cchX) != 0)
154 return FALSE;
155
156 /*
157 * State 1: match 'S'
158 */
159
164 if (cchY != 0)
165 {
166 /* TODO: case insensitive character search */
167 lpMatch = strchr(&lpFileName[cchX + 1], *lpY);
168
169 if (!lpMatch)
170 return FALSE;
171
172 if (_strnicmp(lpMatch, lpY, cchY) != 0)
173 return FALSE;
174 }
175 else
176 {
177 if ((cchX + 1) > cchFileName)
178 return FALSE;
179
180 lpMatch = &lpFileName[cchX + 1];
181 }
182
186 *ppMatchEnd = &lpMatch[cchY];
187 return TRUE;
188 }
189 else if (*lpWildcard == '~')
190 {
191 WLog_ERR(TAG, "warning: unimplemented '~' pattern match");
192 return TRUE;
193 }
194
195 return FALSE;
196}
197
198BOOL FilePatternMatchA(LPCSTR lpFileName, LPCSTR lpPattern)
199{
200 BOOL match = 0;
201 LPCSTR lpTail = NULL;
202 size_t cchTail = 0;
203 size_t cchPattern = 0;
204 size_t cchFileName = 0;
205 DWORD dwFlags = 0;
206 DWORD dwNextFlags = 0;
207 LPSTR lpWildcard = NULL;
208 LPSTR lpNextWildcard = NULL;
209
224 if (!lpPattern)
225 return FALSE;
226
227 if (!lpFileName)
228 return FALSE;
229
230 cchPattern = strlen(lpPattern);
231 cchFileName = strlen(lpFileName);
232
240 if ((lpPattern[0] == '*') && (cchPattern == 1))
241 return TRUE;
242
253 if (lpPattern[0] == '*')
254 {
255 lpTail = &lpPattern[1];
256 cchTail = strlen(lpTail);
257
258 if (!FilePatternFindNextWildcardA(lpTail, &dwFlags))
259 {
260 /* tail contains no wildcards */
261 if (cchFileName < cchTail)
262 return FALSE;
263
264 if (_stricmp(&lpFileName[cchFileName - cchTail], lpTail) == 0)
265 return TRUE;
266
267 return FALSE;
268 }
269 }
270
304 lpWildcard = FilePatternFindNextWildcardA(lpPattern, &dwFlags);
305
306 if (lpWildcard)
307 {
308 LPCSTR lpX = NULL;
309 LPCSTR lpY = NULL;
310 size_t cchX = 0;
311 size_t cchY = 0;
312 LPCSTR lpMatchEnd = NULL;
313 LPCSTR lpSubPattern = NULL;
314 size_t cchSubPattern = 0;
315 LPCSTR lpSubFileName = NULL;
316 size_t cchSubFileName = 0;
317 size_t cchWildcard = 0;
318 size_t cchNextWildcard = 0;
319 cchSubPattern = cchPattern;
320 lpSubPattern = lpPattern;
321 cchSubFileName = cchFileName;
322 lpSubFileName = lpFileName;
323 cchWildcard = ((dwFlags & WILDCARD_DOS) ? 2 : 1);
324 lpNextWildcard = FilePatternFindNextWildcardA(&lpWildcard[cchWildcard], &dwNextFlags);
325
326 if (!lpNextWildcard)
327 {
328 lpX = lpSubPattern;
329 cchX = WINPR_ASSERTING_INT_CAST(size_t, (lpWildcard - lpSubPattern));
330 lpY = &lpSubPattern[cchX + cchWildcard];
331 cchY = (cchSubPattern - WINPR_ASSERTING_INT_CAST(size_t, (lpY - lpSubPattern)));
332 match = FilePatternMatchSubExpressionA(lpSubFileName, cchSubFileName, lpX, cchX, lpY,
333 cchY, lpWildcard, &lpMatchEnd);
334 return match;
335 }
336 else
337 {
338 while (lpNextWildcard)
339 {
340 cchSubFileName =
341 cchFileName - WINPR_ASSERTING_INT_CAST(size_t, (lpSubFileName - lpFileName));
342 cchNextWildcard = ((dwNextFlags & WILDCARD_DOS) ? 2 : 1);
343 lpX = lpSubPattern;
344 cchX = WINPR_ASSERTING_INT_CAST(size_t, (lpWildcard - lpSubPattern));
345 lpY = &lpSubPattern[cchX + cchWildcard];
346 cchY =
347 WINPR_ASSERTING_INT_CAST(size_t, (lpNextWildcard - lpWildcard)) - cchWildcard;
348 match = FilePatternMatchSubExpressionA(lpSubFileName, cchSubFileName, lpX, cchX,
349 lpY, cchY, lpWildcard, &lpMatchEnd);
350
351 if (!match)
352 return FALSE;
353
354 lpSubFileName = lpMatchEnd;
355 cchWildcard = cchNextWildcard;
356 lpWildcard = lpNextWildcard;
357 dwFlags = dwNextFlags;
358 lpNextWildcard =
359 FilePatternFindNextWildcardA(&lpWildcard[cchWildcard], &dwNextFlags);
360 }
361
362 return TRUE;
363 }
364 }
365 else
366 {
367 /* no wildcard characters */
368 if (_stricmp(lpFileName, lpPattern) == 0)
369 return TRUE;
370 }
371
372 return FALSE;
373}