~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/HostDrivers/VBoxUSB/USBFilter.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

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