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(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 =
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);
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 );
153 case DLL_PROCESS_ATTACH:
157 case DLL_PROCESS_DETACH:
159 DeleteCriticalSection(&tls_cs);
162 case DLL_THREAD_DETACH:
169 const char *debugstr_bindstatus(ULONG status)
172 #define X(x) case x: return #x; break
173 X(BINDSTATUS_FINDINGRESOURCE);
174 X(BINDSTATUS_CONNECTING);
175 X(BINDSTATUS_REDIRECTING);
176 X(BINDSTATUS_BEGINDOWNLOADDATA);
177 X(BINDSTATUS_DOWNLOADINGDATA);
178 X(BINDSTATUS_ENDDOWNLOADDATA);
179 X(BINDSTATUS_BEGINDOWNLOADCOMPONENTS);
180 X(BINDSTATUS_INSTALLINGCOMPONENTS);
181 X(BINDSTATUS_ENDDOWNLOADCOMPONENTS);
182 X(BINDSTATUS_USINGCACHEDCOPY);
183 X(BINDSTATUS_SENDINGREQUEST);
184 X(BINDSTATUS_CLASSIDAVAILABLE);
185 X(BINDSTATUS_MIMETYPEAVAILABLE);
186 X(BINDSTATUS_CACHEFILENAMEAVAILABLE);
187 X(BINDSTATUS_BEGINSYNCOPERATION);
188 X(BINDSTATUS_ENDSYNCOPERATION);
189 X(BINDSTATUS_BEGINUPLOADDATA);
190 X(BINDSTATUS_UPLOADINGDATA);
191 X(BINDSTATUS_ENDUPLOADINGDATA);
192 X(BINDSTATUS_PROTOCOLCLASSID);
193 X(BINDSTATUS_ENCODING);
194 X(BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE);
195 X(BINDSTATUS_CLASSINSTALLLOCATION);
196 X(BINDSTATUS_DECODING);
197 X(BINDSTATUS_LOADINGMIMEHANDLER);
198 X(BINDSTATUS_CONTENTDISPOSITIONATTACH);
199 X(BINDSTATUS_FILTERREPORTMIMETYPE);
200 X(BINDSTATUS_CLSIDCANINSTANTIATE);
201 X(BINDSTATUS_IUNKNOWNAVAILABLE);
202 X(BINDSTATUS_DIRECTBIND);
203 X(BINDSTATUS_RAWMIMETYPE);
204 X(BINDSTATUS_PROXYDETECTING);
205 X(BINDSTATUS_ACCEPTRANGES);
206 X(BINDSTATUS_COOKIE_SENT);
207 X(BINDSTATUS_COMPACT_POLICY_RECEIVED);
208 X(BINDSTATUS_COOKIE_SUPPRESSED);
209 X(BINDSTATUS_COOKIE_STATE_UNKNOWN);
210 X(BINDSTATUS_COOKIE_STATE_ACCEPT);
211 X(BINDSTATUS_COOKIE_STATE_REJECT);
212 X(BINDSTATUS_COOKIE_STATE_PROMPT);
213 X(BINDSTATUS_COOKIE_STATE_LEASH);
214 X(BINDSTATUS_COOKIE_STATE_DOWNGRADE);
215 X(BINDSTATUS_POLICY_HREF);
216 X(BINDSTATUS_P3P_HEADER);
217 X(BINDSTATUS_SESSION_COOKIE_RECEIVED);
218 X(BINDSTATUS_PERSISTENT_COOKIE_RECEIVED);
219 X(BINDSTATUS_SESSION_COOKIES_ALLOWED);
220 X(BINDSTATUS_CACHECONTROL);
221 X(BINDSTATUS_CONTENTDISPOSITIONFILENAME);
222 X(BINDSTATUS_MIMETEXTPLAINMISMATCH);
223 X(BINDSTATUS_PUBLISHERAVAILABLE);
224 X(BINDSTATUS_DISPLAYNAMEAVAILABLE);
227 return wine_dbg_sprintf("(invalid status %u)", status);
231 /***********************************************************************
232 * DllInstall (URLMON.@)
234 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
236 FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
237 debugstr_w(cmdline));
242 /***********************************************************************
243 * DllCanUnloadNow (URLMON.@)
245 HRESULT WINAPI DllCanUnloadNow(void)
247 return URLMON_refCount != 0 ? S_FALSE : S_OK;
252 /******************************************************************************
253 * Urlmon ClassFactory
256 IClassFactory IClassFactory_iface;
258 HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
261 static inline ClassFactory *impl_from_IClassFactory(IClassFactory *iface)
263 return CONTAINING_RECORD(iface, ClassFactory, IClassFactory_iface);
266 static HRESULT WINAPI CF_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppv)
270 if(IsEqualGUID(riid, &IID_IUnknown)) {
271 TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
273 }else if(IsEqualGUID(riid, &IID_IClassFactory)) {
274 TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv);
279 IUnknown_AddRef((IUnknown*)*ppv);
283 WARN("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ppv);
284 return E_NOINTERFACE;
287 static ULONG WINAPI CF_AddRef(IClassFactory *iface)
293 static ULONG WINAPI CF_Release(IClassFactory *iface)
295 URLMON_UnlockModule();
300 static HRESULT WINAPI CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
301 REFIID riid, LPVOID *ppobj)
303 ClassFactory *This = impl_from_IClassFactory(iface);
307 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
310 if(SUCCEEDED(hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk))) {
311 hres = IUnknown_QueryInterface(punk, riid, ppobj);
312 IUnknown_Release(punk);
317 static HRESULT WINAPI CF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
319 TRACE("(%d)\n", dolock);
324 URLMON_UnlockModule();
329 static const IClassFactoryVtbl ClassFactoryVtbl =
338 static ClassFactory FileProtocolCF =
339 { { &ClassFactoryVtbl }, FileProtocol_Construct};
340 static ClassFactory FtpProtocolCF =
341 { { &ClassFactoryVtbl }, FtpProtocol_Construct};
342 static ClassFactory GopherProtocolCF =
343 { { &ClassFactoryVtbl }, GopherProtocol_Construct};
344 static ClassFactory HttpProtocolCF =
345 { { &ClassFactoryVtbl }, HttpProtocol_Construct};
346 static ClassFactory HttpSProtocolCF =
347 { { &ClassFactoryVtbl }, HttpSProtocol_Construct};
348 static ClassFactory MkProtocolCF =
349 { { &ClassFactoryVtbl }, MkProtocol_Construct};
350 static ClassFactory SecurityManagerCF =
351 { { &ClassFactoryVtbl }, SecManagerImpl_Construct};
352 static ClassFactory ZoneManagerCF =
353 { { &ClassFactoryVtbl }, ZoneMgrImpl_Construct};
354 static ClassFactory StdURLMonikerCF =
355 { { &ClassFactoryVtbl }, StdURLMoniker_Construct};
356 static ClassFactory MimeFilterCF =
357 { { &ClassFactoryVtbl }, MimeFilter_Construct};
358 static ClassFactory CUriCF =
359 { { &ClassFactoryVtbl }, Uri_Construct};
361 struct object_creation_info
368 static const WCHAR wszFile[] = {'f','i','l','e',0};
369 static const WCHAR wszFtp[] = {'f','t','p',0};
370 static const WCHAR wszGopher[] = {'g','o','p','h','e','r',0};
371 static const WCHAR wszHttp[] = {'h','t','t','p',0};
372 static const WCHAR wszHttps[] = {'h','t','t','p','s',0};
373 static const WCHAR wszMk[] = {'m','k',0};
375 static const struct object_creation_info object_creation[] =
377 { &CLSID_FileProtocol, &FileProtocolCF.IClassFactory_iface, wszFile },
378 { &CLSID_FtpProtocol, &FtpProtocolCF.IClassFactory_iface, wszFtp },
379 { &CLSID_GopherProtocol, &GopherProtocolCF.IClassFactory_iface, wszGopher },
380 { &CLSID_HttpProtocol, &HttpProtocolCF.IClassFactory_iface, wszHttp },
381 { &CLSID_HttpSProtocol, &HttpSProtocolCF.IClassFactory_iface, wszHttps },
382 { &CLSID_MkProtocol, &MkProtocolCF.IClassFactory_iface, wszMk },
383 { &CLSID_InternetSecurityManager, &SecurityManagerCF.IClassFactory_iface, NULL },
384 { &CLSID_InternetZoneManager, &ZoneManagerCF.IClassFactory_iface, NULL },
385 { &CLSID_StdURLMoniker, &StdURLMonikerCF.IClassFactory_iface, NULL },
386 { &CLSID_DeCompMimeFilter, &MimeFilterCF.IClassFactory_iface, NULL },
387 { &CLSID_CUri, &CUriCF.IClassFactory_iface, NULL }
390 static void init_session(void)
394 for(i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) {
395 if(object_creation[i].protocol)
396 register_namespace(object_creation[i].cf, object_creation[i].clsid,
397 object_creation[i].protocol, TRUE);
401 /*******************************************************************************
402 * DllGetClassObject [URLMON.@]
403 * Retrieves class object from a DLL object
406 * Docs say returns STDAPI
409 * rclsid [I] CLSID for the class object
410 * riid [I] Reference to identifier of interface for class object
411 * ppv [O] Address of variable to receive interface pointer for riid
415 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
419 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
424 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
426 for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
428 if (IsEqualGUID(object_creation[i].clsid, rclsid))
429 return IClassFactory_QueryInterface(object_creation[i].cf, riid, ppv);
432 hr = URLMON_DllGetClassObject(rclsid, riid, ppv);
436 FIXME("%s: no class found.\n", debugstr_guid(rclsid));
437 return CLASS_E_CLASSNOTAVAILABLE;
440 static HRESULT register_inf(BOOL doregister)
442 HRESULT (WINAPI *pRegInstall)(HMODULE hm, LPCSTR pszSection, const STRTABLEA* pstTable);
445 static const WCHAR wszAdvpack[] = {'a','d','v','p','a','c','k','.','d','l','l',0};
447 hAdvpack = LoadLibraryW(wszAdvpack);
448 pRegInstall = (void *)GetProcAddress(hAdvpack, "RegInstall");
450 return pRegInstall(hProxyDll, doregister ? "RegisterDll" : "UnregisterDll", NULL);
453 /***********************************************************************
454 * DllRegisterServer (URLMON.@)
456 HRESULT WINAPI DllRegisterServer(void)
462 hr = URLMON_DllRegisterServer();
463 return SUCCEEDED(hr) ? register_inf(TRUE) : hr;
466 /***********************************************************************
467 * DllUnregisterServer (URLMON.@)
469 HRESULT WINAPI DllUnregisterServer(void)
475 hr = URLMON_DllUnregisterServer();
476 return SUCCEEDED(hr) ? register_inf(FALSE) : hr;
479 /***********************************************************************
480 * DllRegisterServerEx (URLMON.@)
482 HRESULT WINAPI DllRegisterServerEx(void)
484 FIXME("(void): stub\n");
489 /**************************************************************************
490 * IsValidURL (URLMON.@)
492 * Determines if a specified string is a valid URL.
495 * pBC [I] ignored, should be NULL.
496 * szURL [I] string that represents the URL in question.
497 * dwReserved [I] reserved and must be zero.
502 * returns E_INVALIDARG if one or more of the args is invalid.
505 * test functionality against windows to see what a valid URL is.
507 HRESULT WINAPI IsValidURL(LPBC pBC, LPCWSTR szURL, DWORD dwReserved)
509 FIXME("(%p, %s, %d): stub\n", pBC, debugstr_w(szURL), dwReserved);
511 if (dwReserved || !szURL)
517 /**************************************************************************
518 * FaultInIEFeature (URLMON.@)
520 * Undocumented. Appears to be used by native shdocvw.dll.
522 HRESULT WINAPI FaultInIEFeature( HWND hwnd, uCLSSPEC * pClassSpec,
523 QUERYCONTEXT *pQuery, DWORD flags )
525 FIXME("%p %p %p %08x\n", hwnd, pClassSpec, pQuery, flags);
529 /**************************************************************************
530 * CoGetClassObjectFromURL (URLMON.@)
532 HRESULT WINAPI CoGetClassObjectFromURL( REFCLSID rclsid, LPCWSTR szCodeURL, DWORD dwFileVersionMS,
533 DWORD dwFileVersionLS, LPCWSTR szContentType,
534 LPBINDCTX pBindCtx, DWORD dwClsContext, LPVOID pvReserved,
535 REFIID riid, LPVOID *ppv )
537 FIXME("(%s %s %d %d %s %p %d %p %s %p) Stub!\n", debugstr_guid(rclsid), debugstr_w(szCodeURL),
538 dwFileVersionMS, dwFileVersionLS, debugstr_w(szContentType), pBindCtx, dwClsContext, pvReserved,
539 debugstr_guid(riid), ppv);
540 return E_NOINTERFACE;
543 /***********************************************************************
544 * ReleaseBindInfo (URLMON.@)
546 * Release the resources used by the specified BINDINFO structure.
549 * pbindinfo [I] BINDINFO to release.
554 void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo)
558 TRACE("(%p)\n", pbindinfo);
560 if(!pbindinfo || !(size = pbindinfo->cbSize))
563 CoTaskMemFree(pbindinfo->szExtraInfo);
564 ReleaseStgMedium(&pbindinfo->stgmedData);
566 if(offsetof(BINDINFO, szExtraInfo) < size)
567 CoTaskMemFree(pbindinfo->szCustomVerb);
569 if(pbindinfo->pUnk && offsetof(BINDINFO, pUnk) < size)
570 IUnknown_Release(pbindinfo->pUnk);
572 memset(pbindinfo, 0, size);
573 pbindinfo->cbSize = size;
576 /***********************************************************************
577 * CopyStgMedium (URLMON.@)
579 HRESULT WINAPI CopyStgMedium(const STGMEDIUM *src, STGMEDIUM *dst)
581 TRACE("(%p %p)\n", src, dst);
592 if(src->u.lpszFileName && !src->pUnkForRelease) {
593 DWORD size = (strlenW(src->u.lpszFileName)+1)*sizeof(WCHAR);
594 dst->u.lpszFileName = CoTaskMemAlloc(size);
595 if(!dst->u.lpszFileName)
596 return E_OUTOFMEMORY;
597 memcpy(dst->u.lpszFileName, src->u.lpszFileName, size);
602 IStream_AddRef(dst->u.pstm);
606 IStorage_AddRef(dst->u.pstg);
610 SIZE_T size = GlobalSize(src->u.hGlobal);
611 char *src_ptr, *dst_ptr;
613 dst->u.hGlobal = GlobalAlloc(GMEM_FIXED, size);
615 return E_OUTOFMEMORY;
616 dst_ptr = GlobalLock(dst->u.hGlobal);
617 src_ptr = GlobalLock(src->u.hGlobal);
618 memcpy(dst_ptr, src_ptr, size);
619 GlobalUnlock(src_ptr);
620 GlobalUnlock(dst_ptr);
624 FIXME("Unimplemented tymed %d\n", src->tymed);
627 if(dst->pUnkForRelease)
628 IUnknown_AddRef(dst->pUnkForRelease);
633 /***********************************************************************
634 * CopyBindInfo (URLMON.@)
636 HRESULT WINAPI CopyBindInfo(const BINDINFO *pcbiSrc, BINDINFO *pcbiDest)
641 TRACE("(%p %p)\n", pcbiSrc, pcbiDest);
643 if(!pcbiSrc || !pcbiDest)
645 if(!pcbiSrc->cbSize || !pcbiDest->cbSize)
648 size = pcbiDest->cbSize;
649 if(size > pcbiSrc->cbSize) {
650 memcpy(pcbiDest, pcbiSrc, pcbiSrc->cbSize);
651 memset((char*)pcbiDest+pcbiSrc->cbSize, 0, size-pcbiSrc->cbSize);
653 memcpy(pcbiDest, pcbiSrc, size);
655 pcbiDest->cbSize = size;
657 size = FIELD_OFFSET(BINDINFO, szExtraInfo)+sizeof(void*);
658 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size && pcbiSrc->szExtraInfo) {
659 size = (strlenW(pcbiSrc->szExtraInfo)+1)*sizeof(WCHAR);
660 pcbiDest->szExtraInfo = CoTaskMemAlloc(size);
661 if(!pcbiDest->szExtraInfo)
662 return E_OUTOFMEMORY;
663 memcpy(pcbiDest->szExtraInfo, pcbiSrc->szExtraInfo, size);
666 size = FIELD_OFFSET(BINDINFO, stgmedData)+sizeof(STGMEDIUM);
667 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size) {
668 hres = CopyStgMedium(&pcbiSrc->stgmedData, &pcbiDest->stgmedData);
670 CoTaskMemFree(pcbiDest->szExtraInfo);
675 size = FIELD_OFFSET(BINDINFO, szCustomVerb)+sizeof(void*);
676 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size && pcbiSrc->szCustomVerb) {
677 size = (strlenW(pcbiSrc->szCustomVerb)+1)*sizeof(WCHAR);
678 pcbiDest->szCustomVerb = CoTaskMemAlloc(size);
679 if(!pcbiDest->szCustomVerb) {
680 CoTaskMemFree(pcbiDest->szExtraInfo);
681 ReleaseStgMedium(&pcbiDest->stgmedData);
682 return E_OUTOFMEMORY;
684 memcpy(pcbiDest->szCustomVerb, pcbiSrc->szCustomVerb, size);
687 size = FIELD_OFFSET(BINDINFO, securityAttributes)+sizeof(SECURITY_ATTRIBUTES);
688 if(pcbiDest->cbSize >= size)
689 memset(&pcbiDest->securityAttributes, 0, sizeof(SECURITY_ATTRIBUTES));
692 IUnknown_AddRef(pcbiDest->pUnk);
697 static BOOL text_richtext_filter(const BYTE *b, DWORD size)
699 return size > 5 && !memcmp(b, "{\\rtf", 5);
702 static BOOL text_html_filter(const BYTE *b, DWORD size)
708 && (b[1] == 'h' || b[1] == 'H')
709 && (b[2] == 't' || b[2] == 'T')
710 && (b[3] == 'm' || b[3] == 'M')
711 && (b[4] == 'l' || b[4] == 'L'))
713 && (b[1] == 'h' || b[1] == 'H')
714 && (b[2] == 'e' || b[2] == 'E')
715 && (b[3] == 'a' || b[3] == 'A')
716 && (b[4] == 'd' || b[4] == 'D'))) return TRUE;
721 static BOOL text_xml_filter(const BYTE *b, DWORD size)
726 if(b[0] == '<' && b[1] == '?'
727 && (b[2] == 'x' || b[2] == 'X')
728 && (b[3] == 'm' || b[3] == 'M')
729 && (b[4] == 'l' || b[4] == 'L')
730 && b[5] == ' ') return TRUE;
735 static BOOL audio_basic_filter(const BYTE *b, DWORD size)
738 && b[0] == '.' && b[1] == 's' && b[2] == 'n' && b[3] == 'd';
741 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
744 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
745 && b[8] == 'W' && b[9] == 'A' && b[10] == 'V' && b[11] == 'E';
748 static BOOL image_gif_filter(const BYTE *b, DWORD size)
751 && (b[0] == 'G' || b[0] == 'g')
752 && (b[1] == 'I' || b[1] == 'i')
753 && (b[2] == 'F' || b[2] == 'f')
755 && (b[4] == '7' || b[4] == '9')
756 && (b[5] == 'A' || b[5] == 'a');
759 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
761 return size > 2 && b[0] == 0xff && b[1] == 0xd8;
764 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
766 static const BYTE magic1[] = {0x4d,0x4d,0x00,0x2a};
767 static const BYTE magic2[] = {0x49,0x49,0x2a,0xff};
769 return size >= 4 && (!memcmp(b, magic1, 4) || !memcmp(b, magic2, 4));
772 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
774 static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
775 return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header));
778 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
781 && b[0] == 0x42 && b[1] == 0x4d
782 && *(const DWORD *)(b+6) == 0;
785 static BOOL video_avi_filter(const BYTE *b, DWORD size)
788 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
789 && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20;
792 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
795 && !b[0] && !b[1] && b[2] == 0x01
796 && (b[3] == 0xb3 || b[3] == 0xba);
799 static BOOL application_postscript_filter(const BYTE *b, DWORD size)
801 return size > 2 && b[0] == '%' && b[1] == '!';
804 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
806 return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
809 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
811 return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
814 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
816 return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
819 static BOOL application_java_filter(const BYTE *b, DWORD size)
821 return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
824 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
826 return size > 2 && b[0] == 'M' && b[1] == 'Z';
829 static inline BOOL is_text_plain_char(BYTE b)
831 if(b < 0x20 && b != '\n' && b != '\r' && b != '\t')
836 static BOOL text_plain_filter(const BYTE *b, DWORD size)
840 for(ptr = b; ptr < b+size-1; ptr++) {
841 if(!is_text_plain_char(*ptr))
848 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
853 static HRESULT find_mime_from_buffer(const BYTE *buf, DWORD size, const WCHAR *proposed_mime, WCHAR **ret_mime)
856 int len, i, any_pos_mime = -1;
858 static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0};
859 static const WCHAR text_richtextW[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0};
860 static const WCHAR text_xmlW[] = {'t','e','x','t','/','x','m','l',0};
861 static const WCHAR audio_basicW[] = {'a','u','d','i','o','/','b','a','s','i','c',0};
862 static const WCHAR audio_wavW[] = {'a','u','d','i','o','/','w','a','v',0};
863 static const WCHAR image_gifW[] = {'i','m','a','g','e','/','g','i','f',0};
864 static const WCHAR image_pjpegW[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
865 static const WCHAR image_tiffW[] = {'i','m','a','g','e','/','t','i','f','f',0};
866 static const WCHAR image_xpngW[] = {'i','m','a','g','e','/','x','-','p','n','g',0};
867 static const WCHAR image_bmpW[] = {'i','m','a','g','e','/','b','m','p',0};
868 static const WCHAR video_aviW[] = {'v','i','d','e','o','/','a','v','i',0};
869 static const WCHAR video_mpegW[] = {'v','i','d','e','o','/','m','p','e','g',0};
870 static const WCHAR app_postscriptW[] =
871 {'a','p','p','l','i','c','a','t','i','o','n','/','p','o','s','t','s','c','r','i','p','t',0};
872 static const WCHAR app_pdfW[] = {'a','p','p','l','i','c','a','t','i','o','n','/','p','d','f',0};
873 static const WCHAR app_xzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
874 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
875 static const WCHAR app_xgzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
876 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
877 static const WCHAR app_javaW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
879 static const WCHAR app_xmsdownloadW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
880 'x','-','m','s','d','o','w','n','l','o','a','d',0};
881 static const WCHAR text_plainW[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
882 static const WCHAR app_octetstreamW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
883 'o','c','t','e','t','-','s','t','r','e','a','m','\0'};
885 static const struct {
887 BOOL (*filter)(const BYTE *,DWORD);
888 } mime_filters_any_pos[] = {
889 {text_htmlW, text_html_filter},
890 {text_xmlW, text_xml_filter}
891 }, mime_filters[] = {
892 {text_richtextW, text_richtext_filter},
893 /* {audio_xaiffW, audio_xaiff_filter}, */
894 {audio_basicW, audio_basic_filter},
895 {audio_wavW, audio_wav_filter},
896 {image_gifW, image_gif_filter},
897 {image_pjpegW, image_pjpeg_filter},
898 {image_tiffW, image_tiff_filter},
899 {image_xpngW, image_xpng_filter},
900 /* {image_xbitmapW, image_xbitmap_filter}, */
901 {image_bmpW, image_bmp_filter},
902 /* {image_xjgW, image_xjg_filter}, */
903 /* {image_xemfW, image_xemf_filter}, */
904 /* {image_xwmfW, image_xwmf_filter}, */
905 {video_aviW, video_avi_filter},
906 {video_mpegW, video_mpeg_filter},
907 {app_postscriptW, application_postscript_filter},
908 /* {app_base64W, application_base64_filter}, */
909 /* {app_macbinhex40W, application_macbinhex40_filter}, */
910 {app_pdfW, application_pdf_filter},
911 /* {app_zcompressedW, application_xcompressed_filter}, */
912 {app_xzipW, application_xzip_filter},
913 {app_xgzipW, application_xgzip_filter},
914 {app_javaW, application_java_filter},
915 {app_xmsdownloadW, application_xmsdownload},
916 {text_plainW, text_plain_filter},
917 {app_octetstreamW, application_octet_stream_filter}
924 len = strlenW(proposed_mime)+1;
925 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
927 return E_OUTOFMEMORY;
929 memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR));
933 if(proposed_mime && (!strcmpW(proposed_mime, app_octetstreamW)
934 || !strcmpW(proposed_mime, text_plainW)))
935 proposed_mime = NULL;
940 for(i=0; i < sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
941 if(!strcmpW(proposed_mime, mime_filters_any_pos[i].mime)) {
943 for(len=size; len>0; len--) {
944 if(mime_filters_any_pos[i].filter(buf+size-len, len))
953 if(i == sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos)) {
954 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
955 if(!strcmpW(proposed_mime, mime_filters[i].mime)) {
956 if(!mime_filters[i].filter(buf, size))
964 /* Looks like a bug in native implementation, html and xml mimes
965 * are not looked for if none of them was proposed */
966 if(!proposed_mime || any_pos_mime!=-1) {
967 for(len=size; !ret && len>0; len--) {
968 for(i=0; i<sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
969 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
970 ret = mime_filters_any_pos[i].mime;
979 if(mime_filters[i].filter(buf, size))
980 ret = mime_filters[i].mime;
984 if(any_pos_mime!=-1 && ret==text_plainW)
985 ret = mime_filters_any_pos[any_pos_mime].mime;
986 else if(proposed_mime && ret==app_octetstreamW) {
987 for(len=size; ret==app_octetstreamW && len>0; len--) {
988 if(!is_text_plain_char(buf[size-len]))
990 for(i=0; i<sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
991 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
998 if(ret == app_octetstreamW)
1001 TRACE("found %s for %s\n", debugstr_w(ret), debugstr_an((const char*)buf, min(32, size)));
1003 len = strlenW(ret)+1;
1004 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
1006 return E_OUTOFMEMORY;
1008 memcpy(*ret_mime, ret, len*sizeof(WCHAR));
1012 /***********************************************************************
1013 * FindMimeFromData (URLMON.@)
1015 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
1017 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
1018 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
1019 LPWSTR* ppwzMimeOut, DWORD dwReserved)
1021 TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
1022 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
1025 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
1027 WARN("dwReserved=%d\n", dwReserved);
1029 /* pBC seams to not be used */
1031 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
1032 return E_INVALIDARG;
1034 if(pwzMimeProposed || pBuffer)
1035 return find_mime_from_buffer(pBuffer, cbSize, pwzMimeProposed, ppwzMimeOut);
1043 static const WCHAR wszContentType[] =
1044 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
1046 ptr = strrchrW(pwzUrl, '.');
1050 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
1051 if(res != ERROR_SUCCESS)
1052 return HRESULT_FROM_WIN32(res);
1054 size = sizeof(mime);
1055 res = RegQueryValueExW(hkey, wszContentType, NULL, NULL, (LPBYTE)mime, &size);
1057 if(res != ERROR_SUCCESS)
1058 return HRESULT_FROM_WIN32(res);
1060 *ppwzMimeOut = CoTaskMemAlloc(size);
1061 memcpy(*ppwzMimeOut, mime, size);
1068 /***********************************************************************
1069 * GetClassFileOrMime (URLMON.@)
1071 * Determines the class ID from the bind context, file name or MIME type.
1073 HRESULT WINAPI GetClassFileOrMime(LPBC pBC, LPCWSTR pszFilename,
1074 LPVOID pBuffer, DWORD cbBuffer, LPCWSTR pszMimeType, DWORD dwReserved,
1077 FIXME("(%p, %s, %p, %d, %s, 0x%08x, %p): stub\n", pBC, debugstr_w(pszFilename), pBuffer,
1078 cbBuffer, debugstr_w(pszMimeType), dwReserved, pclsid);
1082 /***********************************************************************
1083 * Extract (URLMON.@)
1085 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
1087 HRESULT (WINAPI *pExtract)(void *, LPCSTR);
1090 hCabinet = LoadLibraryA("cabinet.dll");
1092 if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
1093 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
1094 if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());
1096 return pExtract(dest, szCabName);
1099 /***********************************************************************
1100 * IsLoggingEnabledA (URLMON.@)
1102 BOOL WINAPI IsLoggingEnabledA(LPCSTR url)
1104 FIXME("(%s)\n", debugstr_a(url));
1108 /***********************************************************************
1109 * IsLoggingEnabledW (URLMON.@)
1111 BOOL WINAPI IsLoggingEnabledW(LPCWSTR url)
1113 FIXME("(%s)\n", debugstr_w(url));
1117 /***********************************************************************
1118 * IsProtectedModeURL (URLMON.111)
1119 * Undocumented, added in IE7
1121 BOOL WINAPI IsProtectedModeURL(const WCHAR *url)
1123 FIXME("stub: %s\n", debugstr_w(url));
1127 /***********************************************************************
1128 * LogSqmBits (URLMON.410)
1129 * Undocumented, added in IE8
1131 int WINAPI LogSqmBits(DWORD unk1, DWORD unk2)
1133 FIXME("stub: %d %d\n", unk1, unk2);
1137 /***********************************************************************
1138 * LogSqmUXCommandOffsetInternal (URLMON.423)
1139 * Undocumented, added in IE8
1141 void WINAPI LogSqmUXCommandOffsetInternal(DWORD unk1, DWORD unk2, DWORD unk3, DWORD unk4)
1143 FIXME("stub: %d %d %d %d\n", unk1, unk2, unk3, unk4);
1146 /***********************************************************************
1147 * MapUriToBrowserEmulationState (URLMON.444)
1148 * Undocumented, added in IE8
1150 int WINAPI MapUriToBrowserEmulationState(DWORD unk1, DWORD unk2, DWORD unk3)
1152 FIXME("stub: %d %d %d\n", unk1, unk2, unk3);
1156 /***********************************************************************
1157 * MapBrowserEmulationModeToUserAgent (URLMON.445)
1158 * Undocumented, added in IE8
1160 int WINAPI MapBrowserEmulationModeToUserAgent(DWORD unk1, DWORD unk2)
1162 FIXME("stub: %d %d\n", unk1, unk2);
1166 /***********************************************************************
1167 * RegisterMediaTypes
1168 * Added in IE3, registers known MIME-type strings.
1170 HRESULT WINAPI RegisterMediaTypes(UINT types, LPCSTR *szTypes, CLIPFORMAT *cfTypes)
1172 FIXME("stub: %u %p %p\n", types, szTypes, cfTypes);
1173 return E_INVALIDARG;