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
29 #include "wine/debug.h"
31 #include "mshtml_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(mshtml
);
35 /* Native defaults to 5 million chars per origin */
36 enum { MAX_QUOTA
= 5000000 };
40 IHTMLStorage IHTMLStorage_iface
;
42 struct session_map_entry
*session_storage
;
47 struct session_map_entry
{
48 struct wine_rb_entry entry
;
49 struct wine_rb_tree data_map
;
50 struct list data_list
; /* for key() */
58 int session_storage_map_cmp(const void *key
, const struct wine_rb_entry
*entry
)
60 struct session_map_entry
*p
= WINE_RB_ENTRY_VALUE(entry
, struct session_map_entry
, entry
);
61 UINT len
= SysStringLen((BSTR
)key
);
63 return (len
!= p
->origin_len
) ? (len
- p
->origin_len
) : memcmp(key
, p
->origin
, len
* sizeof(WCHAR
));
68 struct wine_rb_entry entry
;
69 struct list list_entry
;
74 static int session_entry_cmp(const void *key
, const struct wine_rb_entry
*entry
)
76 struct session_entry
*data
= WINE_RB_ENTRY_VALUE(entry
, struct session_entry
, entry
);
77 return wcscmp(key
, data
->key
);
80 static struct session_map_entry
*grab_session_map_entry(BSTR origin
)
82 struct session_map_entry
*entry
;
83 struct wine_rb_entry
*rb_entry
;
84 thread_data_t
*thread_data
;
87 thread_data
= get_thread_data(TRUE
);
91 rb_entry
= wine_rb_get(&thread_data
->session_storage_map
, origin
);
93 entry
= WINE_RB_ENTRY_VALUE(rb_entry
, struct session_map_entry
, entry
);
98 origin_len
= SysStringLen(origin
);
99 entry
= heap_alloc(FIELD_OFFSET(struct session_map_entry
, origin
[origin_len
]));
102 wine_rb_init(&entry
->data_map
, session_entry_cmp
);
103 list_init(&entry
->data_list
);
105 entry
->quota
= MAX_QUOTA
;
107 entry
->origin_len
= origin_len
;
108 memcpy(entry
->origin
, origin
, origin_len
* sizeof(WCHAR
));
110 wine_rb_put(&thread_data
->session_storage_map
, origin
, &entry
->entry
);
114 static void release_session_map_entry(struct session_map_entry
*entry
)
116 if(!entry
|| --entry
->ref
|| entry
->num_keys
)
119 wine_rb_remove(&get_thread_data(FALSE
)->session_storage_map
, &entry
->entry
);
123 static HRESULT
get_session_entry(struct session_map_entry
*entry
, const WCHAR
*name
, BOOL create
, struct session_entry
**ret
)
125 const WCHAR
*key
= name
? name
: L
"";
126 struct wine_rb_entry
*rb_entry
;
127 struct session_entry
*data
;
130 rb_entry
= wine_rb_get(&entry
->data_map
, key
);
132 *ret
= WINE_RB_ENTRY_VALUE(rb_entry
, struct session_entry
, entry
);
141 key_len
= wcslen(key
);
142 if(entry
->quota
< key_len
)
143 return E_OUTOFMEMORY
; /* native returns this when quota is exceeded */
144 if(!(data
= heap_alloc(FIELD_OFFSET(struct session_entry
, key
[key_len
+ 1]))))
145 return E_OUTOFMEMORY
;
147 memcpy(data
->key
, key
, (key_len
+ 1) * sizeof(WCHAR
));
149 entry
->quota
-= key_len
;
151 list_add_tail(&entry
->data_list
, &data
->list_entry
);
152 wine_rb_put(&entry
->data_map
, key
, &data
->entry
);
157 static void clear_session_storage(struct session_map_entry
*entry
)
159 struct session_entry
*iter
, *iter2
;
161 LIST_FOR_EACH_ENTRY_SAFE(iter
, iter2
, &entry
->data_list
, struct session_entry
, list_entry
) {
162 SysFreeString(iter
->value
);
165 wine_rb_destroy(&entry
->data_map
, NULL
, NULL
);
166 list_init(&entry
->data_list
);
167 entry
->quota
= MAX_QUOTA
;
171 void destroy_session_storage(thread_data_t
*thread_data
)
173 struct session_map_entry
*iter
, *iter2
;
175 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR(iter
, iter2
, &thread_data
->session_storage_map
, struct session_map_entry
, entry
) {
176 clear_session_storage(iter
);
181 static inline HTMLStorage
*impl_from_IHTMLStorage(IHTMLStorage
*iface
)
183 return CONTAINING_RECORD(iface
, HTMLStorage
, IHTMLStorage_iface
);
186 static HRESULT WINAPI
HTMLStorage_QueryInterface(IHTMLStorage
*iface
, REFIID riid
, void **ppv
)
188 HTMLStorage
*This
= impl_from_IHTMLStorage(iface
);
190 TRACE("(%p)->(%s %p)\n", This
, debugstr_mshtml_guid(riid
), ppv
);
192 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
193 *ppv
= &This
->IHTMLStorage_iface
;
194 }else if(IsEqualGUID(&IID_IHTMLStorage
, riid
)) {
195 *ppv
= &This
->IHTMLStorage_iface
;
196 }else if(dispex_query_interface(&This
->dispex
, riid
, ppv
)) {
197 return *ppv
? S_OK
: E_NOINTERFACE
;
200 WARN("(%p)->(%s %p)\n", This
, debugstr_mshtml_guid(riid
), ppv
);
201 return E_NOINTERFACE
;
204 IUnknown_AddRef((IUnknown
*)*ppv
);
208 static ULONG WINAPI
HTMLStorage_AddRef(IHTMLStorage
*iface
)
210 HTMLStorage
*This
= impl_from_IHTMLStorage(iface
);
211 LONG ref
= InterlockedIncrement(&This
->ref
);
213 TRACE("(%p) ref=%ld\n", This
, ref
);
218 static ULONG WINAPI
HTMLStorage_Release(IHTMLStorage
*iface
)
220 HTMLStorage
*This
= impl_from_IHTMLStorage(iface
);
221 LONG ref
= InterlockedDecrement(&This
->ref
);
223 TRACE("(%p) ref=%ld\n", This
, ref
);
226 release_session_map_entry(This
->session_storage
);
227 release_dispex(&This
->dispex
);
228 heap_free(This
->filename
);
229 CloseHandle(This
->mutex
);
236 static HRESULT WINAPI
HTMLStorage_GetTypeInfoCount(IHTMLStorage
*iface
, UINT
*pctinfo
)
238 HTMLStorage
*This
= impl_from_IHTMLStorage(iface
);
239 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
242 static HRESULT WINAPI
HTMLStorage_GetTypeInfo(IHTMLStorage
*iface
, UINT iTInfo
,
243 LCID lcid
, ITypeInfo
**ppTInfo
)
245 HTMLStorage
*This
= impl_from_IHTMLStorage(iface
);
247 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
, iTInfo
, lcid
, ppTInfo
);
250 static HRESULT WINAPI
HTMLStorage_GetIDsOfNames(IHTMLStorage
*iface
, REFIID riid
, LPOLESTR
*rgszNames
, UINT cNames
,
251 LCID lcid
, DISPID
*rgDispId
)
253 HTMLStorage
*This
= impl_from_IHTMLStorage(iface
);
255 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
, riid
, rgszNames
, cNames
,
259 static HRESULT WINAPI
HTMLStorage_Invoke(IHTMLStorage
*iface
, DISPID dispIdMember
, REFIID riid
, LCID lcid
,
260 WORD wFlags
, DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
262 HTMLStorage
*This
= impl_from_IHTMLStorage(iface
);
264 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
, dispIdMember
, riid
, lcid
, wFlags
,
265 pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
268 static BOOL
create_path(const WCHAR
*path
)
274 new_path
= heap_alloc((wcslen(path
) + 1) * sizeof(WCHAR
));
277 wcscpy(new_path
, path
);
279 while((len
= wcslen(new_path
)) && new_path
[len
- 1] == '\\')
280 new_path
[len
- 1] = 0;
282 while(!CreateDirectoryW(new_path
, NULL
)) {
284 DWORD error
= GetLastError();
285 if(error
== ERROR_ALREADY_EXISTS
) break;
286 if(error
!= ERROR_PATH_NOT_FOUND
) {
290 slash
= wcsrchr(new_path
, '\\');
295 len
= slash
- new_path
;
297 if(!create_path(new_path
)) {
301 new_path
[len
] = '\\';
307 static HRESULT
open_document(const WCHAR
*filename
, IXMLDOMDocument
**ret
)
309 IXMLDOMDocument
*doc
= NULL
;
310 HRESULT hres
= E_OUTOFMEMORY
;
313 VARIANT_BOOL success
;
315 path
= heap_strdupW(filename
);
317 return E_OUTOFMEMORY
;
319 *(ptr
= wcsrchr(path
, '\\')) = 0;
320 if(!create_path(path
))
323 if(GetFileAttributesW(filename
) == INVALID_FILE_ATTRIBUTES
) {
325 HANDLE file
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, 0, NULL
);
326 if(file
== INVALID_HANDLE_VALUE
) {
327 hres
= HRESULT_FROM_WIN32(GetLastError());
330 if(!WriteFile(file
, "<root/>", sizeof("<root/>") - 1, &count
, NULL
)) {
332 hres
= HRESULT_FROM_WIN32(GetLastError());
338 hres
= CoCreateInstance(&CLSID_DOMDocument
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IXMLDOMDocument
, (void**)&doc
);
342 V_VT(&var
) = VT_BSTR
;
343 V_BSTR(&var
) = SysAllocString(filename
);
345 hres
= E_OUTOFMEMORY
;
349 hres
= IXMLDOMDocument_load(doc
, var
, &success
);
350 if(hres
== S_FALSE
|| success
== VARIANT_FALSE
)
353 SysFreeString(V_BSTR(&var
));
360 IXMLDOMDocument_Release(doc
);
365 static HRESULT
get_root_node(IXMLDOMDocument
*doc
, IXMLDOMNode
**root
)
370 str
= SysAllocString(L
"root");
372 return E_OUTOFMEMORY
;
374 hres
= IXMLDOMDocument_selectSingleNode(doc
, str
, root
);
379 static HRESULT
get_node_list(const WCHAR
*filename
, IXMLDOMNodeList
**node_list
)
381 IXMLDOMDocument
*doc
;
386 hres
= open_document(filename
, &doc
);
390 hres
= get_root_node(doc
, &root
);
391 IXMLDOMDocument_Release(doc
);
395 if(!(query
= SysAllocString(L
"item")))
396 hres
= E_OUTOFMEMORY
;
398 hres
= IXMLDOMNode_selectNodes(root
, query
, node_list
);
399 SysFreeString(query
);
401 IXMLDOMNode_Release(root
);
405 static HRESULT WINAPI
HTMLStorage_get_length(IHTMLStorage
*iface
, LONG
*p
)
407 HTMLStorage
*This
= impl_from_IHTMLStorage(iface
);
408 IXMLDOMNodeList
*node_list
;
411 TRACE("(%p)->(%p)\n", This
, p
);
413 if(!This
->filename
) {
414 *p
= This
->session_storage
->num_keys
;
418 WaitForSingleObject(This
->mutex
, INFINITE
);
419 hres
= get_node_list(This
->filename
, &node_list
);
420 if(SUCCEEDED(hres
)) {
421 hres
= IXMLDOMNodeList_get_length(node_list
, p
);
422 IXMLDOMNodeList_Release(node_list
);
424 ReleaseMutex(This
->mutex
);
429 static HRESULT WINAPI
HTMLStorage_get_remainingSpace(IHTMLStorage
*iface
, LONG
*p
)
431 HTMLStorage
*This
= impl_from_IHTMLStorage(iface
);
433 TRACE("(%p)->(%p)\n", This
, p
);
435 if(!This
->filename
) {
436 *p
= This
->session_storage
->quota
;
440 FIXME("local storage not supported\n");
444 static HRESULT
get_key(const WCHAR
*filename
, LONG index
, BSTR
*ret
)
446 IXMLDOMNodeList
*node_list
;
447 IXMLDOMElement
*elem
;
452 hres
= get_node_list(filename
, &node_list
);
456 hres
= IXMLDOMNodeList_get_item(node_list
, index
, &node
);
457 IXMLDOMNodeList_Release(node_list
);
459 return FAILED(hres
) ? hres
: E_INVALIDARG
;
461 hres
= IXMLDOMNode_QueryInterface(node
, &IID_IXMLDOMElement
, (void**)&elem
);
462 IXMLDOMNode_Release(node
);
466 hres
= IXMLDOMElement_getAttribute(elem
, (BSTR
)L
"name", &key
);
467 IXMLDOMElement_Release(elem
);
471 if(V_VT(&key
) != VT_BSTR
) {
472 FIXME("non-string key %s\n", debugstr_variant(&key
));
481 static HRESULT WINAPI
HTMLStorage_key(IHTMLStorage
*iface
, LONG lIndex
, BSTR
*p
)
483 HTMLStorage
*This
= impl_from_IHTMLStorage(iface
);
484 struct session_entry
*session_entry
;
487 TRACE("(%p)->(%ld %p)\n", This
, lIndex
, p
);
489 if(!This
->filename
) {
490 struct list
*entry
= &This
->session_storage
->data_list
;
493 if(lIndex
>= This
->session_storage
->num_keys
)
496 do entry
= entry
->next
; while(i
++ < lIndex
);
497 session_entry
= LIST_ENTRY(entry
, struct session_entry
, list_entry
);
499 *p
= SysAllocString(session_entry
->key
);
500 return *p
? S_OK
: E_OUTOFMEMORY
;
503 WaitForSingleObject(This
->mutex
, INFINITE
);
504 hres
= get_key(This
->filename
, lIndex
, p
);
505 ReleaseMutex(This
->mutex
);
510 static BSTR
build_query(const WCHAR
*key
)
512 static const WCHAR fmt
[] = L
"item[@name='%s']";
513 const WCHAR
*str
= key
? key
: L
"";
514 UINT len
= ARRAY_SIZE(fmt
) + wcslen(str
);
515 BSTR ret
= SysAllocStringLen(NULL
, len
);
517 if(ret
) swprintf(ret
, len
, fmt
, str
);
521 static HRESULT
get_item(const WCHAR
*filename
, BSTR key
, VARIANT
*value
)
523 IXMLDOMDocument
*doc
;
525 IXMLDOMNode
*root
= NULL
, *node
= NULL
;
526 IXMLDOMElement
*elem
= NULL
;
529 hres
= open_document(filename
, &doc
);
533 hres
= get_root_node(doc
, &root
);
537 query
= build_query(key
);
539 hres
= E_OUTOFMEMORY
;
543 hres
= IXMLDOMNode_selectSingleNode(root
, query
, &node
);
545 hres
= IXMLDOMNode_QueryInterface(node
, &IID_IXMLDOMElement
, (void**)&elem
);
549 hres
= IXMLDOMElement_getAttribute(elem
, (BSTR
)L
"value", value
);
551 V_VT(value
) = VT_NULL
;
556 SysFreeString(query
);
558 IXMLDOMNode_Release(root
);
560 IXMLDOMNode_Release(node
);
562 IXMLDOMElement_Release(elem
);
563 IXMLDOMDocument_Release(doc
);
567 static HRESULT WINAPI
HTMLStorage_getItem(IHTMLStorage
*iface
, BSTR bstrKey
, VARIANT
*value
)
569 HTMLStorage
*This
= impl_from_IHTMLStorage(iface
);
570 struct session_entry
*session_entry
;
573 TRACE("(%p)->(%s %p)\n", This
, debugstr_w(bstrKey
), value
);
578 if(!This
->filename
) {
579 hres
= get_session_entry(This
->session_storage
, bstrKey
, FALSE
, &session_entry
);
580 if(SUCCEEDED(hres
)) {
581 if(!session_entry
|| !session_entry
->value
)
582 V_VT(value
) = VT_NULL
;
584 V_VT(value
) = VT_BSTR
;
585 V_BSTR(value
) = SysAllocStringLen(session_entry
->value
, SysStringLen(session_entry
->value
));
586 hres
= V_BSTR(value
) ? S_OK
: E_OUTOFMEMORY
;
592 WaitForSingleObject(This
->mutex
, INFINITE
);
593 hres
= get_item(This
->filename
, bstrKey
, value
);
594 ReleaseMutex(This
->mutex
);
599 static HRESULT
set_attribute(IXMLDOMElement
*elem
, const WCHAR
*name
, BSTR value
)
605 str
= SysAllocString(name
);
607 return E_OUTOFMEMORY
;
608 V_VT(&var
) = VT_BSTR
;
609 V_BSTR(&var
) = value
;
611 hres
= IXMLDOMElement_setAttribute(elem
, str
, var
);
616 static HRESULT
save_document(IXMLDOMDocument
*doc
, const WCHAR
*filename
)
621 V_VT(&var
) = VT_BSTR
;
622 V_BSTR(&var
) = SysAllocString(filename
);
624 return E_OUTOFMEMORY
;
626 hres
= IXMLDOMDocument_save(doc
, var
);
627 SysFreeString(V_BSTR(&var
));
631 static HRESULT
set_item(const WCHAR
*filename
, BSTR key
, BSTR value
)
633 IXMLDOMDocument
*doc
;
634 IXMLDOMNode
*root
= NULL
, *node
= NULL
;
635 IXMLDOMElement
*elem
= NULL
;
639 hres
= open_document(filename
, &doc
);
643 hres
= get_root_node(doc
, &root
);
647 query
= build_query(key
);
649 hres
= E_OUTOFMEMORY
;
653 hres
= IXMLDOMNode_selectSingleNode(root
, query
, &node
);
655 hres
= IXMLDOMNode_QueryInterface(node
, &IID_IXMLDOMElement
, (void**)&elem
);
659 hres
= set_attribute(elem
, L
"value", value
);
663 BSTR str
= SysAllocString(L
"item");
664 hres
= IXMLDOMDocument_createElement(doc
, str
, &elem
);
669 hres
= set_attribute(elem
, L
"name", key
);
673 hres
= set_attribute(elem
, L
"value", value
);
677 hres
= IXMLDOMNode_appendChild(root
, (IXMLDOMNode
*)elem
, NULL
);
682 hres
= save_document(doc
, filename
);
685 SysFreeString(query
);
687 IXMLDOMNode_Release(root
);
689 IXMLDOMNode_Release(node
);
691 IXMLDOMElement_Release(elem
);
692 IXMLDOMDocument_Release(doc
);
696 static HRESULT WINAPI
HTMLStorage_setItem(IHTMLStorage
*iface
, BSTR bstrKey
, BSTR bstrValue
)
698 HTMLStorage
*This
= impl_from_IHTMLStorage(iface
);
699 struct session_entry
*session_entry
;
702 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(bstrKey
), debugstr_w(bstrValue
));
704 if(!This
->filename
) {
705 UINT value_len
= bstrValue
? wcslen(bstrValue
) : 0;
706 BSTR value
= SysAllocStringLen(bstrValue
, value_len
);
708 return E_OUTOFMEMORY
;
710 hres
= get_session_entry(This
->session_storage
, bstrKey
, TRUE
, &session_entry
);
712 SysFreeString(value
);
714 UINT old_len
= SysStringLen(session_entry
->value
);
715 if(old_len
< value_len
&& This
->session_storage
->quota
< value_len
- old_len
) {
716 SysFreeString(value
);
717 return E_OUTOFMEMORY
; /* native returns this when quota is exceeded */
719 This
->session_storage
->quota
-= value_len
- old_len
;
720 SysFreeString(session_entry
->value
);
721 session_entry
->value
= value
;
726 WaitForSingleObject(This
->mutex
, INFINITE
);
727 hres
= set_item(This
->filename
, bstrKey
, bstrValue
);
728 ReleaseMutex(This
->mutex
);
733 static HRESULT
remove_item(const WCHAR
*filename
, BSTR key
)
735 IXMLDOMDocument
*doc
;
736 IXMLDOMNode
*root
= NULL
, *node
= NULL
;
740 hres
= open_document(filename
, &doc
);
744 hres
= get_root_node(doc
, &root
);
748 query
= build_query(key
);
750 hres
= E_OUTOFMEMORY
;
754 hres
= IXMLDOMNode_selectSingleNode(root
, query
, &node
);
756 hres
= IXMLDOMNode_removeChild(root
, node
, NULL
);
761 hres
= save_document(doc
, filename
);
764 SysFreeString(query
);
766 IXMLDOMNode_Release(root
);
768 IXMLDOMNode_Release(node
);
769 IXMLDOMDocument_Release(doc
);
773 static HRESULT WINAPI
HTMLStorage_removeItem(IHTMLStorage
*iface
, BSTR bstrKey
)
775 HTMLStorage
*This
= impl_from_IHTMLStorage(iface
);
776 struct session_entry
*session_entry
;
779 TRACE("(%p)->(%s)\n", This
, debugstr_w(bstrKey
));
781 if(!This
->filename
) {
782 hres
= get_session_entry(This
->session_storage
, bstrKey
, FALSE
, &session_entry
);
783 if(SUCCEEDED(hres
) && session_entry
) {
784 This
->session_storage
->quota
+= wcslen(session_entry
->key
) + SysStringLen(session_entry
->value
);
785 This
->session_storage
->num_keys
--;
786 list_remove(&session_entry
->list_entry
);
787 wine_rb_remove(&This
->session_storage
->data_map
, &session_entry
->entry
);
788 SysFreeString(session_entry
->value
);
789 heap_free(session_entry
);
794 WaitForSingleObject(This
->mutex
, INFINITE
);
795 hres
= remove_item(This
->filename
, bstrKey
);
796 ReleaseMutex(This
->mutex
);
801 static HRESULT WINAPI
HTMLStorage_clear(IHTMLStorage
*iface
)
803 HTMLStorage
*This
= impl_from_IHTMLStorage(iface
);
806 if(!This
->filename
) {
807 clear_session_storage(This
->session_storage
);
811 WaitForSingleObject(This
->mutex
, INFINITE
);
812 if(!DeleteFileW(This
->filename
)) {
813 DWORD error
= GetLastError();
814 if(error
!= ERROR_FILE_NOT_FOUND
&& error
!= ERROR_PATH_NOT_FOUND
)
815 hres
= HRESULT_FROM_WIN32(error
);
817 ReleaseMutex(This
->mutex
);
821 static const IHTMLStorageVtbl HTMLStorageVtbl
= {
822 HTMLStorage_QueryInterface
,
825 HTMLStorage_GetTypeInfoCount
,
826 HTMLStorage_GetTypeInfo
,
827 HTMLStorage_GetIDsOfNames
,
829 HTMLStorage_get_length
,
830 HTMLStorage_get_remainingSpace
,
834 HTMLStorage_removeItem
,
838 static const tid_t HTMLStorage_iface_tids
[] = {
842 static dispex_static_data_t HTMLStorage_dispex
= {
846 HTMLStorage_iface_tids
849 static HRESULT
build_session_origin(IUri
*uri
, BSTR hostname
, BSTR
*ret
)
851 UINT host_len
, scheme_len
;
855 hres
= IUri_GetSchemeName(uri
, &scheme
);
859 SysFreeString(scheme
);
863 /* Since it's only used for lookup, we can apply transformations to
864 keep the lookup itself simple and fast. First, we convert `https`
865 to `http` because they are equal for lookup. Next, we place the
866 scheme after the hostname, separated by NUL, to compare the host
867 first, since it tends to differ more often. Lastly, we lowercase
868 the whole thing since lookup must be case-insensitive. */
869 scheme_len
= SysStringLen(scheme
);
870 host_len
= SysStringLen(hostname
);
872 if(scheme_len
== 5 && !wcsicmp(scheme
, L
"https"))
875 origin
= SysAllocStringLen(NULL
, host_len
+ 1 + scheme_len
);
878 memcpy(p
, hostname
, host_len
* sizeof(WCHAR
));
880 *p
= ' '; /* for wcslwr */
881 memcpy(p
+ 1, scheme
, scheme_len
* sizeof(WCHAR
));
882 p
[1 + scheme_len
] = '\0';
886 SysFreeString(scheme
);
889 return E_OUTOFMEMORY
;
895 static WCHAR
*build_filename(BSTR hostname
)
897 static const WCHAR store
[] = L
"\\Microsoft\\Internet Explorer\\DOMStore\\";
898 WCHAR path
[MAX_PATH
], *ret
;
901 if(!SHGetSpecialFolderPathW(NULL
, path
, CSIDL_LOCAL_APPDATA
, TRUE
)) {
902 ERR("Can't get folder path %lu\n", GetLastError());
907 if(len
+ ARRAY_SIZE(store
) > ARRAY_SIZE(path
)) {
908 ERR("Path too long\n");
911 memcpy(path
+ len
, store
, sizeof(store
));
913 len
+= ARRAY_SIZE(store
);
914 ret
= heap_alloc((len
+ wcslen(hostname
) + ARRAY_SIZE(L
".xml")) * sizeof(WCHAR
));
920 wcscat(ret
, hostname
);
921 wcscat(ret
, L
".xml");
926 static WCHAR
*build_mutexname(const WCHAR
*filename
)
929 ret
= heap_strdupW(filename
);
932 for(ptr
= ret
; *ptr
; ptr
++)
933 if(*ptr
== '\\') *ptr
= '_';
937 HRESULT
create_html_storage(HTMLInnerWindow
*window
, BOOL local
, IHTMLStorage
**p
)
939 IUri
*uri
= window
->base
.outer_window
->uri
;
940 BSTR origin
, hostname
= NULL
;
941 HTMLStorage
*storage
;
947 hres
= IUri_GetHost(uri
, &hostname
);
949 SysFreeString(hostname
);
953 storage
= heap_alloc_zero(sizeof(*storage
));
955 SysFreeString(hostname
);
956 return E_OUTOFMEMORY
;
961 storage
->filename
= build_filename(hostname
);
962 SysFreeString(hostname
);
963 if(!storage
->filename
) {
965 return E_OUTOFMEMORY
;
967 mutexname
= build_mutexname(storage
->filename
);
969 heap_free(storage
->filename
);
971 return E_OUTOFMEMORY
;
973 storage
->mutex
= CreateMutexW(NULL
, FALSE
, mutexname
);
974 heap_free(mutexname
);
975 if(!storage
->mutex
) {
976 heap_free(storage
->filename
);
978 return HRESULT_FROM_WIN32(GetLastError());
981 hres
= build_session_origin(uri
, hostname
, &origin
);
982 SysFreeString(hostname
);
987 storage
->session_storage
= grab_session_map_entry(origin
);
988 SysFreeString(origin
);
989 if(!storage
->session_storage
) {
991 return E_OUTOFMEMORY
;
995 storage
->IHTMLStorage_iface
.lpVtbl
= &HTMLStorageVtbl
;
997 init_dispatch(&storage
->dispex
, (IUnknown
*)&storage
->IHTMLStorage_iface
, &HTMLStorage_dispex
,
998 dispex_compat_mode(&window
->event_target
.dispex
));
1000 *p
= &storage
->IHTMLStorage_iface
;