Create this branch to work on loading of different Kernel-Debugger DLL providers...
[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 #include <initguid.h>
31
32 #include <wine/debug.h>
33
34 #include "urlmon.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
37
38 DEFINE_GUID(CLSID_CUri, 0xDF2FCE13, 0x25EC, 0x45BB, 0x9D,0x4C, 0xCE,0xCD,0x47,0xC2,0x43,0x0C);
39
40 LONG URLMON_refCount = 0;
41 HINSTANCE urlmon_instance;
42
43 static HMODULE hCabinet = NULL;
44 static DWORD urlmon_tls = TLS_OUT_OF_INDEXES;
45
46 static void init_session(void);
47
48 static struct list tls_list = LIST_INIT(tls_list);
49
50 static CRITICAL_SECTION tls_cs;
51 static CRITICAL_SECTION_DEBUG tls_cs_dbg =
52 {
53 0, 0, &tls_cs,
54 { &tls_cs_dbg.ProcessLocksList, &tls_cs_dbg.ProcessLocksList },
55 0, 0, { (DWORD_PTR)(__FILE__ ": tls") }
56 };
57
58 static CRITICAL_SECTION tls_cs = { &tls_cs_dbg, -1, 0, 0, 0, 0 };
59
60 tls_data_t *get_tls_data(void)
61 {
62 tls_data_t *data;
63
64 if(urlmon_tls == TLS_OUT_OF_INDEXES) {
65 DWORD tls = TlsAlloc();
66 if(tls == TLS_OUT_OF_INDEXES)
67 return NULL;
68
69 tls = InterlockedCompareExchange((LONG*)&urlmon_tls, tls, TLS_OUT_OF_INDEXES);
70 if(tls != urlmon_tls)
71 TlsFree(tls);
72 }
73
74 data = TlsGetValue(urlmon_tls);
75 if(!data) {
76 data = heap_alloc_zero(sizeof(tls_data_t));
77 if(!data)
78 return NULL;
79
80 EnterCriticalSection(&tls_cs);
81 list_add_tail(&tls_list, &data->entry);
82 LeaveCriticalSection(&tls_cs);
83
84 TlsSetValue(urlmon_tls, data);
85 }
86
87 return data;
88 }
89
90 static void free_tls_list(void)
91 {
92 tls_data_t *data;
93
94 if(urlmon_tls == TLS_OUT_OF_INDEXES)
95 return;
96
97 while(!list_empty(&tls_list)) {
98 data = LIST_ENTRY(list_head(&tls_list), tls_data_t, entry);
99 list_remove(&data->entry);
100 heap_free(data);
101 }
102
103 TlsFree(urlmon_tls);
104 }
105
106 static void detach_thread(void)
107 {
108 tls_data_t *data;
109
110 if(urlmon_tls == TLS_OUT_OF_INDEXES)
111 return;
112
113 data = TlsGetValue(urlmon_tls);
114 if(!data)
115 return;
116
117 EnterCriticalSection(&tls_cs);
118 list_remove(&data->entry);
119 LeaveCriticalSection(&tls_cs);
120
121 if(data->notif_hwnd) {
122 WARN("notif_hwnd not destroyed\n");
123 DestroyWindow(data->notif_hwnd);
124 }
125
126 heap_free(data);
127 }
128
129 static void process_detach(void)
130 {
131 HINTERNET internet_session;
132
133 internet_session = get_internet_session(NULL);
134 if(internet_session)
135 InternetCloseHandle(internet_session);
136
137 if (hCabinet)
138 FreeLibrary(hCabinet);
139
140 free_session();
141 free_tls_list();
142 }
143
144 /***********************************************************************
145 * DllMain (URLMON.init)
146 */
147 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
148 {
149 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
150
151 URLMON_DllMain( hinstDLL, fdwReason, fImpLoad );
152
153 switch(fdwReason) {
154 case DLL_PROCESS_ATTACH:
155 urlmon_instance = hinstDLL;
156 init_session();
157 break;
158
159 case DLL_PROCESS_DETACH:
160 process_detach();
161 DeleteCriticalSection(&tls_cs);
162 break;
163
164 case DLL_THREAD_DETACH:
165 detach_thread();
166 break;
167 }
168 return TRUE;
169 }
170
171 const char *debugstr_bindstatus(ULONG status)
172 {
173 switch(status) {
174 #define X(x) case x: return #x
175 X(BINDSTATUS_FINDINGRESOURCE);
176 X(BINDSTATUS_CONNECTING);
177 X(BINDSTATUS_REDIRECTING);
178 X(BINDSTATUS_BEGINDOWNLOADDATA);
179 X(BINDSTATUS_DOWNLOADINGDATA);
180 X(BINDSTATUS_ENDDOWNLOADDATA);
181 X(BINDSTATUS_BEGINDOWNLOADCOMPONENTS);
182 X(BINDSTATUS_INSTALLINGCOMPONENTS);
183 X(BINDSTATUS_ENDDOWNLOADCOMPONENTS);
184 X(BINDSTATUS_USINGCACHEDCOPY);
185 X(BINDSTATUS_SENDINGREQUEST);
186 X(BINDSTATUS_CLASSIDAVAILABLE);
187 X(BINDSTATUS_MIMETYPEAVAILABLE);
188 X(BINDSTATUS_CACHEFILENAMEAVAILABLE);
189 X(BINDSTATUS_BEGINSYNCOPERATION);
190 X(BINDSTATUS_ENDSYNCOPERATION);
191 X(BINDSTATUS_BEGINUPLOADDATA);
192 X(BINDSTATUS_UPLOADINGDATA);
193 X(BINDSTATUS_ENDUPLOADINGDATA);
194 X(BINDSTATUS_PROTOCOLCLASSID);
195 X(BINDSTATUS_ENCODING);
196 X(BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE);
197 X(BINDSTATUS_CLASSINSTALLLOCATION);
198 X(BINDSTATUS_DECODING);
199 X(BINDSTATUS_LOADINGMIMEHANDLER);
200 X(BINDSTATUS_CONTENTDISPOSITIONATTACH);
201 X(BINDSTATUS_FILTERREPORTMIMETYPE);
202 X(BINDSTATUS_CLSIDCANINSTANTIATE);
203 X(BINDSTATUS_IUNKNOWNAVAILABLE);
204 X(BINDSTATUS_DIRECTBIND);
205 X(BINDSTATUS_RAWMIMETYPE);
206 X(BINDSTATUS_PROXYDETECTING);
207 X(BINDSTATUS_ACCEPTRANGES);
208 X(BINDSTATUS_COOKIE_SENT);
209 X(BINDSTATUS_COMPACT_POLICY_RECEIVED);
210 X(BINDSTATUS_COOKIE_SUPPRESSED);
211 X(BINDSTATUS_COOKIE_STATE_UNKNOWN);
212 X(BINDSTATUS_COOKIE_STATE_ACCEPT);
213 X(BINDSTATUS_COOKIE_STATE_REJECT);
214 X(BINDSTATUS_COOKIE_STATE_PROMPT);
215 X(BINDSTATUS_COOKIE_STATE_LEASH);
216 X(BINDSTATUS_COOKIE_STATE_DOWNGRADE);
217 X(BINDSTATUS_POLICY_HREF);
218 X(BINDSTATUS_P3P_HEADER);
219 X(BINDSTATUS_SESSION_COOKIE_RECEIVED);
220 X(BINDSTATUS_PERSISTENT_COOKIE_RECEIVED);
221 X(BINDSTATUS_SESSION_COOKIES_ALLOWED);
222 X(BINDSTATUS_CACHECONTROL);
223 X(BINDSTATUS_CONTENTDISPOSITIONFILENAME);
224 X(BINDSTATUS_MIMETEXTPLAINMISMATCH);
225 X(BINDSTATUS_PUBLISHERAVAILABLE);
226 X(BINDSTATUS_DISPLAYNAMEAVAILABLE);
227 #undef X
228 default:
229 return wine_dbg_sprintf("(invalid status %u)", status);
230 }
231 }
232
233 /***********************************************************************
234 * DllInstall (URLMON.@)
235 */
236 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
237 {
238 FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
239 debugstr_w(cmdline));
240
241 return S_OK;
242 }
243
244 /***********************************************************************
245 * DllCanUnloadNow (URLMON.@)
246 */
247 HRESULT WINAPI DllCanUnloadNow(void)
248 {
249 return URLMON_refCount != 0 ? S_FALSE : S_OK;
250 }
251
252
253
254 /******************************************************************************
255 * Urlmon ClassFactory
256 */
257 typedef struct {
258 IClassFactory IClassFactory_iface;
259
260 HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
261 } ClassFactory;
262
263 static inline ClassFactory *impl_from_IClassFactory(IClassFactory *iface)
264 {
265 return CONTAINING_RECORD(iface, ClassFactory, IClassFactory_iface);
266 }
267
268 static HRESULT WINAPI CF_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppv)
269 {
270 *ppv = NULL;
271
272 if(IsEqualGUID(riid, &IID_IUnknown)) {
273 TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
274 *ppv = iface;
275 }else if(IsEqualGUID(riid, &IID_IClassFactory)) {
276 TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv);
277 *ppv = iface;
278 }
279
280 if(*ppv) {
281 IUnknown_AddRef((IUnknown*)*ppv);
282 return S_OK;
283 }
284
285 WARN("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ppv);
286 return E_NOINTERFACE;
287 }
288
289 static ULONG WINAPI CF_AddRef(IClassFactory *iface)
290 {
291 URLMON_LockModule();
292 return 2;
293 }
294
295 static ULONG WINAPI CF_Release(IClassFactory *iface)
296 {
297 URLMON_UnlockModule();
298 return 1;
299 }
300
301
302 static HRESULT WINAPI CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
303 REFIID riid, LPVOID *ppobj)
304 {
305 ClassFactory *This = impl_from_IClassFactory(iface);
306 HRESULT hres;
307 LPUNKNOWN punk;
308
309 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
310
311 *ppobj = NULL;
312 if(SUCCEEDED(hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk))) {
313 hres = IUnknown_QueryInterface(punk, riid, ppobj);
314 IUnknown_Release(punk);
315 }
316 return hres;
317 }
318
319 static HRESULT WINAPI CF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
320 {
321 TRACE("(%d)\n", dolock);
322
323 if (dolock)
324 URLMON_LockModule();
325 else
326 URLMON_UnlockModule();
327
328 return S_OK;
329 }
330
331 static const IClassFactoryVtbl ClassFactoryVtbl =
332 {
333 CF_QueryInterface,
334 CF_AddRef,
335 CF_Release,
336 CF_CreateInstance,
337 CF_LockServer
338 };
339
340 static ClassFactory FileProtocolCF =
341 { { &ClassFactoryVtbl }, FileProtocol_Construct};
342 static ClassFactory FtpProtocolCF =
343 { { &ClassFactoryVtbl }, FtpProtocol_Construct};
344 static ClassFactory GopherProtocolCF =
345 { { &ClassFactoryVtbl }, GopherProtocol_Construct};
346 static ClassFactory HttpProtocolCF =
347 { { &ClassFactoryVtbl }, HttpProtocol_Construct};
348 static ClassFactory HttpSProtocolCF =
349 { { &ClassFactoryVtbl }, HttpSProtocol_Construct};
350 static ClassFactory MkProtocolCF =
351 { { &ClassFactoryVtbl }, MkProtocol_Construct};
352 static ClassFactory SecurityManagerCF =
353 { { &ClassFactoryVtbl }, SecManagerImpl_Construct};
354 static ClassFactory ZoneManagerCF =
355 { { &ClassFactoryVtbl }, ZoneMgrImpl_Construct};
356 static ClassFactory StdURLMonikerCF =
357 { { &ClassFactoryVtbl }, StdURLMoniker_Construct};
358 static ClassFactory MimeFilterCF =
359 { { &ClassFactoryVtbl }, MimeFilter_Construct};
360 static ClassFactory CUriCF =
361 { { &ClassFactoryVtbl }, Uri_Construct};
362
363 struct object_creation_info
364 {
365 const CLSID *clsid;
366 IClassFactory *cf;
367 LPCWSTR protocol;
368 };
369
370 static const WCHAR wszFile[] = {'f','i','l','e',0};
371 static const WCHAR wszFtp[] = {'f','t','p',0};
372 static const WCHAR wszGopher[] = {'g','o','p','h','e','r',0};
373 static const WCHAR wszHttp[] = {'h','t','t','p',0};
374 static const WCHAR wszHttps[] = {'h','t','t','p','s',0};
375 static const WCHAR wszMk[] = {'m','k',0};
376
377 static const struct object_creation_info object_creation[] =
378 {
379 { &CLSID_FileProtocol, &FileProtocolCF.IClassFactory_iface, wszFile },
380 { &CLSID_FtpProtocol, &FtpProtocolCF.IClassFactory_iface, wszFtp },
381 { &CLSID_GopherProtocol, &GopherProtocolCF.IClassFactory_iface, wszGopher },
382 { &CLSID_HttpProtocol, &HttpProtocolCF.IClassFactory_iface, wszHttp },
383 { &CLSID_HttpSProtocol, &HttpSProtocolCF.IClassFactory_iface, wszHttps },
384 { &CLSID_MkProtocol, &MkProtocolCF.IClassFactory_iface, wszMk },
385 { &CLSID_InternetSecurityManager, &SecurityManagerCF.IClassFactory_iface, NULL },
386 { &CLSID_InternetZoneManager, &ZoneManagerCF.IClassFactory_iface, NULL },
387 { &CLSID_StdURLMoniker, &StdURLMonikerCF.IClassFactory_iface, NULL },
388 { &CLSID_DeCompMimeFilter, &MimeFilterCF.IClassFactory_iface, NULL },
389 { &CLSID_CUri, &CUriCF.IClassFactory_iface, NULL }
390 };
391
392 static void init_session(void)
393 {
394 unsigned int i;
395
396 for(i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) {
397 if(object_creation[i].protocol)
398 register_namespace(object_creation[i].cf, object_creation[i].clsid,
399 object_creation[i].protocol, TRUE);
400 }
401 }
402
403 /*******************************************************************************
404 * DllGetClassObject [URLMON.@]
405 * Retrieves class object from a DLL object
406 *
407 * NOTES
408 * Docs say returns STDAPI
409 *
410 * PARAMS
411 * rclsid [I] CLSID for the class object
412 * riid [I] Reference to identifier of interface for class object
413 * ppv [O] Address of variable to receive interface pointer for riid
414 *
415 * RETURNS
416 * Success: S_OK
417 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
418 * E_UNEXPECTED
419 */
420
421 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
422 {
423 unsigned int i;
424 HRESULT hr;
425
426 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
427
428 for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
429 {
430 if (IsEqualGUID(object_creation[i].clsid, rclsid))
431 return IClassFactory_QueryInterface(object_creation[i].cf, riid, ppv);
432 }
433
434 hr = URLMON_DllGetClassObject(rclsid, riid, ppv);
435 if(SUCCEEDED(hr))
436 return hr;
437
438 FIXME("%s: no class found.\n", debugstr_guid(rclsid));
439 return CLASS_E_CLASSNOTAVAILABLE;
440 }
441
442 static HRESULT register_inf(BOOL doregister)
443 {
444 HRESULT (WINAPI *pRegInstall)(HMODULE hm, LPCSTR pszSection, const STRTABLEA* pstTable);
445 HMODULE hAdvpack;
446
447 static const WCHAR wszAdvpack[] = {'a','d','v','p','a','c','k','.','d','l','l',0};
448
449 hAdvpack = LoadLibraryW(wszAdvpack);
450 pRegInstall = (void *)GetProcAddress(hAdvpack, "RegInstall");
451
452 return pRegInstall(hProxyDll, doregister ? "RegisterDll" : "UnregisterDll", NULL);
453 }
454
455 /***********************************************************************
456 * DllRegisterServer (URLMON.@)
457 */
458 HRESULT WINAPI DllRegisterServer(void)
459 {
460 HRESULT hr;
461
462 TRACE("\n");
463
464 hr = URLMON_DllRegisterServer();
465 return SUCCEEDED(hr) ? register_inf(TRUE) : hr;
466 }
467
468 /***********************************************************************
469 * DllUnregisterServer (URLMON.@)
470 */
471 HRESULT WINAPI DllUnregisterServer(void)
472 {
473 HRESULT hr;
474
475 TRACE("\n");
476
477 hr = URLMON_DllUnregisterServer();
478 return SUCCEEDED(hr) ? register_inf(FALSE) : hr;
479 }
480
481 /***********************************************************************
482 * DllRegisterServerEx (URLMON.@)
483 */
484 HRESULT WINAPI DllRegisterServerEx(void)
485 {
486 FIXME("(void): stub\n");
487
488 return E_FAIL;
489 }
490
491 /**************************************************************************
492 * IsValidURL (URLMON.@)
493 *
494 * Determines if a specified string is a valid URL.
495 *
496 * PARAMS
497 * pBC [I] ignored, should be NULL.
498 * szURL [I] string that represents the URL in question.
499 * dwReserved [I] reserved and must be zero.
500 *
501 * RETURNS
502 * Success: S_OK.
503 * Failure: S_FALSE.
504 * returns E_INVALIDARG if one or more of the args is invalid.
505 *
506 * TODO:
507 * test functionality against windows to see what a valid URL is.
508 */
509 HRESULT WINAPI IsValidURL(LPBC pBC, LPCWSTR szURL, DWORD dwReserved)
510 {
511 FIXME("(%p, %s, %d): stub\n", pBC, debugstr_w(szURL), dwReserved);
512
513 if (dwReserved || !szURL)
514 return E_INVALIDARG;
515
516 return S_OK;
517 }
518
519 /**************************************************************************
520 * FaultInIEFeature (URLMON.@)
521 *
522 * Undocumented. Appears to be used by native shdocvw.dll.
523 */
524 HRESULT WINAPI FaultInIEFeature( HWND hwnd, uCLSSPEC * pClassSpec,
525 QUERYCONTEXT *pQuery, DWORD flags )
526 {
527 FIXME("%p %p %p %08x\n", hwnd, pClassSpec, pQuery, flags);
528 return E_NOTIMPL;
529 }
530
531 /**************************************************************************
532 * CoGetClassObjectFromURL (URLMON.@)
533 */
534 HRESULT WINAPI CoGetClassObjectFromURL( REFCLSID rclsid, LPCWSTR szCodeURL, DWORD dwFileVersionMS,
535 DWORD dwFileVersionLS, LPCWSTR szContentType,
536 LPBINDCTX pBindCtx, DWORD dwClsContext, LPVOID pvReserved,
537 REFIID riid, LPVOID *ppv )
538 {
539 FIXME("(%s %s %d %d %s %p %d %p %s %p) Stub!\n", debugstr_guid(rclsid), debugstr_w(szCodeURL),
540 dwFileVersionMS, dwFileVersionLS, debugstr_w(szContentType), pBindCtx, dwClsContext, pvReserved,
541 debugstr_guid(riid), ppv);
542 return E_NOINTERFACE;
543 }
544
545 /***********************************************************************
546 * ReleaseBindInfo (URLMON.@)
547 *
548 * Release the resources used by the specified BINDINFO structure.
549 *
550 * PARAMS
551 * pbindinfo [I] BINDINFO to release.
552 *
553 * RETURNS
554 * Nothing.
555 */
556 void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo)
557 {
558 DWORD size;
559
560 TRACE("(%p)\n", pbindinfo);
561
562 if(!pbindinfo || !(size = pbindinfo->cbSize))
563 return;
564
565 CoTaskMemFree(pbindinfo->szExtraInfo);
566 ReleaseStgMedium(&pbindinfo->stgmedData);
567
568 if(offsetof(BINDINFO, szExtraInfo) < size)
569 CoTaskMemFree(pbindinfo->szCustomVerb);
570
571 if(pbindinfo->pUnk && offsetof(BINDINFO, pUnk) < size)
572 IUnknown_Release(pbindinfo->pUnk);
573
574 memset(pbindinfo, 0, size);
575 pbindinfo->cbSize = size;
576 }
577
578 /***********************************************************************
579 * CopyStgMedium (URLMON.@)
580 */
581 HRESULT WINAPI CopyStgMedium(const STGMEDIUM *src, STGMEDIUM *dst)
582 {
583 TRACE("(%p %p)\n", src, dst);
584
585 if(!src || !dst)
586 return E_POINTER;
587
588 *dst = *src;
589
590 switch(dst->tymed) {
591 case TYMED_NULL:
592 break;
593 case TYMED_FILE:
594 if(src->u.lpszFileName && !src->pUnkForRelease) {
595 DWORD size = (strlenW(src->u.lpszFileName)+1)*sizeof(WCHAR);
596 dst->u.lpszFileName = CoTaskMemAlloc(size);
597 if(!dst->u.lpszFileName)
598 return E_OUTOFMEMORY;
599 memcpy(dst->u.lpszFileName, src->u.lpszFileName, size);
600 }
601 break;
602 case TYMED_ISTREAM:
603 if(dst->u.pstm)
604 IStream_AddRef(dst->u.pstm);
605 break;
606 case TYMED_ISTORAGE:
607 if(dst->u.pstg)
608 IStorage_AddRef(dst->u.pstg);
609 break;
610 case TYMED_HGLOBAL:
611 if(dst->u.hGlobal) {
612 SIZE_T size = GlobalSize(src->u.hGlobal);
613 char *src_ptr, *dst_ptr;
614
615 dst->u.hGlobal = GlobalAlloc(GMEM_FIXED, size);
616 if(!dst->u.hGlobal)
617 return E_OUTOFMEMORY;
618 dst_ptr = GlobalLock(dst->u.hGlobal);
619 src_ptr = GlobalLock(src->u.hGlobal);
620 memcpy(dst_ptr, src_ptr, size);
621 GlobalUnlock(src_ptr);
622 GlobalUnlock(dst_ptr);
623 }
624 break;
625 default:
626 FIXME("Unimplemented tymed %d\n", src->tymed);
627 }
628
629 if(dst->pUnkForRelease)
630 IUnknown_AddRef(dst->pUnkForRelease);
631
632 return S_OK;
633 }
634
635 /***********************************************************************
636 * CopyBindInfo (URLMON.@)
637 */
638 HRESULT WINAPI CopyBindInfo(const BINDINFO *pcbiSrc, BINDINFO *pcbiDest)
639 {
640 DWORD size;
641 HRESULT hres;
642
643 TRACE("(%p %p)\n", pcbiSrc, pcbiDest);
644
645 if(!pcbiSrc || !pcbiDest)
646 return E_POINTER;
647 if(!pcbiSrc->cbSize || !pcbiDest->cbSize)
648 return E_INVALIDARG;
649
650 size = pcbiDest->cbSize;
651 if(size > pcbiSrc->cbSize) {
652 memcpy(pcbiDest, pcbiSrc, pcbiSrc->cbSize);
653 memset((char*)pcbiDest+pcbiSrc->cbSize, 0, size-pcbiSrc->cbSize);
654 } else {
655 memcpy(pcbiDest, pcbiSrc, size);
656 }
657 pcbiDest->cbSize = size;
658
659 size = FIELD_OFFSET(BINDINFO, szExtraInfo)+sizeof(void*);
660 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size && pcbiSrc->szExtraInfo) {
661 size = (strlenW(pcbiSrc->szExtraInfo)+1)*sizeof(WCHAR);
662 pcbiDest->szExtraInfo = CoTaskMemAlloc(size);
663 if(!pcbiDest->szExtraInfo)
664 return E_OUTOFMEMORY;
665 memcpy(pcbiDest->szExtraInfo, pcbiSrc->szExtraInfo, size);
666 }
667
668 size = FIELD_OFFSET(BINDINFO, stgmedData)+sizeof(STGMEDIUM);
669 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size) {
670 hres = CopyStgMedium(&pcbiSrc->stgmedData, &pcbiDest->stgmedData);
671 if(FAILED(hres)) {
672 CoTaskMemFree(pcbiDest->szExtraInfo);
673 return hres;
674 }
675 }
676
677 size = FIELD_OFFSET(BINDINFO, szCustomVerb)+sizeof(void*);
678 if(pcbiSrc->cbSize>=size && pcbiDest->cbSize>=size && pcbiSrc->szCustomVerb) {
679 size = (strlenW(pcbiSrc->szCustomVerb)+1)*sizeof(WCHAR);
680 pcbiDest->szCustomVerb = CoTaskMemAlloc(size);
681 if(!pcbiDest->szCustomVerb) {
682 CoTaskMemFree(pcbiDest->szExtraInfo);
683 ReleaseStgMedium(&pcbiDest->stgmedData);
684 return E_OUTOFMEMORY;
685 }
686 memcpy(pcbiDest->szCustomVerb, pcbiSrc->szCustomVerb, size);
687 }
688
689 size = FIELD_OFFSET(BINDINFO, securityAttributes)+sizeof(SECURITY_ATTRIBUTES);
690 if(pcbiDest->cbSize >= size)
691 memset(&pcbiDest->securityAttributes, 0, sizeof(SECURITY_ATTRIBUTES));
692
693 if(pcbiSrc->pUnk)
694 IUnknown_AddRef(pcbiDest->pUnk);
695
696 return S_OK;
697 }
698
699 static BOOL text_richtext_filter(const BYTE *b, DWORD size)
700 {
701 return size > 5 && !memcmp(b, "{\\rtf", 5);
702 }
703
704 static BOOL text_html_filter(const BYTE *b, DWORD size)
705 {
706 if(size < 6)
707 return FALSE;
708
709 if((b[0] == '<'
710 && (b[1] == 'h' || b[1] == 'H')
711 && (b[2] == 't' || b[2] == 'T')
712 && (b[3] == 'm' || b[3] == 'M')
713 && (b[4] == 'l' || b[4] == 'L'))
714 || (b[0] == '<'
715 && (b[1] == 'h' || b[1] == 'H')
716 && (b[2] == 'e' || b[2] == 'E')
717 && (b[3] == 'a' || b[3] == 'A')
718 && (b[4] == 'd' || b[4] == 'D'))) return TRUE;
719
720 return FALSE;
721 }
722
723 static BOOL text_xml_filter(const BYTE *b, DWORD size)
724 {
725 if(size < 7)
726 return FALSE;
727
728 if(b[0] == '<' && b[1] == '?'
729 && (b[2] == 'x' || b[2] == 'X')
730 && (b[3] == 'm' || b[3] == 'M')
731 && (b[4] == 'l' || b[4] == 'L')
732 && b[5] == ' ') return TRUE;
733
734 return FALSE;
735 }
736
737 static BOOL audio_basic_filter(const BYTE *b, DWORD size)
738 {
739 return size > 4
740 && b[0] == '.' && b[1] == 's' && b[2] == 'n' && b[3] == 'd';
741 }
742
743 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
744 {
745 return size > 12
746 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
747 && b[8] == 'W' && b[9] == 'A' && b[10] == 'V' && b[11] == 'E';
748 }
749
750 static BOOL image_gif_filter(const BYTE *b, DWORD size)
751 {
752 return size >= 6
753 && (b[0] == 'G' || b[0] == 'g')
754 && (b[1] == 'I' || b[1] == 'i')
755 && (b[2] == 'F' || b[2] == 'f')
756 && b[3] == '8'
757 && (b[4] == '7' || b[4] == '9')
758 && (b[5] == 'A' || b[5] == 'a');
759 }
760
761 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
762 {
763 return size > 2 && b[0] == 0xff && b[1] == 0xd8;
764 }
765
766 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
767 {
768 static const BYTE magic1[] = {0x4d,0x4d,0x00,0x2a};
769 static const BYTE magic2[] = {0x49,0x49,0x2a,0xff};
770
771 return size >= 4 && (!memcmp(b, magic1, 4) || !memcmp(b, magic2, 4));
772 }
773
774 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
775 {
776 static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
777 return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header));
778 }
779
780 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
781 {
782 return size >= 14
783 && b[0] == 0x42 && b[1] == 0x4d
784 && *(const DWORD *)(b+6) == 0;
785 }
786
787 static BOOL video_avi_filter(const BYTE *b, DWORD size)
788 {
789 return size > 12
790 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
791 && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20;
792 }
793
794 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
795 {
796 return size > 4
797 && !b[0] && !b[1] && b[2] == 0x01
798 && (b[3] == 0xb3 || b[3] == 0xba);
799 }
800
801 static BOOL application_postscript_filter(const BYTE *b, DWORD size)
802 {
803 return size > 2 && b[0] == '%' && b[1] == '!';
804 }
805
806 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
807 {
808 return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
809 }
810
811 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
812 {
813 return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
814 }
815
816 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
817 {
818 return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
819 }
820
821 static BOOL application_java_filter(const BYTE *b, DWORD size)
822 {
823 return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
824 }
825
826 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
827 {
828 return size > 2 && b[0] == 'M' && b[1] == 'Z';
829 }
830
831 static inline BOOL is_text_plain_char(BYTE b)
832 {
833 if(b < 0x20 && b != '\n' && b != '\r' && b != '\t')
834 return FALSE;
835 return TRUE;
836 }
837
838 static BOOL text_plain_filter(const BYTE *b, DWORD size)
839 {
840 const BYTE *ptr;
841
842 for(ptr = b; ptr < b+size-1; ptr++) {
843 if(!is_text_plain_char(*ptr))
844 return FALSE;
845 }
846
847 return TRUE;
848 }
849
850 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
851 {
852 return TRUE;
853 }
854
855 static HRESULT find_mime_from_buffer(const BYTE *buf, DWORD size, const WCHAR *proposed_mime, WCHAR **ret_mime)
856 {
857 LPCWSTR ret = NULL;
858 int len, i, any_pos_mime = -1;
859
860 static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0};
861 static const WCHAR text_richtextW[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0};
862 static const WCHAR text_xmlW[] = {'t','e','x','t','/','x','m','l',0};
863 static const WCHAR audio_basicW[] = {'a','u','d','i','o','/','b','a','s','i','c',0};
864 static const WCHAR audio_wavW[] = {'a','u','d','i','o','/','w','a','v',0};
865 static const WCHAR image_gifW[] = {'i','m','a','g','e','/','g','i','f',0};
866 static const WCHAR image_pjpegW[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
867 static const WCHAR image_tiffW[] = {'i','m','a','g','e','/','t','i','f','f',0};
868 static const WCHAR image_xpngW[] = {'i','m','a','g','e','/','x','-','p','n','g',0};
869 static const WCHAR image_bmpW[] = {'i','m','a','g','e','/','b','m','p',0};
870 static const WCHAR video_aviW[] = {'v','i','d','e','o','/','a','v','i',0};
871 static const WCHAR video_mpegW[] = {'v','i','d','e','o','/','m','p','e','g',0};
872 static const WCHAR app_postscriptW[] =
873 {'a','p','p','l','i','c','a','t','i','o','n','/','p','o','s','t','s','c','r','i','p','t',0};
874 static const WCHAR app_pdfW[] = {'a','p','p','l','i','c','a','t','i','o','n','/','p','d','f',0};
875 static const WCHAR app_xzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
876 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
877 static const WCHAR app_xgzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
878 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
879 static const WCHAR app_javaW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
880 'j','a','v','a',0};
881 static const WCHAR app_xmsdownloadW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
882 'x','-','m','s','d','o','w','n','l','o','a','d',0};
883 static const WCHAR text_plainW[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
884 static const WCHAR app_octetstreamW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
885 'o','c','t','e','t','-','s','t','r','e','a','m','\0'};
886
887 static const struct {
888 LPCWSTR mime;
889 BOOL (*filter)(const BYTE *,DWORD);
890 } mime_filters_any_pos[] = {
891 {text_htmlW, text_html_filter},
892 {text_xmlW, text_xml_filter}
893 }, mime_filters[] = {
894 {text_richtextW, text_richtext_filter},
895 /* {audio_xaiffW, audio_xaiff_filter}, */
896 {audio_basicW, audio_basic_filter},
897 {audio_wavW, audio_wav_filter},
898 {image_gifW, image_gif_filter},
899 {image_pjpegW, image_pjpeg_filter},
900 {image_tiffW, image_tiff_filter},
901 {image_xpngW, image_xpng_filter},
902 /* {image_xbitmapW, image_xbitmap_filter}, */
903 {image_bmpW, image_bmp_filter},
904 /* {image_xjgW, image_xjg_filter}, */
905 /* {image_xemfW, image_xemf_filter}, */
906 /* {image_xwmfW, image_xwmf_filter}, */
907 {video_aviW, video_avi_filter},
908 {video_mpegW, video_mpeg_filter},
909 {app_postscriptW, application_postscript_filter},
910 /* {app_base64W, application_base64_filter}, */
911 /* {app_macbinhex40W, application_macbinhex40_filter}, */
912 {app_pdfW, application_pdf_filter},
913 /* {app_zcompressedW, application_xcompressed_filter}, */
914 {app_xzipW, application_xzip_filter},
915 {app_xgzipW, application_xgzip_filter},
916 {app_javaW, application_java_filter},
917 {app_xmsdownloadW, application_xmsdownload},
918 {text_plainW, text_plain_filter},
919 {app_octetstreamW, application_octet_stream_filter}
920 };
921
922 if(!buf || !size) {
923 if(!proposed_mime)
924 return E_FAIL;
925
926 len = strlenW(proposed_mime)+1;
927 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
928 if(!*ret_mime)
929 return E_OUTOFMEMORY;
930
931 memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR));
932 return S_OK;
933 }
934
935 if(proposed_mime && (!strcmpW(proposed_mime, app_octetstreamW)
936 || !strcmpW(proposed_mime, text_plainW)))
937 proposed_mime = NULL;
938
939 if(proposed_mime) {
940 ret = proposed_mime;
941
942 for(i=0; i < sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
943 if(!strcmpW(proposed_mime, mime_filters_any_pos[i].mime)) {
944 any_pos_mime = i;
945 for(len=size; len>0; len--) {
946 if(mime_filters_any_pos[i].filter(buf+size-len, len))
947 break;
948 }
949 if(!len)
950 ret = NULL;
951 break;
952 }
953 }
954
955 if(i == sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos)) {
956 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
957 if(!strcmpW(proposed_mime, mime_filters[i].mime)) {
958 if(!mime_filters[i].filter(buf, size))
959 ret = NULL;
960 break;
961 }
962 }
963 }
964 }
965
966 /* Looks like a bug in native implementation, html and xml mimes
967 * are not looked for if none of them was proposed */
968 if(!proposed_mime || any_pos_mime!=-1) {
969 for(len=size; !ret && len>0; len--) {
970 for(i=0; i<sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
971 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
972 ret = mime_filters_any_pos[i].mime;
973 break;
974 }
975 }
976 }
977 }
978
979 i=0;
980 while(!ret) {
981 if(mime_filters[i].filter(buf, size))
982 ret = mime_filters[i].mime;
983 i++;
984 }
985
986 if(any_pos_mime!=-1 && ret==text_plainW)
987 ret = mime_filters_any_pos[any_pos_mime].mime;
988 else if(proposed_mime && ret==app_octetstreamW) {
989 for(len=size; ret==app_octetstreamW && len>0; len--) {
990 if(!is_text_plain_char(buf[size-len]))
991 break;
992 for(i=0; i<sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
993 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
994 ret = text_plainW;
995 break;
996 }
997 }
998 }
999
1000 if(ret == app_octetstreamW)
1001 ret = proposed_mime;
1002 }
1003 TRACE("found %s for %s\n", debugstr_w(ret), debugstr_an((const char*)buf, min(32, size)));
1004
1005 len = strlenW(ret)+1;
1006 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
1007 if(!*ret_mime)
1008 return E_OUTOFMEMORY;
1009
1010 memcpy(*ret_mime, ret, len*sizeof(WCHAR));
1011 return S_OK;
1012 }
1013
1014 /***********************************************************************
1015 * FindMimeFromData (URLMON.@)
1016 *
1017 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
1018 */
1019 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
1020 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
1021 LPWSTR* ppwzMimeOut, DWORD dwReserved)
1022 {
1023 TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
1024 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
1025
1026 if(dwMimeFlags)
1027 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
1028 if(dwReserved)
1029 WARN("dwReserved=%d\n", dwReserved);
1030
1031 /* pBC seams to not be used */
1032
1033 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
1034 return E_INVALIDARG;
1035
1036 if(pwzMimeProposed || pBuffer)
1037 return find_mime_from_buffer(pBuffer, cbSize, pwzMimeProposed, ppwzMimeOut);
1038
1039 if(pwzUrl) {
1040 HKEY hkey;
1041 DWORD res, size;
1042 LPCWSTR ptr;
1043 WCHAR mime[64];
1044
1045 static const WCHAR wszContentType[] =
1046 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
1047
1048 ptr = strrchrW(pwzUrl, '.');
1049 if(!ptr)
1050 return E_FAIL;
1051
1052 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
1053 if(res != ERROR_SUCCESS)
1054 return HRESULT_FROM_WIN32(res);
1055
1056 size = sizeof(mime);
1057 res = RegQueryValueExW(hkey, wszContentType, NULL, NULL, (LPBYTE)mime, &size);
1058 RegCloseKey(hkey);
1059 if(res != ERROR_SUCCESS)
1060 return HRESULT_FROM_WIN32(res);
1061
1062 *ppwzMimeOut = CoTaskMemAlloc(size);
1063 memcpy(*ppwzMimeOut, mime, size);
1064 return S_OK;
1065 }
1066
1067 return E_FAIL;
1068 }
1069
1070 /***********************************************************************
1071 * GetClassFileOrMime (URLMON.@)
1072 *
1073 * Determines the class ID from the bind context, file name or MIME type.
1074 */
1075 HRESULT WINAPI GetClassFileOrMime(LPBC pBC, LPCWSTR pszFilename,
1076 LPVOID pBuffer, DWORD cbBuffer, LPCWSTR pszMimeType, DWORD dwReserved,
1077 CLSID *pclsid)
1078 {
1079 FIXME("(%p, %s, %p, %d, %s, 0x%08x, %p): stub\n", pBC, debugstr_w(pszFilename), pBuffer,
1080 cbBuffer, debugstr_w(pszMimeType), dwReserved, pclsid);
1081 return E_NOTIMPL;
1082 }
1083
1084 /***********************************************************************
1085 * Extract (URLMON.@)
1086 */
1087 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
1088 {
1089 HRESULT (WINAPI *pExtract)(void *, LPCSTR);
1090
1091 if (!hCabinet)
1092 hCabinet = LoadLibraryA("cabinet.dll");
1093
1094 if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
1095 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
1096 if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());
1097
1098 return pExtract(dest, szCabName);
1099 }
1100
1101 /***********************************************************************
1102 * IsLoggingEnabledA (URLMON.@)
1103 */
1104 BOOL WINAPI IsLoggingEnabledA(LPCSTR url)
1105 {
1106 FIXME("(%s)\n", debugstr_a(url));
1107 return FALSE;
1108 }
1109
1110 /***********************************************************************
1111 * IsLoggingEnabledW (URLMON.@)
1112 */
1113 BOOL WINAPI IsLoggingEnabledW(LPCWSTR url)
1114 {
1115 FIXME("(%s)\n", debugstr_w(url));
1116 return FALSE;
1117 }
1118
1119 /***********************************************************************
1120 * IsProtectedModeURL (URLMON.111)
1121 * Undocumented, added in IE7
1122 */
1123 BOOL WINAPI IsProtectedModeURL(const WCHAR *url)
1124 {
1125 FIXME("stub: %s\n", debugstr_w(url));
1126 return TRUE;
1127 }
1128
1129 /***********************************************************************
1130 * LogSqmBits (URLMON.410)
1131 * Undocumented, added in IE8
1132 */
1133 int WINAPI LogSqmBits(DWORD unk1, DWORD unk2)
1134 {
1135 FIXME("stub: %d %d\n", unk1, unk2);
1136 return 0;
1137 }
1138
1139 /***********************************************************************
1140 * LogSqmUXCommandOffsetInternal (URLMON.423)
1141 * Undocumented, added in IE8
1142 */
1143 void WINAPI LogSqmUXCommandOffsetInternal(DWORD unk1, DWORD unk2, DWORD unk3, DWORD unk4)
1144 {
1145 FIXME("stub: %d %d %d %d\n", unk1, unk2, unk3, unk4);
1146 }
1147
1148 /***********************************************************************
1149 * MapUriToBrowserEmulationState (URLMON.444)
1150 * Undocumented, added in IE8
1151 */
1152 int WINAPI MapUriToBrowserEmulationState(DWORD unk1, DWORD unk2, DWORD unk3)
1153 {
1154 FIXME("stub: %d %d %d\n", unk1, unk2, unk3);
1155 return 0;
1156 }
1157
1158 /***********************************************************************
1159 * MapBrowserEmulationModeToUserAgent (URLMON.445)
1160 * Undocumented, added in IE8
1161 */
1162 int WINAPI MapBrowserEmulationModeToUserAgent(DWORD unk1, DWORD unk2)
1163 {
1164 FIXME("stub: %d %d\n", unk1, unk2);
1165 return 0;
1166 }
1167
1168 /***********************************************************************
1169 * FlushUrlmonZonesCache (URLMON.455)
1170 * Undocumented, added in IE8
1171 */
1172 void WINAPI FlushUrlmonZonesCache(void)
1173 {
1174 FIXME("stub\n");
1175 }
1176
1177 /***********************************************************************
1178 * RegisterMediaTypes
1179 * Added in IE3, registers known MIME-type strings.
1180 */
1181 HRESULT WINAPI RegisterMediaTypes(UINT types, LPCSTR *szTypes, CLIPFORMAT *cfTypes)
1182 {
1183 FIXME("stub: %u %p %p\n", types, szTypes, cfTypes);
1184 return E_INVALIDARG;
1185 }