v2: Fix test failure.
Signed-off-by: Hans Leidekker <hans(a)codeweavers.com>
---
dlls/mshtml/htmlstorage.c | 245 ++++++++++++++++++++++++++++++++++-
dlls/mshtml/htmlwindow.c | 4 +-
dlls/mshtml/mshtml_private.h | 2 +-
3 files changed, 243 insertions(+), 8 deletions(-)
diff --git a/dlls/mshtml/htmlstorage.c b/dlls/mshtml/htmlstorage.c
index 95f7ae5cd16..fe1d6a21b88 100644
--- a/dlls/mshtml/htmlstorage.c
+++ b/dlls/mshtml/htmlstorage.c
@@ -24,6 +24,7 @@
#include "winbase.h"
#include "winuser.h"
#include "ole2.h"
+#include "shlobj.h"
#include "wine/debug.h"
@@ -35,6 +36,7 @@ typedef struct {
DispatchEx dispex;
IHTMLStorage IHTMLStorage_iface;
LONG ref;
+ HTMLInnerWindow *window;
} HTMLStorage;
static inline HTMLStorage *impl_from_IHTMLStorage(IHTMLStorage *iface)
@@ -121,6 +123,151 @@ static HRESULT WINAPI HTMLStorage_Invoke(IHTMLStorage *iface, DISPID dispIdMembe
pDispParams, pVarResult, pExcepInfo, puArgErr);
}
+static BOOL create_path(const WCHAR *path)
+{
+ BOOL ret = TRUE;
+ WCHAR *new_path;
+ int len;
+
+ new_path = malloc((wcslen(path) + 1) * sizeof(WCHAR));
+ if(!new_path)
+ return FALSE;
+ wcscpy(new_path, path);
+
+ while((len = wcslen(new_path)) && new_path[len - 1] == '\\')
+ new_path[len - 1] = 0;
+
+ while(!CreateDirectoryW(new_path, NULL)) {
+ WCHAR *slash;
+ DWORD error = GetLastError();
+ if(error == ERROR_ALREADY_EXISTS) break;
+ if(error != ERROR_PATH_NOT_FOUND) {
+ ret = FALSE;
+ break;
+ }
+ slash = wcsrchr(new_path, '\\');
+ if(!slash) {
+ ret = FALSE;
+ break;
+ }
+ len = slash - new_path;
+ new_path[len] = 0;
+ if(!create_path(new_path)) {
+ ret = FALSE;
+ break;
+ }
+ new_path[len] = '\\';
+ }
+ free(new_path);
+ return ret;
+}
+
+static WCHAR *build_filename(const WCHAR *hostname)
+{
+ static const WCHAR store[] = L"\\Microsoft\\Internet Explorer\\DOMStore\\";
+ WCHAR path[MAX_PATH], *ret;
+ int len;
+
+ if(!SHGetSpecialFolderPathW(NULL, path, CSIDL_LOCAL_APPDATA, TRUE)) {
+ ERR("Can't get folder path %lu\n", GetLastError());
+ return NULL;
+ }
+
+ len = wcslen(path);
+ if(len + ARRAY_SIZE(store) > ARRAY_SIZE(path)) {
+ ERR("Path too long\n");
+ return NULL;
+ }
+ memcpy(path + len, store, sizeof(store));
+
+ len += ARRAY_SIZE(store);
+ ret = malloc((len + wcslen(hostname) + ARRAY_SIZE(L".xml")) * sizeof(WCHAR));
+ if(!ret)
+ return NULL;
+
+ wcscpy(ret, path);
+ wcscat(ret, hostname);
+ wcscat(ret, L".xml");
+ return ret;
+}
+
+struct storage {
+ WCHAR *filename;
+ IXMLDOMDocument *doc;
+};
+
+static void close_storage(struct storage *storage)
+{
+ free(storage->filename);
+ if(storage->doc)
+ IXMLDOMDocument_Release(storage->doc);
+ free(storage);
+}
+
+static HRESULT open_storage(const WCHAR *hostname, struct storage **ret)
+{
+ struct storage *storage;
+ HRESULT hres = E_OUTOFMEMORY;
+ VARIANT var;
+ VARIANT_BOOL success;
+ WCHAR *ptr;
+
+ storage = calloc(1, sizeof(*storage));
+ if(!storage)
+ return E_OUTOFMEMORY;
+
+ storage->filename = build_filename(hostname);
+ if(!storage->filename)
+ goto done;
+
+ *(ptr = wcsrchr(storage->filename, '\\')) = 0;
+ if(!create_path(storage->filename)) {
+ hres = E_FAIL;
+ goto done;
+ }
+ *ptr = '\\';
+
+ if(GetFileAttributesW(storage->filename) == INVALID_FILE_ATTRIBUTES) {
+ DWORD count;
+ HANDLE file = CreateFileW(storage->filename, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
+ if(file == INVALID_HANDLE_VALUE) {
+ hres = HRESULT_FROM_WIN32(GetLastError());
+ goto done;
+ }
+ if(!WriteFile(file, "<root/>", sizeof("<root/>") - 1, &count, NULL)) {
+ CloseHandle(file);
+ hres = HRESULT_FROM_WIN32(GetLastError());
+ goto done;
+ }
+ CloseHandle(file);
+ }
+
+ hres = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void**)&storage->doc);
+ if(hres != S_OK)
+ goto done;
+
+ V_VT(&var) = VT_BSTR;
+ V_BSTR(&var) = SysAllocString(storage->filename);
+ if(!V_BSTR(&var)) {
+ hres = E_OUTOFMEMORY;
+ goto done;
+ }
+
+ hres = IXMLDOMDocument_load(storage->doc, var, &success);
+ if(hres == S_FALSE || success == VARIANT_FALSE)
+ hres = E_FAIL;
+
+ SysFreeString(V_BSTR(&var));
+
+done:
+ if(hres != S_OK)
+ close_storage(storage);
+ else
+ *ret = storage;
+
+ return hres;
+}
+
static HRESULT WINAPI HTMLStorage_get_length(IHTMLStorage *iface, LONG *p)
{
HTMLStorage *This = impl_from_IHTMLStorage(iface);
@@ -142,14 +289,101 @@ static HRESULT WINAPI HTMLStorage_key(IHTMLStorage *iface, LONG lIndex, BSTR *p)
return E_NOTIMPL;
}
-static HRESULT WINAPI HTMLStorage_getItem(IHTMLStorage *iface, BSTR bstrKey, VARIANT *p)
+static BSTR build_query(const WCHAR *key)
+{
+ static const WCHAR fmt[] = L"item[@name='%s']";
+ const WCHAR *str = key ? key : L"";
+ UINT len = ARRAY_SIZE(fmt) + wcslen(str);
+ BSTR ret = SysAllocStringLen(NULL, len);
+
+ if(ret) swprintf(ret, len, fmt, str);
+ return ret;
+}
+
+static HRESULT get_root_node(IXMLDOMDocument *doc, IXMLDOMNode **root)
+{
+ HRESULT hres;
+ BSTR str;
+
+ str = SysAllocString(L"root");
+ if(!str)
+ return E_OUTOFMEMORY;
+
+ hres = IXMLDOMDocument_selectSingleNode(doc, str, root);
+ SysFreeString(str);
+ return hres;
+}
+
+static HRESULT get_item(BSTR hostname, BSTR key, VARIANT *value)
+{
+ struct storage *storage;
+ BSTR query = NULL;
+ IXMLDOMNode *root = NULL, *node = NULL;
+ IXMLDOMElement *elem = NULL;
+ HRESULT hres;
+
+ hres = open_storage(hostname, &storage);
+ if(hres != S_OK)
+ return hres;
+
+ hres = get_root_node(storage->doc, &root);
+ if(hres != S_OK)
+ goto done;
+
+ query = build_query(key);
+ if(!query) {
+ hres = E_OUTOFMEMORY;
+ goto done;
+ }
+
+ hres = IXMLDOMNode_selectSingleNode(root, query, &node);
+ if(hres == S_OK) {
+ hres = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)&elem);
+ if(hres != S_OK)
+ goto done;
+
+ hres = IXMLDOMElement_getAttribute(elem, (BSTR)L"value", value);
+ }else {
+ V_VT(value) = VT_NULL;
+ hres = S_OK;
+ }
+
+done:
+ SysFreeString(query);
+ if(root)
+ IXMLDOMNode_Release(root);
+ if(node)
+ IXMLDOMNode_Release(node);
+ if(elem)
+ IXMLDOMElement_Release(elem);
+ close_storage(storage);
+ return hres;
+}
+
+static HRESULT WINAPI HTMLStorage_getItem(IHTMLStorage *iface, BSTR bstrKey, VARIANT *value)
{
HTMLStorage *This = impl_from_IHTMLStorage(iface);
+ BSTR hostname;
+ HRESULT hres;
- FIXME("(%p)->(%s %p)\n", This, debugstr_w(bstrKey), p);
+ TRACE("(%p)->(%s %p)\n", This, debugstr_w(bstrKey), value);
- V_VT(p) = VT_NULL;
- return S_OK;
+ if(!value)
+ return E_POINTER;
+
+ if(!This->window) {
+ FIXME("session storage not supported\n");
+ V_VT(value) = VT_NULL;
+ return S_OK;
+ }
+
+ hres = IUri_GetHost(This->window->base.outer_window->uri, &hostname);
+ if(hres != S_OK)
+ return hres;
+
+ hres = get_item(hostname, bstrKey, value);
+ SysFreeString(hostname);
+ return hres;
}
static HRESULT WINAPI HTMLStorage_setItem(IHTMLStorage *iface, BSTR bstrKey, BSTR bstrValue)
@@ -201,7 +435,7 @@ static dispex_static_data_t HTMLStorage_dispex = {
HTMLStorage_iface_tids
};
-HRESULT create_html_storage(compat_mode_t compat_mode, IHTMLStorage **p)
+HRESULT create_html_storage(compat_mode_t compat_mode, HTMLInnerWindow *window, IHTMLStorage **p)
{
HTMLStorage *storage;
@@ -211,6 +445,7 @@ HRESULT create_html_storage(compat_mode_t compat_mode, IHTMLStorage **p)
storage->IHTMLStorage_iface.lpVtbl = &HTMLStorageVtbl;
storage->ref = 1;
+ storage->window = window;
init_dispatch(&storage->dispex, (IUnknown*)&storage->IHTMLStorage_iface, &HTMLStorage_dispex, compat_mode);
*p = &storage->IHTMLStorage_iface;
diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c
index ecd530db7e2..57388ae64a2 100644
--- a/dlls/mshtml/htmlwindow.c
+++ b/dlls/mshtml/htmlwindow.c
@@ -2143,7 +2143,7 @@ static HRESULT WINAPI HTMLWindow6_get_sessionStorage(IHTMLWindow6 *iface, IHTMLS
HRESULT hres;
hres = create_html_storage(dispex_compat_mode(&This->inner_window->event_target.dispex),
- &This->inner_window->session_storage);
+ NULL, &This->inner_window->session_storage);
if(FAILED(hres))
return hres;
}
@@ -2163,7 +2163,7 @@ static HRESULT WINAPI HTMLWindow6_get_localStorage(IHTMLWindow6 *iface, IHTMLSto
HRESULT hres;
hres = create_html_storage(dispex_compat_mode(&This->inner_window->event_target.dispex),
- &This->inner_window->local_storage);
+ This->inner_window, &This->inner_window->local_storage);
if(FAILED(hres))
return hres;
}
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h
index a94f1be1969..0fed06b8aae 100644
--- a/dlls/mshtml/mshtml_private.h
+++ b/dlls/mshtml/mshtml_private.h
@@ -941,7 +941,7 @@ HRESULT create_namespace_collection(compat_mode_t,IHTMLNamespaceCollection**) DE
HRESULT create_dom_implementation(HTMLDocumentNode*,IHTMLDOMImplementation**) DECLSPEC_HIDDEN;
void detach_dom_implementation(IHTMLDOMImplementation*) DECLSPEC_HIDDEN;
-HRESULT create_html_storage(compat_mode_t,IHTMLStorage**) DECLSPEC_HIDDEN;
+HRESULT create_html_storage(compat_mode_t,HTMLInnerWindow*,IHTMLStorage**) DECLSPEC_HIDDEN;
void HTMLDocument_Persist_Init(HTMLDocument*) DECLSPEC_HIDDEN;
void HTMLDocument_OleCmd_Init(HTMLDocument*) DECLSPEC_HIDDEN;
--
2.30.2