[PATCH 1/5] mshtml: Implement HTMLStorage_getItem().

Hans Leidekker hans at codeweavers.com
Fri May 20 03:15:23 CDT 2022


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/mshtml/htmlstorage.c    | 244 ++++++++++++++++++++++++++++++++++-
 dlls/mshtml/htmlwindow.c     |   4 +-
 dlls/mshtml/mshtml_private.h |   2 +-
 3 files changed, 242 insertions(+), 8 deletions(-)

diff --git a/dlls/mshtml/htmlstorage.c b/dlls/mshtml/htmlstorage.c
index 95f7ae5cd16..fb433fa28b9 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,100 @@ 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");
+        return E_NOTIMPL;
+    }
+
+    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 +434,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 +444,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




More information about the wine-devel mailing list