VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxUSB/USBFilter.cpp@ 103914

Last change on this file since 103914 was 100772, checked in by vboxsync, 16 months ago

include/VBox/usbfilter.h,HostDrivers/VBoxUSB/USBFilter: IUSBDeviceFilter:
USB device interval filters don't work. bugref:10452

Main/Host,Main/USBDeviceFilter: Adding or removing global USB device
filters causes memory corruption wihch can lead to a deadlock or a SEGV
as the list of global USB device filters (llChildren) changes while
the list is being walked.

Frontends/VBoxManage: 'VBoxManage list usbfilters' doesn't display the
'Port' value of the device filter.

Frontends/VBoxManage: 'VBoxManage add usbfilter' and 'VBoxManage modify
usbfilter' both ignore the --product="Value" option.

Main/VirtualBox.xidl: Improve the IUSBDeviceFilter wording to make
things clearer in the 'VirtualBox Programming Guide and Reference Guide'
aka SDKRef.pdf.

HostDrivers/VBoxUSB/testcase/tstUSBFilter: Include a variety of USB
device filter entries which include the 'int:' prefix to fully exercise
the interval filter parsing code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 62.6 KB
Line 
1/* $Id: USBFilter.cpp 100772 2023-08-01 17:34:48Z vboxsync $ */
2/** @file
3 * VirtualBox USB filter abstraction.
4 */
5
6/*
7 * Copyright (C) 2007-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <VBox/usbfilter.h>
42#include <VBox/usblib.h>
43#include <VBox/err.h>
44#include <VBox/log.h>
45#include <iprt/string.h>
46#include <iprt/assert.h>
47#include <iprt/ctype.h>
48
49
50/** @todo split this up for the sake of device drivers and such. */
51
52
53/**
54 * Initializes an USBFILTER structure.
55 *
56 * @param pFilter The filter to initialize.
57 * @param enmType The filter type. If not valid, the filter will not
58 * be properly initialized and all other calls will fail.
59 */
60USBLIB_DECL(void) USBFilterInit(PUSBFILTER pFilter, USBFILTERTYPE enmType)
61{
62 memset(pFilter, 0, sizeof(*pFilter));
63 AssertReturnVoid(enmType > USBFILTERTYPE_INVALID && enmType < USBFILTERTYPE_END);
64 pFilter->u32Magic = USBFILTER_MAGIC;
65 pFilter->enmType = enmType;
66 for (unsigned i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
67 pFilter->aFields[i].enmMatch = USBFILTERMATCH_IGNORE;
68}
69
70
71/**
72 * Make a clone of the specified filter.
73 *
74 * @param pFilter The target filter.
75 * @param pToClone The source filter.
76 */
77USBLIB_DECL(void) USBFilterClone(PUSBFILTER pFilter, PCUSBFILTER pToClone)
78{
79 memcpy(pFilter, pToClone, sizeof(*pToClone));
80}
81
82
83/**
84 * Deletes (invalidates) an USBFILTER structure.
85 *
86 * @param pFilter The filter to delete.
87 */
88USBLIB_DECL(void) USBFilterDelete(PUSBFILTER pFilter)
89{
90 pFilter->u32Magic = ~USBFILTER_MAGIC;
91 pFilter->enmType = USBFILTERTYPE_INVALID;
92 pFilter->offCurEnd = 0xfffff;
93}
94
95
96/**
97 * Skips blanks.
98 *
99 * @returns Next non-blank char in the string.
100 * @param psz The string.
101 */
102DECLINLINE(const char *) usbfilterSkipBlanks(const char *psz)
103{
104 while (RT_C_IS_BLANK(*psz))
105 psz++;
106 return psz;
107}
108
109
110/**
111 * Worker for usbfilterReadNumber that parses a hexadecimal number.
112 *
113 * @returns Same as usbfilterReadNumber, except for VERR_NO_DIGITS.
114 * @param pszExpr Where to start converting, first char is a valid digit.
115 * @param ppszExpr See usbfilterReadNumber.
116 * @param pu16Val See usbfilterReadNumber.
117 */
118static int usbfilterReadNumberHex(const char *pszExpr, const char **ppszExpr, uint16_t *pu16Val)
119{
120 int rc = VINF_SUCCESS;
121 uint32_t u32 = 0;
122 do
123 {
124 unsigned uDigit = *pszExpr >= 'a' && *pszExpr <= 'f'
125 ? *pszExpr - 'a' + 10
126 : *pszExpr >= 'A' && *pszExpr <= 'F'
127 ? *pszExpr - 'A' + 10
128 : *pszExpr - '0';
129 if (uDigit >= 16)
130 break;
131 u32 *= 16;
132 u32 += uDigit;
133 if (u32 > UINT16_MAX)
134 rc = VWRN_NUMBER_TOO_BIG;
135 } while (*++pszExpr);
136
137 *ppszExpr = usbfilterSkipBlanks(pszExpr);
138 *pu16Val = rc == VINF_SUCCESS ? u32 : UINT16_MAX;
139 return VINF_SUCCESS;
140}
141
142
143/**
144 * Worker for usbfilterReadNumber that parses a decimal number.
145 *
146 * @returns Same as usbfilterReadNumber, except for VERR_NO_DIGITS.
147 * @param pszExpr Where to start converting, first char is a valid digit.
148 * @param uBase The base - 8 or 16.
149 * @param ppszExpr See usbfilterReadNumber.
150 * @param pu16Val See usbfilterReadNumber.
151 */
152static int usbfilterReadNumberDecimal(const char *pszExpr, unsigned uBase, const char **ppszExpr, uint16_t *pu16Val)
153{
154 int rc = VINF_SUCCESS;
155 uint32_t u32 = 0;
156 do
157 {
158 unsigned uDigit = *pszExpr - '0';
159 if (uDigit >= uBase)
160 break;
161 u32 *= uBase;
162 u32 += uDigit;
163 if (u32 > UINT16_MAX)
164 rc = VWRN_NUMBER_TOO_BIG;
165 } while (*++pszExpr);
166
167 *ppszExpr = usbfilterSkipBlanks(pszExpr);
168 *pu16Val = rc == VINF_SUCCESS ? u32 : UINT16_MAX;
169 return rc;
170}
171
172
173/**
174 * Reads a number from a numeric expression.
175 *
176 * @returns IPRT status code.
177 * @retval VINF_SUCCESS if all is fine. *ppszExpr and *pu16Val are updated.
178 * @retval VWRN_NUMBER_TOO_BIG if the number exceeds unsigned 16-bit, both *ppszExpr and *pu16Val are updated.
179 * @retval VERR_NO_DIGITS if there aren't any digits.
180 *
181 * @param ppszExpr Pointer to the current expression pointer.
182 * This is advanced past the expression and trailing blanks on success.
183 * @param pu16Val Where to store the value on success.
184 */
185static int usbfilterReadNumber(const char **ppszExpr, uint16_t *pu16Val)
186{
187 const char *pszExpr = usbfilterSkipBlanks(*ppszExpr);
188 if (!RT_C_IS_DIGIT(*pszExpr))
189 return VERR_NO_DIGITS;
190
191 if (*pszExpr == '0')
192 {
193 if (pszExpr[1] == 'x' || pszExpr[1] == 'X')
194 {
195 if (!RT_C_IS_XDIGIT(pszExpr[2]))
196 return VERR_NO_DIGITS;
197 return usbfilterReadNumberHex(pszExpr + 2, ppszExpr, pu16Val);
198 }
199 if (RT_C_IS_ODIGIT(pszExpr[1]))
200 return usbfilterReadNumberDecimal(pszExpr + 1, 8, ppszExpr, pu16Val);
201 /* Solitary 0! */
202 if (RT_C_IS_DIGIT(pszExpr[1]))
203 return VERR_NO_DIGITS;
204 }
205 return usbfilterReadNumberDecimal(pszExpr, 10, ppszExpr, pu16Val);
206}
207
208
209/**
210 * Validates a numeric expression.
211 *
212 * @returns VBox status code.
213 * @retval VINF_SUCCESS if valid.
214 * @retval VERR_INVALID_PARAMETER if invalid.
215 * @retval VERR_NO_DIGITS if some expression is short of digits.
216 *
217 * @param pszExpr The numeric expression.
218 */
219static int usbfilterValidateNumExpression(const char *pszExpr)
220{
221 /*
222 * An empty expression is fine.
223 */
224 if (!*pszExpr)
225 return VINF_SUCCESS;
226
227 /*
228 * The string format is: "int:((<m>)|([<m>]-[<n>]))(,(<m>)|([<m>]-[<n>]))*"
229 * where <m> and <n> are numbers in decimal, hex (0xNNN) or octal (0NNN).
230 * Spaces are allowed around <m> and <n>.
231 */
232 unsigned cSubExpressions = 0;
233 while (*pszExpr)
234 {
235 if (!strncmp(pszExpr, RT_STR_TUPLE("int:")))
236 pszExpr += strlen("int:");
237
238 /*
239 * Skip remnants of the previous expression and any empty expressions.
240 * ('|' is the expression separator.)
241 */
242 while (*pszExpr == '|' || RT_C_IS_BLANK(*pszExpr) || *pszExpr == '(' || *pszExpr == ')')
243 pszExpr++;
244 if (!*pszExpr)
245 break;
246
247 /*
248 * Parse the expression.
249 */
250 int rc;
251 uint16_t u16First = 0;
252 uint16_t u16Last = 0;
253 if (*pszExpr == '-')
254 {
255 /* -N */
256 pszExpr++;
257 rc = usbfilterReadNumber(&pszExpr, &u16Last);
258 }
259 else
260 {
261 /* M or M,N or M-N or M- */
262 rc = usbfilterReadNumber(&pszExpr, &u16First);
263 if (RT_SUCCESS(rc))
264 {
265 pszExpr = usbfilterSkipBlanks(pszExpr);
266 if (*pszExpr == '-')
267 {
268 pszExpr++;
269 if (*pszExpr) /* M-N */
270 rc = usbfilterReadNumber(&pszExpr, &u16Last);
271 else /* M- */
272 u16Last = UINT16_MAX;
273 }
274 else if (*pszExpr == ',')
275 {
276 /* M,N */
277 pszExpr++;
278 rc = usbfilterReadNumber(&pszExpr, &u16Last);
279 }
280 else
281 {
282 /* M */
283 u16Last = u16First;
284 }
285 }
286 }
287 if (RT_FAILURE(rc))
288 return rc;
289
290 /*
291 * We should either be at the end of the string, at an expression separator (|),
292 * or at the end of an interval filter (')').
293 */
294 if (*pszExpr && *pszExpr != '|' && *pszExpr != ')')
295 return VERR_INVALID_PARAMETER;
296
297 cSubExpressions++;
298 }
299
300 return cSubExpressions ? VINF_SUCCESS : VERR_INVALID_PARAMETER;
301}
302
303
304/**
305 * Validates a string pattern.
306 *
307 * @returns VBox status code.
308 * @retval VINF_SUCCESS if valid.
309 * @retval VERR_INVALID_PARAMETER if invalid.
310 *
311 * @param psz The string pattern.
312 */
313static int usbfilterValidateStringPattern(const char *psz)
314{
315 /*
316 * This is only becomes important if we start doing
317 * sets ([0-9]) and such like.
318 */
319 RT_NOREF1(psz);
320 return VINF_SUCCESS;
321}
322
323
324/**
325 * Thoroughly validates the USB Filter.
326 *
327 * @returns Appropriate VBox status code.
328 * @param pFilter The filter to validate.
329 */
330USBLIB_DECL(int) USBFilterValidate(PCUSBFILTER pFilter)
331{
332 if (!RT_VALID_PTR(pFilter))
333 return VERR_INVALID_POINTER;
334
335 if (pFilter->u32Magic != USBFILTER_MAGIC)
336 return VERR_INVALID_MAGIC;
337
338 if ( pFilter->enmType <= USBFILTERTYPE_INVALID
339 || pFilter->enmType >= USBFILTERTYPE_END)
340 {
341 Log(("USBFilter: %p - enmType=%d!\n", pFilter, pFilter->enmType));
342 return VERR_INVALID_PARAMETER;
343 }
344
345 if (pFilter->offCurEnd >= sizeof(pFilter->achStrTab))
346 {
347 Log(("USBFilter: %p - offCurEnd=%#x!\n", pFilter, pFilter->offCurEnd));
348 return VERR_INVALID_PARAMETER;
349 }
350
351 /* Validate that string value offsets are inside the string table. */
352 for (uint32_t i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
353 {
354 if ( USBFilterIsMethodUsingStringValue((USBFILTERMATCH)pFilter->aFields[i].enmMatch)
355 && pFilter->aFields[i].u16Value > pFilter->offCurEnd)
356 {
357 Log(("USBFilter: %p - bad offset=%#x\n", pFilter, pFilter->aFields[i].u16Value));
358 return VERR_INVALID_PARAMETER;
359 }
360 }
361
362 /*
363 * Validate the string table.
364 */
365 if (pFilter->achStrTab[0])
366 {
367 Log(("USBFilter: %p - bad null string\n", pFilter));
368 return VERR_INVALID_PARAMETER;
369 }
370
371 const char *psz = &pFilter->achStrTab[1];
372 while (psz < &pFilter->achStrTab[pFilter->offCurEnd])
373 {
374 const char *pszEnd = RTStrEnd(psz, &pFilter->achStrTab[sizeof(pFilter->achStrTab)] - psz);
375 if (!pszEnd)
376 {
377 Log(("USBFilter: %p - string at %#x isn't terminated!\n",
378 pFilter, psz - &pFilter->achStrTab[0]));
379 return VERR_INVALID_PARAMETER;
380 }
381
382 uint16_t off = (uint16_t)(uintptr_t)(psz - &pFilter->achStrTab[0]);
383 unsigned i;
384 for (i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
385 if ( USBFilterIsMethodUsingStringValue((USBFILTERMATCH)pFilter->aFields[i].enmMatch)
386 && pFilter->aFields[i].u16Value == off)
387 break;
388 if (i >= RT_ELEMENTS(pFilter->aFields))
389 {
390 Log(("USBFilter: %p - string at %#x isn't used by anyone! (%s)\n",
391 pFilter, psz - &pFilter->achStrTab[0], psz));
392 return VERR_INVALID_PARAMETER;
393 }
394
395 psz = pszEnd + 1;
396 }
397
398 if ((uintptr_t)(psz - &pFilter->achStrTab[0] - 1) != pFilter->offCurEnd)
399 {
400 Log(("USBFilter: %p - offCurEnd=%#x currently at %#x\n",
401 pFilter, pFilter->offCurEnd, psz - &pFilter->achStrTab[0] - 1));
402 return VERR_INVALID_PARAMETER;
403 }
404
405 while (psz < &pFilter->achStrTab[sizeof(pFilter->achStrTab)])
406 {
407 if (*psz)
408 {
409 Log(("USBFilter: %p - str tab isn't zero padded! %#x: %c\n",
410 pFilter, psz - &pFilter->achStrTab[0], *psz));
411 return VERR_INVALID_PARAMETER;
412 }
413 psz++;
414 }
415
416
417 /*
418 * Validate the fields.
419 */
420 int rc;
421 for (unsigned i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
422 {
423 switch (pFilter->aFields[i].enmMatch)
424 {
425 case USBFILTERMATCH_IGNORE:
426 case USBFILTERMATCH_PRESENT:
427 if (pFilter->aFields[i].u16Value)
428 {
429 Log(("USBFilter: %p - #%d/%d u16Value=%d expected 0!\n",
430 pFilter, i, pFilter->aFields[i].enmMatch, pFilter->aFields[i].u16Value));
431 return VERR_INVALID_PARAMETER;
432 }
433 break;
434
435 case USBFILTERMATCH_NUM_EXACT:
436 case USBFILTERMATCH_NUM_EXACT_NP:
437 if (!USBFilterIsNumericField((USBFILTERIDX)i))
438 {
439 Log(("USBFilter: %p - #%d / %d - not numeric field\n",
440 pFilter, i, pFilter->aFields[i].enmMatch));
441 return VERR_INVALID_PARAMETER;
442 }
443 break;
444
445 case USBFILTERMATCH_NUM_EXPRESSION:
446 case USBFILTERMATCH_NUM_EXPRESSION_NP:
447 if (!USBFilterIsNumericField((USBFILTERIDX)i))
448 {
449 Log(("USBFilter: %p - #%d / %d - not numeric field\n",
450 pFilter, i, pFilter->aFields[i].enmMatch));
451 return VERR_INVALID_PARAMETER;
452 }
453 if ( pFilter->aFields[i].u16Value >= pFilter->offCurEnd
454 && pFilter->offCurEnd)
455 {
456 Log(("USBFilter: %p - #%d / %d - off=%#x max=%#x\n",
457 pFilter, i, pFilter->aFields[i].enmMatch, pFilter->aFields[i].u16Value, pFilter->offCurEnd));
458 return VERR_INVALID_PARAMETER;
459 }
460 psz = &pFilter->achStrTab[pFilter->aFields[i].u16Value];
461 rc = usbfilterValidateNumExpression(psz);
462 if (RT_FAILURE(rc))
463 {
464 Log(("USBFilter: %p - #%d / %d - bad num expr: %s (rc=%Rrc)\n",
465 pFilter, i, pFilter->aFields[i].enmMatch, psz, rc));
466 return rc;
467 }
468 break;
469
470 case USBFILTERMATCH_STR_EXACT:
471 case USBFILTERMATCH_STR_EXACT_NP:
472 if (!USBFilterIsStringField((USBFILTERIDX)i))
473 {
474 Log(("USBFilter: %p - #%d / %d - not string field\n",
475 pFilter, i, pFilter->aFields[i].enmMatch));
476 return VERR_INVALID_PARAMETER;
477 }
478 if ( pFilter->aFields[i].u16Value >= pFilter->offCurEnd
479 && pFilter->offCurEnd)
480 {
481 Log(("USBFilter: %p - #%d / %d - off=%#x max=%#x\n",
482 pFilter, i, pFilter->aFields[i].enmMatch, pFilter->aFields[i].u16Value, pFilter->offCurEnd));
483 return VERR_INVALID_PARAMETER;
484 }
485 break;
486
487 case USBFILTERMATCH_STR_PATTERN:
488 case USBFILTERMATCH_STR_PATTERN_NP:
489 if (!USBFilterIsStringField((USBFILTERIDX)i))
490 {
491 Log(("USBFilter: %p - #%d / %d - not string field\n",
492 pFilter, i, pFilter->aFields[i].enmMatch));
493 return VERR_INVALID_PARAMETER;
494 }
495 if ( pFilter->aFields[i].u16Value >= pFilter->offCurEnd
496 && pFilter->offCurEnd)
497 {
498 Log(("USBFilter: %p - #%d / %d - off=%#x max=%#x\n",
499 pFilter, i, pFilter->aFields[i].enmMatch, pFilter->aFields[i].u16Value, pFilter->offCurEnd));
500 return VERR_INVALID_PARAMETER;
501 }
502 psz = &pFilter->achStrTab[pFilter->aFields[i].u16Value];
503 rc = usbfilterValidateStringPattern(psz);
504 if (RT_FAILURE(rc))
505 {
506 Log(("USBFilter: %p - #%d / %d - bad string pattern: %s (rc=%Rrc)\n",
507 pFilter, i, pFilter->aFields[i].enmMatch, psz, rc));
508 return rc;
509 }
510 break;
511
512 default:
513 Log(("USBFilter: %p - #%d enmMatch=%d!\n", pFilter, i, pFilter->aFields[i].enmMatch));
514 return VERR_INVALID_PARAMETER;
515 }
516 }
517
518 return VINF_SUCCESS;
519}
520
521
522/**
523 * Find the specified field in the string table.
524 *
525 * @returns Pointer to the string in the string table on success.
526 * NULL if the field is invalid or it doesn't have a string value.
527 * @param pFilter The filter.
528 * @param enmFieldIdx The field index.
529 */
530DECLINLINE(const char *) usbfilterGetString(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
531{
532 if ((unsigned)enmFieldIdx < (unsigned)USBFILTERIDX_END)
533 {
534 switch (pFilter->aFields[enmFieldIdx].enmMatch)
535 {
536 case USBFILTERMATCH_NUM_EXPRESSION:
537 case USBFILTERMATCH_NUM_EXPRESSION_NP:
538 case USBFILTERMATCH_STR_EXACT:
539 case USBFILTERMATCH_STR_EXACT_NP:
540 case USBFILTERMATCH_STR_PATTERN:
541 case USBFILTERMATCH_STR_PATTERN_NP:
542 Assert(pFilter->aFields[enmFieldIdx].u16Value < sizeof(pFilter->achStrTab));
543 return &pFilter->achStrTab[pFilter->aFields[enmFieldIdx].u16Value];
544
545 default:
546 AssertMsgFailed(("%d\n", pFilter->aFields[enmFieldIdx].enmMatch));
547 case USBFILTERMATCH_IGNORE:
548 case USBFILTERMATCH_PRESENT:
549 case USBFILTERMATCH_NUM_EXACT:
550 case USBFILTERMATCH_NUM_EXACT_NP:
551 break;
552 }
553 }
554 return NULL;
555}
556
557
558/**
559 * Gets a number value of a field.
560 *
561 * The field must contain a numeric value.
562 *
563 * @returns The field value on success, -1 on failure (invalid input / not numeric).
564 * @param pFilter The filter.
565 * @param enmFieldIdx The field index.
566 */
567DECLINLINE(int) usbfilterGetNum(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
568{
569 if ((unsigned)enmFieldIdx < (unsigned)USBFILTERIDX_END)
570 {
571 switch (pFilter->aFields[enmFieldIdx].enmMatch)
572 {
573 case USBFILTERMATCH_NUM_EXACT:
574 case USBFILTERMATCH_NUM_EXACT_NP:
575 return pFilter->aFields[enmFieldIdx].u16Value;
576
577 default:
578 AssertMsgFailed(("%d\n", pFilter->aFields[enmFieldIdx].enmMatch));
579 case USBFILTERMATCH_IGNORE:
580 case USBFILTERMATCH_PRESENT:
581 case USBFILTERMATCH_NUM_EXPRESSION:
582 case USBFILTERMATCH_NUM_EXPRESSION_NP:
583 case USBFILTERMATCH_STR_EXACT:
584 case USBFILTERMATCH_STR_EXACT_NP:
585 case USBFILTERMATCH_STR_PATTERN:
586 case USBFILTERMATCH_STR_PATTERN_NP:
587 break;
588 }
589 }
590 return -1;
591}
592
593
594/**
595 * Performs simple pattern matching.
596 *
597 * @returns true on match and false on mismatch.
598 * @param pszExpr The numeric expression.
599 * @param u16Value The value to match.
600 */
601static bool usbfilterMatchNumExpression(const char *pszExpr, uint16_t u16Value)
602{
603 /*
604 * The string format is: "int:((<m>)|([<m>]-[<n>]))(,(<m>)|([<m>]-[<n>]))*"
605 * where <m> and <n> are numbers in decimal, hex (0xNNN) or octal (0NNN).
606 * Spaces are allowed around <m> and <n>.
607 */
608 while (*pszExpr)
609 {
610 if (!strncmp(pszExpr, RT_STR_TUPLE("int:")))
611 pszExpr += strlen("int:");
612
613 /*
614 * Skip remnants of the previous expression and any empty expressions.
615 * ('|' is the expression separator.)
616 */
617 while (*pszExpr == '|' || RT_C_IS_BLANK(*pszExpr) || *pszExpr == '(' || *pszExpr == ')')
618 pszExpr++;
619 if (!*pszExpr)
620 break;
621
622 /*
623 * Parse the expression.
624 */
625 int rc;
626 uint16_t u16First = 0;
627 uint16_t u16Last = 0;
628 if (*pszExpr == '-')
629 {
630 /* -N */
631 pszExpr++;
632 rc = usbfilterReadNumber(&pszExpr, &u16Last);
633 }
634 else
635 {
636 /* M or M,N or M-N or M- */
637 rc = usbfilterReadNumber(&pszExpr, &u16First);
638 if (RT_SUCCESS(rc))
639 {
640 pszExpr = usbfilterSkipBlanks(pszExpr);
641 if (*pszExpr == '-')
642 {
643 pszExpr++;
644 if (*pszExpr) /* M-N */
645 rc = usbfilterReadNumber(&pszExpr, &u16Last);
646 else /* M- */
647 u16Last = UINT16_MAX;
648 }
649 else if (*pszExpr == ',')
650 {
651 /* M,N */
652 pszExpr++;
653 rc = usbfilterReadNumber(&pszExpr, &u16Last);
654 }
655 else
656 {
657 /* M */
658 u16Last = u16First;
659 }
660 }
661 }
662
663 /* On success, we should either be at the end of the string, at an expression
664 * separator (|), or at the end of an interval filter (')').
665 */
666 if (RT_SUCCESS(rc) && *pszExpr && *pszExpr != '|' && *pszExpr != ')')
667 rc = VERR_INVALID_PARAMETER;
668 if (RT_SUCCESS(rc))
669 {
670 /*
671 * Swap the values if the order is mixed up.
672 */
673 if (u16First > u16Last)
674 {
675 uint16_t u16Tmp = u16First;
676 u16First = u16Last;
677 u16Last = u16Tmp;
678 }
679
680 /*
681 * Perform the compare.
682 */
683 if ( u16Value >= u16First
684 && u16Value <= u16Last)
685 return true;
686 }
687 else
688 {
689 /*
690 * Skip the bad expression.
691 * ('|' is the expression separator.)
692 */
693 while (*pszExpr && *pszExpr != '|')
694 pszExpr++;
695 }
696 }
697
698 return false;
699}
700
701
702/**
703 * Performs simple pattern matching.
704 *
705 * @returns true on match and false on mismatch.
706 * @param pszPattern The pattern to match against.
707 * @param psz The string to match.
708 */
709static bool usbfilterMatchStringPattern(const char *pszPattern, const char *psz)
710{
711 char ch;
712 while ((ch = *pszPattern++))
713 {
714 if (ch == '?')
715 {
716 /*
717 * Matches one char or end of string.
718 */
719 if (*psz)
720 psz++;
721 }
722 else if (ch == '*')
723 {
724 /*
725 * Matches zero or more characters.
726 */
727 /* skip subsequent wildcards */
728 while ( (ch = *pszPattern) == '*'
729 || ch == '?')
730 pszPattern++;
731 if (!ch)
732 /* Pattern ends with a '*' and thus matches the rest of psz. */
733 return true;
734
735 /* Find the length of the following exact pattern sequence. */
736 ssize_t cchMatch = 1;
737 while ( (ch = pszPattern[cchMatch]) != '\0'
738 && ch != '*'
739 && ch != '?')
740 cchMatch++;
741
742 /* Check if the exact pattern sequence is too long. */
743 ssize_t cch = strlen(psz);
744 cch -= cchMatch;
745 if (cch < 0)
746 return false;
747
748 /* Is the rest an exact match? */
749 if (!ch)
750 return memcmp(psz + cch, pszPattern, cchMatch) == 0;
751
752 /*
753 * This is where things normally starts to get recursive or ugly.
754 *
755 * Just to make life simple, we'll skip the nasty stuff and say
756 * that we will do a maximal wildcard match and forget about any
757 * alternative matches.
758 *
759 * If somebody is bored out of their mind one day, feel free to
760 * implement correct matching without using recursion.
761 */
762 ch = *pszPattern;
763 const char *pszMatch = NULL;
764 while ( cch-- >= 0
765 && *psz)
766 {
767 if ( *psz == ch
768 && !strncmp(psz, pszPattern, cchMatch))
769 pszMatch = psz;
770 psz++;
771 }
772 if (!pszMatch)
773 return false;
774
775 /* advance */
776 psz = pszMatch + cchMatch;
777 pszPattern += cchMatch;
778 }
779 else
780 {
781 /* exact match */
782 if (ch != *psz)
783 return false;
784 psz++;
785 }
786 }
787
788 return *psz == '\0';
789}
790
791
792/**
793 * Match a filter against a device.
794 *
795 * @returns true if they match, false if not.
796 *
797 * @param pFilter The filter to match with.
798 * @param pDevice The device data. This is a filter (type ignored) that
799 * contains 'exact' values for all present fields and 'ignore'
800 * values for the non-present fields.
801 *
802 * @remark Both the filter and the device are ASSUMED to be valid because
803 * we don't wish to waste any time in this function.
804 */
805USBLIB_DECL(bool) USBFilterMatch(PCUSBFILTER pFilter, PCUSBFILTER pDevice)
806{
807 return USBFilterMatchRated(pFilter, pDevice) > 0;
808}
809
810
811#if 0 /*def IN_RING0*/ /** @todo convert to proper logging. */
812extern "C" int printf(const char *format, ...);
813# define dprintf(a) printf a
814#else
815# define dprintf(a) do {} while (0)
816#endif
817
818/**
819 * Match a filter against a device and rate the result.
820 *
821 * @returns -1 if no match, matching rate between 1 and 100 (inclusive) if matched.
822 *
823 * @param pFilter The filter to match with.
824 * @param pDevice The device data. This is a filter (type ignored) that
825 * contains 'exact' values for all present fields and 'ignore'
826 * values for the non-present fields.
827 *
828 * @remark Both the filter and the device are ASSUMED to be valid because
829 * we don't wish to waste any time in this function.
830 */
831USBLIB_DECL(int) USBFilterMatchRated(PCUSBFILTER pFilter, PCUSBFILTER pDevice)
832{
833 unsigned iRate = 0;
834dprintf(("USBFilterMatchRated: %p %p\n", pFilter, pDevice));
835
836 for (unsigned i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
837 {
838 switch (pFilter->aFields[i].enmMatch)
839 {
840 case USBFILTERMATCH_IGNORE:
841 iRate += 2;
842 break;
843
844 case USBFILTERMATCH_PRESENT:
845 if (pDevice->aFields[i].enmMatch == USBFILTERMATCH_IGNORE)
846 {
847dprintf(("filter match[%d]: !present\n", i));
848 return -1;
849 }
850 iRate += 2;
851 break;
852
853 case USBFILTERMATCH_NUM_EXACT:
854 if ( pDevice->aFields[i].enmMatch == USBFILTERMATCH_IGNORE
855 || pFilter->aFields[i].u16Value != pDevice->aFields[i].u16Value)
856 {
857if (pDevice->aFields[i].enmMatch == USBFILTERMATCH_IGNORE)
858 dprintf(("filter match[%d]: !num_exact device=ignore\n", i));
859else
860 dprintf(("filter match[%d]: !num_exact %#x (filter) != %#x (device)\n", i, pFilter->aFields[i].u16Value, pDevice->aFields[i].u16Value));
861 return -1;
862 }
863 iRate += 2;
864 break;
865
866 case USBFILTERMATCH_NUM_EXACT_NP:
867 if ( pDevice->aFields[i].enmMatch != USBFILTERMATCH_IGNORE
868 && pFilter->aFields[i].u16Value != pDevice->aFields[i].u16Value)
869 {
870dprintf(("filter match[%d]: !num_exact_np %#x (filter) != %#x (device)\n", i, pFilter->aFields[i].u16Value, pDevice->aFields[i].u16Value));
871 return -1;
872 }
873 iRate += 2;
874 break;
875
876 case USBFILTERMATCH_NUM_EXPRESSION:
877 if ( pDevice->aFields[i].enmMatch == USBFILTERMATCH_IGNORE
878 || !usbfilterMatchNumExpression(usbfilterGetString(pFilter, (USBFILTERIDX)i),
879 pDevice->aFields[i].u16Value))
880 {
881dprintf(("filter match[%d]: !num_expression\n", i));
882 return -1;
883 }
884 iRate += 1;
885 break;
886
887 case USBFILTERMATCH_NUM_EXPRESSION_NP:
888 if ( pDevice->aFields[i].enmMatch != USBFILTERMATCH_IGNORE
889 && !usbfilterMatchNumExpression(usbfilterGetString(pFilter, (USBFILTERIDX)i),
890 pDevice->aFields[i].u16Value))
891 {
892dprintf(("filter match[%d]: !num_expression_no\n", i));
893 return -1;
894 }
895 iRate += 1;
896 break;
897
898 case USBFILTERMATCH_STR_EXACT:
899 if ( pDevice->aFields[i].enmMatch == USBFILTERMATCH_IGNORE
900 || strcmp(usbfilterGetString(pFilter, (USBFILTERIDX)i),
901 usbfilterGetString(pDevice, (USBFILTERIDX)i)))
902 {
903dprintf(("filter match[%d]: !str_exact\n", i));
904 return -1;
905 }
906 iRate += 2;
907 break;
908
909 case USBFILTERMATCH_STR_EXACT_NP:
910 if ( pDevice->aFields[i].enmMatch != USBFILTERMATCH_IGNORE
911 && strcmp(usbfilterGetString(pFilter, (USBFILTERIDX)i),
912 usbfilterGetString(pDevice, (USBFILTERIDX)i)))
913 {
914dprintf(("filter match[%d]: !str_exact_np\n", i));
915 return -1;
916 }
917 iRate += 2;
918 break;
919
920 case USBFILTERMATCH_STR_PATTERN:
921 if ( pDevice->aFields[i].enmMatch == USBFILTERMATCH_IGNORE
922 || !usbfilterMatchStringPattern(usbfilterGetString(pFilter, (USBFILTERIDX)i),
923 usbfilterGetString(pDevice, (USBFILTERIDX)i)))
924 {
925dprintf(("filter match[%d]: !str_pattern\n", i));
926 return -1;
927 }
928 iRate += 1;
929 break;
930
931 case USBFILTERMATCH_STR_PATTERN_NP:
932 if ( pDevice->aFields[i].enmMatch != USBFILTERMATCH_IGNORE
933 && !usbfilterMatchStringPattern(usbfilterGetString(pFilter, (USBFILTERIDX)i),
934 usbfilterGetString(pDevice, (USBFILTERIDX)i)))
935 {
936dprintf(("filter match[%d]: !str_pattern_np\n", i));
937 return -1;
938 }
939 iRate += 1;
940 break;
941
942 default:
943 AssertMsgFailed(("#%d: %d\n", i, pFilter->aFields[i].enmMatch));
944 return -1;
945 }
946 }
947
948 /* iRate is the range 0..2*cFields - recalc to percent. */
949dprintf(("filter match: iRate=%d", iRate));
950 return iRate == 2 * RT_ELEMENTS(pFilter->aFields)
951 ? 100
952 : (iRate * 100) / (2 * RT_ELEMENTS(pFilter->aFields));
953}
954
955
956/**
957 * Match a filter against a USBDEVICE.
958 *
959 * @returns true if they match, false if not.
960 *
961 * @param pFilter The filter to match with.
962 * @param pDevice The device to match.
963 *
964 * @remark Both the filter and the device are ASSUMED to be valid because
965 * we don't wish to waste any time in this function.
966 */
967USBLIB_DECL(bool) USBFilterMatchDevice(PCUSBFILTER pFilter, PUSBDEVICE pDevice)
968{
969 for (unsigned i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
970 {
971 switch (pFilter->aFields[i].enmMatch)
972 {
973 case USBFILTERMATCH_IGNORE:
974 break;
975
976 case USBFILTERMATCH_PRESENT:
977 {
978 const char *psz;
979 switch (i)
980 {
981 case USBFILTERIDX_MANUFACTURER_STR: psz = pDevice->pszManufacturer; break;
982 case USBFILTERIDX_PRODUCT_STR: psz = pDevice->pszProduct; break;
983 case USBFILTERIDX_SERIAL_NUMBER_STR: psz = pDevice->pszSerialNumber; break;
984 default: psz = ""; break;
985 }
986 if (!psz)
987 return false;
988 break;
989 }
990
991 case USBFILTERMATCH_NUM_EXACT:
992 case USBFILTERMATCH_NUM_EXACT_NP:
993 case USBFILTERMATCH_NUM_EXPRESSION:
994 case USBFILTERMATCH_NUM_EXPRESSION_NP:
995 {
996 uint16_t u16Value;
997 switch (i)
998 {
999 case USBFILTERIDX_VENDOR_ID: u16Value = pDevice->idVendor; break;
1000 case USBFILTERIDX_PRODUCT_ID: u16Value = pDevice->idProduct; break;
1001 case USBFILTERIDX_DEVICE: u16Value = pDevice->bcdDevice; break;
1002 case USBFILTERIDX_DEVICE_CLASS: u16Value = pDevice->bDeviceClass; break;
1003 case USBFILTERIDX_DEVICE_SUB_CLASS: u16Value = pDevice->bDeviceSubClass; break;
1004 case USBFILTERIDX_DEVICE_PROTOCOL: u16Value = pDevice->bDeviceProtocol; break;
1005 case USBFILTERIDX_BUS: u16Value = pDevice->bBus; break;
1006 case USBFILTERIDX_PORT: u16Value = pDevice->bPort; break;
1007 default: u16Value = UINT16_MAX; break;
1008
1009 }
1010 switch (pFilter->aFields[i].enmMatch)
1011 {
1012 case USBFILTERMATCH_NUM_EXACT:
1013 case USBFILTERMATCH_NUM_EXACT_NP:
1014 if (pFilter->aFields[i].u16Value != u16Value)
1015 return false;
1016 break;
1017 case USBFILTERMATCH_NUM_EXPRESSION:
1018 case USBFILTERMATCH_NUM_EXPRESSION_NP:
1019 if (!usbfilterMatchNumExpression(usbfilterGetString(pFilter, (USBFILTERIDX)i), u16Value))
1020 return false;
1021 break;
1022 }
1023 break;
1024 }
1025
1026 case USBFILTERMATCH_STR_EXACT:
1027 case USBFILTERMATCH_STR_EXACT_NP:
1028 case USBFILTERMATCH_STR_PATTERN:
1029 case USBFILTERMATCH_STR_PATTERN_NP:
1030 {
1031 const char *psz;
1032 switch (i)
1033 {
1034 case USBFILTERIDX_MANUFACTURER_STR: psz = pDevice->pszManufacturer; break;
1035 case USBFILTERIDX_PRODUCT_STR: psz = pDevice->pszProduct; break;
1036 case USBFILTERIDX_SERIAL_NUMBER_STR: psz = pDevice->pszSerialNumber; break;
1037 default: psz = NULL; break;
1038 }
1039 switch (pFilter->aFields[i].enmMatch)
1040 {
1041 case USBFILTERMATCH_STR_EXACT:
1042 if ( !psz
1043 || strcmp(usbfilterGetString(pFilter, (USBFILTERIDX)i), psz))
1044 return false;
1045 break;
1046
1047 case USBFILTERMATCH_STR_EXACT_NP:
1048 if ( psz
1049 && strcmp(usbfilterGetString(pFilter, (USBFILTERIDX)i), psz))
1050 return false;
1051 break;
1052
1053 case USBFILTERMATCH_STR_PATTERN:
1054 if ( !psz
1055 || !usbfilterMatchStringPattern(usbfilterGetString(pFilter, (USBFILTERIDX)i), psz))
1056 return false;
1057 break;
1058
1059 case USBFILTERMATCH_STR_PATTERN_NP:
1060 if ( psz
1061 && !usbfilterMatchStringPattern(usbfilterGetString(pFilter, (USBFILTERIDX)i), psz))
1062 return false;
1063 break;
1064 }
1065 break;
1066 }
1067
1068 default:
1069 AssertMsgFailed(("#%d: %d\n", i, pFilter->aFields[i].enmMatch));
1070 return false;
1071 }
1072 }
1073
1074 return true;
1075}
1076
1077
1078/**
1079 * Checks if the two filters are identical.
1080 *
1081 * @returns true if the are identical, false if they aren't.
1082 * @param pFilter The first filter.
1083 * @param pFilter2 The second filter.
1084 */
1085USBLIB_DECL(bool) USBFilterIsIdentical(PCUSBFILTER pFilter, PCUSBFILTER pFilter2)
1086{
1087 /* Lazy works here because we're darn strict with zero padding and such elsewhere. */
1088 return memcmp(pFilter, pFilter2, sizeof(*pFilter)) == 0;
1089}
1090
1091
1092
1093/**
1094 * Sets the filter type.
1095 *
1096 * @returns VBox status code.
1097 * @retval VERR_INVALID_PARAMETER if the filter type is invalid.
1098 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1099 *
1100 * @param pFilter The filter.
1101 * @param enmType The new filter type.
1102 */
1103USBLIB_DECL(int) USBFilterSetFilterType(PUSBFILTER pFilter, USBFILTERTYPE enmType)
1104{
1105 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, VERR_INVALID_MAGIC);
1106 AssertReturn(enmType > USBFILTERTYPE_INVALID && enmType < USBFILTERTYPE_END, VERR_INVALID_PARAMETER);
1107
1108 pFilter->enmType = enmType;
1109 return VINF_SUCCESS;
1110}
1111
1112
1113/**
1114 * Replaces the string value of a field.
1115 *
1116 * This will remove any existing string value current held by the field from the
1117 * string table and then attempt to add the new value. This function can be used
1118 * to delete any assigned string before changing the type to numeric by passing
1119 * in an empty string. This works because the first byte in the string table is
1120 * reserved for the empty (NULL) string.
1121 *
1122 * @returns VBox status code.
1123 * @retval VINF_SUCCESS on success.
1124 * @retval VERR_BUFFER_OVERFLOW if the string table is full.
1125 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid.
1126 * @retval VERR_INVALID_POINTER if pszString isn't valid.
1127 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1128 *
1129 * @param pFilter The filter.
1130 * @param enmFieldIdx The field index.
1131 * @param pszString The string to add.
1132 * @param fPurge Purge invalid UTF-8 encoding and control characters
1133 * before setting it.
1134 */
1135static int usbfilterSetString(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, const char *pszString, bool fPurge)
1136{
1137 /*
1138 * Validate input.
1139 */
1140 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, VERR_INVALID_MAGIC);
1141 AssertReturn((unsigned)enmFieldIdx < (unsigned)USBFILTERIDX_END, VERR_INVALID_PARAMETER);
1142 AssertPtrReturn(pszString, VERR_INVALID_POINTER);
1143
1144 Assert(pFilter->offCurEnd < sizeof(pFilter->achStrTab));
1145 Assert(pFilter->achStrTab[pFilter->offCurEnd] == '\0');
1146
1147 /*
1148 * Remove old string value if any.
1149 */
1150 if ( USBFilterIsMethodUsingStringValue((USBFILTERMATCH)pFilter->aFields[enmFieldIdx].enmMatch)
1151 && pFilter->aFields[enmFieldIdx].u16Value != 0)
1152 {
1153 uint32_t off = pFilter->aFields[enmFieldIdx].u16Value;
1154 pFilter->aFields[enmFieldIdx].u16Value = 0; /* Assign it to the NULL string. */
1155
1156 unsigned cchShift = (unsigned)strlen(&pFilter->achStrTab[off]) + 1;
1157 ssize_t cchToMove = (pFilter->offCurEnd + 1) - (off + cchShift);
1158 Assert(cchToMove >= 0);
1159 if (cchToMove > 0)
1160 {
1161 /* We're not last - must shift the strings. */
1162 memmove(&pFilter->achStrTab[off], &pFilter->achStrTab[off + cchShift], cchToMove);
1163 for (unsigned i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
1164 if ( pFilter->aFields[i].u16Value >= off
1165 && USBFilterIsMethodUsingStringValue((USBFILTERMATCH)pFilter->aFields[i].enmMatch))
1166 pFilter->aFields[i].u16Value -= cchShift;
1167 }
1168 pFilter->offCurEnd -= cchShift;
1169 Assert(pFilter->offCurEnd < sizeof(pFilter->achStrTab));
1170 Assert(pFilter->offCurEnd + cchShift <= sizeof(pFilter->achStrTab));
1171
1172 /* zero the unused string table (to allow lazyness/strictness elsewhere). */
1173 memset(&pFilter->achStrTab[pFilter->offCurEnd], '\0', cchShift);
1174 }
1175
1176 /*
1177 * Make a special case for the empty string.
1178 * (This also makes the delete logical above work correctly for the last string.)
1179 */
1180 if (!*pszString)
1181 pFilter->aFields[enmFieldIdx].u16Value = 0;
1182 else
1183 {
1184 size_t cch = strlen(pszString);
1185 if (pFilter->offCurEnd + cch + 2 > sizeof(pFilter->achStrTab))
1186 return VERR_BUFFER_OVERFLOW;
1187
1188 pFilter->aFields[enmFieldIdx].u16Value = pFilter->offCurEnd + 1;
1189 memcpy(&pFilter->achStrTab[pFilter->offCurEnd + 1], pszString, cch + 1);
1190 if (fPurge)
1191 cch = USBLibPurgeEncoding(&pFilter->achStrTab[pFilter->offCurEnd + 1]);
1192 pFilter->offCurEnd += (uint32_t)cch + 1;
1193 }
1194
1195 return VINF_SUCCESS;
1196}
1197
1198/**
1199 * Wrapper around usbfilterSetString() that deletes any string value
1200 * currently assigned to a field.
1201 *
1202 * Upon successful return the field contains a null string, nothing or a number.
1203 *
1204 * This function will validate the field index if there isn't any string
1205 * value to delete, thus preventing any extra validating of the index.
1206 *
1207 * @returns VBox status code. See usbfilterSetString.
1208 * @param pFilter The filter.
1209 * @param enmFieldIdx The index of the field which string value should be deleted.
1210 */
1211static int usbfilterDeleteAnyStringValue(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1212{
1213 int rc = VINF_SUCCESS;
1214 if ( USBFilterIsMethodUsingStringValue((USBFILTERMATCH)pFilter->aFields[enmFieldIdx].enmMatch)
1215 && pFilter->aFields[enmFieldIdx].u16Value != 0)
1216 rc = usbfilterSetString(pFilter, enmFieldIdx, "", false /*fPurge*/);
1217 else if ((unsigned)enmFieldIdx >= (unsigned)USBFILTERIDX_END)
1218 rc = VERR_INVALID_PARAMETER;
1219 return rc;
1220}
1221
1222
1223/**
1224 * Sets a field to always match (ignore whatever is thrown at it).
1225 *
1226 * @returns VBox status code.
1227 * @retval VINF_SUCCESS on success.
1228 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid.
1229 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1230 *
1231 * @param pFilter The filter.
1232 * @param enmFieldIdx The field index. This must be a string field.
1233 */
1234USBLIB_DECL(int) USBFilterSetIgnore(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1235{
1236 int rc = usbfilterDeleteAnyStringValue(pFilter, enmFieldIdx);
1237 if (RT_SUCCESS(rc))
1238 {
1239 pFilter->aFields[enmFieldIdx].enmMatch = USBFILTERMATCH_IGNORE;
1240 pFilter->aFields[enmFieldIdx].u16Value = 0;
1241 }
1242 return rc;
1243}
1244
1245
1246/**
1247 * Sets a field to match on device field present only.
1248 *
1249 * @returns VBox status code.
1250 * @retval VINF_SUCCESS on success.
1251 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid.
1252 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1253 *
1254 * @param pFilter The filter.
1255 * @param enmFieldIdx The field index. This must be a string field.
1256 */
1257USBLIB_DECL(int) USBFilterSetPresentOnly(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1258{
1259 int rc = usbfilterDeleteAnyStringValue(pFilter, enmFieldIdx);
1260 if (RT_SUCCESS(rc))
1261 {
1262 pFilter->aFields[enmFieldIdx].enmMatch = USBFILTERMATCH_PRESENT;
1263 pFilter->aFields[enmFieldIdx].u16Value = 0;
1264 }
1265 return rc;
1266}
1267
1268
1269/**
1270 * Sets a field to exactly match a number.
1271 *
1272 * @returns VBox status code.
1273 * @retval VINF_SUCCESS on success.
1274 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid.
1275 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1276 *
1277 * @param pFilter The filter.
1278 * @param enmFieldIdx The field index. This must be a string field.
1279 * @param u16Value The string pattern.
1280 * @param fMustBePresent If set, a non-present field on the device will result in a mismatch.
1281 * If clear, a non-present field on the device will match.
1282 */
1283USBLIB_DECL(int) USBFilterSetNumExact(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, uint16_t u16Value, bool fMustBePresent)
1284{
1285 int rc = USBFilterIsNumericField(enmFieldIdx) ? VINF_SUCCESS : VERR_INVALID_PARAMETER;
1286 if (RT_SUCCESS(rc))
1287 {
1288 rc = usbfilterDeleteAnyStringValue(pFilter, enmFieldIdx);
1289 if (RT_SUCCESS(rc))
1290 {
1291 pFilter->aFields[enmFieldIdx].u16Value = u16Value;
1292 pFilter->aFields[enmFieldIdx].enmMatch = fMustBePresent ? USBFILTERMATCH_NUM_EXACT : USBFILTERMATCH_NUM_EXACT_NP;
1293 }
1294 }
1295
1296 return rc;
1297}
1298
1299
1300/**
1301 * Sets a field to match a numeric expression.
1302 *
1303 * @returns VBox status code.
1304 * @retval VINF_SUCCESS on success.
1305 * @retval VERR_BUFFER_OVERFLOW if the string table is full.
1306 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx or the numeric expression aren't valid.
1307 * @retval VERR_INVALID_POINTER if pszExpression isn't a valid pointer.
1308 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1309 *
1310 * @param pFilter The filter.
1311 * @param enmFieldIdx The field index. This must be a string field.
1312 * @param pszExpression The numeric expression.
1313 * @param fMustBePresent If set, a non-present field on the device will result in a mismatch.
1314 * If clear, a non-present field on the device will match.
1315 */
1316USBLIB_DECL(int) USBFilterSetNumExpression(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, const char *pszExpression, bool fMustBePresent)
1317{
1318 int rc = USBFilterIsNumericField(enmFieldIdx) ? VINF_SUCCESS : VERR_INVALID_PARAMETER;
1319 if (RT_SUCCESS(rc))
1320 {
1321 /* Strip leading spaces and empty sub expressions (||). */
1322 while (*pszExpression && (RT_C_IS_BLANK(*pszExpression) || *pszExpression == '|'))
1323 pszExpression++;
1324
1325 rc = usbfilterValidateNumExpression(pszExpression);
1326 if (RT_SUCCESS(rc))
1327 {
1328 /* We could optimize the expression further (stripping spaces, convert numbers),
1329 but it's more work than what it's worth and it could upset some users. */
1330 rc = usbfilterSetString(pFilter, enmFieldIdx, pszExpression, false /*fPurge*/);
1331 if (RT_SUCCESS(rc))
1332 pFilter->aFields[enmFieldIdx].enmMatch = fMustBePresent ? USBFILTERMATCH_NUM_EXPRESSION : USBFILTERMATCH_NUM_EXPRESSION_NP;
1333 else if (rc == VERR_NO_DIGITS)
1334 rc = VERR_INVALID_PARAMETER;
1335 }
1336 }
1337 return rc;
1338}
1339
1340
1341/**
1342 * Sets a field to exactly match a string.
1343 *
1344 * @returns VBox status code.
1345 * @retval VINF_SUCCESS on success.
1346 * @retval VERR_BUFFER_OVERFLOW if the string table is full.
1347 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid.
1348 * @retval VERR_INVALID_POINTER if pszPattern isn't a valid pointer.
1349 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1350 *
1351 * @param pFilter The filter.
1352 * @param enmFieldIdx The field index. This must be a string field.
1353 * @param pszValue The string value.
1354 * @param fMustBePresent If set, a non-present field on the device will result in a mismatch.
1355 * If clear, a non-present field on the device will match.
1356 * @param fPurge Purge invalid UTF-8 encoding and control
1357 * characters before setting it.
1358 */
1359USBLIB_DECL(int) USBFilterSetStringExact(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, const char *pszValue,
1360 bool fMustBePresent, bool fPurge)
1361{
1362 int rc = USBFilterIsStringField(enmFieldIdx) ? VINF_SUCCESS : VERR_INVALID_PARAMETER;
1363 if (RT_SUCCESS(rc))
1364 {
1365 rc = usbfilterSetString(pFilter, enmFieldIdx, pszValue, fPurge);
1366 if (RT_SUCCESS(rc))
1367 pFilter->aFields[enmFieldIdx].enmMatch = fMustBePresent ? USBFILTERMATCH_STR_EXACT : USBFILTERMATCH_STR_EXACT_NP;
1368 }
1369 return rc;
1370}
1371
1372
1373/**
1374 * Sets a field to match a string pattern.
1375 *
1376 * @returns VBox status code.
1377 * @retval VINF_SUCCESS on success.
1378 * @retval VERR_BUFFER_OVERFLOW if the string table is full.
1379 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx or pattern aren't valid.
1380 * @retval VERR_INVALID_POINTER if pszPattern isn't a valid pointer.
1381 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1382 *
1383 * @param pFilter The filter.
1384 * @param enmFieldIdx The field index. This must be a string field.
1385 * @param pszPattern The string pattern.
1386 * @param fMustBePresent If set, a non-present field on the device will result in a mismatch.
1387 * If clear, a non-present field on the device will match.
1388 */
1389USBLIB_DECL(int) USBFilterSetStringPattern(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, const char *pszPattern, bool fMustBePresent)
1390{
1391 int rc = USBFilterIsStringField(enmFieldIdx) ? VINF_SUCCESS : VERR_INVALID_PARAMETER;
1392 if (RT_SUCCESS(rc))
1393 {
1394 rc = usbfilterValidateStringPattern(pszPattern);
1395 if (RT_SUCCESS(rc))
1396 {
1397 rc = usbfilterSetString(pFilter, enmFieldIdx, pszPattern, false /*fPurge*/);
1398 if (RT_SUCCESS(rc))
1399 pFilter->aFields[enmFieldIdx].enmMatch = fMustBePresent ? USBFILTERMATCH_STR_PATTERN : USBFILTERMATCH_STR_PATTERN_NP;
1400 }
1401 }
1402 return rc;
1403}
1404
1405
1406/**
1407 * Sets the must-be-present part of a field.
1408 *
1409 * This only works on field which already has matching criteria. This means
1410 * that field marked 'ignore' will not be processed and will result in a
1411 * warning status code.
1412 *
1413 * @returns VBox status code.
1414 * @retval VINF_SUCCESS on success.
1415 * @retval VWRN_INVALID_PARAMETER if the field is marked 'ignore'. No assertions.
1416 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx or pattern aren't valid.
1417 * @retval VERR_INVALID_POINTER if pszPattern isn't a valid pointer.
1418 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1419 *
1420 * @param pFilter The filter.
1421 * @param enmFieldIdx The field index.
1422 * @param fMustBePresent If set, a non-present field on the device will result in a mismatch.
1423 * If clear, a non-present field on the device will match.
1424 */
1425USBLIB_DECL(int) USBFilterSetMustBePresent(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, bool fMustBePresent)
1426{
1427 AssertPtrReturn(pFilter, VERR_INVALID_POINTER);
1428 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, VERR_INVALID_MAGIC);
1429 AssertReturn((unsigned)enmFieldIdx < (unsigned)USBFILTERIDX_END, VERR_INVALID_PARAMETER);
1430
1431 USBFILTERMATCH enmMatch = (USBFILTERMATCH)pFilter->aFields[enmFieldIdx].enmMatch;
1432 if (fMustBePresent)
1433 {
1434 switch (enmMatch)
1435 {
1436 case USBFILTERMATCH_IGNORE:
1437 return VWRN_INVALID_PARAMETER;
1438
1439 case USBFILTERMATCH_PRESENT:
1440 case USBFILTERMATCH_NUM_EXACT:
1441 case USBFILTERMATCH_NUM_EXPRESSION:
1442 case USBFILTERMATCH_STR_EXACT:
1443 case USBFILTERMATCH_STR_PATTERN:
1444 break;
1445
1446 case USBFILTERMATCH_NUM_EXACT_NP:
1447 enmMatch = USBFILTERMATCH_NUM_EXACT;
1448 break;
1449 case USBFILTERMATCH_NUM_EXPRESSION_NP:
1450 enmMatch = USBFILTERMATCH_NUM_EXPRESSION;
1451 break;
1452 case USBFILTERMATCH_STR_EXACT_NP:
1453 enmMatch = USBFILTERMATCH_STR_EXACT;
1454 break;
1455 case USBFILTERMATCH_STR_PATTERN_NP:
1456 enmMatch = USBFILTERMATCH_STR_PATTERN;
1457 break;
1458 default:
1459 AssertMsgFailedReturn(("%p: enmFieldIdx=%d enmMatch=%d\n", pFilter, enmFieldIdx, enmMatch), VERR_INVALID_MAGIC);
1460 }
1461 }
1462 else
1463 {
1464 switch (enmMatch)
1465 {
1466 case USBFILTERMATCH_IGNORE:
1467 return VWRN_INVALID_PARAMETER;
1468
1469 case USBFILTERMATCH_NUM_EXACT_NP:
1470 case USBFILTERMATCH_STR_PATTERN_NP:
1471 case USBFILTERMATCH_STR_EXACT_NP:
1472 case USBFILTERMATCH_NUM_EXPRESSION_NP:
1473 break;
1474
1475 case USBFILTERMATCH_PRESENT:
1476 enmMatch = USBFILTERMATCH_IGNORE;
1477 break;
1478 case USBFILTERMATCH_NUM_EXACT:
1479 enmMatch = USBFILTERMATCH_NUM_EXACT_NP;
1480 break;
1481 case USBFILTERMATCH_NUM_EXPRESSION:
1482 enmMatch = USBFILTERMATCH_NUM_EXPRESSION_NP;
1483 break;
1484 case USBFILTERMATCH_STR_EXACT:
1485 enmMatch = USBFILTERMATCH_STR_EXACT_NP;
1486 break;
1487 case USBFILTERMATCH_STR_PATTERN:
1488 enmMatch = USBFILTERMATCH_STR_PATTERN_NP;
1489 break;
1490
1491 default:
1492 AssertMsgFailedReturn(("%p: enmFieldIdx=%d enmMatch=%d\n", pFilter, enmFieldIdx, enmMatch), VERR_INVALID_MAGIC);
1493 }
1494 }
1495
1496 pFilter->aFields[enmFieldIdx].enmMatch = enmMatch;
1497 return VINF_SUCCESS;
1498}
1499
1500
1501/**
1502 * Gets the filter type.
1503 *
1504 * @returns The filter type.
1505 * USBFILTERTYPE_INVALID if the filter is invalid.
1506 * @param pFilter The filter.
1507 */
1508USBLIB_DECL(USBFILTERTYPE) USBFilterGetFilterType(PCUSBFILTER pFilter)
1509{
1510 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, USBFILTERTYPE_INVALID);
1511 return pFilter->enmType;
1512}
1513
1514
1515/**
1516 * Gets the matching method for a field.
1517 *
1518 * @returns The matching method on success, UBFILTERMATCH_INVALID on invalid field index.
1519 * @param pFilter The filter.
1520 * @param enmFieldIdx The field index.
1521 */
1522USBLIB_DECL(USBFILTERMATCH) USBFilterGetMatchingMethod(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1523{
1524 if ( pFilter->u32Magic == USBFILTER_MAGIC
1525 && (unsigned)enmFieldIdx < (unsigned)USBFILTERIDX_END)
1526 return (USBFILTERMATCH)pFilter->aFields[enmFieldIdx].enmMatch;
1527 return USBFILTERMATCH_INVALID;
1528}
1529
1530
1531/**
1532 * Gets the numeric value of a field.
1533 *
1534 * The field must contain a number, we're not doing any conversions for you.
1535 *
1536 * @returns VBox status code.
1537 * @retval VINF_SUCCESS on success.
1538 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid or if the field doesn't contain a number.
1539 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1540 *
1541 * @param pFilter The filter.
1542 * @param enmFieldIdx The field index.
1543 * @param pu16Value Where to store the value.
1544 */
1545USBLIB_DECL(int) USBFilterQueryNum(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, uint16_t *pu16Value)
1546{
1547 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, VERR_INVALID_MAGIC);
1548 int iValue = usbfilterGetNum(pFilter, enmFieldIdx);
1549 if (iValue == -1)
1550 return VERR_INVALID_PARAMETER;
1551 *pu16Value = (uint16_t)iValue;
1552 return VINF_SUCCESS;
1553}
1554
1555
1556/**
1557 * Gets the numeric value of a field.
1558 *
1559 * The field must contain a number, we're not doing any conversions for you.
1560 *
1561 * @returns The field value on success, -1 on failure (invalid input / not numeric).
1562 *
1563 * @param pFilter The filter.
1564 * @param enmFieldIdx The field index.
1565 */
1566USBLIB_DECL(int) USBFilterGetNum(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1567{
1568 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, -1);
1569 return usbfilterGetNum(pFilter, enmFieldIdx);
1570}
1571
1572
1573/**
1574 * Gets the string value of a field.
1575 *
1576 * The field must contain a string, we're not doing any conversions for you.
1577 *
1578 * @returns VBox status code.
1579 * @retval VINF_SUCCESS on success.
1580 * @retval VERR_BUFFER_OVERFLOW if the buffer isn't sufficient to hold the string. The buffer
1581 * will be filled with as much of the string that'll fit.
1582 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid or if the field doesn't contain a string.
1583 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1584 *
1585 * @param pFilter The filter.
1586 * @param enmFieldIdx The field index.
1587 * @param pszBuf Where to store the string.
1588 * @param cchBuf The size of the buffer.
1589 */
1590USBLIB_DECL(int) USBFilterQueryString(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, char *pszBuf, size_t cchBuf)
1591{
1592 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, VERR_INVALID_MAGIC);
1593
1594 const char *psz = usbfilterGetString(pFilter, enmFieldIdx);
1595 if (RT_UNLIKELY(!psz))
1596 return VERR_INVALID_PARAMETER;
1597
1598 int rc = VINF_SUCCESS;
1599 size_t cch = strlen(psz);
1600 if (cch < cchBuf)
1601 memcpy(pszBuf, psz, cch + 1);
1602 else
1603 {
1604 rc = VERR_BUFFER_OVERFLOW;
1605 if (cchBuf)
1606 {
1607 memcpy(pszBuf, psz, cchBuf - 1);
1608 pszBuf[cchBuf - 1] = '\0';
1609 }
1610 }
1611
1612 return rc;
1613}
1614
1615
1616/**
1617 * Gets the string table entry for a field.
1618 *
1619 * @returns Pointer to the string. (readonly!)
1620 *
1621 * @param pFilter The filter.
1622 * @param enmFieldIdx The field index.
1623 */
1624USBLIB_DECL(const char *) USBFilterGetString(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1625{
1626 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, NULL);
1627
1628 const char *psz = usbfilterGetString(pFilter, enmFieldIdx);
1629 if (RT_UNLIKELY(!psz))
1630 return NULL;
1631 return psz;
1632}
1633
1634
1635/**
1636 * Gets the string length of a field containing a string.
1637 *
1638 * @returns String length on success, -1 on failure (not a string, bad filter).
1639 * @param pFilter The filter.
1640 * @param enmFieldIdx The field index.
1641 */
1642USBLIB_DECL(ssize_t) USBFilterGetStringLen(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1643{
1644 if (RT_LIKELY(pFilter->u32Magic == USBFILTER_MAGIC))
1645 {
1646 const char *psz = usbfilterGetString(pFilter, enmFieldIdx);
1647 if (RT_LIKELY(psz))
1648 return strlen(psz);
1649 }
1650 return -1;
1651}
1652
1653
1654/**
1655 * Check if any of the fields are set to something substatial.
1656 *
1657 * Consider the fileter a wildcard if this returns false.
1658 *
1659 * @returns true / false.
1660 * @param pFilter The filter.
1661 */
1662USBLIB_DECL(bool) USBFilterHasAnySubstatialCriteria(PCUSBFILTER pFilter)
1663{
1664 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, false);
1665
1666 for (unsigned i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
1667 {
1668 switch (pFilter->aFields[i].enmMatch)
1669 {
1670 case USBFILTERMATCH_IGNORE:
1671 case USBFILTERMATCH_PRESENT:
1672 break;
1673
1674 case USBFILTERMATCH_NUM_EXACT:
1675 case USBFILTERMATCH_NUM_EXACT_NP:
1676 case USBFILTERMATCH_STR_EXACT:
1677 case USBFILTERMATCH_STR_EXACT_NP:
1678 return true;
1679
1680 case USBFILTERMATCH_NUM_EXPRESSION:
1681 case USBFILTERMATCH_NUM_EXPRESSION_NP:
1682 {
1683 const char *psz = usbfilterGetString(pFilter, (USBFILTERIDX)i);
1684 if (psz)
1685 {
1686 while (*psz && (*psz == '|' || RT_C_IS_BLANK(*psz)))
1687 psz++;
1688 if (*psz)
1689 return true;
1690 }
1691 break;
1692 }
1693
1694 case USBFILTERMATCH_STR_PATTERN:
1695 case USBFILTERMATCH_STR_PATTERN_NP:
1696 {
1697 const char *psz = usbfilterGetString(pFilter, (USBFILTERIDX)i);
1698 if (psz)
1699 {
1700 while (*psz && (*psz == '*' || *psz == '?'))
1701 psz++;
1702 if (*psz)
1703 return true;
1704 }
1705 break;
1706 }
1707 }
1708 }
1709
1710 return false;
1711}
1712
1713
1714
1715/**
1716 * Checks whether the specified field is a numeric field or not.
1717 *
1718 * @returns true / false.
1719 * @param enmFieldIdx The field index.
1720 */
1721USBLIB_DECL(bool) USBFilterIsNumericField(USBFILTERIDX enmFieldIdx)
1722{
1723 switch (enmFieldIdx)
1724 {
1725 case USBFILTERIDX_VENDOR_ID:
1726 case USBFILTERIDX_PRODUCT_ID:
1727 case USBFILTERIDX_DEVICE:
1728 case USBFILTERIDX_DEVICE_CLASS:
1729 case USBFILTERIDX_DEVICE_SUB_CLASS:
1730 case USBFILTERIDX_DEVICE_PROTOCOL:
1731 case USBFILTERIDX_BUS:
1732 case USBFILTERIDX_PORT:
1733 return true;
1734
1735 default:
1736 AssertMsgFailed(("%d\n", enmFieldIdx));
1737 RT_FALL_THRU();
1738 case USBFILTERIDX_MANUFACTURER_STR:
1739 case USBFILTERIDX_PRODUCT_STR:
1740 case USBFILTERIDX_SERIAL_NUMBER_STR:
1741 return false;
1742 }
1743}
1744
1745
1746/**
1747 * Checks whether the specified field is a string field or not.
1748 *
1749 * @returns true / false.
1750 * @param enmFieldIdx The field index.
1751 */
1752USBLIB_DECL(bool) USBFilterIsStringField(USBFILTERIDX enmFieldIdx)
1753{
1754 switch (enmFieldIdx)
1755 {
1756 default:
1757 AssertMsgFailed(("%d\n", enmFieldIdx));
1758 RT_FALL_THRU();
1759 case USBFILTERIDX_VENDOR_ID:
1760 case USBFILTERIDX_PRODUCT_ID:
1761 case USBFILTERIDX_DEVICE:
1762 case USBFILTERIDX_DEVICE_CLASS:
1763 case USBFILTERIDX_DEVICE_SUB_CLASS:
1764 case USBFILTERIDX_DEVICE_PROTOCOL:
1765 case USBFILTERIDX_BUS:
1766 case USBFILTERIDX_PORT:
1767 return false;
1768
1769 case USBFILTERIDX_MANUFACTURER_STR:
1770 case USBFILTERIDX_PRODUCT_STR:
1771 case USBFILTERIDX_SERIAL_NUMBER_STR:
1772 return true;
1773 }
1774}
1775
1776
1777/**
1778 * Checks whether the specified matching method uses a numeric value or not.
1779 *
1780 * @returns true / false.
1781 * @param enmMatchingMethod The matching method.
1782 */
1783USBLIB_DECL(bool) USBFilterIsMethodUsingNumericValue(USBFILTERMATCH enmMatchingMethod)
1784{
1785 switch (enmMatchingMethod)
1786 {
1787 default:
1788 AssertMsgFailed(("%d\n", enmMatchingMethod));
1789 RT_FALL_THRU();
1790 case USBFILTERMATCH_IGNORE:
1791 case USBFILTERMATCH_PRESENT:
1792 case USBFILTERMATCH_NUM_EXPRESSION:
1793 case USBFILTERMATCH_NUM_EXPRESSION_NP:
1794 case USBFILTERMATCH_STR_EXACT:
1795 case USBFILTERMATCH_STR_EXACT_NP:
1796 case USBFILTERMATCH_STR_PATTERN:
1797 case USBFILTERMATCH_STR_PATTERN_NP:
1798 return false;
1799
1800 case USBFILTERMATCH_NUM_EXACT:
1801 case USBFILTERMATCH_NUM_EXACT_NP:
1802 return true;
1803 }
1804}
1805
1806
1807/**
1808 * Checks whether the specified matching method uses a string value or not.
1809 *
1810 * @returns true / false.
1811 * @param enmMatchingMethod The matching method.
1812 */
1813USBLIB_DECL(bool) USBFilterIsMethodUsingStringValue(USBFILTERMATCH enmMatchingMethod)
1814{
1815 switch (enmMatchingMethod)
1816 {
1817 default:
1818 AssertMsgFailed(("%d\n", enmMatchingMethod));
1819 RT_FALL_THRU();
1820 case USBFILTERMATCH_IGNORE:
1821 case USBFILTERMATCH_PRESENT:
1822 case USBFILTERMATCH_NUM_EXACT:
1823 case USBFILTERMATCH_NUM_EXACT_NP:
1824 return false;
1825
1826 case USBFILTERMATCH_NUM_EXPRESSION:
1827 case USBFILTERMATCH_NUM_EXPRESSION_NP:
1828 case USBFILTERMATCH_STR_EXACT:
1829 case USBFILTERMATCH_STR_EXACT_NP:
1830 case USBFILTERMATCH_STR_PATTERN:
1831 case USBFILTERMATCH_STR_PATTERN_NP:
1832 return true;
1833 }
1834}
1835
1836
1837/**
1838 * Checks if a matching method is for numeric fields or not.
1839 *
1840 * @returns true / false.
1841 * @param enmMatchingMethod The matching method.
1842 */
1843USBLIB_DECL(bool) USBFilterIsMethodNumeric(USBFILTERMATCH enmMatchingMethod)
1844{
1845 return enmMatchingMethod >= USBFILTERMATCH_NUM_FIRST
1846 && enmMatchingMethod <= USBFILTERMATCH_NUM_LAST;
1847}
1848
1849/**
1850 * Checks if a matching method is for string fields or not.
1851 *
1852 * @returns true / false.
1853 * @param enmMatchingMethod The matching method.
1854 */
1855USBLIB_DECL(bool) USBFilterIsMethodString(USBFILTERMATCH enmMatchingMethod)
1856{
1857 return enmMatchingMethod >= USBFILTERMATCH_STR_FIRST
1858 && enmMatchingMethod <= USBFILTERMATCH_STR_LAST;
1859}
1860
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette