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
);
37 IHTMLStorage IHTMLStorage_iface
;
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
;
62 WARN("(%p)->(%s %p)\n", This
, debugstr_mshtml_guid(riid
), ppv
);
66 IUnknown_AddRef((IUnknown
*)*ppv
);
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
);
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
);
88 release_dispex(&This
->dispex
);
89 heap_free(This
->filename
);
90 CloseHandle(This
->mutex
);
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
,
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
)
135 new_path
= heap_alloc((wcslen(path
) + 1) * sizeof(WCHAR
));
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
)) {
145 DWORD error
= GetLastError();
146 if(error
== ERROR_ALREADY_EXISTS
) break;
147 if(error
!= ERROR_PATH_NOT_FOUND
) {
151 slash
= wcsrchr(new_path
, '\\');
156 len
= slash
- new_path
;
158 if(!create_path(new_path
)) {
162 new_path
[len
] = '\\';
168 static HRESULT
open_document(const WCHAR
*filename
, IXMLDOMDocument
**ret
)
170 IXMLDOMDocument
*doc
= NULL
;
171 HRESULT hres
= E_OUTOFMEMORY
;
174 VARIANT_BOOL success
;
176 path
= heap_strdupW(filename
);
178 return E_OUTOFMEMORY
;
180 *(ptr
= wcsrchr(path
, '\\')) = 0;
181 if(!create_path(path
))
184 if(GetFileAttributesW(filename
) == INVALID_FILE_ATTRIBUTES
) {
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());
191 if(!WriteFile(file
, "<root/>", sizeof("<root/>") - 1, &count
, NULL
)) {
193 hres
= HRESULT_FROM_WIN32(GetLastError());
199 hres
= CoCreateInstance(&CLSID_DOMDocument
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IXMLDOMDocument
, (void**)&doc
);
203 V_VT(&var
) = VT_BSTR
;
204 V_BSTR(&var
) = SysAllocString(filename
);
206 hres
= E_OUTOFMEMORY
;
210 hres
= IXMLDOMDocument_load(doc
, var
, &success
);
211 if(hres
== S_FALSE
|| success
== VARIANT_FALSE
)
214 SysFreeString(V_BSTR(&var
));
221 IXMLDOMDocument_Release(doc
);
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
);
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
);
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
);
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
);
258 static HRESULT
get_root_node(IXMLDOMDocument
*doc
, IXMLDOMNode
**root
)
263 str
= SysAllocString(L
"root");
265 return E_OUTOFMEMORY
;
267 hres
= IXMLDOMDocument_selectSingleNode(doc
, str
, root
);
272 static HRESULT
get_item(const WCHAR
*filename
, BSTR key
, VARIANT
*value
)
274 IXMLDOMDocument
*doc
;
276 IXMLDOMNode
*root
= NULL
, *node
= NULL
;
277 IXMLDOMElement
*elem
= NULL
;
280 hres
= open_document(filename
, &doc
);
284 hres
= get_root_node(doc
, &root
);
288 query
= build_query(key
);
290 hres
= E_OUTOFMEMORY
;
294 hres
= IXMLDOMNode_selectSingleNode(root
, query
, &node
);
296 hres
= IXMLDOMNode_QueryInterface(node
, &IID_IXMLDOMElement
, (void**)&elem
);
300 hres
= IXMLDOMElement_getAttribute(elem
, (BSTR
)L
"value", value
);
302 V_VT(value
) = VT_NULL
;
307 SysFreeString(query
);
309 IXMLDOMNode_Release(root
);
311 IXMLDOMNode_Release(node
);
313 IXMLDOMElement_Release(elem
);
314 IXMLDOMDocument_Release(doc
);
318 static HRESULT WINAPI
HTMLStorage_getItem(IHTMLStorage
*iface
, BSTR bstrKey
, VARIANT
*value
)
320 HTMLStorage
*This
= impl_from_IHTMLStorage(iface
);
323 TRACE("(%p)->(%s %p)\n", This
, debugstr_w(bstrKey
), value
);
328 if(!This
->filename
) {
329 FIXME("session storage not supported\n");
330 V_VT(value
) = VT_NULL
;
334 WaitForSingleObject(This
->mutex
, INFINITE
);
335 hres
= get_item(This
->filename
, bstrKey
, value
);
336 ReleaseMutex(This
->mutex
);
341 static HRESULT
set_attribute(IXMLDOMElement
*elem
, const WCHAR
*name
, BSTR value
)
347 str
= SysAllocString(name
);
349 return E_OUTOFMEMORY
;
350 V_VT(&var
) = VT_BSTR
;
351 V_BSTR(&var
) = value
;
353 hres
= IXMLDOMElement_setAttribute(elem
, str
, var
);
358 static HRESULT
save_document(IXMLDOMDocument
*doc
, const WCHAR
*filename
)
363 V_VT(&var
) = VT_BSTR
;
364 V_BSTR(&var
) = SysAllocString(filename
);
366 return E_OUTOFMEMORY
;
368 hres
= IXMLDOMDocument_save(doc
, var
);
369 SysFreeString(V_BSTR(&var
));
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
;
381 hres
= open_document(filename
, &doc
);
385 hres
= get_root_node(doc
, &root
);
389 query
= build_query(key
);
391 hres
= E_OUTOFMEMORY
;
395 hres
= IXMLDOMNode_selectSingleNode(root
, query
, &node
);
397 hres
= IXMLDOMNode_QueryInterface(node
, &IID_IXMLDOMElement
, (void**)&elem
);
401 hres
= set_attribute(elem
, L
"value", value
);
405 BSTR str
= SysAllocString(L
"item");
406 hres
= IXMLDOMDocument_createElement(doc
, str
, &elem
);
411 hres
= set_attribute(elem
, L
"name", key
);
415 hres
= set_attribute(elem
, L
"value", value
);
419 hres
= IXMLDOMNode_appendChild(root
, (IXMLDOMNode
*)elem
, NULL
);
424 hres
= save_document(doc
, filename
);
427 SysFreeString(query
);
429 IXMLDOMNode_Release(root
);
431 IXMLDOMNode_Release(node
);
433 IXMLDOMElement_Release(elem
);
434 IXMLDOMDocument_Release(doc
);
438 static HRESULT WINAPI
HTMLStorage_setItem(IHTMLStorage
*iface
, BSTR bstrKey
, BSTR bstrValue
)
440 HTMLStorage
*This
= impl_from_IHTMLStorage(iface
);
443 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(bstrKey
), debugstr_w(bstrValue
));
445 if(!This
->filename
) {
446 FIXME("session storage not supported\n");
450 WaitForSingleObject(This
->mutex
, INFINITE
);
451 hres
= set_item(This
->filename
, bstrKey
, bstrValue
);
452 ReleaseMutex(This
->mutex
);
457 static HRESULT
remove_item(const WCHAR
*filename
, BSTR key
)
459 IXMLDOMDocument
*doc
;
460 IXMLDOMNode
*root
= NULL
, *node
= NULL
;
464 hres
= open_document(filename
, &doc
);
468 hres
= get_root_node(doc
, &root
);
472 query
= build_query(key
);
474 hres
= E_OUTOFMEMORY
;
478 hres
= IXMLDOMNode_selectSingleNode(root
, query
, &node
);
480 hres
= IXMLDOMNode_removeChild(root
, node
, NULL
);
485 hres
= save_document(doc
, filename
);
488 SysFreeString(query
);
490 IXMLDOMNode_Release(root
);
492 IXMLDOMNode_Release(node
);
493 IXMLDOMDocument_Release(doc
);
497 static HRESULT WINAPI
HTMLStorage_removeItem(IHTMLStorage
*iface
, BSTR bstrKey
)
499 HTMLStorage
*This
= impl_from_IHTMLStorage(iface
);
502 TRACE("(%p)->(%s)\n", This
, debugstr_w(bstrKey
));
504 if(!This
->filename
) {
505 FIXME("session storage not supported\n");
509 WaitForSingleObject(This
->mutex
, INFINITE
);
510 hres
= remove_item(This
->filename
, bstrKey
);
511 ReleaseMutex(This
->mutex
);
516 static HRESULT WINAPI
HTMLStorage_clear(IHTMLStorage
*iface
)
518 HTMLStorage
*This
= impl_from_IHTMLStorage(iface
);
519 FIXME("(%p)->()\n", This
);
523 static const IHTMLStorageVtbl HTMLStorageVtbl
= {
524 HTMLStorage_QueryInterface
,
527 HTMLStorage_GetTypeInfoCount
,
528 HTMLStorage_GetTypeInfo
,
529 HTMLStorage_GetIDsOfNames
,
531 HTMLStorage_get_length
,
532 HTMLStorage_get_remainingSpace
,
536 HTMLStorage_removeItem
,
540 static const tid_t HTMLStorage_iface_tids
[] = {
544 static dispex_static_data_t HTMLStorage_dispex
= {
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
;
559 hres
= IUri_GetHost(uri
, &hostname
);
563 if(!SHGetSpecialFolderPathW(NULL
, path
, CSIDL_LOCAL_APPDATA
, TRUE
)) {
564 ERR("Can't get folder path %lu\n", GetLastError());
565 SysFreeString(hostname
);
570 if(len
+ ARRAY_SIZE(store
) > ARRAY_SIZE(path
)) {
571 ERR("Path too long\n");
572 SysFreeString(hostname
);
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
));
580 SysFreeString(hostname
);
585 wcscat(ret
, hostname
);
586 wcscat(ret
, L
".xml");
588 SysFreeString(hostname
);
592 static WCHAR
*build_mutexname(const WCHAR
*filename
)
595 ret
= heap_strdupW(filename
);
598 for(ptr
= ret
; *ptr
; ptr
++)
599 if(*ptr
== '\\') *ptr
= '_';
603 HRESULT
create_html_storage(compat_mode_t compat_mode
, IUri
*uri
, IHTMLStorage
**p
)
605 HTMLStorage
*storage
;
607 storage
= heap_alloc_zero(sizeof(*storage
));
609 return E_OUTOFMEMORY
;
613 if(!(storage
->filename
= build_filename(uri
))) {
615 return E_OUTOFMEMORY
;
617 mutexname
= build_mutexname(storage
->filename
);
619 heap_free(storage
->filename
);
621 return E_OUTOFMEMORY
;
623 storage
->mutex
= CreateMutexW(NULL
, FALSE
, mutexname
);
624 heap_free(mutexname
);
625 if(!storage
->mutex
) {
626 heap_free(storage
->filename
);
628 return HRESULT_FROM_WIN32(GetLastError());
632 storage
->IHTMLStorage_iface
.lpVtbl
= &HTMLStorageVtbl
;
634 init_dispatch(&storage
->dispex
, (IUnknown
*)&storage
->IHTMLStorage_iface
, &HTMLStorage_dispex
, compat_mode
);
636 *p
= &storage
->IHTMLStorage_iface
;