From 176299806853ce89db9c4328782dc6a46b2d6fba Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Sat, 28 Sep 2013 15:08:52 +0000 Subject: [PATCH] [URLMON] * Sync with Wine 1.7.1. CORE-7469 svn path=/trunk/; revision=60416 --- reactos/dll/win32/urlmon/CMakeLists.txt | 9 +- reactos/dll/win32/urlmon/binding.c | 16 +- reactos/dll/win32/urlmon/bindprot.c | 4 + reactos/dll/win32/urlmon/mimefilter.c | 407 ++++++++++++++++++++++++ reactos/dll/win32/urlmon/protocol.c | 2 +- reactos/dll/win32/urlmon/umon.c | 17 +- reactos/dll/win32/urlmon/uri.c | 17 +- reactos/dll/win32/urlmon/urlmon_main.c | 372 +--------------------- reactos/media/doc/README.WINE | 2 +- 9 files changed, 454 insertions(+), 392 deletions(-) diff --git a/reactos/dll/win32/urlmon/CMakeLists.txt b/reactos/dll/win32/urlmon/CMakeLists.txt index 2821e68701d..81404deda38 100644 --- a/reactos/dll/win32/urlmon/CMakeLists.txt +++ b/reactos/dll/win32/urlmon/CMakeLists.txt @@ -7,13 +7,11 @@ add_definitions( -DWINE_REGISTER_DLL -DPROXY_CLSID_IS="{0x79EAC9F1,0xBAF9,0x11CE,{0x8C,0x82,0x00,0xAA,0x00,0x4B,0xA9,0x0B}}") -remove_definitions(-D_WIN32_WINNT=0x502) -add_definitions(-D_WIN32_WINNT=0x600) +#remove_definitions(-D_WIN32_WINNT=0x502) +#add_definitions(-D_WIN32_WINNT=0x600) include_directories(${REACTOS_SOURCE_DIR}/include/reactos/wine) - spec2def(urlmon.dll urlmon.spec ADD_IMPORTLIB) - add_rpcproxy_files(urlmon_urlmon.idl) list(APPEND SOURCE @@ -38,13 +36,12 @@ list(APPEND SOURCE uri.c urlmon_main.c usrmarshal.c - urlmon.rc ${CMAKE_CURRENT_BINARY_DIR}/proxy.dlldata.c ${CMAKE_CURRENT_BINARY_DIR}/urlmon_urlmon_p.c ${CMAKE_CURRENT_BINARY_DIR}/urlmon_stubs.c ${CMAKE_CURRENT_BINARY_DIR}/urlmon.def) -add_library(urlmon SHARED ${SOURCE}) +add_library(urlmon SHARED ${SOURCE} urlmon.rc) set_module_type(urlmon win32dll) target_link_libraries(urlmon uuid wine ${PSEH_LIB}) add_importlibs(urlmon rpcrt4 propsys ole32 oleaut32 shlwapi shell32 wininet user32 advapi32 advpack msvcrt kernel32 ntdll) diff --git a/reactos/dll/win32/urlmon/binding.c b/reactos/dll/win32/urlmon/binding.c index 6f287511599..5767211acbf 100644 --- a/reactos/dll/win32/urlmon/binding.c +++ b/reactos/dll/win32/urlmon/binding.c @@ -299,16 +299,18 @@ static void create_object(Binding *binding) return; } - if(!(clsid_str = get_mime_clsid(binding->mime, &clsid))) { - FIXME("Could not find object for MIME %s\n", debugstr_w(binding->mime)); - return; - } + if((clsid_str = get_mime_clsid(binding->mime, &clsid))) + IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_CLASSIDAVAILABLE, clsid_str); - IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_CLASSIDAVAILABLE, clsid_str); IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_BEGINSYNCOPERATION, NULL); - hres = create_mime_object(binding, &clsid, clsid_str); - heap_free(clsid_str); + if(clsid_str) { + hres = create_mime_object(binding, &clsid, clsid_str); + heap_free(clsid_str); + }else { + FIXME("Could not find object for MIME %s\n", debugstr_w(binding->mime)); + hres = REGDB_E_CLASSNOTREG; + } IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_ENDSYNCOPERATION, NULL); binding->clsid = CLSID_NULL; diff --git a/reactos/dll/win32/urlmon/bindprot.c b/reactos/dll/win32/urlmon/bindprot.c index 7326e761fc7..de3f3f0261e 100644 --- a/reactos/dll/win32/urlmon/bindprot.c +++ b/reactos/dll/win32/urlmon/bindprot.c @@ -897,8 +897,12 @@ static HRESULT WINAPI ProtocolSinkHandler_ReportData(IInternetProtocolSink *ifac do { read = 0; + if(is_apartment_thread(This)) + This->continue_call++; hres = IInternetProtocol_Read(This->protocol, buf, sizeof(buf)-This->buf_size, &read); + if(is_apartment_thread(This)) + This->continue_call--; if(FAILED(hres) && hres != E_PENDING) return hres; diff --git a/reactos/dll/win32/urlmon/mimefilter.c b/reactos/dll/win32/urlmon/mimefilter.c index 5b92faffaec..f0c8073da7b 100644 --- a/reactos/dll/win32/urlmon/mimefilter.c +++ b/reactos/dll/win32/urlmon/mimefilter.c @@ -260,3 +260,410 @@ HRESULT MimeFilter_Construct(IUnknown *pUnkOuter, LPVOID *ppobj) *ppobj = &ret->IInternetProtocol_iface; return S_OK; } + +static BOOL text_richtext_filter(const BYTE *b, DWORD size) +{ + return size > 5 && !memcmp(b, "{\\rtf", 5); +} + +static BOOL text_html_filter(const BYTE *b, DWORD size) +{ + if(size < 6) + return FALSE; + + if((b[0] == '<' + && (b[1] == 'h' || b[1] == 'H') + && (b[2] == 't' || b[2] == 'T') + && (b[3] == 'm' || b[3] == 'M') + && (b[4] == 'l' || b[4] == 'L')) + || (b[0] == '<' + && (b[1] == 'h' || b[1] == 'H') + && (b[2] == 'e' || b[2] == 'E') + && (b[3] == 'a' || b[3] == 'A') + && (b[4] == 'd' || b[4] == 'D'))) return TRUE; + + return FALSE; +} + +static BOOL text_xml_filter(const BYTE *b, DWORD size) +{ + if(size < 7) + return FALSE; + + if(b[0] == '<' && b[1] == '?' + && (b[2] == 'x' || b[2] == 'X') + && (b[3] == 'm' || b[3] == 'M') + && (b[4] == 'l' || b[4] == 'L') + && b[5] == ' ') return TRUE; + + return FALSE; +} + +static BOOL audio_basic_filter(const BYTE *b, DWORD size) +{ + return size > 4 + && b[0] == '.' && b[1] == 's' && b[2] == 'n' && b[3] == 'd'; +} + +static BOOL audio_wav_filter(const BYTE *b, DWORD size) +{ + return size > 12 + && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F' + && b[8] == 'W' && b[9] == 'A' && b[10] == 'V' && b[11] == 'E'; +} + +static BOOL image_gif_filter(const BYTE *b, DWORD size) +{ + return size >= 6 + && (b[0] == 'G' || b[0] == 'g') + && (b[1] == 'I' || b[1] == 'i') + && (b[2] == 'F' || b[2] == 'f') + && b[3] == '8' + && (b[4] == '7' || b[4] == '9') + && (b[5] == 'A' || b[5] == 'a'); +} + +static BOOL image_pjpeg_filter(const BYTE *b, DWORD size) +{ + return size > 2 && b[0] == 0xff && b[1] == 0xd8; +} + +static BOOL image_tiff_filter(const BYTE *b, DWORD size) +{ + static const BYTE magic1[] = {0x4d,0x4d,0x00,0x2a}; + static const BYTE magic2[] = {0x49,0x49,0x2a,0xff}; + + return size >= 4 && (!memcmp(b, magic1, 4) || !memcmp(b, magic2, 4)); +} + +static BOOL image_xpng_filter(const BYTE *b, DWORD size) +{ + static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a}; + return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header)); +} + +static BOOL image_bmp_filter(const BYTE *b, DWORD size) +{ + return size >= 14 + && b[0] == 0x42 && b[1] == 0x4d + && *(const DWORD *)(b+6) == 0; +} + +static BOOL video_avi_filter(const BYTE *b, DWORD size) +{ + return size > 12 + && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F' + && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20; +} + +static BOOL video_mpeg_filter(const BYTE *b, DWORD size) +{ + return size > 4 + && !b[0] && !b[1] && b[2] == 0x01 + && (b[3] == 0xb3 || b[3] == 0xba); +} + +static BOOL application_postscript_filter(const BYTE *b, DWORD size) +{ + return size > 2 && b[0] == '%' && b[1] == '!'; +} + +static BOOL application_pdf_filter(const BYTE *b, DWORD size) +{ + return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46; +} + +static BOOL application_xzip_filter(const BYTE *b, DWORD size) +{ + return size > 2 && b[0] == 0x50 && b[1] == 0x4b; +} + +static BOOL application_xgzip_filter(const BYTE *b, DWORD size) +{ + return size > 2 && b[0] == 0x1f && b[1] == 0x8b; +} + +static BOOL application_java_filter(const BYTE *b, DWORD size) +{ + return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe; +} + +static BOOL application_xmsdownload(const BYTE *b, DWORD size) +{ + return size > 2 && b[0] == 'M' && b[1] == 'Z'; +} + +static inline BOOL is_text_plain_char(BYTE b) +{ + if(b < 0x20 && b != '\n' && b != '\r' && b != '\t') + return FALSE; + return TRUE; +} + +static BOOL text_plain_filter(const BYTE *b, DWORD size) +{ + const BYTE *ptr; + + for(ptr = b; ptr < b+size-1; ptr++) { + if(!is_text_plain_char(*ptr)) + return FALSE; + } + + return TRUE; +} + +static BOOL application_octet_stream_filter(const BYTE *b, DWORD size) +{ + return TRUE; +} + +static HRESULT find_mime_from_url(const WCHAR *url, WCHAR **ret) +{ + const WCHAR *ptr; + DWORD res, size; + WCHAR mime[64]; + HKEY hkey; + + static const WCHAR content_typeW[] = {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'}; + + ptr = strrchrW(url, '.'); + if(!ptr) + return E_FAIL; + + res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey); + if(res != ERROR_SUCCESS) + return HRESULT_FROM_WIN32(res); + + size = sizeof(mime); + res = RegQueryValueExW(hkey, content_typeW, NULL, NULL, (LPBYTE)mime, &size); + RegCloseKey(hkey); + if(res != ERROR_SUCCESS) + return HRESULT_FROM_WIN32(res); + + TRACE("found MIME %s\n", debugstr_w(mime)); + + *ret = CoTaskMemAlloc(size); + memcpy(*ret, mime, size); + return S_OK; +} + +static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0}; +static const WCHAR text_richtextW[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0}; +static const WCHAR text_xmlW[] = {'t','e','x','t','/','x','m','l',0}; +static const WCHAR audio_basicW[] = {'a','u','d','i','o','/','b','a','s','i','c',0}; +static const WCHAR audio_wavW[] = {'a','u','d','i','o','/','w','a','v',0}; +static const WCHAR image_gifW[] = {'i','m','a','g','e','/','g','i','f',0}; +static const WCHAR image_pjpegW[] = {'i','m','a','g','e','/','p','j','p','e','g',0}; +static const WCHAR image_tiffW[] = {'i','m','a','g','e','/','t','i','f','f',0}; +static const WCHAR image_xpngW[] = {'i','m','a','g','e','/','x','-','p','n','g',0}; +static const WCHAR image_bmpW[] = {'i','m','a','g','e','/','b','m','p',0}; +static const WCHAR video_aviW[] = {'v','i','d','e','o','/','a','v','i',0}; +static const WCHAR video_mpegW[] = {'v','i','d','e','o','/','m','p','e','g',0}; +static const WCHAR app_postscriptW[] = + {'a','p','p','l','i','c','a','t','i','o','n','/','p','o','s','t','s','c','r','i','p','t',0}; +static const WCHAR app_pdfW[] = {'a','p','p','l','i','c','a','t','i','o','n','/','p','d','f',0}; +static const WCHAR app_xzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/', + 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0}; +static const WCHAR app_xgzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/', + 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0}; +static const WCHAR app_javaW[] = {'a','p','p','l','i','c','a','t','i','o','n','/','j','a','v','a',0}; +static const WCHAR app_xmsdownloadW[] = {'a','p','p','l','i','c','a','t','i','o','n','/', + 'x','-','m','s','d','o','w','n','l','o','a','d',0}; +static const WCHAR text_plainW[] = {'t','e','x','t','/','p','l','a','i','n','\0'}; +static const WCHAR app_octetstreamW[] = {'a','p','p','l','i','c','a','t','i','o','n','/', + 'o','c','t','e','t','-','s','t','r','e','a','m','\0'}; + +static const struct { + const WCHAR *mime; + BOOL (*filter)(const BYTE *,DWORD); +} mime_filters_any_pos[] = { + {text_htmlW, text_html_filter}, + {text_xmlW, text_xml_filter} +}, mime_filters[] = { + {text_richtextW, text_richtext_filter}, + /* {audio_xaiffW, audio_xaiff_filter}, */ + {audio_basicW, audio_basic_filter}, + {audio_wavW, audio_wav_filter}, + {image_gifW, image_gif_filter}, + {image_pjpegW, image_pjpeg_filter}, + {image_tiffW, image_tiff_filter}, + {image_xpngW, image_xpng_filter}, + /* {image_xbitmapW, image_xbitmap_filter}, */ + {image_bmpW, image_bmp_filter}, + /* {image_xjgW, image_xjg_filter}, */ + /* {image_xemfW, image_xemf_filter}, */ + /* {image_xwmfW, image_xwmf_filter}, */ + {video_aviW, video_avi_filter}, + {video_mpegW, video_mpeg_filter}, + {app_postscriptW, application_postscript_filter}, + /* {app_base64W, application_base64_filter}, */ + /* {app_macbinhex40W, application_macbinhex40_filter}, */ + {app_pdfW, application_pdf_filter}, + /* {app_zcompressedW, application_xcompressed_filter}, */ + {app_xzipW, application_xzip_filter}, + {app_xgzipW, application_xgzip_filter}, + {app_javaW, application_java_filter}, + {app_xmsdownloadW, application_xmsdownload}, + {text_plainW, text_plain_filter}, + {app_octetstreamW, application_octet_stream_filter} +}; + +static BOOL is_known_mime_type(const WCHAR *mime) +{ + unsigned i; + + for(i=0; i < sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) { + if(!strcmpW(mime, mime_filters_any_pos[i].mime)) + return TRUE; + } + + for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) { + if(!strcmpW(mime, mime_filters[i].mime)) + return TRUE; + } + + return FALSE; +} + +static HRESULT find_mime_from_buffer(const BYTE *buf, DWORD size, const WCHAR *proposed_mime, const WCHAR *url, WCHAR **ret_mime) +{ + int len, i, any_pos_mime = -1; + const WCHAR *ret = NULL; + + if(!buf || !size) { + if(!proposed_mime) + return E_FAIL; + + len = strlenW(proposed_mime)+1; + *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR)); + if(!*ret_mime) + return E_OUTOFMEMORY; + + memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR)); + return S_OK; + } + + if(proposed_mime && (!strcmpW(proposed_mime, app_octetstreamW) + || !strcmpW(proposed_mime, text_plainW))) + proposed_mime = NULL; + + if(proposed_mime) { + ret = proposed_mime; + + for(i=0; i < sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) { + if(!strcmpW(proposed_mime, mime_filters_any_pos[i].mime)) { + any_pos_mime = i; + for(len=size; len>0; len--) { + if(mime_filters_any_pos[i].filter(buf+size-len, len)) + break; + } + if(!len) + ret = NULL; + break; + } + } + + if(i == sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos)) { + for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) { + if(!strcmpW(proposed_mime, mime_filters[i].mime)) { + if(!mime_filters[i].filter(buf, size)) + ret = NULL; + break; + } + } + } + } + + /* Looks like a bug in native implementation, html and xml mimes + * are not looked for if none of them was proposed */ + if(!proposed_mime || any_pos_mime!=-1) { + for(len=size; !ret && len>0; len--) { + for(i=0; i0; len--) { + if(!is_text_plain_char(buf[size-len])) + break; + for(i=0; ibindf & BINDF_NEEDFILE) { diff --git a/reactos/dll/win32/urlmon/umon.c b/reactos/dll/win32/urlmon/umon.c index 926fb7a66bf..39846bfe112 100644 --- a/reactos/dll/win32/urlmon/umon.c +++ b/reactos/dll/win32/urlmon/umon.c @@ -233,7 +233,22 @@ static HRESULT WINAPI URLMoniker_BindToObject(IMoniker *iface, IBindCtx* pbc, IM hres = IBindCtx_GetRunningObjectTable(pbc, &obj_tbl); if(SUCCEEDED(hres)) { - FIXME("use running object table\n"); + hres = IRunningObjectTable_IsRunning(obj_tbl, &This->IMoniker_iface); + if(hres == S_OK) { + IUnknown *unk = NULL; + + TRACE("Found in running object table\n"); + + hres = IRunningObjectTable_GetObject(obj_tbl, &This->IMoniker_iface, &unk); + if(SUCCEEDED(hres)) { + hres = IUnknown_QueryInterface(unk, riid, ppv); + IUnknown_Release(unk); + } + + IRunningObjectTable_Release(obj_tbl); + return hres; + } + IRunningObjectTable_Release(obj_tbl); } diff --git a/reactos/dll/win32/urlmon/uri.c b/reactos/dll/win32/urlmon/uri.c index 3f3b19c0257..35ec20f1a78 100644 --- a/reactos/dll/win32/urlmon/uri.c +++ b/reactos/dll/win32/urlmon/uri.c @@ -422,7 +422,7 @@ static inline BOOL is_hierarchical_uri(const WCHAR **ptr, const parse_data *data else if(is_hierarchical_scheme(data->scheme_type) && (*ptr)[0] == '\\' && (*ptr)[1] == '\\') { *ptr += 2; return TRUE; - } else if(check_hierarchical(ptr)) + } else if(data->scheme_type != URL_SCHEME_MAILTO && check_hierarchical(ptr)) return TRUE; *ptr = start; @@ -1917,8 +1917,15 @@ static BOOL parse_path_hierarchical(const WCHAR **ptr, parse_data *data, DWORD f static BOOL parse_path_opaque(const WCHAR **ptr, parse_data *data, DWORD flags) { const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN; const BOOL is_file = data->scheme_type == URL_SCHEME_FILE; + const BOOL is_mailto = data->scheme_type == URL_SCHEME_MAILTO; - data->path = *ptr; + if (is_mailto && (*ptr)[0] == '/' && (*ptr)[1] == '/') + { + if ((*ptr)[2]) data->path = *ptr + 2; + else data->path = NULL; + } + else + data->path = *ptr; while(!is_path_delim(**ptr)) { if(**ptr == '%' && known_scheme) { @@ -1938,7 +1945,7 @@ static BOOL parse_path_opaque(const WCHAR **ptr, parse_data *data, DWORD flags) ++(*ptr); } - data->path_len = *ptr - data->path; + if (data->path) data->path_len = *ptr - data->path; TRACE("(%p %p %x): Parsed opaque URI path %s len=%d\n", ptr, data, flags, debugstr_wn(data->path, data->path_len), data->path_len); return TRUE; @@ -6461,7 +6468,7 @@ static HRESULT combine_uri(Uri *base, Uri *relative, DWORD flags, IUri **result, return E_OUTOFMEMORY; } - parse_uri(&data, 0); + parse_uri(&data, Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME); hr = Uri_Construct(NULL, (void**)&ret); if(FAILED(hr)) { @@ -6800,7 +6807,7 @@ HRESULT WINAPI CoInternetCombineUrlEx(IUri *pBaseUri, LPCWSTR pwzRelativeUrl, DW } } - hr = CreateUri(pwzRelativeUrl, Uri_CREATE_ALLOW_RELATIVE, 0, &relative); + hr = CreateUri(pwzRelativeUrl, Uri_CREATE_ALLOW_RELATIVE|Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME, 0, &relative); if(FAILED(hr)) { *ppCombinedUri = NULL; return hr; diff --git a/reactos/dll/win32/urlmon/urlmon_main.c b/reactos/dll/win32/urlmon/urlmon_main.c index 4a81d13ab9a..bb707498a18 100644 --- a/reactos/dll/win32/urlmon/urlmon_main.c +++ b/reactos/dll/win32/urlmon/urlmon_main.c @@ -157,6 +157,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad) break; case DLL_PROCESS_DETACH: + if (fImpLoad) break; process_detach(); DeleteCriticalSection(&tls_cs); break; @@ -696,377 +697,6 @@ HRESULT WINAPI CopyBindInfo(const BINDINFO *pcbiSrc, BINDINFO *pcbiDest) return S_OK; } -static BOOL text_richtext_filter(const BYTE *b, DWORD size) -{ - return size > 5 && !memcmp(b, "{\\rtf", 5); -} - -static BOOL text_html_filter(const BYTE *b, DWORD size) -{ - if(size < 6) - return FALSE; - - if((b[0] == '<' - && (b[1] == 'h' || b[1] == 'H') - && (b[2] == 't' || b[2] == 'T') - && (b[3] == 'm' || b[3] == 'M') - && (b[4] == 'l' || b[4] == 'L')) - || (b[0] == '<' - && (b[1] == 'h' || b[1] == 'H') - && (b[2] == 'e' || b[2] == 'E') - && (b[3] == 'a' || b[3] == 'A') - && (b[4] == 'd' || b[4] == 'D'))) return TRUE; - - return FALSE; -} - -static BOOL text_xml_filter(const BYTE *b, DWORD size) -{ - if(size < 7) - return FALSE; - - if(b[0] == '<' && b[1] == '?' - && (b[2] == 'x' || b[2] == 'X') - && (b[3] == 'm' || b[3] == 'M') - && (b[4] == 'l' || b[4] == 'L') - && b[5] == ' ') return TRUE; - - return FALSE; -} - -static BOOL audio_basic_filter(const BYTE *b, DWORD size) -{ - return size > 4 - && b[0] == '.' && b[1] == 's' && b[2] == 'n' && b[3] == 'd'; -} - -static BOOL audio_wav_filter(const BYTE *b, DWORD size) -{ - return size > 12 - && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F' - && b[8] == 'W' && b[9] == 'A' && b[10] == 'V' && b[11] == 'E'; -} - -static BOOL image_gif_filter(const BYTE *b, DWORD size) -{ - return size >= 6 - && (b[0] == 'G' || b[0] == 'g') - && (b[1] == 'I' || b[1] == 'i') - && (b[2] == 'F' || b[2] == 'f') - && b[3] == '8' - && (b[4] == '7' || b[4] == '9') - && (b[5] == 'A' || b[5] == 'a'); -} - -static BOOL image_pjpeg_filter(const BYTE *b, DWORD size) -{ - return size > 2 && b[0] == 0xff && b[1] == 0xd8; -} - -static BOOL image_tiff_filter(const BYTE *b, DWORD size) -{ - static const BYTE magic1[] = {0x4d,0x4d,0x00,0x2a}; - static const BYTE magic2[] = {0x49,0x49,0x2a,0xff}; - - return size >= 4 && (!memcmp(b, magic1, 4) || !memcmp(b, magic2, 4)); -} - -static BOOL image_xpng_filter(const BYTE *b, DWORD size) -{ - static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a}; - return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header)); -} - -static BOOL image_bmp_filter(const BYTE *b, DWORD size) -{ - return size >= 14 - && b[0] == 0x42 && b[1] == 0x4d - && *(const DWORD *)(b+6) == 0; -} - -static BOOL video_avi_filter(const BYTE *b, DWORD size) -{ - return size > 12 - && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F' - && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20; -} - -static BOOL video_mpeg_filter(const BYTE *b, DWORD size) -{ - return size > 4 - && !b[0] && !b[1] && b[2] == 0x01 - && (b[3] == 0xb3 || b[3] == 0xba); -} - -static BOOL application_postscript_filter(const BYTE *b, DWORD size) -{ - return size > 2 && b[0] == '%' && b[1] == '!'; -} - -static BOOL application_pdf_filter(const BYTE *b, DWORD size) -{ - return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46; -} - -static BOOL application_xzip_filter(const BYTE *b, DWORD size) -{ - return size > 2 && b[0] == 0x50 && b[1] == 0x4b; -} - -static BOOL application_xgzip_filter(const BYTE *b, DWORD size) -{ - return size > 2 && b[0] == 0x1f && b[1] == 0x8b; -} - -static BOOL application_java_filter(const BYTE *b, DWORD size) -{ - return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe; -} - -static BOOL application_xmsdownload(const BYTE *b, DWORD size) -{ - return size > 2 && b[0] == 'M' && b[1] == 'Z'; -} - -static inline BOOL is_text_plain_char(BYTE b) -{ - if(b < 0x20 && b != '\n' && b != '\r' && b != '\t') - return FALSE; - return TRUE; -} - -static BOOL text_plain_filter(const BYTE *b, DWORD size) -{ - const BYTE *ptr; - - for(ptr = b; ptr < b+size-1; ptr++) { - if(!is_text_plain_char(*ptr)) - return FALSE; - } - - return TRUE; -} - -static BOOL application_octet_stream_filter(const BYTE *b, DWORD size) -{ - return TRUE; -} - -static HRESULT find_mime_from_buffer(const BYTE *buf, DWORD size, const WCHAR *proposed_mime, WCHAR **ret_mime) -{ - LPCWSTR ret = NULL; - int len, i, any_pos_mime = -1; - - static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0}; - static const WCHAR text_richtextW[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0}; - static const WCHAR text_xmlW[] = {'t','e','x','t','/','x','m','l',0}; - static const WCHAR audio_basicW[] = {'a','u','d','i','o','/','b','a','s','i','c',0}; - static const WCHAR audio_wavW[] = {'a','u','d','i','o','/','w','a','v',0}; - static const WCHAR image_gifW[] = {'i','m','a','g','e','/','g','i','f',0}; - static const WCHAR image_pjpegW[] = {'i','m','a','g','e','/','p','j','p','e','g',0}; - static const WCHAR image_tiffW[] = {'i','m','a','g','e','/','t','i','f','f',0}; - static const WCHAR image_xpngW[] = {'i','m','a','g','e','/','x','-','p','n','g',0}; - static const WCHAR image_bmpW[] = {'i','m','a','g','e','/','b','m','p',0}; - static const WCHAR video_aviW[] = {'v','i','d','e','o','/','a','v','i',0}; - static const WCHAR video_mpegW[] = {'v','i','d','e','o','/','m','p','e','g',0}; - static const WCHAR app_postscriptW[] = - {'a','p','p','l','i','c','a','t','i','o','n','/','p','o','s','t','s','c','r','i','p','t',0}; - static const WCHAR app_pdfW[] = {'a','p','p','l','i','c','a','t','i','o','n','/','p','d','f',0}; - static const WCHAR app_xzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/', - 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0}; - static const WCHAR app_xgzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/', - 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0}; - static const WCHAR app_javaW[] = {'a','p','p','l','i','c','a','t','i','o','n','/', - 'j','a','v','a',0}; - static const WCHAR app_xmsdownloadW[] = {'a','p','p','l','i','c','a','t','i','o','n','/', - 'x','-','m','s','d','o','w','n','l','o','a','d',0}; - static const WCHAR text_plainW[] = {'t','e','x','t','/','p','l','a','i','n','\0'}; - static const WCHAR app_octetstreamW[] = {'a','p','p','l','i','c','a','t','i','o','n','/', - 'o','c','t','e','t','-','s','t','r','e','a','m','\0'}; - - static const struct { - LPCWSTR mime; - BOOL (*filter)(const BYTE *,DWORD); - } mime_filters_any_pos[] = { - {text_htmlW, text_html_filter}, - {text_xmlW, text_xml_filter} - }, mime_filters[] = { - {text_richtextW, text_richtext_filter}, - /* {audio_xaiffW, audio_xaiff_filter}, */ - {audio_basicW, audio_basic_filter}, - {audio_wavW, audio_wav_filter}, - {image_gifW, image_gif_filter}, - {image_pjpegW, image_pjpeg_filter}, - {image_tiffW, image_tiff_filter}, - {image_xpngW, image_xpng_filter}, - /* {image_xbitmapW, image_xbitmap_filter}, */ - {image_bmpW, image_bmp_filter}, - /* {image_xjgW, image_xjg_filter}, */ - /* {image_xemfW, image_xemf_filter}, */ - /* {image_xwmfW, image_xwmf_filter}, */ - {video_aviW, video_avi_filter}, - {video_mpegW, video_mpeg_filter}, - {app_postscriptW, application_postscript_filter}, - /* {app_base64W, application_base64_filter}, */ - /* {app_macbinhex40W, application_macbinhex40_filter}, */ - {app_pdfW, application_pdf_filter}, - /* {app_zcompressedW, application_xcompressed_filter}, */ - {app_xzipW, application_xzip_filter}, - {app_xgzipW, application_xgzip_filter}, - {app_javaW, application_java_filter}, - {app_xmsdownloadW, application_xmsdownload}, - {text_plainW, text_plain_filter}, - {app_octetstreamW, application_octet_stream_filter} - }; - - if(!buf || !size) { - if(!proposed_mime) - return E_FAIL; - - len = strlenW(proposed_mime)+1; - *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR)); - if(!*ret_mime) - return E_OUTOFMEMORY; - - memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR)); - return S_OK; - } - - if(proposed_mime && (!strcmpW(proposed_mime, app_octetstreamW) - || !strcmpW(proposed_mime, text_plainW))) - proposed_mime = NULL; - - if(proposed_mime) { - ret = proposed_mime; - - for(i=0; i < sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) { - if(!strcmpW(proposed_mime, mime_filters_any_pos[i].mime)) { - any_pos_mime = i; - for(len=size; len>0; len--) { - if(mime_filters_any_pos[i].filter(buf+size-len, len)) - break; - } - if(!len) - ret = NULL; - break; - } - } - - if(i == sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos)) { - for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) { - if(!strcmpW(proposed_mime, mime_filters[i].mime)) { - if(!mime_filters[i].filter(buf, size)) - ret = NULL; - break; - } - } - } - } - - /* Looks like a bug in native implementation, html and xml mimes - * are not looked for if none of them was proposed */ - if(!proposed_mime || any_pos_mime!=-1) { - for(len=size; !ret && len>0; len--) { - for(i=0; i0; len--) { - if(!is_text_plain_char(buf[size-len])) - break; - for(i=0; i