rpcrt4/tests: Fix a few more broken tests on NT4.
[wine.git] / dlls / urlmon / urlmon_main.c
blob6e51db56b9891e7316e8098de2c95c991c55ee7d
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 = TLS_OUT_OF_INDEXES;
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 == TLS_OUT_OF_INDEXES) {
60 DWORD tls = TlsAlloc();
61 if(tls == TLS_OUT_OF_INDEXES)
62 return NULL;
64 tls = InterlockedCompareExchange((LONG*)&urlmon_tls, tls, TLS_OUT_OF_INDEXES);
65 if(tls != urlmon_tls)
66 TlsFree(tls);
69 data = TlsGetValue(urlmon_tls);
70 if(!data) {
71 data = heap_alloc_zero(sizeof(tls_data_t));
72 if(!data)
73 return NULL;
75 EnterCriticalSection(&tls_cs);
76 list_add_tail(&tls_list, &data->entry);
77 LeaveCriticalSection(&tls_cs);
79 TlsSetValue(urlmon_tls, data);
82 return data;
85 static void free_tls_list(void)
87 tls_data_t *data;
89 if(urlmon_tls == TLS_OUT_OF_INDEXES)
90 return;
92 while(!list_empty(&tls_list)) {
93 data = LIST_ENTRY(list_head(&tls_list), tls_data_t, entry);
94 list_remove(&data->entry);
95 heap_free(data);
98 TlsFree(urlmon_tls);
101 static void detach_thread(void)
103 tls_data_t *data;
105 if(urlmon_tls == TLS_OUT_OF_INDEXES)
106 return;
108 data = TlsGetValue(urlmon_tls);
109 if(!data)
110 return;
112 EnterCriticalSection(&tls_cs);
113 list_remove(&data->entry);
114 LeaveCriticalSection(&tls_cs);
116 if(data->notif_hwnd) {
117 WARN("notif_hwnd not destroyed\n");
118 DestroyWindow(data->notif_hwnd);
121 heap_free(data);
124 /***********************************************************************
125 * DllMain (URLMON.init)
127 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
129 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
131 switch(fdwReason) {
132 case DLL_PROCESS_ATTACH:
133 URLMON_hInstance = hinstDLL;
134 init_session(TRUE);
135 break;
137 case DLL_PROCESS_DETACH:
138 if (hCabinet)
139 FreeLibrary(hCabinet);
140 hCabinet = NULL;
141 init_session(FALSE);
142 free_tls_list();
143 URLMON_hInstance = 0;
144 break;
146 case DLL_THREAD_DETACH:
147 detach_thread();
148 break;
150 return TRUE;
154 /***********************************************************************
155 * DllInstall (URLMON.@)
157 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
159 FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
160 debugstr_w(cmdline));
162 return S_OK;
165 /***********************************************************************
166 * DllCanUnloadNow (URLMON.@)
168 HRESULT WINAPI DllCanUnloadNow(void)
170 return URLMON_refCount != 0 ? S_FALSE : S_OK;
175 /******************************************************************************
176 * Urlmon ClassFactory
178 typedef struct {
179 const IClassFactoryVtbl *lpClassFactoryVtbl;
181 HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
182 } ClassFactory;
184 #define CLASSFACTORY(x) ((IClassFactory*) &(x)->lpClassFactoryVtbl)
186 static HRESULT WINAPI CF_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppv)
188 *ppv = NULL;
190 if(IsEqualGUID(riid, &IID_IUnknown)) {
191 TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
192 *ppv = iface;
193 }else if(IsEqualGUID(riid, &IID_IClassFactory)) {
194 TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv);
195 *ppv = iface;
198 if(*ppv) {
199 IUnknown_AddRef((IUnknown*)*ppv);
200 return S_OK;
203 WARN("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ppv);
204 return E_NOINTERFACE;
207 static ULONG WINAPI CF_AddRef(IClassFactory *iface)
209 URLMON_LockModule();
210 return 2;
213 static ULONG WINAPI CF_Release(IClassFactory *iface)
215 URLMON_UnlockModule();
216 return 1;
220 static HRESULT WINAPI CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
221 REFIID riid, LPVOID *ppobj)
223 ClassFactory *This = (ClassFactory*)iface;
224 HRESULT hres;
225 LPUNKNOWN punk;
227 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
229 *ppobj = NULL;
230 if(SUCCEEDED(hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk))) {
231 hres = IUnknown_QueryInterface(punk, riid, ppobj);
232 IUnknown_Release(punk);
234 return hres;
237 static HRESULT WINAPI CF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
239 TRACE("(%d)\n", dolock);
241 if (dolock)
242 URLMON_LockModule();
243 else
244 URLMON_UnlockModule();
246 return S_OK;
249 static const IClassFactoryVtbl ClassFactoryVtbl =
251 CF_QueryInterface,
252 CF_AddRef,
253 CF_Release,
254 CF_CreateInstance,
255 CF_LockServer
258 static const ClassFactory FileProtocolCF =
259 { &ClassFactoryVtbl, FileProtocol_Construct};
260 static const ClassFactory FtpProtocolCF =
261 { &ClassFactoryVtbl, FtpProtocol_Construct};
262 static const ClassFactory GopherProtocolCF =
263 { &ClassFactoryVtbl, GopherProtocol_Construct};
264 static const ClassFactory HttpProtocolCF =
265 { &ClassFactoryVtbl, HttpProtocol_Construct};
266 static const ClassFactory HttpSProtocolCF =
267 { &ClassFactoryVtbl, HttpSProtocol_Construct};
268 static const ClassFactory MkProtocolCF =
269 { &ClassFactoryVtbl, MkProtocol_Construct};
270 static const ClassFactory SecurityManagerCF =
271 { &ClassFactoryVtbl, SecManagerImpl_Construct};
272 static const ClassFactory ZoneManagerCF =
273 { &ClassFactoryVtbl, ZoneMgrImpl_Construct};
274 static const ClassFactory StdURLMonikerCF =
275 { &ClassFactoryVtbl, StdURLMoniker_Construct};
276 static const ClassFactory MimeFilterCF =
277 { &ClassFactoryVtbl, MimeFilter_Construct};
279 struct object_creation_info
281 const CLSID *clsid;
282 IClassFactory *cf;
283 LPCWSTR protocol;
286 static const WCHAR wszFile[] = {'f','i','l','e',0};
287 static const WCHAR wszFtp[] = {'f','t','p',0};
288 static const WCHAR wszGopher[] = {'g','o','p','h','e','r',0};
289 static const WCHAR wszHttp[] = {'h','t','t','p',0};
290 static const WCHAR wszHttps[] = {'h','t','t','p','s',0};
291 static const WCHAR wszMk[] = {'m','k',0};
293 static const struct object_creation_info object_creation[] =
295 { &CLSID_FileProtocol, CLASSFACTORY(&FileProtocolCF), wszFile },
296 { &CLSID_FtpProtocol, CLASSFACTORY(&FtpProtocolCF), wszFtp },
297 { &CLSID_GopherProtocol, CLASSFACTORY(&GopherProtocolCF), wszGopher },
298 { &CLSID_HttpProtocol, CLASSFACTORY(&HttpProtocolCF), wszHttp },
299 { &CLSID_HttpSProtocol, CLASSFACTORY(&HttpSProtocolCF), wszHttps },
300 { &CLSID_MkProtocol, CLASSFACTORY(&MkProtocolCF), wszMk },
301 { &CLSID_InternetSecurityManager, CLASSFACTORY(&SecurityManagerCF), NULL },
302 { &CLSID_InternetZoneManager, CLASSFACTORY(&ZoneManagerCF), NULL },
303 { &CLSID_StdURLMoniker, CLASSFACTORY(&StdURLMonikerCF), NULL },
304 { &CLSID_DeCompMimeFilter, CLASSFACTORY(&MimeFilterCF), NULL }
307 static void init_session(BOOL init)
309 unsigned int i;
311 for(i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) {
313 if(object_creation[i].protocol)
314 register_urlmon_namespace(object_creation[i].cf, object_creation[i].clsid,
315 object_creation[i].protocol, init);
319 /*******************************************************************************
320 * DllGetClassObject [URLMON.@]
321 * Retrieves class object from a DLL object
323 * NOTES
324 * Docs say returns STDAPI
326 * PARAMS
327 * rclsid [I] CLSID for the class object
328 * riid [I] Reference to identifier of interface for class object
329 * ppv [O] Address of variable to receive interface pointer for riid
331 * RETURNS
332 * Success: S_OK
333 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
334 * E_UNEXPECTED
337 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
339 unsigned int i;
341 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
343 for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
345 if (IsEqualGUID(object_creation[i].clsid, rclsid))
346 return IClassFactory_QueryInterface(object_creation[i].cf, riid, ppv);
349 FIXME("%s: no class found.\n", debugstr_guid(rclsid));
350 return CLASS_E_CLASSNOTAVAILABLE;
354 /***********************************************************************
355 * DllRegisterServerEx (URLMON.@)
357 HRESULT WINAPI DllRegisterServerEx(void)
359 FIXME("(void): stub\n");
361 return E_FAIL;
364 /**************************************************************************
365 * UrlMkSetSessionOption (URLMON.@)
367 HRESULT WINAPI UrlMkSetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength,
368 DWORD Reserved)
370 FIXME("(%#x, %p, %#x): stub\n", dwOption, pBuffer, dwBufferLength);
372 return S_OK;
375 static const CHAR Agent[] = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)";
377 /**************************************************************************
378 * ObtainUserAgentString (URLMON.@)
380 HRESULT WINAPI ObtainUserAgentString(DWORD dwOption, LPSTR pcszUAOut, DWORD *cbSize)
382 FIXME("(%d, %p, %p): stub\n", dwOption, pcszUAOut, cbSize);
384 if (pcszUAOut == NULL || cbSize == NULL)
385 return E_INVALIDARG;
387 if (*cbSize < sizeof(Agent))
389 *cbSize = sizeof(Agent);
390 return E_OUTOFMEMORY;
393 if (sizeof(Agent) < *cbSize)
394 *cbSize = sizeof(Agent);
395 lstrcpynA(pcszUAOut, Agent, *cbSize);
397 return S_OK;
400 /**************************************************************************
401 * IsValidURL (URLMON.@)
403 * Determines if a specified string is a valid URL.
405 * PARAMS
406 * pBC [I] ignored, must be NULL.
407 * szURL [I] string that represents the URL in question.
408 * dwReserved [I] reserved and must be zero.
410 * RETURNS
411 * Success: S_OK.
412 * Failure: S_FALSE.
413 * returns E_INVALIDARG if one or more of the args is invalid.
415 * TODO:
416 * test functionality against windows to see what a valid URL is.
418 HRESULT WINAPI IsValidURL(LPBC pBC, LPCWSTR szURL, DWORD dwReserved)
420 FIXME("(%p, %s, %d): stub\n", pBC, debugstr_w(szURL), dwReserved);
422 if (pBC != NULL || dwReserved != 0)
423 return E_INVALIDARG;
425 return S_OK;
428 /**************************************************************************
429 * FaultInIEFeature (URLMON.@)
431 * Undocumented. Appears to be used by native shdocvw.dll.
433 HRESULT WINAPI FaultInIEFeature( HWND hwnd, uCLSSPEC * pClassSpec,
434 QUERYCONTEXT *pQuery, DWORD flags )
436 FIXME("%p %p %p %08x\n", hwnd, pClassSpec, pQuery, flags);
437 return E_NOTIMPL;
440 /**************************************************************************
441 * CoGetClassObjectFromURL (URLMON.@)
443 HRESULT WINAPI CoGetClassObjectFromURL( REFCLSID rclsid, LPCWSTR szCodeURL, DWORD dwFileVersionMS,
444 DWORD dwFileVersionLS, LPCWSTR szContentType,
445 LPBINDCTX pBindCtx, DWORD dwClsContext, LPVOID pvReserved,
446 REFIID riid, LPVOID *ppv )
448 FIXME("(%s %s %d %d %s %p %d %p %s %p) Stub!\n", debugstr_guid(rclsid), debugstr_w(szCodeURL),
449 dwFileVersionMS, dwFileVersionLS, debugstr_w(szContentType), pBindCtx, dwClsContext, pvReserved,
450 debugstr_guid(riid), ppv);
451 return E_NOINTERFACE;
454 /***********************************************************************
455 * ReleaseBindInfo (URLMON.@)
457 * Release the resources used by the specified BINDINFO structure.
459 * PARAMS
460 * pbindinfo [I] BINDINFO to release.
462 * RETURNS
463 * Nothing.
465 void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo)
467 DWORD size;
469 TRACE("(%p)\n", pbindinfo);
471 if(!pbindinfo || !(size = pbindinfo->cbSize))
472 return;
474 CoTaskMemFree(pbindinfo->szExtraInfo);
475 ReleaseStgMedium(&pbindinfo->stgmedData);
477 if(offsetof(BINDINFO, szExtraInfo) < size)
478 CoTaskMemFree(pbindinfo->szCustomVerb);
480 if(pbindinfo->pUnk && offsetof(BINDINFO, pUnk) < size)
481 IUnknown_Release(pbindinfo->pUnk);
483 memset(pbindinfo, 0, size);
484 pbindinfo->cbSize = size;
487 /***********************************************************************
488 * CopyStgMedium (URLMON.@)
490 HRESULT WINAPI CopyStgMedium(const STGMEDIUM *src, STGMEDIUM *dst)
492 TRACE("(%p %p)\n", src, dst);
494 if(!src || !dst)
495 return E_POINTER;
497 *dst = *src;
499 switch(dst->tymed) {
500 case TYMED_NULL:
501 break;
502 case TYMED_FILE:
503 if(src->u.lpszFileName && !src->pUnkForRelease) {
504 DWORD size = (strlenW(src->u.lpszFileName)+1)*sizeof(WCHAR);
505 dst->u.lpszFileName = CoTaskMemAlloc(size);
506 memcpy(dst->u.lpszFileName, src->u.lpszFileName, size);
508 break;
509 case TYMED_ISTREAM:
510 if(dst->u.pstm)
511 IStream_AddRef(dst->u.pstm);
512 break;
513 case TYMED_ISTORAGE:
514 if(dst->u.pstg)
515 IStorage_AddRef(dst->u.pstg);
516 break;
517 default:
518 FIXME("Unimplemented tymed %d\n", src->tymed);
521 if(dst->pUnkForRelease)
522 IUnknown_AddRef(dst->pUnkForRelease);
524 return S_OK;
527 static BOOL text_richtext_filter(const BYTE *b, DWORD size)
529 return size > 5 && !memcmp(b, "{\\rtf", 5);
532 static BOOL text_html_filter(const BYTE *b, DWORD size)
534 DWORD i;
536 if(size < 5)
537 return FALSE;
539 for(i=0; i < size-5; i++) {
540 if(b[i] == '<'
541 && (b[i+1] == 'h' || b[i+1] == 'H')
542 && (b[i+2] == 't' || b[i+2] == 'T')
543 && (b[i+3] == 'm' || b[i+3] == 'M')
544 && (b[i+4] == 'l' || b[i+4] == 'L'))
545 return TRUE;
548 return FALSE;
551 static BOOL audio_basic_filter(const BYTE *b, DWORD size)
553 return size > 4
554 && b[0] == '.' && b[1] == 's' && b[2] == 'n' && b[3] == 'd';
557 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
559 return size > 12
560 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
561 && b[8] == 'W' && b[9] == 'A' && b[10] == 'V' && b[11] == 'E';
564 static BOOL image_gif_filter(const BYTE *b, DWORD size)
566 return size >= 6
567 && (b[0] == 'G' || b[0] == 'g')
568 && (b[1] == 'I' || b[1] == 'i')
569 && (b[2] == 'F' || b[2] == 'f')
570 && b[3] == '8'
571 && (b[4] == '7' || b[4] == '9')
572 && (b[5] == 'A' || b[5] == 'a');
575 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
577 return size > 2 && b[0] == 0xff && b[1] == 0xd8;
580 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
582 return size > 2 && b[0] == 0x4d && b[1] == 0x4d;
585 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
587 static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
588 return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header));
591 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
593 return size >= 14
594 && b[0] == 0x42 && b[1] == 0x4d
595 && *(const DWORD *)(b+6) == 0;
598 static BOOL video_avi_filter(const BYTE *b, DWORD size)
600 return size > 12
601 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
602 && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20;
605 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
607 return size > 4
608 && !b[0] && !b[1] && b[2] == 0x01
609 && (b[3] == 0xb3 || b[3] == 0xba);
612 static BOOL application_postscript_filter(const BYTE *b, DWORD size)
614 return size > 2 && b[0] == '%' && b[1] == '!';
617 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
619 return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
622 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
624 return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
627 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
629 return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
632 static BOOL application_java_filter(const BYTE *b, DWORD size)
634 return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
637 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
639 return size > 2 && b[0] == 'M' && b[1] == 'Z';
642 static BOOL text_plain_filter(const BYTE *b, DWORD size)
644 const BYTE *ptr;
646 for(ptr = b; ptr < b+size-1; ptr++) {
647 if(*ptr < 0x20 && *ptr != '\n' && *ptr != '\r' && *ptr != '\t')
648 return FALSE;
651 return TRUE;
654 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
656 return TRUE;
659 /***********************************************************************
660 * FindMimeFromData (URLMON.@)
662 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
664 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
665 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
666 LPWSTR* ppwzMimeOut, DWORD dwReserved)
668 TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
669 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
671 if(dwMimeFlags)
672 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
673 if(dwReserved)
674 WARN("dwReserved=%d\n", dwReserved);
676 /* pBC seams to not be used */
678 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
679 return E_INVALIDARG;
681 if(pwzMimeProposed && (!pBuffer || (pBuffer && !cbSize))) {
682 DWORD len;
684 if(!pwzMimeProposed)
685 return E_FAIL;
687 len = strlenW(pwzMimeProposed)+1;
688 *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
689 memcpy(*ppwzMimeOut, pwzMimeProposed, len*sizeof(WCHAR));
690 return S_OK;
693 if(pBuffer) {
694 const BYTE *buf = pBuffer;
695 DWORD len;
696 LPCWSTR ret = NULL;
697 unsigned int i;
699 static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
700 static const WCHAR wszTextRichtext[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0};
701 static const WCHAR wszAudioBasic[] = {'a','u','d','i','o','/','b','a','s','i','c',0};
702 static const WCHAR wszAudioWav[] = {'a','u','d','i','o','/','w','a','v',0};
703 static const WCHAR wszImageGif[] = {'i','m','a','g','e','/','g','i','f',0};
704 static const WCHAR wszImagePjpeg[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
705 static const WCHAR wszImageTiff[] = {'i','m','a','g','e','/','t','i','f','f',0};
706 static const WCHAR wszImageXPng[] = {'i','m','a','g','e','/','x','-','p','n','g',0};
707 static const WCHAR wszImageBmp[] = {'i','m','a','g','e','/','b','m','p',0};
708 static const WCHAR wszVideoAvi[] = {'v','i','d','e','o','/','a','v','i',0};
709 static const WCHAR wszVideoMpeg[] = {'v','i','d','e','o','/','m','p','e','g',0};
710 static const WCHAR wszAppPostscript[] =
711 {'a','p','p','l','i','c','a','t','i','o','n','/','p','o','s','t','s','c','r','i','p','t',0};
712 static const WCHAR wszAppPdf[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
713 'p','d','f',0};
714 static const WCHAR wszAppXZip[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
715 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
716 static const WCHAR wszAppXGzip[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
717 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
718 static const WCHAR wszAppJava[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
719 'j','a','v','a',0};
720 static const WCHAR wszAppXMSDownload[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
721 'x','-','m','s','d','o','w','n','l','o','a','d',0};
722 static const WCHAR wszTextPlain[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
723 static const WCHAR wszAppOctetStream[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
724 'o','c','t','e','t','-','s','t','r','e','a','m','\0'};
726 static const struct {
727 LPCWSTR mime;
728 BOOL (*filter)(const BYTE *,DWORD);
729 } mime_filters[] = {
730 {wszTextHtml, text_html_filter},
731 {wszTextRichtext, text_richtext_filter},
732 /* {wszAudioXAiff, audio_xaiff_filter}, */
733 {wszAudioBasic, audio_basic_filter},
734 {wszAudioWav, audio_wav_filter},
735 {wszImageGif, image_gif_filter},
736 {wszImagePjpeg, image_pjpeg_filter},
737 {wszImageTiff, image_tiff_filter},
738 {wszImageXPng, image_xpng_filter},
739 /* {wszImageXBitmap, image_xbitmap_filter}, */
740 {wszImageBmp, image_bmp_filter},
741 /* {wszImageXJg, image_xjg_filter}, */
742 /* {wszImageXEmf, image_xemf_filter}, */
743 /* {wszImageXWmf, image_xwmf_filter}, */
744 {wszVideoAvi, video_avi_filter},
745 {wszVideoMpeg, video_mpeg_filter},
746 {wszAppPostscript, application_postscript_filter},
747 /* {wszAppBase64, application_base64_filter}, */
748 /* {wszAppMacbinhex40, application_macbinhex40_filter}, */
749 {wszAppPdf, application_pdf_filter},
750 /* {wszAppXCompressed, application_xcompressed_filter}, */
751 {wszAppXZip, application_xzip_filter},
752 {wszAppXGzip, application_xgzip_filter},
753 {wszAppJava, application_java_filter},
754 {wszAppXMSDownload, application_xmsdownload},
755 {wszTextPlain, text_plain_filter},
756 {wszAppOctetStream, application_octet_stream_filter}
759 if(!cbSize)
760 return E_FAIL;
762 if(pwzMimeProposed && strcmpW(pwzMimeProposed, wszAppOctetStream)) {
763 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
764 if(!strcmpW(pwzMimeProposed, mime_filters[i].mime))
765 break;
768 if(i == sizeof(mime_filters)/sizeof(*mime_filters)
769 || mime_filters[i].filter(buf, cbSize)) {
770 len = strlenW(pwzMimeProposed)+1;
771 *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
772 memcpy(*ppwzMimeOut, pwzMimeProposed, len*sizeof(WCHAR));
773 return S_OK;
777 i=0;
778 while(!ret) {
779 if(mime_filters[i].filter(buf, cbSize))
780 ret = mime_filters[i].mime;
781 i++;
784 TRACE("found %s for data\n"
785 "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
786 debugstr_w(ret), buf[0],buf[1],buf[2],buf[3], buf[4],buf[5],buf[6],buf[7],
787 buf[8],buf[9],buf[10],buf[11], buf[12],buf[13],buf[14],buf[15]);
789 if(pwzMimeProposed) {
790 if(i == sizeof(mime_filters)/sizeof(*mime_filters))
791 ret = pwzMimeProposed;
793 /* text/html is a special case */
794 if(!strcmpW(pwzMimeProposed, wszTextHtml) && !strcmpW(ret, wszTextPlain))
795 ret = wszTextHtml;
798 len = strlenW(ret)+1;
799 *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
800 memcpy(*ppwzMimeOut, ret, len*sizeof(WCHAR));
801 return S_OK;
804 if(pwzUrl) {
805 HKEY hkey;
806 DWORD res, size;
807 LPCWSTR ptr;
808 WCHAR mime[64];
810 static const WCHAR wszContentType[] =
811 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
813 ptr = strrchrW(pwzUrl, '.');
814 if(!ptr)
815 return E_FAIL;
817 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
818 if(res != ERROR_SUCCESS)
819 return HRESULT_FROM_WIN32(res);
821 size = sizeof(mime);
822 res = RegQueryValueExW(hkey, wszContentType, NULL, NULL, (LPBYTE)mime, &size);
823 RegCloseKey(hkey);
824 if(res != ERROR_SUCCESS)
825 return HRESULT_FROM_WIN32(res);
827 *ppwzMimeOut = CoTaskMemAlloc(size);
828 memcpy(*ppwzMimeOut, mime, size);
829 return S_OK;
832 return E_FAIL;
835 /***********************************************************************
836 * GetClassFileOrMime (URLMON.@)
838 * Determines the class ID from the bind context, file name or MIME type.
840 HRESULT WINAPI GetClassFileOrMime(LPBC pBC, LPCWSTR pszFilename,
841 LPVOID pBuffer, DWORD cbBuffer, LPCWSTR pszMimeType, DWORD dwReserved,
842 CLSID *pclsid)
844 FIXME("(%p, %s, %p, %d, %p, 0x%08x, %p): stub\n", pBC,
845 debugstr_w(pszFilename), pBuffer, cbBuffer, debugstr_w(pszMimeType),
846 dwReserved, pclsid);
847 return E_NOTIMPL;
850 /***********************************************************************
851 * Extract (URLMON.@)
853 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
855 HRESULT (WINAPI *pExtract)(void *, LPCSTR);
857 if (!hCabinet)
858 hCabinet = LoadLibraryA("cabinet.dll");
860 if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
861 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
862 if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());
864 return pExtract(dest, szCabName);
867 /***********************************************************************
868 * IsLoggingEnabledA (URLMON.@)
870 BOOL WINAPI IsLoggingEnabledA(LPCSTR url)
872 FIXME("(%s)\n", debugstr_a(url));
873 return FALSE;
876 /***********************************************************************
877 * IsLoggingEnabledW (URLMON.@)
879 BOOL WINAPI IsLoggingEnabledW(LPCWSTR url)
881 FIXME("(%s)\n", debugstr_w(url));
882 return FALSE;