urlmon: Fixed misc.c tests on IE9 and make image_tiff_filter behave like IE9.
[wine/multimedia.git] / dlls / urlmon / urlmon_main.c
blob091112793e94d24068662a933d2fb6c82edc5d8a
1 /*
2 * UrlMon
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
21 #include <stdarg.h>
23 #include "urlmon_main.h"
25 #include "winreg.h"
27 #define NO_SHLWAPI_REG
28 #include "shlwapi.h"
29 #include "advpub.h"
31 #include "wine/debug.h"
33 #include "urlmon.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
37 LONG URLMON_refCount = 0;
39 static HMODULE hCabinet = NULL;
40 static DWORD urlmon_tls = TLS_OUT_OF_INDEXES;
42 static void init_session(BOOL);
44 static struct list tls_list = LIST_INIT(tls_list);
46 static CRITICAL_SECTION tls_cs;
47 static CRITICAL_SECTION_DEBUG tls_cs_dbg =
49 0, 0, &tls_cs,
50 { &tls_cs_dbg.ProcessLocksList, &tls_cs_dbg.ProcessLocksList },
51 0, 0, { (DWORD_PTR)(__FILE__ ": tls") }
54 static CRITICAL_SECTION tls_cs = { &tls_cs_dbg, -1, 0, 0, 0, 0 };
56 tls_data_t *get_tls_data(void)
58 tls_data_t *data;
60 if(urlmon_tls == TLS_OUT_OF_INDEXES) {
61 DWORD tls = TlsAlloc();
62 if(tls == TLS_OUT_OF_INDEXES)
63 return NULL;
65 tls = InterlockedCompareExchange((LONG*)&urlmon_tls, tls, TLS_OUT_OF_INDEXES);
66 if(tls != urlmon_tls)
67 TlsFree(tls);
70 data = TlsGetValue(urlmon_tls);
71 if(!data) {
72 data = heap_alloc_zero(sizeof(tls_data_t));
73 if(!data)
74 return NULL;
76 EnterCriticalSection(&tls_cs);
77 list_add_tail(&tls_list, &data->entry);
78 LeaveCriticalSection(&tls_cs);
80 TlsSetValue(urlmon_tls, data);
83 return data;
86 static void free_tls_list(void)
88 tls_data_t *data;
90 if(urlmon_tls == TLS_OUT_OF_INDEXES)
91 return;
93 while(!list_empty(&tls_list)) {
94 data = LIST_ENTRY(list_head(&tls_list), tls_data_t, entry);
95 list_remove(&data->entry);
96 heap_free(data);
99 TlsFree(urlmon_tls);
102 static void detach_thread(void)
104 tls_data_t *data;
106 if(urlmon_tls == TLS_OUT_OF_INDEXES)
107 return;
109 data = TlsGetValue(urlmon_tls);
110 if(!data)
111 return;
113 EnterCriticalSection(&tls_cs);
114 list_remove(&data->entry);
115 LeaveCriticalSection(&tls_cs);
117 if(data->notif_hwnd) {
118 WARN("notif_hwnd not destroyed\n");
119 DestroyWindow(data->notif_hwnd);
122 heap_free(data);
125 static void process_detach(void)
127 HINTERNET internet_session;
129 internet_session = get_internet_session(NULL);
130 if(internet_session)
131 InternetCloseHandle(internet_session);
133 if (hCabinet)
134 FreeLibrary(hCabinet);
136 init_session(FALSE);
137 free_session();
138 free_tls_list();
141 /***********************************************************************
142 * DllMain (URLMON.init)
144 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
146 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
148 URLMON_DllMain( hinstDLL, fdwReason, fImpLoad );
150 switch(fdwReason) {
151 case DLL_PROCESS_ATTACH:
152 init_session(TRUE);
153 break;
155 case DLL_PROCESS_DETACH:
156 process_detach();
157 break;
159 case DLL_THREAD_DETACH:
160 detach_thread();
161 break;
163 return TRUE;
167 /***********************************************************************
168 * DllInstall (URLMON.@)
170 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
172 FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
173 debugstr_w(cmdline));
175 return S_OK;
178 /***********************************************************************
179 * DllCanUnloadNow (URLMON.@)
181 HRESULT WINAPI DllCanUnloadNow(void)
183 return URLMON_refCount != 0 ? S_FALSE : S_OK;
188 /******************************************************************************
189 * Urlmon ClassFactory
191 typedef struct {
192 IClassFactory IClassFactory_iface;
194 HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
195 } ClassFactory;
197 static inline ClassFactory *impl_from_IClassFactory(IClassFactory *iface)
199 return CONTAINING_RECORD(iface, ClassFactory, IClassFactory_iface);
202 static HRESULT WINAPI CF_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppv)
204 *ppv = NULL;
206 if(IsEqualGUID(riid, &IID_IUnknown)) {
207 TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
208 *ppv = iface;
209 }else if(IsEqualGUID(riid, &IID_IClassFactory)) {
210 TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv);
211 *ppv = iface;
214 if(*ppv) {
215 IUnknown_AddRef((IUnknown*)*ppv);
216 return S_OK;
219 WARN("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ppv);
220 return E_NOINTERFACE;
223 static ULONG WINAPI CF_AddRef(IClassFactory *iface)
225 URLMON_LockModule();
226 return 2;
229 static ULONG WINAPI CF_Release(IClassFactory *iface)
231 URLMON_UnlockModule();
232 return 1;
236 static HRESULT WINAPI CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
237 REFIID riid, LPVOID *ppobj)
239 ClassFactory *This = impl_from_IClassFactory(iface);
240 HRESULT hres;
241 LPUNKNOWN punk;
243 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
245 *ppobj = NULL;
246 if(SUCCEEDED(hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk))) {
247 hres = IUnknown_QueryInterface(punk, riid, ppobj);
248 IUnknown_Release(punk);
250 return hres;
253 static HRESULT WINAPI CF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
255 TRACE("(%d)\n", dolock);
257 if (dolock)
258 URLMON_LockModule();
259 else
260 URLMON_UnlockModule();
262 return S_OK;
265 static const IClassFactoryVtbl ClassFactoryVtbl =
267 CF_QueryInterface,
268 CF_AddRef,
269 CF_Release,
270 CF_CreateInstance,
271 CF_LockServer
274 static ClassFactory FileProtocolCF =
275 { { &ClassFactoryVtbl }, FileProtocol_Construct};
276 static ClassFactory FtpProtocolCF =
277 { { &ClassFactoryVtbl }, FtpProtocol_Construct};
278 static ClassFactory GopherProtocolCF =
279 { { &ClassFactoryVtbl }, GopherProtocol_Construct};
280 static ClassFactory HttpProtocolCF =
281 { { &ClassFactoryVtbl }, HttpProtocol_Construct};
282 static ClassFactory HttpSProtocolCF =
283 { { &ClassFactoryVtbl }, HttpSProtocol_Construct};
284 static ClassFactory MkProtocolCF =
285 { { &ClassFactoryVtbl }, MkProtocol_Construct};
286 static ClassFactory SecurityManagerCF =
287 { { &ClassFactoryVtbl }, SecManagerImpl_Construct};
288 static ClassFactory ZoneManagerCF =
289 { { &ClassFactoryVtbl }, ZoneMgrImpl_Construct};
290 static ClassFactory StdURLMonikerCF =
291 { { &ClassFactoryVtbl }, StdURLMoniker_Construct};
292 static ClassFactory MimeFilterCF =
293 { { &ClassFactoryVtbl }, MimeFilter_Construct};
295 struct object_creation_info
297 const CLSID *clsid;
298 IClassFactory *cf;
299 LPCWSTR protocol;
302 static const WCHAR wszFile[] = {'f','i','l','e',0};
303 static const WCHAR wszFtp[] = {'f','t','p',0};
304 static const WCHAR wszGopher[] = {'g','o','p','h','e','r',0};
305 static const WCHAR wszHttp[] = {'h','t','t','p',0};
306 static const WCHAR wszHttps[] = {'h','t','t','p','s',0};
307 static const WCHAR wszMk[] = {'m','k',0};
309 static const struct object_creation_info object_creation[] =
311 { &CLSID_FileProtocol, &FileProtocolCF.IClassFactory_iface, wszFile },
312 { &CLSID_FtpProtocol, &FtpProtocolCF.IClassFactory_iface, wszFtp },
313 { &CLSID_GopherProtocol, &GopherProtocolCF.IClassFactory_iface, wszGopher },
314 { &CLSID_HttpProtocol, &HttpProtocolCF.IClassFactory_iface, wszHttp },
315 { &CLSID_HttpSProtocol, &HttpSProtocolCF.IClassFactory_iface, wszHttps },
316 { &CLSID_MkProtocol, &MkProtocolCF.IClassFactory_iface, wszMk },
317 { &CLSID_InternetSecurityManager, &SecurityManagerCF.IClassFactory_iface, NULL },
318 { &CLSID_InternetZoneManager, &ZoneManagerCF.IClassFactory_iface, NULL },
319 { &CLSID_StdURLMoniker, &StdURLMonikerCF.IClassFactory_iface, NULL },
320 { &CLSID_DeCompMimeFilter, &MimeFilterCF.IClassFactory_iface, NULL }
323 static void init_session(BOOL init)
325 unsigned int i;
327 for(i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) {
329 if(object_creation[i].protocol)
330 register_urlmon_namespace(object_creation[i].cf, object_creation[i].clsid,
331 object_creation[i].protocol, init);
335 /*******************************************************************************
336 * DllGetClassObject [URLMON.@]
337 * Retrieves class object from a DLL object
339 * NOTES
340 * Docs say returns STDAPI
342 * PARAMS
343 * rclsid [I] CLSID for the class object
344 * riid [I] Reference to identifier of interface for class object
345 * ppv [O] Address of variable to receive interface pointer for riid
347 * RETURNS
348 * Success: S_OK
349 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
350 * E_UNEXPECTED
353 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
355 unsigned int i;
356 HRESULT hr;
358 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
360 for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
362 if (IsEqualGUID(object_creation[i].clsid, rclsid))
363 return IClassFactory_QueryInterface(object_creation[i].cf, riid, ppv);
366 hr = URLMON_DllGetClassObject(rclsid, riid, ppv);
367 if(SUCCEEDED(hr))
368 return hr;
370 FIXME("%s: no class found.\n", debugstr_guid(rclsid));
371 return CLASS_E_CLASSNOTAVAILABLE;
374 static HRESULT register_inf(BOOL doregister)
376 HRESULT (WINAPI *pRegInstall)(HMODULE hm, LPCSTR pszSection, const STRTABLEA* pstTable);
377 HMODULE hAdvpack;
379 static const WCHAR wszAdvpack[] = {'a','d','v','p','a','c','k','.','d','l','l',0};
381 hAdvpack = LoadLibraryW(wszAdvpack);
382 pRegInstall = (void *)GetProcAddress(hAdvpack, "RegInstall");
384 return pRegInstall(hProxyDll, doregister ? "RegisterDll" : "UnregisterDll", NULL);
387 /***********************************************************************
388 * DllRegisterServer (URLMON.@)
390 HRESULT WINAPI DllRegisterServer(void)
392 HRESULT hr;
394 TRACE("\n");
396 hr = URLMON_DllRegisterServer();
397 return SUCCEEDED(hr) ? register_inf(TRUE) : hr;
400 /***********************************************************************
401 * DllUnregisterServer (URLMON.@)
403 HRESULT WINAPI DllUnregisterServer(void)
405 HRESULT hr;
407 TRACE("\n");
409 hr = URLMON_DllUnregisterServer();
410 return SUCCEEDED(hr) ? register_inf(FALSE) : hr;
413 /***********************************************************************
414 * DllRegisterServerEx (URLMON.@)
416 HRESULT WINAPI DllRegisterServerEx(void)
418 FIXME("(void): stub\n");
420 return E_FAIL;
423 /**************************************************************************
424 * IsValidURL (URLMON.@)
426 * Determines if a specified string is a valid URL.
428 * PARAMS
429 * pBC [I] ignored, should be NULL.
430 * szURL [I] string that represents the URL in question.
431 * dwReserved [I] reserved and must be zero.
433 * RETURNS
434 * Success: S_OK.
435 * Failure: S_FALSE.
436 * returns E_INVALIDARG if one or more of the args is invalid.
438 * TODO:
439 * test functionality against windows to see what a valid URL is.
441 HRESULT WINAPI IsValidURL(LPBC pBC, LPCWSTR szURL, DWORD dwReserved)
443 FIXME("(%p, %s, %d): stub\n", pBC, debugstr_w(szURL), dwReserved);
445 if (dwReserved || !szURL)
446 return E_INVALIDARG;
448 return S_OK;
451 /**************************************************************************
452 * FaultInIEFeature (URLMON.@)
454 * Undocumented. Appears to be used by native shdocvw.dll.
456 HRESULT WINAPI FaultInIEFeature( HWND hwnd, uCLSSPEC * pClassSpec,
457 QUERYCONTEXT *pQuery, DWORD flags )
459 FIXME("%p %p %p %08x\n", hwnd, pClassSpec, pQuery, flags);
460 return E_NOTIMPL;
463 /**************************************************************************
464 * CoGetClassObjectFromURL (URLMON.@)
466 HRESULT WINAPI CoGetClassObjectFromURL( REFCLSID rclsid, LPCWSTR szCodeURL, DWORD dwFileVersionMS,
467 DWORD dwFileVersionLS, LPCWSTR szContentType,
468 LPBINDCTX pBindCtx, DWORD dwClsContext, LPVOID pvReserved,
469 REFIID riid, LPVOID *ppv )
471 FIXME("(%s %s %d %d %s %p %d %p %s %p) Stub!\n", debugstr_guid(rclsid), debugstr_w(szCodeURL),
472 dwFileVersionMS, dwFileVersionLS, debugstr_w(szContentType), pBindCtx, dwClsContext, pvReserved,
473 debugstr_guid(riid), ppv);
474 return E_NOINTERFACE;
477 /***********************************************************************
478 * ReleaseBindInfo (URLMON.@)
480 * Release the resources used by the specified BINDINFO structure.
482 * PARAMS
483 * pbindinfo [I] BINDINFO to release.
485 * RETURNS
486 * Nothing.
488 void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo)
490 DWORD size;
492 TRACE("(%p)\n", pbindinfo);
494 if(!pbindinfo || !(size = pbindinfo->cbSize))
495 return;
497 CoTaskMemFree(pbindinfo->szExtraInfo);
498 ReleaseStgMedium(&pbindinfo->stgmedData);
500 if(offsetof(BINDINFO, szExtraInfo) < size)
501 CoTaskMemFree(pbindinfo->szCustomVerb);
503 if(pbindinfo->pUnk && offsetof(BINDINFO, pUnk) < size)
504 IUnknown_Release(pbindinfo->pUnk);
506 memset(pbindinfo, 0, size);
507 pbindinfo->cbSize = size;
510 /***********************************************************************
511 * CopyStgMedium (URLMON.@)
513 HRESULT WINAPI CopyStgMedium(const STGMEDIUM *src, STGMEDIUM *dst)
515 TRACE("(%p %p)\n", src, dst);
517 if(!src || !dst)
518 return E_POINTER;
520 *dst = *src;
522 switch(dst->tymed) {
523 case TYMED_NULL:
524 break;
525 case TYMED_FILE:
526 if(src->u.lpszFileName && !src->pUnkForRelease) {
527 DWORD size = (strlenW(src->u.lpszFileName)+1)*sizeof(WCHAR);
528 dst->u.lpszFileName = CoTaskMemAlloc(size);
529 memcpy(dst->u.lpszFileName, src->u.lpszFileName, size);
531 break;
532 case TYMED_ISTREAM:
533 if(dst->u.pstm)
534 IStream_AddRef(dst->u.pstm);
535 break;
536 case TYMED_ISTORAGE:
537 if(dst->u.pstg)
538 IStorage_AddRef(dst->u.pstg);
539 break;
540 default:
541 FIXME("Unimplemented tymed %d\n", src->tymed);
544 if(dst->pUnkForRelease)
545 IUnknown_AddRef(dst->pUnkForRelease);
547 return S_OK;
550 static BOOL text_richtext_filter(const BYTE *b, DWORD size)
552 return size > 5 && !memcmp(b, "{\\rtf", 5);
555 static BOOL text_html_filter(const BYTE *b, DWORD size)
557 DWORD i;
559 if(size < 5)
560 return FALSE;
562 for(i=0; i < size-5; i++) {
563 if(b[i] == '<'
564 && (b[i+1] == 'h' || b[i+1] == 'H')
565 && (b[i+2] == 't' || b[i+2] == 'T')
566 && (b[i+3] == 'm' || b[i+3] == 'M')
567 && (b[i+4] == 'l' || b[i+4] == 'L'))
568 return TRUE;
571 return FALSE;
574 static BOOL audio_basic_filter(const BYTE *b, DWORD size)
576 return size > 4
577 && b[0] == '.' && b[1] == 's' && b[2] == 'n' && b[3] == 'd';
580 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
582 return size > 12
583 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
584 && b[8] == 'W' && b[9] == 'A' && b[10] == 'V' && b[11] == 'E';
587 static BOOL image_gif_filter(const BYTE *b, DWORD size)
589 return size >= 6
590 && (b[0] == 'G' || b[0] == 'g')
591 && (b[1] == 'I' || b[1] == 'i')
592 && (b[2] == 'F' || b[2] == 'f')
593 && b[3] == '8'
594 && (b[4] == '7' || b[4] == '9')
595 && (b[5] == 'A' || b[5] == 'a');
598 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
600 return size > 2 && b[0] == 0xff && b[1] == 0xd8;
603 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
605 static const BYTE magic1[] = {0x4d,0x4d,0x00,0x2a};
606 static const BYTE magic2[] = {0x49,0x49,0x2a,0xff};
608 return size >= 4 && (!memcmp(b, magic1, 4) || !memcmp(b, magic2, 4));
611 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
613 static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
614 return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header));
617 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
619 return size >= 14
620 && b[0] == 0x42 && b[1] == 0x4d
621 && *(const DWORD *)(b+6) == 0;
624 static BOOL video_avi_filter(const BYTE *b, DWORD size)
626 return size > 12
627 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
628 && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20;
631 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
633 return size > 4
634 && !b[0] && !b[1] && b[2] == 0x01
635 && (b[3] == 0xb3 || b[3] == 0xba);
638 static BOOL application_postscript_filter(const BYTE *b, DWORD size)
640 return size > 2 && b[0] == '%' && b[1] == '!';
643 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
645 return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
648 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
650 return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
653 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
655 return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
658 static BOOL application_java_filter(const BYTE *b, DWORD size)
660 return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
663 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
665 return size > 2 && b[0] == 'M' && b[1] == 'Z';
668 static BOOL text_plain_filter(const BYTE *b, DWORD size)
670 const BYTE *ptr;
672 for(ptr = b; ptr < b+size-1; ptr++) {
673 if(*ptr < 0x20 && *ptr != '\n' && *ptr != '\r' && *ptr != '\t')
674 return FALSE;
677 return TRUE;
680 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
682 return TRUE;
685 static HRESULT find_mime_from_buffer(const BYTE *buf, DWORD size, const WCHAR *proposed_mime, WCHAR **ret_mime)
687 LPCWSTR ret = NULL;
688 DWORD len, i;
690 static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0};
691 static const WCHAR text_richtextW[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0};
692 static const WCHAR audio_basicW[] = {'a','u','d','i','o','/','b','a','s','i','c',0};
693 static const WCHAR audio_wavW[] = {'a','u','d','i','o','/','w','a','v',0};
694 static const WCHAR image_gifW[] = {'i','m','a','g','e','/','g','i','f',0};
695 static const WCHAR image_pjpegW[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
696 static const WCHAR image_tiffW[] = {'i','m','a','g','e','/','t','i','f','f',0};
697 static const WCHAR image_xpngW[] = {'i','m','a','g','e','/','x','-','p','n','g',0};
698 static const WCHAR image_bmpW[] = {'i','m','a','g','e','/','b','m','p',0};
699 static const WCHAR video_aviW[] = {'v','i','d','e','o','/','a','v','i',0};
700 static const WCHAR video_mpegW[] = {'v','i','d','e','o','/','m','p','e','g',0};
701 static const WCHAR app_postscriptW[] =
702 {'a','p','p','l','i','c','a','t','i','o','n','/','p','o','s','t','s','c','r','i','p','t',0};
703 static const WCHAR app_pdfW[] = {'a','p','p','l','i','c','a','t','i','o','n','/','p','d','f',0};
704 static const WCHAR app_xzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
705 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
706 static const WCHAR app_xgzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
707 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
708 static const WCHAR app_javaW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
709 'j','a','v','a',0};
710 static const WCHAR app_xmsdownloadW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
711 'x','-','m','s','d','o','w','n','l','o','a','d',0};
712 static const WCHAR text_plainW[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
713 static const WCHAR app_octetstreamW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
714 'o','c','t','e','t','-','s','t','r','e','a','m','\0'};
716 static const struct {
717 LPCWSTR mime;
718 BOOL (*filter)(const BYTE *,DWORD);
719 } mime_filters[] = {
720 {text_htmlW, text_html_filter},
721 {text_richtextW, text_richtext_filter},
722 /* {audio_xaiffW, audio_xaiff_filter}, */
723 {audio_basicW, audio_basic_filter},
724 {audio_wavW, audio_wav_filter},
725 {image_gifW, image_gif_filter},
726 {image_pjpegW, image_pjpeg_filter},
727 {image_tiffW, image_tiff_filter},
728 {image_xpngW, image_xpng_filter},
729 /* {image_xbitmapW, image_xbitmap_filter}, */
730 {image_bmpW, image_bmp_filter},
731 /* {image_xjgW, image_xjg_filter}, */
732 /* {image_xemfW, image_xemf_filter}, */
733 /* {image_xwmfW, image_xwmf_filter}, */
734 {video_aviW, video_avi_filter},
735 {video_mpegW, video_mpeg_filter},
736 {app_postscriptW, application_postscript_filter},
737 /* {app_base64W, application_base64_filter}, */
738 /* {app_macbinhex40W, application_macbinhex40_filter}, */
739 {app_pdfW, application_pdf_filter},
740 /* {app_zcompressedW, application_xcompressed_filter}, */
741 {app_xzipW, application_xzip_filter},
742 {app_xgzipW, application_xgzip_filter},
743 {app_javaW, application_java_filter},
744 {app_xmsdownloadW, application_xmsdownload},
745 {text_plainW, text_plain_filter},
746 {app_octetstreamW, application_octet_stream_filter}
749 if(!buf || !size) {
750 if(!proposed_mime)
751 return E_FAIL;
753 len = strlenW(proposed_mime)+1;
754 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
755 if(!*ret_mime)
756 return E_OUTOFMEMORY;
758 memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR));
759 return S_OK;
762 if(proposed_mime && strcmpW(proposed_mime, app_octetstreamW)) {
763 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
764 if(!strcmpW(proposed_mime, mime_filters[i].mime))
765 break;
768 if(i == sizeof(mime_filters)/sizeof(*mime_filters) || mime_filters[i].filter(buf, size)) {
769 len = strlenW(proposed_mime)+1;
770 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
771 if(!*ret_mime)
772 return E_OUTOFMEMORY;
774 memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR));
775 return S_OK;
779 i=0;
780 while(!ret) {
781 if(mime_filters[i].filter(buf, size))
782 ret = mime_filters[i].mime;
783 i++;
786 TRACE("found %s for %s\n", debugstr_w(ret), debugstr_an((const char*)buf, min(32, size)));
788 if(proposed_mime) {
789 if(i == sizeof(mime_filters)/sizeof(*mime_filters))
790 ret = proposed_mime;
792 /* text/html is a special case */
793 if(!strcmpW(proposed_mime, text_htmlW) && !strcmpW(ret, text_plainW))
794 ret = text_htmlW;
797 len = strlenW(ret)+1;
798 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
799 if(!*ret_mime)
800 return E_OUTOFMEMORY;
802 memcpy(*ret_mime, ret, len*sizeof(WCHAR));
803 return S_OK;
806 /***********************************************************************
807 * FindMimeFromData (URLMON.@)
809 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
811 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
812 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
813 LPWSTR* ppwzMimeOut, DWORD dwReserved)
815 TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
816 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
818 if(dwMimeFlags)
819 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
820 if(dwReserved)
821 WARN("dwReserved=%d\n", dwReserved);
823 /* pBC seams to not be used */
825 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
826 return E_INVALIDARG;
828 if(pwzMimeProposed || pBuffer)
829 return find_mime_from_buffer(pBuffer, cbSize, pwzMimeProposed, ppwzMimeOut);
831 if(pwzUrl) {
832 HKEY hkey;
833 DWORD res, size;
834 LPCWSTR ptr;
835 WCHAR mime[64];
837 static const WCHAR wszContentType[] =
838 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
840 ptr = strrchrW(pwzUrl, '.');
841 if(!ptr)
842 return E_FAIL;
844 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
845 if(res != ERROR_SUCCESS)
846 return HRESULT_FROM_WIN32(res);
848 size = sizeof(mime);
849 res = RegQueryValueExW(hkey, wszContentType, NULL, NULL, (LPBYTE)mime, &size);
850 RegCloseKey(hkey);
851 if(res != ERROR_SUCCESS)
852 return HRESULT_FROM_WIN32(res);
854 *ppwzMimeOut = CoTaskMemAlloc(size);
855 memcpy(*ppwzMimeOut, mime, size);
856 return S_OK;
859 return E_FAIL;
862 /***********************************************************************
863 * GetClassFileOrMime (URLMON.@)
865 * Determines the class ID from the bind context, file name or MIME type.
867 HRESULT WINAPI GetClassFileOrMime(LPBC pBC, LPCWSTR pszFilename,
868 LPVOID pBuffer, DWORD cbBuffer, LPCWSTR pszMimeType, DWORD dwReserved,
869 CLSID *pclsid)
871 FIXME("(%p, %s, %p, %d, %p, 0x%08x, %p): stub\n", pBC,
872 debugstr_w(pszFilename), pBuffer, cbBuffer, debugstr_w(pszMimeType),
873 dwReserved, pclsid);
874 return E_NOTIMPL;
877 /***********************************************************************
878 * Extract (URLMON.@)
880 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
882 HRESULT (WINAPI *pExtract)(void *, LPCSTR);
884 if (!hCabinet)
885 hCabinet = LoadLibraryA("cabinet.dll");
887 if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
888 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
889 if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());
891 return pExtract(dest, szCabName);
894 /***********************************************************************
895 * IsLoggingEnabledA (URLMON.@)
897 BOOL WINAPI IsLoggingEnabledA(LPCSTR url)
899 FIXME("(%s)\n", debugstr_a(url));
900 return FALSE;
903 /***********************************************************************
904 * IsLoggingEnabledW (URLMON.@)
906 BOOL WINAPI IsLoggingEnabledW(LPCWSTR url)
908 FIXME("(%s)\n", debugstr_w(url));
909 return FALSE;
912 /***********************************************************************
913 * IsProtectedModeURL (URLMON.111)
914 * Undocumented, added in IE7
916 BOOL WINAPI IsProtectedModeURL(const WCHAR *url)
918 FIXME("stub: %s\n", debugstr_w(url));
919 return TRUE;
922 /***********************************************************************
923 * URLMON_410 (URLMON.410)
924 * Undocumented, added in IE8
926 BOOL WINAPI URLMON_410(DWORD unknown1, DWORD unknown2)
928 FIXME("stub: %d %d\n", unknown1, unknown2);
929 return FALSE;
932 /***********************************************************************
933 * URLMON_423 (URLMON.423)
934 * Undocumented, added in IE8
936 BOOL WINAPI URLMON_423(DWORD unknown1, DWORD unknown2, DWORD unknown3, DWORD unknown4)
938 FIXME("stub: %d %d %d %d\n", unknown1, unknown2, unknown3, unknown4);
939 return FALSE;
942 /***********************************************************************
943 * RegisterMediaTypes
944 * Added in IE3, registers known MIME-type strings.
946 HRESULT WINAPI RegisterMediaTypes(UINT types, LPCSTR *szTypes, CLIPFORMAT *cfTypes)
948 FIXME("stub: %u %p %p\n", types, szTypes, cfTypes);
949 return E_INVALIDARG;