push 52cba0a224aad01bcbdb26d79e43229ba950650e
[wine/hacks.git] / dlls / urlmon / urlmon_main.c
blob3203753f923dc23ca6cb43c07acb1e0d441dabba
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 "wine/debug.h"
31 #include "urlmon.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
35 LONG URLMON_refCount = 0;
37 HINSTANCE URLMON_hInstance = 0;
38 static HMODULE hCabinet = NULL;
39 static DWORD urlmon_tls;
41 static void init_session(BOOL);
43 static struct list tls_list = LIST_INIT(tls_list);
45 static CRITICAL_SECTION tls_cs;
46 static CRITICAL_SECTION_DEBUG tls_cs_dbg =
48 0, 0, &tls_cs,
49 { &tls_cs_dbg.ProcessLocksList, &tls_cs_dbg.ProcessLocksList },
50 0, 0, { (DWORD_PTR)(__FILE__ ": tls") }
53 static CRITICAL_SECTION tls_cs = { &tls_cs_dbg, -1, 0, 0, 0, 0 };
55 tls_data_t *get_tls_data(void)
57 tls_data_t *data;
59 if(!urlmon_tls) {
60 DWORD tls = TlsAlloc();
61 tls = InterlockedCompareExchange((LONG*)&urlmon_tls, tls, 0);
62 if(tls != urlmon_tls)
63 TlsFree(tls);
66 data = TlsGetValue(urlmon_tls);
67 if(!data) {
68 data = heap_alloc_zero(sizeof(tls_data_t));
69 if(!data)
70 return NULL;
72 EnterCriticalSection(&tls_cs);
73 list_add_tail(&tls_list, &data->entry);
74 LeaveCriticalSection(&tls_cs);
76 TlsSetValue(urlmon_tls, data);
79 return data;
82 static void free_tls_list(void)
84 tls_data_t *data;
86 if(!urlmon_tls)
87 return;
89 while(!list_empty(&tls_list)) {
90 data = LIST_ENTRY(list_head(&tls_list), tls_data_t, entry);
91 list_remove(&data->entry);
92 heap_free(data);
95 TlsFree(urlmon_tls);
98 static void detach_thread(void)
100 tls_data_t *data;
102 if(!urlmon_tls)
103 return;
105 data = TlsGetValue(urlmon_tls);
106 if(!data)
107 return;
109 EnterCriticalSection(&tls_cs);
110 list_remove(&data->entry);
111 LeaveCriticalSection(&tls_cs);
113 if(data->notif_hwnd) {
114 WARN("notif_hwnd not destroyed\n");
115 DestroyWindow(data->notif_hwnd);
118 heap_free(data);
121 /***********************************************************************
122 * DllMain (URLMON.init)
124 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
126 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
128 switch(fdwReason) {
129 case DLL_PROCESS_ATTACH:
130 URLMON_hInstance = hinstDLL;
131 init_session(TRUE);
132 break;
134 case DLL_PROCESS_DETACH:
135 if (hCabinet)
136 FreeLibrary(hCabinet);
137 hCabinet = NULL;
138 init_session(FALSE);
139 free_tls_list();
140 URLMON_hInstance = 0;
141 break;
143 case DLL_THREAD_DETACH:
144 detach_thread();
145 break;
147 return TRUE;
151 /***********************************************************************
152 * DllInstall (URLMON.@)
154 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
156 FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
157 debugstr_w(cmdline));
159 return S_OK;
162 /***********************************************************************
163 * DllCanUnloadNow (URLMON.@)
165 HRESULT WINAPI DllCanUnloadNow(void)
167 return URLMON_refCount != 0 ? S_FALSE : S_OK;
172 /******************************************************************************
173 * Urlmon ClassFactory
175 typedef struct {
176 const IClassFactoryVtbl *lpClassFactoryVtbl;
178 HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
179 } ClassFactory;
181 #define CLASSFACTORY(x) ((IClassFactory*) &(x)->lpClassFactoryVtbl)
183 static HRESULT WINAPI CF_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppv)
185 *ppv = NULL;
187 if(IsEqualGUID(riid, &IID_IUnknown)) {
188 TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
189 *ppv = iface;
190 }else if(IsEqualGUID(riid, &IID_IClassFactory)) {
191 TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv);
192 *ppv = iface;
195 if(*ppv) {
196 IUnknown_AddRef((IUnknown*)*ppv);
197 return S_OK;
200 WARN("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ppv);
201 return E_NOINTERFACE;
204 static ULONG WINAPI CF_AddRef(IClassFactory *iface)
206 URLMON_LockModule();
207 return 2;
210 static ULONG WINAPI CF_Release(IClassFactory *iface)
212 URLMON_UnlockModule();
213 return 1;
217 static HRESULT WINAPI CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
218 REFIID riid, LPVOID *ppobj)
220 ClassFactory *This = (ClassFactory*)iface;
221 HRESULT hres;
222 LPUNKNOWN punk;
224 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
226 *ppobj = NULL;
227 if(SUCCEEDED(hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk))) {
228 hres = IUnknown_QueryInterface(punk, riid, ppobj);
229 IUnknown_Release(punk);
231 return hres;
234 static HRESULT WINAPI CF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
236 TRACE("(%d)\n", dolock);
238 if (dolock)
239 URLMON_LockModule();
240 else
241 URLMON_UnlockModule();
243 return S_OK;
246 static const IClassFactoryVtbl ClassFactoryVtbl =
248 CF_QueryInterface,
249 CF_AddRef,
250 CF_Release,
251 CF_CreateInstance,
252 CF_LockServer
255 static const ClassFactory FileProtocolCF =
256 { &ClassFactoryVtbl, FileProtocol_Construct};
257 static const ClassFactory FtpProtocolCF =
258 { &ClassFactoryVtbl, FtpProtocol_Construct};
259 static const ClassFactory GopherProtocolCF =
260 { &ClassFactoryVtbl, GopherProtocol_Construct};
261 static const ClassFactory HttpProtocolCF =
262 { &ClassFactoryVtbl, HttpProtocol_Construct};
263 static const ClassFactory HttpSProtocolCF =
264 { &ClassFactoryVtbl, HttpSProtocol_Construct};
265 static const ClassFactory MkProtocolCF =
266 { &ClassFactoryVtbl, MkProtocol_Construct};
267 static const ClassFactory SecurityManagerCF =
268 { &ClassFactoryVtbl, SecManagerImpl_Construct};
269 static const ClassFactory ZoneManagerCF =
270 { &ClassFactoryVtbl, ZoneMgrImpl_Construct};
271 static const ClassFactory StdURLMonikerCF =
272 { &ClassFactoryVtbl, StdURLMoniker_Construct};
273 static const ClassFactory MimeFilterCF =
274 { &ClassFactoryVtbl, MimeFilter_Construct};
276 struct object_creation_info
278 const CLSID *clsid;
279 IClassFactory *cf;
280 LPCWSTR protocol;
283 static const WCHAR wszFile[] = {'f','i','l','e',0};
284 static const WCHAR wszFtp[] = {'f','t','p',0};
285 static const WCHAR wszGopher[] = {'g','o','p','h','e','r',0};
286 static const WCHAR wszHttp[] = {'h','t','t','p',0};
287 static const WCHAR wszHttps[] = {'h','t','t','p','s',0};
288 static const WCHAR wszMk[] = {'m','k',0};
290 static const struct object_creation_info object_creation[] =
292 { &CLSID_FileProtocol, CLASSFACTORY(&FileProtocolCF), wszFile },
293 { &CLSID_FtpProtocol, CLASSFACTORY(&FtpProtocolCF), wszFtp },
294 { &CLSID_GopherProtocol, CLASSFACTORY(&GopherProtocolCF), wszGopher },
295 { &CLSID_HttpProtocol, CLASSFACTORY(&HttpProtocolCF), wszHttp },
296 { &CLSID_HttpSProtocol, CLASSFACTORY(&HttpSProtocolCF), wszHttps },
297 { &CLSID_MkProtocol, CLASSFACTORY(&MkProtocolCF), wszMk },
298 { &CLSID_InternetSecurityManager, CLASSFACTORY(&SecurityManagerCF), NULL },
299 { &CLSID_InternetZoneManager, CLASSFACTORY(&ZoneManagerCF), NULL },
300 { &CLSID_StdURLMoniker, CLASSFACTORY(&StdURLMonikerCF), NULL },
301 { &CLSID_DeCompMimeFilter, CLASSFACTORY(&MimeFilterCF), NULL }
304 static void init_session(BOOL init)
306 unsigned int i;
308 for(i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) {
310 if(object_creation[i].protocol)
311 register_urlmon_namespace(object_creation[i].cf, object_creation[i].clsid,
312 object_creation[i].protocol, init);
316 /*******************************************************************************
317 * DllGetClassObject [URLMON.@]
318 * Retrieves class object from a DLL object
320 * NOTES
321 * Docs say returns STDAPI
323 * PARAMS
324 * rclsid [I] CLSID for the class object
325 * riid [I] Reference to identifier of interface for class object
326 * ppv [O] Address of variable to receive interface pointer for riid
328 * RETURNS
329 * Success: S_OK
330 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
331 * E_UNEXPECTED
334 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
336 unsigned int i;
338 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
340 for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
342 if (IsEqualGUID(object_creation[i].clsid, rclsid))
343 return IClassFactory_QueryInterface(object_creation[i].cf, riid, ppv);
346 FIXME("%s: no class found.\n", debugstr_guid(rclsid));
347 return CLASS_E_CLASSNOTAVAILABLE;
351 /***********************************************************************
352 * DllRegisterServerEx (URLMON.@)
354 HRESULT WINAPI DllRegisterServerEx(void)
356 FIXME("(void): stub\n");
358 return E_FAIL;
361 /**************************************************************************
362 * UrlMkSetSessionOption (URLMON.@)
364 HRESULT WINAPI UrlMkSetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength,
365 DWORD Reserved)
367 FIXME("(%#x, %p, %#x): stub\n", dwOption, pBuffer, dwBufferLength);
369 return S_OK;
372 static const CHAR Agent[] = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)";
374 /**************************************************************************
375 * ObtainUserAgentString (URLMON.@)
377 HRESULT WINAPI ObtainUserAgentString(DWORD dwOption, LPSTR pcszUAOut, DWORD *cbSize)
379 FIXME("(%d, %p, %p): stub\n", dwOption, pcszUAOut, cbSize);
381 if (pcszUAOut == NULL || cbSize == NULL)
382 return E_INVALIDARG;
384 if (*cbSize < sizeof(Agent))
386 *cbSize = sizeof(Agent);
387 return E_OUTOFMEMORY;
390 if (sizeof(Agent) < *cbSize)
391 *cbSize = sizeof(Agent);
392 lstrcpynA(pcszUAOut, Agent, *cbSize);
394 return S_OK;
397 /**************************************************************************
398 * IsValidURL (URLMON.@)
400 * Determines if a specified string is a valid URL.
402 * PARAMS
403 * pBC [I] ignored, must be NULL.
404 * szURL [I] string that represents the URL in question.
405 * dwReserved [I] reserved and must be zero.
407 * RETURNS
408 * Success: S_OK.
409 * Failure: S_FALSE.
410 * returns E_INVALIDARG if one or more of the args is invalid.
412 * TODO:
413 * test functionality against windows to see what a valid URL is.
415 HRESULT WINAPI IsValidURL(LPBC pBC, LPCWSTR szURL, DWORD dwReserved)
417 FIXME("(%p, %s, %d): stub\n", pBC, debugstr_w(szURL), dwReserved);
419 if (pBC != NULL || dwReserved != 0)
420 return E_INVALIDARG;
422 return S_OK;
425 /**************************************************************************
426 * FaultInIEFeature (URLMON.@)
428 * Undocumented. Appears to be used by native shdocvw.dll.
430 HRESULT WINAPI FaultInIEFeature( HWND hwnd, uCLSSPEC * pClassSpec,
431 QUERYCONTEXT *pQuery, DWORD flags )
433 FIXME("%p %p %p %08x\n", hwnd, pClassSpec, pQuery, flags);
434 return E_NOTIMPL;
437 /**************************************************************************
438 * CoGetClassObjectFromURL (URLMON.@)
440 HRESULT WINAPI CoGetClassObjectFromURL( REFCLSID rclsid, LPCWSTR szCodeURL, DWORD dwFileVersionMS,
441 DWORD dwFileVersionLS, LPCWSTR szContentType,
442 LPBINDCTX pBindCtx, DWORD dwClsContext, LPVOID pvReserved,
443 REFIID riid, LPVOID *ppv )
445 FIXME("(%s %s %d %d %s %p %d %p %s %p) Stub!\n", debugstr_guid(rclsid), debugstr_w(szCodeURL),
446 dwFileVersionMS, dwFileVersionLS, debugstr_w(szContentType), pBindCtx, dwClsContext, pvReserved,
447 debugstr_guid(riid), ppv);
448 return E_NOINTERFACE;
451 /***********************************************************************
452 * ReleaseBindInfo (URLMON.@)
454 * Release the resources used by the specified BINDINFO structure.
456 * PARAMS
457 * pbindinfo [I] BINDINFO to release.
459 * RETURNS
460 * Nothing.
462 void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo)
464 DWORD size;
466 TRACE("(%p)\n", pbindinfo);
468 if(!pbindinfo || !(size = pbindinfo->cbSize))
469 return;
471 CoTaskMemFree(pbindinfo->szExtraInfo);
472 ReleaseStgMedium(&pbindinfo->stgmedData);
474 if(offsetof(BINDINFO, szExtraInfo) < size)
475 CoTaskMemFree(pbindinfo->szCustomVerb);
477 if(pbindinfo->pUnk && offsetof(BINDINFO, pUnk) < size)
478 IUnknown_Release(pbindinfo->pUnk);
480 memset(pbindinfo, 0, size);
481 pbindinfo->cbSize = size;
484 /***********************************************************************
485 * CopyStgMedium (URLMON.@)
487 HRESULT WINAPI CopyStgMedium(const STGMEDIUM *src, STGMEDIUM *dst)
489 TRACE("(%p %p)\n", src, dst);
491 if(!src || !dst)
492 return E_POINTER;
494 *dst = *src;
496 switch(dst->tymed) {
497 case TYMED_NULL:
498 break;
499 case TYMED_FILE:
500 if(src->u.lpszFileName && !src->pUnkForRelease) {
501 DWORD size = (strlenW(src->u.lpszFileName)+1)*sizeof(WCHAR);
502 dst->u.lpszFileName = CoTaskMemAlloc(size);
503 memcpy(dst->u.lpszFileName, src->u.lpszFileName, size);
505 break;
506 case TYMED_ISTREAM:
507 if(dst->u.pstm)
508 IStream_AddRef(dst->u.pstm);
509 break;
510 case TYMED_ISTORAGE:
511 if(dst->u.pstg)
512 IStorage_AddRef(dst->u.pstg);
513 break;
514 default:
515 FIXME("Unimplemented tymed %d\n", src->tymed);
518 if(dst->pUnkForRelease)
519 IUnknown_AddRef(dst->pUnkForRelease);
521 return S_OK;
524 static BOOL text_richtext_filter(const BYTE *b, DWORD size)
526 return size > 5 && !memcmp(b, "{\\rtf", 5);
529 static BOOL text_html_filter(const BYTE *b, DWORD size)
531 DWORD i;
533 if(size < 5)
534 return FALSE;
536 for(i=0; i < size-5; i++) {
537 if(b[i] == '<'
538 && (b[i+1] == 'h' || b[i+1] == 'H')
539 && (b[i+2] == 't' || b[i+2] == 'T')
540 && (b[i+3] == 'm' || b[i+3] == 'M')
541 && (b[i+4] == 'l' || b[i+4] == 'L'))
542 return TRUE;
545 return FALSE;
548 static BOOL audio_basic_filter(const BYTE *b, DWORD size)
550 return size > 4
551 && b[0] == '.' && b[1] == 's' && b[2] == 'n' && b[3] == 'd';
554 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
556 return size > 12
557 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
558 && b[8] == 'W' && b[9] == 'A' && b[10] == 'V' && b[11] == 'E';
561 static BOOL image_gif_filter(const BYTE *b, DWORD size)
563 return size >= 6
564 && (b[0] == 'G' || b[0] == 'g')
565 && (b[1] == 'I' || b[1] == 'i')
566 && (b[2] == 'F' || b[2] == 'f')
567 && b[3] == '8'
568 && (b[4] == '7' || b[4] == '9')
569 && (b[5] == 'A' || b[5] == 'a');
572 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
574 return size > 2 && b[0] == 0xff && b[1] == 0xd8;
577 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
579 return size > 2 && b[0] == 0x4d && b[1] == 0x4d;
582 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
584 static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
585 return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header));
588 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
590 return size >= 14
591 && b[0] == 0x42 && b[1] == 0x4d
592 && *(const DWORD *)(b+6) == 0;
595 static BOOL video_avi_filter(const BYTE *b, DWORD size)
597 return size > 12
598 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
599 && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20;
602 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
604 return size > 4
605 && !b[0] && !b[1] && b[2] == 0x01
606 && (b[3] == 0xb3 || b[3] == 0xba);
609 static BOOL application_postscript_filter(const BYTE *b, DWORD size)
611 return size > 2 && b[0] == '%' && b[1] == '!';
614 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
616 return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
619 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
621 return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
624 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
626 return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
629 static BOOL application_java_filter(const BYTE *b, DWORD size)
631 return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
634 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
636 return size > 2 && b[0] == 'M' && b[1] == 'Z';
639 static BOOL text_plain_filter(const BYTE *b, DWORD size)
641 const BYTE *ptr;
643 for(ptr = b; ptr < b+size-1; ptr++) {
644 if(*ptr < 0x20 && *ptr != '\n' && *ptr != '\r' && *ptr != '\t')
645 return FALSE;
648 return TRUE;
651 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
653 return TRUE;
656 /***********************************************************************
657 * FindMimeFromData (URLMON.@)
659 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
661 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
662 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
663 LPWSTR* ppwzMimeOut, DWORD dwReserved)
665 TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
666 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
668 if(dwMimeFlags)
669 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
670 if(dwReserved)
671 WARN("dwReserved=%d\n", dwReserved);
673 /* pBC seams to not be used */
675 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
676 return E_INVALIDARG;
678 if(pwzMimeProposed && (!pBuffer || (pBuffer && !cbSize))) {
679 DWORD len;
681 if(!pwzMimeProposed)
682 return E_FAIL;
684 len = strlenW(pwzMimeProposed)+1;
685 *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
686 memcpy(*ppwzMimeOut, pwzMimeProposed, len*sizeof(WCHAR));
687 return S_OK;
690 if(pBuffer) {
691 const BYTE *buf = pBuffer;
692 DWORD len;
693 LPCWSTR ret = NULL;
694 unsigned int i;
696 static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
697 static const WCHAR wszTextRichtext[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0};
698 static const WCHAR wszAudioBasic[] = {'a','u','d','i','o','/','b','a','s','i','c',0};
699 static const WCHAR wszAudioWav[] = {'a','u','d','i','o','/','w','a','v',0};
700 static const WCHAR wszImageGif[] = {'i','m','a','g','e','/','g','i','f',0};
701 static const WCHAR wszImagePjpeg[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
702 static const WCHAR wszImageTiff[] = {'i','m','a','g','e','/','t','i','f','f',0};
703 static const WCHAR wszImageXPng[] = {'i','m','a','g','e','/','x','-','p','n','g',0};
704 static const WCHAR wszImageBmp[] = {'i','m','a','g','e','/','b','m','p',0};
705 static const WCHAR wszVideoAvi[] = {'v','i','d','e','o','/','a','v','i',0};
706 static const WCHAR wszVideoMpeg[] = {'v','i','d','e','o','/','m','p','e','g',0};
707 static const WCHAR wszAppPostscript[] =
708 {'a','p','p','l','i','c','a','t','i','o','n','/','p','o','s','t','s','c','r','i','p','t',0};
709 static const WCHAR wszAppPdf[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
710 'p','d','f',0};
711 static const WCHAR wszAppXZip[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
712 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
713 static const WCHAR wszAppXGzip[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
714 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
715 static const WCHAR wszAppJava[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
716 'j','a','v','a',0};
717 static const WCHAR wszAppXMSDownload[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
718 'x','-','m','s','d','o','w','n','l','o','a','d',0};
719 static const WCHAR wszTextPlain[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
720 static const WCHAR wszAppOctetStream[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
721 'o','c','t','e','t','-','s','t','r','e','a','m','\0'};
723 static const struct {
724 LPCWSTR mime;
725 BOOL (*filter)(const BYTE *,DWORD);
726 } mime_filters[] = {
727 {wszTextHtml, text_html_filter},
728 {wszTextRichtext, text_richtext_filter},
729 /* {wszAudioXAiff, audio_xaiff_filter}, */
730 {wszAudioBasic, audio_basic_filter},
731 {wszAudioWav, audio_wav_filter},
732 {wszImageGif, image_gif_filter},
733 {wszImagePjpeg, image_pjpeg_filter},
734 {wszImageTiff, image_tiff_filter},
735 {wszImageXPng, image_xpng_filter},
736 /* {wszImageXBitmap, image_xbitmap_filter}, */
737 {wszImageBmp, image_bmp_filter},
738 /* {wszImageXJg, image_xjg_filter}, */
739 /* {wszImageXEmf, image_xemf_filter}, */
740 /* {wszImageXWmf, image_xwmf_filter}, */
741 {wszVideoAvi, video_avi_filter},
742 {wszVideoMpeg, video_mpeg_filter},
743 {wszAppPostscript, application_postscript_filter},
744 /* {wszAppBase64, application_base64_filter}, */
745 /* {wszAppMacbinhex40, application_macbinhex40_filter}, */
746 {wszAppPdf, application_pdf_filter},
747 /* {wszAppXCompressed, application_xcompressed_filter}, */
748 {wszAppXZip, application_xzip_filter},
749 {wszAppXGzip, application_xgzip_filter},
750 {wszAppJava, application_java_filter},
751 {wszAppXMSDownload, application_xmsdownload},
752 {wszTextPlain, text_plain_filter},
753 {wszAppOctetStream, application_octet_stream_filter}
756 if(!cbSize)
757 return E_FAIL;
759 if(pwzMimeProposed && strcmpW(pwzMimeProposed, wszAppOctetStream)) {
760 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
761 if(!strcmpW(pwzMimeProposed, mime_filters[i].mime))
762 break;
765 if(i == sizeof(mime_filters)/sizeof(*mime_filters)
766 || mime_filters[i].filter(buf, cbSize)) {
767 len = strlenW(pwzMimeProposed)+1;
768 *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
769 memcpy(*ppwzMimeOut, pwzMimeProposed, len*sizeof(WCHAR));
770 return S_OK;
774 i=0;
775 while(!ret) {
776 if(mime_filters[i].filter(buf, cbSize))
777 ret = mime_filters[i].mime;
778 i++;
781 TRACE("found %s for data\n"
782 "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
783 debugstr_w(ret), buf[0],buf[1],buf[2],buf[3], buf[4],buf[5],buf[6],buf[7],
784 buf[8],buf[9],buf[10],buf[11], buf[12],buf[13],buf[14],buf[15]);
786 if(pwzMimeProposed) {
787 if(i == sizeof(mime_filters)/sizeof(*mime_filters))
788 ret = pwzMimeProposed;
790 /* text/html is a special case */
791 if(!strcmpW(pwzMimeProposed, wszTextHtml) && !strcmpW(ret, wszTextPlain))
792 ret = wszTextHtml;
795 len = strlenW(ret)+1;
796 *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
797 memcpy(*ppwzMimeOut, ret, len*sizeof(WCHAR));
798 return S_OK;
801 if(pwzUrl) {
802 HKEY hkey;
803 DWORD res, size;
804 LPCWSTR ptr;
805 WCHAR mime[64];
807 static const WCHAR wszContentType[] =
808 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
810 ptr = strrchrW(pwzUrl, '.');
811 if(!ptr)
812 return E_FAIL;
814 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
815 if(res != ERROR_SUCCESS)
816 return HRESULT_FROM_WIN32(res);
818 size = sizeof(mime);
819 res = RegQueryValueExW(hkey, wszContentType, NULL, NULL, (LPBYTE)mime, &size);
820 RegCloseKey(hkey);
821 if(res != ERROR_SUCCESS)
822 return HRESULT_FROM_WIN32(res);
824 *ppwzMimeOut = CoTaskMemAlloc(size);
825 memcpy(*ppwzMimeOut, mime, size);
826 return S_OK;
829 return E_FAIL;
832 /***********************************************************************
833 * GetClassFileOrMime (URLMON.@)
835 * Determines the class ID from the bind context, file name or MIME type.
837 HRESULT WINAPI GetClassFileOrMime(LPBC pBC, LPCWSTR pszFilename,
838 LPVOID pBuffer, DWORD cbBuffer, LPCWSTR pszMimeType, DWORD dwReserved,
839 CLSID *pclsid)
841 FIXME("(%p, %s, %p, %d, %p, 0x%08x, %p): stub\n", pBC,
842 debugstr_w(pszFilename), pBuffer, cbBuffer, debugstr_w(pszMimeType),
843 dwReserved, pclsid);
844 return E_NOTIMPL;
847 /***********************************************************************
848 * Extract (URLMON.@)
850 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
852 HRESULT (WINAPI *pExtract)(void *, LPCSTR);
854 if (!hCabinet)
855 hCabinet = LoadLibraryA("cabinet.dll");
857 if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
858 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
859 if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());
861 return pExtract(dest, szCabName);
864 /***********************************************************************
865 * IsLoggingEnabledA (URLMON.@)
867 BOOL WINAPI IsLoggingEnabledA(LPCSTR url)
869 FIXME("(%s)\n", debugstr_a(url));
870 return FALSE;
873 /***********************************************************************
874 * IsLoggingEnabledW (URLMON.@)
876 BOOL WINAPI IsLoggingEnabledW(LPCWSTR url)
878 FIXME("(%s)\n", debugstr_w(url));
879 return FALSE;