4 * Copyright (c) 2000 Patrik Stridvall
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "urlmon_main.h"
27 #define NO_SHLWAPI_REG
32 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
38 DEFINE_GUID(CLSID_CUri, 0xDF2FCE13, 0x25EC, 0x45BB, 0x9D,0x4C, 0xCE,0xCD,0x47,0xC2,0x43,0x0C);
40 LONG URLMON_refCount = 0;
42 static HMODULE hCabinet = NULL;
43 static DWORD urlmon_tls = TLS_OUT_OF_INDEXES;
45 static void init_session(void);
47 static struct list tls_list = LIST_INIT(tls_list);
49 static CRITICAL_SECTION tls_cs;
50 static CRITICAL_SECTION_DEBUG tls_cs_dbg =
53 { &tls_cs_dbg.ProcessLocksList, &tls_cs_dbg.ProcessLocksList },
54 0, 0, { (DWORD_PTR)(__FILE__ ": tls") }
57 static CRITICAL_SECTION tls_cs = { &tls_cs_dbg, -1, 0, 0, 0, 0 };
59 tls_data_t *get_tls_data(void)
63 if(urlmon_tls == TLS_OUT_OF_INDEXES) {
64 DWORD tls = TlsAlloc();
65 if(tls == TLS_OUT_OF_INDEXES)
68 tls = InterlockedCompareExchange((LONG*)&urlmon_tls, tls, TLS_OUT_OF_INDEXES);
73 data = TlsGetValue(urlmon_tls);
75 data = heap_alloc_zero(sizeof(tls_data_t));
79 EnterCriticalSection(&tls_cs);
80 list_add_tail(&tls_list, &data->entry);
81 LeaveCriticalSection(&tls_cs);
83 TlsSetValue(urlmon_tls, data);
89 static void free_tls_list(void)
93 if(urlmon_tls == TLS_OUT_OF_INDEXES)
96 while(!list_empty(&tls_list)) {
97 data = LIST_ENTRY(list_head(&tls_list), tls_data_t, entry);
98 list_remove(&data->entry);
105 static void detach_thread(void)
109 if(urlmon_tls == TLS_OUT_OF_INDEXES)
112 data = TlsGetValue(urlmon_tls);
116 EnterCriticalSection(&tls_cs);
117 list_remove(&data->entry);
118 LeaveCriticalSection(&tls_cs);
120 if(data->notif_hwnd) {
121 WARN("notif_hwnd not destroyed\n");
122 DestroyWindow(data->notif_hwnd);
128 static void process_detach(void)
130 HINTERNET internet_session;
132 internet_session = get_internet_session(NULL);
134 InternetCloseHandle(internet_session);
137 FreeLibrary(hCabinet);
143 /***********************************************************************
144 * DllMain (URLMON.init)
146 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
148 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
150 URLMON_DllMain( hinstDLL, fdwReason, fImpLoad );
153 case DLL_PROCESS_ATTACH:
157 case DLL_PROCESS_DETACH:
159 DeleteCriticalSection(&tls_cs);
162 case DLL_THREAD_DETACH:
170 /***********************************************************************
171 * DllInstall (URLMON.@)
173 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
175 FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
176 debugstr_w(cmdline));
181 /***********************************************************************
182 * DllCanUnloadNow (URLMON.@)
184 HRESULT WINAPI DllCanUnloadNow(void)
186 return URLMON_refCount != 0 ? S_FALSE : S_OK;
191 /******************************************************************************
192 * Urlmon ClassFactory
195 IClassFactory IClassFactory_iface;
197 HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
200 static inline ClassFactory *impl_from_IClassFactory(IClassFactory *iface)
202 return CONTAINING_RECORD(iface, ClassFactory, IClassFactory_iface);
205 static HRESULT WINAPI CF_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppv)
209 if(IsEqualGUID(riid, &IID_IUnknown)) {
210 TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
212 }else if(IsEqualGUID(riid, &IID_IClassFactory)) {
213 TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv);
218 IUnknown_AddRef((IUnknown*)*ppv);
222 WARN("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ppv);
223 return E_NOINTERFACE;
226 static ULONG WINAPI CF_AddRef(IClassFactory *iface)
232 static ULONG WINAPI CF_Release(IClassFactory *iface)
234 URLMON_UnlockModule();
239 static HRESULT WINAPI CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
240 REFIID riid, LPVOID *ppobj)
242 ClassFactory *This = impl_from_IClassFactory(iface);
246 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
249 if(SUCCEEDED(hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk))) {
250 hres = IUnknown_QueryInterface(punk, riid, ppobj);
251 IUnknown_Release(punk);
256 static HRESULT WINAPI CF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
258 TRACE("(%d)\n", dolock);
263 URLMON_UnlockModule();
268 static const IClassFactoryVtbl ClassFactoryVtbl =
277 static ClassFactory FileProtocolCF =
278 { { &ClassFactoryVtbl }, FileProtocol_Construct};
279 static ClassFactory FtpProtocolCF =
280 { { &ClassFactoryVtbl }, FtpProtocol_Construct};
281 static ClassFactory GopherProtocolCF =
282 { { &ClassFactoryVtbl }, GopherProtocol_Construct};
283 static ClassFactory HttpProtocolCF =
284 { { &ClassFactoryVtbl }, HttpProtocol_Construct};
285 static ClassFactory HttpSProtocolCF =
286 { { &ClassFactoryVtbl }, HttpSProtocol_Construct};
287 static ClassFactory MkProtocolCF =
288 { { &ClassFactoryVtbl }, MkProtocol_Construct};
289 static ClassFactory SecurityManagerCF =
290 { { &ClassFactoryVtbl }, SecManagerImpl_Construct};
291 static ClassFactory ZoneManagerCF =
292 { { &ClassFactoryVtbl }, ZoneMgrImpl_Construct};
293 static ClassFactory StdURLMonikerCF =
294 { { &ClassFactoryVtbl }, StdURLMoniker_Construct};
295 static ClassFactory MimeFilterCF =
296 { { &ClassFactoryVtbl }, MimeFilter_Construct};
297 static ClassFactory CUriCF =
298 { { &ClassFactoryVtbl }, Uri_Construct};
300 struct object_creation_info
307 static const WCHAR wszFile[] = {'f','i','l','e',0};
308 static const WCHAR wszFtp[] = {'f','t','p',0};
309 static const WCHAR wszGopher[] = {'g','o','p','h','e','r',0};
310 static const WCHAR wszHttp[] = {'h','t','t','p',0};
311 static const WCHAR wszHttps[] = {'h','t','t','p','s',0};
312 static const WCHAR wszMk[] = {'m','k',0};
314 static const struct object_creation_info object_creation[] =
316 { &CLSID_FileProtocol, &FileProtocolCF.IClassFactory_iface, wszFile },
317 { &CLSID_FtpProtocol, &FtpProtocolCF.IClassFactory_iface, wszFtp },
318 { &CLSID_GopherProtocol, &GopherProtocolCF.IClassFactory_iface, wszGopher },
319 { &CLSID_HttpProtocol, &HttpProtocolCF.IClassFactory_iface, wszHttp },
320 { &CLSID_HttpSProtocol, &HttpSProtocolCF.IClassFactory_iface, wszHttps },
321 { &CLSID_MkProtocol, &MkProtocolCF.IClassFactory_iface, wszMk },
322 { &CLSID_InternetSecurityManager, &SecurityManagerCF.IClassFactory_iface, NULL },
323 { &CLSID_InternetZoneManager, &ZoneManagerCF.IClassFactory_iface, NULL },
324 { &CLSID_StdURLMoniker, &StdURLMonikerCF.IClassFactory_iface, NULL },
325 { &CLSID_DeCompMimeFilter, &MimeFilterCF.IClassFactory_iface, NULL },
326 { &CLSID_CUri, &CUriCF.IClassFactory_iface, NULL }
329 static void init_session(void)
333 for(i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) {
334 if(object_creation[i].protocol)
335 register_namespace(object_creation[i].cf, object_creation[i].clsid,
336 object_creation[i].protocol, TRUE);
340 /*******************************************************************************
341 * DllGetClassObject [URLMON.@]
342 * Retrieves class object from a DLL object
345 * Docs say returns STDAPI
348 * rclsid [I] CLSID for the class object
349 * riid [I] Reference to identifier of interface for class object
350 * ppv [O] Address of variable to receive interface pointer for riid
354 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
358 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
363 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
365 for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
367 if (IsEqualGUID(object_creation[i].clsid, rclsid))
368 return IClassFactory_QueryInterface(object_creation[i].cf, riid, ppv);
371 hr = URLMON_DllGetClassObject(rclsid, riid, ppv);
375 FIXME("%s: no class found.\n", debugstr_guid(rclsid));
376 return CLASS_E_CLASSNOTAVAILABLE;
379 static HRESULT register_inf(BOOL doregister)
381 HRESULT (WINAPI *pRegInstall)(HMODULE hm, LPCSTR pszSection, const STRTABLEA* pstTable);
384 static const WCHAR wszAdvpack[] = {'a','d','v','p','a','c','k','.','d','l','l',0};
386 hAdvpack = LoadLibraryW(wszAdvpack);
387 pRegInstall = (void *)GetProcAddress(hAdvpack, "RegInstall");
389 return pRegInstall(hProxyDll, doregister ? "RegisterDll" : "UnregisterDll", NULL);
392 /***********************************************************************
393 * DllRegisterServer (URLMON.@)
395 HRESULT WINAPI DllRegisterServer(void)
401 hr = URLMON_DllRegisterServer();
402 return SUCCEEDED(hr) ? register_inf(TRUE) : hr;
405 /***********************************************************************
406 * DllUnregisterServer (URLMON.@)
408 HRESULT WINAPI DllUnregisterServer(void)
414 hr = URLMON_DllUnregisterServer();
415 return SUCCEEDED(hr) ? register_inf(FALSE) : hr;
418 /***********************************************************************
419 * DllRegisterServerEx (URLMON.@)
421 HRESULT WINAPI DllRegisterServerEx(void)
423 FIXME("(void): stub\n");
428 /**************************************************************************
429 * IsValidURL (URLMON.@)
431 * Determines if a specified string is a valid URL.
434 * pBC [I] ignored, should be NULL.
435 * szURL [I] string that represents the URL in question.
436 * dwReserved [I] reserved and must be zero.
441 * returns E_INVALIDARG if one or more of the args is invalid.
444 * test functionality against windows to see what a valid URL is.
446 HRESULT WINAPI IsValidURL(LPBC pBC, LPCWSTR szURL, DWORD dwReserved)
448 FIXME("(%p, %s, %d): stub\n", pBC, debugstr_w(szURL), dwReserved);
450 if (dwReserved || !szURL)
456 /**************************************************************************
457 * FaultInIEFeature (URLMON.@)
459 * Undocumented. Appears to be used by native shdocvw.dll.
461 HRESULT WINAPI FaultInIEFeature( HWND hwnd, uCLSSPEC * pClassSpec,
462 QUERYCONTEXT *pQuery, DWORD flags )
464 FIXME("%p %p %p %08x\n", hwnd, pClassSpec, pQuery, flags);
468 /**************************************************************************
469 * CoGetClassObjectFromURL (URLMON.@)
471 HRESULT WINAPI CoGetClassObjectFromURL( REFCLSID rclsid, LPCWSTR szCodeURL, DWORD dwFileVersionMS,
472 DWORD dwFileVersionLS, LPCWSTR szContentType,
473 LPBINDCTX pBindCtx, DWORD dwClsContext, LPVOID pvReserved,
474 REFIID riid, LPVOID *ppv )
476 FIXME("(%s %s %d %d %s %p %d %p %s %p) Stub!\n", debugstr_guid(rclsid), debugstr_w(szCodeURL),
477 dwFileVersionMS, dwFileVersionLS, debugstr_w(szContentType), pBindCtx, dwClsContext, pvReserved,
478 debugstr_guid(riid), ppv);
479 return E_NOINTERFACE;
482 /***********************************************************************
483 * ReleaseBindInfo (URLMON.@)
485 * Release the resources used by the specified BINDINFO structure.
488 * pbindinfo [I] BINDINFO to release.
493 void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo)
497 TRACE("(%p)\n", pbindinfo);
499 if(!pbindinfo || !(size = pbindinfo->cbSize))
502 CoTaskMemFree(pbindinfo->szExtraInfo);
503 ReleaseStgMedium(&pbindinfo->stgmedData);
505 if(offsetof(BINDINFO, szExtraInfo) < size)
506 CoTaskMemFree(pbindinfo->szCustomVerb);
508 if(pbindinfo->pUnk && offsetof(BINDINFO, pUnk) < size)
509 IUnknown_Release(pbindinfo->pUnk);
511 memset(pbindinfo, 0, size);
512 pbindinfo->cbSize = size;
515 /***********************************************************************
516 * CopyStgMedium (URLMON.@)
518 HRESULT WINAPI CopyStgMedium(const STGMEDIUM *src, STGMEDIUM *dst)
520 TRACE("(%p %p)\n", src, dst);
531 if(src->u.lpszFileName && !src->pUnkForRelease) {
532 DWORD size = (strlenW(src->u.lpszFileName)+1)*sizeof(WCHAR);
533 dst->u.lpszFileName = CoTaskMemAlloc(size);
534 if(!dst->u.lpszFileName)
535 return E_OUTOFMEMORY;
536 memcpy(dst->u.lpszFileName, src->u.lpszFileName, size);
541 IStream_AddRef(dst->u.pstm);
545 IStorage_AddRef(dst->u.pstg);
548 FIXME("Unimplemented tymed %d\n", src->tymed);
551 if(dst->pUnkForRelease)
552 IUnknown_AddRef(dst->pUnkForRelease);
557 /***********************************************************************
558 * CopyBindInfo (URLMON.@)
560 HRESULT WINAPI CopyBindInfo(const BINDINFO *pcbiSrc, BINDINFO *pcbiDest)
565 TRACE("(%p %p)\n", pcbiSrc, pcbiDest);
567 if(!pcbiSrc || !pcbiDest)
569 if(!pcbiSrc->cbSize || !pcbiDest->cbSize)
572 size = pcbiDest->cbSize;
573 if(size > pcbiSrc->cbSize) {
574 memcpy(pcbiDest, pcbiSrc, pcbiSrc->cbSize);
575 memset((char*)pcbiDest+pcbiSrc->cbSize, 0, size-pcbiSrc->cbSize);
577 memcpy(pcbiDest, pcbiSrc, size);
579 pcbiDest->cbSize = size;
581 size = FIELD_OFFSET(BINDINFO, szExtraInfo)+sizeof(void*);
582 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size && pcbiSrc->szExtraInfo) {
583 size = (strlenW(pcbiSrc->szExtraInfo)+1)*sizeof(WCHAR);
584 pcbiDest->szExtraInfo = CoTaskMemAlloc(size);
585 if(!pcbiDest->szExtraInfo)
586 return E_OUTOFMEMORY;
587 memcpy(pcbiDest->szExtraInfo, pcbiSrc->szExtraInfo, size);
590 size = FIELD_OFFSET(BINDINFO, stgmedData)+sizeof(STGMEDIUM);
591 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size) {
592 hres = CopyStgMedium(&pcbiSrc->stgmedData, &pcbiDest->stgmedData);
594 CoTaskMemFree(pcbiDest->szExtraInfo);
599 size = FIELD_OFFSET(BINDINFO, szCustomVerb)+sizeof(void*);
600 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size && pcbiSrc->szCustomVerb) {
601 size = (strlenW(pcbiSrc->szCustomVerb)+1)*sizeof(WCHAR);
602 pcbiDest->szCustomVerb = CoTaskMemAlloc(size);
603 if(!pcbiDest->szCustomVerb) {
604 CoTaskMemFree(pcbiDest->szExtraInfo);
605 ReleaseStgMedium(&pcbiDest->stgmedData);
606 return E_OUTOFMEMORY;
608 memcpy(pcbiDest->szCustomVerb, pcbiSrc->szCustomVerb, size);
611 size = FIELD_OFFSET(BINDINFO, securityAttributes)+sizeof(SECURITY_ATTRIBUTES);
612 if(pcbiDest->cbSize >= size)
613 memset(&pcbiDest->securityAttributes, 0, sizeof(SECURITY_ATTRIBUTES));
616 IUnknown_AddRef(pcbiDest->pUnk);
621 static BOOL text_richtext_filter(const BYTE *b, DWORD size)
623 return size > 5 && !memcmp(b, "{\\rtf", 5);
626 static BOOL text_html_filter(const BYTE *b, DWORD size)
632 && (b[1] == 'h' || b[1] == 'H')
633 && (b[2] == 't' || b[2] == 'T')
634 && (b[3] == 'm' || b[3] == 'M')
635 && (b[4] == 'l' || b[4] == 'L'))
637 && (b[1] == 'h' || b[1] == 'H')
638 && (b[2] == 'e' || b[2] == 'E')
639 && (b[3] == 'a' || b[3] == 'A')
640 && (b[4] == 'd' || b[4] == 'D'))) return TRUE;
645 static BOOL text_xml_filter(const BYTE *b, DWORD size)
650 if(b[0] == '<' && b[1] == '?'
651 && (b[2] == 'x' || b[2] == 'X')
652 && (b[3] == 'm' || b[3] == 'M')
653 && (b[4] == 'l' || b[4] == 'L')
654 && b[5] == ' ') return TRUE;
659 static BOOL audio_basic_filter(const BYTE *b, DWORD size)
662 && b[0] == '.' && b[1] == 's' && b[2] == 'n' && b[3] == 'd';
665 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
668 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
669 && b[8] == 'W' && b[9] == 'A' && b[10] == 'V' && b[11] == 'E';
672 static BOOL image_gif_filter(const BYTE *b, DWORD size)
675 && (b[0] == 'G' || b[0] == 'g')
676 && (b[1] == 'I' || b[1] == 'i')
677 && (b[2] == 'F' || b[2] == 'f')
679 && (b[4] == '7' || b[4] == '9')
680 && (b[5] == 'A' || b[5] == 'a');
683 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
685 return size > 2 && b[0] == 0xff && b[1] == 0xd8;
688 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
690 static const BYTE magic1[] = {0x4d,0x4d,0x00,0x2a};
691 static const BYTE magic2[] = {0x49,0x49,0x2a,0xff};
693 return size >= 4 && (!memcmp(b, magic1, 4) || !memcmp(b, magic2, 4));
696 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
698 static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
699 return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header));
702 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
705 && b[0] == 0x42 && b[1] == 0x4d
706 && *(const DWORD *)(b+6) == 0;
709 static BOOL video_avi_filter(const BYTE *b, DWORD size)
712 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
713 && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20;
716 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
719 && !b[0] && !b[1] && b[2] == 0x01
720 && (b[3] == 0xb3 || b[3] == 0xba);
723 static BOOL application_postscript_filter(const BYTE *b, DWORD size)
725 return size > 2 && b[0] == '%' && b[1] == '!';
728 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
730 return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
733 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
735 return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
738 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
740 return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
743 static BOOL application_java_filter(const BYTE *b, DWORD size)
745 return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
748 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
750 return size > 2 && b[0] == 'M' && b[1] == 'Z';
753 static inline BOOL is_text_plain_char(BYTE b)
755 if(b < 0x20 && b != '\n' && b != '\r' && b != '\t')
760 static BOOL text_plain_filter(const BYTE *b, DWORD size)
764 for(ptr = b; ptr < b+size-1; ptr++) {
765 if(!is_text_plain_char(*ptr))
772 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
777 static HRESULT find_mime_from_buffer(const BYTE *buf, DWORD size, const WCHAR *proposed_mime, WCHAR **ret_mime)
780 int len, i, any_pos_mime = -1;
782 static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0};
783 static const WCHAR text_richtextW[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0};
784 static const WCHAR text_xmlW[] = {'t','e','x','t','/','x','m','l',0};
785 static const WCHAR audio_basicW[] = {'a','u','d','i','o','/','b','a','s','i','c',0};
786 static const WCHAR audio_wavW[] = {'a','u','d','i','o','/','w','a','v',0};
787 static const WCHAR image_gifW[] = {'i','m','a','g','e','/','g','i','f',0};
788 static const WCHAR image_pjpegW[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
789 static const WCHAR image_tiffW[] = {'i','m','a','g','e','/','t','i','f','f',0};
790 static const WCHAR image_xpngW[] = {'i','m','a','g','e','/','x','-','p','n','g',0};
791 static const WCHAR image_bmpW[] = {'i','m','a','g','e','/','b','m','p',0};
792 static const WCHAR video_aviW[] = {'v','i','d','e','o','/','a','v','i',0};
793 static const WCHAR video_mpegW[] = {'v','i','d','e','o','/','m','p','e','g',0};
794 static const WCHAR app_postscriptW[] =
795 {'a','p','p','l','i','c','a','t','i','o','n','/','p','o','s','t','s','c','r','i','p','t',0};
796 static const WCHAR app_pdfW[] = {'a','p','p','l','i','c','a','t','i','o','n','/','p','d','f',0};
797 static const WCHAR app_xzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
798 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
799 static const WCHAR app_xgzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
800 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
801 static const WCHAR app_javaW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
803 static const WCHAR app_xmsdownloadW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
804 'x','-','m','s','d','o','w','n','l','o','a','d',0};
805 static const WCHAR text_plainW[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
806 static const WCHAR app_octetstreamW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
807 'o','c','t','e','t','-','s','t','r','e','a','m','\0'};
809 static const struct {
811 BOOL (*filter)(const BYTE *,DWORD);
812 } mime_filters_any_pos[] = {
813 {text_htmlW, text_html_filter},
814 {text_xmlW, text_xml_filter}
815 }, mime_filters[] = {
816 {text_richtextW, text_richtext_filter},
817 /* {audio_xaiffW, audio_xaiff_filter}, */
818 {audio_basicW, audio_basic_filter},
819 {audio_wavW, audio_wav_filter},
820 {image_gifW, image_gif_filter},
821 {image_pjpegW, image_pjpeg_filter},
822 {image_tiffW, image_tiff_filter},
823 {image_xpngW, image_xpng_filter},
824 /* {image_xbitmapW, image_xbitmap_filter}, */
825 {image_bmpW, image_bmp_filter},
826 /* {image_xjgW, image_xjg_filter}, */
827 /* {image_xemfW, image_xemf_filter}, */
828 /* {image_xwmfW, image_xwmf_filter}, */
829 {video_aviW, video_avi_filter},
830 {video_mpegW, video_mpeg_filter},
831 {app_postscriptW, application_postscript_filter},
832 /* {app_base64W, application_base64_filter}, */
833 /* {app_macbinhex40W, application_macbinhex40_filter}, */
834 {app_pdfW, application_pdf_filter},
835 /* {app_zcompressedW, application_xcompressed_filter}, */
836 {app_xzipW, application_xzip_filter},
837 {app_xgzipW, application_xgzip_filter},
838 {app_javaW, application_java_filter},
839 {app_xmsdownloadW, application_xmsdownload},
840 {text_plainW, text_plain_filter},
841 {app_octetstreamW, application_octet_stream_filter}
848 len = strlenW(proposed_mime)+1;
849 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
851 return E_OUTOFMEMORY;
853 memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR));
857 if(proposed_mime && (!strcmpW(proposed_mime, app_octetstreamW)
858 || !strcmpW(proposed_mime, text_plainW)))
859 proposed_mime = NULL;
864 for(i=0; i < sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
865 if(!strcmpW(proposed_mime, mime_filters_any_pos[i].mime)) {
867 for(len=size; len>0; len--) {
868 if(mime_filters_any_pos[i].filter(buf+size-len, len))
877 if(i == sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos)) {
878 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
879 if(!strcmpW(proposed_mime, mime_filters[i].mime)) {
880 if(!mime_filters[i].filter(buf, size))
888 /* Looks like a bug in native implementation, html and xml mimes
889 * are not looked for if none of them was proposed */
890 if(!proposed_mime || any_pos_mime!=-1) {
891 for(len=size; !ret && len>0; len--) {
892 for(i=0; i<sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
893 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
894 ret = mime_filters_any_pos[i].mime;
903 if(mime_filters[i].filter(buf, size))
904 ret = mime_filters[i].mime;
908 if(any_pos_mime!=-1 && ret==text_plainW)
909 ret = mime_filters_any_pos[any_pos_mime].mime;
910 else if(proposed_mime && ret==app_octetstreamW) {
911 for(len=size; ret==app_octetstreamW && len>0; len--) {
912 if(!is_text_plain_char(buf[size-len]))
914 for(i=0; i<sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
915 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
922 if(ret == app_octetstreamW)
925 TRACE("found %s for %s\n", debugstr_w(ret), debugstr_an((const char*)buf, min(32, size)));
927 len = strlenW(ret)+1;
928 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
930 return E_OUTOFMEMORY;
932 memcpy(*ret_mime, ret, len*sizeof(WCHAR));
936 /***********************************************************************
937 * FindMimeFromData (URLMON.@)
939 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
941 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
942 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
943 LPWSTR* ppwzMimeOut, DWORD dwReserved)
945 TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
946 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
949 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
951 WARN("dwReserved=%d\n", dwReserved);
953 /* pBC seams to not be used */
955 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
958 if(pwzMimeProposed || pBuffer)
959 return find_mime_from_buffer(pBuffer, cbSize, pwzMimeProposed, ppwzMimeOut);
967 static const WCHAR wszContentType[] =
968 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
970 ptr = strrchrW(pwzUrl, '.');
974 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
975 if(res != ERROR_SUCCESS)
976 return HRESULT_FROM_WIN32(res);
979 res = RegQueryValueExW(hkey, wszContentType, NULL, NULL, (LPBYTE)mime, &size);
981 if(res != ERROR_SUCCESS)
982 return HRESULT_FROM_WIN32(res);
984 *ppwzMimeOut = CoTaskMemAlloc(size);
985 memcpy(*ppwzMimeOut, mime, size);
992 /***********************************************************************
993 * GetClassFileOrMime (URLMON.@)
995 * Determines the class ID from the bind context, file name or MIME type.
997 HRESULT WINAPI GetClassFileOrMime(LPBC pBC, LPCWSTR pszFilename,
998 LPVOID pBuffer, DWORD cbBuffer, LPCWSTR pszMimeType, DWORD dwReserved,
1001 FIXME("(%p, %s, %p, %d, %s, 0x%08x, %p): stub\n", pBC, debugstr_w(pszFilename), pBuffer,
1002 cbBuffer, debugstr_w(pszMimeType), dwReserved, pclsid);
1006 /***********************************************************************
1007 * Extract (URLMON.@)
1009 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
1011 HRESULT (WINAPI *pExtract)(void *, LPCSTR);
1014 hCabinet = LoadLibraryA("cabinet.dll");
1016 if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
1017 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
1018 if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());
1020 return pExtract(dest, szCabName);
1023 /***********************************************************************
1024 * IsLoggingEnabledA (URLMON.@)
1026 BOOL WINAPI IsLoggingEnabledA(LPCSTR url)
1028 FIXME("(%s)\n", debugstr_a(url));
1032 /***********************************************************************
1033 * IsLoggingEnabledW (URLMON.@)
1035 BOOL WINAPI IsLoggingEnabledW(LPCWSTR url)
1037 FIXME("(%s)\n", debugstr_w(url));
1041 /***********************************************************************
1042 * IsProtectedModeURL (URLMON.111)
1043 * Undocumented, added in IE7
1045 BOOL WINAPI IsProtectedModeURL(const WCHAR *url)
1047 FIXME("stub: %s\n", debugstr_w(url));
1051 /***********************************************************************
1052 * LogSqmBits (URLMON.410)
1053 * Undocumented, added in IE8
1055 int WINAPI LogSqmBits(DWORD unk1, DWORD unk2)
1057 FIXME("stub: %d %d\n", unk1, unk2);
1061 /***********************************************************************
1062 * LogSqmUXCommandOffsetInternal (URLMON.423)
1063 * Undocumented, added in IE8
1065 void WINAPI LogSqmUXCommandOffsetInternal(DWORD unk1, DWORD unk2, DWORD unk3, DWORD unk4)
1067 FIXME("stub: %d %d %d %d\n", unk1, unk2, unk3, unk4);
1070 /***********************************************************************
1071 * MapUriToBrowserEmulationState (URLMON.444)
1072 * Undocumented, added in IE8
1074 int WINAPI MapUriToBrowserEmulationState(DWORD unk1, DWORD unk2, DWORD unk3)
1076 FIXME("stub: %d %d %d\n", unk1, unk2, unk3);
1080 /***********************************************************************
1081 * MapBrowserEmulationModeToUserAgent (URLMON.445)
1082 * Undocumented, added in IE8
1084 int WINAPI MapBrowserEmulationModeToUserAgent(DWORD unk1, DWORD unk2)
1086 FIXME("stub: %d %d\n", unk1, unk2);
1090 /***********************************************************************
1091 * RegisterMediaTypes
1092 * Added in IE3, registers known MIME-type strings.
1094 HRESULT WINAPI RegisterMediaTypes(UINT types, LPCSTR *szTypes, CLIPFORMAT *cfTypes)
1096 FIXME("stub: %u %p %p\n", types, szTypes, cfTypes);
1097 return E_INVALIDARG;