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