1 /*
2 * Copyright (C) 2012 Alistair Leslie-Hughes
3 * Copyright 2015 Nikolay Sivov for CodeWeavers
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19 #define COBJMACROS
20
21 #ifdef __REACTOS__
22 #include <wine/config.h>
23 #include <wine/port.h>
24 #endif
25 #include <stdarg.h>
26 #include <math.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "ole2.h"
31 #include "olectl.h"
32 #include "dispex.h"
33 #include "scrrun.h"
34 #include "scrrun_private.h"
35
36 #include "wine/debug.h"
37 #include "wine/heap.h"
38 #include "wine/list.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(scrrun);
41
42 #define BUCKET_COUNT 509
43 #define DICT_HASH_MOD 1201
44
45 /* Implementation details
46
47 Dictionary contains one list that links all pairs, this way
48 order in which they were added is preserved. Each bucket has
49 its own list to hold all pairs in this bucket. Initially all
50 bucket lists are zeroed and we init them once we about to add
51 first pair.
52
53 When pair is removed it's unlinked from both lists; if it was
54 a last pair in a bucket list it stays empty in initialized state.
55
56 Preserving pair order is important for enumeration, so far testing
57 indicates that pairs are not reordered basing on hash value.
58 */
59
60 struct keyitem_pair {
61 struct list entry;
62 struct list bucket;
63 DWORD hash;
64 VARIANT key;
65 VARIANT item;
66 };
67
68 typedef struct
69 {
70 struct provideclassinfo classinfo;
71 IDictionary IDictionary_iface;
72 LONG ref;
73
74 CompareMethod method;
75 LONG count;
76 struct list pairs;
77 struct list buckets[BUCKET_COUNT];
78 struct list notifier;
79 } dictionary;
80
81 struct dictionary_enum {
82 IEnumVARIANT IEnumVARIANT_iface;
83 LONG ref;
84
85 dictionary *dict;
86 struct list *cur;
87 struct list notify;
88 };
89
impl_from_IDictionary(IDictionary * iface)90 static inline dictionary *impl_from_IDictionary(IDictionary *iface)
91 {
92 return CONTAINING_RECORD(iface, dictionary, IDictionary_iface);
93 }
94
impl_from_IEnumVARIANT(IEnumVARIANT * iface)95 static inline struct dictionary_enum *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
96 {
97 return CONTAINING_RECORD(iface, struct dictionary_enum, IEnumVARIANT_iface);
98 }
99
get_bucket_head(dictionary * dict,DWORD hash)100 static inline struct list *get_bucket_head(dictionary *dict, DWORD hash)
101 {
102 return &dict->buckets[hash % BUCKET_COUNT];
103 }
104
is_string_key(const VARIANT * key)105 static inline BOOL is_string_key(const VARIANT *key)
106 {
107 return V_VT(key) == VT_BSTR || V_VT(key) == (VT_BSTR|VT_BYREF);
108 }
109
110 /* Only for VT_BSTR or VT_BSTR|VT_BYREF types */
get_key_strptr(const VARIANT * key)111 static inline WCHAR *get_key_strptr(const VARIANT *key)
112 {
113 if (V_VT(key) == VT_BSTR)
114 return V_BSTR(key);
115
116 if (V_BSTRREF(key))
117 return *V_BSTRREF(key);
118
119 return NULL;
120 }
121
122 /* should be used only when both keys are of string type, it's not checked */
strcmp_key(const dictionary * dict,const VARIANT * key1,const VARIANT * key2)123 static inline int strcmp_key(const dictionary *dict, const VARIANT *key1, const VARIANT *key2)
124 {
125 const WCHAR *str1, *str2;
126
127 str1 = get_key_strptr(key1);
128 str2 = get_key_strptr(key2);
129 return dict->method == BinaryCompare ? wcscmp(str1, str2) : wcsicmp(str1, str2);
130 }
131
is_matching_key(const dictionary * dict,const struct keyitem_pair * pair,const VARIANT * key,DWORD hash)132 static BOOL is_matching_key(const dictionary *dict, const struct keyitem_pair *pair, const VARIANT *key, DWORD hash)
133 {
134 if (is_string_key(key) && is_string_key(&pair->key)) {
135 if (hash != pair->hash)
136 return FALSE;
137
138 return strcmp_key(dict, key, &pair->key) == 0;
139 }
140
141 if ((is_string_key(key) && !is_string_key(&pair->key)) ||
142 (!is_string_key(key) && is_string_key(&pair->key)))
143 return FALSE;
144
145 /* for numeric keys only check hash */
146 return hash == pair->hash;
147 }
148
get_keyitem_pair(dictionary * dict,VARIANT * key)149 static struct keyitem_pair *get_keyitem_pair(dictionary *dict, VARIANT *key)
150 {
151 struct keyitem_pair *pair;
152 struct list *head, *entry;
153 VARIANT hash;
154 HRESULT hr;
155
156 hr = IDictionary_get_HashVal(&dict->IDictionary_iface, key, &hash);
157 if (FAILED(hr))
158 return NULL;
159
160 head = get_bucket_head(dict, V_I4(&hash));
161 if (!head->next || list_empty(head))
162 return NULL;
163
164 entry = list_head(head);
165 do {
166 pair = LIST_ENTRY(entry, struct keyitem_pair, bucket);
167 if (is_matching_key(dict, pair, key, V_I4(&hash))) return pair;
168 } while ((entry = list_next(head, entry)));
169
170 return NULL;
171 }
172
add_keyitem_pair(dictionary * dict,VARIANT * key,VARIANT * item)173 static HRESULT add_keyitem_pair(dictionary *dict, VARIANT *key, VARIANT *item)
174 {
175 struct keyitem_pair *pair;
176 struct list *head;
177 VARIANT hash;
178 HRESULT hr;
179
180 hr = IDictionary_get_HashVal(&dict->IDictionary_iface, key, &hash);
181 if (FAILED(hr))
182 return hr;
183
184 pair = heap_alloc(sizeof(*pair));
185 if (!pair)
186 return E_OUTOFMEMORY;
187
188 pair->hash = V_I4(&hash);
189 VariantInit(&pair->key);
190 VariantInit(&pair->item);
191
192 hr = VariantCopyInd(&pair->key, key);
193 if (FAILED(hr))
194 goto failed;
195
196 hr = VariantCopyInd(&pair->item, item);
197 if (FAILED(hr))
198 goto failed;
199
200 head = get_bucket_head(dict, pair->hash);
201 if (!head->next)
202 /* this only happens once per bucket */
203 list_init(head);
204
205 /* link to bucket list and to full list */
206 list_add_tail(head, &pair->bucket);
207 list_add_tail(&dict->pairs, &pair->entry);
208 dict->count++;
209 return S_OK;
210
211 failed:
212 VariantClear(&pair->key);
213 VariantClear(&pair->item);
214 heap_free(pair);
215 return hr;
216 }
217
free_keyitem_pair(struct keyitem_pair * pair)218 static void free_keyitem_pair(struct keyitem_pair *pair)
219 {
220 VariantClear(&pair->key);
221 VariantClear(&pair->item);
222 heap_free(pair);
223 }
224
dict_enum_QueryInterface(IEnumVARIANT * iface,REFIID riid,void ** obj)225 static HRESULT WINAPI dict_enum_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **obj)
226 {
227 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
228
229 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
230
231 if (IsEqualIID(riid, &IID_IEnumVARIANT) || IsEqualIID(riid, &IID_IUnknown)) {
232 *obj = iface;
233 IEnumVARIANT_AddRef(iface);
234 return S_OK;
235 }
236 else {
237 WARN("interface not supported %s\n", debugstr_guid(riid));
238 *obj = NULL;
239 return E_NOINTERFACE;
240 }
241 }
242
dict_enum_AddRef(IEnumVARIANT * iface)243 static ULONG WINAPI dict_enum_AddRef(IEnumVARIANT *iface)
244 {
245 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
246 ULONG ref = InterlockedIncrement(&This->ref);
247 TRACE("(%p)->(%u)\n", This, ref);
248 return ref;
249 }
250
dict_enum_Release(IEnumVARIANT * iface)251 static ULONG WINAPI dict_enum_Release(IEnumVARIANT *iface)
252 {
253 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
254 LONG ref = InterlockedDecrement(&This->ref);
255
256 TRACE("(%p)->(%u)\n", This, ref);
257
258 if (!ref) {
259 list_remove(&This->notify);
260 IDictionary_Release(&This->dict->IDictionary_iface);
261 heap_free(This);
262 }
263
264 return ref;
265 }
266
dict_enum_Next(IEnumVARIANT * iface,ULONG count,VARIANT * keys,ULONG * fetched)267 static HRESULT WINAPI dict_enum_Next(IEnumVARIANT *iface, ULONG count, VARIANT *keys, ULONG *fetched)
268 {
269 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
270 struct keyitem_pair *pair;
271 ULONG i = 0;
272
273 TRACE("(%p)->(%u %p %p)\n", This, count, keys, fetched);
274
275 if (fetched)
276 *fetched = 0;
277
278 if (!count)
279 return S_OK;
280
281 while (This->cur && i < count) {
282 pair = LIST_ENTRY(This->cur, struct keyitem_pair, entry);
283 VariantCopy(&keys[i], &pair->key);
284 This->cur = list_next(&This->dict->pairs, This->cur);
285 i++;
286 }
287
288 if (fetched)
289 *fetched = i;
290
291 return i < count ? S_FALSE : S_OK;
292 }
293
dict_enum_Skip(IEnumVARIANT * iface,ULONG count)294 static HRESULT WINAPI dict_enum_Skip(IEnumVARIANT *iface, ULONG count)
295 {
296 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
297
298 TRACE("(%p)->(%u)\n", This, count);
299
300 if (!count)
301 return S_OK;
302
303 if (!This->cur)
304 return S_FALSE;
305
306 while (count--) {
307 This->cur = list_next(&This->dict->pairs, This->cur);
308 if (!This->cur) break;
309 }
310
311 return count == 0 ? S_OK : S_FALSE;
312 }
313
dict_enum_Reset(IEnumVARIANT * iface)314 static HRESULT WINAPI dict_enum_Reset(IEnumVARIANT *iface)
315 {
316 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
317
318 TRACE("(%p)\n", This);
319
320 This->cur = list_head(&This->dict->pairs);
321 return S_OK;
322 }
323
324 static HRESULT create_dict_enum(dictionary*, IUnknown**);
325
dict_enum_Clone(IEnumVARIANT * iface,IEnumVARIANT ** cloned)326 static HRESULT WINAPI dict_enum_Clone(IEnumVARIANT *iface, IEnumVARIANT **cloned)
327 {
328 struct dictionary_enum *This = impl_from_IEnumVARIANT(iface);
329 TRACE("(%p)->(%p)\n", This, cloned);
330 return create_dict_enum(This->dict, (IUnknown**)cloned);
331 }
332
333 static const IEnumVARIANTVtbl dictenumvtbl = {
334 dict_enum_QueryInterface,
335 dict_enum_AddRef,
336 dict_enum_Release,
337 dict_enum_Next,
338 dict_enum_Skip,
339 dict_enum_Reset,
340 dict_enum_Clone
341 };
342
create_dict_enum(dictionary * dict,IUnknown ** ret)343 static HRESULT create_dict_enum(dictionary *dict, IUnknown **ret)
344 {
345 struct dictionary_enum *This;
346
347 *ret = NULL;
348
349 This = heap_alloc(sizeof(*This));
350 if (!This)
351 return E_OUTOFMEMORY;
352
353 This->IEnumVARIANT_iface.lpVtbl = &dictenumvtbl;
354 This->ref = 1;
355 This->cur = list_head(&dict->pairs);
356 list_add_tail(&dict->notifier, &This->notify);
357 This->dict = dict;
358 IDictionary_AddRef(&dict->IDictionary_iface);
359
360 *ret = (IUnknown*)&This->IEnumVARIANT_iface;
361 return S_OK;
362 }
363
notify_remove_pair(struct list * notifier,struct list * pair)364 static void notify_remove_pair(struct list *notifier, struct list *pair)
365 {
366 struct dictionary_enum *dict_enum;
367 struct list *cur;
368
369 LIST_FOR_EACH(cur, notifier) {
370 dict_enum = LIST_ENTRY(cur, struct dictionary_enum, notify);
371 if (!pair)
372 dict_enum->cur = list_head(&dict_enum->dict->pairs);
373 else if (dict_enum->cur == pair) {
374 dict_enum->cur = list_next(&dict_enum->dict->pairs, dict_enum->cur);
375 }
376 }
377 }
378
dictionary_QueryInterface(IDictionary * iface,REFIID riid,void ** obj)379 static HRESULT WINAPI dictionary_QueryInterface(IDictionary *iface, REFIID riid, void **obj)
380 {
381 dictionary *This = impl_from_IDictionary(iface);
382 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
383
384 *obj = NULL;
385
386 if(IsEqualIID(riid, &IID_IUnknown) ||
387 IsEqualIID(riid, &IID_IDispatch) ||
388 IsEqualIID(riid, &IID_IDictionary))
389 {
390 *obj = &This->IDictionary_iface;
391 }
392 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
393 {
394 *obj = &This->classinfo.IProvideClassInfo_iface;
395 }
396 else if ( IsEqualGUID( riid, &IID_IDispatchEx ))
397 {
398 TRACE("Interface IDispatchEx not supported - returning NULL\n");
399 *obj = NULL;
400 return E_NOINTERFACE;
401 }
402 else if ( IsEqualGUID( riid, &IID_IObjectWithSite ))
403 {
404 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
405 *obj = NULL;
406 return E_NOINTERFACE;
407 }
408 else
409 {
410 WARN("interface %s not implemented\n", debugstr_guid(riid));
411 return E_NOINTERFACE;
412 }
413
414 IUnknown_AddRef((IUnknown*)*obj);
415 return S_OK;
416 }
417
dictionary_AddRef(IDictionary * iface)418 static ULONG WINAPI dictionary_AddRef(IDictionary *iface)
419 {
420 dictionary *This = impl_from_IDictionary(iface);
421 ULONG ref = InterlockedIncrement(&This->ref);
422
423 TRACE("(%p)->(%u)\n", This, ref);
424
425 return ref;
426 }
427
dictionary_Release(IDictionary * iface)428 static ULONG WINAPI dictionary_Release(IDictionary *iface)
429 {
430 dictionary *This = impl_from_IDictionary(iface);
431 ULONG ref = InterlockedDecrement(&This->ref);
432
433 TRACE("(%p)->(%u)\n", This, ref);
434
435 if (!ref) {
436 IDictionary_RemoveAll(iface);
437 heap_free(This);
438 }
439
440 return ref;
441 }
442
dictionary_GetTypeInfoCount(IDictionary * iface,UINT * pctinfo)443 static HRESULT WINAPI dictionary_GetTypeInfoCount(IDictionary *iface, UINT *pctinfo)
444 {
445 dictionary *This = impl_from_IDictionary(iface);
446
447 TRACE("(%p)->(%p)\n", This, pctinfo);
448
449 *pctinfo = 1;
450 return S_OK;
451 }
452
dictionary_GetTypeInfo(IDictionary * iface,UINT iTInfo,LCID lcid,ITypeInfo ** ppTInfo)453 static HRESULT WINAPI dictionary_GetTypeInfo(IDictionary *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
454 {
455 dictionary *This = impl_from_IDictionary(iface);
456
457 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
458 return get_typeinfo(IDictionary_tid, ppTInfo);
459 }
460
dictionary_GetIDsOfNames(IDictionary * iface,REFIID riid,LPOLESTR * rgszNames,UINT cNames,LCID lcid,DISPID * rgDispId)461 static HRESULT WINAPI dictionary_GetIDsOfNames(IDictionary *iface, REFIID riid, LPOLESTR *rgszNames,
462 UINT cNames, LCID lcid, DISPID *rgDispId)
463 {
464 dictionary *This = impl_from_IDictionary(iface);
465 ITypeInfo *typeinfo;
466 HRESULT hr;
467
468 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
469
470 hr = get_typeinfo(IDictionary_tid, &typeinfo);
471 if(SUCCEEDED(hr))
472 {
473 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
474 ITypeInfo_Release(typeinfo);
475 }
476
477 return hr;
478 }
479
dictionary_Invoke(IDictionary * iface,DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)480 static HRESULT WINAPI dictionary_Invoke(IDictionary *iface, DISPID dispIdMember, REFIID riid,
481 LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
482 EXCEPINFO *pExcepInfo, UINT *puArgErr)
483 {
484 dictionary *This = impl_from_IDictionary(iface);
485 ITypeInfo *typeinfo;
486 HRESULT hr;
487
488 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
489 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
490
491 hr = get_typeinfo(IDictionary_tid, &typeinfo);
492 if(SUCCEEDED(hr))
493 {
494 hr = ITypeInfo_Invoke(typeinfo, &This->IDictionary_iface, dispIdMember, wFlags,
495 pDispParams, pVarResult, pExcepInfo, puArgErr);
496 ITypeInfo_Release(typeinfo);
497 }
498
499 return hr;
500 }
501
dictionary_putref_Item(IDictionary * iface,VARIANT * Key,VARIANT * pRetItem)502 static HRESULT WINAPI dictionary_putref_Item(IDictionary *iface, VARIANT *Key, VARIANT *pRetItem)
503 {
504 dictionary *This = impl_from_IDictionary(iface);
505
506 FIXME("(%p)->(%p %p)\n", This, Key, pRetItem);
507
508 return E_NOTIMPL;
509 }
510
dictionary_put_Item(IDictionary * iface,VARIANT * key,VARIANT * item)511 static HRESULT WINAPI dictionary_put_Item(IDictionary *iface, VARIANT *key, VARIANT *item)
512 {
513 dictionary *This = impl_from_IDictionary(iface);
514 struct keyitem_pair *pair;
515
516 TRACE("(%p)->(%s %s)\n", This, debugstr_variant(key), debugstr_variant(item));
517
518 if ((pair = get_keyitem_pair(This, key)))
519 return VariantCopyInd(&pair->item, item);
520
521 return IDictionary_Add(iface, key, item);
522 }
523
dictionary_get_Item(IDictionary * iface,VARIANT * key,VARIANT * item)524 static HRESULT WINAPI dictionary_get_Item(IDictionary *iface, VARIANT *key, VARIANT *item)
525 {
526 dictionary *This = impl_from_IDictionary(iface);
527 struct keyitem_pair *pair;
528
529 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(key), item);
530
531 if ((pair = get_keyitem_pair(This, key)))
532 VariantCopy(item, &pair->item);
533 else {
534 VariantInit(item);
535 return IDictionary_Add(iface, key, item);
536 }
537
538 return S_OK;
539 }
540
dictionary_Add(IDictionary * iface,VARIANT * key,VARIANT * item)541 static HRESULT WINAPI dictionary_Add(IDictionary *iface, VARIANT *key, VARIANT *item)
542 {
543 dictionary *This = impl_from_IDictionary(iface);
544
545 TRACE("(%p)->(%s %s)\n", This, debugstr_variant(key), debugstr_variant(item));
546
547 if (get_keyitem_pair(This, key))
548 return CTL_E_KEY_ALREADY_EXISTS;
549
550 return add_keyitem_pair(This, key, item);
551 }
552
dictionary_get_Count(IDictionary * iface,LONG * count)553 static HRESULT WINAPI dictionary_get_Count(IDictionary *iface, LONG *count)
554 {
555 dictionary *This = impl_from_IDictionary(iface);
556
557 TRACE("(%p)->(%p)\n", This, count);
558
559 *count = This->count;
560 return S_OK;
561 }
562
dictionary_Exists(IDictionary * iface,VARIANT * key,VARIANT_BOOL * exists)563 static HRESULT WINAPI dictionary_Exists(IDictionary *iface, VARIANT *key, VARIANT_BOOL *exists)
564 {
565 dictionary *This = impl_from_IDictionary(iface);
566
567 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(key), exists);
568
569 if (!exists)
570 return CTL_E_ILLEGALFUNCTIONCALL;
571
572 *exists = get_keyitem_pair(This, key) != NULL ? VARIANT_TRUE : VARIANT_FALSE;
573 return S_OK;
574 }
575
dictionary_Items(IDictionary * iface,VARIANT * items)576 static HRESULT WINAPI dictionary_Items(IDictionary *iface, VARIANT *items)
577 {
578 dictionary *This = impl_from_IDictionary(iface);
579 struct keyitem_pair *pair;
580 SAFEARRAYBOUND bound;
581 SAFEARRAY *sa;
582 VARIANT *v;
583 HRESULT hr;
584 LONG i;
585
586 TRACE("(%p)->(%p)\n", This, items);
587
588 if (!items)
589 return S_OK;
590
591 bound.lLbound = 0;
592 bound.cElements = This->count;
593 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
594 if (!sa)
595 return E_OUTOFMEMORY;
596
597 hr = SafeArrayAccessData(sa, (void**)&v);
598 if (FAILED(hr)) {
599 SafeArrayDestroy(sa);
600 return hr;
601 }
602
603 i = 0;
604 LIST_FOR_EACH_ENTRY(pair, &This->pairs, struct keyitem_pair, entry) {
605 VariantCopy(&v[i], &pair->item);
606 i++;
607 }
608 SafeArrayUnaccessData(sa);
609
610 V_VT(items) = VT_ARRAY|VT_VARIANT;
611 V_ARRAY(items) = sa;
612 return S_OK;
613 }
614
dictionary_put_Key(IDictionary * iface,VARIANT * key,VARIANT * newkey)615 static HRESULT WINAPI dictionary_put_Key(IDictionary *iface, VARIANT *key, VARIANT *newkey)
616 {
617 dictionary *This = impl_from_IDictionary(iface);
618 struct keyitem_pair *pair;
619 VARIANT empty;
620 HRESULT hr;
621
622 TRACE("(%p)->(%s %s)\n", This, debugstr_variant(key), debugstr_variant(newkey));
623
624 if ((pair = get_keyitem_pair(This, key))) {
625 /* found existing pair for a key, add new pair with new key
626 and old item and remove old pair after that */
627
628 hr = IDictionary_Add(iface, newkey, &pair->item);
629 if (FAILED(hr))
630 return hr;
631
632 return IDictionary_Remove(iface, key);
633 }
634
635 VariantInit(&empty);
636 return IDictionary_Add(iface, newkey, &empty);
637 }
638
dictionary_Keys(IDictionary * iface,VARIANT * keys)639 static HRESULT WINAPI dictionary_Keys(IDictionary *iface, VARIANT *keys)
640 {
641 dictionary *This = impl_from_IDictionary(iface);
642 struct keyitem_pair *pair;
643 SAFEARRAYBOUND bound;
644 SAFEARRAY *sa;
645 VARIANT *v;
646 HRESULT hr;
647 LONG i;
648
649 TRACE("(%p)->(%p)\n", This, keys);
650
651 if (!keys)
652 return S_OK;
653
654 bound.lLbound = 0;
655 bound.cElements = This->count;
656 sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
657 if (!sa)
658 return E_OUTOFMEMORY;
659
660 hr = SafeArrayAccessData(sa, (void**)&v);
661 if (FAILED(hr)) {
662 SafeArrayDestroy(sa);
663 return hr;
664 }
665
666 i = 0;
667 LIST_FOR_EACH_ENTRY(pair, &This->pairs, struct keyitem_pair, entry) {
668 VariantCopy(&v[i], &pair->key);
669 i++;
670 }
671 SafeArrayUnaccessData(sa);
672
673 V_VT(keys) = VT_ARRAY|VT_VARIANT;
674 V_ARRAY(keys) = sa;
675 return S_OK;
676 }
677
dictionary_Remove(IDictionary * iface,VARIANT * key)678 static HRESULT WINAPI dictionary_Remove(IDictionary *iface, VARIANT *key)
679 {
680 dictionary *This = impl_from_IDictionary(iface);
681 struct keyitem_pair *pair;
682
683 TRACE("(%p)->(%s)\n", This, debugstr_variant(key));
684
685 if (!(pair = get_keyitem_pair(This, key)))
686 return CTL_E_ELEMENT_NOT_FOUND;
687
688 notify_remove_pair(&This->notifier, &pair->entry);
689 list_remove(&pair->entry);
690 list_remove(&pair->bucket);
691 This->count--;
692
693 free_keyitem_pair(pair);
694 return S_OK;
695 }
696
dictionary_RemoveAll(IDictionary * iface)697 static HRESULT WINAPI dictionary_RemoveAll(IDictionary *iface)
698 {
699 dictionary *This = impl_from_IDictionary(iface);
700 struct keyitem_pair *pair, *pair2;
701
702 TRACE("(%p)\n", This);
703
704 if (This->count == 0)
705 return S_OK;
706
707 notify_remove_pair(&This->notifier, NULL);
708 LIST_FOR_EACH_ENTRY_SAFE(pair, pair2, &This->pairs, struct keyitem_pair, entry) {
709 list_remove(&pair->entry);
710 list_remove(&pair->bucket);
711 free_keyitem_pair(pair);
712 }
713 This->count = 0;
714
715 return S_OK;
716 }
717
dictionary_put_CompareMode(IDictionary * iface,CompareMethod method)718 static HRESULT WINAPI dictionary_put_CompareMode(IDictionary *iface, CompareMethod method)
719 {
720 dictionary *This = impl_from_IDictionary(iface);
721
722 TRACE("(%p)->(%d)\n", This, method);
723
724 if (This->count)
725 return CTL_E_ILLEGALFUNCTIONCALL;
726
727 This->method = method;
728 return S_OK;
729 }
730
dictionary_get_CompareMode(IDictionary * iface,CompareMethod * method)731 static HRESULT WINAPI dictionary_get_CompareMode(IDictionary *iface, CompareMethod *method)
732 {
733 dictionary *This = impl_from_IDictionary(iface);
734
735 TRACE("(%p)->(%p)\n", This, method);
736
737 *method = This->method;
738 return S_OK;
739 }
740
dictionary__NewEnum(IDictionary * iface,IUnknown ** ret)741 static HRESULT WINAPI dictionary__NewEnum(IDictionary *iface, IUnknown **ret)
742 {
743 dictionary *This = impl_from_IDictionary(iface);
744
745 TRACE("(%p)->(%p)\n", This, ret);
746
747 return create_dict_enum(This, ret);
748 }
749
get_str_hash(const WCHAR * str,CompareMethod method)750 static DWORD get_str_hash(const WCHAR *str, CompareMethod method)
751 {
752 DWORD hash = 0;
753
754 if (str) {
755 while (*str) {
756 WCHAR ch;
757
758 ch = (method == TextCompare || method == DatabaseCompare) ? towlower(*str) : *str;
759
760 hash += (hash << 4) + ch;
761 str++;
762 }
763 }
764
765 return hash % DICT_HASH_MOD;
766 }
767
get_num_hash(FLOAT num)768 static DWORD get_num_hash(FLOAT num)
769 {
770 return (*((DWORD*)&num)) % DICT_HASH_MOD;
771 }
772
get_flt_hash(FLOAT flt,LONG * hash)773 static HRESULT get_flt_hash(FLOAT flt, LONG *hash)
774 {
775 if (isinf(flt)) {
776 *hash = 0;
777 return S_OK;
778 }
779 else if (!isnan(flt)) {
780 *hash = get_num_hash(flt);
781 return S_OK;
782 }
783
784 /* NaN case */
785 *hash = ~0u;
786 return CTL_E_ILLEGALFUNCTIONCALL;
787 }
788
get_ptr_hash(void * ptr)789 static DWORD get_ptr_hash(void *ptr)
790 {
791 return PtrToUlong(ptr) % DICT_HASH_MOD;
792 }
793
dictionary_get_HashVal(IDictionary * iface,VARIANT * key,VARIANT * hash)794 static HRESULT WINAPI dictionary_get_HashVal(IDictionary *iface, VARIANT *key, VARIANT *hash)
795 {
796 dictionary *This = impl_from_IDictionary(iface);
797
798 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(key), hash);
799
800 V_VT(hash) = VT_I4;
801 switch (V_VT(key))
802 {
803 case VT_BSTR|VT_BYREF:
804 case VT_BSTR:
805 V_I4(hash) = get_str_hash(get_key_strptr(key), This->method);
806 break;
807 case VT_UI1|VT_BYREF:
808 case VT_UI1:
809 V_I4(hash) = get_num_hash(V_VT(key) & VT_BYREF ? *V_UI1REF(key) : V_UI1(key));
810 break;
811 case VT_I2|VT_BYREF:
812 case VT_I2:
813 V_I4(hash) = get_num_hash(V_VT(key) & VT_BYREF ? *V_I2REF(key) : V_I2(key));
814 break;
815 case VT_I4|VT_BYREF:
816 case VT_I4:
817 V_I4(hash) = get_num_hash(V_VT(key) & VT_BYREF ? *V_I4REF(key) : V_I4(key));
818 break;
819 case VT_UNKNOWN|VT_BYREF:
820 case VT_DISPATCH|VT_BYREF:
821 case VT_UNKNOWN:
822 case VT_DISPATCH:
823 {
824 IUnknown *src = (V_VT(key) & VT_BYREF) ? *V_UNKNOWNREF(key) : V_UNKNOWN(key);
825 IUnknown *unk = NULL;
826
827 if (!src) {
828 V_I4(hash) = 0;
829 return S_OK;
830 }
831
832 IUnknown_QueryInterface(src, &IID_IUnknown, (void**)&unk);
833 if (!unk) {
834 V_I4(hash) = ~0u;
835 return CTL_E_ILLEGALFUNCTIONCALL;
836 }
837 V_I4(hash) = get_ptr_hash(unk);
838 IUnknown_Release(unk);
839 break;
840 }
841 case VT_DATE|VT_BYREF:
842 case VT_DATE:
843 return get_flt_hash(V_VT(key) & VT_BYREF ? *V_DATEREF(key) : V_DATE(key), &V_I4(hash));
844 case VT_R4|VT_BYREF:
845 case VT_R4:
846 return get_flt_hash(V_VT(key) & VT_BYREF ? *V_R4REF(key) : V_R4(key), &V_I4(hash));
847 case VT_R8|VT_BYREF:
848 case VT_R8:
849 return get_flt_hash(V_VT(key) & VT_BYREF ? *V_R8REF(key) : V_R8(key), &V_I4(hash));
850 case VT_INT:
851 case VT_UINT:
852 case VT_I1:
853 case VT_I8:
854 case VT_UI2:
855 case VT_UI4:
856 V_I4(hash) = ~0u;
857 return CTL_E_ILLEGALFUNCTIONCALL;
858 default:
859 FIXME("not implemented for type %d\n", V_VT(key));
860 return E_NOTIMPL;
861 }
862
863 return S_OK;
864 }
865
866 static const struct IDictionaryVtbl dictionary_vtbl =
867 {
868 dictionary_QueryInterface,
869 dictionary_AddRef,
870 dictionary_Release,
871 dictionary_GetTypeInfoCount,
872 dictionary_GetTypeInfo,
873 dictionary_GetIDsOfNames,
874 dictionary_Invoke,
875 dictionary_putref_Item,
876 dictionary_put_Item,
877 dictionary_get_Item,
878 dictionary_Add,
879 dictionary_get_Count,
880 dictionary_Exists,
881 dictionary_Items,
882 dictionary_put_Key,
883 dictionary_Keys,
884 dictionary_Remove,
885 dictionary_RemoveAll,
886 dictionary_put_CompareMode,
887 dictionary_get_CompareMode,
888 dictionary__NewEnum,
889 dictionary_get_HashVal
890 };
891
Dictionary_CreateInstance(IClassFactory * factory,IUnknown * outer,REFIID riid,void ** obj)892 HRESULT WINAPI Dictionary_CreateInstance(IClassFactory *factory,IUnknown *outer,REFIID riid, void **obj)
893 {
894 dictionary *This;
895
896 TRACE("(%p, %p, %s, %p)\n", factory, outer, debugstr_guid(riid), obj);
897
898 *obj = NULL;
899
900 This = heap_alloc(sizeof(*This));
901 if(!This) return E_OUTOFMEMORY;
902
903 This->IDictionary_iface.lpVtbl = &dictionary_vtbl;
904 This->ref = 1;
905 This->method = BinaryCompare;
906 This->count = 0;
907 list_init(&This->pairs);
908 list_init(&This->notifier);
909 memset(This->buckets, 0, sizeof(This->buckets));
910
911 init_classinfo(&CLSID_Dictionary, (IUnknown *)&This->IDictionary_iface, &This->classinfo);
912 *obj = &This->IDictionary_iface;
913
914 return S_OK;
915 }
916