mshtml: Implement getItem() for sessionStorage.
[wine.git] / dlls / mshtml / htmlstorage.c
blobd25f8fef6a1f73d2c1a4db1e9bcb9baaf210fc66
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 struct session_map_entry *session_storage;
40 WCHAR *filename;
41 HANDLE mutex;
42 } HTMLStorage;
44 struct session_map_entry {
45 struct wine_rb_entry entry;
46 struct wine_rb_tree data_map;
47 UINT ref;
48 UINT num_keys;
49 UINT origin_len;
50 WCHAR origin[1];
53 int session_storage_map_cmp(const void *key, const struct wine_rb_entry *entry)
55 struct session_map_entry *p = WINE_RB_ENTRY_VALUE(entry, struct session_map_entry, entry);
56 UINT len = SysStringLen((BSTR)key);
58 return (len != p->origin_len) ? (len - p->origin_len) : memcmp(key, p->origin, len * sizeof(WCHAR));
61 struct session_entry
63 struct wine_rb_entry entry;
64 BSTR value;
65 WCHAR key[1];
68 static int session_entry_cmp(const void *key, const struct wine_rb_entry *entry)
70 struct session_entry *data = WINE_RB_ENTRY_VALUE(entry, struct session_entry, entry);
71 return wcscmp(key, data->key);
74 static struct session_map_entry *grab_session_map_entry(BSTR origin)
76 struct session_map_entry *entry;
77 struct wine_rb_entry *rb_entry;
78 thread_data_t *thread_data;
79 UINT origin_len;
81 thread_data = get_thread_data(TRUE);
82 if(!thread_data)
83 return NULL;
85 rb_entry = wine_rb_get(&thread_data->session_storage_map, origin);
86 if(rb_entry) {
87 entry = WINE_RB_ENTRY_VALUE(rb_entry, struct session_map_entry, entry);
88 entry->ref++;
89 return entry;
92 origin_len = SysStringLen(origin);
93 entry = heap_alloc(FIELD_OFFSET(struct session_map_entry, origin[origin_len]));
94 if(!entry)
95 return NULL;
96 wine_rb_init(&entry->data_map, session_entry_cmp);
97 entry->ref = 1;
98 entry->num_keys = 0;
99 entry->origin_len = origin_len;
100 memcpy(entry->origin, origin, origin_len * sizeof(WCHAR));
102 wine_rb_put(&thread_data->session_storage_map, origin, &entry->entry);
103 return entry;
106 static void release_session_map_entry(struct session_map_entry *entry)
108 if(!entry || --entry->ref || entry->num_keys)
109 return;
111 wine_rb_remove(&get_thread_data(FALSE)->session_storage_map, &entry->entry);
112 heap_free(entry);
115 static HRESULT get_session_entry(struct session_map_entry *entry, const WCHAR *name, BOOL create, struct session_entry **ret)
117 const WCHAR *key = name ? name : L"";
118 struct wine_rb_entry *rb_entry;
119 struct session_entry *data;
120 UINT key_len;
122 rb_entry = wine_rb_get(&entry->data_map, key);
123 if(rb_entry) {
124 *ret = WINE_RB_ENTRY_VALUE(rb_entry, struct session_entry, entry);
125 return S_OK;
128 if(!create) {
129 *ret = NULL;
130 return S_OK;
133 key_len = wcslen(key);
134 if(!(data = heap_alloc(FIELD_OFFSET(struct session_entry, key[key_len + 1]))))
135 return E_OUTOFMEMORY;
136 data->value = NULL;
137 memcpy(data->key, key, (key_len + 1) * sizeof(WCHAR));
139 entry->num_keys++;
140 wine_rb_put(&entry->data_map, key, &data->entry);
141 *ret = data;
142 return S_OK;
145 static void clear_session_storage(struct session_map_entry *entry)
147 struct session_entry *iter, *iter2;
149 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR(iter, iter2, &entry->data_map, struct session_entry, entry) {
150 SysFreeString(iter->value);
151 heap_free(iter);
153 wine_rb_destroy(&entry->data_map, NULL, NULL);
154 entry->num_keys = 0;
157 void destroy_session_storage(thread_data_t *thread_data)
159 struct session_map_entry *iter, *iter2;
161 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR(iter, iter2, &thread_data->session_storage_map, struct session_map_entry, entry) {
162 clear_session_storage(iter);
163 heap_free(iter);
167 static inline HTMLStorage *impl_from_IHTMLStorage(IHTMLStorage *iface)
169 return CONTAINING_RECORD(iface, HTMLStorage, IHTMLStorage_iface);
172 static HRESULT WINAPI HTMLStorage_QueryInterface(IHTMLStorage *iface, REFIID riid, void **ppv)
174 HTMLStorage *This = impl_from_IHTMLStorage(iface);
176 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
178 if(IsEqualGUID(&IID_IUnknown, riid)) {
179 *ppv = &This->IHTMLStorage_iface;
180 }else if(IsEqualGUID(&IID_IHTMLStorage, riid)) {
181 *ppv = &This->IHTMLStorage_iface;
182 }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
183 return *ppv ? S_OK : E_NOINTERFACE;
184 }else {
185 *ppv = NULL;
186 WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
187 return E_NOINTERFACE;
190 IUnknown_AddRef((IUnknown*)*ppv);
191 return S_OK;
194 static ULONG WINAPI HTMLStorage_AddRef(IHTMLStorage *iface)
196 HTMLStorage *This = impl_from_IHTMLStorage(iface);
197 LONG ref = InterlockedIncrement(&This->ref);
199 TRACE("(%p) ref=%ld\n", This, ref);
201 return ref;
204 static ULONG WINAPI HTMLStorage_Release(IHTMLStorage *iface)
206 HTMLStorage *This = impl_from_IHTMLStorage(iface);
207 LONG ref = InterlockedDecrement(&This->ref);
209 TRACE("(%p) ref=%ld\n", This, ref);
211 if(!ref) {
212 release_session_map_entry(This->session_storage);
213 release_dispex(&This->dispex);
214 heap_free(This->filename);
215 CloseHandle(This->mutex);
216 heap_free(This);
219 return ref;
222 static HRESULT WINAPI HTMLStorage_GetTypeInfoCount(IHTMLStorage *iface, UINT *pctinfo)
224 HTMLStorage *This = impl_from_IHTMLStorage(iface);
225 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
228 static HRESULT WINAPI HTMLStorage_GetTypeInfo(IHTMLStorage *iface, UINT iTInfo,
229 LCID lcid, ITypeInfo **ppTInfo)
231 HTMLStorage *This = impl_from_IHTMLStorage(iface);
233 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
236 static HRESULT WINAPI HTMLStorage_GetIDsOfNames(IHTMLStorage *iface, REFIID riid, LPOLESTR *rgszNames, UINT cNames,
237 LCID lcid, DISPID *rgDispId)
239 HTMLStorage *This = impl_from_IHTMLStorage(iface);
241 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
242 lcid, rgDispId);
245 static HRESULT WINAPI HTMLStorage_Invoke(IHTMLStorage *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
246 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
248 HTMLStorage *This = impl_from_IHTMLStorage(iface);
250 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags,
251 pDispParams, pVarResult, pExcepInfo, puArgErr);
254 static BOOL create_path(const WCHAR *path)
256 BOOL ret = TRUE;
257 WCHAR *new_path;
258 int len;
260 new_path = heap_alloc((wcslen(path) + 1) * sizeof(WCHAR));
261 if(!new_path)
262 return FALSE;
263 wcscpy(new_path, path);
265 while((len = wcslen(new_path)) && new_path[len - 1] == '\\')
266 new_path[len - 1] = 0;
268 while(!CreateDirectoryW(new_path, NULL)) {
269 WCHAR *slash;
270 DWORD error = GetLastError();
271 if(error == ERROR_ALREADY_EXISTS) break;
272 if(error != ERROR_PATH_NOT_FOUND) {
273 ret = FALSE;
274 break;
276 slash = wcsrchr(new_path, '\\');
277 if(!slash) {
278 ret = FALSE;
279 break;
281 len = slash - new_path;
282 new_path[len] = 0;
283 if(!create_path(new_path)) {
284 ret = FALSE;
285 break;
287 new_path[len] = '\\';
289 heap_free(new_path);
290 return ret;
293 static HRESULT open_document(const WCHAR *filename, IXMLDOMDocument **ret)
295 IXMLDOMDocument *doc = NULL;
296 HRESULT hres = E_OUTOFMEMORY;
297 WCHAR *ptr, *path;
298 VARIANT var;
299 VARIANT_BOOL success;
301 path = heap_strdupW(filename);
302 if(!path)
303 return E_OUTOFMEMORY;
305 *(ptr = wcsrchr(path, '\\')) = 0;
306 if(!create_path(path))
307 goto done;
309 if(GetFileAttributesW(filename) == INVALID_FILE_ATTRIBUTES) {
310 DWORD count;
311 HANDLE file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
312 if(file == INVALID_HANDLE_VALUE) {
313 hres = HRESULT_FROM_WIN32(GetLastError());
314 goto done;
316 if(!WriteFile(file, "<root/>", sizeof("<root/>") - 1, &count, NULL)) {
317 CloseHandle(file);
318 hres = HRESULT_FROM_WIN32(GetLastError());
319 goto done;
321 CloseHandle(file);
324 hres = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void**)&doc);
325 if(hres != S_OK)
326 goto done;
328 V_VT(&var) = VT_BSTR;
329 V_BSTR(&var) = SysAllocString(filename);
330 if(!V_BSTR(&var)) {
331 hres = E_OUTOFMEMORY;
332 goto done;
335 hres = IXMLDOMDocument_load(doc, var, &success);
336 if(hres == S_FALSE || success == VARIANT_FALSE)
337 hres = E_FAIL;
339 SysFreeString(V_BSTR(&var));
341 done:
342 heap_free(path);
343 if(hres == S_OK)
344 *ret = doc;
345 else if(doc)
346 IXMLDOMDocument_Release(doc);
348 return hres;
351 static HRESULT WINAPI HTMLStorage_get_length(IHTMLStorage *iface, LONG *p)
353 HTMLStorage *This = impl_from_IHTMLStorage(iface);
354 FIXME("(%p)->(%p)\n", This, p);
355 return E_NOTIMPL;
358 static HRESULT WINAPI HTMLStorage_get_remainingSpace(IHTMLStorage *iface, LONG *p)
360 HTMLStorage *This = impl_from_IHTMLStorage(iface);
361 FIXME("(%p)->(%p)\n", This, p);
362 return E_NOTIMPL;
365 static HRESULT WINAPI HTMLStorage_key(IHTMLStorage *iface, LONG lIndex, BSTR *p)
367 HTMLStorage *This = impl_from_IHTMLStorage(iface);
368 FIXME("(%p)->(%ld %p)\n", This, lIndex, p);
369 return E_NOTIMPL;
372 static BSTR build_query(const WCHAR *key)
374 static const WCHAR fmt[] = L"item[@name='%s']";
375 const WCHAR *str = key ? key : L"";
376 UINT len = ARRAY_SIZE(fmt) + wcslen(str);
377 BSTR ret = SysAllocStringLen(NULL, len);
379 if(ret) swprintf(ret, len, fmt, str);
380 return ret;
383 static HRESULT get_root_node(IXMLDOMDocument *doc, IXMLDOMNode **root)
385 HRESULT hres;
386 BSTR str;
388 str = SysAllocString(L"root");
389 if(!str)
390 return E_OUTOFMEMORY;
392 hres = IXMLDOMDocument_selectSingleNode(doc, str, root);
393 SysFreeString(str);
394 return hres;
397 static HRESULT get_item(const WCHAR *filename, BSTR key, VARIANT *value)
399 IXMLDOMDocument *doc;
400 BSTR query = NULL;
401 IXMLDOMNode *root = NULL, *node = NULL;
402 IXMLDOMElement *elem = NULL;
403 HRESULT hres;
405 hres = open_document(filename, &doc);
406 if(hres != S_OK)
407 return hres;
409 hres = get_root_node(doc, &root);
410 if(hres != S_OK)
411 goto done;
413 query = build_query(key);
414 if(!query) {
415 hres = E_OUTOFMEMORY;
416 goto done;
419 hres = IXMLDOMNode_selectSingleNode(root, query, &node);
420 if(hres == S_OK) {
421 hres = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)&elem);
422 if(hres != S_OK)
423 goto done;
425 hres = IXMLDOMElement_getAttribute(elem, (BSTR)L"value", value);
426 }else {
427 V_VT(value) = VT_NULL;
428 hres = S_OK;
431 done:
432 SysFreeString(query);
433 if(root)
434 IXMLDOMNode_Release(root);
435 if(node)
436 IXMLDOMNode_Release(node);
437 if(elem)
438 IXMLDOMElement_Release(elem);
439 IXMLDOMDocument_Release(doc);
440 return hres;
443 static HRESULT WINAPI HTMLStorage_getItem(IHTMLStorage *iface, BSTR bstrKey, VARIANT *value)
445 HTMLStorage *This = impl_from_IHTMLStorage(iface);
446 struct session_entry *session_entry;
447 HRESULT hres;
449 TRACE("(%p)->(%s %p)\n", This, debugstr_w(bstrKey), value);
451 if(!value)
452 return E_POINTER;
454 if(!This->filename) {
455 hres = get_session_entry(This->session_storage, bstrKey, FALSE, &session_entry);
456 if(SUCCEEDED(hres)) {
457 if(!session_entry || !session_entry->value)
458 V_VT(value) = VT_NULL;
459 else {
460 V_VT(value) = VT_BSTR;
461 V_BSTR(value) = SysAllocStringLen(session_entry->value, SysStringLen(session_entry->value));
462 hres = V_BSTR(value) ? S_OK : E_OUTOFMEMORY;
465 return hres;
468 WaitForSingleObject(This->mutex, INFINITE);
469 hres = get_item(This->filename, bstrKey, value);
470 ReleaseMutex(This->mutex);
472 return hres;
475 static HRESULT set_attribute(IXMLDOMElement *elem, const WCHAR *name, BSTR value)
477 BSTR str;
478 VARIANT var;
479 HRESULT hres;
481 str = SysAllocString(name);
482 if(!str)
483 return E_OUTOFMEMORY;
484 V_VT(&var) = VT_BSTR;
485 V_BSTR(&var) = value;
487 hres = IXMLDOMElement_setAttribute(elem, str, var);
488 SysFreeString(str);
489 return hres;
492 static HRESULT save_document(IXMLDOMDocument *doc, const WCHAR *filename)
494 VARIANT var;
495 HRESULT hres;
497 V_VT(&var) = VT_BSTR;
498 V_BSTR(&var) = SysAllocString(filename);
499 if(!V_BSTR(&var))
500 return E_OUTOFMEMORY;
502 hres = IXMLDOMDocument_save(doc, var);
503 SysFreeString(V_BSTR(&var));
504 return hres;
507 static HRESULT set_item(const WCHAR *filename, BSTR key, BSTR value)
509 IXMLDOMDocument *doc;
510 IXMLDOMNode *root = NULL, *node = NULL;
511 IXMLDOMElement *elem = NULL;
512 BSTR query = NULL;
513 HRESULT hres;
515 hres = open_document(filename, &doc);
516 if(hres != S_OK)
517 return hres;
519 hres = get_root_node(doc, &root);
520 if(hres != S_OK)
521 goto done;
523 query = build_query(key);
524 if(!query) {
525 hres = E_OUTOFMEMORY;
526 goto done;
529 hres = IXMLDOMNode_selectSingleNode(root, query, &node);
530 if(hres == S_OK) {
531 hres = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)&elem);
532 if(hres != S_OK)
533 goto done;
535 hres = set_attribute(elem, L"value", value);
536 if(hres != S_OK)
537 goto done;
538 }else {
539 BSTR str = SysAllocString(L"item");
540 hres = IXMLDOMDocument_createElement(doc, str, &elem);
541 SysFreeString(str);
542 if(hres != S_OK)
543 goto done;
545 hres = set_attribute(elem, L"name", key);
546 if(hres != S_OK)
547 goto done;
549 hres = set_attribute(elem, L"value", value);
550 if(hres != S_OK)
551 goto done;
553 hres = IXMLDOMNode_appendChild(root, (IXMLDOMNode*)elem, NULL);
554 if(hres != S_OK)
555 goto done;
558 hres = save_document(doc, filename);
560 done:
561 SysFreeString(query);
562 if(root)
563 IXMLDOMNode_Release(root);
564 if(node)
565 IXMLDOMNode_Release(node);
566 if(elem)
567 IXMLDOMElement_Release(elem);
568 IXMLDOMDocument_Release(doc);
569 return hres;
572 static HRESULT WINAPI HTMLStorage_setItem(IHTMLStorage *iface, BSTR bstrKey, BSTR bstrValue)
574 HTMLStorage *This = impl_from_IHTMLStorage(iface);
575 struct session_entry *session_entry;
576 HRESULT hres;
578 TRACE("(%p)->(%s %s)\n", This, debugstr_w(bstrKey), debugstr_w(bstrValue));
580 if(!This->filename) {
581 BSTR value = SysAllocString(bstrValue ? bstrValue : L"");
582 if(!value)
583 return E_OUTOFMEMORY;
585 hres = get_session_entry(This->session_storage, bstrKey, TRUE, &session_entry);
586 if(FAILED(hres))
587 SysFreeString(value);
588 else {
589 SysFreeString(session_entry->value);
590 session_entry->value = value;
592 return hres;
595 WaitForSingleObject(This->mutex, INFINITE);
596 hres = set_item(This->filename, bstrKey, bstrValue);
597 ReleaseMutex(This->mutex);
599 return hres;
602 static HRESULT remove_item(const WCHAR *filename, BSTR key)
604 IXMLDOMDocument *doc;
605 IXMLDOMNode *root = NULL, *node = NULL;
606 BSTR query = NULL;
607 HRESULT hres;
609 hres = open_document(filename, &doc);
610 if(hres != S_OK)
611 return hres;
613 hres = get_root_node(doc, &root);
614 if(hres != S_OK)
615 goto done;
617 query = build_query(key);
618 if(!query) {
619 hres = E_OUTOFMEMORY;
620 goto done;
623 hres = IXMLDOMNode_selectSingleNode(root, query, &node);
624 if(hres == S_OK) {
625 hres = IXMLDOMNode_removeChild(root, node, NULL);
626 if(hres != S_OK)
627 goto done;
630 hres = save_document(doc, filename);
632 done:
633 SysFreeString(query);
634 if(root)
635 IXMLDOMNode_Release(root);
636 if(node)
637 IXMLDOMNode_Release(node);
638 IXMLDOMDocument_Release(doc);
639 return hres;
642 static HRESULT WINAPI HTMLStorage_removeItem(IHTMLStorage *iface, BSTR bstrKey)
644 HTMLStorage *This = impl_from_IHTMLStorage(iface);
645 HRESULT hres;
647 TRACE("(%p)->(%s)\n", This, debugstr_w(bstrKey));
649 if(!This->filename) {
650 FIXME("session storage not supported\n");
651 return E_NOTIMPL;
654 WaitForSingleObject(This->mutex, INFINITE);
655 hres = remove_item(This->filename, bstrKey);
656 ReleaseMutex(This->mutex);
658 return hres;
661 static HRESULT WINAPI HTMLStorage_clear(IHTMLStorage *iface)
663 HTMLStorage *This = impl_from_IHTMLStorage(iface);
664 FIXME("(%p)->()\n", This);
665 return E_NOTIMPL;
668 static const IHTMLStorageVtbl HTMLStorageVtbl = {
669 HTMLStorage_QueryInterface,
670 HTMLStorage_AddRef,
671 HTMLStorage_Release,
672 HTMLStorage_GetTypeInfoCount,
673 HTMLStorage_GetTypeInfo,
674 HTMLStorage_GetIDsOfNames,
675 HTMLStorage_Invoke,
676 HTMLStorage_get_length,
677 HTMLStorage_get_remainingSpace,
678 HTMLStorage_key,
679 HTMLStorage_getItem,
680 HTMLStorage_setItem,
681 HTMLStorage_removeItem,
682 HTMLStorage_clear
685 static const tid_t HTMLStorage_iface_tids[] = {
686 IHTMLStorage_tid,
689 static dispex_static_data_t HTMLStorage_dispex = {
690 L"Storage",
691 NULL,
692 IHTMLStorage_tid,
693 HTMLStorage_iface_tids
696 static HRESULT build_session_origin(IUri *uri, BSTR hostname, BSTR *ret)
698 UINT host_len, scheme_len;
699 BSTR scheme, origin;
700 HRESULT hres;
702 hres = IUri_GetSchemeName(uri, &scheme);
703 if(FAILED(hres))
704 return hres;
705 if(hres != S_OK) {
706 SysFreeString(scheme);
707 scheme = NULL;
710 /* Since it's only used for lookup, we can apply transformations to
711 keep the lookup itself simple and fast. First, we convert `https`
712 to `http` because they are equal for lookup. Next, we place the
713 scheme after the hostname, separated by NUL, to compare the host
714 first, since it tends to differ more often. Lastly, we lowercase
715 the whole thing since lookup must be case-insensitive. */
716 scheme_len = SysStringLen(scheme);
717 host_len = SysStringLen(hostname);
719 if(scheme_len == 5 && !wcsicmp(scheme, L"https"))
720 scheme_len--;
722 origin = SysAllocStringLen(NULL, host_len + 1 + scheme_len);
723 if(origin) {
724 WCHAR *p = origin;
725 memcpy(p, hostname, host_len * sizeof(WCHAR));
726 p += host_len;
727 *p = ' '; /* for wcslwr */
728 memcpy(p + 1, scheme, scheme_len * sizeof(WCHAR));
729 p[1 + scheme_len] = '\0';
730 _wcslwr(origin);
731 *p = '\0';
733 SysFreeString(scheme);
735 if(!origin)
736 return E_OUTOFMEMORY;
738 *ret = origin;
739 return S_OK;
742 static WCHAR *build_filename(BSTR hostname)
744 static const WCHAR store[] = L"\\Microsoft\\Internet Explorer\\DOMStore\\";
745 WCHAR path[MAX_PATH], *ret;
746 int len;
748 if(!SHGetSpecialFolderPathW(NULL, path, CSIDL_LOCAL_APPDATA, TRUE)) {
749 ERR("Can't get folder path %lu\n", GetLastError());
750 return NULL;
753 len = wcslen(path);
754 if(len + ARRAY_SIZE(store) > ARRAY_SIZE(path)) {
755 ERR("Path too long\n");
756 return NULL;
758 memcpy(path + len, store, sizeof(store));
760 len += ARRAY_SIZE(store);
761 ret = heap_alloc((len + wcslen(hostname) + ARRAY_SIZE(L".xml")) * sizeof(WCHAR));
762 if(!ret) {
763 return NULL;
766 wcscpy(ret, path);
767 wcscat(ret, hostname);
768 wcscat(ret, L".xml");
770 return ret;
773 static WCHAR *build_mutexname(const WCHAR *filename)
775 WCHAR *ret, *ptr;
776 ret = heap_strdupW(filename);
777 if(!ret)
778 return NULL;
779 for(ptr = ret; *ptr; ptr++)
780 if(*ptr == '\\') *ptr = '_';
781 return ret;
784 HRESULT create_html_storage(HTMLInnerWindow *window, BOOL local, IHTMLStorage **p)
786 IUri *uri = window->base.outer_window->uri;
787 BSTR origin, hostname = NULL;
788 HTMLStorage *storage;
789 HRESULT hres;
791 if(!uri)
792 return S_FALSE;
794 hres = IUri_GetHost(uri, &hostname);
795 if(hres != S_OK) {
796 SysFreeString(hostname);
797 return hres;
800 storage = heap_alloc_zero(sizeof(*storage));
801 if(!storage) {
802 SysFreeString(hostname);
803 return E_OUTOFMEMORY;
806 if(local) {
807 WCHAR *mutexname;
808 storage->filename = build_filename(hostname);
809 SysFreeString(hostname);
810 if(!storage->filename) {
811 heap_free(storage);
812 return E_OUTOFMEMORY;
814 mutexname = build_mutexname(storage->filename);
815 if(!mutexname) {
816 heap_free(storage->filename);
817 heap_free(storage);
818 return E_OUTOFMEMORY;
820 storage->mutex = CreateMutexW(NULL, FALSE, mutexname);
821 heap_free(mutexname);
822 if(!storage->mutex) {
823 heap_free(storage->filename);
824 heap_free(storage);
825 return HRESULT_FROM_WIN32(GetLastError());
827 }else {
828 hres = build_session_origin(uri, hostname, &origin);
829 SysFreeString(hostname);
830 if(hres != S_OK) {
831 heap_free(storage);
832 return hres;
834 storage->session_storage = grab_session_map_entry(origin);
835 SysFreeString(origin);
836 if(!storage->session_storage) {
837 heap_free(storage);
838 return E_OUTOFMEMORY;
842 storage->IHTMLStorage_iface.lpVtbl = &HTMLStorageVtbl;
843 storage->ref = 1;
844 init_dispatch(&storage->dispex, (IUnknown*)&storage->IHTMLStorage_iface, &HTMLStorage_dispex,
845 dispex_compat_mode(&window->event_target.dispex));
847 *p = &storage->IHTMLStorage_iface;
848 return S_OK;