mshtml: Implement document.mimeType.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
This commit is contained in:
Gabriel Ivăncescu 2022-10-31 18:27:37 +02:00 committed by Alexandre Julliard
parent 8dd8664a51
commit c25dfb7965
7 changed files with 325 additions and 3 deletions

View file

@ -1245,8 +1245,27 @@ static HRESULT WINAPI HTMLDocument_get_defaultCharset(IHTMLDocument2 *iface, BST
static HRESULT WINAPI HTMLDocument_get_mimeType(IHTMLDocument2 *iface, BSTR *p)
{
HTMLDocumentNode *This = impl_from_IHTMLDocument2(iface);
FIXME("(%p)->(%p)\n", This, p);
return E_NOTIMPL;
const PRUnichar *content_type;
nsAString nsstr;
nsresult nsres;
HRESULT hres;
TRACE("(%p)->(%p)\n", This, p);
*p = NULL;
if(This->window && This->window->base.outer_window->readystate == READYSTATE_UNINITIALIZED)
return (*p = SysAllocString(L"")) ? S_OK : E_FAIL;
nsAString_InitDepend(&nsstr, NULL);
nsres = nsIDOMHTMLDocument_GetContentType(This->nsdoc, &nsstr);
if(NS_FAILED(nsres))
return map_nsresult(nsres);
nsAString_GetData(&nsstr, &content_type);
hres = get_mime_type_display_name(content_type, p);
nsAString_Finish(&nsstr);
return hres;
}
static HRESULT WINAPI HTMLDocument_get_fileSize(IHTMLDocument2 *iface, BSTR *p)

View file

@ -126,6 +126,109 @@ BSTR charset_string_from_cp(UINT cp)
return SysAllocString(info.wszWebCharset);
}
HRESULT get_mime_type_display_name(const WCHAR *content_type, BSTR *ret)
{
/* undocumented */
extern BOOL WINAPI GetMIMETypeSubKeyW(LPCWSTR,LPWSTR,DWORD);
WCHAR buffer[128], ext[128], *str, *progid;
DWORD type, len;
HKEY key = NULL;
LSTATUS status;
HRESULT hres;
CLSID clsid;
str = buffer;
if(!GetMIMETypeSubKeyW(content_type, buffer, ARRAY_SIZE(buffer))) {
len = wcslen(content_type) + 32;
for(;;) {
if(!(str = heap_alloc(len * sizeof(WCHAR))))
return E_OUTOFMEMORY;
if(GetMIMETypeSubKeyW(content_type, str, len))
break;
heap_free(str);
len *= 2;
}
}
status = RegOpenKeyExW(HKEY_CLASSES_ROOT, str, 0, KEY_QUERY_VALUE, &key);
if(str != buffer)
heap_free(str);
if(status != ERROR_SUCCESS)
goto fail;
len = sizeof(ext);
status = RegQueryValueExW(key, L"Extension", NULL, &type, (BYTE*)ext, &len);
if(status != ERROR_SUCCESS || type != REG_SZ) {
len = sizeof(buffer);
status = RegQueryValueExW(key, L"CLSID", NULL, &type, (BYTE*)buffer, &len);
if(status != ERROR_SUCCESS || type != REG_SZ || CLSIDFromString(buffer, &clsid) != S_OK)
goto fail;
hres = ProgIDFromCLSID(&clsid, &progid);
if(hres == E_OUTOFMEMORY) {
RegCloseKey(key);
return hres;
}
if(hres != S_OK)
goto fail;
}else {
progid = ext;
}
len = ARRAY_SIZE(buffer);
str = buffer;
for(;;) {
hres = AssocQueryStringW(ASSOCF_NOTRUNCATE, ASSOCSTR_FRIENDLYDOCNAME, progid, NULL, str, &len);
if(hres == S_OK && len)
break;
if(str != buffer)
heap_free(str);
if(hres != E_POINTER) {
if(progid != ext) {
CoTaskMemFree(progid);
goto fail;
}
/* Try from CLSID */
len = sizeof(buffer);
status = RegQueryValueExW(key, L"CLSID", NULL, &type, (BYTE*)buffer, &len);
if(status != ERROR_SUCCESS || type != REG_SZ || CLSIDFromString(buffer, &clsid) != S_OK)
goto fail;
hres = ProgIDFromCLSID(&clsid, &progid);
if(hres == E_OUTOFMEMORY) {
RegCloseKey(key);
return hres;
}
if(hres != S_OK)
goto fail;
len = ARRAY_SIZE(buffer);
str = buffer;
continue;
}
str = heap_alloc(len * sizeof(WCHAR));
}
if(progid != ext)
CoTaskMemFree(progid);
RegCloseKey(key);
*ret = SysAllocString(str);
if(str != buffer)
heap_free(str);
return *ret ? S_OK : E_OUTOFMEMORY;
fail:
RegCloseKey(key);
WARN("Did not find MIME in database for %s\n", debugstr_w(content_type));
/* native seems to return "File" when it doesn't know the content type */
*ret = SysAllocString(L"File");
return *ret ? S_OK : E_OUTOFMEMORY;
}
IInternetSecurityManager *get_security_manager(void)
{
if(!security_manager) {

View file

@ -1455,6 +1455,7 @@ extern void *call_thiscall_func;
compat_mode_t get_max_compat_mode(IUri*) DECLSPEC_HIDDEN;
UINT cp_from_charset_string(BSTR) DECLSPEC_HIDDEN;
BSTR charset_string_from_cp(UINT) DECLSPEC_HIDDEN;
HRESULT get_mime_type_display_name(const WCHAR*,BSTR*) DECLSPEC_HIDDEN;
HINSTANCE get_shdoclc(void) DECLSPEC_HIDDEN;
void set_statustext(HTMLDocumentObj*,INT,LPCWSTR) DECLSPEC_HIDDEN;
IInternetSecurityManager *get_security_manager(void) DECLSPEC_HIDDEN;

View file

@ -1,5 +1,5 @@
TESTDLL = mshtml.dll
IMPORTS = ole32 oleaut32 wininet user32 urlmon gdi32 advapi32
IMPORTS = ole32 oleaut32 shlwapi wininet user32 urlmon gdi32 advapi32
C_SRCS = \
activex.c \
dom.c \

View file

@ -311,6 +311,7 @@ sync_test("doc_props", function() {
}
var v = document.documentMode;
ok(document.mimeType === external.getExpectedMimeType("text/html"), "mimeType = " + document.mimeType);
test_exposed("onstorage", v < 9);
test_exposed("textContent", v >= 9);

View file

@ -27,6 +27,7 @@
#include "winbase.h"
#include "initguid.h"
#include "ole2.h"
#include "shlwapi.h"
#include "mshtml.h"
#include "docobj.h"
#include "docobjectservice.h"
@ -449,6 +450,84 @@ static void _test_current_url(unsigned line, IUnknown *unk, const WCHAR *exurl)
IHTMLDocument2_Release(doc);
}
static BSTR get_mime_type_display_name(const WCHAR *content_type)
{
WCHAR buffer[128], ext[128], *str, *progid;
HKEY key, type_key = NULL;
DWORD type, len;
LSTATUS status;
HRESULT hres;
CLSID clsid;
BSTR ret;
status = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"MIME\\Database\\Content Type", 0, KEY_READ, &key);
if(status != ERROR_SUCCESS)
goto fail;
status = RegOpenKeyExW(key, content_type, 0, KEY_QUERY_VALUE, &type_key);
RegCloseKey(key);
if(status != ERROR_SUCCESS)
goto fail;
len = sizeof(ext);
status = RegQueryValueExW(type_key, L"Extension", NULL, &type, (BYTE*)ext, &len);
if(status != ERROR_SUCCESS || type != REG_SZ) {
len = sizeof(buffer);
status = RegQueryValueExW(type_key, L"CLSID", NULL, &type, (BYTE*)buffer, &len);
if(status != ERROR_SUCCESS || type != REG_SZ || CLSIDFromString(buffer, &clsid) != S_OK ||
ProgIDFromCLSID(&clsid, &progid) != S_OK)
goto fail;
}else {
/* For some reason w1064v1809 testbot VM uses .htm here, despite .html being set in the database */
if(!wcscmp(ext, L".html"))
wcscpy(ext, L".htm");
progid = ext;
}
len = ARRAY_SIZE(buffer);
str = buffer;
for(;;) {
hres = AssocQueryStringW(ASSOCF_NOTRUNCATE, ASSOCSTR_FRIENDLYDOCNAME, progid, NULL, str, &len);
if(hres == S_OK && len)
break;
if(str != buffer)
free(str);
if(hres != E_POINTER) {
if(progid != ext) {
CoTaskMemFree(progid);
goto fail;
}
/* Try from CLSID */
len = sizeof(buffer);
status = RegQueryValueExW(type_key, L"CLSID", NULL, &type, (BYTE*)buffer, &len);
if(status != ERROR_SUCCESS || type != REG_SZ || CLSIDFromString(buffer, &clsid) != S_OK ||
ProgIDFromCLSID(&clsid, &progid) != S_OK)
goto fail;
len = ARRAY_SIZE(buffer);
str = buffer;
continue;
}
str = malloc(len * sizeof(WCHAR));
}
if(progid != ext)
CoTaskMemFree(progid);
RegCloseKey(type_key);
ret = SysAllocString(str);
if(str != buffer)
free(str);
return ret;
fail:
RegCloseKey(type_key);
trace("Did not find MIME in database for %s\n", debugstr_w(content_type));
return SysAllocString(L"File");
}
DEFINE_GUID(IID_External_unk,0x30510406,0x98B5,0x11CF,0xBB,0x82,0x00,0xAA,0x00,0xBD,0xCE,0x0B);
static HRESULT WINAPI External_QueryInterface(IDispatch *iface, REFIID riid, void **ppv)
@ -7680,6 +7759,25 @@ static void test_QueryInterface(IHTMLDocument2 *htmldoc)
IUnknown_Release(qi);
}
static void test_mimeType(IHTMLDocument2 *doc, const WCHAR *content_type)
{
BSTR mime_type = (BSTR)0xdeadbeef;
HRESULT hres;
hres = IHTMLDocument2_get_mimeType(doc, &mime_type);
if(content_type) {
BSTR display_name = get_mime_type_display_name(content_type);
ok(hres == S_OK, "get_mimeType returned %08lx\n", hres);
ok(!wcscmp(mime_type, display_name), "mime type = %s, expected %s\n",
debugstr_w(mime_type), debugstr_w(display_name));
SysFreeString(display_name);
}else {
ok(hres == S_OK || broken(hres == E_FAIL), "get_mimeType returned %08lx\n", hres);
ok(!mime_type || !mime_type[0], "mime type = %s\n", debugstr_w(mime_type));
}
SysFreeString(mime_type);
}
static void init_test(enum load_state_t ls) {
doc_unk = NULL;
doc_hwnd = last_hwnd = NULL;
@ -7733,6 +7831,7 @@ static void test_HTMLDocument(BOOL do_load, BOOL mime)
test_GetCurMoniker((IUnknown*)doc, &Moniker, NULL, FALSE);
test_elem_from_point(doc);
}
test_mimeType(doc, do_load ? L"text/html" : NULL);
test_MSHTML_QueryStatus(doc, OLECMDF_SUPPORTED);
test_OleCommandTarget_fail(doc);
@ -7844,6 +7943,7 @@ static void test_MHTMLDocument(void)
set_custom_uihandler(doc, &CustomDocHostUIHandler);
test_GetCurMoniker((IUnknown*)doc, NULL, L"mhtml:winetest:doc", FALSE);
test_download(0);
test_mimeType(doc, L"text/html");
test_exec_onunload(doc);
test_UIDeactivate();

View file

@ -26,6 +26,7 @@
#include "windef.h"
#include "winbase.h"
#include "ole2.h"
#include "shlwapi.h"
#include "wininet.h"
#include "docobj.h"
#include "dispex.h"
@ -157,6 +158,7 @@ DEFINE_EXPECT(GetTypeInfo);
#define DISPID_EXTERNAL_IS_ENGLISH 0x300009
#define DISPID_EXTERNAL_LIST_SEP 0x30000A
#define DISPID_EXTERNAL_TEST_VARS 0x30000B
#define DISPID_EXTERNAL_GETMIMETYPE 0x30000C
static const GUID CLSID_TestScript =
{0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x07,0x46}};
@ -200,6 +202,84 @@ static BOOL init_key(const char *key_name, const char *def_value, BOOL init)
return res == ERROR_SUCCESS;
}
static BSTR get_mime_type_display_name(const WCHAR *content_type)
{
WCHAR buffer[128], ext[128], *str, *progid;
HKEY key, type_key = NULL;
DWORD type, len;
LSTATUS status;
HRESULT hres;
CLSID clsid;
BSTR ret;
status = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"MIME\\Database\\Content Type", 0, KEY_READ, &key);
if(status != ERROR_SUCCESS)
goto fail;
status = RegOpenKeyExW(key, content_type, 0, KEY_QUERY_VALUE, &type_key);
RegCloseKey(key);
if(status != ERROR_SUCCESS)
goto fail;
len = sizeof(ext);
status = RegQueryValueExW(type_key, L"Extension", NULL, &type, (BYTE*)ext, &len);
if(status != ERROR_SUCCESS || type != REG_SZ) {
len = sizeof(buffer);
status = RegQueryValueExW(type_key, L"CLSID", NULL, &type, (BYTE*)buffer, &len);
if(status != ERROR_SUCCESS || type != REG_SZ || CLSIDFromString(buffer, &clsid) != S_OK ||
ProgIDFromCLSID(&clsid, &progid) != S_OK)
goto fail;
}else {
/* For some reason w1064v1809 testbot VM uses .htm here, despite .html being set in the database */
if(!wcscmp(ext, L".html"))
wcscpy(ext, L".htm");
progid = ext;
}
len = ARRAY_SIZE(buffer);
str = buffer;
for(;;) {
hres = AssocQueryStringW(ASSOCF_NOTRUNCATE, ASSOCSTR_FRIENDLYDOCNAME, progid, NULL, str, &len);
if(hres == S_OK && len)
break;
if(str != buffer)
free(str);
if(hres != E_POINTER) {
if(progid != ext) {
CoTaskMemFree(progid);
goto fail;
}
/* Try from CLSID */
len = sizeof(buffer);
status = RegQueryValueExW(type_key, L"CLSID", NULL, &type, (BYTE*)buffer, &len);
if(status != ERROR_SUCCESS || type != REG_SZ || CLSIDFromString(buffer, &clsid) != S_OK ||
ProgIDFromCLSID(&clsid, &progid) != S_OK)
goto fail;
len = ARRAY_SIZE(buffer);
str = buffer;
continue;
}
str = malloc(len * sizeof(WCHAR));
}
if(progid != ext)
CoTaskMemFree(progid);
RegCloseKey(type_key);
ret = SysAllocString(str);
if(str != buffer)
free(str);
return ret;
fail:
RegCloseKey(type_key);
trace("Did not find MIME in database for %s\n", debugstr_w(content_type));
return SysAllocString(L"File");
}
static void test_script_vars(unsigned argc, VARIANTARG *argv)
{
static const WCHAR *const jsobj_names[] = { L"abc", L"foO", L"bar", L"TostRing", L"hasownpropERty" };
@ -715,6 +795,10 @@ static HRESULT WINAPI externalDisp_GetDispID(IDispatchEx *iface, BSTR bstrName,
*pid = DISPID_EXTERNAL_TEST_VARS;
return S_OK;
}
if(!lstrcmpW(bstrName, L"getExpectedMimeType")) {
*pid = DISPID_EXTERNAL_GETMIMETYPE;
return S_OK;
}
ok(0, "unexpected name %s\n", wine_dbgstr_w(bstrName));
return DISP_E_UNKNOWNNAME;
@ -948,6 +1032,20 @@ static HRESULT WINAPI externalDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID
test_script_vars(pdp->cArgs, pdp->rgvarg);
return S_OK;
case DISPID_EXTERNAL_GETMIMETYPE:
ok(pdp != NULL, "pdp == NULL\n");
ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
ok(V_VT(pdp->rgvarg) == VT_BSTR, "VT(rgvarg) = %d\n", V_VT(pdp->rgvarg));
ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs);
ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
ok(pvarRes != NULL, "pvarRes == NULL\n");
ok(V_VT(pvarRes) == VT_EMPTY, "V_VT(pvarRes) = %d\n", V_VT(pvarRes));
ok(pei != NULL, "pei == NULL\n");
V_BSTR(pvarRes) = get_mime_type_display_name(V_BSTR(pdp->rgvarg));
V_VT(pvarRes) = V_BSTR(pvarRes) ? VT_BSTR : VT_NULL;
return S_OK;
default:
ok(0, "unexpected call\n");
return E_NOTIMPL;