Branching for 0.3.15 release after two days of no response from a certain sphere...
[reactos.git] / dll / win32 / 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 <advpub.h>
30
31 #include <wine/debug.h>
32
33 //#include "urlmon.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
36
37 LONG URLMON_refCount = 0;
38
39 static HMODULE hCabinet = NULL;
40 static DWORD urlmon_tls = TLS_OUT_OF_INDEXES;
41
42 static void init_session(BOOL);
43
44 static struct list tls_list = LIST_INIT(tls_list);
45
46 static CRITICAL_SECTION tls_cs;
47 static CRITICAL_SECTION_DEBUG tls_cs_dbg =
48 {
49 0, 0, &tls_cs,
50 { &tls_cs_dbg.ProcessLocksList, &tls_cs_dbg.ProcessLocksList },
51 0, 0, { (DWORD_PTR)(__FILE__ ": tls") }
52 };
53
54 static CRITICAL_SECTION tls_cs = { &tls_cs_dbg, -1, 0, 0, 0, 0 };
55
56 tls_data_t *get_tls_data(void)
57 {
58 tls_data_t *data;
59
60 if(urlmon_tls == TLS_OUT_OF_INDEXES) {
61 DWORD tls = TlsAlloc();
62 if(tls == TLS_OUT_OF_INDEXES)
63 return NULL;
64
65 tls = InterlockedCompareExchange((LONG*)&urlmon_tls, tls, TLS_OUT_OF_INDEXES);
66 if(tls != urlmon_tls)
67 TlsFree(tls);
68 }
69
70 data = TlsGetValue(urlmon_tls);
71 if(!data) {
72 data = heap_alloc_zero(sizeof(tls_data_t));
73 if(!data)
74 return NULL;
75
76 EnterCriticalSection(&tls_cs);
77 list_add_tail(&tls_list, &data->entry);
78 LeaveCriticalSection(&tls_cs);
79
80 TlsSetValue(urlmon_tls, data);
81 }
82
83 return data;
84 }
85
86 static void free_tls_list(void)
87 {
88 tls_data_t *data;
89
90 if(urlmon_tls == TLS_OUT_OF_INDEXES)
91 return;
92
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);
97 }
98
99 TlsFree(urlmon_tls);
100 }
101
102 static void detach_thread(void)
103 {
104 tls_data_t *data;
105
106 if(urlmon_tls == TLS_OUT_OF_INDEXES)
107 return;
108
109 data = TlsGetValue(urlmon_tls);
110 if(!data)
111 return;
112
113 EnterCriticalSection(&tls_cs);
114 list_remove(&data->entry);
115 LeaveCriticalSection(&tls_cs);
116
117 if(data->notif_hwnd) {
118 WARN("notif_hwnd not destroyed\n");
119 DestroyWindow(data->notif_hwnd);
120 }
121
122 heap_free(data);
123 }
124
125 static void process_detach(void)
126 {
127 HINTERNET internet_session;
128
129 internet_session = get_internet_session(NULL);
130 if(internet_session)
131 InternetCloseHandle(internet_session);
132
133 if (hCabinet)
134 FreeLibrary(hCabinet);
135
136 init_session(FALSE);
137 free_session();
138 free_tls_list();
139 }
140
141 /***********************************************************************
142 * DllMain (URLMON.init)
143 */
144 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
145 {
146 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
147
148 URLMON_DllMain( hinstDLL, fdwReason, fImpLoad );
149
150 switch(fdwReason) {
151 case DLL_PROCESS_ATTACH:
152 init_session(TRUE);
153 break;
154
155 case DLL_PROCESS_DETACH:
156 process_detach();
157 break;
158
159 case DLL_THREAD_DETACH:
160 detach_thread();
161 break;
162 }
163 return TRUE;
164 }
165
166
167 /***********************************************************************
168 * DllInstall (URLMON.@)
169 */
170 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
171 {
172 FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
173 debugstr_w(cmdline));
174
175 return S_OK;
176 }
177
178 /***********************************************************************
179 * DllCanUnloadNow (URLMON.@)
180 */
181 HRESULT WINAPI DllCanUnloadNow(void)
182 {
183 return URLMON_refCount != 0 ? S_FALSE : S_OK;
184 }
185
186
187
188 /******************************************************************************
189 * Urlmon ClassFactory
190 */
191 typedef struct {
192 IClassFactory IClassFactory_iface;
193
194 HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
195 } ClassFactory;
196
197 static inline ClassFactory *impl_from_IClassFactory(IClassFactory *iface)
198 {
199 return CONTAINING_RECORD(iface, ClassFactory, IClassFactory_iface);
200 }
201
202 static HRESULT WINAPI CF_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppv)
203 {
204 *ppv = NULL;
205
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;
212 }
213
214 if(*ppv) {
215 IUnknown_AddRef((IUnknown*)*ppv);
216 return S_OK;
217 }
218
219 WARN("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ppv);
220 return E_NOINTERFACE;
221 }
222
223 static ULONG WINAPI CF_AddRef(IClassFactory *iface)
224 {
225 URLMON_LockModule();
226 return 2;
227 }
228
229 static ULONG WINAPI CF_Release(IClassFactory *iface)
230 {
231 URLMON_UnlockModule();
232 return 1;
233 }
234
235
236 static HRESULT WINAPI CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
237 REFIID riid, LPVOID *ppobj)
238 {
239 ClassFactory *This = impl_from_IClassFactory(iface);
240 HRESULT hres;
241 LPUNKNOWN punk;
242
243 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
244
245 *ppobj = NULL;
246 if(SUCCEEDED(hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk))) {
247 hres = IUnknown_QueryInterface(punk, riid, ppobj);
248 IUnknown_Release(punk);
249 }
250 return hres;
251 }
252
253 static HRESULT WINAPI CF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
254 {
255 TRACE("(%d)\n", dolock);
256
257 if (dolock)
258 URLMON_LockModule();
259 else
260 URLMON_UnlockModule();
261
262 return S_OK;
263 }
264
265 static const IClassFactoryVtbl ClassFactoryVtbl =
266 {
267 CF_QueryInterface,
268 CF_AddRef,
269 CF_Release,
270 CF_CreateInstance,
271 CF_LockServer
272 };
273
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};
294
295 struct object_creation_info
296 {
297 const CLSID *clsid;
298 IClassFactory *cf;
299 LPCWSTR protocol;
300 };
301
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};
308
309 static const struct object_creation_info object_creation[] =
310 {
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 }
321 };
322
323 static void init_session(BOOL init)
324 {
325 unsigned int i;
326
327 for(i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) {
328
329 if(object_creation[i].protocol)
330 register_urlmon_namespace(object_creation[i].cf, object_creation[i].clsid,
331 object_creation[i].protocol, init);
332 }
333 }
334
335 /*******************************************************************************
336 * DllGetClassObject [URLMON.@]
337 * Retrieves class object from a DLL object
338 *
339 * NOTES
340 * Docs say returns STDAPI
341 *
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
346 *
347 * RETURNS
348 * Success: S_OK
349 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
350 * E_UNEXPECTED
351 */
352
353 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
354 {
355 unsigned int i;
356 HRESULT hr;
357
358 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
359
360 for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
361 {
362 if (IsEqualGUID(object_creation[i].clsid, rclsid))
363 return IClassFactory_QueryInterface(object_creation[i].cf, riid, ppv);
364 }
365
366 hr = URLMON_DllGetClassObject(rclsid, riid, ppv);
367 if(SUCCEEDED(hr))
368 return hr;
369
370 FIXME("%s: no class found.\n", debugstr_guid(rclsid));
371 return CLASS_E_CLASSNOTAVAILABLE;
372 }
373
374 static HRESULT register_inf(BOOL doregister)
375 {
376 HRESULT (WINAPI *pRegInstall)(HMODULE hm, LPCSTR pszSection, const STRTABLEA* pstTable);
377 HMODULE hAdvpack;
378
379 static const WCHAR wszAdvpack[] = {'a','d','v','p','a','c','k','.','d','l','l',0};
380
381 hAdvpack = LoadLibraryW(wszAdvpack);
382 pRegInstall = (void *)GetProcAddress(hAdvpack, "RegInstall");
383
384 return pRegInstall(hProxyDll, doregister ? "RegisterDll" : "UnregisterDll", NULL);
385 }
386
387 /***********************************************************************
388 * DllRegisterServer (URLMON.@)
389 */
390 HRESULT WINAPI DllRegisterServer(void)
391 {
392 HRESULT hr;
393
394 TRACE("\n");
395
396 hr = URLMON_DllRegisterServer();
397 return SUCCEEDED(hr) ? register_inf(TRUE) : hr;
398 }
399
400 /***********************************************************************
401 * DllUnregisterServer (URLMON.@)
402 */
403 HRESULT WINAPI DllUnregisterServer(void)
404 {
405 HRESULT hr;
406
407 TRACE("\n");
408
409 hr = URLMON_DllUnregisterServer();
410 return SUCCEEDED(hr) ? register_inf(FALSE) : hr;
411 }
412
413 /***********************************************************************
414 * DllRegisterServerEx (URLMON.@)
415 */
416 HRESULT WINAPI DllRegisterServerEx(void)
417 {
418 FIXME("(void): stub\n");
419
420 return E_FAIL;
421 }
422
423 /**************************************************************************
424 * IsValidURL (URLMON.@)
425 *
426 * Determines if a specified string is a valid URL.
427 *
428 * PARAMS
429 * pBC [I] ignored, should be NULL.
430 * szURL [I] string that represents the URL in question.
431 * dwReserved [I] reserved and must be zero.
432 *
433 * RETURNS
434 * Success: S_OK.
435 * Failure: S_FALSE.
436 * returns E_INVALIDARG if one or more of the args is invalid.
437 *
438 * TODO:
439 * test functionality against windows to see what a valid URL is.
440 */
441 HRESULT WINAPI IsValidURL(LPBC pBC, LPCWSTR szURL, DWORD dwReserved)
442 {
443 FIXME("(%p, %s, %d): stub\n", pBC, debugstr_w(szURL), dwReserved);
444
445 if (dwReserved || !szURL)
446 return E_INVALIDARG;
447
448 return S_OK;
449 }
450
451 /**************************************************************************
452 * FaultInIEFeature (URLMON.@)
453 *
454 * Undocumented. Appears to be used by native shdocvw.dll.
455 */
456 HRESULT WINAPI FaultInIEFeature( HWND hwnd, uCLSSPEC * pClassSpec,
457 QUERYCONTEXT *pQuery, DWORD flags )
458 {
459 FIXME("%p %p %p %08x\n", hwnd, pClassSpec, pQuery, flags);
460 return E_NOTIMPL;
461 }
462
463 /**************************************************************************
464 * CoGetClassObjectFromURL (URLMON.@)
465 */
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 )
470 {
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;
475 }
476
477 /***********************************************************************
478 * ReleaseBindInfo (URLMON.@)
479 *
480 * Release the resources used by the specified BINDINFO structure.
481 *
482 * PARAMS
483 * pbindinfo [I] BINDINFO to release.
484 *
485 * RETURNS
486 * Nothing.
487 */
488 void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo)
489 {
490 DWORD size;
491
492 TRACE("(%p)\n", pbindinfo);
493
494 if(!pbindinfo || !(size = pbindinfo->cbSize))
495 return;
496
497 CoTaskMemFree(pbindinfo->szExtraInfo);
498 ReleaseStgMedium(&pbindinfo->stgmedData);
499
500 if(offsetof(BINDINFO, szExtraInfo) < size)
501 CoTaskMemFree(pbindinfo->szCustomVerb);
502
503 if(pbindinfo->pUnk && offsetof(BINDINFO, pUnk) < size)
504 IUnknown_Release(pbindinfo->pUnk);
505
506 memset(pbindinfo, 0, size);
507 pbindinfo->cbSize = size;
508 }
509
510 /***********************************************************************
511 * CopyStgMedium (URLMON.@)
512 */
513 HRESULT WINAPI CopyStgMedium(const STGMEDIUM *src, STGMEDIUM *dst)
514 {
515 TRACE("(%p %p)\n", src, dst);
516
517 if(!src || !dst)
518 return E_POINTER;
519
520 *dst = *src;
521
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);
530 }
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);
542 }
543
544 if(dst->pUnkForRelease)
545 IUnknown_AddRef(dst->pUnkForRelease);
546
547 return S_OK;
548 }
549
550 static BOOL text_richtext_filter(const BYTE *b, DWORD size)
551 {
552 return size > 5 && !memcmp(b, "{\\rtf", 5);
553 }
554
555 static BOOL text_html_filter(const BYTE *b, DWORD size)
556 {
557 DWORD i;
558
559 if(size < 5)
560 return FALSE;
561
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;
569 }
570
571 return FALSE;
572 }
573
574 static BOOL audio_basic_filter(const BYTE *b, DWORD size)
575 {
576 return size > 4
577 && b[0] == '.' && b[1] == 's' && b[2] == 'n' && b[3] == 'd';
578 }
579
580 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
581 {
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';
585 }
586
587 static BOOL image_gif_filter(const BYTE *b, DWORD size)
588 {
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');
596 }
597
598 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
599 {
600 return size > 2 && b[0] == 0xff && b[1] == 0xd8;
601 }
602
603 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
604 {
605 return size > 2 && b[0] == 0x4d && b[1] == 0x4d;
606 }
607
608 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
609 {
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));
612 }
613
614 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
615 {
616 return size >= 14
617 && b[0] == 0x42 && b[1] == 0x4d
618 && *(const DWORD *)(b+6) == 0;
619 }
620
621 static BOOL video_avi_filter(const BYTE *b, DWORD size)
622 {
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;
626 }
627
628 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
629 {
630 return size > 4
631 && !b[0] && !b[1] && b[2] == 0x01
632 && (b[3] == 0xb3 || b[3] == 0xba);
633 }
634
635 static BOOL application_postscript_filter(const BYTE *b, DWORD size)
636 {
637 return size > 2 && b[0] == '%' && b[1] == '!';
638 }
639
640 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
641 {
642 return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
643 }
644
645 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
646 {
647 return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
648 }
649
650 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
651 {
652 return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
653 }
654
655 static BOOL application_java_filter(const BYTE *b, DWORD size)
656 {
657 return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
658 }
659
660 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
661 {
662 return size > 2 && b[0] == 'M' && b[1] == 'Z';
663 }
664
665 static BOOL text_plain_filter(const BYTE *b, DWORD size)
666 {
667 const BYTE *ptr;
668
669 for(ptr = b; ptr < b+size-1; ptr++) {
670 if(*ptr < 0x20 && *ptr != '\n' && *ptr != '\r' && *ptr != '\t')
671 return FALSE;
672 }
673
674 return TRUE;
675 }
676
677 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
678 {
679 return TRUE;
680 }
681
682 static HRESULT find_mime_from_buffer(const BYTE *buf, DWORD size, const WCHAR *proposed_mime, WCHAR **ret_mime)
683 {
684 LPCWSTR ret = NULL;
685 DWORD len, i;
686
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'};
712
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}
744 };
745
746 if(!buf || !size) {
747 if(!proposed_mime)
748 return E_FAIL;
749
750 len = strlenW(proposed_mime)+1;
751 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
752 if(!*ret_mime)
753 return E_OUTOFMEMORY;
754
755 memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR));
756 return S_OK;
757 }
758
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;
763 }
764
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;
770
771 memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR));
772 return S_OK;
773 }
774 }
775
776 i=0;
777 while(!ret) {
778 if(mime_filters[i].filter(buf, size))
779 ret = mime_filters[i].mime;
780 i++;
781 }
782
783 TRACE("found %s for %s\n", debugstr_w(ret), debugstr_an((const char*)buf, min(32, size)));
784
785 if(proposed_mime) {
786 if(i == sizeof(mime_filters)/sizeof(*mime_filters))
787 ret = proposed_mime;
788
789 /* text/html is a special case */
790 if(!strcmpW(proposed_mime, text_htmlW) && !strcmpW(ret, text_plainW))
791 ret = text_htmlW;
792 }
793
794 len = strlenW(ret)+1;
795 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
796 if(!*ret_mime)
797 return E_OUTOFMEMORY;
798
799 memcpy(*ret_mime, ret, len*sizeof(WCHAR));
800 return S_OK;
801 }
802
803 /***********************************************************************
804 * FindMimeFromData (URLMON.@)
805 *
806 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
807 */
808 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
809 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
810 LPWSTR* ppwzMimeOut, DWORD dwReserved)
811 {
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);
814
815 if(dwMimeFlags)
816 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
817 if(dwReserved)
818 WARN("dwReserved=%d\n", dwReserved);
819
820 /* pBC seams to not be used */
821
822 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
823 return E_INVALIDARG;
824
825 if(pwzMimeProposed || pBuffer)
826 return find_mime_from_buffer(pBuffer, cbSize, pwzMimeProposed, ppwzMimeOut);
827
828 if(pwzUrl) {
829 HKEY hkey;
830 DWORD res, size;
831 LPCWSTR ptr;
832 WCHAR mime[64];
833
834 static const WCHAR wszContentType[] =
835 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
836
837 ptr = strrchrW(pwzUrl, '.');
838 if(!ptr)
839 return E_FAIL;
840
841 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
842 if(res != ERROR_SUCCESS)
843 return HRESULT_FROM_WIN32(res);
844
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);
850
851 *ppwzMimeOut = CoTaskMemAlloc(size);
852 memcpy(*ppwzMimeOut, mime, size);
853 return S_OK;
854 }
855
856 return E_FAIL;
857 }
858
859 /***********************************************************************
860 * GetClassFileOrMime (URLMON.@)
861 *
862 * Determines the class ID from the bind context, file name or MIME type.
863 */
864 HRESULT WINAPI GetClassFileOrMime(LPBC pBC, LPCWSTR pszFilename,
865 LPVOID pBuffer, DWORD cbBuffer, LPCWSTR pszMimeType, DWORD dwReserved,
866 CLSID *pclsid)
867 {
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;
872 }
873
874 /***********************************************************************
875 * Extract (URLMON.@)
876 */
877 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
878 {
879 HRESULT (WINAPI *pExtract)(void *, LPCSTR);
880
881 if (!hCabinet)
882 hCabinet = LoadLibraryA("cabinet.dll");
883
884 if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
885 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
886 if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());
887
888 return pExtract(dest, szCabName);
889 }
890
891 /***********************************************************************
892 * IsLoggingEnabledA (URLMON.@)
893 */
894 BOOL WINAPI IsLoggingEnabledA(LPCSTR url)
895 {
896 FIXME("(%s)\n", debugstr_a(url));
897 return FALSE;
898 }
899
900 /***********************************************************************
901 * IsLoggingEnabledW (URLMON.@)
902 */
903 BOOL WINAPI IsLoggingEnabledW(LPCWSTR url)
904 {
905 FIXME("(%s)\n", debugstr_w(url));
906 return FALSE;
907 }
908
909 /***********************************************************************
910 * URLMON_410 (URLMON.410)
911 * Undocumented, added in IE8
912 */
913 BOOL WINAPI URLMON_410(DWORD unknown1, DWORD unknown2)
914 {
915 FIXME("stub: %d %d\n", unknown1, unknown2);
916 return FALSE;
917 }
918
919 /***********************************************************************
920 * URLMON_423 (URLMON.423)
921 * Undocumented, added in IE8
922 */
923 BOOL WINAPI URLMON_423(DWORD unknown1, DWORD unknown2, DWORD unknown3, DWORD unknown4)
924 {
925 FIXME("stub: %d %d %d %d\n", unknown1, unknown2, unknown3, unknown4);
926 return FALSE;
927 }