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 90 static inline dictionary *impl_from_IDictionary(IDictionary *iface) 91 { 92 return CONTAINING_RECORD(iface, dictionary, IDictionary_iface); 93 } 94 95 static inline struct dictionary_enum *impl_from_IEnumVARIANT(IEnumVARIANT *iface) 96 { 97 return CONTAINING_RECORD(iface, struct dictionary_enum, IEnumVARIANT_iface); 98 } 99 100 static inline struct list *get_bucket_head(dictionary *dict, DWORD hash) 101 { 102 return &dict->buckets[hash % BUCKET_COUNT]; 103 } 104 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 */ 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 768 static DWORD get_num_hash(FLOAT num) 769 { 770 return (*((DWORD*)&num)) % DICT_HASH_MOD; 771 } 772 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 789 static DWORD get_ptr_hash(void *ptr) 790 { 791 return PtrToUlong(ptr) % DICT_HASH_MOD; 792 } 793 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 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