urlmon: Added text/xml filter.
[wine/multimedia.git] / dlls / urlmon / urlmon_main.c
blobb02ddd0ffa84f754769f8af438e5834903bec429
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(BOOL);
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 init_session(FALSE);
140 free_session();
141 free_tls_list();
144 /***********************************************************************
145 * DllMain (URLMON.init)
147 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
149 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
151 URLMON_DllMain( hinstDLL, fdwReason, fImpLoad );
153 switch(fdwReason) {
154 case DLL_PROCESS_ATTACH:
155 init_session(TRUE);
156 break;
158 case DLL_PROCESS_DETACH:
159 process_detach();
160 DeleteCriticalSection(&tls_cs);
161 break;
163 case DLL_THREAD_DETACH:
164 detach_thread();
165 break;
167 return TRUE;
171 /***********************************************************************
172 * DllInstall (URLMON.@)
174 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
176 FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
177 debugstr_w(cmdline));
179 return S_OK;
182 /***********************************************************************
183 * DllCanUnloadNow (URLMON.@)
185 HRESULT WINAPI DllCanUnloadNow(void)
187 return URLMON_refCount != 0 ? S_FALSE : S_OK;
192 /******************************************************************************
193 * Urlmon ClassFactory
195 typedef struct {
196 IClassFactory IClassFactory_iface;
198 HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
199 } ClassFactory;
201 static inline ClassFactory *impl_from_IClassFactory(IClassFactory *iface)
203 return CONTAINING_RECORD(iface, ClassFactory, IClassFactory_iface);
206 static HRESULT WINAPI CF_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppv)
208 *ppv = NULL;
210 if(IsEqualGUID(riid, &IID_IUnknown)) {
211 TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
212 *ppv = iface;
213 }else if(IsEqualGUID(riid, &IID_IClassFactory)) {
214 TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv);
215 *ppv = iface;
218 if(*ppv) {
219 IUnknown_AddRef((IUnknown*)*ppv);
220 return S_OK;
223 WARN("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ppv);
224 return E_NOINTERFACE;
227 static ULONG WINAPI CF_AddRef(IClassFactory *iface)
229 URLMON_LockModule();
230 return 2;
233 static ULONG WINAPI CF_Release(IClassFactory *iface)
235 URLMON_UnlockModule();
236 return 1;
240 static HRESULT WINAPI CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
241 REFIID riid, LPVOID *ppobj)
243 ClassFactory *This = impl_from_IClassFactory(iface);
244 HRESULT hres;
245 LPUNKNOWN punk;
247 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
249 *ppobj = NULL;
250 if(SUCCEEDED(hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk))) {
251 hres = IUnknown_QueryInterface(punk, riid, ppobj);
252 IUnknown_Release(punk);
254 return hres;
257 static HRESULT WINAPI CF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
259 TRACE("(%d)\n", dolock);
261 if (dolock)
262 URLMON_LockModule();
263 else
264 URLMON_UnlockModule();
266 return S_OK;
269 static const IClassFactoryVtbl ClassFactoryVtbl =
271 CF_QueryInterface,
272 CF_AddRef,
273 CF_Release,
274 CF_CreateInstance,
275 CF_LockServer
278 static ClassFactory FileProtocolCF =
279 { { &ClassFactoryVtbl }, FileProtocol_Construct};
280 static ClassFactory FtpProtocolCF =
281 { { &ClassFactoryVtbl }, FtpProtocol_Construct};
282 static ClassFactory GopherProtocolCF =
283 { { &ClassFactoryVtbl }, GopherProtocol_Construct};
284 static ClassFactory HttpProtocolCF =
285 { { &ClassFactoryVtbl }, HttpProtocol_Construct};
286 static ClassFactory HttpSProtocolCF =
287 { { &ClassFactoryVtbl }, HttpSProtocol_Construct};
288 static ClassFactory MkProtocolCF =
289 { { &ClassFactoryVtbl }, MkProtocol_Construct};
290 static ClassFactory SecurityManagerCF =
291 { { &ClassFactoryVtbl }, SecManagerImpl_Construct};
292 static ClassFactory ZoneManagerCF =
293 { { &ClassFactoryVtbl }, ZoneMgrImpl_Construct};
294 static ClassFactory StdURLMonikerCF =
295 { { &ClassFactoryVtbl }, StdURLMoniker_Construct};
296 static ClassFactory MimeFilterCF =
297 { { &ClassFactoryVtbl }, MimeFilter_Construct};
298 static ClassFactory CUriCF =
299 { { &ClassFactoryVtbl }, Uri_Construct};
301 struct object_creation_info
303 const CLSID *clsid;
304 IClassFactory *cf;
305 LPCWSTR protocol;
308 static const WCHAR wszFile[] = {'f','i','l','e',0};
309 static const WCHAR wszFtp[] = {'f','t','p',0};
310 static const WCHAR wszGopher[] = {'g','o','p','h','e','r',0};
311 static const WCHAR wszHttp[] = {'h','t','t','p',0};
312 static const WCHAR wszHttps[] = {'h','t','t','p','s',0};
313 static const WCHAR wszMk[] = {'m','k',0};
315 static const struct object_creation_info object_creation[] =
317 { &CLSID_FileProtocol, &FileProtocolCF.IClassFactory_iface, wszFile },
318 { &CLSID_FtpProtocol, &FtpProtocolCF.IClassFactory_iface, wszFtp },
319 { &CLSID_GopherProtocol, &GopherProtocolCF.IClassFactory_iface, wszGopher },
320 { &CLSID_HttpProtocol, &HttpProtocolCF.IClassFactory_iface, wszHttp },
321 { &CLSID_HttpSProtocol, &HttpSProtocolCF.IClassFactory_iface, wszHttps },
322 { &CLSID_MkProtocol, &MkProtocolCF.IClassFactory_iface, wszMk },
323 { &CLSID_InternetSecurityManager, &SecurityManagerCF.IClassFactory_iface, NULL },
324 { &CLSID_InternetZoneManager, &ZoneManagerCF.IClassFactory_iface, NULL },
325 { &CLSID_StdURLMoniker, &StdURLMonikerCF.IClassFactory_iface, NULL },
326 { &CLSID_DeCompMimeFilter, &MimeFilterCF.IClassFactory_iface, NULL },
327 { &CLSID_CUri, &CUriCF.IClassFactory_iface, NULL }
330 static void init_session(BOOL init)
332 unsigned int i;
334 for(i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) {
336 if(object_creation[i].protocol)
337 register_urlmon_namespace(object_creation[i].cf, object_creation[i].clsid,
338 object_creation[i].protocol, init);
342 /*******************************************************************************
343 * DllGetClassObject [URLMON.@]
344 * Retrieves class object from a DLL object
346 * NOTES
347 * Docs say returns STDAPI
349 * PARAMS
350 * rclsid [I] CLSID for the class object
351 * riid [I] Reference to identifier of interface for class object
352 * ppv [O] Address of variable to receive interface pointer for riid
354 * RETURNS
355 * Success: S_OK
356 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
357 * E_UNEXPECTED
360 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
362 unsigned int i;
363 HRESULT hr;
365 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
367 for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
369 if (IsEqualGUID(object_creation[i].clsid, rclsid))
370 return IClassFactory_QueryInterface(object_creation[i].cf, riid, ppv);
373 hr = URLMON_DllGetClassObject(rclsid, riid, ppv);
374 if(SUCCEEDED(hr))
375 return hr;
377 FIXME("%s: no class found.\n", debugstr_guid(rclsid));
378 return CLASS_E_CLASSNOTAVAILABLE;
381 static HRESULT register_inf(BOOL doregister)
383 HRESULT (WINAPI *pRegInstall)(HMODULE hm, LPCSTR pszSection, const STRTABLEA* pstTable);
384 HMODULE hAdvpack;
386 static const WCHAR wszAdvpack[] = {'a','d','v','p','a','c','k','.','d','l','l',0};
388 hAdvpack = LoadLibraryW(wszAdvpack);
389 pRegInstall = (void *)GetProcAddress(hAdvpack, "RegInstall");
391 return pRegInstall(hProxyDll, doregister ? "RegisterDll" : "UnregisterDll", NULL);
394 /***********************************************************************
395 * DllRegisterServer (URLMON.@)
397 HRESULT WINAPI DllRegisterServer(void)
399 HRESULT hr;
401 TRACE("\n");
403 hr = URLMON_DllRegisterServer();
404 return SUCCEEDED(hr) ? register_inf(TRUE) : hr;
407 /***********************************************************************
408 * DllUnregisterServer (URLMON.@)
410 HRESULT WINAPI DllUnregisterServer(void)
412 HRESULT hr;
414 TRACE("\n");
416 hr = URLMON_DllUnregisterServer();
417 return SUCCEEDED(hr) ? register_inf(FALSE) : hr;
420 /***********************************************************************
421 * DllRegisterServerEx (URLMON.@)
423 HRESULT WINAPI DllRegisterServerEx(void)
425 FIXME("(void): stub\n");
427 return E_FAIL;
430 /**************************************************************************
431 * IsValidURL (URLMON.@)
433 * Determines if a specified string is a valid URL.
435 * PARAMS
436 * pBC [I] ignored, should be NULL.
437 * szURL [I] string that represents the URL in question.
438 * dwReserved [I] reserved and must be zero.
440 * RETURNS
441 * Success: S_OK.
442 * Failure: S_FALSE.
443 * returns E_INVALIDARG if one or more of the args is invalid.
445 * TODO:
446 * test functionality against windows to see what a valid URL is.
448 HRESULT WINAPI IsValidURL(LPBC pBC, LPCWSTR szURL, DWORD dwReserved)
450 FIXME("(%p, %s, %d): stub\n", pBC, debugstr_w(szURL), dwReserved);
452 if (dwReserved || !szURL)
453 return E_INVALIDARG;
455 return S_OK;
458 /**************************************************************************
459 * FaultInIEFeature (URLMON.@)
461 * Undocumented. Appears to be used by native shdocvw.dll.
463 HRESULT WINAPI FaultInIEFeature( HWND hwnd, uCLSSPEC * pClassSpec,
464 QUERYCONTEXT *pQuery, DWORD flags )
466 FIXME("%p %p %p %08x\n", hwnd, pClassSpec, pQuery, flags);
467 return E_NOTIMPL;
470 /**************************************************************************
471 * CoGetClassObjectFromURL (URLMON.@)
473 HRESULT WINAPI CoGetClassObjectFromURL( REFCLSID rclsid, LPCWSTR szCodeURL, DWORD dwFileVersionMS,
474 DWORD dwFileVersionLS, LPCWSTR szContentType,
475 LPBINDCTX pBindCtx, DWORD dwClsContext, LPVOID pvReserved,
476 REFIID riid, LPVOID *ppv )
478 FIXME("(%s %s %d %d %s %p %d %p %s %p) Stub!\n", debugstr_guid(rclsid), debugstr_w(szCodeURL),
479 dwFileVersionMS, dwFileVersionLS, debugstr_w(szContentType), pBindCtx, dwClsContext, pvReserved,
480 debugstr_guid(riid), ppv);
481 return E_NOINTERFACE;
484 /***********************************************************************
485 * ReleaseBindInfo (URLMON.@)
487 * Release the resources used by the specified BINDINFO structure.
489 * PARAMS
490 * pbindinfo [I] BINDINFO to release.
492 * RETURNS
493 * Nothing.
495 void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo)
497 DWORD size;
499 TRACE("(%p)\n", pbindinfo);
501 if(!pbindinfo || !(size = pbindinfo->cbSize))
502 return;
504 CoTaskMemFree(pbindinfo->szExtraInfo);
505 ReleaseStgMedium(&pbindinfo->stgmedData);
507 if(offsetof(BINDINFO, szExtraInfo) < size)
508 CoTaskMemFree(pbindinfo->szCustomVerb);
510 if(pbindinfo->pUnk && offsetof(BINDINFO, pUnk) < size)
511 IUnknown_Release(pbindinfo->pUnk);
513 memset(pbindinfo, 0, size);
514 pbindinfo->cbSize = size;
517 /***********************************************************************
518 * CopyStgMedium (URLMON.@)
520 HRESULT WINAPI CopyStgMedium(const STGMEDIUM *src, STGMEDIUM *dst)
522 TRACE("(%p %p)\n", src, dst);
524 if(!src || !dst)
525 return E_POINTER;
527 *dst = *src;
529 switch(dst->tymed) {
530 case TYMED_NULL:
531 break;
532 case TYMED_FILE:
533 if(src->u.lpszFileName && !src->pUnkForRelease) {
534 DWORD size = (strlenW(src->u.lpszFileName)+1)*sizeof(WCHAR);
535 dst->u.lpszFileName = CoTaskMemAlloc(size);
536 if(!dst->u.lpszFileName)
537 return E_OUTOFMEMORY;
538 memcpy(dst->u.lpszFileName, src->u.lpszFileName, size);
540 break;
541 case TYMED_ISTREAM:
542 if(dst->u.pstm)
543 IStream_AddRef(dst->u.pstm);
544 break;
545 case TYMED_ISTORAGE:
546 if(dst->u.pstg)
547 IStorage_AddRef(dst->u.pstg);
548 break;
549 default:
550 FIXME("Unimplemented tymed %d\n", src->tymed);
553 if(dst->pUnkForRelease)
554 IUnknown_AddRef(dst->pUnkForRelease);
556 return S_OK;
559 /***********************************************************************
560 * CopyBindInfo (URLMON.@)
562 HRESULT WINAPI CopyBindInfo(const BINDINFO *pcbiSrc, BINDINFO *pcbiDest)
564 DWORD size;
565 HRESULT hres;
567 TRACE("(%p %p)\n", pcbiSrc, pcbiDest);
569 if(!pcbiSrc || !pcbiDest)
570 return E_POINTER;
571 if(!pcbiSrc->cbSize || !pcbiDest->cbSize)
572 return E_INVALIDARG;
574 size = pcbiDest->cbSize;
575 if(size > pcbiSrc->cbSize) {
576 memcpy(pcbiDest, pcbiSrc, pcbiSrc->cbSize);
577 memset((char*)pcbiDest+pcbiSrc->cbSize, 0, size-pcbiSrc->cbSize);
578 } else {
579 memcpy(pcbiDest, pcbiSrc, size);
581 pcbiDest->cbSize = size;
583 size = FIELD_OFFSET(BINDINFO, szExtraInfo)+sizeof(void*);
584 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size && pcbiSrc->szExtraInfo) {
585 size = (strlenW(pcbiSrc->szExtraInfo)+1)*sizeof(WCHAR);
586 pcbiDest->szExtraInfo = CoTaskMemAlloc(size);
587 if(!pcbiDest->szExtraInfo)
588 return E_OUTOFMEMORY;
589 memcpy(pcbiDest->szExtraInfo, pcbiSrc->szExtraInfo, size);
592 size = FIELD_OFFSET(BINDINFO, stgmedData)+sizeof(STGMEDIUM);
593 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size) {
594 hres = CopyStgMedium(&pcbiSrc->stgmedData, &pcbiDest->stgmedData);
595 if(FAILED(hres)) {
596 CoTaskMemFree(pcbiDest->szExtraInfo);
597 return hres;
601 size = FIELD_OFFSET(BINDINFO, szCustomVerb)+sizeof(void*);
602 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size && pcbiSrc->szCustomVerb) {
603 size = (strlenW(pcbiSrc->szCustomVerb)+1)*sizeof(WCHAR);
604 pcbiDest->szCustomVerb = CoTaskMemAlloc(size);
605 if(!pcbiDest->szCustomVerb) {
606 CoTaskMemFree(pcbiDest->szExtraInfo);
607 ReleaseStgMedium(&pcbiDest->stgmedData);
608 return E_OUTOFMEMORY;
612 size = FIELD_OFFSET(BINDINFO, securityAttributes)+sizeof(SECURITY_ATTRIBUTES);
613 if(pcbiDest->cbSize >= size)
614 memset(&pcbiDest->securityAttributes, 0, sizeof(SECURITY_ATTRIBUTES));
616 if(pcbiSrc->pUnk)
617 IUnknown_AddRef(pcbiDest->pUnk);
619 return S_OK;
622 static BOOL text_richtext_filter(const BYTE *b, DWORD size)
624 return size > 5 && !memcmp(b, "{\\rtf", 5);
627 static BOOL text_html_filter(const BYTE *b, DWORD size)
629 DWORD i;
631 if(size < 5)
632 return FALSE;
634 for(i = 0; i < size-5; i++) {
635 if((b[i] == '<'
636 && (b[i+1] == 'h' || b[i+1] == 'H')
637 && (b[i+2] == 't' || b[i+2] == 'T')
638 && (b[i+3] == 'm' || b[i+3] == 'M')
639 && (b[i+4] == 'l' || b[i+4] == 'L')) ||
640 (b[i] == '<'
641 && (b[i+1] == 'h' || b[i+1] == 'H')
642 && (b[i+2] == 'e' || b[i+2] == 'E')
643 && (b[i+3] == 'a' || b[i+3] == 'A')
644 && (b[i+4] == 'd' || b[i+4] == 'D')
645 && b[i+5] == '>')) return TRUE;
648 return FALSE;
651 static BOOL text_xml_filter(const BYTE *b, DWORD size)
653 DWORD i;
655 if(size < 6)
656 return FALSE;
658 for(i=0; i<size-6; i++) {
659 if(b[i] == '<' && b[i+1] == '?'
660 && (b[i+2] == 'x' || b[i+2] == 'X')
661 && (b[i+3] == 'm' || b[i+3] == 'M')
662 && (b[i+4] == 'l' || b[i+4] == 'L')
663 && b[i+5] == ' ') return TRUE;
666 return FALSE;
669 static BOOL audio_basic_filter(const BYTE *b, DWORD size)
671 return size > 4
672 && b[0] == '.' && b[1] == 's' && b[2] == 'n' && b[3] == 'd';
675 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
677 return size > 12
678 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
679 && b[8] == 'W' && b[9] == 'A' && b[10] == 'V' && b[11] == 'E';
682 static BOOL image_gif_filter(const BYTE *b, DWORD size)
684 return size >= 6
685 && (b[0] == 'G' || b[0] == 'g')
686 && (b[1] == 'I' || b[1] == 'i')
687 && (b[2] == 'F' || b[2] == 'f')
688 && b[3] == '8'
689 && (b[4] == '7' || b[4] == '9')
690 && (b[5] == 'A' || b[5] == 'a');
693 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
695 return size > 2 && b[0] == 0xff && b[1] == 0xd8;
698 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
700 static const BYTE magic1[] = {0x4d,0x4d,0x00,0x2a};
701 static const BYTE magic2[] = {0x49,0x49,0x2a,0xff};
703 return size >= 4 && (!memcmp(b, magic1, 4) || !memcmp(b, magic2, 4));
706 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
708 static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
709 return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header));
712 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
714 return size >= 14
715 && b[0] == 0x42 && b[1] == 0x4d
716 && *(const DWORD *)(b+6) == 0;
719 static BOOL video_avi_filter(const BYTE *b, DWORD size)
721 return size > 12
722 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
723 && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20;
726 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
728 return size > 4
729 && !b[0] && !b[1] && b[2] == 0x01
730 && (b[3] == 0xb3 || b[3] == 0xba);
733 static BOOL application_postscript_filter(const BYTE *b, DWORD size)
735 return size > 2 && b[0] == '%' && b[1] == '!';
738 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
740 return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
743 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
745 return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
748 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
750 return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
753 static BOOL application_java_filter(const BYTE *b, DWORD size)
755 return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
758 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
760 return size > 2 && b[0] == 'M' && b[1] == 'Z';
763 static BOOL text_plain_filter(const BYTE *b, DWORD size)
765 const BYTE *ptr;
767 for(ptr = b; ptr < b+size-1; ptr++) {
768 if(*ptr < 0x20 && *ptr != '\n' && *ptr != '\r' && *ptr != '\t')
769 return FALSE;
772 return TRUE;
775 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
777 return TRUE;
780 static HRESULT find_mime_from_buffer(const BYTE *buf, DWORD size, const WCHAR *proposed_mime, WCHAR **ret_mime)
782 LPCWSTR ret = NULL;
783 DWORD len, i;
785 static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0};
786 static const WCHAR text_richtextW[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0};
787 static const WCHAR text_xmlW[] = {'t','e','x','t','/','x','m','l',0};
788 static const WCHAR audio_basicW[] = {'a','u','d','i','o','/','b','a','s','i','c',0};
789 static const WCHAR audio_wavW[] = {'a','u','d','i','o','/','w','a','v',0};
790 static const WCHAR image_gifW[] = {'i','m','a','g','e','/','g','i','f',0};
791 static const WCHAR image_pjpegW[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
792 static const WCHAR image_tiffW[] = {'i','m','a','g','e','/','t','i','f','f',0};
793 static const WCHAR image_xpngW[] = {'i','m','a','g','e','/','x','-','p','n','g',0};
794 static const WCHAR image_bmpW[] = {'i','m','a','g','e','/','b','m','p',0};
795 static const WCHAR video_aviW[] = {'v','i','d','e','o','/','a','v','i',0};
796 static const WCHAR video_mpegW[] = {'v','i','d','e','o','/','m','p','e','g',0};
797 static const WCHAR app_postscriptW[] =
798 {'a','p','p','l','i','c','a','t','i','o','n','/','p','o','s','t','s','c','r','i','p','t',0};
799 static const WCHAR app_pdfW[] = {'a','p','p','l','i','c','a','t','i','o','n','/','p','d','f',0};
800 static const WCHAR app_xzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
801 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
802 static const WCHAR app_xgzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
803 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
804 static const WCHAR app_javaW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
805 'j','a','v','a',0};
806 static const WCHAR app_xmsdownloadW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
807 'x','-','m','s','d','o','w','n','l','o','a','d',0};
808 static const WCHAR text_plainW[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
809 static const WCHAR app_octetstreamW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
810 'o','c','t','e','t','-','s','t','r','e','a','m','\0'};
812 static const struct {
813 LPCWSTR mime;
814 BOOL (*filter)(const BYTE *,DWORD);
815 } mime_filters[] = {
816 {text_htmlW, text_html_filter},
817 {text_xmlW, text_xml_filter},
818 {text_richtextW, text_richtext_filter},
819 /* {audio_xaiffW, audio_xaiff_filter}, */
820 {audio_basicW, audio_basic_filter},
821 {audio_wavW, audio_wav_filter},
822 {image_gifW, image_gif_filter},
823 {image_pjpegW, image_pjpeg_filter},
824 {image_tiffW, image_tiff_filter},
825 {image_xpngW, image_xpng_filter},
826 /* {image_xbitmapW, image_xbitmap_filter}, */
827 {image_bmpW, image_bmp_filter},
828 /* {image_xjgW, image_xjg_filter}, */
829 /* {image_xemfW, image_xemf_filter}, */
830 /* {image_xwmfW, image_xwmf_filter}, */
831 {video_aviW, video_avi_filter},
832 {video_mpegW, video_mpeg_filter},
833 {app_postscriptW, application_postscript_filter},
834 /* {app_base64W, application_base64_filter}, */
835 /* {app_macbinhex40W, application_macbinhex40_filter}, */
836 {app_pdfW, application_pdf_filter},
837 /* {app_zcompressedW, application_xcompressed_filter}, */
838 {app_xzipW, application_xzip_filter},
839 {app_xgzipW, application_xgzip_filter},
840 {app_javaW, application_java_filter},
841 {app_xmsdownloadW, application_xmsdownload},
842 {text_plainW, text_plain_filter},
843 {app_octetstreamW, application_octet_stream_filter}
846 if(!buf || !size) {
847 if(!proposed_mime)
848 return E_FAIL;
850 len = strlenW(proposed_mime)+1;
851 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
852 if(!*ret_mime)
853 return E_OUTOFMEMORY;
855 memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR));
856 return S_OK;
859 if(proposed_mime && strcmpW(proposed_mime, app_octetstreamW)) {
860 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
861 if(!strcmpW(proposed_mime, mime_filters[i].mime))
862 break;
865 if(i == sizeof(mime_filters)/sizeof(*mime_filters) || mime_filters[i].filter(buf, size)) {
866 len = strlenW(proposed_mime)+1;
867 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
868 if(!*ret_mime)
869 return E_OUTOFMEMORY;
871 memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR));
872 return S_OK;
876 i=0;
877 while(!ret) {
878 if(mime_filters[i].filter(buf, size))
879 ret = mime_filters[i].mime;
880 i++;
883 TRACE("found %s for %s\n", debugstr_w(ret), debugstr_an((const char*)buf, min(32, size)));
885 if(proposed_mime) {
886 if(i == sizeof(mime_filters)/sizeof(*mime_filters))
887 ret = proposed_mime;
889 /* text/html is a special case */
890 if(!strcmpW(proposed_mime, text_htmlW) && !strcmpW(ret, text_plainW))
891 ret = text_htmlW;
894 len = strlenW(ret)+1;
895 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
896 if(!*ret_mime)
897 return E_OUTOFMEMORY;
899 memcpy(*ret_mime, ret, len*sizeof(WCHAR));
900 return S_OK;
903 /***********************************************************************
904 * FindMimeFromData (URLMON.@)
906 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
908 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
909 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
910 LPWSTR* ppwzMimeOut, DWORD dwReserved)
912 TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
913 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
915 if(dwMimeFlags)
916 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
917 if(dwReserved)
918 WARN("dwReserved=%d\n", dwReserved);
920 /* pBC seams to not be used */
922 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
923 return E_INVALIDARG;
925 if(pwzMimeProposed || pBuffer)
926 return find_mime_from_buffer(pBuffer, cbSize, pwzMimeProposed, ppwzMimeOut);
928 if(pwzUrl) {
929 HKEY hkey;
930 DWORD res, size;
931 LPCWSTR ptr;
932 WCHAR mime[64];
934 static const WCHAR wszContentType[] =
935 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
937 ptr = strrchrW(pwzUrl, '.');
938 if(!ptr)
939 return E_FAIL;
941 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
942 if(res != ERROR_SUCCESS)
943 return HRESULT_FROM_WIN32(res);
945 size = sizeof(mime);
946 res = RegQueryValueExW(hkey, wszContentType, NULL, NULL, (LPBYTE)mime, &size);
947 RegCloseKey(hkey);
948 if(res != ERROR_SUCCESS)
949 return HRESULT_FROM_WIN32(res);
951 *ppwzMimeOut = CoTaskMemAlloc(size);
952 memcpy(*ppwzMimeOut, mime, size);
953 return S_OK;
956 return E_FAIL;
959 /***********************************************************************
960 * GetClassFileOrMime (URLMON.@)
962 * Determines the class ID from the bind context, file name or MIME type.
964 HRESULT WINAPI GetClassFileOrMime(LPBC pBC, LPCWSTR pszFilename,
965 LPVOID pBuffer, DWORD cbBuffer, LPCWSTR pszMimeType, DWORD dwReserved,
966 CLSID *pclsid)
968 FIXME("(%p, %s, %p, %d, %p, 0x%08x, %p): stub\n", pBC,
969 debugstr_w(pszFilename), pBuffer, cbBuffer, debugstr_w(pszMimeType),
970 dwReserved, pclsid);
971 return E_NOTIMPL;
974 /***********************************************************************
975 * Extract (URLMON.@)
977 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
979 HRESULT (WINAPI *pExtract)(void *, LPCSTR);
981 if (!hCabinet)
982 hCabinet = LoadLibraryA("cabinet.dll");
984 if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
985 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
986 if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());
988 return pExtract(dest, szCabName);
991 /***********************************************************************
992 * IsLoggingEnabledA (URLMON.@)
994 BOOL WINAPI IsLoggingEnabledA(LPCSTR url)
996 FIXME("(%s)\n", debugstr_a(url));
997 return FALSE;
1000 /***********************************************************************
1001 * IsLoggingEnabledW (URLMON.@)
1003 BOOL WINAPI IsLoggingEnabledW(LPCWSTR url)
1005 FIXME("(%s)\n", debugstr_w(url));
1006 return FALSE;
1009 /***********************************************************************
1010 * IsProtectedModeURL (URLMON.111)
1011 * Undocumented, added in IE7
1013 BOOL WINAPI IsProtectedModeURL(const WCHAR *url)
1015 FIXME("stub: %s\n", debugstr_w(url));
1016 return TRUE;
1019 /***********************************************************************
1020 * LogSqmBits (URLMON.410)
1021 * Undocumented, added in IE8
1023 int WINAPI LogSqmBits(DWORD unk1, DWORD unk2)
1025 FIXME("stub: %d %d\n", unk1, unk2);
1026 return 0;
1029 /***********************************************************************
1030 * LogSqmUXCommandOffsetInternal (URLMON.423)
1031 * Undocumented, added in IE8
1033 void WINAPI LogSqmUXCommandOffsetInternal(DWORD unk1, DWORD unk2, DWORD unk3, DWORD unk4)
1035 FIXME("stub: %d %d %d %d\n", unk1, unk2, unk3, unk4);
1038 /***********************************************************************
1039 * MapUriToBrowserEmulationState (URLMON.444)
1040 * Undocumented, added in IE8
1042 int WINAPI MapUriToBrowserEmulationState(DWORD unk1, DWORD unk2, DWORD unk3)
1044 FIXME("stub: %d %d %d\n", unk1, unk2, unk3);
1045 return 0;
1048 /***********************************************************************
1049 * MapBrowserEmulationModeToUserAgent (URLMON.445)
1050 * Undocumented, added in IE8
1052 int WINAPI MapBrowserEmulationModeToUserAgent(DWORD unk1, DWORD unk2)
1054 FIXME("stub: %d %d\n", unk1, unk2);
1055 return 0;
1058 /***********************************************************************
1059 * RegisterMediaTypes
1060 * Added in IE3, registers known MIME-type strings.
1062 HRESULT WINAPI RegisterMediaTypes(UINT types, LPCSTR *szTypes, CLIPFORMAT *cfTypes)
1064 FIXME("stub: %u %p %p\n", types, szTypes, cfTypes);
1065 return E_INVALIDARG;