4 * Copyright (c) 2000 Patrik Stridvall
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "urlmon_main.h"
27 #define NO_SHLWAPI_REG
32 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
38 DEFINE_GUID(CLSID_CUri, 0xDF2FCE13, 0x25EC, 0x45BB, 0x9D,0x4C, 0xCE,0xCD,0x47,0xC2,0x43,0x0C);
40 LONG URLMON_refCount = 0;
42 static HMODULE hCabinet = NULL;
43 static DWORD urlmon_tls = TLS_OUT_OF_INDEXES;
45 static void init_session(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 =
53 { &tls_cs_dbg.ProcessLocksList, &tls_cs_dbg.ProcessLocksList },
54 0, 0, { (DWORD_PTR)(__FILE__ ": tls") }
57 static CRITICAL_SECTION tls_cs = { &tls_cs_dbg, -1, 0, 0, 0, 0 };
59 tls_data_t *get_tls_data(void)
63 if(urlmon_tls == TLS_OUT_OF_INDEXES) {
64 DWORD tls = TlsAlloc();
65 if(tls == TLS_OUT_OF_INDEXES)
68 tls = InterlockedCompareExchange((LONG*)&urlmon_tls, tls, TLS_OUT_OF_INDEXES);
73 data = TlsGetValue(urlmon_tls);
75 data = heap_alloc_zero(sizeof(tls_data_t));
79 EnterCriticalSection(&tls_cs);
80 list_add_tail(&tls_list, &data->entry);
81 LeaveCriticalSection(&tls_cs);
83 TlsSetValue(urlmon_tls, data);
89 static void free_tls_list(void)
93 if(urlmon_tls == TLS_OUT_OF_INDEXES)
96 while(!list_empty(&tls_list)) {
97 data = LIST_ENTRY(list_head(&tls_list), tls_data_t, entry);
98 list_remove(&data->entry);
105 static void detach_thread(void)
109 if(urlmon_tls == TLS_OUT_OF_INDEXES)
112 data = TlsGetValue(urlmon_tls);
116 EnterCriticalSection(&tls_cs);
117 list_remove(&data->entry);
118 LeaveCriticalSection(&tls_cs);
120 if(data->notif_hwnd) {
121 WARN("notif_hwnd not destroyed\n");
122 DestroyWindow(data->notif_hwnd);
128 static void process_detach(void)
130 HINTERNET internet_session;
132 internet_session = get_internet_session(NULL);
134 InternetCloseHandle(internet_session);
137 FreeLibrary(hCabinet);
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 );
154 case DLL_PROCESS_ATTACH:
158 case DLL_PROCESS_DETACH:
160 DeleteCriticalSection(&tls_cs);
163 case DLL_THREAD_DETACH:
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));
182 /***********************************************************************
183 * DllCanUnloadNow (URLMON.@)
185 HRESULT WINAPI DllCanUnloadNow(void)
187 return URLMON_refCount != 0 ? S_FALSE : S_OK;
192 /******************************************************************************
193 * Urlmon ClassFactory
196 IClassFactory IClassFactory_iface;
198 HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
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)
210 if(IsEqualGUID(riid, &IID_IUnknown)) {
211 TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
213 }else if(IsEqualGUID(riid, &IID_IClassFactory)) {
214 TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv);
219 IUnknown_AddRef((IUnknown*)*ppv);
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)
233 static ULONG WINAPI CF_Release(IClassFactory *iface)
235 URLMON_UnlockModule();
240 static HRESULT WINAPI CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
241 REFIID riid, LPVOID *ppobj)
243 ClassFactory *This = impl_from_IClassFactory(iface);
247 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
250 if(SUCCEEDED(hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk))) {
251 hres = IUnknown_QueryInterface(punk, riid, ppobj);
252 IUnknown_Release(punk);
257 static HRESULT WINAPI CF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
259 TRACE("(%d)\n", dolock);
264 URLMON_UnlockModule();
269 static const IClassFactoryVtbl ClassFactoryVtbl =
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
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)
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
347 * Docs say returns STDAPI
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
356 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
360 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
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);
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);
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)
403 hr = URLMON_DllRegisterServer();
404 return SUCCEEDED(hr) ? register_inf(TRUE) : hr;
407 /***********************************************************************
408 * DllUnregisterServer (URLMON.@)
410 HRESULT WINAPI DllUnregisterServer(void)
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");
430 /**************************************************************************
431 * IsValidURL (URLMON.@)
433 * Determines if a specified string is a valid URL.
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.
443 * returns E_INVALIDARG if one or more of the args is invalid.
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)
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);
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.
490 * pbindinfo [I] BINDINFO to release.
495 void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo)
499 TRACE("(%p)\n", pbindinfo);
501 if(!pbindinfo || !(size = pbindinfo->cbSize))
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);
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);
543 IStream_AddRef(dst->u.pstm);
547 IStorage_AddRef(dst->u.pstg);
550 FIXME("Unimplemented tymed %d\n", src->tymed);
553 if(dst->pUnkForRelease)
554 IUnknown_AddRef(dst->pUnkForRelease);
559 /***********************************************************************
560 * CopyBindInfo (URLMON.@)
562 HRESULT WINAPI CopyBindInfo(const BINDINFO *pcbiSrc, BINDINFO *pcbiDest)
567 TRACE("(%p %p)\n", pcbiSrc, pcbiDest);
569 if(!pcbiSrc || !pcbiDest)
571 if(!pcbiSrc->cbSize || !pcbiDest->cbSize)
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);
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);
596 CoTaskMemFree(pcbiDest->szExtraInfo);
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;
610 memcpy(pcbiDest->szCustomVerb, pcbiSrc->szCustomVerb, size);
613 size = FIELD_OFFSET(BINDINFO, securityAttributes)+sizeof(SECURITY_ATTRIBUTES);
614 if(pcbiDest->cbSize >= size)
615 memset(&pcbiDest->securityAttributes, 0, sizeof(SECURITY_ATTRIBUTES));
618 IUnknown_AddRef(pcbiDest->pUnk);
623 static BOOL text_richtext_filter(const BYTE *b, DWORD size)
625 return size > 5 && !memcmp(b, "{\\rtf", 5);
628 static BOOL text_html_filter(const BYTE *b, DWORD size)
634 && (b[1] == 'h' || b[1] == 'H')
635 && (b[2] == 't' || b[2] == 'T')
636 && (b[3] == 'm' || b[3] == 'M')
637 && (b[4] == 'l' || b[4] == 'L'))
639 && (b[1] == 'h' || b[1] == 'H')
640 && (b[2] == 'e' || b[2] == 'E')
641 && (b[3] == 'a' || b[3] == 'A')
642 && (b[4] == 'd' || b[4] == 'D'))) return TRUE;
647 static BOOL text_xml_filter(const BYTE *b, DWORD size)
652 if(b[0] == '<' && b[1] == '?'
653 && (b[2] == 'x' || b[2] == 'X')
654 && (b[3] == 'm' || b[3] == 'M')
655 && (b[4] == 'l' || b[4] == 'L')
656 && b[5] == ' ') return TRUE;
661 static BOOL audio_basic_filter(const BYTE *b, DWORD size)
664 && b[0] == '.' && b[1] == 's' && b[2] == 'n' && b[3] == 'd';
667 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
670 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
671 && b[8] == 'W' && b[9] == 'A' && b[10] == 'V' && b[11] == 'E';
674 static BOOL image_gif_filter(const BYTE *b, DWORD size)
677 && (b[0] == 'G' || b[0] == 'g')
678 && (b[1] == 'I' || b[1] == 'i')
679 && (b[2] == 'F' || b[2] == 'f')
681 && (b[4] == '7' || b[4] == '9')
682 && (b[5] == 'A' || b[5] == 'a');
685 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
687 return size > 2 && b[0] == 0xff && b[1] == 0xd8;
690 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
692 static const BYTE magic1[] = {0x4d,0x4d,0x00,0x2a};
693 static const BYTE magic2[] = {0x49,0x49,0x2a,0xff};
695 return size >= 4 && (!memcmp(b, magic1, 4) || !memcmp(b, magic2, 4));
698 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
700 static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
701 return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header));
704 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
707 && b[0] == 0x42 && b[1] == 0x4d
708 && *(const DWORD *)(b+6) == 0;
711 static BOOL video_avi_filter(const BYTE *b, DWORD size)
714 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
715 && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20;
718 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
721 && !b[0] && !b[1] && b[2] == 0x01
722 && (b[3] == 0xb3 || b[3] == 0xba);
725 static BOOL application_postscript_filter(const BYTE *b, DWORD size)
727 return size > 2 && b[0] == '%' && b[1] == '!';
730 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
732 return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
735 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
737 return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
740 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
742 return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
745 static BOOL application_java_filter(const BYTE *b, DWORD size)
747 return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
750 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
752 return size > 2 && b[0] == 'M' && b[1] == 'Z';
755 static inline BOOL is_text_plain_char(BYTE b)
757 if(b < 0x20 && b != '\n' && b != '\r' && b != '\t')
762 static BOOL text_plain_filter(const BYTE *b, DWORD size)
766 for(ptr = b; ptr < b+size-1; ptr++) {
767 if(!is_text_plain_char(*ptr))
774 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
779 static HRESULT find_mime_from_buffer(const BYTE *buf, DWORD size, const WCHAR *proposed_mime, WCHAR **ret_mime)
782 int len, i, any_pos_mime = -1;
784 static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0};
785 static const WCHAR text_richtextW[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0};
786 static const WCHAR text_xmlW[] = {'t','e','x','t','/','x','m','l',0};
787 static const WCHAR audio_basicW[] = {'a','u','d','i','o','/','b','a','s','i','c',0};
788 static const WCHAR audio_wavW[] = {'a','u','d','i','o','/','w','a','v',0};
789 static const WCHAR image_gifW[] = {'i','m','a','g','e','/','g','i','f',0};
790 static const WCHAR image_pjpegW[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
791 static const WCHAR image_tiffW[] = {'i','m','a','g','e','/','t','i','f','f',0};
792 static const WCHAR image_xpngW[] = {'i','m','a','g','e','/','x','-','p','n','g',0};
793 static const WCHAR image_bmpW[] = {'i','m','a','g','e','/','b','m','p',0};
794 static const WCHAR video_aviW[] = {'v','i','d','e','o','/','a','v','i',0};
795 static const WCHAR video_mpegW[] = {'v','i','d','e','o','/','m','p','e','g',0};
796 static const WCHAR app_postscriptW[] =
797 {'a','p','p','l','i','c','a','t','i','o','n','/','p','o','s','t','s','c','r','i','p','t',0};
798 static const WCHAR app_pdfW[] = {'a','p','p','l','i','c','a','t','i','o','n','/','p','d','f',0};
799 static const WCHAR app_xzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
800 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
801 static const WCHAR app_xgzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
802 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
803 static const WCHAR app_javaW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
805 static const WCHAR app_xmsdownloadW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
806 'x','-','m','s','d','o','w','n','l','o','a','d',0};
807 static const WCHAR text_plainW[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
808 static const WCHAR app_octetstreamW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
809 'o','c','t','e','t','-','s','t','r','e','a','m','\0'};
811 static const struct {
813 BOOL (*filter)(const BYTE *,DWORD);
814 } mime_filters_any_pos[] = {
815 {text_htmlW, text_html_filter},
816 {text_xmlW, text_xml_filter}
817 }, mime_filters[] = {
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}
850 len = strlenW(proposed_mime)+1;
851 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
853 return E_OUTOFMEMORY;
855 memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR));
859 if(proposed_mime && (!strcmpW(proposed_mime, app_octetstreamW)
860 || !strcmpW(proposed_mime, text_plainW)))
861 proposed_mime = NULL;
866 for(i=0; i < sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
867 if(!strcmpW(proposed_mime, mime_filters_any_pos[i].mime)) {
869 for(len=size; len>0; len--) {
870 if(mime_filters_any_pos[i].filter(buf+size-len, len))
879 if(i == sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos)) {
880 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
881 if(!strcmpW(proposed_mime, mime_filters[i].mime)) {
882 if(!mime_filters[i].filter(buf, size))
890 /* Looks like a bug in native implementation, html and xml mimes
891 * are not looked for if none of them was proposed */
892 if(!proposed_mime || any_pos_mime!=-1) {
893 for(len=size; !ret && len>0; len--) {
894 for(i=0; i<sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
895 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
896 ret = mime_filters_any_pos[i].mime;
905 if(mime_filters[i].filter(buf, size))
906 ret = mime_filters[i].mime;
910 if(any_pos_mime!=-1 && ret==text_plainW)
911 ret = mime_filters_any_pos[any_pos_mime].mime;
912 else if(proposed_mime && ret==app_octetstreamW) {
913 for(len=size; ret==app_octetstreamW && len>0; len--) {
914 if(!is_text_plain_char(buf[size-len]))
916 for(i=0; i<sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
917 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
924 if(ret == app_octetstreamW)
927 TRACE("found %s for %s\n", debugstr_w(ret), debugstr_an((const char*)buf, min(32, size)));
929 len = strlenW(ret)+1;
930 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
932 return E_OUTOFMEMORY;
934 memcpy(*ret_mime, ret, len*sizeof(WCHAR));
938 /***********************************************************************
939 * FindMimeFromData (URLMON.@)
941 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
943 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
944 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
945 LPWSTR* ppwzMimeOut, DWORD dwReserved)
947 TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
948 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
951 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
953 WARN("dwReserved=%d\n", dwReserved);
955 /* pBC seams to not be used */
957 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
960 if(pwzMimeProposed || pBuffer)
961 return find_mime_from_buffer(pBuffer, cbSize, pwzMimeProposed, ppwzMimeOut);
969 static const WCHAR wszContentType[] =
970 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
972 ptr = strrchrW(pwzUrl, '.');
976 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
977 if(res != ERROR_SUCCESS)
978 return HRESULT_FROM_WIN32(res);
981 res = RegQueryValueExW(hkey, wszContentType, NULL, NULL, (LPBYTE)mime, &size);
983 if(res != ERROR_SUCCESS)
984 return HRESULT_FROM_WIN32(res);
986 *ppwzMimeOut = CoTaskMemAlloc(size);
987 memcpy(*ppwzMimeOut, mime, size);
994 /***********************************************************************
995 * GetClassFileOrMime (URLMON.@)
997 * Determines the class ID from the bind context, file name or MIME type.
999 HRESULT WINAPI GetClassFileOrMime(LPBC pBC, LPCWSTR pszFilename,
1000 LPVOID pBuffer, DWORD cbBuffer, LPCWSTR pszMimeType, DWORD dwReserved,
1003 FIXME("(%p, %s, %p, %d, %p, 0x%08x, %p): stub\n", pBC,
1004 debugstr_w(pszFilename), pBuffer, cbBuffer, debugstr_w(pszMimeType),
1005 dwReserved, pclsid);
1009 /***********************************************************************
1010 * Extract (URLMON.@)
1012 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
1014 HRESULT (WINAPI *pExtract)(void *, LPCSTR);
1017 hCabinet = LoadLibraryA("cabinet.dll");
1019 if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
1020 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
1021 if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());
1023 return pExtract(dest, szCabName);
1026 /***********************************************************************
1027 * IsLoggingEnabledA (URLMON.@)
1029 BOOL WINAPI IsLoggingEnabledA(LPCSTR url)
1031 FIXME("(%s)\n", debugstr_a(url));
1035 /***********************************************************************
1036 * IsLoggingEnabledW (URLMON.@)
1038 BOOL WINAPI IsLoggingEnabledW(LPCWSTR url)
1040 FIXME("(%s)\n", debugstr_w(url));
1044 /***********************************************************************
1045 * IsProtectedModeURL (URLMON.111)
1046 * Undocumented, added in IE7
1048 BOOL WINAPI IsProtectedModeURL(const WCHAR *url)
1050 FIXME("stub: %s\n", debugstr_w(url));
1054 /***********************************************************************
1055 * LogSqmBits (URLMON.410)
1056 * Undocumented, added in IE8
1058 int WINAPI LogSqmBits(DWORD unk1, DWORD unk2)
1060 FIXME("stub: %d %d\n", unk1, unk2);
1064 /***********************************************************************
1065 * LogSqmUXCommandOffsetInternal (URLMON.423)
1066 * Undocumented, added in IE8
1068 void WINAPI LogSqmUXCommandOffsetInternal(DWORD unk1, DWORD unk2, DWORD unk3, DWORD unk4)
1070 FIXME("stub: %d %d %d %d\n", unk1, unk2, unk3, unk4);
1073 /***********************************************************************
1074 * MapUriToBrowserEmulationState (URLMON.444)
1075 * Undocumented, added in IE8
1077 int WINAPI MapUriToBrowserEmulationState(DWORD unk1, DWORD unk2, DWORD unk3)
1079 FIXME("stub: %d %d %d\n", unk1, unk2, unk3);
1083 /***********************************************************************
1084 * MapBrowserEmulationModeToUserAgent (URLMON.445)
1085 * Undocumented, added in IE8
1087 int WINAPI MapBrowserEmulationModeToUserAgent(DWORD unk1, DWORD unk2)
1089 FIXME("stub: %d %d\n", unk1, unk2);
1093 /***********************************************************************
1094 * RegisterMediaTypes
1095 * Added in IE3, registers known MIME-type strings.
1097 HRESULT WINAPI RegisterMediaTypes(UINT types, LPCSTR *szTypes, CLIPFORMAT *cfTypes)
1099 FIXME("stub: %u %p %p\n", types, szTypes, cfTypes);
1100 return E_INVALIDARG;