oleaut32/tests: Compare the correct variants.
[wine/multimedia.git] / dlls / urlmon / urlmon_main.c
blob0cb72ddae2e92b7c6d1a0ddbabf00ae040bb0445
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 default:
548 FIXME("Unimplemented tymed %d\n", src->tymed);
551 if(dst->pUnkForRelease)
552 IUnknown_AddRef(dst->pUnkForRelease);
554 return S_OK;
557 /***********************************************************************
558 * CopyBindInfo (URLMON.@)
560 HRESULT WINAPI CopyBindInfo(const BINDINFO *pcbiSrc, BINDINFO *pcbiDest)
562 DWORD size;
563 HRESULT hres;
565 TRACE("(%p %p)\n", pcbiSrc, pcbiDest);
567 if(!pcbiSrc || !pcbiDest)
568 return E_POINTER;
569 if(!pcbiSrc->cbSize || !pcbiDest->cbSize)
570 return E_INVALIDARG;
572 size = pcbiDest->cbSize;
573 if(size > pcbiSrc->cbSize) {
574 memcpy(pcbiDest, pcbiSrc, pcbiSrc->cbSize);
575 memset((char*)pcbiDest+pcbiSrc->cbSize, 0, size-pcbiSrc->cbSize);
576 } else {
577 memcpy(pcbiDest, pcbiSrc, size);
579 pcbiDest->cbSize = size;
581 size = FIELD_OFFSET(BINDINFO, szExtraInfo)+sizeof(void*);
582 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size && pcbiSrc->szExtraInfo) {
583 size = (strlenW(pcbiSrc->szExtraInfo)+1)*sizeof(WCHAR);
584 pcbiDest->szExtraInfo = CoTaskMemAlloc(size);
585 if(!pcbiDest->szExtraInfo)
586 return E_OUTOFMEMORY;
587 memcpy(pcbiDest->szExtraInfo, pcbiSrc->szExtraInfo, size);
590 size = FIELD_OFFSET(BINDINFO, stgmedData)+sizeof(STGMEDIUM);
591 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size) {
592 hres = CopyStgMedium(&pcbiSrc->stgmedData, &pcbiDest->stgmedData);
593 if(FAILED(hres)) {
594 CoTaskMemFree(pcbiDest->szExtraInfo);
595 return hres;
599 size = FIELD_OFFSET(BINDINFO, szCustomVerb)+sizeof(void*);
600 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size && pcbiSrc->szCustomVerb) {
601 size = (strlenW(pcbiSrc->szCustomVerb)+1)*sizeof(WCHAR);
602 pcbiDest->szCustomVerb = CoTaskMemAlloc(size);
603 if(!pcbiDest->szCustomVerb) {
604 CoTaskMemFree(pcbiDest->szExtraInfo);
605 ReleaseStgMedium(&pcbiDest->stgmedData);
606 return E_OUTOFMEMORY;
608 memcpy(pcbiDest->szCustomVerb, pcbiSrc->szCustomVerb, size);
611 size = FIELD_OFFSET(BINDINFO, securityAttributes)+sizeof(SECURITY_ATTRIBUTES);
612 if(pcbiDest->cbSize >= size)
613 memset(&pcbiDest->securityAttributes, 0, sizeof(SECURITY_ATTRIBUTES));
615 if(pcbiSrc->pUnk)
616 IUnknown_AddRef(pcbiDest->pUnk);
618 return S_OK;
621 static BOOL text_richtext_filter(const BYTE *b, DWORD size)
623 return size > 5 && !memcmp(b, "{\\rtf", 5);
626 static BOOL text_html_filter(const BYTE *b, DWORD size)
628 if(size < 6)
629 return FALSE;
631 if((b[0] == '<'
632 && (b[1] == 'h' || b[1] == 'H')
633 && (b[2] == 't' || b[2] == 'T')
634 && (b[3] == 'm' || b[3] == 'M')
635 && (b[4] == 'l' || b[4] == 'L'))
636 || (b[0] == '<'
637 && (b[1] == 'h' || b[1] == 'H')
638 && (b[2] == 'e' || b[2] == 'E')
639 && (b[3] == 'a' || b[3] == 'A')
640 && (b[4] == 'd' || b[4] == 'D'))) return TRUE;
642 return FALSE;
645 static BOOL text_xml_filter(const BYTE *b, DWORD size)
647 if(size < 7)
648 return FALSE;
650 if(b[0] == '<' && b[1] == '?'
651 && (b[2] == 'x' || b[2] == 'X')
652 && (b[3] == 'm' || b[3] == 'M')
653 && (b[4] == 'l' || b[4] == 'L')
654 && b[5] == ' ') return TRUE;
656 return FALSE;
659 static BOOL audio_basic_filter(const BYTE *b, DWORD size)
661 return size > 4
662 && b[0] == '.' && b[1] == 's' && b[2] == 'n' && b[3] == 'd';
665 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
667 return size > 12
668 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
669 && b[8] == 'W' && b[9] == 'A' && b[10] == 'V' && b[11] == 'E';
672 static BOOL image_gif_filter(const BYTE *b, DWORD size)
674 return size >= 6
675 && (b[0] == 'G' || b[0] == 'g')
676 && (b[1] == 'I' || b[1] == 'i')
677 && (b[2] == 'F' || b[2] == 'f')
678 && b[3] == '8'
679 && (b[4] == '7' || b[4] == '9')
680 && (b[5] == 'A' || b[5] == 'a');
683 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
685 return size > 2 && b[0] == 0xff && b[1] == 0xd8;
688 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
690 static const BYTE magic1[] = {0x4d,0x4d,0x00,0x2a};
691 static const BYTE magic2[] = {0x49,0x49,0x2a,0xff};
693 return size >= 4 && (!memcmp(b, magic1, 4) || !memcmp(b, magic2, 4));
696 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
698 static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
699 return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header));
702 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
704 return size >= 14
705 && b[0] == 0x42 && b[1] == 0x4d
706 && *(const DWORD *)(b+6) == 0;
709 static BOOL video_avi_filter(const BYTE *b, DWORD size)
711 return size > 12
712 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
713 && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20;
716 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
718 return size > 4
719 && !b[0] && !b[1] && b[2] == 0x01
720 && (b[3] == 0xb3 || b[3] == 0xba);
723 static BOOL application_postscript_filter(const BYTE *b, DWORD size)
725 return size > 2 && b[0] == '%' && b[1] == '!';
728 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
730 return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
733 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
735 return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
738 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
740 return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
743 static BOOL application_java_filter(const BYTE *b, DWORD size)
745 return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
748 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
750 return size > 2 && b[0] == 'M' && b[1] == 'Z';
753 static inline BOOL is_text_plain_char(BYTE b)
755 if(b < 0x20 && b != '\n' && b != '\r' && b != '\t')
756 return FALSE;
757 return TRUE;
760 static BOOL text_plain_filter(const BYTE *b, DWORD size)
762 const BYTE *ptr;
764 for(ptr = b; ptr < b+size-1; ptr++) {
765 if(!is_text_plain_char(*ptr))
766 return FALSE;
769 return TRUE;
772 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
774 return TRUE;
777 static HRESULT find_mime_from_buffer(const BYTE *buf, DWORD size, const WCHAR *proposed_mime, WCHAR **ret_mime)
779 LPCWSTR ret = NULL;
780 int len, i, any_pos_mime = -1;
782 static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0};
783 static const WCHAR text_richtextW[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0};
784 static const WCHAR text_xmlW[] = {'t','e','x','t','/','x','m','l',0};
785 static const WCHAR audio_basicW[] = {'a','u','d','i','o','/','b','a','s','i','c',0};
786 static const WCHAR audio_wavW[] = {'a','u','d','i','o','/','w','a','v',0};
787 static const WCHAR image_gifW[] = {'i','m','a','g','e','/','g','i','f',0};
788 static const WCHAR image_pjpegW[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
789 static const WCHAR image_tiffW[] = {'i','m','a','g','e','/','t','i','f','f',0};
790 static const WCHAR image_xpngW[] = {'i','m','a','g','e','/','x','-','p','n','g',0};
791 static const WCHAR image_bmpW[] = {'i','m','a','g','e','/','b','m','p',0};
792 static const WCHAR video_aviW[] = {'v','i','d','e','o','/','a','v','i',0};
793 static const WCHAR video_mpegW[] = {'v','i','d','e','o','/','m','p','e','g',0};
794 static const WCHAR app_postscriptW[] =
795 {'a','p','p','l','i','c','a','t','i','o','n','/','p','o','s','t','s','c','r','i','p','t',0};
796 static const WCHAR app_pdfW[] = {'a','p','p','l','i','c','a','t','i','o','n','/','p','d','f',0};
797 static const WCHAR app_xzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
798 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
799 static const WCHAR app_xgzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
800 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
801 static const WCHAR app_javaW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
802 'j','a','v','a',0};
803 static const WCHAR app_xmsdownloadW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
804 'x','-','m','s','d','o','w','n','l','o','a','d',0};
805 static const WCHAR text_plainW[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
806 static const WCHAR app_octetstreamW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
807 'o','c','t','e','t','-','s','t','r','e','a','m','\0'};
809 static const struct {
810 LPCWSTR mime;
811 BOOL (*filter)(const BYTE *,DWORD);
812 } mime_filters_any_pos[] = {
813 {text_htmlW, text_html_filter},
814 {text_xmlW, text_xml_filter}
815 }, mime_filters[] = {
816 {text_richtextW, text_richtext_filter},
817 /* {audio_xaiffW, audio_xaiff_filter}, */
818 {audio_basicW, audio_basic_filter},
819 {audio_wavW, audio_wav_filter},
820 {image_gifW, image_gif_filter},
821 {image_pjpegW, image_pjpeg_filter},
822 {image_tiffW, image_tiff_filter},
823 {image_xpngW, image_xpng_filter},
824 /* {image_xbitmapW, image_xbitmap_filter}, */
825 {image_bmpW, image_bmp_filter},
826 /* {image_xjgW, image_xjg_filter}, */
827 /* {image_xemfW, image_xemf_filter}, */
828 /* {image_xwmfW, image_xwmf_filter}, */
829 {video_aviW, video_avi_filter},
830 {video_mpegW, video_mpeg_filter},
831 {app_postscriptW, application_postscript_filter},
832 /* {app_base64W, application_base64_filter}, */
833 /* {app_macbinhex40W, application_macbinhex40_filter}, */
834 {app_pdfW, application_pdf_filter},
835 /* {app_zcompressedW, application_xcompressed_filter}, */
836 {app_xzipW, application_xzip_filter},
837 {app_xgzipW, application_xgzip_filter},
838 {app_javaW, application_java_filter},
839 {app_xmsdownloadW, application_xmsdownload},
840 {text_plainW, text_plain_filter},
841 {app_octetstreamW, application_octet_stream_filter}
844 if(!buf || !size) {
845 if(!proposed_mime)
846 return E_FAIL;
848 len = strlenW(proposed_mime)+1;
849 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
850 if(!*ret_mime)
851 return E_OUTOFMEMORY;
853 memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR));
854 return S_OK;
857 if(proposed_mime && (!strcmpW(proposed_mime, app_octetstreamW)
858 || !strcmpW(proposed_mime, text_plainW)))
859 proposed_mime = NULL;
861 if(proposed_mime) {
862 ret = proposed_mime;
864 for(i=0; i < sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
865 if(!strcmpW(proposed_mime, mime_filters_any_pos[i].mime)) {
866 any_pos_mime = i;
867 for(len=size; len>0; len--) {
868 if(mime_filters_any_pos[i].filter(buf+size-len, len))
869 break;
871 if(!len)
872 ret = NULL;
873 break;
877 if(i == sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos)) {
878 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
879 if(!strcmpW(proposed_mime, mime_filters[i].mime)) {
880 if(!mime_filters[i].filter(buf, size))
881 ret = NULL;
882 break;
888 /* Looks like a bug in native implementation, html and xml mimes
889 * are not looked for if none of them was proposed */
890 if(!proposed_mime || any_pos_mime!=-1) {
891 for(len=size; !ret && len>0; len--) {
892 for(i=0; i<sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
893 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
894 ret = mime_filters_any_pos[i].mime;
895 break;
901 i=0;
902 while(!ret) {
903 if(mime_filters[i].filter(buf, size))
904 ret = mime_filters[i].mime;
905 i++;
908 if(any_pos_mime!=-1 && ret==text_plainW)
909 ret = mime_filters_any_pos[any_pos_mime].mime;
910 else if(proposed_mime && ret==app_octetstreamW) {
911 for(len=size; ret==app_octetstreamW && len>0; len--) {
912 if(!is_text_plain_char(buf[size-len]))
913 break;
914 for(i=0; i<sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
915 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
916 ret = text_plainW;
917 break;
922 if(ret == app_octetstreamW)
923 ret = proposed_mime;
925 TRACE("found %s for %s\n", debugstr_w(ret), debugstr_an((const char*)buf, min(32, size)));
927 len = strlenW(ret)+1;
928 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
929 if(!*ret_mime)
930 return E_OUTOFMEMORY;
932 memcpy(*ret_mime, ret, len*sizeof(WCHAR));
933 return S_OK;
936 /***********************************************************************
937 * FindMimeFromData (URLMON.@)
939 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
941 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
942 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
943 LPWSTR* ppwzMimeOut, DWORD dwReserved)
945 TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
946 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
948 if(dwMimeFlags)
949 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
950 if(dwReserved)
951 WARN("dwReserved=%d\n", dwReserved);
953 /* pBC seams to not be used */
955 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
956 return E_INVALIDARG;
958 if(pwzMimeProposed || pBuffer)
959 return find_mime_from_buffer(pBuffer, cbSize, pwzMimeProposed, ppwzMimeOut);
961 if(pwzUrl) {
962 HKEY hkey;
963 DWORD res, size;
964 LPCWSTR ptr;
965 WCHAR mime[64];
967 static const WCHAR wszContentType[] =
968 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
970 ptr = strrchrW(pwzUrl, '.');
971 if(!ptr)
972 return E_FAIL;
974 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
975 if(res != ERROR_SUCCESS)
976 return HRESULT_FROM_WIN32(res);
978 size = sizeof(mime);
979 res = RegQueryValueExW(hkey, wszContentType, NULL, NULL, (LPBYTE)mime, &size);
980 RegCloseKey(hkey);
981 if(res != ERROR_SUCCESS)
982 return HRESULT_FROM_WIN32(res);
984 *ppwzMimeOut = CoTaskMemAlloc(size);
985 memcpy(*ppwzMimeOut, mime, size);
986 return S_OK;
989 return E_FAIL;
992 /***********************************************************************
993 * GetClassFileOrMime (URLMON.@)
995 * Determines the class ID from the bind context, file name or MIME type.
997 HRESULT WINAPI GetClassFileOrMime(LPBC pBC, LPCWSTR pszFilename,
998 LPVOID pBuffer, DWORD cbBuffer, LPCWSTR pszMimeType, DWORD dwReserved,
999 CLSID *pclsid)
1001 FIXME("(%p, %s, %p, %d, %s, 0x%08x, %p): stub\n", pBC, debugstr_w(pszFilename), pBuffer,
1002 cbBuffer, debugstr_w(pszMimeType), dwReserved, pclsid);
1003 return E_NOTIMPL;
1006 /***********************************************************************
1007 * Extract (URLMON.@)
1009 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
1011 HRESULT (WINAPI *pExtract)(void *, LPCSTR);
1013 if (!hCabinet)
1014 hCabinet = LoadLibraryA("cabinet.dll");
1016 if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
1017 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
1018 if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());
1020 return pExtract(dest, szCabName);
1023 /***********************************************************************
1024 * IsLoggingEnabledA (URLMON.@)
1026 BOOL WINAPI IsLoggingEnabledA(LPCSTR url)
1028 FIXME("(%s)\n", debugstr_a(url));
1029 return FALSE;
1032 /***********************************************************************
1033 * IsLoggingEnabledW (URLMON.@)
1035 BOOL WINAPI IsLoggingEnabledW(LPCWSTR url)
1037 FIXME("(%s)\n", debugstr_w(url));
1038 return FALSE;
1041 /***********************************************************************
1042 * IsProtectedModeURL (URLMON.111)
1043 * Undocumented, added in IE7
1045 BOOL WINAPI IsProtectedModeURL(const WCHAR *url)
1047 FIXME("stub: %s\n", debugstr_w(url));
1048 return TRUE;
1051 /***********************************************************************
1052 * LogSqmBits (URLMON.410)
1053 * Undocumented, added in IE8
1055 int WINAPI LogSqmBits(DWORD unk1, DWORD unk2)
1057 FIXME("stub: %d %d\n", unk1, unk2);
1058 return 0;
1061 /***********************************************************************
1062 * LogSqmUXCommandOffsetInternal (URLMON.423)
1063 * Undocumented, added in IE8
1065 void WINAPI LogSqmUXCommandOffsetInternal(DWORD unk1, DWORD unk2, DWORD unk3, DWORD unk4)
1067 FIXME("stub: %d %d %d %d\n", unk1, unk2, unk3, unk4);
1070 /***********************************************************************
1071 * MapUriToBrowserEmulationState (URLMON.444)
1072 * Undocumented, added in IE8
1074 int WINAPI MapUriToBrowserEmulationState(DWORD unk1, DWORD unk2, DWORD unk3)
1076 FIXME("stub: %d %d %d\n", unk1, unk2, unk3);
1077 return 0;
1080 /***********************************************************************
1081 * MapBrowserEmulationModeToUserAgent (URLMON.445)
1082 * Undocumented, added in IE8
1084 int WINAPI MapBrowserEmulationModeToUserAgent(DWORD unk1, DWORD unk2)
1086 FIXME("stub: %d %d\n", unk1, unk2);
1087 return 0;
1090 /***********************************************************************
1091 * RegisterMediaTypes
1092 * Added in IE3, registers known MIME-type strings.
1094 HRESULT WINAPI RegisterMediaTypes(UINT types, LPCSTR *szTypes, CLIPFORMAT *cfTypes)
1096 FIXME("stub: %u %p %p\n", types, szTypes, cfTypes);
1097 return E_INVALIDARG;