VirtualBox

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

Last change on this file was 107634, checked in by vboxsync, 4 months ago

src/VBox/HostDrivers/VBoxUSB/USBFilter.cpp: Fixed warnings found by Parfait (null pointer dereference). Needs backport. jiraref:VBP-1424

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 62.9 KB
Line 
1/* $Id: USBFilter.cpp 107634 2025-01-10 11:15:19Z vboxsync $ */
2/** @file
3 * VirtualBox USB filter abstraction.
4 */
5
6/*
7 * Copyright (C) 2007-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.215389.xyz.
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 RT_FALL_THROUGH();
548 case USBFILTERMATCH_IGNORE:
549 case USBFILTERMATCH_PRESENT:
550 case USBFILTERMATCH_NUM_EXACT:
551 case USBFILTERMATCH_NUM_EXACT_NP:
552 break;
553 }
554 }
555 return NULL;
556}
557
558
559/**
560 * Gets a number value of a field.
561 *
562 * The field must contain a numeric value.
563 *
564 * @returns The field value on success, -1 on failure (invalid input / not numeric).
565 * @param pFilter The filter.
566 * @param enmFieldIdx The field index.
567 */
568DECLINLINE(int) usbfilterGetNum(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
569{
570 if ((unsigned)enmFieldIdx < (unsigned)USBFILTERIDX_END)
571 {
572 switch (pFilter->aFields[enmFieldIdx].enmMatch)
573 {
574 case USBFILTERMATCH_NUM_EXACT:
575 case USBFILTERMATCH_NUM_EXACT_NP:
576 return pFilter->aFields[enmFieldIdx].u16Value;
577
578 default:
579 AssertMsgFailed(("%d\n", pFilter->aFields[enmFieldIdx].enmMatch));
580 RT_FALL_THROUGH();
581 case USBFILTERMATCH_IGNORE:
582 case USBFILTERMATCH_PRESENT:
583 case USBFILTERMATCH_NUM_EXPRESSION:
584 case USBFILTERMATCH_NUM_EXPRESSION_NP:
585 case USBFILTERMATCH_STR_EXACT:
586 case USBFILTERMATCH_STR_EXACT_NP:
587 case USBFILTERMATCH_STR_PATTERN:
588 case USBFILTERMATCH_STR_PATTERN_NP:
589 break;
590 }
591 }
592 return -1;
593}
594
595
596/**
597 * Performs simple pattern matching.
598 *
599 * @returns \c true on match and \c false on mismatch.
600 * @param pszExpr The numeric expression. NULL is not okay.
601 * @param u16Value The value to match.
602 */
603static bool usbfilterMatchNumExpression(const char *pszExpr, uint16_t u16Value)
604{
605 AssertPtrReturn(pszExpr, false);
606
607 /*
608 * The string format is: "int:((<m>)|([<m>]-[<n>]))(,(<m>)|([<m>]-[<n>]))*"
609 * where <m> and <n> are numbers in decimal, hex (0xNNN) or octal (0NNN).
610 * Spaces are allowed around <m> and <n>.
611 */
612 while (*pszExpr)
613 {
614 if (!strncmp(pszExpr, RT_STR_TUPLE("int:")))
615 pszExpr += strlen("int:");
616
617 /*
618 * Skip remnants of the previous expression and any empty expressions.
619 * ('|' is the expression separator.)
620 */
621 while (*pszExpr == '|' || RT_C_IS_BLANK(*pszExpr) || *pszExpr == '(' || *pszExpr == ')')
622 pszExpr++;
623 if (!*pszExpr)
624 break;
625
626 /*
627 * Parse the expression.
628 */
629 int rc;
630 uint16_t u16First = 0;
631 uint16_t u16Last = 0;
632 if (*pszExpr == '-')
633 {
634 /* -N */
635 pszExpr++;
636 rc = usbfilterReadNumber(&pszExpr, &u16Last);
637 }
638 else
639 {
640 /* M or M,N or M-N or M- */
641 rc = usbfilterReadNumber(&pszExpr, &u16First);
642 if (RT_SUCCESS(rc))
643 {
644 pszExpr = usbfilterSkipBlanks(pszExpr);
645 if (*pszExpr == '-')
646 {
647 pszExpr++;
648 if (*pszExpr) /* M-N */
649 rc = usbfilterReadNumber(&pszExpr, &u16Last);
650 else /* M- */
651 u16Last = UINT16_MAX;
652 }
653 else if (*pszExpr == ',')
654 {
655 /* M,N */
656 pszExpr++;
657 rc = usbfilterReadNumber(&pszExpr, &u16Last);
658 }
659 else
660 {
661 /* M */
662 u16Last = u16First;
663 }
664 }
665 }
666
667 /* On success, we should either be at the end of the string, at an expression
668 * separator (|), or at the end of an interval filter (')').
669 */
670 if (RT_SUCCESS(rc) && *pszExpr && *pszExpr != '|' && *pszExpr != ')')
671 rc = VERR_INVALID_PARAMETER;
672 if (RT_SUCCESS(rc))
673 {
674 /*
675 * Swap the values if the order is mixed up.
676 */
677 if (u16First > u16Last)
678 {
679 uint16_t u16Tmp = u16First;
680 u16First = u16Last;
681 u16Last = u16Tmp;
682 }
683
684 /*
685 * Perform the compare.
686 */
687 if ( u16Value >= u16First
688 && u16Value <= u16Last)
689 return true;
690 }
691 else
692 {
693 /*
694 * Skip the bad expression.
695 * ('|' is the expression separator.)
696 */
697 while (*pszExpr && *pszExpr != '|')
698 pszExpr++;
699 }
700 }
701
702 return false;
703}
704
705
706/**
707 * Performs simple pattern matching.
708 *
709 * @returns \c true on match and \c false on mismatch.
710 * @param pszPattern The pattern to match against. NULL is not okay.
711 * @param psz The string to match.
712 */
713static bool usbfilterMatchStringPattern(const char *pszPattern, const char *psz)
714{
715 AssertPtrReturn(pszPattern, false);
716 AssertPtrReturn(psz, false);
717
718 char ch;
719 while ((ch = *pszPattern++))
720 {
721 if (ch == '?')
722 {
723 /*
724 * Matches one char or end of string.
725 */
726 if (*psz)
727 psz++;
728 }
729 else if (ch == '*')
730 {
731 /*
732 * Matches zero or more characters.
733 */
734 /* skip subsequent wildcards */
735 while ( (ch = *pszPattern) == '*'
736 || ch == '?')
737 pszPattern++;
738 if (!ch)
739 /* Pattern ends with a '*' and thus matches the rest of psz. */
740 return true;
741
742 /* Find the length of the following exact pattern sequence. */
743 ssize_t cchMatch = 1;
744 while ( (ch = pszPattern[cchMatch]) != '\0'
745 && ch != '*'
746 && ch != '?')
747 cchMatch++;
748
749 /* Check if the exact pattern sequence is too long. */
750 ssize_t cch = strlen(psz);
751 cch -= cchMatch;
752 if (cch < 0)
753 return false;
754
755 /* Is the rest an exact match? */
756 if (!ch)
757 return memcmp(psz + cch, pszPattern, cchMatch) == 0;
758
759 /*
760 * This is where things normally starts to get recursive or ugly.
761 *
762 * Just to make life simple, we'll skip the nasty stuff and say
763 * that we will do a maximal wildcard match and forget about any
764 * alternative matches.
765 *
766 * If somebody is bored out of their mind one day, feel free to
767 * implement correct matching without using recursion.
768 */
769 ch = *pszPattern;
770 const char *pszMatch = NULL;
771 while ( cch-- >= 0
772 && *psz)
773 {
774 if ( *psz == ch
775 && !strncmp(psz, pszPattern, cchMatch))
776 pszMatch = psz;
777 psz++;
778 }
779 if (!pszMatch)
780 return false;
781
782 /* advance */
783 psz = pszMatch + cchMatch;
784 pszPattern += cchMatch;
785 }
786 else
787 {
788 /* exact match */
789 if (ch != *psz)
790 return false;
791 psz++;
792 }
793 }
794
795 return *psz == '\0';
796}
797
798
799/**
800 * Match a filter against a device.
801 *
802 * @returns true if they match, false if not.
803 *
804 * @param pFilter The filter to match with.
805 * @param pDevice The device data. This is a filter (type ignored) that
806 * contains 'exact' values for all present fields and 'ignore'
807 * values for the non-present fields.
808 *
809 * @remark Both the filter and the device are ASSUMED to be valid because
810 * we don't wish to waste any time in this function.
811 */
812USBLIB_DECL(bool) USBFilterMatch(PCUSBFILTER pFilter, PCUSBFILTER pDevice)
813{
814 return USBFilterMatchRated(pFilter, pDevice) > 0;
815}
816
817
818#if 0 /*def IN_RING0*/ /** @todo convert to proper logging. */
819extern "C" int printf(const char *format, ...);
820# define dprintf(a) printf a
821#else
822# define dprintf(a) do {} while (0)
823#endif
824
825/**
826 * Match a filter against a device and rate the result.
827 *
828 * @returns -1 if no match, matching rate between 1 and 100 (inclusive) if matched.
829 *
830 * @param pFilter The filter to match with.
831 * @param pDevice The device data. This is a filter (type ignored) that
832 * contains 'exact' values for all present fields and 'ignore'
833 * values for the non-present fields.
834 *
835 * @remark Both the filter and the device are ASSUMED to be valid because
836 * we don't wish to waste any time in this function.
837 */
838USBLIB_DECL(int) USBFilterMatchRated(PCUSBFILTER pFilter, PCUSBFILTER pDevice)
839{
840 unsigned iRate = 0;
841dprintf(("USBFilterMatchRated: %p %p\n", pFilter, pDevice));
842
843 for (unsigned i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
844 {
845 switch (pFilter->aFields[i].enmMatch)
846 {
847 case USBFILTERMATCH_IGNORE:
848 iRate += 2;
849 break;
850
851 case USBFILTERMATCH_PRESENT:
852 if (pDevice->aFields[i].enmMatch == USBFILTERMATCH_IGNORE)
853 {
854dprintf(("filter match[%d]: !present\n", i));
855 return -1;
856 }
857 iRate += 2;
858 break;
859
860 case USBFILTERMATCH_NUM_EXACT:
861 if ( pDevice->aFields[i].enmMatch == USBFILTERMATCH_IGNORE
862 || pFilter->aFields[i].u16Value != pDevice->aFields[i].u16Value)
863 {
864if (pDevice->aFields[i].enmMatch == USBFILTERMATCH_IGNORE)
865 dprintf(("filter match[%d]: !num_exact device=ignore\n", i));
866else
867 dprintf(("filter match[%d]: !num_exact %#x (filter) != %#x (device)\n", i, pFilter->aFields[i].u16Value, pDevice->aFields[i].u16Value));
868 return -1;
869 }
870 iRate += 2;
871 break;
872
873 case USBFILTERMATCH_NUM_EXACT_NP:
874 if ( pDevice->aFields[i].enmMatch != USBFILTERMATCH_IGNORE
875 && pFilter->aFields[i].u16Value != pDevice->aFields[i].u16Value)
876 {
877dprintf(("filter match[%d]: !num_exact_np %#x (filter) != %#x (device)\n", i, pFilter->aFields[i].u16Value, pDevice->aFields[i].u16Value));
878 return -1;
879 }
880 iRate += 2;
881 break;
882
883 case USBFILTERMATCH_NUM_EXPRESSION:
884 if ( pDevice->aFields[i].enmMatch == USBFILTERMATCH_IGNORE
885 || !usbfilterMatchNumExpression(usbfilterGetString(pFilter, (USBFILTERIDX)i),
886 pDevice->aFields[i].u16Value))
887 {
888dprintf(("filter match[%d]: !num_expression\n", i));
889 return -1;
890 }
891 iRate += 1;
892 break;
893
894 case USBFILTERMATCH_NUM_EXPRESSION_NP:
895 if ( pDevice->aFields[i].enmMatch != USBFILTERMATCH_IGNORE
896 && !usbfilterMatchNumExpression(usbfilterGetString(pFilter, (USBFILTERIDX)i),
897 pDevice->aFields[i].u16Value))
898 {
899dprintf(("filter match[%d]: !num_expression_no\n", i));
900 return -1;
901 }
902 iRate += 1;
903 break;
904
905 case USBFILTERMATCH_STR_EXACT:
906 if ( pDevice->aFields[i].enmMatch == USBFILTERMATCH_IGNORE
907 || strcmp(usbfilterGetString(pFilter, (USBFILTERIDX)i),
908 usbfilterGetString(pDevice, (USBFILTERIDX)i)))
909 {
910dprintf(("filter match[%d]: !str_exact\n", i));
911 return -1;
912 }
913 iRate += 2;
914 break;
915
916 case USBFILTERMATCH_STR_EXACT_NP:
917 if ( pDevice->aFields[i].enmMatch != USBFILTERMATCH_IGNORE
918 && strcmp(usbfilterGetString(pFilter, (USBFILTERIDX)i),
919 usbfilterGetString(pDevice, (USBFILTERIDX)i)))
920 {
921dprintf(("filter match[%d]: !str_exact_np\n", i));
922 return -1;
923 }
924 iRate += 2;
925 break;
926
927 case USBFILTERMATCH_STR_PATTERN:
928 if ( pDevice->aFields[i].enmMatch == USBFILTERMATCH_IGNORE
929 || !usbfilterMatchStringPattern(usbfilterGetString(pFilter, (USBFILTERIDX)i),
930 usbfilterGetString(pDevice, (USBFILTERIDX)i)))
931 {
932dprintf(("filter match[%d]: !str_pattern\n", i));
933 return -1;
934 }
935 iRate += 1;
936 break;
937
938 case USBFILTERMATCH_STR_PATTERN_NP:
939 if ( pDevice->aFields[i].enmMatch != USBFILTERMATCH_IGNORE
940 && !usbfilterMatchStringPattern(usbfilterGetString(pFilter, (USBFILTERIDX)i),
941 usbfilterGetString(pDevice, (USBFILTERIDX)i)))
942 {
943dprintf(("filter match[%d]: !str_pattern_np\n", i));
944 return -1;
945 }
946 iRate += 1;
947 break;
948
949 default:
950 AssertMsgFailed(("#%d: %d\n", i, pFilter->aFields[i].enmMatch));
951 return -1;
952 }
953 }
954
955 /* iRate is the range 0..2*cFields - recalc to percent. */
956dprintf(("filter match: iRate=%d", iRate));
957 return iRate == 2 * RT_ELEMENTS(pFilter->aFields)
958 ? 100
959 : (iRate * 100) / (2 * RT_ELEMENTS(pFilter->aFields));
960}
961
962
963/**
964 * Match a filter against a USBDEVICE.
965 *
966 * @returns true if they match, false if not.
967 *
968 * @param pFilter The filter to match with.
969 * @param pDevice The device to match.
970 *
971 * @remark Both the filter and the device are ASSUMED to be valid because
972 * we don't wish to waste any time in this function.
973 */
974USBLIB_DECL(bool) USBFilterMatchDevice(PCUSBFILTER pFilter, PUSBDEVICE pDevice)
975{
976 for (unsigned i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
977 {
978 switch (pFilter->aFields[i].enmMatch)
979 {
980 case USBFILTERMATCH_IGNORE:
981 break;
982
983 case USBFILTERMATCH_PRESENT:
984 {
985 const char *psz;
986 switch (i)
987 {
988 case USBFILTERIDX_MANUFACTURER_STR: psz = pDevice->pszManufacturer; break;
989 case USBFILTERIDX_PRODUCT_STR: psz = pDevice->pszProduct; break;
990 case USBFILTERIDX_SERIAL_NUMBER_STR: psz = pDevice->pszSerialNumber; break;
991 default: psz = ""; break;
992 }
993 if (!psz)
994 return false;
995 break;
996 }
997
998 case USBFILTERMATCH_NUM_EXACT:
999 case USBFILTERMATCH_NUM_EXACT_NP:
1000 case USBFILTERMATCH_NUM_EXPRESSION:
1001 case USBFILTERMATCH_NUM_EXPRESSION_NP:
1002 {
1003 uint16_t u16Value;
1004 switch (i)
1005 {
1006 case USBFILTERIDX_VENDOR_ID: u16Value = pDevice->idVendor; break;
1007 case USBFILTERIDX_PRODUCT_ID: u16Value = pDevice->idProduct; break;
1008 case USBFILTERIDX_DEVICE: u16Value = pDevice->bcdDevice; break;
1009 case USBFILTERIDX_DEVICE_CLASS: u16Value = pDevice->bDeviceClass; break;
1010 case USBFILTERIDX_DEVICE_SUB_CLASS: u16Value = pDevice->bDeviceSubClass; break;
1011 case USBFILTERIDX_DEVICE_PROTOCOL: u16Value = pDevice->bDeviceProtocol; break;
1012 case USBFILTERIDX_BUS: u16Value = pDevice->bBus; break;
1013 case USBFILTERIDX_PORT: u16Value = pDevice->bPort; break;
1014 default: u16Value = UINT16_MAX; break;
1015
1016 }
1017 switch (pFilter->aFields[i].enmMatch)
1018 {
1019 case USBFILTERMATCH_NUM_EXACT:
1020 case USBFILTERMATCH_NUM_EXACT_NP:
1021 if (pFilter->aFields[i].u16Value != u16Value)
1022 return false;
1023 break;
1024 case USBFILTERMATCH_NUM_EXPRESSION:
1025 case USBFILTERMATCH_NUM_EXPRESSION_NP:
1026 if (!usbfilterMatchNumExpression(usbfilterGetString(pFilter, (USBFILTERIDX)i), u16Value))
1027 return false;
1028 break;
1029 }
1030 break;
1031 }
1032
1033 case USBFILTERMATCH_STR_EXACT:
1034 case USBFILTERMATCH_STR_EXACT_NP:
1035 case USBFILTERMATCH_STR_PATTERN:
1036 case USBFILTERMATCH_STR_PATTERN_NP:
1037 {
1038 const char *psz;
1039 switch (i)
1040 {
1041 case USBFILTERIDX_MANUFACTURER_STR: psz = pDevice->pszManufacturer; break;
1042 case USBFILTERIDX_PRODUCT_STR: psz = pDevice->pszProduct; break;
1043 case USBFILTERIDX_SERIAL_NUMBER_STR: psz = pDevice->pszSerialNumber; break;
1044 default: psz = NULL; break;
1045 }
1046 switch (pFilter->aFields[i].enmMatch)
1047 {
1048 case USBFILTERMATCH_STR_EXACT:
1049 if ( !psz
1050 || strcmp(usbfilterGetString(pFilter, (USBFILTERIDX)i), psz))
1051 return false;
1052 break;
1053
1054 case USBFILTERMATCH_STR_EXACT_NP:
1055 if ( psz
1056 && strcmp(usbfilterGetString(pFilter, (USBFILTERIDX)i), psz))
1057 return false;
1058 break;
1059
1060 case USBFILTERMATCH_STR_PATTERN:
1061 if ( !psz
1062 || !usbfilterMatchStringPattern(usbfilterGetString(pFilter, (USBFILTERIDX)i), psz))
1063 return false;
1064 break;
1065
1066 case USBFILTERMATCH_STR_PATTERN_NP:
1067 if ( psz
1068 && !usbfilterMatchStringPattern(usbfilterGetString(pFilter, (USBFILTERIDX)i), psz))
1069 return false;
1070 break;
1071 }
1072 break;
1073 }
1074
1075 default:
1076 AssertMsgFailed(("#%d: %d\n", i, pFilter->aFields[i].enmMatch));
1077 return false;
1078 }
1079 }
1080
1081 return true;
1082}
1083
1084
1085/**
1086 * Checks if the two filters are identical.
1087 *
1088 * @returns true if the are identical, false if they aren't.
1089 * @param pFilter The first filter.
1090 * @param pFilter2 The second filter.
1091 */
1092USBLIB_DECL(bool) USBFilterIsIdentical(PCUSBFILTER pFilter, PCUSBFILTER pFilter2)
1093{
1094 /* Lazy works here because we're darn strict with zero padding and such elsewhere. */
1095 return memcmp(pFilter, pFilter2, sizeof(*pFilter)) == 0;
1096}
1097
1098
1099
1100/**
1101 * Sets the filter type.
1102 *
1103 * @returns VBox status code.
1104 * @retval VERR_INVALID_PARAMETER if the filter type is invalid.
1105 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1106 *
1107 * @param pFilter The filter.
1108 * @param enmType The new filter type.
1109 */
1110USBLIB_DECL(int) USBFilterSetFilterType(PUSBFILTER pFilter, USBFILTERTYPE enmType)
1111{
1112 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, VERR_INVALID_MAGIC);
1113 AssertReturn(enmType > USBFILTERTYPE_INVALID && enmType < USBFILTERTYPE_END, VERR_INVALID_PARAMETER);
1114
1115 pFilter->enmType = enmType;
1116 return VINF_SUCCESS;
1117}
1118
1119
1120/**
1121 * Replaces the string value of a field.
1122 *
1123 * This will remove any existing string value current held by the field from the
1124 * string table and then attempt to add the new value. This function can be used
1125 * to delete any assigned string before changing the type to numeric by passing
1126 * in an empty string. This works because the first byte in the string table is
1127 * reserved for the empty (NULL) string.
1128 *
1129 * @returns VBox status code.
1130 * @retval VINF_SUCCESS on success.
1131 * @retval VERR_BUFFER_OVERFLOW if the string table is full.
1132 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid.
1133 * @retval VERR_INVALID_POINTER if pszString isn't valid.
1134 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1135 *
1136 * @param pFilter The filter.
1137 * @param enmFieldIdx The field index.
1138 * @param pszString The string to add.
1139 * @param fPurge Purge invalid UTF-8 encoding and control characters
1140 * before setting it.
1141 */
1142static int usbfilterSetString(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, const char *pszString, bool fPurge)
1143{
1144 /*
1145 * Validate input.
1146 */
1147 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, VERR_INVALID_MAGIC);
1148 AssertReturn((unsigned)enmFieldIdx < (unsigned)USBFILTERIDX_END, VERR_INVALID_PARAMETER);
1149 AssertPtrReturn(pszString, VERR_INVALID_POINTER);
1150
1151 Assert(pFilter->offCurEnd < sizeof(pFilter->achStrTab));
1152 Assert(pFilter->achStrTab[pFilter->offCurEnd] == '\0');
1153
1154 /*
1155 * Remove old string value if any.
1156 */
1157 if ( USBFilterIsMethodUsingStringValue((USBFILTERMATCH)pFilter->aFields[enmFieldIdx].enmMatch)
1158 && pFilter->aFields[enmFieldIdx].u16Value != 0)
1159 {
1160 uint32_t off = pFilter->aFields[enmFieldIdx].u16Value;
1161 pFilter->aFields[enmFieldIdx].u16Value = 0; /* Assign it to the NULL string. */
1162
1163 unsigned cchShift = (unsigned)strlen(&pFilter->achStrTab[off]) + 1;
1164 ssize_t cchToMove = (pFilter->offCurEnd + 1) - (off + cchShift);
1165 Assert(cchToMove >= 0);
1166 if (cchToMove > 0)
1167 {
1168 /* We're not last - must shift the strings. */
1169 memmove(&pFilter->achStrTab[off], &pFilter->achStrTab[off + cchShift], cchToMove);
1170 for (unsigned i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
1171 if ( pFilter->aFields[i].u16Value >= off
1172 && USBFilterIsMethodUsingStringValue((USBFILTERMATCH)pFilter->aFields[i].enmMatch))
1173 pFilter->aFields[i].u16Value -= cchShift;
1174 }
1175 pFilter->offCurEnd -= cchShift;
1176 Assert(pFilter->offCurEnd < sizeof(pFilter->achStrTab));
1177 Assert(pFilter->offCurEnd + cchShift <= sizeof(pFilter->achStrTab));
1178
1179 /* zero the unused string table (to allow lazyness/strictness elsewhere). */
1180 memset(&pFilter->achStrTab[pFilter->offCurEnd], '\0', cchShift);
1181 }
1182
1183 /*
1184 * Make a special case for the empty string.
1185 * (This also makes the delete logical above work correctly for the last string.)
1186 */
1187 if (!*pszString)
1188 pFilter->aFields[enmFieldIdx].u16Value = 0;
1189 else
1190 {
1191 size_t cch = strlen(pszString);
1192 if (pFilter->offCurEnd + cch + 2 > sizeof(pFilter->achStrTab))
1193 return VERR_BUFFER_OVERFLOW;
1194
1195 pFilter->aFields[enmFieldIdx].u16Value = pFilter->offCurEnd + 1;
1196 memcpy(&pFilter->achStrTab[pFilter->offCurEnd + 1], pszString, cch + 1);
1197 if (fPurge)
1198 cch = USBLibPurgeEncoding(&pFilter->achStrTab[pFilter->offCurEnd + 1]);
1199 pFilter->offCurEnd += (uint32_t)cch + 1;
1200 }
1201
1202 return VINF_SUCCESS;
1203}
1204
1205/**
1206 * Wrapper around usbfilterSetString() that deletes any string value
1207 * currently assigned to a field.
1208 *
1209 * Upon successful return the field contains a null string, nothing or a number.
1210 *
1211 * This function will validate the field index if there isn't any string
1212 * value to delete, thus preventing any extra validating of the index.
1213 *
1214 * @returns VBox status code. See usbfilterSetString.
1215 * @param pFilter The filter.
1216 * @param enmFieldIdx The index of the field which string value should be deleted.
1217 */
1218static int usbfilterDeleteAnyStringValue(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1219{
1220 int rc = VINF_SUCCESS;
1221 if ( USBFilterIsMethodUsingStringValue((USBFILTERMATCH)pFilter->aFields[enmFieldIdx].enmMatch)
1222 && pFilter->aFields[enmFieldIdx].u16Value != 0)
1223 rc = usbfilterSetString(pFilter, enmFieldIdx, "", false /*fPurge*/);
1224 else if ((unsigned)enmFieldIdx >= (unsigned)USBFILTERIDX_END)
1225 rc = VERR_INVALID_PARAMETER;
1226 return rc;
1227}
1228
1229
1230/**
1231 * Sets a field to always match (ignore whatever is thrown at it).
1232 *
1233 * @returns VBox status code.
1234 * @retval VINF_SUCCESS on success.
1235 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid.
1236 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1237 *
1238 * @param pFilter The filter.
1239 * @param enmFieldIdx The field index. This must be a string field.
1240 */
1241USBLIB_DECL(int) USBFilterSetIgnore(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1242{
1243 int rc = usbfilterDeleteAnyStringValue(pFilter, enmFieldIdx);
1244 if (RT_SUCCESS(rc))
1245 {
1246 pFilter->aFields[enmFieldIdx].enmMatch = USBFILTERMATCH_IGNORE;
1247 pFilter->aFields[enmFieldIdx].u16Value = 0;
1248 }
1249 return rc;
1250}
1251
1252
1253/**
1254 * Sets a field to match on device field present only.
1255 *
1256 * @returns VBox status code.
1257 * @retval VINF_SUCCESS on success.
1258 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid.
1259 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1260 *
1261 * @param pFilter The filter.
1262 * @param enmFieldIdx The field index. This must be a string field.
1263 */
1264USBLIB_DECL(int) USBFilterSetPresentOnly(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1265{
1266 int rc = usbfilterDeleteAnyStringValue(pFilter, enmFieldIdx);
1267 if (RT_SUCCESS(rc))
1268 {
1269 pFilter->aFields[enmFieldIdx].enmMatch = USBFILTERMATCH_PRESENT;
1270 pFilter->aFields[enmFieldIdx].u16Value = 0;
1271 }
1272 return rc;
1273}
1274
1275
1276/**
1277 * Sets a field to exactly match a number.
1278 *
1279 * @returns VBox status code.
1280 * @retval VINF_SUCCESS on success.
1281 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid.
1282 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1283 *
1284 * @param pFilter The filter.
1285 * @param enmFieldIdx The field index. This must be a string field.
1286 * @param u16Value The string pattern.
1287 * @param fMustBePresent If set, a non-present field on the device will result in a mismatch.
1288 * If clear, a non-present field on the device will match.
1289 */
1290USBLIB_DECL(int) USBFilterSetNumExact(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, uint16_t u16Value, bool fMustBePresent)
1291{
1292 int rc = USBFilterIsNumericField(enmFieldIdx) ? VINF_SUCCESS : VERR_INVALID_PARAMETER;
1293 if (RT_SUCCESS(rc))
1294 {
1295 rc = usbfilterDeleteAnyStringValue(pFilter, enmFieldIdx);
1296 if (RT_SUCCESS(rc))
1297 {
1298 pFilter->aFields[enmFieldIdx].u16Value = u16Value;
1299 pFilter->aFields[enmFieldIdx].enmMatch = fMustBePresent ? USBFILTERMATCH_NUM_EXACT : USBFILTERMATCH_NUM_EXACT_NP;
1300 }
1301 }
1302
1303 return rc;
1304}
1305
1306
1307/**
1308 * Sets a field to match a numeric expression.
1309 *
1310 * @returns VBox status code.
1311 * @retval VINF_SUCCESS on success.
1312 * @retval VERR_BUFFER_OVERFLOW if the string table is full.
1313 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx or the numeric expression aren't valid.
1314 * @retval VERR_INVALID_POINTER if pszExpression isn't a valid pointer.
1315 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1316 *
1317 * @param pFilter The filter.
1318 * @param enmFieldIdx The field index. This must be a string field.
1319 * @param pszExpression The numeric expression.
1320 * @param fMustBePresent If set, a non-present field on the device will result in a mismatch.
1321 * If clear, a non-present field on the device will match.
1322 */
1323USBLIB_DECL(int) USBFilterSetNumExpression(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, const char *pszExpression, bool fMustBePresent)
1324{
1325 int rc = USBFilterIsNumericField(enmFieldIdx) ? VINF_SUCCESS : VERR_INVALID_PARAMETER;
1326 if (RT_SUCCESS(rc))
1327 {
1328 /* Strip leading spaces and empty sub expressions (||). */
1329 while (*pszExpression && (RT_C_IS_BLANK(*pszExpression) || *pszExpression == '|'))
1330 pszExpression++;
1331
1332 rc = usbfilterValidateNumExpression(pszExpression);
1333 if (RT_SUCCESS(rc))
1334 {
1335 /* We could optimize the expression further (stripping spaces, convert numbers),
1336 but it's more work than what it's worth and it could upset some users. */
1337 rc = usbfilterSetString(pFilter, enmFieldIdx, pszExpression, false /*fPurge*/);
1338 if (RT_SUCCESS(rc))
1339 pFilter->aFields[enmFieldIdx].enmMatch = fMustBePresent ? USBFILTERMATCH_NUM_EXPRESSION : USBFILTERMATCH_NUM_EXPRESSION_NP;
1340 else if (rc == VERR_NO_DIGITS)
1341 rc = VERR_INVALID_PARAMETER;
1342 }
1343 }
1344 return rc;
1345}
1346
1347
1348/**
1349 * Sets a field to exactly match a string.
1350 *
1351 * @returns VBox status code.
1352 * @retval VINF_SUCCESS on success.
1353 * @retval VERR_BUFFER_OVERFLOW if the string table is full.
1354 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid.
1355 * @retval VERR_INVALID_POINTER if pszPattern isn't a valid pointer.
1356 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1357 *
1358 * @param pFilter The filter.
1359 * @param enmFieldIdx The field index. This must be a string field.
1360 * @param pszValue The string value.
1361 * @param fMustBePresent If set, a non-present field on the device will result in a mismatch.
1362 * If clear, a non-present field on the device will match.
1363 * @param fPurge Purge invalid UTF-8 encoding and control
1364 * characters before setting it.
1365 */
1366USBLIB_DECL(int) USBFilterSetStringExact(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, const char *pszValue,
1367 bool fMustBePresent, bool fPurge)
1368{
1369 int rc = USBFilterIsStringField(enmFieldIdx) ? VINF_SUCCESS : VERR_INVALID_PARAMETER;
1370 if (RT_SUCCESS(rc))
1371 {
1372 rc = usbfilterSetString(pFilter, enmFieldIdx, pszValue, fPurge);
1373 if (RT_SUCCESS(rc))
1374 pFilter->aFields[enmFieldIdx].enmMatch = fMustBePresent ? USBFILTERMATCH_STR_EXACT : USBFILTERMATCH_STR_EXACT_NP;
1375 }
1376 return rc;
1377}
1378
1379
1380/**
1381 * Sets a field to match a string pattern.
1382 *
1383 * @returns VBox status code.
1384 * @retval VINF_SUCCESS on success.
1385 * @retval VERR_BUFFER_OVERFLOW if the string table is full.
1386 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx or pattern aren't valid.
1387 * @retval VERR_INVALID_POINTER if pszPattern isn't a valid pointer.
1388 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1389 *
1390 * @param pFilter The filter.
1391 * @param enmFieldIdx The field index. This must be a string field.
1392 * @param pszPattern The string pattern.
1393 * @param fMustBePresent If set, a non-present field on the device will result in a mismatch.
1394 * If clear, a non-present field on the device will match.
1395 */
1396USBLIB_DECL(int) USBFilterSetStringPattern(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, const char *pszPattern, bool fMustBePresent)
1397{
1398 int rc = USBFilterIsStringField(enmFieldIdx) ? VINF_SUCCESS : VERR_INVALID_PARAMETER;
1399 if (RT_SUCCESS(rc))
1400 {
1401 rc = usbfilterValidateStringPattern(pszPattern);
1402 if (RT_SUCCESS(rc))
1403 {
1404 rc = usbfilterSetString(pFilter, enmFieldIdx, pszPattern, false /*fPurge*/);
1405 if (RT_SUCCESS(rc))
1406 pFilter->aFields[enmFieldIdx].enmMatch = fMustBePresent ? USBFILTERMATCH_STR_PATTERN : USBFILTERMATCH_STR_PATTERN_NP;
1407 }
1408 }
1409 return rc;
1410}
1411
1412
1413/**
1414 * Sets the must-be-present part of a field.
1415 *
1416 * This only works on field which already has matching criteria. This means
1417 * that field marked 'ignore' will not be processed and will result in a
1418 * warning status code.
1419 *
1420 * @returns VBox status code.
1421 * @retval VINF_SUCCESS on success.
1422 * @retval VWRN_INVALID_PARAMETER if the field is marked 'ignore'. No assertions.
1423 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx or pattern aren't valid.
1424 * @retval VERR_INVALID_POINTER if pszPattern isn't a valid pointer.
1425 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1426 *
1427 * @param pFilter The filter.
1428 * @param enmFieldIdx The field index.
1429 * @param fMustBePresent If set, a non-present field on the device will result in a mismatch.
1430 * If clear, a non-present field on the device will match.
1431 */
1432USBLIB_DECL(int) USBFilterSetMustBePresent(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, bool fMustBePresent)
1433{
1434 AssertPtrReturn(pFilter, VERR_INVALID_POINTER);
1435 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, VERR_INVALID_MAGIC);
1436 AssertReturn((unsigned)enmFieldIdx < (unsigned)USBFILTERIDX_END, VERR_INVALID_PARAMETER);
1437
1438 USBFILTERMATCH enmMatch = (USBFILTERMATCH)pFilter->aFields[enmFieldIdx].enmMatch;
1439 if (fMustBePresent)
1440 {
1441 switch (enmMatch)
1442 {
1443 case USBFILTERMATCH_IGNORE:
1444 return VWRN_INVALID_PARAMETER;
1445
1446 case USBFILTERMATCH_PRESENT:
1447 case USBFILTERMATCH_NUM_EXACT:
1448 case USBFILTERMATCH_NUM_EXPRESSION:
1449 case USBFILTERMATCH_STR_EXACT:
1450 case USBFILTERMATCH_STR_PATTERN:
1451 break;
1452
1453 case USBFILTERMATCH_NUM_EXACT_NP:
1454 enmMatch = USBFILTERMATCH_NUM_EXACT;
1455 break;
1456 case USBFILTERMATCH_NUM_EXPRESSION_NP:
1457 enmMatch = USBFILTERMATCH_NUM_EXPRESSION;
1458 break;
1459 case USBFILTERMATCH_STR_EXACT_NP:
1460 enmMatch = USBFILTERMATCH_STR_EXACT;
1461 break;
1462 case USBFILTERMATCH_STR_PATTERN_NP:
1463 enmMatch = USBFILTERMATCH_STR_PATTERN;
1464 break;
1465 default:
1466 AssertMsgFailedReturn(("%p: enmFieldIdx=%d enmMatch=%d\n", pFilter, enmFieldIdx, enmMatch), VERR_INVALID_MAGIC);
1467 }
1468 }
1469 else
1470 {
1471 switch (enmMatch)
1472 {
1473 case USBFILTERMATCH_IGNORE:
1474 return VWRN_INVALID_PARAMETER;
1475
1476 case USBFILTERMATCH_NUM_EXACT_NP:
1477 case USBFILTERMATCH_STR_PATTERN_NP:
1478 case USBFILTERMATCH_STR_EXACT_NP:
1479 case USBFILTERMATCH_NUM_EXPRESSION_NP:
1480 break;
1481
1482 case USBFILTERMATCH_PRESENT:
1483 enmMatch = USBFILTERMATCH_IGNORE;
1484 break;
1485 case USBFILTERMATCH_NUM_EXACT:
1486 enmMatch = USBFILTERMATCH_NUM_EXACT_NP;
1487 break;
1488 case USBFILTERMATCH_NUM_EXPRESSION:
1489 enmMatch = USBFILTERMATCH_NUM_EXPRESSION_NP;
1490 break;
1491 case USBFILTERMATCH_STR_EXACT:
1492 enmMatch = USBFILTERMATCH_STR_EXACT_NP;
1493 break;
1494 case USBFILTERMATCH_STR_PATTERN:
1495 enmMatch = USBFILTERMATCH_STR_PATTERN_NP;
1496 break;
1497
1498 default:
1499 AssertMsgFailedReturn(("%p: enmFieldIdx=%d enmMatch=%d\n", pFilter, enmFieldIdx, enmMatch), VERR_INVALID_MAGIC);
1500 }
1501 }
1502
1503 pFilter->aFields[enmFieldIdx].enmMatch = enmMatch;
1504 return VINF_SUCCESS;
1505}
1506
1507
1508/**
1509 * Gets the filter type.
1510 *
1511 * @returns The filter type.
1512 * USBFILTERTYPE_INVALID if the filter is invalid.
1513 * @param pFilter The filter.
1514 */
1515USBLIB_DECL(USBFILTERTYPE) USBFilterGetFilterType(PCUSBFILTER pFilter)
1516{
1517 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, USBFILTERTYPE_INVALID);
1518 return pFilter->enmType;
1519}
1520
1521
1522/**
1523 * Gets the matching method for a field.
1524 *
1525 * @returns The matching method on success, UBFILTERMATCH_INVALID on invalid field index.
1526 * @param pFilter The filter.
1527 * @param enmFieldIdx The field index.
1528 */
1529USBLIB_DECL(USBFILTERMATCH) USBFilterGetMatchingMethod(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1530{
1531 if ( pFilter->u32Magic == USBFILTER_MAGIC
1532 && (unsigned)enmFieldIdx < (unsigned)USBFILTERIDX_END)
1533 return (USBFILTERMATCH)pFilter->aFields[enmFieldIdx].enmMatch;
1534 return USBFILTERMATCH_INVALID;
1535}
1536
1537
1538/**
1539 * Gets the numeric value of a field.
1540 *
1541 * The field must contain a number, we're not doing any conversions for you.
1542 *
1543 * @returns VBox status code.
1544 * @retval VINF_SUCCESS on success.
1545 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid or if the field doesn't contain a number.
1546 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1547 *
1548 * @param pFilter The filter.
1549 * @param enmFieldIdx The field index.
1550 * @param pu16Value Where to store the value.
1551 */
1552USBLIB_DECL(int) USBFilterQueryNum(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, uint16_t *pu16Value)
1553{
1554 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, VERR_INVALID_MAGIC);
1555 int iValue = usbfilterGetNum(pFilter, enmFieldIdx);
1556 if (iValue == -1)
1557 return VERR_INVALID_PARAMETER;
1558 *pu16Value = (uint16_t)iValue;
1559 return VINF_SUCCESS;
1560}
1561
1562
1563/**
1564 * Gets the numeric value of a field.
1565 *
1566 * The field must contain a number, we're not doing any conversions for you.
1567 *
1568 * @returns The field value on success, -1 on failure (invalid input / not numeric).
1569 *
1570 * @param pFilter The filter.
1571 * @param enmFieldIdx The field index.
1572 */
1573USBLIB_DECL(int) USBFilterGetNum(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1574{
1575 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, -1);
1576 return usbfilterGetNum(pFilter, enmFieldIdx);
1577}
1578
1579
1580/**
1581 * Gets the string value of a field.
1582 *
1583 * The field must contain a string, we're not doing any conversions for you.
1584 *
1585 * @returns VBox status code.
1586 * @retval VINF_SUCCESS on success.
1587 * @retval VERR_BUFFER_OVERFLOW if the buffer isn't sufficient to hold the string. The buffer
1588 * will be filled with as much of the string that'll fit.
1589 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid or if the field doesn't contain a string.
1590 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1591 *
1592 * @param pFilter The filter.
1593 * @param enmFieldIdx The field index.
1594 * @param pszBuf Where to store the string.
1595 * @param cchBuf The size of the buffer.
1596 */
1597USBLIB_DECL(int) USBFilterQueryString(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, char *pszBuf, size_t cchBuf)
1598{
1599 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, VERR_INVALID_MAGIC);
1600
1601 const char *psz = usbfilterGetString(pFilter, enmFieldIdx);
1602 if (RT_UNLIKELY(!psz))
1603 return VERR_INVALID_PARAMETER;
1604
1605 int rc = VINF_SUCCESS;
1606 size_t cch = strlen(psz);
1607 if (cch < cchBuf)
1608 memcpy(pszBuf, psz, cch + 1);
1609 else
1610 {
1611 rc = VERR_BUFFER_OVERFLOW;
1612 if (cchBuf)
1613 {
1614 memcpy(pszBuf, psz, cchBuf - 1);
1615 pszBuf[cchBuf - 1] = '\0';
1616 }
1617 }
1618
1619 return rc;
1620}
1621
1622
1623/**
1624 * Gets the string table entry for a field.
1625 *
1626 * @returns Pointer to the string. (readonly!)
1627 *
1628 * @param pFilter The filter.
1629 * @param enmFieldIdx The field index.
1630 */
1631USBLIB_DECL(const char *) USBFilterGetString(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1632{
1633 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, NULL);
1634
1635 const char *psz = usbfilterGetString(pFilter, enmFieldIdx);
1636 if (RT_UNLIKELY(!psz))
1637 return NULL;
1638 return psz;
1639}
1640
1641
1642/**
1643 * Gets the string length of a field containing a string.
1644 *
1645 * @returns String length on success, -1 on failure (not a string, bad filter).
1646 * @param pFilter The filter.
1647 * @param enmFieldIdx The field index.
1648 */
1649USBLIB_DECL(ssize_t) USBFilterGetStringLen(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1650{
1651 if (RT_LIKELY(pFilter->u32Magic == USBFILTER_MAGIC))
1652 {
1653 const char *psz = usbfilterGetString(pFilter, enmFieldIdx);
1654 if (RT_LIKELY(psz))
1655 return strlen(psz);
1656 }
1657 return -1;
1658}
1659
1660
1661/**
1662 * Check if any of the fields are set to something substatial.
1663 *
1664 * Consider the fileter a wildcard if this returns false.
1665 *
1666 * @returns true / false.
1667 * @param pFilter The filter.
1668 */
1669USBLIB_DECL(bool) USBFilterHasAnySubstatialCriteria(PCUSBFILTER pFilter)
1670{
1671 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, false);
1672
1673 for (unsigned i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
1674 {
1675 switch (pFilter->aFields[i].enmMatch)
1676 {
1677 case USBFILTERMATCH_IGNORE:
1678 case USBFILTERMATCH_PRESENT:
1679 break;
1680
1681 case USBFILTERMATCH_NUM_EXACT:
1682 case USBFILTERMATCH_NUM_EXACT_NP:
1683 case USBFILTERMATCH_STR_EXACT:
1684 case USBFILTERMATCH_STR_EXACT_NP:
1685 return true;
1686
1687 case USBFILTERMATCH_NUM_EXPRESSION:
1688 case USBFILTERMATCH_NUM_EXPRESSION_NP:
1689 {
1690 const char *psz = usbfilterGetString(pFilter, (USBFILTERIDX)i);
1691 if (psz)
1692 {
1693 while (*psz && (*psz == '|' || RT_C_IS_BLANK(*psz)))
1694 psz++;
1695 if (*psz)
1696 return true;
1697 }
1698 break;
1699 }
1700
1701 case USBFILTERMATCH_STR_PATTERN:
1702 case USBFILTERMATCH_STR_PATTERN_NP:
1703 {
1704 const char *psz = usbfilterGetString(pFilter, (USBFILTERIDX)i);
1705 if (psz)
1706 {
1707 while (*psz && (*psz == '*' || *psz == '?'))
1708 psz++;
1709 if (*psz)
1710 return true;
1711 }
1712 break;
1713 }
1714 }
1715 }
1716
1717 return false;
1718}
1719
1720
1721
1722/**
1723 * Checks whether the specified field is a numeric field or not.
1724 *
1725 * @returns true / false.
1726 * @param enmFieldIdx The field index.
1727 */
1728USBLIB_DECL(bool) USBFilterIsNumericField(USBFILTERIDX enmFieldIdx)
1729{
1730 switch (enmFieldIdx)
1731 {
1732 case USBFILTERIDX_VENDOR_ID:
1733 case USBFILTERIDX_PRODUCT_ID:
1734 case USBFILTERIDX_DEVICE:
1735 case USBFILTERIDX_DEVICE_CLASS:
1736 case USBFILTERIDX_DEVICE_SUB_CLASS:
1737 case USBFILTERIDX_DEVICE_PROTOCOL:
1738 case USBFILTERIDX_BUS:
1739 case USBFILTERIDX_PORT:
1740 return true;
1741
1742 default:
1743 AssertMsgFailed(("%d\n", enmFieldIdx));
1744 RT_FALL_THRU();
1745 case USBFILTERIDX_MANUFACTURER_STR:
1746 case USBFILTERIDX_PRODUCT_STR:
1747 case USBFILTERIDX_SERIAL_NUMBER_STR:
1748 return false;
1749 }
1750}
1751
1752
1753/**
1754 * Checks whether the specified field is a string field or not.
1755 *
1756 * @returns true / false.
1757 * @param enmFieldIdx The field index.
1758 */
1759USBLIB_DECL(bool) USBFilterIsStringField(USBFILTERIDX enmFieldIdx)
1760{
1761 switch (enmFieldIdx)
1762 {
1763 default:
1764 AssertMsgFailed(("%d\n", enmFieldIdx));
1765 RT_FALL_THRU();
1766 case USBFILTERIDX_VENDOR_ID:
1767 case USBFILTERIDX_PRODUCT_ID:
1768 case USBFILTERIDX_DEVICE:
1769 case USBFILTERIDX_DEVICE_CLASS:
1770 case USBFILTERIDX_DEVICE_SUB_CLASS:
1771 case USBFILTERIDX_DEVICE_PROTOCOL:
1772 case USBFILTERIDX_BUS:
1773 case USBFILTERIDX_PORT:
1774 return false;
1775
1776 case USBFILTERIDX_MANUFACTURER_STR:
1777 case USBFILTERIDX_PRODUCT_STR:
1778 case USBFILTERIDX_SERIAL_NUMBER_STR:
1779 return true;
1780 }
1781}
1782
1783
1784/**
1785 * Checks whether the specified matching method uses a numeric value or not.
1786 *
1787 * @returns true / false.
1788 * @param enmMatchingMethod The matching method.
1789 */
1790USBLIB_DECL(bool) USBFilterIsMethodUsingNumericValue(USBFILTERMATCH enmMatchingMethod)
1791{
1792 switch (enmMatchingMethod)
1793 {
1794 default:
1795 AssertMsgFailed(("%d\n", enmMatchingMethod));
1796 RT_FALL_THRU();
1797 case USBFILTERMATCH_IGNORE:
1798 case USBFILTERMATCH_PRESENT:
1799 case USBFILTERMATCH_NUM_EXPRESSION:
1800 case USBFILTERMATCH_NUM_EXPRESSION_NP:
1801 case USBFILTERMATCH_STR_EXACT:
1802 case USBFILTERMATCH_STR_EXACT_NP:
1803 case USBFILTERMATCH_STR_PATTERN:
1804 case USBFILTERMATCH_STR_PATTERN_NP:
1805 return false;
1806
1807 case USBFILTERMATCH_NUM_EXACT:
1808 case USBFILTERMATCH_NUM_EXACT_NP:
1809 return true;
1810 }
1811}
1812
1813
1814/**
1815 * Checks whether the specified matching method uses a string value or not.
1816 *
1817 * @returns true / false.
1818 * @param enmMatchingMethod The matching method.
1819 */
1820USBLIB_DECL(bool) USBFilterIsMethodUsingStringValue(USBFILTERMATCH enmMatchingMethod)
1821{
1822 switch (enmMatchingMethod)
1823 {
1824 default:
1825 AssertMsgFailed(("%d\n", enmMatchingMethod));
1826 RT_FALL_THRU();
1827 case USBFILTERMATCH_IGNORE:
1828 case USBFILTERMATCH_PRESENT:
1829 case USBFILTERMATCH_NUM_EXACT:
1830 case USBFILTERMATCH_NUM_EXACT_NP:
1831 return false;
1832
1833 case USBFILTERMATCH_NUM_EXPRESSION:
1834 case USBFILTERMATCH_NUM_EXPRESSION_NP:
1835 case USBFILTERMATCH_STR_EXACT:
1836 case USBFILTERMATCH_STR_EXACT_NP:
1837 case USBFILTERMATCH_STR_PATTERN:
1838 case USBFILTERMATCH_STR_PATTERN_NP:
1839 return true;
1840 }
1841}
1842
1843
1844/**
1845 * Checks if a matching method is for numeric fields or not.
1846 *
1847 * @returns true / false.
1848 * @param enmMatchingMethod The matching method.
1849 */
1850USBLIB_DECL(bool) USBFilterIsMethodNumeric(USBFILTERMATCH enmMatchingMethod)
1851{
1852 return enmMatchingMethod >= USBFILTERMATCH_NUM_FIRST
1853 && enmMatchingMethod <= USBFILTERMATCH_NUM_LAST;
1854}
1855
1856/**
1857 * Checks if a matching method is for string fields or not.
1858 *
1859 * @returns true / false.
1860 * @param enmMatchingMethod The matching method.
1861 */
1862USBLIB_DECL(bool) USBFilterIsMethodString(USBFILTERMATCH enmMatchingMethod)
1863{
1864 return enmMatchingMethod >= USBFILTERMATCH_STR_FIRST
1865 && enmMatchingMethod <= USBFILTERMATCH_STR_LAST;
1866}
1867
Note: See TracBrowser for help on using the repository browser.

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