mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-06 09:35:52 +00:00
sapi: Implement token filtering and sorting in ISpObjectTokenEnumBuilder.
This commit is contained in:
parent
f286ee9bfa
commit
db2640d06b
|
@ -172,6 +172,10 @@ static void test_token_category(void)
|
|||
IEnumSpObjectTokens *enum_tokens;
|
||||
HRESULT hr;
|
||||
ULONG count;
|
||||
int i;
|
||||
ISpObjectToken *token;
|
||||
WCHAR *token_id;
|
||||
WCHAR tmp[MAX_PATH];
|
||||
|
||||
hr = CoCreateInstance( &CLSID_SpObjectTokenCategory, NULL, CLSCTX_INPROC_SERVER,
|
||||
&IID_ISpObjectTokenCategory, (void **)&cat );
|
||||
|
@ -198,6 +202,43 @@ static void test_token_category(void)
|
|||
ok( count == 5, "got %lu\n", count );
|
||||
|
||||
IEnumSpObjectTokens_Release( enum_tokens );
|
||||
|
||||
hr = ISpObjectTokenCategory_EnumTokens( cat, L"Language=409", NULL, &enum_tokens );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
|
||||
count = 0xdeadbeef;
|
||||
hr = IEnumSpObjectTokens_GetCount( enum_tokens, &count );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
ok( count == 3, "got %lu\n", count );
|
||||
|
||||
IEnumSpObjectTokens_Release( enum_tokens );
|
||||
|
||||
hr = ISpObjectTokenCategory_EnumTokens( cat, L"Language=409", L"Vendor=Vendor1;Age=Child;Gender=Female",
|
||||
&enum_tokens );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
|
||||
count = 0xdeadbeef;
|
||||
hr = IEnumSpObjectTokens_GetCount( enum_tokens, &count );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
ok( count == 3, "got %lu\n", count );
|
||||
|
||||
for ( i = 0; i < 3; i++ ) {
|
||||
token = NULL;
|
||||
hr = IEnumSpObjectTokens_Item( enum_tokens, i, &token );
|
||||
ok( hr == S_OK, "i = %d: got %08lx\n", i, hr );
|
||||
|
||||
token_id = NULL;
|
||||
hr = ISpObjectToken_GetId( token, &token_id );
|
||||
ok( hr == S_OK, "i = %d: got %08lx\n", i, hr );
|
||||
swprintf( tmp, MAX_PATH, L"%ls\\Tokens\\Voice%d", test_cat, 3 - i );
|
||||
ok( !wcscmp( token_id, tmp ), "i = %d: got %s\n", i, wine_dbgstr_w(token_id) );
|
||||
|
||||
CoTaskMemFree( token_id );
|
||||
ISpObjectToken_Release( token );
|
||||
}
|
||||
|
||||
IEnumSpObjectTokens_Release( enum_tokens );
|
||||
|
||||
ISpObjectTokenCategory_Release( cat );
|
||||
}
|
||||
|
||||
|
@ -205,8 +246,8 @@ static void test_token_enum(void)
|
|||
{
|
||||
ISpObjectTokenEnumBuilder *token_enum;
|
||||
HRESULT hr;
|
||||
ISpObjectToken *tokens[3];
|
||||
ISpObjectToken *out_tokens[3];
|
||||
ISpObjectToken *tokens[5];
|
||||
ISpObjectToken *out_tokens[5];
|
||||
WCHAR token_id[MAX_PATH];
|
||||
ULONG count;
|
||||
int i;
|
||||
|
@ -234,7 +275,7 @@ static void test_token_enum(void)
|
|||
ok( hr == S_FALSE, "got %08lx\n", hr );
|
||||
ok( count == 0, "got %lu\n", count );
|
||||
|
||||
for ( i = 0; i < 3; i++ ) {
|
||||
for ( i = 0; i < 5; i++ ) {
|
||||
hr = CoCreateInstance( &CLSID_SpObjectToken, NULL, CLSCTX_INPROC_SERVER,
|
||||
&IID_ISpObjectToken, (void **)&tokens[i] );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
|
@ -273,7 +314,96 @@ static void test_token_enum(void)
|
|||
|
||||
ISpObjectTokenEnumBuilder_Release( token_enum );
|
||||
|
||||
for ( i = 0; i < 3; i++ ) ISpObjectToken_Release( tokens[i] );
|
||||
hr = CoCreateInstance( &CLSID_SpObjectTokenEnum, NULL, CLSCTX_INPROC_SERVER,
|
||||
&IID_ISpObjectTokenEnumBuilder, (void **)&token_enum );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
|
||||
/* Vendor attribute must exist */
|
||||
hr = ISpObjectTokenEnumBuilder_SetAttribs( token_enum, L"Vendor", NULL );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
hr = ISpObjectTokenEnumBuilder_AddTokens( token_enum, 5, tokens );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
|
||||
count = 0xdeadbeef;
|
||||
hr = ISpObjectTokenEnumBuilder_Next( token_enum, 5, &out_tokens[0], &count );
|
||||
ok( hr == S_FALSE, "got %08lx\n", hr );
|
||||
ok( count == 4, "got %lu\n", count );
|
||||
|
||||
ISpObjectTokenEnumBuilder_Release( token_enum );
|
||||
|
||||
hr = CoCreateInstance( &CLSID_SpObjectTokenEnum, NULL, CLSCTX_INPROC_SERVER,
|
||||
&IID_ISpObjectTokenEnumBuilder, (void **)&token_enum );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
|
||||
/* Vendor attribute must contain Vendor1 */
|
||||
hr = ISpObjectTokenEnumBuilder_SetAttribs( token_enum, L"Vendor=Vendor1", NULL );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
hr = ISpObjectTokenEnumBuilder_AddTokens( token_enum, 5, tokens );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
|
||||
count = 0xdeadbeef;
|
||||
hr = ISpObjectTokenEnumBuilder_Next( token_enum, 5, &out_tokens[0], &count );
|
||||
ok( hr == S_FALSE, "got %08lx\n", hr );
|
||||
ok( count == 2, "got %lu\n", count );
|
||||
|
||||
ISpObjectTokenEnumBuilder_Release( token_enum );
|
||||
|
||||
hr = CoCreateInstance( &CLSID_SpObjectTokenEnum, NULL, CLSCTX_INPROC_SERVER,
|
||||
&IID_ISpObjectTokenEnumBuilder, (void **)&token_enum );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
|
||||
/* Vendor attribute must not contain Vendor1 */
|
||||
hr = ISpObjectTokenEnumBuilder_SetAttribs( token_enum, L"Vendor!=Vendor1", NULL );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
hr = ISpObjectTokenEnumBuilder_AddTokens( token_enum, 5, tokens );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
|
||||
count = 0xdeadbeef;
|
||||
hr = ISpObjectTokenEnumBuilder_Next( token_enum, 5, &out_tokens[0], &count );
|
||||
ok( hr == S_FALSE, "got %08lx\n", hr );
|
||||
ok( count == 3, "got %lu\n", count );
|
||||
|
||||
ISpObjectTokenEnumBuilder_Release( token_enum );
|
||||
|
||||
hr = CoCreateInstance( &CLSID_SpObjectTokenEnum, NULL, CLSCTX_INPROC_SERVER,
|
||||
&IID_ISpObjectTokenEnumBuilder, (void **)&token_enum );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
|
||||
/* Vendor attribute must contain Vendor1 and Language attribute must contain 407 */
|
||||
hr = ISpObjectTokenEnumBuilder_SetAttribs( token_enum, L"Vendor=Vendor1;Language=407", NULL );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
hr = ISpObjectTokenEnumBuilder_AddTokens( token_enum, 5, tokens );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
|
||||
count = 0xdeadbeef;
|
||||
hr = ISpObjectTokenEnumBuilder_Next( token_enum, 5, &out_tokens[0], &count );
|
||||
ok( hr == S_FALSE, "got %08lx\n", hr );
|
||||
ok( count == 1, "got %lu\n", count );
|
||||
|
||||
hr = CoCreateInstance( &CLSID_SpObjectTokenEnum, NULL, CLSCTX_INPROC_SERVER,
|
||||
&IID_ISpObjectTokenEnumBuilder, (void **)&token_enum );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
|
||||
hr = ISpObjectTokenEnumBuilder_SetAttribs( token_enum, L"Language=409",
|
||||
L"Vendor=Vendor1;Age=Child;Gender=Female" );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
hr = ISpObjectTokenEnumBuilder_AddTokens( token_enum, 5, tokens );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
|
||||
hr = ISpObjectTokenEnumBuilder_Sort( token_enum, NULL );
|
||||
ok( hr == S_OK, "got %08lx\n", hr );
|
||||
|
||||
count = 0xdeadbeef;
|
||||
hr = ISpObjectTokenEnumBuilder_Next( token_enum, 5, &out_tokens[0], &count );
|
||||
ok( hr == S_FALSE, "got %08lx\n", hr );
|
||||
ok( count == 3, "got %lu\n", count );
|
||||
ok( out_tokens[0] == tokens[2], "got %p\n", out_tokens[0] );
|
||||
ok( out_tokens[1] == tokens[1], "got %p\n", out_tokens[1] );
|
||||
ok( out_tokens[2] == tokens[0], "got %p\n", out_tokens[2] );
|
||||
|
||||
ISpObjectTokenEnumBuilder_Release( token_enum );
|
||||
|
||||
for ( i = 0; i < 5; i++ ) ISpObjectToken_Release( tokens[i] );
|
||||
}
|
||||
|
||||
static void test_default_token_id(void)
|
||||
|
|
|
@ -908,6 +908,104 @@ out_of_mem:
|
|||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
static HRESULT score_attributes( ISpObjectToken *token, const WCHAR *attrs,
|
||||
BOOL match_all, uint64_t *score )
|
||||
{
|
||||
ISpDataKey *attrs_key;
|
||||
WCHAR *attr, *attr_ctx, *buf;
|
||||
BOOL match[64];
|
||||
unsigned int i, j;
|
||||
HRESULT hr;
|
||||
|
||||
if (!attrs)
|
||||
{
|
||||
*score = 1;
|
||||
return S_OK;
|
||||
}
|
||||
*score = 0;
|
||||
|
||||
if (FAILED(hr = ISpObjectToken_OpenKey( token, L"Attributes", &attrs_key )))
|
||||
return hr == SPERR_NOT_FOUND ? S_OK : hr;
|
||||
|
||||
memset( match, 0, sizeof(match) );
|
||||
|
||||
/* attrs is a semicolon-separated list of attribute clauses.
|
||||
* Each clause consists of an attribute name and an optional operator and value.
|
||||
* The meaning of a clause depends on the operator given:
|
||||
* If no operator is given, the attribute must exist.
|
||||
* If the operator is '=', the attribute must contain the given value.
|
||||
* If the operator is '!=', the attribute must not exist or contain the given value.
|
||||
*/
|
||||
if (!(buf = wcsdup( attrs ))) return E_OUTOFMEMORY;
|
||||
for ( attr = wcstok_s( buf, L";", &attr_ctx ), i = 0; attr && i < 64;
|
||||
attr = wcstok_s( NULL, L";", &attr_ctx ), i++ )
|
||||
{
|
||||
WCHAR *p = wcspbrk( attr, L"!=" );
|
||||
WCHAR op = p ? *p : L'\0';
|
||||
WCHAR *value = NULL, *res;
|
||||
if ( p )
|
||||
{
|
||||
if ( op == L'=' )
|
||||
value = p + 1;
|
||||
else if ( op == L'!' )
|
||||
{
|
||||
if ( *(p + 1) != L'=' )
|
||||
{
|
||||
WARN( "invalid attr operator '!%lc'.\n", *(p + 1) );
|
||||
hr = E_INVALIDARG;
|
||||
goto done;
|
||||
}
|
||||
value = p + 2;
|
||||
}
|
||||
*p = L'\0';
|
||||
}
|
||||
|
||||
hr = ISpDataKey_GetStringValue( attrs_key, attr, &res );
|
||||
if ( p ) *p = op;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if ( !op )
|
||||
match[i] = TRUE;
|
||||
else
|
||||
{
|
||||
WCHAR *val, *val_ctx;
|
||||
|
||||
match[i] = FALSE;
|
||||
for ( val = wcstok_s( res, L";", &val_ctx ); val && !match[i];
|
||||
val = wcstok_s( NULL, L";", &val_ctx ) )
|
||||
match[i] = !wcscmp( val, value );
|
||||
|
||||
if (op == L'!') match[i] = !match[i];
|
||||
}
|
||||
CoTaskMemFree( res );
|
||||
}
|
||||
else if (hr == SPERR_NOT_FOUND)
|
||||
{
|
||||
hr = S_OK;
|
||||
if (op == L'!') match[i] = TRUE;
|
||||
}
|
||||
else
|
||||
goto done;
|
||||
|
||||
if ( match_all && !match[i] )
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ( attr )
|
||||
hr = E_INVALIDARG;
|
||||
else
|
||||
{
|
||||
/* Attributes in attrs are ordered from highest to lowest priority. */
|
||||
for ( j = 0; j < i; j++ )
|
||||
if ( match[j] )
|
||||
*score |= 1ULL << (i - 1 - j);
|
||||
}
|
||||
|
||||
done:
|
||||
free( buf );
|
||||
return hr;
|
||||
}
|
||||
|
||||
static BOOL grow_tokens_array( struct token_enum *This )
|
||||
{
|
||||
struct token_with_score *new_tokens;
|
||||
|
@ -938,26 +1036,29 @@ static HRESULT WINAPI token_enum_AddTokens( ISpObjectTokenEnumBuilder *iface,
|
|||
{
|
||||
struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface );
|
||||
ULONG i;
|
||||
uint64_t score;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE( "(%p)->(%lu %p)\n", iface, num, tokens );
|
||||
|
||||
if (!This->init) return SPERR_UNINITIALIZED;
|
||||
if (!tokens) return E_POINTER;
|
||||
|
||||
if (This->req || This->opt)
|
||||
{
|
||||
FIXME( "filtering and sorting of tokens is not implemented\n" );
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
for ( i = 0; i < num; i++ )
|
||||
{
|
||||
if (!tokens[i]) return E_POINTER;
|
||||
|
||||
hr = score_attributes( tokens[i], This->req, TRUE, &score );
|
||||
if (FAILED(hr)) return hr;
|
||||
if (!score) continue;
|
||||
|
||||
hr = score_attributes( tokens[i], This->opt, FALSE, &score );
|
||||
if (FAILED(hr)) return hr;
|
||||
|
||||
if (!grow_tokens_array( This )) return E_OUTOFMEMORY;
|
||||
ISpObjectToken_AddRef( tokens[i] );
|
||||
This->tokens[This->count].token = tokens[i];
|
||||
This->tokens[This->count].score = 0;
|
||||
This->tokens[This->count].score = score;
|
||||
This->count++;
|
||||
}
|
||||
|
||||
|
@ -979,12 +1080,21 @@ static HRESULT WINAPI token_enum_AddTokensFromTokenEnum( ISpObjectTokenEnumBuild
|
|||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static int __cdecl token_with_score_cmp( const void *a, const void *b )
|
||||
{
|
||||
const struct token_with_score *ta = a, *tb = b;
|
||||
|
||||
if (ta->score > tb->score) return -1;
|
||||
else if (ta->score < tb->score) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI token_enum_Sort( ISpObjectTokenEnumBuilder *iface,
|
||||
LPCWSTR first )
|
||||
{
|
||||
struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface );
|
||||
|
||||
FIXME( "(%p)->(%s): semi-stub\n", iface, debugstr_w(first) );
|
||||
TRACE( "(%p)->(%s).\n", iface, debugstr_w(first) );
|
||||
|
||||
if (!This->init) return SPERR_UNINITIALIZED;
|
||||
if (!This->tokens) return S_OK;
|
||||
|
@ -996,10 +1106,7 @@ static HRESULT WINAPI token_enum_Sort( ISpObjectTokenEnumBuilder *iface,
|
|||
}
|
||||
|
||||
if (This->opt)
|
||||
{
|
||||
FIXME( "sorting with optional attributes is not implemented.\n" );
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
qsort( This->tokens, This->count, sizeof(*This->tokens), token_with_score_cmp );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue