msvcp60: Manually define virtual destructors in vtables.
[wine/multimedia.git] / dlls / urlmon / urlmon_main.c
blobf2abe137609421a273e6001db2a76f2ec6bc76aa
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"
30 #include "initguid.h"
32 #include "wine/debug.h"
34 #include "urlmon.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 =
52 0, 0, &tls_cs,
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)
61 tls_data_t *data;
63 if(urlmon_tls == TLS_OUT_OF_INDEXES) {
64 DWORD tls = TlsAlloc();
65 if(tls == TLS_OUT_OF_INDEXES)
66 return NULL;
68 tls = InterlockedCompareExchange((LONG*)&urlmon_tls, tls, TLS_OUT_OF_INDEXES);
69 if(tls != urlmon_tls)
70 TlsFree(tls);
73 data = TlsGetValue(urlmon_tls);
74 if(!data) {
75 data = heap_alloc_zero(sizeof(tls_data_t));
76 if(!data)
77 return NULL;
79 EnterCriticalSection(&tls_cs);
80 list_add_tail(&tls_list, &data->entry);
81 LeaveCriticalSection(&tls_cs);
83 TlsSetValue(urlmon_tls, data);
86 return data;
89 static void free_tls_list(void)
91 tls_data_t *data;
93 if(urlmon_tls == TLS_OUT_OF_INDEXES)
94 return;
96 while(!list_empty(&tls_list)) {
97 data = LIST_ENTRY(list_head(&tls_list), tls_data_t, entry);
98 list_remove(&data->entry);
99 heap_free(data);
102 TlsFree(urlmon_tls);
105 static void detach_thread(void)
107 tls_data_t *data;
109 if(urlmon_tls == TLS_OUT_OF_INDEXES)
110 return;
112 data = TlsGetValue(urlmon_tls);
113 if(!data)
114 return;
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);
125 heap_free(data);
128 static void process_detach(void)
130 HINTERNET internet_session;
132 internet_session = get_internet_session(NULL);
133 if(internet_session)
134 InternetCloseHandle(internet_session);
136 if (hCabinet)
137 FreeLibrary(hCabinet);
139 free_session();
140 free_tls_list();
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 );
152 switch(fdwReason) {
153 case DLL_PROCESS_ATTACH:
154 init_session();
155 break;
157 case DLL_PROCESS_DETACH:
158 process_detach();
159 DeleteCriticalSection(&tls_cs);
160 break;
162 case DLL_THREAD_DETACH:
163 detach_thread();
164 break;
166 return TRUE;
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));
178 return S_OK;
181 /***********************************************************************
182 * DllCanUnloadNow (URLMON.@)
184 HRESULT WINAPI DllCanUnloadNow(void)
186 return URLMON_refCount != 0 ? S_FALSE : S_OK;
191 /******************************************************************************
192 * Urlmon ClassFactory
194 typedef struct {
195 IClassFactory IClassFactory_iface;
197 HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
198 } ClassFactory;
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)
207 *ppv = NULL;
209 if(IsEqualGUID(riid, &IID_IUnknown)) {
210 TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
211 *ppv = iface;
212 }else if(IsEqualGUID(riid, &IID_IClassFactory)) {
213 TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv);
214 *ppv = iface;
217 if(*ppv) {
218 IUnknown_AddRef((IUnknown*)*ppv);
219 return S_OK;
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)
228 URLMON_LockModule();
229 return 2;
232 static ULONG WINAPI CF_Release(IClassFactory *iface)
234 URLMON_UnlockModule();
235 return 1;
239 static HRESULT WINAPI CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
240 REFIID riid, LPVOID *ppobj)
242 ClassFactory *This = impl_from_IClassFactory(iface);
243 HRESULT hres;
244 LPUNKNOWN punk;
246 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
248 *ppobj = NULL;
249 if(SUCCEEDED(hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk))) {
250 hres = IUnknown_QueryInterface(punk, riid, ppobj);
251 IUnknown_Release(punk);
253 return hres;
256 static HRESULT WINAPI CF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
258 TRACE("(%d)\n", dolock);
260 if (dolock)
261 URLMON_LockModule();
262 else
263 URLMON_UnlockModule();
265 return S_OK;
268 static const IClassFactoryVtbl ClassFactoryVtbl =
270 CF_QueryInterface,
271 CF_AddRef,
272 CF_Release,
273 CF_CreateInstance,
274 CF_LockServer
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
302 const CLSID *clsid;
303 IClassFactory *cf;
304 LPCWSTR protocol;
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)
331 unsigned int i;
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
344 * NOTES
345 * Docs say returns STDAPI
347 * PARAMS
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
352 * RETURNS
353 * Success: S_OK
354 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
355 * E_UNEXPECTED
358 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
360 unsigned int i;
361 HRESULT hr;
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);
372 if(SUCCEEDED(hr))
373 return hr;
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);
382 HMODULE hAdvpack;
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)
397 HRESULT hr;
399 TRACE("\n");
401 hr = URLMON_DllRegisterServer();
402 return SUCCEEDED(hr) ? register_inf(TRUE) : hr;
405 /***********************************************************************
406 * DllUnregisterServer (URLMON.@)
408 HRESULT WINAPI DllUnregisterServer(void)
410 HRESULT hr;
412 TRACE("\n");
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");
425 return E_FAIL;
428 /**************************************************************************
429 * IsValidURL (URLMON.@)
431 * Determines if a specified string is a valid URL.
433 * PARAMS
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.
438 * RETURNS
439 * Success: S_OK.
440 * Failure: S_FALSE.
441 * returns E_INVALIDARG if one or more of the args is invalid.
443 * TODO:
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)
451 return E_INVALIDARG;
453 return S_OK;
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);
465 return E_NOTIMPL;
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.
487 * PARAMS
488 * pbindinfo [I] BINDINFO to release.
490 * RETURNS
491 * Nothing.
493 void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo)
495 DWORD size;
497 TRACE("(%p)\n", pbindinfo);
499 if(!pbindinfo || !(size = pbindinfo->cbSize))
500 return;
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);
522 if(!src || !dst)
523 return E_POINTER;
525 *dst = *src;
527 switch(dst->tymed) {
528 case TYMED_NULL:
529 break;
530 case TYMED_FILE:
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);
538 break;
539 case TYMED_ISTREAM:
540 if(dst->u.pstm)
541 IStream_AddRef(dst->u.pstm);
542 break;
543 case TYMED_ISTORAGE:
544 if(dst->u.pstg)
545 IStorage_AddRef(dst->u.pstg);
546 break;
547 case TYMED_HGLOBAL:
548 if(dst->u.hGlobal) {
549 SIZE_T size = GlobalSize(src->u.hGlobal);
550 char *src_ptr, *dst_ptr;
552 dst->u.hGlobal = GlobalAlloc(GMEM_FIXED, size);
553 if(!dst->u.hGlobal)
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);
561 break;
562 default:
563 FIXME("Unimplemented tymed %d\n", src->tymed);
566 if(dst->pUnkForRelease)
567 IUnknown_AddRef(dst->pUnkForRelease);
569 return S_OK;
572 /***********************************************************************
573 * CopyBindInfo (URLMON.@)
575 HRESULT WINAPI CopyBindInfo(const BINDINFO *pcbiSrc, BINDINFO *pcbiDest)
577 DWORD size;
578 HRESULT hres;
580 TRACE("(%p %p)\n", pcbiSrc, pcbiDest);
582 if(!pcbiSrc || !pcbiDest)
583 return E_POINTER;
584 if(!pcbiSrc->cbSize || !pcbiDest->cbSize)
585 return E_INVALIDARG;
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);
591 } else {
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);
608 if(FAILED(hres)) {
609 CoTaskMemFree(pcbiDest->szExtraInfo);
610 return hres;
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));
630 if(pcbiSrc->pUnk)
631 IUnknown_AddRef(pcbiDest->pUnk);
633 return S_OK;
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)
643 if(size < 6)
644 return FALSE;
646 if((b[0] == '<'
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'))
651 || (b[0] == '<'
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;
657 return FALSE;
660 static BOOL text_xml_filter(const BYTE *b, DWORD size)
662 if(size < 7)
663 return FALSE;
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;
671 return FALSE;
674 static BOOL audio_basic_filter(const BYTE *b, DWORD size)
676 return size > 4
677 && b[0] == '.' && b[1] == 's' && b[2] == 'n' && b[3] == 'd';
680 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
682 return size > 12
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)
689 return size >= 6
690 && (b[0] == 'G' || b[0] == 'g')
691 && (b[1] == 'I' || b[1] == 'i')
692 && (b[2] == 'F' || b[2] == 'f')
693 && b[3] == '8'
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)
719 return size >= 14
720 && b[0] == 0x42 && b[1] == 0x4d
721 && *(const DWORD *)(b+6) == 0;
724 static BOOL video_avi_filter(const BYTE *b, DWORD size)
726 return size > 12
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)
733 return size > 4
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')
771 return FALSE;
772 return TRUE;
775 static BOOL text_plain_filter(const BYTE *b, DWORD size)
777 const BYTE *ptr;
779 for(ptr = b; ptr < b+size-1; ptr++) {
780 if(!is_text_plain_char(*ptr))
781 return FALSE;
784 return TRUE;
787 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
789 return TRUE;
792 static HRESULT find_mime_from_buffer(const BYTE *buf, DWORD size, const WCHAR *proposed_mime, WCHAR **ret_mime)
794 LPCWSTR ret = NULL;
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','/',
817 'j','a','v','a',0};
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 {
825 LPCWSTR mime;
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}
859 if(!buf || !size) {
860 if(!proposed_mime)
861 return E_FAIL;
863 len = strlenW(proposed_mime)+1;
864 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
865 if(!*ret_mime)
866 return E_OUTOFMEMORY;
868 memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR));
869 return S_OK;
872 if(proposed_mime && (!strcmpW(proposed_mime, app_octetstreamW)
873 || !strcmpW(proposed_mime, text_plainW)))
874 proposed_mime = NULL;
876 if(proposed_mime) {
877 ret = proposed_mime;
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)) {
881 any_pos_mime = i;
882 for(len=size; len>0; len--) {
883 if(mime_filters_any_pos[i].filter(buf+size-len, len))
884 break;
886 if(!len)
887 ret = NULL;
888 break;
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))
896 ret = NULL;
897 break;
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;
910 break;
916 i=0;
917 while(!ret) {
918 if(mime_filters[i].filter(buf, size))
919 ret = mime_filters[i].mime;
920 i++;
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]))
928 break;
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)) {
931 ret = text_plainW;
932 break;
937 if(ret == app_octetstreamW)
938 ret = proposed_mime;
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));
944 if(!*ret_mime)
945 return E_OUTOFMEMORY;
947 memcpy(*ret_mime, ret, len*sizeof(WCHAR));
948 return S_OK;
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);
963 if(dwMimeFlags)
964 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
965 if(dwReserved)
966 WARN("dwReserved=%d\n", dwReserved);
968 /* pBC seams to not be used */
970 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
971 return E_INVALIDARG;
973 if(pwzMimeProposed || pBuffer)
974 return find_mime_from_buffer(pBuffer, cbSize, pwzMimeProposed, ppwzMimeOut);
976 if(pwzUrl) {
977 HKEY hkey;
978 DWORD res, size;
979 LPCWSTR ptr;
980 WCHAR mime[64];
982 static const WCHAR wszContentType[] =
983 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
985 ptr = strrchrW(pwzUrl, '.');
986 if(!ptr)
987 return E_FAIL;
989 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
990 if(res != ERROR_SUCCESS)
991 return HRESULT_FROM_WIN32(res);
993 size = sizeof(mime);
994 res = RegQueryValueExW(hkey, wszContentType, NULL, NULL, (LPBYTE)mime, &size);
995 RegCloseKey(hkey);
996 if(res != ERROR_SUCCESS)
997 return HRESULT_FROM_WIN32(res);
999 *ppwzMimeOut = CoTaskMemAlloc(size);
1000 memcpy(*ppwzMimeOut, mime, size);
1001 return S_OK;
1004 return E_FAIL;
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,
1014 CLSID *pclsid)
1016 FIXME("(%p, %s, %p, %d, %s, 0x%08x, %p): stub\n", pBC, debugstr_w(pszFilename), pBuffer,
1017 cbBuffer, debugstr_w(pszMimeType), dwReserved, pclsid);
1018 return E_NOTIMPL;
1021 /***********************************************************************
1022 * Extract (URLMON.@)
1024 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
1026 HRESULT (WINAPI *pExtract)(void *, LPCSTR);
1028 if (!hCabinet)
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));
1044 return FALSE;
1047 /***********************************************************************
1048 * IsLoggingEnabledW (URLMON.@)
1050 BOOL WINAPI IsLoggingEnabledW(LPCWSTR url)
1052 FIXME("(%s)\n", debugstr_w(url));
1053 return FALSE;
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));
1063 return TRUE;
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);
1073 return 0;
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);
1092 return 0;
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);
1102 return 0;
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;