Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
db2640d0
Commit
db2640d0
authored
May 26, 2023
by
Shaun Ren
Committed by
Alexandre Julliard
Jun 02, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
sapi: Implement token filtering and sorting in ISpObjectTokenEnumBuilder.
parent
f286ee9b
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
253 additions
and
16 deletions
+253
-16
token.c
dlls/sapi/tests/token.c
+134
-4
token.c
dlls/sapi/token.c
+119
-12
No files found.
dlls/sapi/tests/token.c
View file @
db2640d0
...
@@ -172,6 +172,10 @@ static void test_token_category(void)
...
@@ -172,6 +172,10 @@ static void test_token_category(void)
IEnumSpObjectTokens
*
enum_tokens
;
IEnumSpObjectTokens
*
enum_tokens
;
HRESULT
hr
;
HRESULT
hr
;
ULONG
count
;
ULONG
count
;
int
i
;
ISpObjectToken
*
token
;
WCHAR
*
token_id
;
WCHAR
tmp
[
MAX_PATH
];
hr
=
CoCreateInstance
(
&
CLSID_SpObjectTokenCategory
,
NULL
,
CLSCTX_INPROC_SERVER
,
hr
=
CoCreateInstance
(
&
CLSID_SpObjectTokenCategory
,
NULL
,
CLSCTX_INPROC_SERVER
,
&
IID_ISpObjectTokenCategory
,
(
void
**
)
&
cat
);
&
IID_ISpObjectTokenCategory
,
(
void
**
)
&
cat
);
...
@@ -198,6 +202,43 @@ static void test_token_category(void)
...
@@ -198,6 +202,43 @@ static void test_token_category(void)
ok
(
count
==
5
,
"got %lu
\n
"
,
count
);
ok
(
count
==
5
,
"got %lu
\n
"
,
count
);
IEnumSpObjectTokens_Release
(
enum_tokens
);
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
);
ISpObjectTokenCategory_Release
(
cat
);
}
}
...
@@ -205,8 +246,8 @@ static void test_token_enum(void)
...
@@ -205,8 +246,8 @@ static void test_token_enum(void)
{
{
ISpObjectTokenEnumBuilder
*
token_enum
;
ISpObjectTokenEnumBuilder
*
token_enum
;
HRESULT
hr
;
HRESULT
hr
;
ISpObjectToken
*
tokens
[
3
];
ISpObjectToken
*
tokens
[
5
];
ISpObjectToken
*
out_tokens
[
3
];
ISpObjectToken
*
out_tokens
[
5
];
WCHAR
token_id
[
MAX_PATH
];
WCHAR
token_id
[
MAX_PATH
];
ULONG
count
;
ULONG
count
;
int
i
;
int
i
;
...
@@ -234,7 +275,7 @@ static void test_token_enum(void)
...
@@ -234,7 +275,7 @@ static void test_token_enum(void)
ok
(
hr
==
S_FALSE
,
"got %08lx
\n
"
,
hr
);
ok
(
hr
==
S_FALSE
,
"got %08lx
\n
"
,
hr
);
ok
(
count
==
0
,
"got %lu
\n
"
,
count
);
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
,
hr
=
CoCreateInstance
(
&
CLSID_SpObjectToken
,
NULL
,
CLSCTX_INPROC_SERVER
,
&
IID_ISpObjectToken
,
(
void
**
)
&
tokens
[
i
]
);
&
IID_ISpObjectToken
,
(
void
**
)
&
tokens
[
i
]
);
ok
(
hr
==
S_OK
,
"got %08lx
\n
"
,
hr
);
ok
(
hr
==
S_OK
,
"got %08lx
\n
"
,
hr
);
...
@@ -273,7 +314,96 @@ static void test_token_enum(void)
...
@@ -273,7 +314,96 @@ static void test_token_enum(void)
ISpObjectTokenEnumBuilder_Release
(
token_enum
);
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
)
static
void
test_default_token_id
(
void
)
...
...
dlls/sapi/token.c
View file @
db2640d0
...
@@ -908,6 +908,104 @@ out_of_mem:
...
@@ -908,6 +908,104 @@ out_of_mem:
return
E_OUTOFMEMORY
;
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
)
static
BOOL
grow_tokens_array
(
struct
token_enum
*
This
)
{
{
struct
token_with_score
*
new_tokens
;
struct
token_with_score
*
new_tokens
;
...
@@ -938,26 +1036,29 @@ static HRESULT WINAPI token_enum_AddTokens( ISpObjectTokenEnumBuilder *iface,
...
@@ -938,26 +1036,29 @@ static HRESULT WINAPI token_enum_AddTokens( ISpObjectTokenEnumBuilder *iface,
{
{
struct
token_enum
*
This
=
impl_from_ISpObjectTokenEnumBuilder
(
iface
);
struct
token_enum
*
This
=
impl_from_ISpObjectTokenEnumBuilder
(
iface
);
ULONG
i
;
ULONG
i
;
uint64_t
score
;
HRESULT
hr
;
TRACE
(
"(%p)->(%lu %p)
\n
"
,
iface
,
num
,
tokens
);
TRACE
(
"(%p)->(%lu %p)
\n
"
,
iface
,
num
,
tokens
);
if
(
!
This
->
init
)
return
SPERR_UNINITIALIZED
;
if
(
!
This
->
init
)
return
SPERR_UNINITIALIZED
;
if
(
!
tokens
)
return
E_POINTER
;
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
++
)
for
(
i
=
0
;
i
<
num
;
i
++
)
{
{
if
(
!
tokens
[
i
])
return
E_POINTER
;
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
;
if
(
!
grow_tokens_array
(
This
))
return
E_OUTOFMEMORY
;
ISpObjectToken_AddRef
(
tokens
[
i
]
);
ISpObjectToken_AddRef
(
tokens
[
i
]
);
This
->
tokens
[
This
->
count
].
token
=
tokens
[
i
];
This
->
tokens
[
This
->
count
].
token
=
tokens
[
i
];
This
->
tokens
[
This
->
count
].
score
=
0
;
This
->
tokens
[
This
->
count
].
score
=
score
;
This
->
count
++
;
This
->
count
++
;
}
}
...
@@ -979,12 +1080,21 @@ static HRESULT WINAPI token_enum_AddTokensFromTokenEnum( ISpObjectTokenEnumBuild
...
@@ -979,12 +1080,21 @@ static HRESULT WINAPI token_enum_AddTokensFromTokenEnum( ISpObjectTokenEnumBuild
return
E_NOTIMPL
;
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
,
static
HRESULT
WINAPI
token_enum_Sort
(
ISpObjectTokenEnumBuilder
*
iface
,
LPCWSTR
first
)
LPCWSTR
first
)
{
{
struct
token_enum
*
This
=
impl_from_ISpObjectTokenEnumBuilder
(
iface
);
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
->
init
)
return
SPERR_UNINITIALIZED
;
if
(
!
This
->
tokens
)
return
S_OK
;
if
(
!
This
->
tokens
)
return
S_OK
;
...
@@ -996,10 +1106,7 @@ static HRESULT WINAPI token_enum_Sort( ISpObjectTokenEnumBuilder *iface,
...
@@ -996,10 +1106,7 @@ static HRESULT WINAPI token_enum_Sort( ISpObjectTokenEnumBuilder *iface,
}
}
if
(
This
->
opt
)
if
(
This
->
opt
)
{
qsort
(
This
->
tokens
,
This
->
count
,
sizeof
(
*
This
->
tokens
),
token_with_score_cmp
);
FIXME
(
"sorting with optional attributes is not implemented.
\n
"
);
return
E_NOTIMPL
;
}
return
S_OK
;
return
S_OK
;
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment