mshtml: Implement props for Storage by forwarding to the underlying storage.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
This commit is contained in:
Gabriel Ivăncescu 2022-09-01 16:49:45 +03:00 committed by Alexandre Julliard
parent 74e6ec1eab
commit e28cc104c1
3 changed files with 184 additions and 2 deletions

View file

@ -39,6 +39,8 @@ typedef struct {
DispatchEx dispex;
IHTMLStorage IHTMLStorage_iface;
LONG ref;
unsigned num_props;
BSTR *props;
struct session_map_entry *session_storage;
WCHAR *filename;
HANDLE mutex;
@ -178,6 +180,16 @@ void destroy_session_storage(thread_data_t *thread_data)
}
}
static void release_props(HTMLStorage *This)
{
BSTR *prop = This->props, *end = prop + This->num_props;
while(prop != end) {
SysFreeString(*prop);
prop++;
}
heap_free(This->props);
}
static inline HTMLStorage *impl_from_IHTMLStorage(IHTMLStorage *iface)
{
return CONTAINING_RECORD(iface, HTMLStorage, IHTMLStorage_iface);
@ -227,6 +239,7 @@ static ULONG WINAPI HTMLStorage_Release(IHTMLStorage *iface)
release_dispex(&This->dispex);
heap_free(This->filename);
CloseHandle(This->mutex);
release_props(This);
heap_free(This);
}
@ -835,13 +848,157 @@ static const IHTMLStorageVtbl HTMLStorageVtbl = {
HTMLStorage_clear
};
static inline HTMLStorage *impl_from_DispatchEx(DispatchEx *iface)
{
return CONTAINING_RECORD(iface, HTMLStorage, dispex);
}
static HRESULT check_item(HTMLStorage *This, const WCHAR *key)
{
struct session_entry *session_entry;
IXMLDOMNode *root, *node;
IXMLDOMDocument *doc;
HRESULT hres;
BSTR query;
if(!This->filename) {
hres = get_session_entry(This->session_storage, key, FALSE, &session_entry);
if(SUCCEEDED(hres))
hres = (session_entry && session_entry->value) ? S_OK : S_FALSE;
return hres;
}
WaitForSingleObject(This->mutex, INFINITE);
hres = open_document(This->filename, &doc);
if(hres == S_OK) {
hres = get_root_node(doc, &root);
IXMLDOMDocument_Release(doc);
if(hres == S_OK) {
if(!(query = build_query(key)))
hres = E_OUTOFMEMORY;
else {
hres = IXMLDOMNode_selectSingleNode(root, query, &node);
SysFreeString(query);
if(hres == S_OK)
IXMLDOMNode_Release(node);
}
IXMLDOMNode_Release(root);
}
}
ReleaseMutex(This->mutex);
return hres;
}
static HRESULT get_prop(HTMLStorage *This, const WCHAR *name, DISPID *dispid)
{
UINT name_len = wcslen(name);
BSTR p, *prop, *end;
for(prop = This->props, end = prop + This->num_props; prop != end; prop++) {
if(SysStringLen(*prop) == name_len && !memcmp(*prop, name, name_len * sizeof(WCHAR))) {
*dispid = MSHTML_DISPID_CUSTOM_MIN + (prop - This->props);
return S_OK;
}
}
if(is_power_of_2(This->num_props)) {
BSTR *new_props = heap_realloc(This->props, max(This->num_props * 2 * sizeof(BSTR*), 1));
if(!new_props)
return E_OUTOFMEMORY;
This->props = new_props;
}
if(!(p = SysAllocStringLen(name, name_len)))
return E_OUTOFMEMORY;
This->props[This->num_props] = p;
*dispid = MSHTML_DISPID_CUSTOM_MIN + This->num_props++;
return S_OK;
}
static HRESULT HTMLStorage_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid)
{
HTMLStorage *This = impl_from_DispatchEx(dispex);
HRESULT hres;
if(flags & fdexNameCaseInsensitive)
FIXME("case insensitive not supported\n");
if(!(flags & fdexNameEnsure)) {
hres = check_item(This, name);
if(hres != S_OK)
return FAILED(hres) ? hres : DISP_E_UNKNOWNNAME;
}
return get_prop(This, name, dispid);
}
static HRESULT HTMLStorage_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
{
HTMLStorage *This = impl_from_DispatchEx(dispex);
DWORD idx = id - MSHTML_DISPID_CUSTOM_MIN;
HRESULT hres;
BSTR bstr;
if(idx >= This->num_props)
return DISP_E_MEMBERNOTFOUND;
switch(flags) {
case DISPATCH_PROPERTYGET:
hres = HTMLStorage_getItem(&This->IHTMLStorage_iface, This->props[idx], res);
if(FAILED(hres))
return hres;
if(V_VT(res) == VT_NULL)
return DISP_E_MEMBERNOTFOUND;
break;
case DISPATCH_PROPERTYPUTREF:
case DISPATCH_PROPERTYPUT:
if(params->cArgs != 1 || (params->cNamedArgs && params->rgdispidNamedArgs[0] != DISPID_PROPERTYPUT)) {
FIXME("unimplemented args %u %u\n", params->cArgs, params->cNamedArgs);
return E_NOTIMPL;
}
bstr = V_BSTR(params->rgvarg);
if(V_VT(params->rgvarg) != VT_BSTR) {
VARIANT var;
hres = change_type(&var, params->rgvarg, VT_BSTR, caller);
if(FAILED(hres))
return hres;
bstr = V_BSTR(&var);
}
hres = HTMLStorage_setItem(&This->IHTMLStorage_iface, This->props[idx], bstr);
if(V_VT(params->rgvarg) != VT_BSTR)
SysFreeString(bstr);
return hres;
default:
FIXME("unimplemented flags %x\n", flags);
return E_NOTIMPL;
}
return S_OK;
}
static const dispex_static_data_vtbl_t HTMLStorage_dispex_vtbl = {
NULL,
HTMLStorage_get_dispid,
HTMLStorage_invoke,
NULL
};
static const tid_t HTMLStorage_iface_tids[] = {
IHTMLStorage_tid,
0
};
static dispex_static_data_t HTMLStorage_dispex = {
L"Storage",
NULL,
&HTMLStorage_dispex_vtbl,
IHTMLStorage_tid,
HTMLStorage_iface_tids
};

View file

@ -1423,6 +1423,11 @@ static inline BOOL is_digit(WCHAR c)
return '0' <= c && c <= '9';
}
static inline BOOL is_power_of_2(unsigned x)
{
return !(x & (x - 1));
}
#ifdef __i386__
extern void *call_thiscall_func;
#endif

View file

@ -473,7 +473,27 @@ sync_test("storage", function() {
"typeof(window.localStorage) = " + typeof(window.localStorage));
var item = sessionStorage.getItem("nonexisting");
ok(item === null, "item = " + item);
ok(item === null, "'nonexisting' item = " + item);
item = sessionStorage["nonexisting"];
ok(item === undefined, "[nonexisting] item = " + item);
ok(!("nonexisting" in sessionStorage), "nonexisting in sessionStorage");
sessionStorage.setItem("foobar", 42);
ok("foobar" in sessionStorage, "foobar not in sessionStorage");
item = sessionStorage.getItem("foobar");
ok(item === "42", "'foobar' item = " + item);
item = sessionStorage["foobar"];
ok(item === "42", "[foobar] item = " + item);
sessionStorage.removeItem("foobar");
item = sessionStorage["foobar"];
ok(item === undefined, "[foobar] item after removal = " + item);
sessionStorage["barfoo"] = true;
ok("barfoo" in sessionStorage, "barfoo not in sessionStorage");
item = sessionStorage["barfoo"];
ok(item === "true", "[barfoo] item = " + item);
item = sessionStorage.getItem("barfoo");
ok(item === "true", "'barfoo' item = " + item);
});
async_test("animation", function() {