advapi32: Add a bunch of file access tests.
[wine/wine-gecko.git] / dlls / urlmon / urlmon_main.c
blob57eeaf971056faa34579e374d9586106869f55c6
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"
31 #include "wine/debug.h"
33 #include "urlmon.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
37 LONG URLMON_refCount = 0;
39 static HMODULE hCabinet = NULL;
40 static DWORD urlmon_tls = TLS_OUT_OF_INDEXES;
42 static void init_session(BOOL);
44 static struct list tls_list = LIST_INIT(tls_list);
46 static CRITICAL_SECTION tls_cs;
47 static CRITICAL_SECTION_DEBUG tls_cs_dbg =
49 0, 0, &tls_cs,
50 { &tls_cs_dbg.ProcessLocksList, &tls_cs_dbg.ProcessLocksList },
51 0, 0, { (DWORD_PTR)(__FILE__ ": tls") }
54 static CRITICAL_SECTION tls_cs = { &tls_cs_dbg, -1, 0, 0, 0, 0 };
56 tls_data_t *get_tls_data(void)
58 tls_data_t *data;
60 if(urlmon_tls == TLS_OUT_OF_INDEXES) {
61 DWORD tls = TlsAlloc();
62 if(tls == TLS_OUT_OF_INDEXES)
63 return NULL;
65 tls = InterlockedCompareExchange((LONG*)&urlmon_tls, tls, TLS_OUT_OF_INDEXES);
66 if(tls != urlmon_tls)
67 TlsFree(tls);
70 data = TlsGetValue(urlmon_tls);
71 if(!data) {
72 data = heap_alloc_zero(sizeof(tls_data_t));
73 if(!data)
74 return NULL;
76 EnterCriticalSection(&tls_cs);
77 list_add_tail(&tls_list, &data->entry);
78 LeaveCriticalSection(&tls_cs);
80 TlsSetValue(urlmon_tls, data);
83 return data;
86 static void free_tls_list(void)
88 tls_data_t *data;
90 if(urlmon_tls == TLS_OUT_OF_INDEXES)
91 return;
93 while(!list_empty(&tls_list)) {
94 data = LIST_ENTRY(list_head(&tls_list), tls_data_t, entry);
95 list_remove(&data->entry);
96 heap_free(data);
99 TlsFree(urlmon_tls);
102 static void detach_thread(void)
104 tls_data_t *data;
106 if(urlmon_tls == TLS_OUT_OF_INDEXES)
107 return;
109 data = TlsGetValue(urlmon_tls);
110 if(!data)
111 return;
113 EnterCriticalSection(&tls_cs);
114 list_remove(&data->entry);
115 LeaveCriticalSection(&tls_cs);
117 if(data->notif_hwnd) {
118 WARN("notif_hwnd not destroyed\n");
119 DestroyWindow(data->notif_hwnd);
122 heap_free(data);
125 static void process_detach(void)
127 HINTERNET internet_session;
129 internet_session = get_internet_session(NULL);
130 if(internet_session)
131 InternetCloseHandle(internet_session);
133 if (hCabinet)
134 FreeLibrary(hCabinet);
136 init_session(FALSE);
137 free_session();
138 free_tls_list();
141 /***********************************************************************
142 * DllMain (URLMON.init)
144 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
146 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
148 URLMON_DllMain( hinstDLL, fdwReason, fImpLoad );
150 switch(fdwReason) {
151 case DLL_PROCESS_ATTACH:
152 init_session(TRUE);
153 break;
155 case DLL_PROCESS_DETACH:
156 process_detach();
157 break;
159 case DLL_THREAD_DETACH:
160 detach_thread();
161 break;
163 return TRUE;
167 /***********************************************************************
168 * DllInstall (URLMON.@)
170 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
172 FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
173 debugstr_w(cmdline));
175 return S_OK;
178 /***********************************************************************
179 * DllCanUnloadNow (URLMON.@)
181 HRESULT WINAPI DllCanUnloadNow(void)
183 return URLMON_refCount != 0 ? S_FALSE : S_OK;
188 /******************************************************************************
189 * Urlmon ClassFactory
191 typedef struct {
192 IClassFactory IClassFactory_iface;
194 HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
195 } ClassFactory;
197 static inline ClassFactory *impl_from_IClassFactory(IClassFactory *iface)
199 return CONTAINING_RECORD(iface, ClassFactory, IClassFactory_iface);
202 static HRESULT WINAPI CF_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppv)
204 *ppv = NULL;
206 if(IsEqualGUID(riid, &IID_IUnknown)) {
207 TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
208 *ppv = iface;
209 }else if(IsEqualGUID(riid, &IID_IClassFactory)) {
210 TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv);
211 *ppv = iface;
214 if(*ppv) {
215 IUnknown_AddRef((IUnknown*)*ppv);
216 return S_OK;
219 WARN("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ppv);
220 return E_NOINTERFACE;
223 static ULONG WINAPI CF_AddRef(IClassFactory *iface)
225 URLMON_LockModule();
226 return 2;
229 static ULONG WINAPI CF_Release(IClassFactory *iface)
231 URLMON_UnlockModule();
232 return 1;
236 static HRESULT WINAPI CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
237 REFIID riid, LPVOID *ppobj)
239 ClassFactory *This = impl_from_IClassFactory(iface);
240 HRESULT hres;
241 LPUNKNOWN punk;
243 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
245 *ppobj = NULL;
246 if(SUCCEEDED(hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk))) {
247 hres = IUnknown_QueryInterface(punk, riid, ppobj);
248 IUnknown_Release(punk);
250 return hres;
253 static HRESULT WINAPI CF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
255 TRACE("(%d)\n", dolock);
257 if (dolock)
258 URLMON_LockModule();
259 else
260 URLMON_UnlockModule();
262 return S_OK;
265 static const IClassFactoryVtbl ClassFactoryVtbl =
267 CF_QueryInterface,
268 CF_AddRef,
269 CF_Release,
270 CF_CreateInstance,
271 CF_LockServer
274 static ClassFactory FileProtocolCF =
275 { { &ClassFactoryVtbl }, FileProtocol_Construct};
276 static ClassFactory FtpProtocolCF =
277 { { &ClassFactoryVtbl }, FtpProtocol_Construct};
278 static ClassFactory GopherProtocolCF =
279 { { &ClassFactoryVtbl }, GopherProtocol_Construct};
280 static ClassFactory HttpProtocolCF =
281 { { &ClassFactoryVtbl }, HttpProtocol_Construct};
282 static ClassFactory HttpSProtocolCF =
283 { { &ClassFactoryVtbl }, HttpSProtocol_Construct};
284 static ClassFactory MkProtocolCF =
285 { { &ClassFactoryVtbl }, MkProtocol_Construct};
286 static ClassFactory SecurityManagerCF =
287 { { &ClassFactoryVtbl }, SecManagerImpl_Construct};
288 static ClassFactory ZoneManagerCF =
289 { { &ClassFactoryVtbl }, ZoneMgrImpl_Construct};
290 static ClassFactory StdURLMonikerCF =
291 { { &ClassFactoryVtbl }, StdURLMoniker_Construct};
292 static ClassFactory MimeFilterCF =
293 { { &ClassFactoryVtbl }, MimeFilter_Construct};
295 struct object_creation_info
297 const CLSID *clsid;
298 IClassFactory *cf;
299 LPCWSTR protocol;
302 static const WCHAR wszFile[] = {'f','i','l','e',0};
303 static const WCHAR wszFtp[] = {'f','t','p',0};
304 static const WCHAR wszGopher[] = {'g','o','p','h','e','r',0};
305 static const WCHAR wszHttp[] = {'h','t','t','p',0};
306 static const WCHAR wszHttps[] = {'h','t','t','p','s',0};
307 static const WCHAR wszMk[] = {'m','k',0};
309 static const struct object_creation_info object_creation[] =
311 { &CLSID_FileProtocol, &FileProtocolCF.IClassFactory_iface, wszFile },
312 { &CLSID_FtpProtocol, &FtpProtocolCF.IClassFactory_iface, wszFtp },
313 { &CLSID_GopherProtocol, &GopherProtocolCF.IClassFactory_iface, wszGopher },
314 { &CLSID_HttpProtocol, &HttpProtocolCF.IClassFactory_iface, wszHttp },
315 { &CLSID_HttpSProtocol, &HttpSProtocolCF.IClassFactory_iface, wszHttps },
316 { &CLSID_MkProtocol, &MkProtocolCF.IClassFactory_iface, wszMk },
317 { &CLSID_InternetSecurityManager, &SecurityManagerCF.IClassFactory_iface, NULL },
318 { &CLSID_InternetZoneManager, &ZoneManagerCF.IClassFactory_iface, NULL },
319 { &CLSID_StdURLMoniker, &StdURLMonikerCF.IClassFactory_iface, NULL },
320 { &CLSID_DeCompMimeFilter, &MimeFilterCF.IClassFactory_iface, NULL }
323 static void init_session(BOOL init)
325 unsigned int i;
327 for(i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) {
329 if(object_creation[i].protocol)
330 register_urlmon_namespace(object_creation[i].cf, object_creation[i].clsid,
331 object_creation[i].protocol, init);
335 /*******************************************************************************
336 * DllGetClassObject [URLMON.@]
337 * Retrieves class object from a DLL object
339 * NOTES
340 * Docs say returns STDAPI
342 * PARAMS
343 * rclsid [I] CLSID for the class object
344 * riid [I] Reference to identifier of interface for class object
345 * ppv [O] Address of variable to receive interface pointer for riid
347 * RETURNS
348 * Success: S_OK
349 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
350 * E_UNEXPECTED
353 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
355 unsigned int i;
356 HRESULT hr;
358 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
360 for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
362 if (IsEqualGUID(object_creation[i].clsid, rclsid))
363 return IClassFactory_QueryInterface(object_creation[i].cf, riid, ppv);
366 hr = URLMON_DllGetClassObject(rclsid, riid, ppv);
367 if(SUCCEEDED(hr))
368 return hr;
370 FIXME("%s: no class found.\n", debugstr_guid(rclsid));
371 return CLASS_E_CLASSNOTAVAILABLE;
374 static HRESULT register_inf(BOOL doregister)
376 HRESULT (WINAPI *pRegInstall)(HMODULE hm, LPCSTR pszSection, const STRTABLEA* pstTable);
377 HMODULE hAdvpack;
379 static const WCHAR wszAdvpack[] = {'a','d','v','p','a','c','k','.','d','l','l',0};
381 hAdvpack = LoadLibraryW(wszAdvpack);
382 pRegInstall = (void *)GetProcAddress(hAdvpack, "RegInstall");
384 return pRegInstall(hProxyDll, doregister ? "RegisterDll" : "UnregisterDll", NULL);
387 /***********************************************************************
388 * DllRegisterServer (URLMON.@)
390 HRESULT WINAPI DllRegisterServer(void)
392 HRESULT hr;
394 TRACE("\n");
396 hr = URLMON_DllRegisterServer();
397 return SUCCEEDED(hr) ? register_inf(TRUE) : hr;
400 /***********************************************************************
401 * DllUnregisterServer (URLMON.@)
403 HRESULT WINAPI DllUnregisterServer(void)
405 HRESULT hr;
407 TRACE("\n");
409 hr = URLMON_DllUnregisterServer();
410 return SUCCEEDED(hr) ? register_inf(FALSE) : hr;
413 /***********************************************************************
414 * DllRegisterServerEx (URLMON.@)
416 HRESULT WINAPI DllRegisterServerEx(void)
418 FIXME("(void): stub\n");
420 return E_FAIL;
423 /**************************************************************************
424 * IsValidURL (URLMON.@)
426 * Determines if a specified string is a valid URL.
428 * PARAMS
429 * pBC [I] ignored, must be NULL.
430 * szURL [I] string that represents the URL in question.
431 * dwReserved [I] reserved and must be zero.
433 * RETURNS
434 * Success: S_OK.
435 * Failure: S_FALSE.
436 * returns E_INVALIDARG if one or more of the args is invalid.
438 * TODO:
439 * test functionality against windows to see what a valid URL is.
441 HRESULT WINAPI IsValidURL(LPBC pBC, LPCWSTR szURL, DWORD dwReserved)
443 FIXME("(%p, %s, %d): stub\n", pBC, debugstr_w(szURL), dwReserved);
445 if (pBC || dwReserved || !szURL)
446 return E_INVALIDARG;
448 return S_OK;
451 /**************************************************************************
452 * FaultInIEFeature (URLMON.@)
454 * Undocumented. Appears to be used by native shdocvw.dll.
456 HRESULT WINAPI FaultInIEFeature( HWND hwnd, uCLSSPEC * pClassSpec,
457 QUERYCONTEXT *pQuery, DWORD flags )
459 FIXME("%p %p %p %08x\n", hwnd, pClassSpec, pQuery, flags);
460 return E_NOTIMPL;
463 /**************************************************************************
464 * CoGetClassObjectFromURL (URLMON.@)
466 HRESULT WINAPI CoGetClassObjectFromURL( REFCLSID rclsid, LPCWSTR szCodeURL, DWORD dwFileVersionMS,
467 DWORD dwFileVersionLS, LPCWSTR szContentType,
468 LPBINDCTX pBindCtx, DWORD dwClsContext, LPVOID pvReserved,
469 REFIID riid, LPVOID *ppv )
471 FIXME("(%s %s %d %d %s %p %d %p %s %p) Stub!\n", debugstr_guid(rclsid), debugstr_w(szCodeURL),
472 dwFileVersionMS, dwFileVersionLS, debugstr_w(szContentType), pBindCtx, dwClsContext, pvReserved,
473 debugstr_guid(riid), ppv);
474 return E_NOINTERFACE;
477 /***********************************************************************
478 * ReleaseBindInfo (URLMON.@)
480 * Release the resources used by the specified BINDINFO structure.
482 * PARAMS
483 * pbindinfo [I] BINDINFO to release.
485 * RETURNS
486 * Nothing.
488 void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo)
490 DWORD size;
492 TRACE("(%p)\n", pbindinfo);
494 if(!pbindinfo || !(size = pbindinfo->cbSize))
495 return;
497 CoTaskMemFree(pbindinfo->szExtraInfo);
498 ReleaseStgMedium(&pbindinfo->stgmedData);
500 if(offsetof(BINDINFO, szExtraInfo) < size)
501 CoTaskMemFree(pbindinfo->szCustomVerb);
503 if(pbindinfo->pUnk && offsetof(BINDINFO, pUnk) < size)
504 IUnknown_Release(pbindinfo->pUnk);
506 memset(pbindinfo, 0, size);
507 pbindinfo->cbSize = size;
510 /***********************************************************************
511 * CopyStgMedium (URLMON.@)
513 HRESULT WINAPI CopyStgMedium(const STGMEDIUM *src, STGMEDIUM *dst)
515 TRACE("(%p %p)\n", src, dst);
517 if(!src || !dst)
518 return E_POINTER;
520 *dst = *src;
522 switch(dst->tymed) {
523 case TYMED_NULL:
524 break;
525 case TYMED_FILE:
526 if(src->u.lpszFileName && !src->pUnkForRelease) {
527 DWORD size = (strlenW(src->u.lpszFileName)+1)*sizeof(WCHAR);
528 dst->u.lpszFileName = CoTaskMemAlloc(size);
529 memcpy(dst->u.lpszFileName, src->u.lpszFileName, size);
531 break;
532 case TYMED_ISTREAM:
533 if(dst->u.pstm)
534 IStream_AddRef(dst->u.pstm);
535 break;
536 case TYMED_ISTORAGE:
537 if(dst->u.pstg)
538 IStorage_AddRef(dst->u.pstg);
539 break;
540 default:
541 FIXME("Unimplemented tymed %d\n", src->tymed);
544 if(dst->pUnkForRelease)
545 IUnknown_AddRef(dst->pUnkForRelease);
547 return S_OK;
550 static BOOL text_richtext_filter(const BYTE *b, DWORD size)
552 return size > 5 && !memcmp(b, "{\\rtf", 5);
555 static BOOL text_html_filter(const BYTE *b, DWORD size)
557 DWORD i;
559 if(size < 5)
560 return FALSE;
562 for(i=0; i < size-5; i++) {
563 if(b[i] == '<'
564 && (b[i+1] == 'h' || b[i+1] == 'H')
565 && (b[i+2] == 't' || b[i+2] == 'T')
566 && (b[i+3] == 'm' || b[i+3] == 'M')
567 && (b[i+4] == 'l' || b[i+4] == 'L'))
568 return TRUE;
571 return FALSE;
574 static BOOL audio_basic_filter(const BYTE *b, DWORD size)
576 return size > 4
577 && b[0] == '.' && b[1] == 's' && b[2] == 'n' && b[3] == 'd';
580 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
582 return size > 12
583 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
584 && b[8] == 'W' && b[9] == 'A' && b[10] == 'V' && b[11] == 'E';
587 static BOOL image_gif_filter(const BYTE *b, DWORD size)
589 return size >= 6
590 && (b[0] == 'G' || b[0] == 'g')
591 && (b[1] == 'I' || b[1] == 'i')
592 && (b[2] == 'F' || b[2] == 'f')
593 && b[3] == '8'
594 && (b[4] == '7' || b[4] == '9')
595 && (b[5] == 'A' || b[5] == 'a');
598 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
600 return size > 2 && b[0] == 0xff && b[1] == 0xd8;
603 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
605 return size > 2 && b[0] == 0x4d && b[1] == 0x4d;
608 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
610 static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
611 return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header));
614 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
616 return size >= 14
617 && b[0] == 0x42 && b[1] == 0x4d
618 && *(const DWORD *)(b+6) == 0;
621 static BOOL video_avi_filter(const BYTE *b, DWORD size)
623 return size > 12
624 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
625 && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20;
628 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
630 return size > 4
631 && !b[0] && !b[1] && b[2] == 0x01
632 && (b[3] == 0xb3 || b[3] == 0xba);
635 static BOOL application_postscript_filter(const BYTE *b, DWORD size)
637 return size > 2 && b[0] == '%' && b[1] == '!';
640 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
642 return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
645 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
647 return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
650 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
652 return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
655 static BOOL application_java_filter(const BYTE *b, DWORD size)
657 return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
660 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
662 return size > 2 && b[0] == 'M' && b[1] == 'Z';
665 static BOOL text_plain_filter(const BYTE *b, DWORD size)
667 const BYTE *ptr;
669 for(ptr = b; ptr < b+size-1; ptr++) {
670 if(*ptr < 0x20 && *ptr != '\n' && *ptr != '\r' && *ptr != '\t')
671 return FALSE;
674 return TRUE;
677 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
679 return TRUE;
682 static HRESULT find_mime_from_buffer(const BYTE *buf, DWORD size, const WCHAR *proposed_mime, WCHAR **ret_mime)
684 LPCWSTR ret = NULL;
685 DWORD len, i;
687 static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0};
688 static const WCHAR text_richtextW[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0};
689 static const WCHAR audio_basicW[] = {'a','u','d','i','o','/','b','a','s','i','c',0};
690 static const WCHAR audio_wavW[] = {'a','u','d','i','o','/','w','a','v',0};
691 static const WCHAR image_gifW[] = {'i','m','a','g','e','/','g','i','f',0};
692 static const WCHAR image_pjpegW[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
693 static const WCHAR image_tiffW[] = {'i','m','a','g','e','/','t','i','f','f',0};
694 static const WCHAR image_xpngW[] = {'i','m','a','g','e','/','x','-','p','n','g',0};
695 static const WCHAR image_bmpW[] = {'i','m','a','g','e','/','b','m','p',0};
696 static const WCHAR video_aviW[] = {'v','i','d','e','o','/','a','v','i',0};
697 static const WCHAR video_mpegW[] = {'v','i','d','e','o','/','m','p','e','g',0};
698 static const WCHAR app_postscriptW[] =
699 {'a','p','p','l','i','c','a','t','i','o','n','/','p','o','s','t','s','c','r','i','p','t',0};
700 static const WCHAR app_pdfW[] = {'a','p','p','l','i','c','a','t','i','o','n','/','p','d','f',0};
701 static const WCHAR app_xzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
702 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
703 static const WCHAR app_xgzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
704 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
705 static const WCHAR app_javaW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
706 'j','a','v','a',0};
707 static const WCHAR app_xmsdownloadW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
708 'x','-','m','s','d','o','w','n','l','o','a','d',0};
709 static const WCHAR text_plainW[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
710 static const WCHAR app_octetstreamW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
711 'o','c','t','e','t','-','s','t','r','e','a','m','\0'};
713 static const struct {
714 LPCWSTR mime;
715 BOOL (*filter)(const BYTE *,DWORD);
716 } mime_filters[] = {
717 {text_htmlW, text_html_filter},
718 {text_richtextW, text_richtext_filter},
719 /* {audio_xaiffW, audio_xaiff_filter}, */
720 {audio_basicW, audio_basic_filter},
721 {audio_wavW, audio_wav_filter},
722 {image_gifW, image_gif_filter},
723 {image_pjpegW, image_pjpeg_filter},
724 {image_tiffW, image_tiff_filter},
725 {image_xpngW, image_xpng_filter},
726 /* {image_xbitmapW, image_xbitmap_filter}, */
727 {image_bmpW, image_bmp_filter},
728 /* {image_xjgW, image_xjg_filter}, */
729 /* {image_xemfW, image_xemf_filter}, */
730 /* {image_xwmfW, image_xwmf_filter}, */
731 {video_aviW, video_avi_filter},
732 {video_mpegW, video_mpeg_filter},
733 {app_postscriptW, application_postscript_filter},
734 /* {app_base64W, application_base64_filter}, */
735 /* {app_macbinhex40W, application_macbinhex40_filter}, */
736 {app_pdfW, application_pdf_filter},
737 /* {app_zcompressedW, application_xcompressed_filter}, */
738 {app_xzipW, application_xzip_filter},
739 {app_xgzipW, application_xgzip_filter},
740 {app_javaW, application_java_filter},
741 {app_xmsdownloadW, application_xmsdownload},
742 {text_plainW, text_plain_filter},
743 {app_octetstreamW, application_octet_stream_filter}
746 if(!buf || !size) {
747 if(!proposed_mime)
748 return E_FAIL;
750 len = strlenW(proposed_mime)+1;
751 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
752 if(!*ret_mime)
753 return E_OUTOFMEMORY;
755 memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR));
756 return S_OK;
759 if(proposed_mime && strcmpW(proposed_mime, app_octetstreamW)) {
760 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
761 if(!strcmpW(proposed_mime, mime_filters[i].mime))
762 break;
765 if(i == sizeof(mime_filters)/sizeof(*mime_filters) || mime_filters[i].filter(buf, size)) {
766 len = strlenW(proposed_mime)+1;
767 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
768 if(!*ret_mime)
769 return E_OUTOFMEMORY;
771 memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR));
772 return S_OK;
776 i=0;
777 while(!ret) {
778 if(mime_filters[i].filter(buf, size))
779 ret = mime_filters[i].mime;
780 i++;
783 TRACE("found %s for %s\n", debugstr_w(ret), debugstr_an((const char*)buf, min(32, size)));
785 if(proposed_mime) {
786 if(i == sizeof(mime_filters)/sizeof(*mime_filters))
787 ret = proposed_mime;
789 /* text/html is a special case */
790 if(!strcmpW(proposed_mime, text_htmlW) && !strcmpW(ret, text_plainW))
791 ret = text_htmlW;
794 len = strlenW(ret)+1;
795 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
796 if(!*ret_mime)
797 return E_OUTOFMEMORY;
799 memcpy(*ret_mime, ret, len*sizeof(WCHAR));
800 return S_OK;
803 /***********************************************************************
804 * FindMimeFromData (URLMON.@)
806 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
808 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
809 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
810 LPWSTR* ppwzMimeOut, DWORD dwReserved)
812 TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
813 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
815 if(dwMimeFlags)
816 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
817 if(dwReserved)
818 WARN("dwReserved=%d\n", dwReserved);
820 /* pBC seams to not be used */
822 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
823 return E_INVALIDARG;
825 if(pwzMimeProposed || pBuffer)
826 return find_mime_from_buffer(pBuffer, cbSize, pwzMimeProposed, ppwzMimeOut);
828 if(pwzUrl) {
829 HKEY hkey;
830 DWORD res, size;
831 LPCWSTR ptr;
832 WCHAR mime[64];
834 static const WCHAR wszContentType[] =
835 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
837 ptr = strrchrW(pwzUrl, '.');
838 if(!ptr)
839 return E_FAIL;
841 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
842 if(res != ERROR_SUCCESS)
843 return HRESULT_FROM_WIN32(res);
845 size = sizeof(mime);
846 res = RegQueryValueExW(hkey, wszContentType, NULL, NULL, (LPBYTE)mime, &size);
847 RegCloseKey(hkey);
848 if(res != ERROR_SUCCESS)
849 return HRESULT_FROM_WIN32(res);
851 *ppwzMimeOut = CoTaskMemAlloc(size);
852 memcpy(*ppwzMimeOut, mime, size);
853 return S_OK;
856 return E_FAIL;
859 /***********************************************************************
860 * GetClassFileOrMime (URLMON.@)
862 * Determines the class ID from the bind context, file name or MIME type.
864 HRESULT WINAPI GetClassFileOrMime(LPBC pBC, LPCWSTR pszFilename,
865 LPVOID pBuffer, DWORD cbBuffer, LPCWSTR pszMimeType, DWORD dwReserved,
866 CLSID *pclsid)
868 FIXME("(%p, %s, %p, %d, %p, 0x%08x, %p): stub\n", pBC,
869 debugstr_w(pszFilename), pBuffer, cbBuffer, debugstr_w(pszMimeType),
870 dwReserved, pclsid);
871 return E_NOTIMPL;
874 /***********************************************************************
875 * Extract (URLMON.@)
877 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
879 HRESULT (WINAPI *pExtract)(void *, LPCSTR);
881 if (!hCabinet)
882 hCabinet = LoadLibraryA("cabinet.dll");
884 if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
885 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
886 if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());
888 return pExtract(dest, szCabName);
891 /***********************************************************************
892 * IsLoggingEnabledA (URLMON.@)
894 BOOL WINAPI IsLoggingEnabledA(LPCSTR url)
896 FIXME("(%s)\n", debugstr_a(url));
897 return FALSE;
900 /***********************************************************************
901 * IsLoggingEnabledW (URLMON.@)
903 BOOL WINAPI IsLoggingEnabledW(LPCWSTR url)
905 FIXME("(%s)\n", debugstr_w(url));
906 return FALSE;
909 /***********************************************************************
910 * URLMON_410 (URLMON.410)
911 * Undocumented, added in IE8
913 BOOL WINAPI URLMON_410(DWORD unknown1, DWORD unknown2)
915 FIXME("stub: %d %d\n", unknown1, unknown2);
916 return FALSE;
919 /***********************************************************************
920 * URLMON_423 (URLMON.423)
921 * Undocumented, added in IE8
923 BOOL WINAPI URLMON_423(DWORD unknown1, DWORD unknown2, DWORD unknown3, DWORD unknown4)
925 FIXME("stub: %d %d %d %d\n", unknown1, unknown2, unknown3, unknown4);
926 return FALSE;