imagehlp: Use the IMAGE_FIRST_SECTION helper macro.
[wine.git] / dlls / sapi / token.c
blobf599bdb6b144c7c41ae43492f3f71926552f2032
1 /*
2 * Speech API (SAPI) token implementation.
4 * Copyright (C) 2017 Huw Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdint.h>
24 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "objbase.h"
29 #include "sapiddk.h"
30 #include "sperror.h"
32 #include "wine/debug.h"
34 #include "sapi_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(sapi);
38 struct data_key
40 ISpRegDataKey ISpRegDataKey_iface;
41 LONG ref;
43 HKEY key;
46 static struct data_key *impl_from_ISpRegDataKey( ISpRegDataKey *iface )
48 return CONTAINING_RECORD( iface, struct data_key, ISpRegDataKey_iface );
51 struct object_token
53 ISpObjectToken ISpObjectToken_iface;
54 LONG ref;
56 ISpRegDataKey *data_key;
57 WCHAR *token_id;
60 static struct object_token *impl_from_ISpObjectToken( ISpObjectToken *iface )
62 return CONTAINING_RECORD( iface, struct object_token, ISpObjectToken_iface );
65 static HRESULT WINAPI data_key_QueryInterface( ISpRegDataKey *iface, REFIID iid, void **obj )
67 struct data_key *This = impl_from_ISpRegDataKey( iface );
69 TRACE( "(%p)->(%s %p)\n", This, debugstr_guid( iid ), obj );
71 if (IsEqualIID( iid, &IID_IUnknown ) ||
72 IsEqualIID( iid, &IID_ISpDataKey ) ||
73 IsEqualIID( iid, &IID_ISpRegDataKey ))
75 ISpRegDataKey_AddRef( iface );
76 *obj = iface;
77 return S_OK;
80 FIXME( "interface %s not implemented\n", debugstr_guid( iid ) );
81 *obj = NULL;
82 return E_NOINTERFACE;
85 static ULONG WINAPI data_key_AddRef( ISpRegDataKey *iface )
87 struct data_key *This = impl_from_ISpRegDataKey( iface );
88 ULONG ref = InterlockedIncrement( &This->ref );
90 TRACE( "(%p) ref = %lu\n", This, ref );
91 return ref;
94 static ULONG WINAPI data_key_Release( ISpRegDataKey *iface )
96 struct data_key *This = impl_from_ISpRegDataKey( iface );
97 ULONG ref = InterlockedDecrement(&This->ref);
99 TRACE( "(%p) ref = %lu\n", This, ref );
101 if (!ref)
103 if (This->key) RegCloseKey( This->key );
104 free( This );
107 return ref;
110 static HRESULT WINAPI data_key_SetData( ISpRegDataKey *iface, LPCWSTR name,
111 ULONG size, const BYTE *data )
113 FIXME( "stub\n" );
114 return E_NOTIMPL;
117 static HRESULT WINAPI data_key_GetData( ISpRegDataKey *iface, LPCWSTR name,
118 ULONG *size, BYTE *data )
120 FIXME( "stub\n" );
121 return E_NOTIMPL;
124 static HRESULT WINAPI data_key_SetStringValue( ISpRegDataKey *iface,
125 LPCWSTR name, LPCWSTR value )
127 struct data_key *This = impl_from_ISpRegDataKey( iface );
128 DWORD ret, size;
130 TRACE( "%p, %s, %s\n", This, debugstr_w(name), debugstr_w(value) );
132 if (!This->key)
133 return E_HANDLE;
135 size = (wcslen(value) + 1) * sizeof(WCHAR);
136 ret = RegSetValueExW( This->key, name, 0, REG_SZ, (BYTE *)value, size );
138 return HRESULT_FROM_WIN32(ret);
141 static HRESULT WINAPI data_key_GetStringValue( ISpRegDataKey *iface,
142 LPCWSTR name, LPWSTR *value )
144 struct data_key *This = impl_from_ISpRegDataKey( iface );
145 DWORD ret, size;
146 WCHAR *content;
148 TRACE( "%p, %s, %p\n", This, debugstr_w(name), value);
150 if (!This->key)
151 return E_HANDLE;
153 size = 0;
154 ret = RegGetValueW( This->key, NULL, name, RRF_RT_REG_SZ, NULL, NULL, &size );
155 if (ret != ERROR_SUCCESS)
156 return SPERR_NOT_FOUND;
158 content = CoTaskMemAlloc(size);
159 if (!content)
160 return E_OUTOFMEMORY;
162 ret = RegGetValueW( This->key, NULL, name, RRF_RT_REG_SZ, NULL, content, &size );
163 if (ret != ERROR_SUCCESS)
165 CoTaskMemFree(content);
166 return HRESULT_FROM_WIN32(ret);
169 *value = content;
170 return S_OK;
173 static HRESULT WINAPI data_key_SetDWORD( ISpRegDataKey *iface,
174 LPCWSTR name, DWORD value )
176 FIXME( "stub\n" );
177 return E_NOTIMPL;
180 static HRESULT WINAPI data_key_GetDWORD( ISpRegDataKey *iface,
181 LPCWSTR name, DWORD *pdwValue )
183 FIXME( "stub\n" );
184 return E_NOTIMPL;
187 static HRESULT WINAPI data_key_OpenKey( ISpRegDataKey *iface,
188 LPCWSTR name, ISpDataKey **sub_key )
190 struct data_key *This = impl_from_ISpRegDataKey( iface );
191 ISpRegDataKey *spregkey;
192 HRESULT hr;
193 HKEY key;
194 LONG ret;
196 TRACE( "%p, %s, %p\n", This, debugstr_w(name), sub_key );
198 ret = RegOpenKeyExW( This->key, name, 0, KEY_ALL_ACCESS, &key );
199 if (ret != ERROR_SUCCESS)
200 return SPERR_NOT_FOUND;
202 hr = data_key_create( NULL, &IID_ISpRegDataKey, (void**)&spregkey );
203 if (FAILED(hr))
205 RegCloseKey( key );
206 return hr;
209 hr = ISpRegDataKey_SetKey( spregkey, key, FALSE );
210 if (FAILED(hr))
212 RegCloseKey( key );
213 ISpRegDataKey_Release( spregkey );
214 return hr;
217 hr = ISpRegDataKey_QueryInterface( spregkey, &IID_ISpDataKey, (void**)sub_key );
218 ISpRegDataKey_Release( spregkey );
220 return hr;
223 static HRESULT WINAPI data_key_CreateKey( ISpRegDataKey *iface,
224 LPCWSTR name, ISpDataKey **sub_key )
226 struct data_key *This = impl_from_ISpRegDataKey( iface );
227 ISpRegDataKey *spregkey;
228 HRESULT hr;
229 HKEY key;
230 LONG res;
232 TRACE( "%p, %s, %p\n", This, debugstr_w(name), sub_key );
234 res = RegCreateKeyExW( This->key, name, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &key, NULL );
235 if (res != ERROR_SUCCESS)
236 return HRESULT_FROM_WIN32(res);
238 hr = data_key_create(NULL, &IID_ISpRegDataKey, (void**)&spregkey);
239 if (SUCCEEDED(hr))
241 hr = ISpRegDataKey_SetKey(spregkey, key, FALSE);
242 if (SUCCEEDED(hr))
243 hr = ISpRegDataKey_QueryInterface(spregkey, &IID_ISpDataKey, (void**)sub_key);
244 ISpRegDataKey_Release(spregkey);
247 return hr;
250 static HRESULT WINAPI data_key_DeleteKey( ISpRegDataKey *iface, LPCWSTR name )
252 FIXME( "stub\n" );
253 return E_NOTIMPL;
256 static HRESULT WINAPI data_key_DeleteValue( ISpRegDataKey *iface, LPCWSTR name )
258 FIXME( "stub\n" );
259 return E_NOTIMPL;
262 static HRESULT WINAPI data_key_EnumKeys( ISpRegDataKey *iface,
263 ULONG index, LPWSTR *sub_key )
265 FIXME( "stub\n" );
266 return E_NOTIMPL;
269 static HRESULT WINAPI data_key_EnumValues( ISpRegDataKey *iface,
270 ULONG index, LPWSTR *value )
272 FIXME( "stub\n" );
273 return E_NOTIMPL;
276 static HRESULT WINAPI data_key_SetKey( ISpRegDataKey *iface,
277 HKEY key, BOOL read_only )
279 struct data_key *This = impl_from_ISpRegDataKey( iface );
281 TRACE( "(%p)->(%p %d)\n", This, key, read_only );
283 if (This->key) return SPERR_ALREADY_INITIALIZED;
285 /* read_only is ignored in Windows implementations. */
286 This->key = key;
287 return S_OK;
290 const struct ISpRegDataKeyVtbl data_key_vtbl =
292 data_key_QueryInterface,
293 data_key_AddRef,
294 data_key_Release,
295 data_key_SetData,
296 data_key_GetData,
297 data_key_SetStringValue,
298 data_key_GetStringValue,
299 data_key_SetDWORD,
300 data_key_GetDWORD,
301 data_key_OpenKey,
302 data_key_CreateKey,
303 data_key_DeleteKey,
304 data_key_DeleteValue,
305 data_key_EnumKeys,
306 data_key_EnumValues,
307 data_key_SetKey
310 HRESULT data_key_create( IUnknown *outer, REFIID iid, void **obj )
312 struct data_key *This = malloc( sizeof(*This) );
313 HRESULT hr;
315 if (!This) return E_OUTOFMEMORY;
316 This->ISpRegDataKey_iface.lpVtbl = &data_key_vtbl;
317 This->ref = 1;
318 This->key = NULL;
320 hr = ISpRegDataKey_QueryInterface( &This->ISpRegDataKey_iface, iid, obj );
322 ISpRegDataKey_Release( &This->ISpRegDataKey_iface );
323 return hr;
326 struct token_category
328 ISpObjectTokenCategory ISpObjectTokenCategory_iface;
329 LONG ref;
331 ISpRegDataKey *data_key;
332 WCHAR *id;
335 static struct token_category *impl_from_ISpObjectTokenCategory( ISpObjectTokenCategory *iface )
337 return CONTAINING_RECORD( iface, struct token_category, ISpObjectTokenCategory_iface );
340 static HRESULT WINAPI token_category_QueryInterface( ISpObjectTokenCategory *iface,
341 REFIID iid, void **obj )
343 struct token_category *This = impl_from_ISpObjectTokenCategory( iface );
345 TRACE( "(%p)->(%s %p)\n", This, debugstr_guid( iid ), obj );
347 if (IsEqualIID( iid, &IID_IUnknown ) ||
348 IsEqualIID( iid, &IID_ISpDataKey ) ||
349 IsEqualIID( iid, &IID_ISpObjectTokenCategory ))
351 ISpObjectTokenCategory_AddRef( iface );
352 *obj = iface;
353 return S_OK;
356 FIXME( "interface %s not implemented\n", debugstr_guid( iid ) );
357 *obj = NULL;
358 return E_NOINTERFACE;
361 static ULONG WINAPI token_category_AddRef( ISpObjectTokenCategory *iface )
363 struct token_category *This = impl_from_ISpObjectTokenCategory( iface );
364 ULONG ref = InterlockedIncrement( &This->ref );
366 TRACE( "(%p) ref = %lu\n", This, ref );
367 return ref;
370 static ULONG WINAPI token_category_Release( ISpObjectTokenCategory *iface )
372 struct token_category *This = impl_from_ISpObjectTokenCategory( iface );
373 ULONG ref = InterlockedDecrement(&This->ref);
375 TRACE( "(%p) ref = %lu\n", This, ref );
377 if (!ref)
379 if (This->data_key) ISpRegDataKey_Release( This->data_key );
380 free( This->id );
381 free( This );
383 return ref;
386 static HRESULT WINAPI token_category_SetData( ISpObjectTokenCategory *iface,
387 LPCWSTR name, ULONG size,
388 const BYTE *data )
390 FIXME( "stub\n" );
391 return E_NOTIMPL;
394 static HRESULT WINAPI token_category_GetData( ISpObjectTokenCategory *iface,
395 LPCWSTR name, ULONG *size,
396 BYTE *data )
398 FIXME( "stub\n" );
399 return E_NOTIMPL;
402 static HRESULT WINAPI token_category_SetStringValue( ISpObjectTokenCategory *iface,
403 LPCWSTR name, LPCWSTR value )
405 FIXME( "stub\n" );
406 return E_NOTIMPL;
409 static HRESULT WINAPI token_category_GetStringValue( ISpObjectTokenCategory *iface,
410 LPCWSTR name, LPWSTR *value )
412 FIXME( "stub\n" );
413 return E_NOTIMPL;
416 static HRESULT WINAPI token_category_SetDWORD( ISpObjectTokenCategory *iface,
417 LPCWSTR name, DWORD value )
419 FIXME( "stub\n" );
420 return E_NOTIMPL;
423 static HRESULT WINAPI token_category_GetDWORD( ISpObjectTokenCategory *iface,
424 LPCWSTR name, DWORD *pdwValue )
426 FIXME( "stub\n" );
427 return E_NOTIMPL;
430 static HRESULT WINAPI token_category_OpenKey( ISpObjectTokenCategory *iface,
431 LPCWSTR name, ISpDataKey **sub_key )
433 FIXME( "stub\n" );
434 return E_NOTIMPL;
437 static HRESULT WINAPI token_category_CreateKey( ISpObjectTokenCategory *iface,
438 LPCWSTR name, ISpDataKey **sub_key )
440 FIXME( "stub\n" );
441 return E_NOTIMPL;
444 static HRESULT WINAPI token_category_DeleteKey( ISpObjectTokenCategory *iface,
445 LPCWSTR name )
447 FIXME( "stub\n" );
448 return E_NOTIMPL;
451 static HRESULT WINAPI token_category_DeleteValue( ISpObjectTokenCategory *iface,
452 LPCWSTR name )
454 FIXME( "stub\n" );
455 return E_NOTIMPL;
458 static HRESULT WINAPI token_category_EnumKeys( ISpObjectTokenCategory *iface,
459 ULONG index, LPWSTR *sub_key )
461 FIXME( "stub\n" );
462 return E_NOTIMPL;
465 static HRESULT WINAPI token_category_EnumValues( ISpObjectTokenCategory *iface,
466 ULONG index, LPWSTR *value )
468 FIXME( "stub\n" );
469 return E_NOTIMPL;
472 static HRESULT parse_cat_id( const WCHAR *str, HKEY *root, const WCHAR **sub_key )
474 struct table
476 const WCHAR *name;
477 unsigned int len;
478 HKEY key;
479 } table[] =
481 #define X(s) s, ARRAY_SIZE(s) - 1
482 { X(L"HKEY_LOCAL_MACHINE\\"), HKEY_LOCAL_MACHINE },
483 { X(L"HKEY_CURRENT_USER\\"), HKEY_CURRENT_USER },
484 { NULL }
485 #undef X
487 struct table *ptr;
488 int len = lstrlenW( str );
490 for (ptr = table; ptr->name; ptr++)
492 if (len >= ptr->len && !wcsncmp( str, ptr->name, ptr->len ))
494 *root = ptr->key;
495 *sub_key = str + ptr->len;
496 return S_OK;
499 return S_FALSE;
502 static HRESULT WINAPI create_data_key_with_hkey( HKEY key, ISpRegDataKey **data_key )
504 HRESULT hr;
506 if (FAILED(hr = CoCreateInstance( &CLSID_SpDataKey, NULL, CLSCTX_INPROC_SERVER,
507 &IID_ISpRegDataKey, (void **)data_key ) ))
508 return hr;
510 if (FAILED(hr = ISpRegDataKey_SetKey( *data_key, key, TRUE )))
512 ISpRegDataKey_Release( *data_key );
513 *data_key = NULL;
516 return hr;
519 static HRESULT WINAPI token_category_SetId( ISpObjectTokenCategory *iface,
520 LPCWSTR id, BOOL create )
522 struct token_category *This = impl_from_ISpObjectTokenCategory( iface );
523 HKEY root, key;
524 const WCHAR *subkey;
525 LONG res;
526 HRESULT hr;
528 TRACE( "(%p)->(%s %d)\n", This, debugstr_w( id ), create );
530 if (This->data_key) return SPERR_ALREADY_INITIALIZED;
532 hr = parse_cat_id( id, &root, &subkey );
533 if (hr != S_OK) return SPERR_INVALID_REGISTRY_KEY;
535 if (create)
536 res = RegCreateKeyExW( root, subkey, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &key, NULL );
537 else
538 res = RegOpenKeyExW( root, subkey, 0, KEY_ALL_ACCESS, &key );
539 if (res) return SPERR_INVALID_REGISTRY_KEY;
541 if (FAILED(hr = create_data_key_with_hkey( key, &This->data_key )))
543 RegCloseKey( key );
544 return hr;
547 This->id = wcsdup( id );
549 return hr;
552 static HRESULT WINAPI token_category_GetId( ISpObjectTokenCategory *iface,
553 LPWSTR *id )
555 FIXME( "stub\n" );
556 return E_NOTIMPL;
559 static HRESULT WINAPI token_category_GetDataKey( ISpObjectTokenCategory *iface,
560 SPDATAKEYLOCATION location,
561 ISpDataKey **data_key )
563 FIXME( "stub\n" );
564 return E_NOTIMPL;
567 struct token_with_score
569 ISpObjectToken *token;
570 uint64_t score;
573 struct token_enum
575 ISpObjectTokenEnumBuilder ISpObjectTokenEnumBuilder_iface;
576 LONG ref;
578 BOOL init;
579 WCHAR *req, *opt;
580 struct token_with_score *tokens;
581 ULONG capacity, count;
582 DWORD index;
585 static struct token_enum *impl_from_ISpObjectTokenEnumBuilder( ISpObjectTokenEnumBuilder *iface )
587 return CONTAINING_RECORD( iface, struct token_enum, ISpObjectTokenEnumBuilder_iface );
590 static HRESULT WINAPI token_category_EnumTokens( ISpObjectTokenCategory *iface,
591 LPCWSTR req, LPCWSTR opt,
592 IEnumSpObjectTokens **enum_tokens )
594 struct token_category *This = impl_from_ISpObjectTokenCategory( iface );
595 ISpObjectTokenEnumBuilder *builder;
596 struct data_key *this_data_key;
597 HKEY tokens_key;
598 DWORD count, max_subkey_size, root_len, token_id_size;
599 DWORD size, i;
600 WCHAR *token_id = NULL;
601 ISpObjectToken *token = NULL;
602 HRESULT hr;
604 TRACE( "(%p)->(%s %s %p)\n", This, debugstr_w( req ), debugstr_w( opt ), enum_tokens );
606 if (!This->data_key) return SPERR_UNINITIALIZED;
608 hr = CoCreateInstance( &CLSID_SpObjectTokenEnum, NULL, CLSCTX_ALL,
609 &IID_ISpObjectTokenEnumBuilder, (void **)&builder );
610 if (FAILED(hr)) return hr;
612 hr = ISpObjectTokenEnumBuilder_SetAttribs( builder, req, opt );
613 if (FAILED(hr)) goto fail;
615 this_data_key = impl_from_ISpRegDataKey( This->data_key );
617 if (!RegOpenKeyExW( this_data_key->key, L"Tokens", 0, KEY_ALL_ACCESS, &tokens_key ))
619 RegQueryInfoKeyW( tokens_key, NULL, NULL, NULL, &count, &max_subkey_size, NULL,
620 NULL, NULL, NULL, NULL, NULL );
621 max_subkey_size++;
623 root_len = wcslen( This->id );
624 token_id_size = root_len + sizeof("\\Tokens\\") + max_subkey_size;
625 token_id = malloc( token_id_size * sizeof(WCHAR) );
626 if (!token_id)
628 hr = E_OUTOFMEMORY;
629 goto fail;
631 root_len = swprintf( token_id, token_id_size, L"%ls%lsTokens\\",
632 This->id, This->id[root_len - 1] == L'\\' ? L"" : L"\\" );
634 for ( i = 0; i < count; i++ )
636 size = max_subkey_size;
637 hr = HRESULT_FROM_WIN32(RegEnumKeyExW( tokens_key, i, token_id + root_len, &size, NULL, NULL, NULL, NULL ));
638 if (FAILED(hr)) goto fail;
640 hr = token_create( NULL, &IID_ISpObjectToken, (void **)&token );
641 if (FAILED(hr)) goto fail;
643 hr = ISpObjectToken_SetId( token, NULL, token_id, FALSE );
644 if (FAILED(hr)) goto fail;
646 hr = ISpObjectTokenEnumBuilder_AddTokens( builder, 1, &token );
647 if (FAILED(hr)) goto fail;
648 ISpObjectToken_Release( token );
649 token = NULL;
652 hr = ISpObjectTokenEnumBuilder_Sort( builder, NULL );
653 if (FAILED(hr)) goto fail;
656 hr = ISpObjectTokenEnumBuilder_QueryInterface( builder, &IID_IEnumSpObjectTokens,
657 (void **)enum_tokens );
659 fail:
660 ISpObjectTokenEnumBuilder_Release( builder );
661 if ( token ) ISpObjectToken_Release( token );
662 free( token_id );
663 return hr;
666 static HRESULT WINAPI token_category_SetDefaultTokenId( ISpObjectTokenCategory *iface,
667 LPCWSTR id )
669 FIXME( "stub\n" );
670 return E_NOTIMPL;
673 static HRESULT WINAPI token_category_GetDefaultTokenId( ISpObjectTokenCategory *iface,
674 LPWSTR *id )
676 struct token_category *This = impl_from_ISpObjectTokenCategory( iface );
677 struct data_key *this_data_key;
678 LONG res;
679 WCHAR regvalue[512];
680 DWORD regvalue_size = sizeof( regvalue );
682 FIXME( "(%p)->(%p): semi-stub\n", iface, id );
684 if (!This->data_key)
685 return SPERR_UNINITIALIZED;
687 if (!id)
688 return E_POINTER;
690 /* todo: check HKCU's DefaultTokenId before */
692 this_data_key = impl_from_ISpRegDataKey( This->data_key );
694 res = RegGetValueW( this_data_key->key, NULL, L"DefaultDefaultTokenId", RRF_RT_REG_SZ,
695 NULL, &regvalue, &regvalue_size);
696 if (res == ERROR_FILE_NOT_FOUND) {
697 return SPERR_NOT_FOUND;
698 } else if (res != ERROR_SUCCESS) {
699 /* probably not the correct return value */
700 FIXME( "returning %08lx\n", res );
701 return res;
704 *id = CoTaskMemAlloc( regvalue_size );
705 wcscpy( *id, regvalue );
707 return S_OK;
710 const struct ISpObjectTokenCategoryVtbl token_category_vtbl =
712 token_category_QueryInterface,
713 token_category_AddRef,
714 token_category_Release,
715 token_category_SetData,
716 token_category_GetData,
717 token_category_SetStringValue,
718 token_category_GetStringValue,
719 token_category_SetDWORD,
720 token_category_GetDWORD,
721 token_category_OpenKey,
722 token_category_CreateKey,
723 token_category_DeleteKey,
724 token_category_DeleteValue,
725 token_category_EnumKeys,
726 token_category_EnumValues,
727 token_category_SetId,
728 token_category_GetId,
729 token_category_GetDataKey,
730 token_category_EnumTokens,
731 token_category_SetDefaultTokenId,
732 token_category_GetDefaultTokenId,
735 HRESULT token_category_create( IUnknown *outer, REFIID iid, void **obj )
737 struct token_category *This = malloc( sizeof(*This) );
738 HRESULT hr;
740 if (!This) return E_OUTOFMEMORY;
741 This->ISpObjectTokenCategory_iface.lpVtbl = &token_category_vtbl;
742 This->ref = 1;
743 This->data_key = NULL;
744 This->id = NULL;
746 hr = ISpObjectTokenCategory_QueryInterface( &This->ISpObjectTokenCategory_iface, iid, obj );
748 ISpObjectTokenCategory_Release( &This->ISpObjectTokenCategory_iface );
749 return hr;
752 static HRESULT WINAPI token_enum_QueryInterface( ISpObjectTokenEnumBuilder *iface,
753 REFIID iid, void **obj )
755 struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface );
757 TRACE( "(%p)->(%s %p)\n", This, debugstr_guid( iid ), obj );
759 if (IsEqualIID( iid, &IID_IUnknown ) ||
760 IsEqualIID( iid, &IID_IEnumSpObjectTokens ) ||
761 IsEqualIID( iid, &IID_ISpObjectTokenEnumBuilder ))
763 ISpObjectTokenEnumBuilder_AddRef( iface );
764 *obj = iface;
765 return S_OK;
768 FIXME( "interface %s not implemented\n", debugstr_guid( iid ) );
769 *obj = NULL;
770 return E_NOINTERFACE;
773 static ULONG WINAPI token_enum_AddRef( ISpObjectTokenEnumBuilder *iface )
775 struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface );
776 ULONG ref = InterlockedIncrement( &This->ref );
778 TRACE( "(%p) ref = %lu\n", This, ref );
779 return ref;
782 static ULONG WINAPI token_enum_Release( ISpObjectTokenEnumBuilder *iface )
784 struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface );
785 ULONG ref = InterlockedDecrement(&This->ref);
787 TRACE( "(%p) ref = %lu\n", This, ref );
789 if (!ref)
791 free( This->req );
792 free( This->opt );
793 if (This->tokens)
795 ULONG i;
796 for ( i = 0; i < This->count; i++ )
797 if ( This->tokens[i].token )
798 ISpObjectToken_Release( This->tokens[i].token );
799 free( This->tokens );
801 free( This );
804 return ref;
807 static HRESULT WINAPI token_enum_Next( ISpObjectTokenEnumBuilder *iface,
808 ULONG num, ISpObjectToken **tokens,
809 ULONG *fetched )
811 struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface );
812 ULONG i;
814 TRACE( "(%p)->(%lu %p %p)\n", This, num, tokens, fetched );
816 if (!This->init) return SPERR_UNINITIALIZED;
817 if (!fetched && num != 1) return E_POINTER;
818 if (!tokens) return E_POINTER;
820 for ( i = 0; i < num && This->index < This->count; i++, This->index++ )
822 ISpObjectToken_AddRef( This->tokens[This->index].token );
823 tokens[i] = This->tokens[This->index].token;
826 if (fetched) *fetched = i;
828 return i == num ? S_OK : S_FALSE;
831 static HRESULT WINAPI token_enum_Skip( ISpObjectTokenEnumBuilder *iface,
832 ULONG num )
834 FIXME( "stub\n" );
835 return E_NOTIMPL;
838 static HRESULT WINAPI token_enum_Reset( ISpObjectTokenEnumBuilder *iface)
840 FIXME( "stub\n" );
841 return E_NOTIMPL;
844 static HRESULT WINAPI token_enum_Clone( ISpObjectTokenEnumBuilder *iface,
845 IEnumSpObjectTokens **clone )
847 FIXME( "stub\n" );
848 return E_NOTIMPL;
851 static HRESULT WINAPI token_enum_Item( ISpObjectTokenEnumBuilder *iface,
852 ULONG index, ISpObjectToken **token )
854 struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface );
856 TRACE( "(%p)->(%lu %p)\n", This, index, token );
858 if (!This->init) return SPERR_UNINITIALIZED;
860 if (!token) return E_POINTER;
861 if (index >= This->count) return SPERR_NO_MORE_ITEMS;
863 ISpObjectToken_AddRef( This->tokens[index].token );
864 *token = This->tokens[index].token;
866 return S_OK;
869 static HRESULT WINAPI token_enum_GetCount( ISpObjectTokenEnumBuilder *iface,
870 ULONG *count )
872 struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface );
874 TRACE( "(%p)->(%p)\n", This, count );
876 if (!This->init) return SPERR_UNINITIALIZED;
878 *count = This->count;
879 return S_OK;
882 static HRESULT WINAPI token_enum_SetAttribs( ISpObjectTokenEnumBuilder *iface,
883 LPCWSTR req, LPCWSTR opt)
885 struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface );
887 TRACE( "(%p)->(%s %s)\n", This, debugstr_w( req ), debugstr_w( opt ) );
889 if (This->init) return SPERR_ALREADY_INITIALIZED;
891 if (req)
893 This->req = wcsdup( req );
894 if (!This->req) goto out_of_mem;
897 if (opt)
899 This->opt = wcsdup( opt );
900 if (!This->opt) goto out_of_mem;
903 This->init = TRUE;
904 return S_OK;
906 out_of_mem:
907 free( This->req );
908 return E_OUTOFMEMORY;
911 static HRESULT score_attributes( ISpObjectToken *token, const WCHAR *attrs,
912 BOOL match_all, uint64_t *score )
914 ISpDataKey *attrs_key;
915 WCHAR *attr, *attr_ctx, *buf;
916 BOOL match[64];
917 unsigned int i, j;
918 HRESULT hr;
920 if (!attrs)
922 *score = 1;
923 return S_OK;
925 *score = 0;
927 if (FAILED(hr = ISpObjectToken_OpenKey( token, L"Attributes", &attrs_key )))
928 return hr == SPERR_NOT_FOUND ? S_OK : hr;
930 memset( match, 0, sizeof(match) );
932 /* attrs is a semicolon-separated list of attribute clauses.
933 * Each clause consists of an attribute name and an optional operator and value.
934 * The meaning of a clause depends on the operator given:
935 * If no operator is given, the attribute must exist.
936 * If the operator is '=', the attribute must contain the given value.
937 * If the operator is '!=', the attribute must not exist or contain the given value.
939 if (!(buf = wcsdup( attrs ))) return E_OUTOFMEMORY;
940 for ( attr = wcstok_s( buf, L";", &attr_ctx ), i = 0; attr && i < 64;
941 attr = wcstok_s( NULL, L";", &attr_ctx ), i++ )
943 WCHAR *p = wcspbrk( attr, L"!=" );
944 WCHAR op = p ? *p : L'\0';
945 WCHAR *value = NULL, *res;
946 if ( p )
948 if ( op == L'=' )
949 value = p + 1;
950 else if ( op == L'!' )
952 if ( *(p + 1) != L'=' )
954 WARN( "invalid attr operator '!%lc'.\n", *(p + 1) );
955 hr = E_INVALIDARG;
956 goto done;
958 value = p + 2;
960 *p = L'\0';
963 hr = ISpDataKey_GetStringValue( attrs_key, attr, &res );
964 if ( p ) *p = op;
965 if (SUCCEEDED(hr))
967 if ( !op )
968 match[i] = TRUE;
969 else
971 WCHAR *val, *val_ctx;
973 match[i] = FALSE;
974 for ( val = wcstok_s( res, L";", &val_ctx ); val && !match[i];
975 val = wcstok_s( NULL, L";", &val_ctx ) )
976 match[i] = !wcscmp( val, value );
978 if (op == L'!') match[i] = !match[i];
980 CoTaskMemFree( res );
982 else if (hr == SPERR_NOT_FOUND)
984 hr = S_OK;
985 if (op == L'!') match[i] = TRUE;
987 else
988 goto done;
990 if ( match_all && !match[i] )
991 goto done;
994 if ( attr )
995 hr = E_INVALIDARG;
996 else
998 /* Attributes in attrs are ordered from highest to lowest priority. */
999 for ( j = 0; j < i; j++ )
1000 if ( match[j] )
1001 *score |= 1ULL << (i - 1 - j);
1004 done:
1005 free( buf );
1006 return hr;
1009 static BOOL grow_tokens_array( struct token_enum *This )
1011 struct token_with_score *new_tokens;
1012 ULONG new_cap;
1014 if (This->count < This->capacity) return TRUE;
1016 if (This->capacity > 0)
1018 new_cap = This->capacity * 2;
1019 new_tokens = realloc( This->tokens, new_cap * sizeof(*new_tokens) );
1021 else
1023 new_cap = 1;
1024 new_tokens = malloc( sizeof(*new_tokens) );
1027 if (!new_tokens) return FALSE;
1029 This->tokens = new_tokens;
1030 This->capacity = new_cap;
1031 return TRUE;
1034 static HRESULT WINAPI token_enum_AddTokens( ISpObjectTokenEnumBuilder *iface,
1035 ULONG num, ISpObjectToken **tokens )
1037 struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface );
1038 ULONG i;
1039 uint64_t score;
1040 HRESULT hr;
1042 TRACE( "(%p)->(%lu %p)\n", iface, num, tokens );
1044 if (!This->init) return SPERR_UNINITIALIZED;
1045 if (!tokens) return E_POINTER;
1047 for ( i = 0; i < num; i++ )
1049 if (!tokens[i]) return E_POINTER;
1051 hr = score_attributes( tokens[i], This->req, TRUE, &score );
1052 if (FAILED(hr)) return hr;
1053 if (!score) continue;
1055 hr = score_attributes( tokens[i], This->opt, FALSE, &score );
1056 if (FAILED(hr)) return hr;
1058 if (!grow_tokens_array( This )) return E_OUTOFMEMORY;
1059 ISpObjectToken_AddRef( tokens[i] );
1060 This->tokens[This->count].token = tokens[i];
1061 This->tokens[This->count].score = score;
1062 This->count++;
1065 return S_OK;
1068 static HRESULT WINAPI token_enum_AddTokensFromDataKey( ISpObjectTokenEnumBuilder *iface,
1069 ISpDataKey *data_key,
1070 LPCWSTR sub_key, LPCWSTR cat_id )
1072 FIXME( "stub\n" );
1073 return E_NOTIMPL;
1076 static HRESULT WINAPI token_enum_AddTokensFromTokenEnum( ISpObjectTokenEnumBuilder *iface,
1077 IEnumSpObjectTokens *token_enum )
1079 FIXME( "stub\n" );
1080 return E_NOTIMPL;
1083 static int __cdecl token_with_score_cmp( const void *a, const void *b )
1085 const struct token_with_score *ta = a, *tb = b;
1087 if (ta->score > tb->score) return -1;
1088 else if (ta->score < tb->score) return 1;
1089 else return 0;
1092 static HRESULT WINAPI token_enum_Sort( ISpObjectTokenEnumBuilder *iface,
1093 LPCWSTR first )
1095 struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface );
1097 TRACE( "(%p)->(%s).\n", iface, debugstr_w(first) );
1099 if (!This->init) return SPERR_UNINITIALIZED;
1100 if (!This->tokens) return S_OK;
1102 if (first)
1104 FIXME( "first != NULL is not implemented.\n" );
1105 return E_NOTIMPL;
1108 if (This->opt)
1109 qsort( This->tokens, This->count, sizeof(*This->tokens), token_with_score_cmp );
1111 return S_OK;
1114 const struct ISpObjectTokenEnumBuilderVtbl token_enum_vtbl =
1116 token_enum_QueryInterface,
1117 token_enum_AddRef,
1118 token_enum_Release,
1119 token_enum_Next,
1120 token_enum_Skip,
1121 token_enum_Reset,
1122 token_enum_Clone,
1123 token_enum_Item,
1124 token_enum_GetCount,
1125 token_enum_SetAttribs,
1126 token_enum_AddTokens,
1127 token_enum_AddTokensFromDataKey,
1128 token_enum_AddTokensFromTokenEnum,
1129 token_enum_Sort
1132 HRESULT token_enum_create( IUnknown *outer, REFIID iid, void **obj )
1134 struct token_enum *This = malloc( sizeof(*This) );
1135 HRESULT hr;
1137 if (!This) return E_OUTOFMEMORY;
1138 This->ISpObjectTokenEnumBuilder_iface.lpVtbl = &token_enum_vtbl;
1139 This->ref = 1;
1140 This->req = NULL;
1141 This->opt = NULL;
1142 This->init = FALSE;
1143 This->tokens = NULL;
1144 This->capacity = This->count = 0;
1145 This->index = 0;
1147 hr = ISpObjectTokenEnumBuilder_QueryInterface( &This->ISpObjectTokenEnumBuilder_iface, iid, obj );
1149 ISpObjectTokenEnumBuilder_Release( &This->ISpObjectTokenEnumBuilder_iface );
1150 return hr;
1153 static HRESULT WINAPI token_QueryInterface( ISpObjectToken *iface,
1154 REFIID iid, void **obj )
1156 struct object_token *This = impl_from_ISpObjectToken( iface );
1158 TRACE( "(%p)->(%s %p)\n", This, debugstr_guid( iid ), obj );
1160 if (IsEqualIID( iid, &IID_IUnknown ) ||
1161 IsEqualIID( iid, &IID_ISpDataKey ) ||
1162 IsEqualIID( iid, &IID_ISpObjectToken ))
1164 ISpObjectToken_AddRef( iface );
1165 *obj = iface;
1166 return S_OK;
1169 FIXME( "interface %s not implemented\n", debugstr_guid( iid ) );
1170 *obj = NULL;
1171 return E_NOINTERFACE;
1174 static ULONG WINAPI token_AddRef( ISpObjectToken *iface )
1176 struct object_token *This = impl_from_ISpObjectToken( iface );
1177 ULONG ref = InterlockedIncrement( &This->ref );
1179 TRACE( "(%p) ref = %lu\n", This, ref );
1180 return ref;
1183 static ULONG WINAPI token_Release( ISpObjectToken *iface )
1185 struct object_token *This = impl_from_ISpObjectToken( iface );
1186 ULONG ref = InterlockedDecrement(&This->ref);
1188 TRACE( "(%p) ref = %lu\n", This, ref );
1190 if (!ref)
1192 if (This->data_key) ISpRegDataKey_Release( This->data_key );
1193 free( This->token_id );
1194 free( This );
1197 return ref;
1200 static HRESULT WINAPI token_SetData( ISpObjectToken *iface,
1201 LPCWSTR name, ULONG size,
1202 const BYTE *data )
1204 FIXME( "stub\n" );
1205 return E_NOTIMPL;
1208 static HRESULT WINAPI token_GetData( ISpObjectToken *iface,
1209 LPCWSTR name, ULONG *size,
1210 BYTE *data )
1212 FIXME( "stub\n" );
1213 return E_NOTIMPL;
1216 static HRESULT WINAPI token_SetStringValue( ISpObjectToken *iface,
1217 LPCWSTR name, LPCWSTR value )
1219 struct object_token *This = impl_from_ISpObjectToken( iface );
1221 TRACE( "%p, %s, %s\n", This, debugstr_w(name), debugstr_w(value) );
1223 return ISpRegDataKey_SetStringValue( This->data_key, name, value );
1226 static HRESULT WINAPI token_GetStringValue( ISpObjectToken *iface,
1227 LPCWSTR name, LPWSTR *value )
1229 struct object_token *This = impl_from_ISpObjectToken( iface );
1231 TRACE( "%p, %s, %p\n", This, debugstr_w(name), value );
1233 return ISpRegDataKey_GetStringValue( This->data_key, name, value );
1236 static HRESULT WINAPI token_SetDWORD( ISpObjectToken *iface,
1237 LPCWSTR name, DWORD value )
1239 FIXME( "stub\n" );
1240 return E_NOTIMPL;
1243 static HRESULT WINAPI token_GetDWORD( ISpObjectToken *iface,
1244 LPCWSTR name, DWORD *pdwValue )
1246 FIXME( "stub\n" );
1247 return E_NOTIMPL;
1250 static HRESULT WINAPI token_OpenKey( ISpObjectToken *iface,
1251 LPCWSTR name, ISpDataKey **sub_key )
1253 struct object_token *This = impl_from_ISpObjectToken( iface );
1255 TRACE( "%p, %s, %p\n", This, debugstr_w(name), sub_key );
1257 return ISpRegDataKey_OpenKey( This->data_key, name, sub_key );
1260 static HRESULT WINAPI token_CreateKey( ISpObjectToken *iface,
1261 LPCWSTR name, ISpDataKey **sub_key )
1263 struct object_token *This = impl_from_ISpObjectToken( iface );
1265 TRACE( "%p, %s, %p\n", iface, debugstr_w(name), sub_key );
1267 return ISpRegDataKey_CreateKey( This->data_key, name, sub_key );
1270 static HRESULT WINAPI token_DeleteKey( ISpObjectToken *iface,
1271 LPCWSTR name )
1273 FIXME( "stub\n" );
1274 return E_NOTIMPL;
1277 static HRESULT WINAPI token_DeleteValue( ISpObjectToken *iface,
1278 LPCWSTR name )
1280 FIXME( "stub\n" );
1281 return E_NOTIMPL;
1284 static HRESULT WINAPI token_EnumKeys( ISpObjectToken *iface,
1285 ULONG index, LPWSTR *sub_key )
1287 FIXME( "stub\n" );
1288 return E_NOTIMPL;
1291 static HRESULT WINAPI token_EnumValues( ISpObjectToken *iface,
1292 ULONG index, LPWSTR *value )
1294 FIXME( "stub\n" );
1295 return E_NOTIMPL;
1298 static HRESULT WINAPI token_SetId( ISpObjectToken *iface,
1299 LPCWSTR category_id, LPCWSTR token_id,
1300 BOOL create )
1302 struct object_token *This = impl_from_ISpObjectToken( iface );
1303 BOOL res;
1304 HRESULT hr;
1305 HKEY root, key;
1306 const WCHAR *subkey;
1308 TRACE( "(%p)->(%s %s %d)\n", This, debugstr_w( category_id ),
1309 debugstr_w(token_id), create );
1311 if (This->data_key) return SPERR_ALREADY_INITIALIZED;
1313 if (!token_id) return E_POINTER;
1315 hr = parse_cat_id( token_id, &root, &subkey );
1316 if (hr != S_OK) return SPERR_NOT_FOUND;
1318 if (create)
1319 res = RegCreateKeyExW( root, subkey, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &key, NULL);
1320 else
1321 res = RegOpenKeyExW( root, subkey, 0, KEY_ALL_ACCESS, &key );
1322 if (res) return SPERR_NOT_FOUND;
1324 hr = create_data_key_with_hkey( key, &This->data_key );
1325 if (FAILED(hr))
1327 RegCloseKey( key );
1328 return hr;
1331 This->token_id = wcsdup(token_id);
1333 return S_OK;
1336 static HRESULT WINAPI token_GetId( ISpObjectToken *iface,
1337 LPWSTR *token_id )
1339 struct object_token *This = impl_from_ISpObjectToken( iface );
1341 TRACE( "%p, %p\n", This, token_id);
1343 if (!This->data_key)
1344 return SPERR_UNINITIALIZED;
1346 if (!token_id)
1347 return E_POINTER;
1349 if (!This->token_id)
1351 FIXME("Loading default category not supported.\n");
1352 return E_POINTER;
1355 *token_id = CoTaskMemAlloc( (wcslen(This->token_id) + 1) * sizeof(WCHAR));
1356 if (!*token_id)
1357 return E_OUTOFMEMORY;
1359 wcscpy(*token_id, This->token_id);
1360 return S_OK;
1363 static HRESULT WINAPI token_GetCategory( ISpObjectToken *iface,
1364 ISpObjectTokenCategory **category )
1366 FIXME( "stub\n" );
1367 return E_NOTIMPL;
1370 static HRESULT WINAPI token_CreateInstance( ISpObjectToken *iface,
1371 IUnknown *outer,
1372 DWORD class_context,
1373 REFIID riid,
1374 void **object )
1376 WCHAR *clsid_str;
1377 CLSID clsid;
1378 IUnknown *unk;
1379 ISpObjectWithToken *obj_token_iface;
1380 HRESULT hr;
1382 TRACE( "%p, %p, %#lx, %s, %p\n", iface, outer, class_context, debugstr_guid( riid ), object );
1384 if (FAILED(hr = ISpObjectToken_GetStringValue( iface, L"CLSID", &clsid_str )))
1385 return hr;
1387 hr = CLSIDFromString( clsid_str, &clsid );
1388 CoTaskMemFree( clsid_str );
1389 if (FAILED(hr))
1390 return hr;
1392 if (FAILED(hr = CoCreateInstance( &clsid, outer, class_context, &IID_IUnknown, (void **)&unk )))
1393 return hr;
1395 /* Call ISpObjectWithToken::SetObjectToken if the interface is available. */
1396 if (SUCCEEDED(IUnknown_QueryInterface( unk, &IID_ISpObjectWithToken, (void **)&obj_token_iface )))
1398 hr = ISpObjectWithToken_SetObjectToken( obj_token_iface, iface );
1399 ISpObjectWithToken_Release( obj_token_iface );
1400 if (FAILED(hr))
1401 goto done;
1404 hr = IUnknown_QueryInterface( unk, riid, object );
1406 done:
1407 IUnknown_Release( unk );
1408 return hr;
1411 static HRESULT WINAPI token_GetStorageFileName( ISpObjectToken *iface,
1412 REFCLSID caller,
1413 LPCWSTR key_name,
1414 LPCWSTR filename,
1415 ULONG folder,
1416 LPWSTR *filepath )
1418 FIXME( "stub\n" );
1419 return E_NOTIMPL;
1422 static HRESULT WINAPI token_RemoveStorageFileName( ISpObjectToken *iface,
1423 REFCLSID caller,
1424 LPCWSTR key_name,
1425 BOOL delete_file )
1427 FIXME( "stub\n" );
1428 return E_NOTIMPL;
1431 static HRESULT WINAPI token_Remove( ISpObjectToken *iface,
1432 REFCLSID caller )
1434 FIXME( "stub\n" );
1435 return E_NOTIMPL;
1438 static HRESULT WINAPI token_IsUISupported( ISpObjectToken *iface,
1439 LPCWSTR ui_type,
1440 void *extra_data,
1441 ULONG extra_data_size,
1442 IUnknown *object,
1443 BOOL *supported )
1445 FIXME( "stub\n" );
1446 return E_NOTIMPL;
1449 static HRESULT WINAPI token_DisplayUI( ISpObjectToken *iface,
1450 HWND parent,
1451 LPCWSTR title,
1452 LPCWSTR ui_type,
1453 void *extra_data,
1454 ULONG extra_data_size,
1455 IUnknown *object )
1457 FIXME( "stub\n" );
1458 return E_NOTIMPL;
1461 static HRESULT WINAPI token_MatchesAttributes( ISpObjectToken *iface,
1462 LPCWSTR attributes,
1463 BOOL *matches )
1465 FIXME( "stub\n" );
1466 return E_NOTIMPL;
1469 const struct ISpObjectTokenVtbl token_vtbl =
1471 token_QueryInterface,
1472 token_AddRef,
1473 token_Release,
1474 token_SetData,
1475 token_GetData,
1476 token_SetStringValue,
1477 token_GetStringValue,
1478 token_SetDWORD,
1479 token_GetDWORD,
1480 token_OpenKey,
1481 token_CreateKey,
1482 token_DeleteKey,
1483 token_DeleteValue,
1484 token_EnumKeys,
1485 token_EnumValues,
1486 token_SetId,
1487 token_GetId,
1488 token_GetCategory,
1489 token_CreateInstance,
1490 token_GetStorageFileName,
1491 token_RemoveStorageFileName,
1492 token_Remove,
1493 token_IsUISupported,
1494 token_DisplayUI,
1495 token_MatchesAttributes
1498 HRESULT token_create( IUnknown *outer, REFIID iid, void **obj )
1500 struct object_token *This = malloc( sizeof(*This) );
1501 HRESULT hr;
1503 if (!This) return E_OUTOFMEMORY;
1504 This->ISpObjectToken_iface.lpVtbl = &token_vtbl;
1505 This->ref = 1;
1507 This->data_key = NULL;
1508 This->token_id = NULL;
1510 hr = ISpObjectToken_QueryInterface( &This->ISpObjectToken_iface, iid, obj );
1512 ISpObjectToken_Release( &This->ISpObjectToken_iface );
1513 return hr;