msctf: Use FAILED instead of !SUCCEDED.
[wine] / dlls / urlmon / urlmon_main.c
1 /*
2  * UrlMon
3  *
4  * Copyright (c) 2000 Patrik Stridvall
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include <stdarg.h>
22
23 #include "urlmon_main.h"
24
25 #include "winreg.h"
26
27 #define NO_SHLWAPI_REG
28 #include "shlwapi.h"
29 #include "wine/debug.h"
30
31 #include "urlmon.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
34
35 LONG URLMON_refCount = 0;
36
37 HINSTANCE URLMON_hInstance = 0;
38 static HMODULE hCabinet = NULL;
39 static DWORD urlmon_tls;
40
41 static void init_session(BOOL);
42
43 static struct list tls_list = LIST_INIT(tls_list);
44
45 static CRITICAL_SECTION tls_cs;
46 static CRITICAL_SECTION_DEBUG tls_cs_dbg =
47 {
48     0, 0, &tls_cs,
49     { &tls_cs_dbg.ProcessLocksList, &tls_cs_dbg.ProcessLocksList },
50       0, 0, { (DWORD_PTR)(__FILE__ ": tls") }
51 };
52
53 static CRITICAL_SECTION tls_cs = { &tls_cs_dbg, -1, 0, 0, 0, 0 };
54
55 tls_data_t *get_tls_data(void)
56 {
57     tls_data_t *data;
58
59     if(!urlmon_tls) {
60         DWORD tls = TlsAlloc();
61         tls = InterlockedCompareExchange((LONG*)&urlmon_tls, tls, 0);
62         if(tls != urlmon_tls)
63             TlsFree(tls);
64     }
65
66     data = TlsGetValue(urlmon_tls);
67     if(!data) {
68         data = heap_alloc_zero(sizeof(tls_data_t));
69         if(!data)
70             return NULL;
71
72         EnterCriticalSection(&tls_cs);
73         list_add_tail(&tls_list, &data->entry);
74         LeaveCriticalSection(&tls_cs);
75
76         TlsSetValue(urlmon_tls, data);
77     }
78
79     return data;
80 }
81
82 static void free_tls_list(void)
83 {
84     tls_data_t *data;
85
86     if(!urlmon_tls)
87         return;
88
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);
93     }
94
95     TlsFree(urlmon_tls);
96 }
97
98 static void detach_thread(void)
99 {
100     tls_data_t *data;
101
102     if(!urlmon_tls)
103         return;
104
105     data = TlsGetValue(urlmon_tls);
106     if(!data)
107         return;
108
109     EnterCriticalSection(&tls_cs);
110     list_remove(&data->entry);
111     LeaveCriticalSection(&tls_cs);
112
113     if(data->notif_hwnd) {
114         WARN("notif_hwnd not destroyed\n");
115         DestroyWindow(data->notif_hwnd);
116     }
117
118     heap_free(data);
119 }
120
121 /***********************************************************************
122  *              DllMain (URLMON.init)
123  */
124 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
125 {
126     TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
127
128     switch(fdwReason) {
129     case DLL_PROCESS_ATTACH:
130         URLMON_hInstance = hinstDLL;
131         init_session(TRUE);
132         break;
133
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;
142
143     case DLL_THREAD_DETACH:
144         detach_thread();
145         break;
146     }
147     return TRUE;
148 }
149
150
151 /***********************************************************************
152  *              DllInstall (URLMON.@)
153  */
154 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
155 {
156   FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
157         debugstr_w(cmdline));
158
159   return S_OK;
160 }
161
162 /***********************************************************************
163  *              DllCanUnloadNow (URLMON.@)
164  */
165 HRESULT WINAPI DllCanUnloadNow(void)
166 {
167     return URLMON_refCount != 0 ? S_FALSE : S_OK;
168 }
169
170
171
172 /******************************************************************************
173  * Urlmon ClassFactory
174  */
175 typedef struct {
176     const IClassFactoryVtbl *lpClassFactoryVtbl;
177
178     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
179 } ClassFactory;
180
181 #define CLASSFACTORY(x)  ((IClassFactory*)  &(x)->lpClassFactoryVtbl)
182
183 static HRESULT WINAPI CF_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppv)
184 {
185     *ppv = NULL;
186
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;
193     }
194
195     if(*ppv) {
196         IUnknown_AddRef((IUnknown*)*ppv);
197         return S_OK;
198     }
199
200     WARN("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ppv);
201     return E_NOINTERFACE;
202 }
203
204 static ULONG WINAPI CF_AddRef(IClassFactory *iface)
205 {
206     URLMON_LockModule();
207     return 2;
208 }
209
210 static ULONG WINAPI CF_Release(IClassFactory *iface)
211 {
212     URLMON_UnlockModule();
213     return 1;
214 }
215
216
217 static HRESULT WINAPI CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
218                                         REFIID riid, LPVOID *ppobj)
219 {
220     ClassFactory *This = (ClassFactory*)iface;
221     HRESULT hres;
222     LPUNKNOWN punk;
223     
224     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
225
226     *ppobj = NULL;
227     if(SUCCEEDED(hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk))) {
228         hres = IUnknown_QueryInterface(punk, riid, ppobj);
229         IUnknown_Release(punk);
230     }
231     return hres;
232 }
233
234 static HRESULT WINAPI CF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
235 {
236     TRACE("(%d)\n", dolock);
237
238     if (dolock)
239            URLMON_LockModule();
240     else
241            URLMON_UnlockModule();
242
243     return S_OK;
244 }
245
246 static const IClassFactoryVtbl ClassFactoryVtbl =
247 {
248     CF_QueryInterface,
249     CF_AddRef,
250     CF_Release,
251     CF_CreateInstance,
252     CF_LockServer
253 };
254
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};
275  
276 struct object_creation_info
277 {
278     const CLSID *clsid;
279     IClassFactory *cf;
280     LPCWSTR protocol;
281 };
282
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};
289
290 static const struct object_creation_info object_creation[] =
291 {
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    }
302 };
303
304 static void init_session(BOOL init)
305 {
306     unsigned int i;
307
308     for(i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) {
309
310         if(object_creation[i].protocol)
311             register_urlmon_namespace(object_creation[i].cf, object_creation[i].clsid,
312                                       object_creation[i].protocol, init);
313     }
314 }
315
316 /*******************************************************************************
317  * DllGetClassObject [URLMON.@]
318  * Retrieves class object from a DLL object
319  *
320  * NOTES
321  *    Docs say returns STDAPI
322  *
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
327  *
328  * RETURNS
329  *    Success: S_OK
330  *    Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
331  *             E_UNEXPECTED
332  */
333
334 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
335 {
336     unsigned int i;
337     
338     TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
339     
340     for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
341     {
342         if (IsEqualGUID(object_creation[i].clsid, rclsid))
343             return IClassFactory_QueryInterface(object_creation[i].cf, riid, ppv);
344     }
345
346     FIXME("%s: no class found.\n", debugstr_guid(rclsid));
347     return CLASS_E_CLASSNOTAVAILABLE;
348 }
349
350
351 /***********************************************************************
352  *              DllRegisterServerEx (URLMON.@)
353  */
354 HRESULT WINAPI DllRegisterServerEx(void)
355 {
356     FIXME("(void): stub\n");
357
358     return E_FAIL;
359 }
360
361 /**************************************************************************
362  *                 UrlMkSetSessionOption (URLMON.@)
363  */
364 HRESULT WINAPI UrlMkSetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength,
365                                         DWORD Reserved)
366 {
367     FIXME("(%#x, %p, %#x): stub\n", dwOption, pBuffer, dwBufferLength);
368
369     return S_OK;
370 }
371
372 static const CHAR Agent[] = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)";
373
374 /**************************************************************************
375  *                 ObtainUserAgentString (URLMON.@)
376  */
377 HRESULT WINAPI ObtainUserAgentString(DWORD dwOption, LPSTR pcszUAOut, DWORD *cbSize)
378 {
379     FIXME("(%d, %p, %p): stub\n", dwOption, pcszUAOut, cbSize);
380
381     if (pcszUAOut == NULL || cbSize == NULL)
382         return E_INVALIDARG;
383
384     if (*cbSize < sizeof(Agent))
385     {
386         *cbSize = sizeof(Agent);
387         return E_OUTOFMEMORY;
388     }
389
390     if (sizeof(Agent) < *cbSize)
391         *cbSize = sizeof(Agent);
392     lstrcpynA(pcszUAOut, Agent, *cbSize);
393
394     return S_OK;
395 }
396
397 /**************************************************************************
398  *                 IsValidURL (URLMON.@)
399  * 
400  * Determines if a specified string is a valid URL.
401  *
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.
406  *
407  * RETURNS
408  *  Success: S_OK.
409  *  Failure: S_FALSE.
410  *  returns E_INVALIDARG if one or more of the args is invalid.
411  *
412  * TODO:
413  *  test functionality against windows to see what a valid URL is.
414  */
415 HRESULT WINAPI IsValidURL(LPBC pBC, LPCWSTR szURL, DWORD dwReserved)
416 {
417     FIXME("(%p, %s, %d): stub\n", pBC, debugstr_w(szURL), dwReserved);
418     
419     if (pBC != NULL || dwReserved != 0)
420         return E_INVALIDARG;
421     
422     return S_OK;
423 }
424
425 /**************************************************************************
426  *                 FaultInIEFeature (URLMON.@)
427  *
428  *  Undocumented.  Appears to be used by native shdocvw.dll.
429  */
430 HRESULT WINAPI FaultInIEFeature( HWND hwnd, uCLSSPEC * pClassSpec,
431                                  QUERYCONTEXT *pQuery, DWORD flags )
432 {
433     FIXME("%p %p %p %08x\n", hwnd, pClassSpec, pQuery, flags);
434     return E_NOTIMPL;
435 }
436
437 /**************************************************************************
438  *                 CoGetClassObjectFromURL (URLMON.@)
439  */
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 )
444 {
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;
449 }
450
451 /***********************************************************************
452  *           ReleaseBindInfo (URLMON.@)
453  *
454  * Release the resources used by the specified BINDINFO structure.
455  *
456  * PARAMS
457  *  pbindinfo [I] BINDINFO to release.
458  *
459  * RETURNS
460  *  Nothing.
461  */
462 void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo)
463 {
464     DWORD size;
465
466     TRACE("(%p)\n", pbindinfo);
467
468     if(!pbindinfo || !(size = pbindinfo->cbSize))
469         return;
470
471     CoTaskMemFree(pbindinfo->szExtraInfo);
472     ReleaseStgMedium(&pbindinfo->stgmedData);
473
474     if(offsetof(BINDINFO, szExtraInfo) < size)
475         CoTaskMemFree(pbindinfo->szCustomVerb);
476
477     if(pbindinfo->pUnk && offsetof(BINDINFO, pUnk) < size)
478         IUnknown_Release(pbindinfo->pUnk);
479
480     memset(pbindinfo, 0, size);
481     pbindinfo->cbSize = size;
482 }
483
484 /***********************************************************************
485  *           CopyStgMedium (URLMON.@)
486  */
487 HRESULT WINAPI CopyStgMedium(const STGMEDIUM *src, STGMEDIUM *dst)
488 {
489     TRACE("(%p %p)\n", src, dst);
490
491     if(!src || !dst)
492         return E_POINTER;
493
494     *dst = *src;
495
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);
504         }
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);
516     }
517
518     if(dst->pUnkForRelease)
519         IUnknown_AddRef(dst->pUnkForRelease);
520
521     return S_OK;
522 }
523
524 static BOOL text_richtext_filter(const BYTE *b, DWORD size)
525 {
526     return size > 5 && !memcmp(b, "{\\rtf", 5);
527 }
528
529 static BOOL text_html_filter(const BYTE *b, DWORD size)
530 {
531     DWORD i;
532
533     if(size < 5)
534         return FALSE;
535
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;
543     }
544
545     return FALSE;
546 }
547
548 static BOOL audio_basic_filter(const BYTE *b, DWORD size)
549 {
550     return size > 4
551         && b[0] == '.' && b[1] == 's' && b[2] == 'n' && b[3] == 'd';
552 }
553
554 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
555 {
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';
559 }
560
561 static BOOL image_gif_filter(const BYTE *b, DWORD size)
562 {
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');
570 }
571
572 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
573 {
574     return size > 2 && b[0] == 0xff && b[1] == 0xd8;
575 }
576
577 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
578 {
579     return size > 2 && b[0] == 0x4d && b[1] == 0x4d;
580 }
581
582 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
583 {
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));
586 }
587
588 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
589 {
590     return size >= 14
591         && b[0] == 0x42 && b[1] == 0x4d
592         && *(const DWORD *)(b+6) == 0;
593 }
594
595 static BOOL video_avi_filter(const BYTE *b, DWORD size)
596 {
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;
600 }
601
602 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
603 {
604     return size > 4
605         && !b[0] && !b[1] && b[2] == 0x01
606         && (b[3] == 0xb3 || b[3] == 0xba);
607 }
608
609 static BOOL application_postscript_filter(const BYTE *b, DWORD size)
610 {
611     return size > 2 && b[0] == '%' && b[1] == '!';
612 }
613
614 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
615 {
616     return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
617 }
618
619 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
620 {
621     return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
622 }
623
624 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
625 {
626     return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
627 }
628
629 static BOOL application_java_filter(const BYTE *b, DWORD size)
630 {
631     return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
632 }
633
634 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
635 {
636     return size > 2 && b[0] == 'M' && b[1] == 'Z';
637 }
638
639 static BOOL text_plain_filter(const BYTE *b, DWORD size)
640 {
641     const BYTE *ptr;
642
643     for(ptr = b; ptr < b+size-1; ptr++) {
644         if(*ptr < 0x20 && *ptr != '\n' && *ptr != '\r' && *ptr != '\t')
645             return FALSE;
646     }
647
648     return TRUE;
649 }
650
651 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
652 {
653     return TRUE;
654 }
655
656 /***********************************************************************
657  *           FindMimeFromData (URLMON.@)
658  *
659  * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
660  */
661 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
662         DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
663         LPWSTR* ppwzMimeOut, DWORD dwReserved)
664 {
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);
667
668     if(dwMimeFlags)
669         WARN("dwMimeFlags=%08x\n", dwMimeFlags);
670     if(dwReserved)
671         WARN("dwReserved=%d\n", dwReserved);
672
673     /* pBC seams to not be used */
674
675     if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
676         return E_INVALIDARG;
677
678     if(pwzMimeProposed && (!pBuffer || (pBuffer && !cbSize))) {
679         DWORD len;
680
681         if(!pwzMimeProposed)
682             return E_FAIL;
683
684         len = strlenW(pwzMimeProposed)+1;
685         *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
686         memcpy(*ppwzMimeOut, pwzMimeProposed, len*sizeof(WCHAR));
687         return S_OK;
688     }
689
690     if(pBuffer) {
691         const BYTE *buf = pBuffer;
692         DWORD len;
693         LPCWSTR ret = NULL;
694         unsigned int i;
695
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'};
722
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}
754         };
755
756         if(!cbSize)
757             return E_FAIL;
758
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;
763             }
764
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;
771             }
772         }
773
774         i=0;
775         while(!ret) {
776             if(mime_filters[i].filter(buf, cbSize))
777                 ret = mime_filters[i].mime;
778             i++;
779         }
780
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]);
785
786         if(pwzMimeProposed) {
787             if(i == sizeof(mime_filters)/sizeof(*mime_filters))
788                 ret = pwzMimeProposed;
789
790             /* text/html is a special case */
791             if(!strcmpW(pwzMimeProposed, wszTextHtml) && !strcmpW(ret, wszTextPlain))
792                 ret = wszTextHtml;
793         }
794
795         len = strlenW(ret)+1;
796         *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
797         memcpy(*ppwzMimeOut, ret, len*sizeof(WCHAR));
798         return S_OK;
799     }
800
801     if(pwzUrl) {
802         HKEY hkey;
803         DWORD res, size;
804         LPCWSTR ptr;
805         WCHAR mime[64];
806
807         static const WCHAR wszContentType[] =
808                 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
809
810         ptr = strrchrW(pwzUrl, '.');
811         if(!ptr)
812             return E_FAIL;
813
814         res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
815         if(res != ERROR_SUCCESS)
816             return HRESULT_FROM_WIN32(res);
817
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);
823
824         *ppwzMimeOut = CoTaskMemAlloc(size);
825         memcpy(*ppwzMimeOut, mime, size);
826         return S_OK;
827     }
828
829     return E_FAIL;
830 }
831
832 /***********************************************************************
833  *           GetClassFileOrMime (URLMON.@)
834  *
835  * Determines the class ID from the bind context, file name or MIME type.
836  */
837 HRESULT WINAPI GetClassFileOrMime(LPBC pBC, LPCWSTR pszFilename,
838         LPVOID pBuffer, DWORD cbBuffer, LPCWSTR pszMimeType, DWORD dwReserved,
839         CLSID *pclsid)
840 {
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;
845 }
846
847 /***********************************************************************
848  * Extract (URLMON.@)
849  */
850 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
851 {
852     HRESULT (WINAPI *pExtract)(void *, LPCSTR);
853
854     if (!hCabinet)
855         hCabinet = LoadLibraryA("cabinet.dll");
856
857     if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
858     pExtract = (void *)GetProcAddress(hCabinet, "Extract");
859     if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());
860
861     return pExtract(dest, szCabName);
862 }
863
864 /***********************************************************************
865  *           IsLoggingEnabledA (URLMON.@)
866  */
867 BOOL WINAPI IsLoggingEnabledA(LPCSTR url)
868 {
869     FIXME("(%s)\n", debugstr_a(url));
870     return FALSE;
871 }
872
873 /***********************************************************************
874  *           IsLoggingEnabledW (URLMON.@)
875  */
876 BOOL WINAPI IsLoggingEnabledW(LPCWSTR url)
877 {
878     FIXME("(%s)\n", debugstr_w(url));
879     return FALSE;
880 }