2 * Copyright (C) 2012 Alistair Leslie-Hughes
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "wine/port.h"
31 #include "scrrun_private.h"
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
35 #include "wine/list.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(scrrun
);
39 #define BUCKET_COUNT 509
51 IDictionary IDictionary_iface
;
57 struct keyitem_pair
*buckets
[BUCKET_COUNT
];
60 static inline dictionary
*impl_from_IDictionary(IDictionary
*iface
)
62 return CONTAINING_RECORD(iface
, dictionary
, IDictionary_iface
);
65 static inline struct keyitem_pair
*get_bucket_head(const dictionary
*dict
, DWORD hash
)
67 return dict
->buckets
[hash
% BUCKET_COUNT
];
70 static inline BOOL
is_string_key(const VARIANT
*key
)
72 return V_VT(key
) == VT_BSTR
|| V_VT(key
) == (VT_BSTR
|VT_BYREF
);
75 /* Only for VT_BSTR or VT_BSTR|VT_BYREF types */
76 static inline WCHAR
*get_key_strptr(const VARIANT
*key
)
78 if (V_VT(key
) == VT_BSTR
)
82 return *V_BSTRREF(key
);
87 /* should be used only when both keys are of string type, it's not checked */
88 static inline int strcmp_key(const dictionary
*dict
, const VARIANT
*key1
, const VARIANT
*key2
)
90 const WCHAR
*str1
, *str2
;
92 str1
= get_key_strptr(key1
);
93 str2
= get_key_strptr(key2
);
94 return dict
->method
== BinaryCompare
? strcmpW(str1
, str2
) : strcmpiW(str1
, str2
);
97 static BOOL
is_matching_key(const dictionary
*dict
, const struct keyitem_pair
*pair
, const VARIANT
*key
, DWORD hash
)
99 if (is_string_key(key
) && is_string_key(&pair
->key
)) {
100 if (hash
!= pair
->hash
)
103 return strcmp_key(dict
, key
, &pair
->key
) == 0;
106 if ((is_string_key(key
) && !is_string_key(&pair
->key
)) ||
107 (!is_string_key(key
) && is_string_key(&pair
->key
)))
110 /* for numeric keys only check hash */
111 return hash
== pair
->hash
;
114 static struct keyitem_pair
*get_keyitem_pair(dictionary
*dict
, VARIANT
*key
)
116 struct keyitem_pair
*pair
;
121 hr
= IDictionary_get_HashVal(&dict
->IDictionary_iface
, key
, &hash
);
125 pair
= get_bucket_head(dict
, V_I4(&hash
));
129 bucket
= pair
->bucket
;
132 if (is_matching_key(dict
, pair
, key
, V_I4(&hash
))) return pair
;
133 pair
= LIST_ENTRY(list_next(&dict
->pairs
, &pair
->entry
), struct keyitem_pair
, entry
);
134 if (pair
&& pair
->bucket
!= bucket
) break;
135 } while (pair
!= NULL
);
140 static HRESULT
add_keyitem_pair(dictionary
*dict
, VARIANT
*key
, VARIANT
*item
)
142 struct keyitem_pair
*pair
, *head
;
146 hr
= IDictionary_get_HashVal(&dict
->IDictionary_iface
, key
, &hash
);
150 pair
= heap_alloc(sizeof(*pair
));
152 return E_OUTOFMEMORY
;
154 pair
->hash
= V_I4(&hash
);
155 pair
->bucket
= pair
->hash
% BUCKET_COUNT
;
156 VariantInit(&pair
->key
);
157 VariantInit(&pair
->item
);
159 hr
= VariantCopyInd(&pair
->key
, key
);
163 hr
= VariantCopyInd(&pair
->item
, item
);
167 head
= get_bucket_head(dict
, pair
->hash
);
169 list_add_tail(&head
->entry
, &pair
->entry
);
171 dict
->buckets
[pair
->bucket
] = pair
;
172 list_add_tail(&dict
->pairs
, &pair
->entry
);
179 VariantClear(&pair
->key
);
180 VariantClear(&pair
->item
);
185 static void free_keyitem_pair(struct keyitem_pair
*pair
)
187 VariantClear(&pair
->key
);
188 VariantClear(&pair
->item
);
192 static HRESULT WINAPI
dictionary_QueryInterface(IDictionary
*iface
, REFIID riid
, void **obj
)
194 dictionary
*This
= impl_from_IDictionary(iface
);
195 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), obj
);
199 if(IsEqualIID(riid
, &IID_IUnknown
) ||
200 IsEqualIID(riid
, &IID_IDispatch
) ||
201 IsEqualIID(riid
, &IID_IDictionary
))
203 *obj
= &This
->IDictionary_iface
;
205 else if ( IsEqualGUID( riid
, &IID_IDispatchEx
))
207 TRACE("Interface IDispatchEx not supported - returning NULL\n");
209 return E_NOINTERFACE
;
211 else if ( IsEqualGUID( riid
, &IID_IObjectWithSite
))
213 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
215 return E_NOINTERFACE
;
219 WARN("interface %s not implemented\n", debugstr_guid(riid
));
220 return E_NOINTERFACE
;
223 IDictionary_AddRef(iface
);
227 static ULONG WINAPI
dictionary_AddRef(IDictionary
*iface
)
229 dictionary
*This
= impl_from_IDictionary(iface
);
230 TRACE("(%p)\n", This
);
232 return InterlockedIncrement(&This
->ref
);
235 static ULONG WINAPI
dictionary_Release(IDictionary
*iface
)
237 dictionary
*This
= impl_from_IDictionary(iface
);
240 TRACE("(%p)\n", This
);
242 ref
= InterlockedDecrement(&This
->ref
);
244 IDictionary_RemoveAll(iface
);
251 static HRESULT WINAPI
dictionary_GetTypeInfoCount(IDictionary
*iface
, UINT
*pctinfo
)
253 dictionary
*This
= impl_from_IDictionary(iface
);
255 TRACE("(%p)->()\n", This
);
261 static HRESULT WINAPI
dictionary_GetTypeInfo(IDictionary
*iface
, UINT iTInfo
, LCID lcid
, ITypeInfo
**ppTInfo
)
263 dictionary
*This
= impl_from_IDictionary(iface
);
265 TRACE("(%p)->(%u %u %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
266 return get_typeinfo(IDictionary_tid
, ppTInfo
);
269 static HRESULT WINAPI
dictionary_GetIDsOfNames(IDictionary
*iface
, REFIID riid
, LPOLESTR
*rgszNames
,
270 UINT cNames
, LCID lcid
, DISPID
*rgDispId
)
272 dictionary
*This
= impl_from_IDictionary(iface
);
276 TRACE("(%p)->(%s %p %u %u %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
, lcid
, rgDispId
);
278 hr
= get_typeinfo(IDictionary_tid
, &typeinfo
);
281 hr
= ITypeInfo_GetIDsOfNames(typeinfo
, rgszNames
, cNames
, rgDispId
);
282 ITypeInfo_Release(typeinfo
);
288 static HRESULT WINAPI
dictionary_Invoke(IDictionary
*iface
, DISPID dispIdMember
, REFIID riid
,
289 LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
,
290 EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
292 dictionary
*This
= impl_from_IDictionary(iface
);
296 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This
, dispIdMember
, debugstr_guid(riid
),
297 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
299 hr
= get_typeinfo(IDictionary_tid
, &typeinfo
);
302 hr
= ITypeInfo_Invoke(typeinfo
, &This
->IDictionary_iface
, dispIdMember
, wFlags
,
303 pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
304 ITypeInfo_Release(typeinfo
);
310 static HRESULT WINAPI
dictionary_putref_Item(IDictionary
*iface
, VARIANT
*Key
, VARIANT
*pRetItem
)
312 dictionary
*This
= impl_from_IDictionary(iface
);
314 FIXME("(%p)->(%p %p)\n", This
, Key
, pRetItem
);
319 static HRESULT WINAPI
dictionary_put_Item(IDictionary
*iface
, VARIANT
*key
, VARIANT
*item
)
321 dictionary
*This
= impl_from_IDictionary(iface
);
322 struct keyitem_pair
*pair
;
324 TRACE("(%p)->(%s %s)\n", This
, debugstr_variant(key
), debugstr_variant(item
));
326 if ((pair
= get_keyitem_pair(This
, key
)))
327 return VariantCopyInd(&pair
->item
, item
);
329 return IDictionary_Add(iface
, key
, item
);
332 static HRESULT WINAPI
dictionary_get_Item(IDictionary
*iface
, VARIANT
*key
, VARIANT
*item
)
334 dictionary
*This
= impl_from_IDictionary(iface
);
335 struct keyitem_pair
*pair
;
337 TRACE("(%p)->(%s %p)\n", This
, debugstr_variant(key
), item
);
339 if ((pair
= get_keyitem_pair(This
, key
)))
340 VariantCopy(item
, &pair
->item
);
343 return IDictionary_Add(iface
, key
, item
);
349 static HRESULT WINAPI
dictionary_Add(IDictionary
*iface
, VARIANT
*key
, VARIANT
*item
)
351 dictionary
*This
= impl_from_IDictionary(iface
);
353 TRACE("(%p)->(%s %s)\n", This
, debugstr_variant(key
), debugstr_variant(item
));
355 if (get_keyitem_pair(This
, key
))
356 return CTL_E_KEY_ALREADY_EXISTS
;
358 return add_keyitem_pair(This
, key
, item
);
361 static HRESULT WINAPI
dictionary_get_Count(IDictionary
*iface
, LONG
*count
)
363 dictionary
*This
= impl_from_IDictionary(iface
);
365 TRACE("(%p)->(%p)\n", This
, count
);
367 *count
= This
->count
;
371 static HRESULT WINAPI
dictionary_Exists(IDictionary
*iface
, VARIANT
*Key
, VARIANT_BOOL
*pExists
)
373 dictionary
*This
= impl_from_IDictionary(iface
);
375 FIXME("(%p)->(%p %p)\n", This
, Key
, pExists
);
380 static HRESULT WINAPI
dictionary_Items(IDictionary
*iface
, VARIANT
*pItemsArray
)
382 dictionary
*This
= impl_from_IDictionary(iface
);
384 FIXME("(%p)->(%p)\n", This
, pItemsArray
);
389 static HRESULT WINAPI
dictionary_put_Key(IDictionary
*iface
, VARIANT
*Key
, VARIANT
*rhs
)
391 dictionary
*This
= impl_from_IDictionary(iface
);
393 FIXME("(%p)->(%p %p)\n", This
, Key
, rhs
);
398 static HRESULT WINAPI
dictionary_Keys(IDictionary
*iface
, VARIANT
*pKeysArray
)
400 dictionary
*This
= impl_from_IDictionary(iface
);
402 FIXME("(%p)->(%p)\n", This
, pKeysArray
);
407 static HRESULT WINAPI
dictionary_Remove(IDictionary
*iface
, VARIANT
*Key
)
409 dictionary
*This
= impl_from_IDictionary(iface
);
411 FIXME("(%p)->(%p)\n", This
, Key
);
416 static HRESULT WINAPI
dictionary_RemoveAll(IDictionary
*iface
)
418 dictionary
*This
= impl_from_IDictionary(iface
);
419 struct keyitem_pair
*pair
, *pair2
;
421 TRACE("(%p)\n", This
);
423 if (This
->count
== 0)
426 LIST_FOR_EACH_ENTRY_SAFE(pair
, pair2
, &This
->pairs
, struct keyitem_pair
, entry
) {
427 list_remove(&pair
->entry
);
428 free_keyitem_pair(pair
);
430 memset(This
->buckets
, 0, sizeof(This
->buckets
));
436 static HRESULT WINAPI
dictionary_put_CompareMode(IDictionary
*iface
, CompareMethod method
)
438 dictionary
*This
= impl_from_IDictionary(iface
);
440 TRACE("(%p)->(%d)\n", This
, method
);
443 return CTL_E_ILLEGALFUNCTIONCALL
;
445 This
->method
= method
;
449 static HRESULT WINAPI
dictionary_get_CompareMode(IDictionary
*iface
, CompareMethod
*method
)
451 dictionary
*This
= impl_from_IDictionary(iface
);
453 TRACE("(%p)->(%p)\n", This
, method
);
455 *method
= This
->method
;
459 static HRESULT WINAPI
dictionary__NewEnum(IDictionary
*iface
, IUnknown
**ppunk
)
461 dictionary
*This
= impl_from_IDictionary(iface
);
463 FIXME("(%p)->(%p)\n", This
, ppunk
);
468 static DWORD
get_str_hash(const WCHAR
*str
, CompareMethod method
)
476 ch
= (method
== TextCompare
|| method
== DatabaseCompare
) ? tolowerW(*str
) : *str
;
478 hash
+= (hash
<< 4) + ch
;
486 static DWORD
get_num_hash(FLOAT num
)
488 return (*((DWORD
*)&num
)) % 1201;
491 static HRESULT WINAPI
dictionary_get_HashVal(IDictionary
*iface
, VARIANT
*key
, VARIANT
*hash
)
493 dictionary
*This
= impl_from_IDictionary(iface
);
495 TRACE("(%p)->(%s %p)\n", This
, debugstr_variant(key
), hash
);
500 case VT_BSTR
|VT_BYREF
:
502 V_I4(hash
) = get_str_hash(get_key_strptr(key
), This
->method
);
505 V_I4(hash
) = get_num_hash(V_UI1(key
));
508 V_I4(hash
) = get_num_hash(V_I2(key
));
511 V_I4(hash
) = get_num_hash(V_I4(key
));
516 FLOAT flt
= V_VT(key
) == VT_R4
? V_R4(key
) : V_R8(key
);
523 else if (!isnan(flt
))
525 V_I4(hash
) = get_num_hash(flt
);
528 /* fallthrough on NAN */
537 return CTL_E_ILLEGALFUNCTIONCALL
;
539 FIXME("not implemented for type %d\n", V_VT(key
));
546 static const struct IDictionaryVtbl dictionary_vtbl
=
548 dictionary_QueryInterface
,
551 dictionary_GetTypeInfoCount
,
552 dictionary_GetTypeInfo
,
553 dictionary_GetIDsOfNames
,
555 dictionary_putref_Item
,
559 dictionary_get_Count
,
565 dictionary_RemoveAll
,
566 dictionary_put_CompareMode
,
567 dictionary_get_CompareMode
,
569 dictionary_get_HashVal
572 HRESULT WINAPI
Dictionary_CreateInstance(IClassFactory
*factory
,IUnknown
*outer
,REFIID riid
, void **obj
)
576 TRACE("(%p)\n", obj
);
580 This
= heap_alloc(sizeof(*This
));
581 if(!This
) return E_OUTOFMEMORY
;
583 This
->IDictionary_iface
.lpVtbl
= &dictionary_vtbl
;
585 This
->method
= BinaryCompare
;
587 list_init(&This
->pairs
);
588 memset(This
->buckets
, 0, sizeof(This
->buckets
));
590 *obj
= &This
->IDictionary_iface
;