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;
41 HINSTANCE urlmon_instance;
43 static HMODULE hCabinet = NULL;
44 static DWORD urlmon_tls = TLS_OUT_OF_INDEXES;
46 static void init_session(void);
48 static struct list tls_list = LIST_INIT(tls_list);
50 static CRITICAL_SECTION tls_cs;
51 static CRITICAL_SECTION_DEBUG tls_cs_dbg =
54 { &tls_cs_dbg.ProcessLocksList, &tls_cs_dbg.ProcessLocksList },
55 0, 0, { (DWORD_PTR)(__FILE__ ": tls") }
58 static CRITICAL_SECTION tls_cs = { &tls_cs_dbg, -1, 0, 0, 0, 0 };
60 tls_data_t *get_tls_data(void)
64 if(urlmon_tls == TLS_OUT_OF_INDEXES) {
65 DWORD tls = TlsAlloc();
66 if(tls == TLS_OUT_OF_INDEXES)
69 tls = InterlockedCompareExchange((LONG*)&urlmon_tls, tls, TLS_OUT_OF_INDEXES);
74 data = TlsGetValue(urlmon_tls);
76 data = heap_alloc_zero(sizeof(tls_data_t));
80 EnterCriticalSection(&tls_cs);
81 list_add_tail(&tls_list, &data->entry);
82 LeaveCriticalSection(&tls_cs);
84 TlsSetValue(urlmon_tls, data);
90 static void free_tls_list(void)
94 if(urlmon_tls == TLS_OUT_OF_INDEXES)
97 while(!list_empty(&tls_list)) {
98 data = LIST_ENTRY(list_head(&tls_list), tls_data_t, entry);
99 list_remove(&data->entry);
106 static void detach_thread(void)
110 if(urlmon_tls == TLS_OUT_OF_INDEXES)
113 data = TlsGetValue(urlmon_tls);
117 EnterCriticalSection(&tls_cs);
118 list_remove(&data->entry);
119 LeaveCriticalSection(&tls_cs);
121 if(data->notif_hwnd) {
122 WARN("notif_hwnd not destroyed\n");
123 DestroyWindow(data->notif_hwnd);
129 static void process_detach(void)
131 HINTERNET internet_session;
133 internet_session = get_internet_session(NULL);
135 InternetCloseHandle(internet_session);
138 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:
155 urlmon_instance = hinstDLL;
159 case DLL_PROCESS_DETACH:
161 DeleteCriticalSection(&tls_cs);
164 case DLL_THREAD_DETACH:
171 const char *debugstr_bindstatus(ULONG status)
174 #define X(x) case x: return #x
175 X(BINDSTATUS_FINDINGRESOURCE);
176 X(BINDSTATUS_CONNECTING);
177 X(BINDSTATUS_REDIRECTING);
178 X(BINDSTATUS_BEGINDOWNLOADDATA);
179 X(BINDSTATUS_DOWNLOADINGDATA);
180 X(BINDSTATUS_ENDDOWNLOADDATA);
181 X(BINDSTATUS_BEGINDOWNLOADCOMPONENTS);
182 X(BINDSTATUS_INSTALLINGCOMPONENTS);
183 X(BINDSTATUS_ENDDOWNLOADCOMPONENTS);
184 X(BINDSTATUS_USINGCACHEDCOPY);
185 X(BINDSTATUS_SENDINGREQUEST);
186 X(BINDSTATUS_CLASSIDAVAILABLE);
187 X(BINDSTATUS_MIMETYPEAVAILABLE);
188 X(BINDSTATUS_CACHEFILENAMEAVAILABLE);
189 X(BINDSTATUS_BEGINSYNCOPERATION);
190 X(BINDSTATUS_ENDSYNCOPERATION);
191 X(BINDSTATUS_BEGINUPLOADDATA);
192 X(BINDSTATUS_UPLOADINGDATA);
193 X(BINDSTATUS_ENDUPLOADINGDATA);
194 X(BINDSTATUS_PROTOCOLCLASSID);
195 X(BINDSTATUS_ENCODING);
196 X(BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE);
197 X(BINDSTATUS_CLASSINSTALLLOCATION);
198 X(BINDSTATUS_DECODING);
199 X(BINDSTATUS_LOADINGMIMEHANDLER);
200 X(BINDSTATUS_CONTENTDISPOSITIONATTACH);
201 X(BINDSTATUS_FILTERREPORTMIMETYPE);
202 X(BINDSTATUS_CLSIDCANINSTANTIATE);
203 X(BINDSTATUS_IUNKNOWNAVAILABLE);
204 X(BINDSTATUS_DIRECTBIND);
205 X(BINDSTATUS_RAWMIMETYPE);
206 X(BINDSTATUS_PROXYDETECTING);
207 X(BINDSTATUS_ACCEPTRANGES);
208 X(BINDSTATUS_COOKIE_SENT);
209 X(BINDSTATUS_COMPACT_POLICY_RECEIVED);
210 X(BINDSTATUS_COOKIE_SUPPRESSED);
211 X(BINDSTATUS_COOKIE_STATE_UNKNOWN);
212 X(BINDSTATUS_COOKIE_STATE_ACCEPT);
213 X(BINDSTATUS_COOKIE_STATE_REJECT);
214 X(BINDSTATUS_COOKIE_STATE_PROMPT);
215 X(BINDSTATUS_COOKIE_STATE_LEASH);
216 X(BINDSTATUS_COOKIE_STATE_DOWNGRADE);
217 X(BINDSTATUS_POLICY_HREF);
218 X(BINDSTATUS_P3P_HEADER);
219 X(BINDSTATUS_SESSION_COOKIE_RECEIVED);
220 X(BINDSTATUS_PERSISTENT_COOKIE_RECEIVED);
221 X(BINDSTATUS_SESSION_COOKIES_ALLOWED);
222 X(BINDSTATUS_CACHECONTROL);
223 X(BINDSTATUS_CONTENTDISPOSITIONFILENAME);
224 X(BINDSTATUS_MIMETEXTPLAINMISMATCH);
225 X(BINDSTATUS_PUBLISHERAVAILABLE);
226 X(BINDSTATUS_DISPLAYNAMEAVAILABLE);
229 return wine_dbg_sprintf("(invalid status %u)", status);
233 /***********************************************************************
234 * DllInstall (URLMON.@)
236 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
238 FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
239 debugstr_w(cmdline));
244 /***********************************************************************
245 * DllCanUnloadNow (URLMON.@)
247 HRESULT WINAPI DllCanUnloadNow(void)
249 return URLMON_refCount != 0 ? S_FALSE : S_OK;
254 /******************************************************************************
255 * Urlmon ClassFactory
258 IClassFactory IClassFactory_iface;
260 HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
263 static inline ClassFactory *impl_from_IClassFactory(IClassFactory *iface)
265 return CONTAINING_RECORD(iface, ClassFactory, IClassFactory_iface);
268 static HRESULT WINAPI CF_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppv)
272 if(IsEqualGUID(riid, &IID_IUnknown)) {
273 TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
275 }else if(IsEqualGUID(riid, &IID_IClassFactory)) {
276 TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv);
281 IUnknown_AddRef((IUnknown*)*ppv);
285 WARN("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ppv);
286 return E_NOINTERFACE;
289 static ULONG WINAPI CF_AddRef(IClassFactory *iface)
295 static ULONG WINAPI CF_Release(IClassFactory *iface)
297 URLMON_UnlockModule();
302 static HRESULT WINAPI CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
303 REFIID riid, LPVOID *ppobj)
305 ClassFactory *This = impl_from_IClassFactory(iface);
309 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
312 if(SUCCEEDED(hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk))) {
313 hres = IUnknown_QueryInterface(punk, riid, ppobj);
314 IUnknown_Release(punk);
319 static HRESULT WINAPI CF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
321 TRACE("(%d)\n", dolock);
326 URLMON_UnlockModule();
331 static const IClassFactoryVtbl ClassFactoryVtbl =
340 static ClassFactory FileProtocolCF =
341 { { &ClassFactoryVtbl }, FileProtocol_Construct};
342 static ClassFactory FtpProtocolCF =
343 { { &ClassFactoryVtbl }, FtpProtocol_Construct};
344 static ClassFactory GopherProtocolCF =
345 { { &ClassFactoryVtbl }, GopherProtocol_Construct};
346 static ClassFactory HttpProtocolCF =
347 { { &ClassFactoryVtbl }, HttpProtocol_Construct};
348 static ClassFactory HttpSProtocolCF =
349 { { &ClassFactoryVtbl }, HttpSProtocol_Construct};
350 static ClassFactory MkProtocolCF =
351 { { &ClassFactoryVtbl }, MkProtocol_Construct};
352 static ClassFactory SecurityManagerCF =
353 { { &ClassFactoryVtbl }, SecManagerImpl_Construct};
354 static ClassFactory ZoneManagerCF =
355 { { &ClassFactoryVtbl }, ZoneMgrImpl_Construct};
356 static ClassFactory StdURLMonikerCF =
357 { { &ClassFactoryVtbl }, StdURLMoniker_Construct};
358 static ClassFactory MimeFilterCF =
359 { { &ClassFactoryVtbl }, MimeFilter_Construct};
360 static ClassFactory CUriCF =
361 { { &ClassFactoryVtbl }, Uri_Construct};
363 struct object_creation_info
370 static const WCHAR wszFile[] = {'f','i','l','e',0};
371 static const WCHAR wszFtp[] = {'f','t','p',0};
372 static const WCHAR wszGopher[] = {'g','o','p','h','e','r',0};
373 static const WCHAR wszHttp[] = {'h','t','t','p',0};
374 static const WCHAR wszHttps[] = {'h','t','t','p','s',0};
375 static const WCHAR wszMk[] = {'m','k',0};
377 static const struct object_creation_info object_creation[] =
379 { &CLSID_FileProtocol, &FileProtocolCF.IClassFactory_iface, wszFile },
380 { &CLSID_FtpProtocol, &FtpProtocolCF.IClassFactory_iface, wszFtp },
381 { &CLSID_GopherProtocol, &GopherProtocolCF.IClassFactory_iface, wszGopher },
382 { &CLSID_HttpProtocol, &HttpProtocolCF.IClassFactory_iface, wszHttp },
383 { &CLSID_HttpSProtocol, &HttpSProtocolCF.IClassFactory_iface, wszHttps },
384 { &CLSID_MkProtocol, &MkProtocolCF.IClassFactory_iface, wszMk },
385 { &CLSID_InternetSecurityManager, &SecurityManagerCF.IClassFactory_iface, NULL },
386 { &CLSID_InternetZoneManager, &ZoneManagerCF.IClassFactory_iface, NULL },
387 { &CLSID_StdURLMoniker, &StdURLMonikerCF.IClassFactory_iface, NULL },
388 { &CLSID_DeCompMimeFilter, &MimeFilterCF.IClassFactory_iface, NULL },
389 { &CLSID_CUri, &CUriCF.IClassFactory_iface, NULL }
392 static void init_session(void)
396 for(i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) {
397 if(object_creation[i].protocol)
398 register_namespace(object_creation[i].cf, object_creation[i].clsid,
399 object_creation[i].protocol, TRUE);
403 /*******************************************************************************
404 * DllGetClassObject [URLMON.@]
405 * Retrieves class object from a DLL object
408 * Docs say returns STDAPI
411 * rclsid [I] CLSID for the class object
412 * riid [I] Reference to identifier of interface for class object
413 * ppv [O] Address of variable to receive interface pointer for riid
417 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
421 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
426 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
428 for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
430 if (IsEqualGUID(object_creation[i].clsid, rclsid))
431 return IClassFactory_QueryInterface(object_creation[i].cf, riid, ppv);
434 hr = URLMON_DllGetClassObject(rclsid, riid, ppv);
438 FIXME("%s: no class found.\n", debugstr_guid(rclsid));
439 return CLASS_E_CLASSNOTAVAILABLE;
442 static HRESULT register_inf(BOOL doregister)
444 HRESULT (WINAPI *pRegInstall)(HMODULE hm, LPCSTR pszSection, const STRTABLEA* pstTable);
447 static const WCHAR wszAdvpack[] = {'a','d','v','p','a','c','k','.','d','l','l',0};
449 hAdvpack = LoadLibraryW(wszAdvpack);
450 pRegInstall = (void *)GetProcAddress(hAdvpack, "RegInstall");
452 return pRegInstall(hProxyDll, doregister ? "RegisterDll" : "UnregisterDll", NULL);
455 /***********************************************************************
456 * DllRegisterServer (URLMON.@)
458 HRESULT WINAPI DllRegisterServer(void)
464 hr = URLMON_DllRegisterServer();
465 return SUCCEEDED(hr) ? register_inf(TRUE) : hr;
468 /***********************************************************************
469 * DllUnregisterServer (URLMON.@)
471 HRESULT WINAPI DllUnregisterServer(void)
477 hr = URLMON_DllUnregisterServer();
478 return SUCCEEDED(hr) ? register_inf(FALSE) : hr;
481 /***********************************************************************
482 * DllRegisterServerEx (URLMON.@)
484 HRESULT WINAPI DllRegisterServerEx(void)
486 FIXME("(void): stub\n");
491 /**************************************************************************
492 * IsValidURL (URLMON.@)
494 * Determines if a specified string is a valid URL.
497 * pBC [I] ignored, should be NULL.
498 * szURL [I] string that represents the URL in question.
499 * dwReserved [I] reserved and must be zero.
504 * returns E_INVALIDARG if one or more of the args is invalid.
507 * test functionality against windows to see what a valid URL is.
509 HRESULT WINAPI IsValidURL(LPBC pBC, LPCWSTR szURL, DWORD dwReserved)
511 FIXME("(%p, %s, %d): stub\n", pBC, debugstr_w(szURL), dwReserved);
513 if (dwReserved || !szURL)
519 /**************************************************************************
520 * FaultInIEFeature (URLMON.@)
522 * Undocumented. Appears to be used by native shdocvw.dll.
524 HRESULT WINAPI FaultInIEFeature( HWND hwnd, uCLSSPEC * pClassSpec,
525 QUERYCONTEXT *pQuery, DWORD flags )
527 FIXME("%p %p %p %08x\n", hwnd, pClassSpec, pQuery, flags);
531 /**************************************************************************
532 * CoGetClassObjectFromURL (URLMON.@)
534 HRESULT WINAPI CoGetClassObjectFromURL( REFCLSID rclsid, LPCWSTR szCodeURL, DWORD dwFileVersionMS,
535 DWORD dwFileVersionLS, LPCWSTR szContentType,
536 LPBINDCTX pBindCtx, DWORD dwClsContext, LPVOID pvReserved,
537 REFIID riid, LPVOID *ppv )
539 FIXME("(%s %s %d %d %s %p %d %p %s %p) Stub!\n", debugstr_guid(rclsid), debugstr_w(szCodeURL),
540 dwFileVersionMS, dwFileVersionLS, debugstr_w(szContentType), pBindCtx, dwClsContext, pvReserved,
541 debugstr_guid(riid), ppv);
542 return E_NOINTERFACE;
545 /***********************************************************************
546 * ReleaseBindInfo (URLMON.@)
548 * Release the resources used by the specified BINDINFO structure.
551 * pbindinfo [I] BINDINFO to release.
556 void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo)
560 TRACE("(%p)\n", pbindinfo);
562 if(!pbindinfo || !(size = pbindinfo->cbSize))
565 CoTaskMemFree(pbindinfo->szExtraInfo);
566 ReleaseStgMedium(&pbindinfo->stgmedData);
568 if(offsetof(BINDINFO, szExtraInfo) < size)
569 CoTaskMemFree(pbindinfo->szCustomVerb);
571 if(pbindinfo->pUnk && offsetof(BINDINFO, pUnk) < size)
572 IUnknown_Release(pbindinfo->pUnk);
574 memset(pbindinfo, 0, size);
575 pbindinfo->cbSize = size;
578 /***********************************************************************
579 * CopyStgMedium (URLMON.@)
581 HRESULT WINAPI CopyStgMedium(const STGMEDIUM *src, STGMEDIUM *dst)
583 TRACE("(%p %p)\n", src, dst);
594 if(src->u.lpszFileName && !src->pUnkForRelease) {
595 DWORD size = (strlenW(src->u.lpszFileName)+1)*sizeof(WCHAR);
596 dst->u.lpszFileName = CoTaskMemAlloc(size);
597 if(!dst->u.lpszFileName)
598 return E_OUTOFMEMORY;
599 memcpy(dst->u.lpszFileName, src->u.lpszFileName, size);
604 IStream_AddRef(dst->u.pstm);
608 IStorage_AddRef(dst->u.pstg);
612 SIZE_T size = GlobalSize(src->u.hGlobal);
613 char *src_ptr, *dst_ptr;
615 dst->u.hGlobal = GlobalAlloc(GMEM_FIXED, size);
617 return E_OUTOFMEMORY;
618 dst_ptr = GlobalLock(dst->u.hGlobal);
619 src_ptr = GlobalLock(src->u.hGlobal);
620 memcpy(dst_ptr, src_ptr, size);
621 GlobalUnlock(src_ptr);
622 GlobalUnlock(dst_ptr);
626 FIXME("Unimplemented tymed %d\n", src->tymed);
629 if(dst->pUnkForRelease)
630 IUnknown_AddRef(dst->pUnkForRelease);
635 /***********************************************************************
636 * CopyBindInfo (URLMON.@)
638 HRESULT WINAPI CopyBindInfo(const BINDINFO *pcbiSrc, BINDINFO *pcbiDest)
643 TRACE("(%p %p)\n", pcbiSrc, pcbiDest);
645 if(!pcbiSrc || !pcbiDest)
647 if(!pcbiSrc->cbSize || !pcbiDest->cbSize)
650 size = pcbiDest->cbSize;
651 if(size > pcbiSrc->cbSize) {
652 memcpy(pcbiDest, pcbiSrc, pcbiSrc->cbSize);
653 memset((char*)pcbiDest+pcbiSrc->cbSize, 0, size-pcbiSrc->cbSize);
655 memcpy(pcbiDest, pcbiSrc, size);
657 pcbiDest->cbSize = size;
659 size = FIELD_OFFSET(BINDINFO, szExtraInfo)+sizeof(void*);
660 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size && pcbiSrc->szExtraInfo) {
661 size = (strlenW(pcbiSrc->szExtraInfo)+1)*sizeof(WCHAR);
662 pcbiDest->szExtraInfo = CoTaskMemAlloc(size);
663 if(!pcbiDest->szExtraInfo)
664 return E_OUTOFMEMORY;
665 memcpy(pcbiDest->szExtraInfo, pcbiSrc->szExtraInfo, size);
668 size = FIELD_OFFSET(BINDINFO, stgmedData)+sizeof(STGMEDIUM);
669 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size) {
670 hres = CopyStgMedium(&pcbiSrc->stgmedData, &pcbiDest->stgmedData);
672 CoTaskMemFree(pcbiDest->szExtraInfo);
677 size = FIELD_OFFSET(BINDINFO, szCustomVerb)+sizeof(void*);
678 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size && pcbiSrc->szCustomVerb) {
679 size = (strlenW(pcbiSrc->szCustomVerb)+1)*sizeof(WCHAR);
680 pcbiDest->szCustomVerb = CoTaskMemAlloc(size);
681 if(!pcbiDest->szCustomVerb) {
682 CoTaskMemFree(pcbiDest->szExtraInfo);
683 ReleaseStgMedium(&pcbiDest->stgmedData);
684 return E_OUTOFMEMORY;
686 memcpy(pcbiDest->szCustomVerb, pcbiSrc->szCustomVerb, size);
689 size = FIELD_OFFSET(BINDINFO, securityAttributes)+sizeof(SECURITY_ATTRIBUTES);
690 if(pcbiDest->cbSize >= size)
691 memset(&pcbiDest->securityAttributes, 0, sizeof(SECURITY_ATTRIBUTES));
694 IUnknown_AddRef(pcbiDest->pUnk);
699 static BOOL text_richtext_filter(const BYTE *b, DWORD size)
701 return size > 5 && !memcmp(b, "{\\rtf", 5);
704 static BOOL text_html_filter(const BYTE *b, DWORD size)
710 && (b[1] == 'h' || b[1] == 'H')
711 && (b[2] == 't' || b[2] == 'T')
712 && (b[3] == 'm' || b[3] == 'M')
713 && (b[4] == 'l' || b[4] == 'L'))
715 && (b[1] == 'h' || b[1] == 'H')
716 && (b[2] == 'e' || b[2] == 'E')
717 && (b[3] == 'a' || b[3] == 'A')
718 && (b[4] == 'd' || b[4] == 'D'))) return TRUE;
723 static BOOL text_xml_filter(const BYTE *b, DWORD size)
728 if(b[0] == '<' && b[1] == '?'
729 && (b[2] == 'x' || b[2] == 'X')
730 && (b[3] == 'm' || b[3] == 'M')
731 && (b[4] == 'l' || b[4] == 'L')
732 && b[5] == ' ') return TRUE;
737 static BOOL audio_basic_filter(const BYTE *b, DWORD size)
740 && b[0] == '.' && b[1] == 's' && b[2] == 'n' && b[3] == 'd';
743 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
746 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
747 && b[8] == 'W' && b[9] == 'A' && b[10] == 'V' && b[11] == 'E';
750 static BOOL image_gif_filter(const BYTE *b, DWORD size)
753 && (b[0] == 'G' || b[0] == 'g')
754 && (b[1] == 'I' || b[1] == 'i')
755 && (b[2] == 'F' || b[2] == 'f')
757 && (b[4] == '7' || b[4] == '9')
758 && (b[5] == 'A' || b[5] == 'a');
761 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
763 return size > 2 && b[0] == 0xff && b[1] == 0xd8;
766 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
768 static const BYTE magic1[] = {0x4d,0x4d,0x00,0x2a};
769 static const BYTE magic2[] = {0x49,0x49,0x2a,0xff};
771 return size >= 4 && (!memcmp(b, magic1, 4) || !memcmp(b, magic2, 4));
774 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
776 static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
777 return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header));
780 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
783 && b[0] == 0x42 && b[1] == 0x4d
784 && *(const DWORD *)(b+6) == 0;
787 static BOOL video_avi_filter(const BYTE *b, DWORD size)
790 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
791 && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20;
794 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
797 && !b[0] && !b[1] && b[2] == 0x01
798 && (b[3] == 0xb3 || b[3] == 0xba);
801 static BOOL application_postscript_filter(const BYTE *b, DWORD size)
803 return size > 2 && b[0] == '%' && b[1] == '!';
806 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
808 return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
811 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
813 return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
816 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
818 return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
821 static BOOL application_java_filter(const BYTE *b, DWORD size)
823 return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
826 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
828 return size > 2 && b[0] == 'M' && b[1] == 'Z';
831 static inline BOOL is_text_plain_char(BYTE b)
833 if(b < 0x20 && b != '\n' && b != '\r' && b != '\t')
838 static BOOL text_plain_filter(const BYTE *b, DWORD size)
842 for(ptr = b; ptr < b+size-1; ptr++) {
843 if(!is_text_plain_char(*ptr))
850 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
855 static HRESULT find_mime_from_buffer(const BYTE *buf, DWORD size, const WCHAR *proposed_mime, WCHAR **ret_mime)
858 int len, i, any_pos_mime = -1;
860 static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0};
861 static const WCHAR text_richtextW[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0};
862 static const WCHAR text_xmlW[] = {'t','e','x','t','/','x','m','l',0};
863 static const WCHAR audio_basicW[] = {'a','u','d','i','o','/','b','a','s','i','c',0};
864 static const WCHAR audio_wavW[] = {'a','u','d','i','o','/','w','a','v',0};
865 static const WCHAR image_gifW[] = {'i','m','a','g','e','/','g','i','f',0};
866 static const WCHAR image_pjpegW[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
867 static const WCHAR image_tiffW[] = {'i','m','a','g','e','/','t','i','f','f',0};
868 static const WCHAR image_xpngW[] = {'i','m','a','g','e','/','x','-','p','n','g',0};
869 static const WCHAR image_bmpW[] = {'i','m','a','g','e','/','b','m','p',0};
870 static const WCHAR video_aviW[] = {'v','i','d','e','o','/','a','v','i',0};
871 static const WCHAR video_mpegW[] = {'v','i','d','e','o','/','m','p','e','g',0};
872 static const WCHAR app_postscriptW[] =
873 {'a','p','p','l','i','c','a','t','i','o','n','/','p','o','s','t','s','c','r','i','p','t',0};
874 static const WCHAR app_pdfW[] = {'a','p','p','l','i','c','a','t','i','o','n','/','p','d','f',0};
875 static const WCHAR app_xzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
876 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
877 static const WCHAR app_xgzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
878 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
879 static const WCHAR app_javaW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
881 static const WCHAR app_xmsdownloadW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
882 'x','-','m','s','d','o','w','n','l','o','a','d',0};
883 static const WCHAR text_plainW[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
884 static const WCHAR app_octetstreamW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
885 'o','c','t','e','t','-','s','t','r','e','a','m','\0'};
887 static const struct {
889 BOOL (*filter)(const BYTE *,DWORD);
890 } mime_filters_any_pos[] = {
891 {text_htmlW, text_html_filter},
892 {text_xmlW, text_xml_filter}
893 }, mime_filters[] = {
894 {text_richtextW, text_richtext_filter},
895 /* {audio_xaiffW, audio_xaiff_filter}, */
896 {audio_basicW, audio_basic_filter},
897 {audio_wavW, audio_wav_filter},
898 {image_gifW, image_gif_filter},
899 {image_pjpegW, image_pjpeg_filter},
900 {image_tiffW, image_tiff_filter},
901 {image_xpngW, image_xpng_filter},
902 /* {image_xbitmapW, image_xbitmap_filter}, */
903 {image_bmpW, image_bmp_filter},
904 /* {image_xjgW, image_xjg_filter}, */
905 /* {image_xemfW, image_xemf_filter}, */
906 /* {image_xwmfW, image_xwmf_filter}, */
907 {video_aviW, video_avi_filter},
908 {video_mpegW, video_mpeg_filter},
909 {app_postscriptW, application_postscript_filter},
910 /* {app_base64W, application_base64_filter}, */
911 /* {app_macbinhex40W, application_macbinhex40_filter}, */
912 {app_pdfW, application_pdf_filter},
913 /* {app_zcompressedW, application_xcompressed_filter}, */
914 {app_xzipW, application_xzip_filter},
915 {app_xgzipW, application_xgzip_filter},
916 {app_javaW, application_java_filter},
917 {app_xmsdownloadW, application_xmsdownload},
918 {text_plainW, text_plain_filter},
919 {app_octetstreamW, application_octet_stream_filter}
926 len = strlenW(proposed_mime)+1;
927 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
929 return E_OUTOFMEMORY;
931 memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR));
935 if(proposed_mime && (!strcmpW(proposed_mime, app_octetstreamW)
936 || !strcmpW(proposed_mime, text_plainW)))
937 proposed_mime = NULL;
942 for(i=0; i < sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
943 if(!strcmpW(proposed_mime, mime_filters_any_pos[i].mime)) {
945 for(len=size; len>0; len--) {
946 if(mime_filters_any_pos[i].filter(buf+size-len, len))
955 if(i == sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos)) {
956 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
957 if(!strcmpW(proposed_mime, mime_filters[i].mime)) {
958 if(!mime_filters[i].filter(buf, size))
966 /* Looks like a bug in native implementation, html and xml mimes
967 * are not looked for if none of them was proposed */
968 if(!proposed_mime || any_pos_mime!=-1) {
969 for(len=size; !ret && len>0; len--) {
970 for(i=0; i<sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
971 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
972 ret = mime_filters_any_pos[i].mime;
981 if(mime_filters[i].filter(buf, size))
982 ret = mime_filters[i].mime;
986 if(any_pos_mime!=-1 && ret==text_plainW)
987 ret = mime_filters_any_pos[any_pos_mime].mime;
988 else if(proposed_mime && ret==app_octetstreamW) {
989 for(len=size; ret==app_octetstreamW && len>0; len--) {
990 if(!is_text_plain_char(buf[size-len]))
992 for(i=0; i<sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
993 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
1000 if(ret == app_octetstreamW)
1001 ret = proposed_mime;
1003 TRACE("found %s for %s\n", debugstr_w(ret), debugstr_an((const char*)buf, min(32, size)));
1005 len = strlenW(ret)+1;
1006 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
1008 return E_OUTOFMEMORY;
1010 memcpy(*ret_mime, ret, len*sizeof(WCHAR));
1014 /***********************************************************************
1015 * FindMimeFromData (URLMON.@)
1017 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
1019 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
1020 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
1021 LPWSTR* ppwzMimeOut, DWORD dwReserved)
1023 TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
1024 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
1027 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
1029 WARN("dwReserved=%d\n", dwReserved);
1031 /* pBC seams to not be used */
1033 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
1034 return E_INVALIDARG;
1036 if(pwzMimeProposed || pBuffer)
1037 return find_mime_from_buffer(pBuffer, cbSize, pwzMimeProposed, ppwzMimeOut);
1045 static const WCHAR wszContentType[] =
1046 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
1048 ptr = strrchrW(pwzUrl, '.');
1052 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
1053 if(res != ERROR_SUCCESS)
1054 return HRESULT_FROM_WIN32(res);
1056 size = sizeof(mime);
1057 res = RegQueryValueExW(hkey, wszContentType, NULL, NULL, (LPBYTE)mime, &size);
1059 if(res != ERROR_SUCCESS)
1060 return HRESULT_FROM_WIN32(res);
1062 *ppwzMimeOut = CoTaskMemAlloc(size);
1063 memcpy(*ppwzMimeOut, mime, size);
1070 /***********************************************************************
1071 * GetClassFileOrMime (URLMON.@)
1073 * Determines the class ID from the bind context, file name or MIME type.
1075 HRESULT WINAPI GetClassFileOrMime(LPBC pBC, LPCWSTR pszFilename,
1076 LPVOID pBuffer, DWORD cbBuffer, LPCWSTR pszMimeType, DWORD dwReserved,
1079 FIXME("(%p, %s, %p, %d, %s, 0x%08x, %p): stub\n", pBC, debugstr_w(pszFilename), pBuffer,
1080 cbBuffer, debugstr_w(pszMimeType), dwReserved, pclsid);
1084 /***********************************************************************
1085 * Extract (URLMON.@)
1087 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
1089 HRESULT (WINAPI *pExtract)(void *, LPCSTR);
1092 hCabinet = LoadLibraryA("cabinet.dll");
1094 if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
1095 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
1096 if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());
1098 return pExtract(dest, szCabName);
1101 /***********************************************************************
1102 * IsLoggingEnabledA (URLMON.@)
1104 BOOL WINAPI IsLoggingEnabledA(LPCSTR url)
1106 FIXME("(%s)\n", debugstr_a(url));
1110 /***********************************************************************
1111 * IsLoggingEnabledW (URLMON.@)
1113 BOOL WINAPI IsLoggingEnabledW(LPCWSTR url)
1115 FIXME("(%s)\n", debugstr_w(url));
1119 /***********************************************************************
1120 * IsProtectedModeURL (URLMON.111)
1121 * Undocumented, added in IE7
1123 BOOL WINAPI IsProtectedModeURL(const WCHAR *url)
1125 FIXME("stub: %s\n", debugstr_w(url));
1129 /***********************************************************************
1130 * LogSqmBits (URLMON.410)
1131 * Undocumented, added in IE8
1133 int WINAPI LogSqmBits(DWORD unk1, DWORD unk2)
1135 FIXME("stub: %d %d\n", unk1, unk2);
1139 /***********************************************************************
1140 * LogSqmUXCommandOffsetInternal (URLMON.423)
1141 * Undocumented, added in IE8
1143 void WINAPI LogSqmUXCommandOffsetInternal(DWORD unk1, DWORD unk2, DWORD unk3, DWORD unk4)
1145 FIXME("stub: %d %d %d %d\n", unk1, unk2, unk3, unk4);
1148 /***********************************************************************
1149 * MapUriToBrowserEmulationState (URLMON.444)
1150 * Undocumented, added in IE8
1152 int WINAPI MapUriToBrowserEmulationState(DWORD unk1, DWORD unk2, DWORD unk3)
1154 FIXME("stub: %d %d %d\n", unk1, unk2, unk3);
1158 /***********************************************************************
1159 * MapBrowserEmulationModeToUserAgent (URLMON.445)
1160 * Undocumented, added in IE8
1162 int WINAPI MapBrowserEmulationModeToUserAgent(DWORD unk1, DWORD unk2)
1164 FIXME("stub: %d %d\n", unk1, unk2);
1168 /***********************************************************************
1169 * RegisterMediaTypes
1170 * Added in IE3, registers known MIME-type strings.
1172 HRESULT WINAPI RegisterMediaTypes(UINT types, LPCSTR *szTypes, CLIPFORMAT *cfTypes)
1174 FIXME("stub: %u %p %p\n", types, szTypes, cfTypes);
1175 return E_INVALIDARG;