e764b4935a6e7eb5da7cd193834d35b9be81b28d
[reactos.git] / reactos / dll / win32 / mshtml / propbag.c
1 /*
2 * Copyright 2010 Jacek Caban for CodeWeavers
3 *
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.
8 *
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.
13 *
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
17 */
18
19 #include <config.h>
20
21 #include <stdarg.h>
22
23 #define WIN32_NO_STATUS
24 #define _INC_WINDOWS
25
26 #define COBJMACROS
27
28 #include <windef.h>
29 #include <winbase.h>
30 //#include "winuser.h"
31 #include <ole2.h>
32 //#include "shlobj.h"
33
34 #include "mshtml_private.h"
35 #include "pluginhost.h"
36
37 #include <wine/debug.h>
38
39 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
40
41 typedef struct {
42 IPropertyBag IPropertyBag_iface;
43 IPropertyBag2 IPropertyBag2_iface;
44
45 LONG ref;
46
47 struct list props;
48 } PropertyBag;
49
50 typedef struct {
51 struct list entry;
52 WCHAR *name;
53 WCHAR *value;
54 } param_prop_t;
55
56 static void free_prop(param_prop_t *prop)
57 {
58 list_remove(&prop->entry);
59
60 heap_free(prop->name);
61 heap_free(prop->value);
62 heap_free(prop);
63 }
64
65 static param_prop_t *find_prop(PropertyBag *prop_bag, const WCHAR *name)
66 {
67 param_prop_t *iter;
68
69 LIST_FOR_EACH_ENTRY(iter, &prop_bag->props, param_prop_t, entry) {
70 if(!strcmpiW(iter->name, name))
71 return iter;
72 }
73
74 return NULL;
75 }
76
77 static HRESULT add_prop(PropertyBag *prop_bag, const WCHAR *name, const WCHAR *value)
78 {
79 param_prop_t *prop;
80
81 if(!name || !value)
82 return S_OK;
83
84 TRACE("%p %s %s\n", prop_bag, debugstr_w(name), debugstr_w(value));
85
86 prop = heap_alloc(sizeof(*prop));
87 if(!prop)
88 return E_OUTOFMEMORY;
89
90 prop->name = heap_strdupW(name);
91 prop->value = heap_strdupW(value);
92 if(!prop->name || !prop->value) {
93 list_init(&prop->entry);
94 free_prop(prop);
95 return E_OUTOFMEMORY;
96 }
97
98 list_add_tail(&prop_bag->props, &prop->entry);
99 return S_OK;
100 }
101
102 static inline PropertyBag *impl_from_IPropertyBag(IPropertyBag *iface)
103 {
104 return CONTAINING_RECORD(iface, PropertyBag, IPropertyBag_iface);
105 }
106
107 static HRESULT WINAPI PropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid, void **ppv)
108 {
109 PropertyBag *This = impl_from_IPropertyBag(iface);
110
111 if(IsEqualGUID(&IID_IUnknown, riid)) {
112 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
113 *ppv = &This->IPropertyBag_iface;
114 }else if(IsEqualGUID(&IID_IPropertyBag, riid)) {
115 TRACE("(%p)->(IID_IPropertyBag %p)\n", This, ppv);
116 *ppv = &This->IPropertyBag_iface;
117 }else if(IsEqualGUID(&IID_IPropertyBag2, riid)) {
118 TRACE("(%p)->(IID_IPropertyBag2 %p)\n", This, ppv);
119 *ppv = &This->IPropertyBag2_iface;
120 }else {
121 WARN("Unsopported interface %s\n", debugstr_guid(riid));
122 *ppv = NULL;
123 return E_NOINTERFACE;
124 }
125
126 IUnknown_AddRef((IUnknown*)*ppv);
127 return S_OK;
128 }
129
130 static ULONG WINAPI PropertyBag_AddRef(IPropertyBag *iface)
131 {
132 PropertyBag *This = impl_from_IPropertyBag(iface);
133 LONG ref = InterlockedIncrement(&This->ref);
134
135 TRACE("(%p) ref=%d\n", This, ref);
136
137 return ref;
138 }
139
140 static ULONG WINAPI PropertyBag_Release(IPropertyBag *iface)
141 {
142 PropertyBag *This = impl_from_IPropertyBag(iface);
143 LONG ref = InterlockedDecrement(&This->ref);
144
145 TRACE("(%p) ref=%d\n", This, ref);
146
147 if(!ref) {
148 while(!list_empty(&This->props))
149 free_prop(LIST_ENTRY(This->props.next, param_prop_t, entry));
150 heap_free(This);
151 }
152
153 return ref;
154 }
155
156 static HRESULT WINAPI PropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog)
157 {
158 PropertyBag *This = impl_from_IPropertyBag(iface);
159 param_prop_t *prop;
160 VARIANT v;
161
162 TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(pszPropName), pVar, pErrorLog);
163
164 prop = find_prop(This, pszPropName);
165 if(!prop) {
166 TRACE("Not found\n");
167 return E_INVALIDARG;
168 }
169
170 V_BSTR(&v) = SysAllocString(prop->value);
171 if(!V_BSTR(&v))
172 return E_OUTOFMEMORY;
173
174 if(V_VT(pVar) != VT_BSTR) {
175 HRESULT hres;
176
177 V_VT(&v) = VT_BSTR;
178 hres = VariantChangeType(pVar, &v, 0, V_VT(pVar));
179 SysFreeString(V_BSTR(&v));
180 return hres;
181 }
182
183 V_BSTR(pVar) = V_BSTR(&v);
184 return S_OK;
185 }
186
187 static HRESULT WINAPI PropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName, VARIANT *pVar)
188 {
189 PropertyBag *This = impl_from_IPropertyBag(iface);
190 FIXME("(%p)->(%s %s)\n", This, debugstr_w(pszPropName), debugstr_variant(pVar));
191 return E_NOTIMPL;
192 }
193
194 static const IPropertyBagVtbl PropertyBagVtbl = {
195 PropertyBag_QueryInterface,
196 PropertyBag_AddRef,
197 PropertyBag_Release,
198 PropertyBag_Read,
199 PropertyBag_Write
200 };
201
202 static inline PropertyBag *impl_from_IPropertyBag2(IPropertyBag2 *iface)
203 {
204 return CONTAINING_RECORD(iface, PropertyBag, IPropertyBag2_iface);
205 }
206
207 static HRESULT WINAPI PropertyBag2_QueryInterface(IPropertyBag2 *iface, REFIID riid, void **ppv)
208 {
209 PropertyBag *This = impl_from_IPropertyBag2(iface);
210 return IPropertyBag_QueryInterface(&This->IPropertyBag_iface, riid, ppv);
211 }
212
213 static ULONG WINAPI PropertyBag2_AddRef(IPropertyBag2 *iface)
214 {
215 PropertyBag *This = impl_from_IPropertyBag2(iface);
216 return IPropertyBag_AddRef(&This->IPropertyBag_iface);
217 }
218
219 static ULONG WINAPI PropertyBag2_Release(IPropertyBag2 *iface)
220 {
221 PropertyBag *This = impl_from_IPropertyBag2(iface);
222 return IPropertyBag_Release(&This->IPropertyBag_iface);
223 }
224
225 static HRESULT WINAPI PropertyBag2_Read(IPropertyBag2 *iface, ULONG cProperties, PROPBAG2 *pPropBag,
226 IErrorLog *pErrLog, VARIANT *pvarValue, HRESULT *phrError)
227 {
228 PropertyBag *This = impl_from_IPropertyBag2(iface);
229 FIXME("(%p)->(%d %p %p %p %p)\n", This, cProperties, pPropBag, pErrLog, pvarValue, phrError);
230 return E_NOTIMPL;
231 }
232
233 static HRESULT WINAPI PropertyBag2_Write(IPropertyBag2 *iface, ULONG cProperties, PROPBAG2 *pPropBag, VARIANT *pvarValue)
234 {
235 PropertyBag *This = impl_from_IPropertyBag2(iface);
236 FIXME("(%p)->(%d %p %s)\n", This, cProperties, pPropBag, debugstr_variant(pvarValue));
237 return E_NOTIMPL;
238 }
239
240 static HRESULT WINAPI PropertyBag2_CountProperties(IPropertyBag2 *iface, ULONG *pcProperties)
241 {
242 PropertyBag *This = impl_from_IPropertyBag2(iface);
243 FIXME("(%p)->(%p)\n", This, pcProperties);
244 return E_NOTIMPL;
245 }
246
247 static HRESULT WINAPI PropertyBag2_GetPropertyInfo(IPropertyBag2 *iface, ULONG iProperty, ULONG cProperties,
248 PROPBAG2 *pPropBag, ULONG *pcProperties)
249 {
250 PropertyBag *This = impl_from_IPropertyBag2(iface);
251 FIXME("(%p)->(%u %u %p %p)\n", This, iProperty, cProperties, pPropBag, pcProperties);
252 return E_NOTIMPL;
253 }
254
255 static HRESULT WINAPI PropertyBag2_LoadObject(IPropertyBag2 *iface, LPCOLESTR pstrName, DWORD dwHint,
256 IUnknown *pUnkObject, IErrorLog *pErrLog)
257 {
258 PropertyBag *This = impl_from_IPropertyBag2(iface);
259 FIXME("(%p)->(%s %x %p %p)\n", This, debugstr_w(pstrName), dwHint, pUnkObject, pErrLog);
260 return E_NOTIMPL;
261 }
262
263 static const IPropertyBag2Vtbl PropertyBag2Vtbl = {
264 PropertyBag2_QueryInterface,
265 PropertyBag2_AddRef,
266 PropertyBag2_Release,
267 PropertyBag2_Read,
268 PropertyBag2_Write,
269 PropertyBag2_CountProperties,
270 PropertyBag2_GetPropertyInfo,
271 PropertyBag2_LoadObject
272 };
273
274 static HRESULT fill_props(nsIDOMHTMLElement *nselem, PropertyBag *prop_bag)
275 {
276 nsIDOMHTMLParamElement *nsparam;
277 nsAString name_str, value_str;
278 nsIDOMHTMLCollection *params;
279 UINT32 length, i;
280 nsIDOMNode *nsnode;
281 nsresult nsres;
282 HRESULT hres = S_OK;
283
284 static const PRUnichar paramW[] = {'p','a','r','a','m',0};
285
286 nsAString_InitDepend(&name_str, paramW);
287 nsres = nsIDOMHTMLElement_GetElementsByTagName(nselem, &name_str, &params);
288 nsAString_Finish(&name_str);
289 if(NS_FAILED(nsres))
290 return E_FAIL;
291
292 nsres = nsIDOMHTMLCollection_GetLength(params, &length);
293 if(NS_FAILED(nsres))
294 length = 0;
295
296 for(i=0; i < length; i++) {
297 nsres = nsIDOMHTMLCollection_Item(params, i, &nsnode);
298 if(NS_FAILED(nsres)) {
299 hres = E_FAIL;
300 break;
301 }
302
303 nsres = nsIDOMNode_QueryInterface(nsnode, &IID_nsIDOMHTMLParamElement, (void**)&nsparam);
304 nsIDOMNode_Release(nsnode);
305 if(NS_FAILED(nsres)) {
306 hres = E_FAIL;
307 break;
308 }
309
310 nsAString_Init(&name_str, NULL);
311 nsres = nsIDOMHTMLParamElement_GetName(nsparam, &name_str);
312 if(NS_SUCCEEDED(nsres)) {
313 nsAString_Init(&value_str, NULL);
314 nsres = nsIDOMHTMLParamElement_GetValue(nsparam, &value_str);
315 if(NS_SUCCEEDED(nsres)) {
316 const PRUnichar *name, *value;
317
318 nsAString_GetData(&name_str, &name);
319 nsAString_GetData(&value_str, &value);
320
321 hres = add_prop(prop_bag, name, value);
322 }
323 nsAString_Finish(&value_str);
324 }
325
326 nsAString_Finish(&name_str);
327 nsIDOMHTMLParamElement_Release(nsparam);
328 if(FAILED(hres))
329 break;
330 if(NS_FAILED(nsres)) {
331 hres = E_FAIL;
332 break;
333 }
334 }
335
336 nsIDOMHTMLCollection_Release(params);
337 return hres;
338 }
339
340 HRESULT create_param_prop_bag(nsIDOMHTMLElement *nselem, IPropertyBag **ret)
341 {
342 PropertyBag *prop_bag;
343 HRESULT hres;
344
345 prop_bag = heap_alloc(sizeof(*prop_bag));
346 if(!prop_bag)
347 return E_OUTOFMEMORY;
348
349 prop_bag->IPropertyBag_iface.lpVtbl = &PropertyBagVtbl;
350 prop_bag->IPropertyBag2_iface.lpVtbl = &PropertyBag2Vtbl;
351 prop_bag->ref = 1;
352
353 list_init(&prop_bag->props);
354 hres = fill_props(nselem, prop_bag);
355 if(FAILED(hres) || list_empty(&prop_bag->props)) {
356 IPropertyBag_Release(&prop_bag->IPropertyBag_iface);
357 *ret = NULL;
358 return hres;
359 }
360
361 *ret = &prop_bag->IPropertyBag_iface;
362 return S_OK;
363 }