FreeRDP
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 
43 LPSTR 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 
84 static 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 
198 BOOL 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 = (lpWildcard - lpSubPattern);
330  lpY = &lpSubPattern[cchX + cchWildcard];
331  cchY = (cchSubPattern - (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 = cchFileName - (lpSubFileName - lpFileName);
341  cchNextWildcard = ((dwNextFlags & WILDCARD_DOS) ? 2 : 1);
342  lpX = lpSubPattern;
343  cchX = (lpWildcard - lpSubPattern);
344  lpY = &lpSubPattern[cchX + cchWildcard];
345  cchY = (lpNextWildcard - lpWildcard) - cchWildcard;
346  match = FilePatternMatchSubExpressionA(lpSubFileName, cchSubFileName, lpX, cchX,
347  lpY, cchY, lpWildcard, &lpMatchEnd);
348 
349  if (!match)
350  return FALSE;
351 
352  lpSubFileName = lpMatchEnd;
353  cchWildcard = cchNextWildcard;
354  lpWildcard = lpNextWildcard;
355  dwFlags = dwNextFlags;
356  lpNextWildcard =
357  FilePatternFindNextWildcardA(&lpWildcard[cchWildcard], &dwNextFlags);
358  }
359 
360  return TRUE;
361  }
362  }
363  else
364  {
365  /* no wildcard characters */
366  if (_stricmp(lpFileName, lpPattern) == 0)
367  return TRUE;
368  }
369 
370  return FALSE;
371 }