mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-31 08:49:15 +00:00
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:
parent
74e6ec1eab
commit
e28cc104c1
3 changed files with 184 additions and 2 deletions
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in a new issue