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);
549 SIZE_T size = GlobalSize(src->u.hGlobal);
550 char *src_ptr, *dst_ptr;
552 dst->u.hGlobal = GlobalAlloc(GMEM_FIXED, size);
554 return E_OUTOFMEMORY;
555 dst_ptr = GlobalLock(dst->u.hGlobal);
556 src_ptr = GlobalLock(src->u.hGlobal);
557 memcpy(dst_ptr, src_ptr, size);
558 GlobalUnlock(src_ptr);
559 GlobalUnlock(dst_ptr);
563 FIXME("Unimplemented tymed %d\n", src->tymed);
566 if(dst->pUnkForRelease)
567 IUnknown_AddRef(dst->pUnkForRelease);
572 /***********************************************************************
573 * CopyBindInfo (URLMON.@)
575 HRESULT WINAPI CopyBindInfo(const BINDINFO *pcbiSrc, BINDINFO *pcbiDest)
580 TRACE("(%p %p)\n", pcbiSrc, pcbiDest);
582 if(!pcbiSrc || !pcbiDest)
584 if(!pcbiSrc->cbSize || !pcbiDest->cbSize)
587 size = pcbiDest->cbSize;
588 if(size > pcbiSrc->cbSize) {
589 memcpy(pcbiDest, pcbiSrc, pcbiSrc->cbSize);
590 memset((char*)pcbiDest+pcbiSrc->cbSize, 0, size-pcbiSrc->cbSize);
592 memcpy(pcbiDest, pcbiSrc, size);
594 pcbiDest->cbSize = size;
596 size = FIELD_OFFSET(BINDINFO, szExtraInfo)+sizeof(void*);
597 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size && pcbiSrc->szExtraInfo) {
598 size = (strlenW(pcbiSrc->szExtraInfo)+1)*sizeof(WCHAR);
599 pcbiDest->szExtraInfo = CoTaskMemAlloc(size);
600 if(!pcbiDest->szExtraInfo)
601 return E_OUTOFMEMORY;
602 memcpy(pcbiDest->szExtraInfo, pcbiSrc->szExtraInfo, size);
605 size = FIELD_OFFSET(BINDINFO, stgmedData)+sizeof(STGMEDIUM);
606 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size) {
607 hres = CopyStgMedium(&pcbiSrc->stgmedData, &pcbiDest->stgmedData);
609 CoTaskMemFree(pcbiDest->szExtraInfo);
614 size = FIELD_OFFSET(BINDINFO, szCustomVerb)+sizeof(void*);
615 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size && pcbiSrc->szCustomVerb) {
616 size = (strlenW(pcbiSrc->szCustomVerb)+1)*sizeof(WCHAR);
617 pcbiDest->szCustomVerb = CoTaskMemAlloc(size);
618 if(!pcbiDest->szCustomVerb) {
619 CoTaskMemFree(pcbiDest->szExtraInfo);
620 ReleaseStgMedium(&pcbiDest->stgmedData);
621 return E_OUTOFMEMORY;
623 memcpy(pcbiDest->szCustomVerb, pcbiSrc->szCustomVerb, size);
626 size = FIELD_OFFSET(BINDINFO, securityAttributes)+sizeof(SECURITY_ATTRIBUTES);
627 if(pcbiDest->cbSize >= size)
628 memset(&pcbiDest->securityAttributes, 0, sizeof(SECURITY_ATTRIBUTES));
631 IUnknown_AddRef(pcbiDest->pUnk);
636 static BOOL text_richtext_filter(const BYTE *b, DWORD size)
638 return size > 5 && !memcmp(b, "{\\rtf", 5);
641 static BOOL text_html_filter(const BYTE *b, DWORD size)
647 && (b[1] == 'h' || b[1] == 'H')
648 && (b[2] == 't' || b[2] == 'T')
649 && (b[3] == 'm' || b[3] == 'M')
650 && (b[4] == 'l' || b[4] == 'L'))
652 && (b[1] == 'h' || b[1] == 'H')
653 && (b[2] == 'e' || b[2] == 'E')
654 && (b[3] == 'a' || b[3] == 'A')
655 && (b[4] == 'd' || b[4] == 'D'))) return TRUE;
660 static BOOL text_xml_filter(const BYTE *b, DWORD size)
665 if(b[0] == '<' && b[1] == '?'
666 && (b[2] == 'x' || b[2] == 'X')
667 && (b[3] == 'm' || b[3] == 'M')
668 && (b[4] == 'l' || b[4] == 'L')
669 && b[5] == ' ') return TRUE;
674 static BOOL audio_basic_filter(const BYTE *b, DWORD size)
677 && b[0] == '.' && b[1] == 's' && b[2] == 'n' && b[3] == 'd';
680 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
683 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
684 && b[8] == 'W' && b[9] == 'A' && b[10] == 'V' && b[11] == 'E';
687 static BOOL image_gif_filter(const BYTE *b, DWORD size)
690 && (b[0] == 'G' || b[0] == 'g')
691 && (b[1] == 'I' || b[1] == 'i')
692 && (b[2] == 'F' || b[2] == 'f')
694 && (b[4] == '7' || b[4] == '9')
695 && (b[5] == 'A' || b[5] == 'a');
698 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
700 return size > 2 && b[0] == 0xff && b[1] == 0xd8;
703 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
705 static const BYTE magic1[] = {0x4d,0x4d,0x00,0x2a};
706 static const BYTE magic2[] = {0x49,0x49,0x2a,0xff};
708 return size >= 4 && (!memcmp(b, magic1, 4) || !memcmp(b, magic2, 4));
711 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
713 static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
714 return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header));
717 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
720 && b[0] == 0x42 && b[1] == 0x4d
721 && *(const DWORD *)(b+6) == 0;
724 static BOOL video_avi_filter(const BYTE *b, DWORD size)
727 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
728 && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20;
731 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
734 && !b[0] && !b[1] && b[2] == 0x01
735 && (b[3] == 0xb3 || b[3] == 0xba);
738 static BOOL application_postscript_filter(const BYTE *b, DWORD size)
740 return size > 2 && b[0] == '%' && b[1] == '!';
743 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
745 return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
748 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
750 return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
753 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
755 return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
758 static BOOL application_java_filter(const BYTE *b, DWORD size)
760 return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
763 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
765 return size > 2 && b[0] == 'M' && b[1] == 'Z';
768 static inline BOOL is_text_plain_char(BYTE b)
770 if(b < 0x20 && b != '\n' && b != '\r' && b != '\t')
775 static BOOL text_plain_filter(const BYTE *b, DWORD size)
779 for(ptr = b; ptr < b+size-1; ptr++) {
780 if(!is_text_plain_char(*ptr))
787 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
792 static HRESULT find_mime_from_buffer(const BYTE *buf, DWORD size, const WCHAR *proposed_mime, WCHAR **ret_mime)
795 int len, i, any_pos_mime = -1;
797 static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0};
798 static const WCHAR text_richtextW[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0};
799 static const WCHAR text_xmlW[] = {'t','e','x','t','/','x','m','l',0};
800 static const WCHAR audio_basicW[] = {'a','u','d','i','o','/','b','a','s','i','c',0};
801 static const WCHAR audio_wavW[] = {'a','u','d','i','o','/','w','a','v',0};
802 static const WCHAR image_gifW[] = {'i','m','a','g','e','/','g','i','f',0};
803 static const WCHAR image_pjpegW[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
804 static const WCHAR image_tiffW[] = {'i','m','a','g','e','/','t','i','f','f',0};
805 static const WCHAR image_xpngW[] = {'i','m','a','g','e','/','x','-','p','n','g',0};
806 static const WCHAR image_bmpW[] = {'i','m','a','g','e','/','b','m','p',0};
807 static const WCHAR video_aviW[] = {'v','i','d','e','o','/','a','v','i',0};
808 static const WCHAR video_mpegW[] = {'v','i','d','e','o','/','m','p','e','g',0};
809 static const WCHAR app_postscriptW[] =
810 {'a','p','p','l','i','c','a','t','i','o','n','/','p','o','s','t','s','c','r','i','p','t',0};
811 static const WCHAR app_pdfW[] = {'a','p','p','l','i','c','a','t','i','o','n','/','p','d','f',0};
812 static const WCHAR app_xzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
813 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
814 static const WCHAR app_xgzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
815 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
816 static const WCHAR app_javaW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
818 static const WCHAR app_xmsdownloadW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
819 'x','-','m','s','d','o','w','n','l','o','a','d',0};
820 static const WCHAR text_plainW[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
821 static const WCHAR app_octetstreamW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
822 'o','c','t','e','t','-','s','t','r','e','a','m','\0'};
824 static const struct {
826 BOOL (*filter)(const BYTE *,DWORD);
827 } mime_filters_any_pos[] = {
828 {text_htmlW, text_html_filter},
829 {text_xmlW, text_xml_filter}
830 }, mime_filters[] = {
831 {text_richtextW, text_richtext_filter},
832 /* {audio_xaiffW, audio_xaiff_filter}, */
833 {audio_basicW, audio_basic_filter},
834 {audio_wavW, audio_wav_filter},
835 {image_gifW, image_gif_filter},
836 {image_pjpegW, image_pjpeg_filter},
837 {image_tiffW, image_tiff_filter},
838 {image_xpngW, image_xpng_filter},
839 /* {image_xbitmapW, image_xbitmap_filter}, */
840 {image_bmpW, image_bmp_filter},
841 /* {image_xjgW, image_xjg_filter}, */
842 /* {image_xemfW, image_xemf_filter}, */
843 /* {image_xwmfW, image_xwmf_filter}, */
844 {video_aviW, video_avi_filter},
845 {video_mpegW, video_mpeg_filter},
846 {app_postscriptW, application_postscript_filter},
847 /* {app_base64W, application_base64_filter}, */
848 /* {app_macbinhex40W, application_macbinhex40_filter}, */
849 {app_pdfW, application_pdf_filter},
850 /* {app_zcompressedW, application_xcompressed_filter}, */
851 {app_xzipW, application_xzip_filter},
852 {app_xgzipW, application_xgzip_filter},
853 {app_javaW, application_java_filter},
854 {app_xmsdownloadW, application_xmsdownload},
855 {text_plainW, text_plain_filter},
856 {app_octetstreamW, application_octet_stream_filter}
863 len = strlenW(proposed_mime)+1;
864 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
866 return E_OUTOFMEMORY;
868 memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR));
872 if(proposed_mime && (!strcmpW(proposed_mime, app_octetstreamW)
873 || !strcmpW(proposed_mime, text_plainW)))
874 proposed_mime = NULL;
879 for(i=0; i < sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
880 if(!strcmpW(proposed_mime, mime_filters_any_pos[i].mime)) {
882 for(len=size; len>0; len--) {
883 if(mime_filters_any_pos[i].filter(buf+size-len, len))
892 if(i == sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos)) {
893 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
894 if(!strcmpW(proposed_mime, mime_filters[i].mime)) {
895 if(!mime_filters[i].filter(buf, size))
903 /* Looks like a bug in native implementation, html and xml mimes
904 * are not looked for if none of them was proposed */
905 if(!proposed_mime || any_pos_mime!=-1) {
906 for(len=size; !ret && len>0; len--) {
907 for(i=0; i<sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
908 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
909 ret = mime_filters_any_pos[i].mime;
918 if(mime_filters[i].filter(buf, size))
919 ret = mime_filters[i].mime;
923 if(any_pos_mime!=-1 && ret==text_plainW)
924 ret = mime_filters_any_pos[any_pos_mime].mime;
925 else if(proposed_mime && ret==app_octetstreamW) {
926 for(len=size; ret==app_octetstreamW && len>0; len--) {
927 if(!is_text_plain_char(buf[size-len]))
929 for(i=0; i<sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
930 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
937 if(ret == app_octetstreamW)
940 TRACE("found %s for %s\n", debugstr_w(ret), debugstr_an((const char*)buf, min(32, size)));
942 len = strlenW(ret)+1;
943 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
945 return E_OUTOFMEMORY;
947 memcpy(*ret_mime, ret, len*sizeof(WCHAR));
951 /***********************************************************************
952 * FindMimeFromData (URLMON.@)
954 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
956 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
957 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
958 LPWSTR* ppwzMimeOut, DWORD dwReserved)
960 TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
961 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
964 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
966 WARN("dwReserved=%d\n", dwReserved);
968 /* pBC seams to not be used */
970 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
973 if(pwzMimeProposed || pBuffer)
974 return find_mime_from_buffer(pBuffer, cbSize, pwzMimeProposed, ppwzMimeOut);
982 static const WCHAR wszContentType[] =
983 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
985 ptr = strrchrW(pwzUrl, '.');
989 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
990 if(res != ERROR_SUCCESS)
991 return HRESULT_FROM_WIN32(res);
994 res = RegQueryValueExW(hkey, wszContentType, NULL, NULL, (LPBYTE)mime, &size);
996 if(res != ERROR_SUCCESS)
997 return HRESULT_FROM_WIN32(res);
999 *ppwzMimeOut = CoTaskMemAlloc(size);
1000 memcpy(*ppwzMimeOut, mime, size);
1007 /***********************************************************************
1008 * GetClassFileOrMime (URLMON.@)
1010 * Determines the class ID from the bind context, file name or MIME type.
1012 HRESULT WINAPI GetClassFileOrMime(LPBC pBC, LPCWSTR pszFilename,
1013 LPVOID pBuffer, DWORD cbBuffer, LPCWSTR pszMimeType, DWORD dwReserved,
1016 FIXME("(%p, %s, %p, %d, %s, 0x%08x, %p): stub\n", pBC, debugstr_w(pszFilename), pBuffer,
1017 cbBuffer, debugstr_w(pszMimeType), dwReserved, pclsid);
1021 /***********************************************************************
1022 * Extract (URLMON.@)
1024 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
1026 HRESULT (WINAPI *pExtract)(void *, LPCSTR);
1029 hCabinet = LoadLibraryA("cabinet.dll");
1031 if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
1032 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
1033 if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());
1035 return pExtract(dest, szCabName);
1038 /***********************************************************************
1039 * IsLoggingEnabledA (URLMON.@)
1041 BOOL WINAPI IsLoggingEnabledA(LPCSTR url)
1043 FIXME("(%s)\n", debugstr_a(url));
1047 /***********************************************************************
1048 * IsLoggingEnabledW (URLMON.@)
1050 BOOL WINAPI IsLoggingEnabledW(LPCWSTR url)
1052 FIXME("(%s)\n", debugstr_w(url));
1056 /***********************************************************************
1057 * IsProtectedModeURL (URLMON.111)
1058 * Undocumented, added in IE7
1060 BOOL WINAPI IsProtectedModeURL(const WCHAR *url)
1062 FIXME("stub: %s\n", debugstr_w(url));
1066 /***********************************************************************
1067 * LogSqmBits (URLMON.410)
1068 * Undocumented, added in IE8
1070 int WINAPI LogSqmBits(DWORD unk1, DWORD unk2)
1072 FIXME("stub: %d %d\n", unk1, unk2);
1076 /***********************************************************************
1077 * LogSqmUXCommandOffsetInternal (URLMON.423)
1078 * Undocumented, added in IE8
1080 void WINAPI LogSqmUXCommandOffsetInternal(DWORD unk1, DWORD unk2, DWORD unk3, DWORD unk4)
1082 FIXME("stub: %d %d %d %d\n", unk1, unk2, unk3, unk4);
1085 /***********************************************************************
1086 * MapUriToBrowserEmulationState (URLMON.444)
1087 * Undocumented, added in IE8
1089 int WINAPI MapUriToBrowserEmulationState(DWORD unk1, DWORD unk2, DWORD unk3)
1091 FIXME("stub: %d %d %d\n", unk1, unk2, unk3);
1095 /***********************************************************************
1096 * MapBrowserEmulationModeToUserAgent (URLMON.445)
1097 * Undocumented, added in IE8
1099 int WINAPI MapBrowserEmulationModeToUserAgent(DWORD unk1, DWORD unk2)
1101 FIXME("stub: %d %d\n", unk1, unk2);
1105 /***********************************************************************
1106 * RegisterMediaTypes
1107 * Added in IE3, registers known MIME-type strings.
1109 HRESULT WINAPI RegisterMediaTypes(UINT types, LPCSTR *szTypes, CLIPFORMAT *cfTypes)
1111 FIXME("stub: %u %p %p\n", types, szTypes, cfTypes);
1112 return E_INVALIDARG;