user32/tests: Link directly to imm32.
[wine.git] / dlls / mshtml / htmlstorage.c
blob1983d87a2961d7c5fd783f8643f8646d47be79bc
1 /*
2 * Copyright 2012 Jacek Caban for CodeWeavers
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
19 #include <stdarg.h>
21 #define COBJMACROS
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "ole2.h"
27 #include "shlobj.h"
29 #include "wine/debug.h"
31 #include "mshtml_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
35 typedef struct {
36 DispatchEx dispex;
37 IHTMLStorage IHTMLStorage_iface;
38 LONG ref;
39 WCHAR *filename;
40 HANDLE mutex;
41 } HTMLStorage;
43 static inline HTMLStorage *impl_from_IHTMLStorage(IHTMLStorage *iface)
45 return CONTAINING_RECORD(iface, HTMLStorage, IHTMLStorage_iface);
48 static HRESULT WINAPI HTMLStorage_QueryInterface(IHTMLStorage *iface, REFIID riid, void **ppv)
50 HTMLStorage *This = impl_from_IHTMLStorage(iface);
52 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
54 if(IsEqualGUID(&IID_IUnknown, riid)) {
55 *ppv = &This->IHTMLStorage_iface;
56 }else if(IsEqualGUID(&IID_IHTMLStorage, riid)) {
57 *ppv = &This->IHTMLStorage_iface;
58 }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
59 return *ppv ? S_OK : E_NOINTERFACE;
60 }else {
61 *ppv = NULL;
62 WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
63 return E_NOINTERFACE;
66 IUnknown_AddRef((IUnknown*)*ppv);
67 return S_OK;
70 static ULONG WINAPI HTMLStorage_AddRef(IHTMLStorage *iface)
72 HTMLStorage *This = impl_from_IHTMLStorage(iface);
73 LONG ref = InterlockedIncrement(&This->ref);
75 TRACE("(%p) ref=%ld\n", This, ref);
77 return ref;
80 static ULONG WINAPI HTMLStorage_Release(IHTMLStorage *iface)
82 HTMLStorage *This = impl_from_IHTMLStorage(iface);
83 LONG ref = InterlockedDecrement(&This->ref);
85 TRACE("(%p) ref=%ld\n", This, ref);
87 if(!ref) {
88 release_dispex(&This->dispex);
89 heap_free(This->filename);
90 CloseHandle(This->mutex);
91 heap_free(This);
94 return ref;
97 static HRESULT WINAPI HTMLStorage_GetTypeInfoCount(IHTMLStorage *iface, UINT *pctinfo)
99 HTMLStorage *This = impl_from_IHTMLStorage(iface);
100 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
103 static HRESULT WINAPI HTMLStorage_GetTypeInfo(IHTMLStorage *iface, UINT iTInfo,
104 LCID lcid, ITypeInfo **ppTInfo)
106 HTMLStorage *This = impl_from_IHTMLStorage(iface);
108 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
111 static HRESULT WINAPI HTMLStorage_GetIDsOfNames(IHTMLStorage *iface, REFIID riid, LPOLESTR *rgszNames, UINT cNames,
112 LCID lcid, DISPID *rgDispId)
114 HTMLStorage *This = impl_from_IHTMLStorage(iface);
116 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
117 lcid, rgDispId);
120 static HRESULT WINAPI HTMLStorage_Invoke(IHTMLStorage *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
121 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
123 HTMLStorage *This = impl_from_IHTMLStorage(iface);
125 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags,
126 pDispParams, pVarResult, pExcepInfo, puArgErr);
129 static BOOL create_path(const WCHAR *path)
131 BOOL ret = TRUE;
132 WCHAR *new_path;
133 int len;
135 new_path = heap_alloc((wcslen(path) + 1) * sizeof(WCHAR));
136 if(!new_path)
137 return FALSE;
138 wcscpy(new_path, path);
140 while((len = wcslen(new_path)) && new_path[len - 1] == '\\')
141 new_path[len - 1] = 0;
143 while(!CreateDirectoryW(new_path, NULL)) {
144 WCHAR *slash;
145 DWORD error = GetLastError();
146 if(error == ERROR_ALREADY_EXISTS) break;
147 if(error != ERROR_PATH_NOT_FOUND) {
148 ret = FALSE;
149 break;
151 slash = wcsrchr(new_path, '\\');
152 if(!slash) {
153 ret = FALSE;
154 break;
156 len = slash - new_path;
157 new_path[len] = 0;
158 if(!create_path(new_path)) {
159 ret = FALSE;
160 break;
162 new_path[len] = '\\';
164 heap_free(new_path);
165 return ret;
168 static HRESULT open_document(const WCHAR *filename, IXMLDOMDocument **ret)
170 IXMLDOMDocument *doc = NULL;
171 HRESULT hres = E_OUTOFMEMORY;
172 WCHAR *ptr, *path;
173 VARIANT var;
174 VARIANT_BOOL success;
176 path = heap_strdupW(filename);
177 if(!path)
178 return E_OUTOFMEMORY;
180 *(ptr = wcsrchr(path, '\\')) = 0;
181 if(!create_path(path))
182 goto done;
184 if(GetFileAttributesW(filename) == INVALID_FILE_ATTRIBUTES) {
185 DWORD count;
186 HANDLE file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
187 if(file == INVALID_HANDLE_VALUE) {
188 hres = HRESULT_FROM_WIN32(GetLastError());
189 goto done;
191 if(!WriteFile(file, "<root/>", sizeof("<root/>") - 1, &count, NULL)) {
192 CloseHandle(file);
193 hres = HRESULT_FROM_WIN32(GetLastError());
194 goto done;
196 CloseHandle(file);
199 hres = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void**)&doc);
200 if(hres != S_OK)
201 goto done;
203 V_VT(&var) = VT_BSTR;
204 V_BSTR(&var) = SysAllocString(filename);
205 if(!V_BSTR(&var)) {
206 hres = E_OUTOFMEMORY;
207 goto done;
210 hres = IXMLDOMDocument_load(doc, var, &success);
211 if(hres == S_FALSE || success == VARIANT_FALSE)
212 hres = E_FAIL;
214 SysFreeString(V_BSTR(&var));
216 done:
217 heap_free(path);
218 if(hres == S_OK)
219 *ret = doc;
220 else if(doc)
221 IXMLDOMDocument_Release(doc);
223 return hres;
226 static HRESULT WINAPI HTMLStorage_get_length(IHTMLStorage *iface, LONG *p)
228 HTMLStorage *This = impl_from_IHTMLStorage(iface);
229 FIXME("(%p)->(%p)\n", This, p);
230 return E_NOTIMPL;
233 static HRESULT WINAPI HTMLStorage_get_remainingSpace(IHTMLStorage *iface, LONG *p)
235 HTMLStorage *This = impl_from_IHTMLStorage(iface);
236 FIXME("(%p)->(%p)\n", This, p);
237 return E_NOTIMPL;
240 static HRESULT WINAPI HTMLStorage_key(IHTMLStorage *iface, LONG lIndex, BSTR *p)
242 HTMLStorage *This = impl_from_IHTMLStorage(iface);
243 FIXME("(%p)->(%ld %p)\n", This, lIndex, p);
244 return E_NOTIMPL;
247 static BSTR build_query(const WCHAR *key)
249 static const WCHAR fmt[] = L"item[@name='%s']";
250 const WCHAR *str = key ? key : L"";
251 UINT len = ARRAY_SIZE(fmt) + wcslen(str);
252 BSTR ret = SysAllocStringLen(NULL, len);
254 if(ret) swprintf(ret, len, fmt, str);
255 return ret;
258 static HRESULT get_root_node(IXMLDOMDocument *doc, IXMLDOMNode **root)
260 HRESULT hres;
261 BSTR str;
263 str = SysAllocString(L"root");
264 if(!str)
265 return E_OUTOFMEMORY;
267 hres = IXMLDOMDocument_selectSingleNode(doc, str, root);
268 SysFreeString(str);
269 return hres;
272 static HRESULT get_item(const WCHAR *filename, BSTR key, VARIANT *value)
274 IXMLDOMDocument *doc;
275 BSTR query = NULL;
276 IXMLDOMNode *root = NULL, *node = NULL;
277 IXMLDOMElement *elem = NULL;
278 HRESULT hres;
280 hres = open_document(filename, &doc);
281 if(hres != S_OK)
282 return hres;
284 hres = get_root_node(doc, &root);
285 if(hres != S_OK)
286 goto done;
288 query = build_query(key);
289 if(!query) {
290 hres = E_OUTOFMEMORY;
291 goto done;
294 hres = IXMLDOMNode_selectSingleNode(root, query, &node);
295 if(hres == S_OK) {
296 hres = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)&elem);
297 if(hres != S_OK)
298 goto done;
300 hres = IXMLDOMElement_getAttribute(elem, (BSTR)L"value", value);
301 }else {
302 V_VT(value) = VT_NULL;
303 hres = S_OK;
306 done:
307 SysFreeString(query);
308 if(root)
309 IXMLDOMNode_Release(root);
310 if(node)
311 IXMLDOMNode_Release(node);
312 if(elem)
313 IXMLDOMElement_Release(elem);
314 IXMLDOMDocument_Release(doc);
315 return hres;
318 static HRESULT WINAPI HTMLStorage_getItem(IHTMLStorage *iface, BSTR bstrKey, VARIANT *value)
320 HTMLStorage *This = impl_from_IHTMLStorage(iface);
321 HRESULT hres;
323 TRACE("(%p)->(%s %p)\n", This, debugstr_w(bstrKey), value);
325 if(!value)
326 return E_POINTER;
328 if(!This->filename) {
329 FIXME("session storage not supported\n");
330 V_VT(value) = VT_NULL;
331 return S_OK;
334 WaitForSingleObject(This->mutex, INFINITE);
335 hres = get_item(This->filename, bstrKey, value);
336 ReleaseMutex(This->mutex);
338 return hres;
341 static HRESULT set_attribute(IXMLDOMElement *elem, const WCHAR *name, BSTR value)
343 BSTR str;
344 VARIANT var;
345 HRESULT hres;
347 str = SysAllocString(name);
348 if(!str)
349 return E_OUTOFMEMORY;
350 V_VT(&var) = VT_BSTR;
351 V_BSTR(&var) = value;
353 hres = IXMLDOMElement_setAttribute(elem, str, var);
354 SysFreeString(str);
355 return hres;
358 static HRESULT save_document(IXMLDOMDocument *doc, const WCHAR *filename)
360 VARIANT var;
361 HRESULT hres;
363 V_VT(&var) = VT_BSTR;
364 V_BSTR(&var) = SysAllocString(filename);
365 if(!V_BSTR(&var))
366 return E_OUTOFMEMORY;
368 hres = IXMLDOMDocument_save(doc, var);
369 SysFreeString(V_BSTR(&var));
370 return hres;
373 static HRESULT set_item(const WCHAR *filename, BSTR key, BSTR value)
375 IXMLDOMDocument *doc;
376 IXMLDOMNode *root = NULL, *node = NULL;
377 IXMLDOMElement *elem = NULL;
378 BSTR query = NULL;
379 HRESULT hres;
381 hres = open_document(filename, &doc);
382 if(hres != S_OK)
383 return hres;
385 hres = get_root_node(doc, &root);
386 if(hres != S_OK)
387 goto done;
389 query = build_query(key);
390 if(!query) {
391 hres = E_OUTOFMEMORY;
392 goto done;
395 hres = IXMLDOMNode_selectSingleNode(root, query, &node);
396 if(hres == S_OK) {
397 hres = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)&elem);
398 if(hres != S_OK)
399 goto done;
401 hres = set_attribute(elem, L"value", value);
402 if(hres != S_OK)
403 goto done;
404 }else {
405 BSTR str = SysAllocString(L"item");
406 hres = IXMLDOMDocument_createElement(doc, str, &elem);
407 SysFreeString(str);
408 if(hres != S_OK)
409 goto done;
411 hres = set_attribute(elem, L"name", key);
412 if(hres != S_OK)
413 goto done;
415 hres = set_attribute(elem, L"value", value);
416 if(hres != S_OK)
417 goto done;
419 hres = IXMLDOMNode_appendChild(root, (IXMLDOMNode*)elem, NULL);
420 if(hres != S_OK)
421 goto done;
424 hres = save_document(doc, filename);
426 done:
427 SysFreeString(query);
428 if(root)
429 IXMLDOMNode_Release(root);
430 if(node)
431 IXMLDOMNode_Release(node);
432 if(elem)
433 IXMLDOMElement_Release(elem);
434 IXMLDOMDocument_Release(doc);
435 return hres;
438 static HRESULT WINAPI HTMLStorage_setItem(IHTMLStorage *iface, BSTR bstrKey, BSTR bstrValue)
440 HTMLStorage *This = impl_from_IHTMLStorage(iface);
441 HRESULT hres;
443 TRACE("(%p)->(%s %s)\n", This, debugstr_w(bstrKey), debugstr_w(bstrValue));
445 if(!This->filename) {
446 FIXME("session storage not supported\n");
447 return E_NOTIMPL;
450 WaitForSingleObject(This->mutex, INFINITE);
451 hres = set_item(This->filename, bstrKey, bstrValue);
452 ReleaseMutex(This->mutex);
454 return hres;
457 static HRESULT remove_item(const WCHAR *filename, BSTR key)
459 IXMLDOMDocument *doc;
460 IXMLDOMNode *root = NULL, *node = NULL;
461 BSTR query = NULL;
462 HRESULT hres;
464 hres = open_document(filename, &doc);
465 if(hres != S_OK)
466 return hres;
468 hres = get_root_node(doc, &root);
469 if(hres != S_OK)
470 goto done;
472 query = build_query(key);
473 if(!query) {
474 hres = E_OUTOFMEMORY;
475 goto done;
478 hres = IXMLDOMNode_selectSingleNode(root, query, &node);
479 if(hres == S_OK) {
480 hres = IXMLDOMNode_removeChild(root, node, NULL);
481 if(hres != S_OK)
482 goto done;
485 hres = save_document(doc, filename);
487 done:
488 SysFreeString(query);
489 if(root)
490 IXMLDOMNode_Release(root);
491 if(node)
492 IXMLDOMNode_Release(node);
493 IXMLDOMDocument_Release(doc);
494 return hres;
497 static HRESULT WINAPI HTMLStorage_removeItem(IHTMLStorage *iface, BSTR bstrKey)
499 HTMLStorage *This = impl_from_IHTMLStorage(iface);
500 HRESULT hres;
502 TRACE("(%p)->(%s)\n", This, debugstr_w(bstrKey));
504 if(!This->filename) {
505 FIXME("session storage not supported\n");
506 return E_NOTIMPL;
509 WaitForSingleObject(This->mutex, INFINITE);
510 hres = remove_item(This->filename, bstrKey);
511 ReleaseMutex(This->mutex);
513 return hres;
516 static HRESULT WINAPI HTMLStorage_clear(IHTMLStorage *iface)
518 HTMLStorage *This = impl_from_IHTMLStorage(iface);
519 FIXME("(%p)->()\n", This);
520 return E_NOTIMPL;
523 static const IHTMLStorageVtbl HTMLStorageVtbl = {
524 HTMLStorage_QueryInterface,
525 HTMLStorage_AddRef,
526 HTMLStorage_Release,
527 HTMLStorage_GetTypeInfoCount,
528 HTMLStorage_GetTypeInfo,
529 HTMLStorage_GetIDsOfNames,
530 HTMLStorage_Invoke,
531 HTMLStorage_get_length,
532 HTMLStorage_get_remainingSpace,
533 HTMLStorage_key,
534 HTMLStorage_getItem,
535 HTMLStorage_setItem,
536 HTMLStorage_removeItem,
537 HTMLStorage_clear
540 static const tid_t HTMLStorage_iface_tids[] = {
541 IHTMLStorage_tid,
544 static dispex_static_data_t HTMLStorage_dispex = {
545 L"Storage",
546 NULL,
547 IHTMLStorage_tid,
548 HTMLStorage_iface_tids
551 static WCHAR *build_filename(IUri *uri)
553 static const WCHAR store[] = L"\\Microsoft\\Internet Explorer\\DOMStore\\";
554 WCHAR path[MAX_PATH], *ret;
555 BSTR hostname;
556 HRESULT hres;
557 int len;
559 hres = IUri_GetHost(uri, &hostname);
560 if(hres != S_OK)
561 return NULL;
563 if(!SHGetSpecialFolderPathW(NULL, path, CSIDL_LOCAL_APPDATA, TRUE)) {
564 ERR("Can't get folder path %lu\n", GetLastError());
565 SysFreeString(hostname);
566 return NULL;
569 len = wcslen(path);
570 if(len + ARRAY_SIZE(store) > ARRAY_SIZE(path)) {
571 ERR("Path too long\n");
572 SysFreeString(hostname);
573 return NULL;
575 memcpy(path + len, store, sizeof(store));
577 len += ARRAY_SIZE(store);
578 ret = heap_alloc((len + wcslen(hostname) + ARRAY_SIZE(L".xml")) * sizeof(WCHAR));
579 if(!ret) {
580 SysFreeString(hostname);
581 return NULL;
584 wcscpy(ret, path);
585 wcscat(ret, hostname);
586 wcscat(ret, L".xml");
588 SysFreeString(hostname);
589 return ret;
592 static WCHAR *build_mutexname(const WCHAR *filename)
594 WCHAR *ret, *ptr;
595 ret = heap_strdupW(filename);
596 if(!ret)
597 return NULL;
598 for(ptr = ret; *ptr; ptr++)
599 if(*ptr == '\\') *ptr = '_';
600 return ret;
603 HRESULT create_html_storage(compat_mode_t compat_mode, IUri *uri, IHTMLStorage **p)
605 HTMLStorage *storage;
607 storage = heap_alloc_zero(sizeof(*storage));
608 if(!storage)
609 return E_OUTOFMEMORY;
611 if(uri) {
612 WCHAR *mutexname;
613 if(!(storage->filename = build_filename(uri))) {
614 heap_free(storage);
615 return E_OUTOFMEMORY;
617 mutexname = build_mutexname(storage->filename);
618 if(!mutexname) {
619 heap_free(storage->filename);
620 heap_free(storage);
621 return E_OUTOFMEMORY;
623 storage->mutex = CreateMutexW(NULL, FALSE, mutexname);
624 heap_free(mutexname);
625 if(!storage->mutex) {
626 heap_free(storage->filename);
627 heap_free(storage);
628 return HRESULT_FROM_WIN32(GetLastError());
632 storage->IHTMLStorage_iface.lpVtbl = &HTMLStorageVtbl;
633 storage->ref = 1;
634 init_dispatch(&storage->dispex, (IUnknown*)&storage->IHTMLStorage_iface, &HTMLStorage_dispex, compat_mode);
636 *p = &storage->IHTMLStorage_iface;
637 return S_OK;