mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / urlmon / mimefilter.c
blob6ee0da5b1190060fa4b0cb3ba0a2fc8403282b11
1 /*
2 * Copyright 2009 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "urlmon_main.h"
20 #include "wine/debug.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
24 typedef struct {
25 IInternetProtocol IInternetProtocol_iface;
26 IInternetProtocolSink IInternetProtocolSink_iface;
28 LONG ref;
29 } MimeFilter;
31 static inline MimeFilter *impl_from_IInternetProtocol(IInternetProtocol *iface)
33 return CONTAINING_RECORD(iface, MimeFilter, IInternetProtocol_iface);
36 static HRESULT WINAPI MimeFilterProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
38 MimeFilter *This = impl_from_IInternetProtocol(iface);
40 *ppv = NULL;
41 if(IsEqualGUID(&IID_IUnknown, riid)) {
42 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
43 *ppv = &This->IInternetProtocol_iface;
44 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
45 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
46 *ppv = &This->IInternetProtocol_iface;
47 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
48 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
49 *ppv = &This->IInternetProtocol_iface;
50 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
51 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
52 *ppv = &This->IInternetProtocolSink_iface;
55 if(*ppv) {
56 IInternetProtocol_AddRef(iface);
57 return S_OK;
60 WARN("not supported interface %s\n", debugstr_guid(riid));
61 return E_NOINTERFACE;
64 static ULONG WINAPI MimeFilterProtocol_AddRef(IInternetProtocol *iface)
66 MimeFilter *This = impl_from_IInternetProtocol(iface);
67 LONG ref = InterlockedIncrement(&This->ref);
68 TRACE("(%p) ref=%d\n", This, ref);
69 return ref;
72 static ULONG WINAPI MimeFilterProtocol_Release(IInternetProtocol *iface)
74 MimeFilter *This = impl_from_IInternetProtocol(iface);
75 LONG ref = InterlockedDecrement(&This->ref);
77 TRACE("(%p) ref=%d\n", This, ref);
79 if(!ref) {
80 heap_free(This);
82 URLMON_UnlockModule();
85 return ref;
88 static HRESULT WINAPI MimeFilterProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
89 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
90 DWORD grfPI, HANDLE_PTR dwReserved)
92 MimeFilter *This = impl_from_IInternetProtocol(iface);
93 FIXME("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
94 pOIBindInfo, grfPI, dwReserved);
95 return E_NOTIMPL;
98 static HRESULT WINAPI MimeFilterProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
100 MimeFilter *This = impl_from_IInternetProtocol(iface);
101 FIXME("(%p)->(%p)\n", This, pProtocolData);
102 return E_NOTIMPL;
105 static HRESULT WINAPI MimeFilterProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
106 DWORD dwOptions)
108 MimeFilter *This = impl_from_IInternetProtocol(iface);
109 FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
110 return E_NOTIMPL;
113 static HRESULT WINAPI MimeFilterProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
115 MimeFilter *This = impl_from_IInternetProtocol(iface);
116 FIXME("(%p)->(%08x)\n", This, dwOptions);
117 return E_NOTIMPL;
120 static HRESULT WINAPI MimeFilterProtocol_Suspend(IInternetProtocol *iface)
122 MimeFilter *This = impl_from_IInternetProtocol(iface);
123 FIXME("(%p)\n", This);
124 return E_NOTIMPL;
127 static HRESULT WINAPI MimeFilterProtocol_Resume(IInternetProtocol *iface)
129 MimeFilter *This = impl_from_IInternetProtocol(iface);
130 FIXME("(%p)\n", This);
131 return E_NOTIMPL;
134 static HRESULT WINAPI MimeFilterProtocol_Read(IInternetProtocol *iface, void *pv,
135 ULONG cb, ULONG *pcbRead)
137 MimeFilter *This = impl_from_IInternetProtocol(iface);
138 FIXME("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
139 return E_NOTIMPL;
142 static HRESULT WINAPI MimeFilterProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
143 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
145 MimeFilter *This = impl_from_IInternetProtocol(iface);
146 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
147 return E_NOTIMPL;
150 static HRESULT WINAPI MimeFilterProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
152 MimeFilter *This = impl_from_IInternetProtocol(iface);
153 FIXME("(%p)->(%08x)\n", This, dwOptions);
154 return E_NOTIMPL;
157 static HRESULT WINAPI MimeFilterProtocol_UnlockRequest(IInternetProtocol *iface)
159 MimeFilter *This = impl_from_IInternetProtocol(iface);
160 FIXME("(%p)\n", This);
161 return E_NOTIMPL;
164 static const IInternetProtocolVtbl MimeFilterProtocolVtbl = {
165 MimeFilterProtocol_QueryInterface,
166 MimeFilterProtocol_AddRef,
167 MimeFilterProtocol_Release,
168 MimeFilterProtocol_Start,
169 MimeFilterProtocol_Continue,
170 MimeFilterProtocol_Abort,
171 MimeFilterProtocol_Terminate,
172 MimeFilterProtocol_Suspend,
173 MimeFilterProtocol_Resume,
174 MimeFilterProtocol_Read,
175 MimeFilterProtocol_Seek,
176 MimeFilterProtocol_LockRequest,
177 MimeFilterProtocol_UnlockRequest
180 static inline MimeFilter *impl_from_IInternetProtocolSink(IInternetProtocolSink *iface)
182 return CONTAINING_RECORD(iface, MimeFilter, IInternetProtocolSink_iface);
185 static HRESULT WINAPI MimeFilterSink_QueryInterface(IInternetProtocolSink *iface,
186 REFIID riid, void **ppv)
188 MimeFilter *This = impl_from_IInternetProtocolSink(iface);
189 return IInternetProtocol_QueryInterface(&This->IInternetProtocol_iface, riid, ppv);
192 static ULONG WINAPI MimeFilterSink_AddRef(IInternetProtocolSink *iface)
194 MimeFilter *This = impl_from_IInternetProtocolSink(iface);
195 return IInternetProtocol_AddRef(&This->IInternetProtocol_iface);
198 static ULONG WINAPI MimeFilterSink_Release(IInternetProtocolSink *iface)
200 MimeFilter *This = impl_from_IInternetProtocolSink(iface);
201 return IInternetProtocol_Release(&This->IInternetProtocol_iface);
204 static HRESULT WINAPI MimeFilterSink_Switch(IInternetProtocolSink *iface,
205 PROTOCOLDATA *pProtocolData)
207 MimeFilter *This = impl_from_IInternetProtocolSink(iface);
208 FIXME("(%p)->(%p)\n", This, pProtocolData);
209 return E_NOTIMPL;
212 static HRESULT WINAPI MimeFilterSink_ReportProgress(IInternetProtocolSink *iface,
213 ULONG ulStatusCode, LPCWSTR szStatusText)
215 MimeFilter *This = impl_from_IInternetProtocolSink(iface);
216 FIXME("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
217 return E_NOTIMPL;
220 static HRESULT WINAPI MimeFilterSink_ReportData(IInternetProtocolSink *iface,
221 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
223 MimeFilter *This = impl_from_IInternetProtocolSink(iface);
224 FIXME("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
225 return E_NOTIMPL;
228 static HRESULT WINAPI MimeFilterSink_ReportResult(IInternetProtocolSink *iface,
229 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
231 MimeFilter *This = impl_from_IInternetProtocolSink(iface);
232 FIXME("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
233 return E_NOTIMPL;
236 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
237 MimeFilterSink_QueryInterface,
238 MimeFilterSink_AddRef,
239 MimeFilterSink_Release,
240 MimeFilterSink_Switch,
241 MimeFilterSink_ReportProgress,
242 MimeFilterSink_ReportData,
243 MimeFilterSink_ReportResult
246 HRESULT MimeFilter_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
248 MimeFilter *ret;
250 TRACE("(%p %p)\n", pUnkOuter, ppobj);
252 URLMON_LockModule();
254 ret = heap_alloc_zero(sizeof(MimeFilter));
256 ret->IInternetProtocol_iface.lpVtbl = &MimeFilterProtocolVtbl;
257 ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl;
258 ret->ref = 1;
260 *ppobj = &ret->IInternetProtocol_iface;
261 return S_OK;
264 static BOOL text_richtext_filter(const BYTE *b, DWORD size)
266 return size > 5 && !memcmp(b, "{\\rtf", 5);
269 static BOOL text_html_filter(const BYTE *b, DWORD size)
271 if(size < 6)
272 return FALSE;
274 if((b[0] == '<'
275 && (b[1] == 'h' || b[1] == 'H')
276 && (b[2] == 't' || b[2] == 'T')
277 && (b[3] == 'm' || b[3] == 'M')
278 && (b[4] == 'l' || b[4] == 'L'))
279 || (b[0] == '<'
280 && (b[1] == 'h' || b[1] == 'H')
281 && (b[2] == 'e' || b[2] == 'E')
282 && (b[3] == 'a' || b[3] == 'A')
283 && (b[4] == 'd' || b[4] == 'D'))
284 || (b[0] == '<'
285 && (b[1] == 'b' || b[1] == 'B')
286 && (b[2] == 'o' || b[2] == 'O')
287 && (b[3] == 'd' || b[3] == 'D')
288 && (b[4] == 'y' || b[4] == 'Y'))) return TRUE;
290 return FALSE;
293 static BOOL text_xml_filter(const BYTE *b, DWORD size)
295 if(size < 7)
296 return FALSE;
298 if(b[0] == '<' && b[1] == '?'
299 && (b[2] == 'x' || b[2] == 'X')
300 && (b[3] == 'm' || b[3] == 'M')
301 && (b[4] == 'l' || b[4] == 'L')
302 && b[5] == ' ') return TRUE;
304 return FALSE;
307 static BOOL audio_basic_filter(const BYTE *b, DWORD size)
309 return size > 4
310 && b[0] == '.' && b[1] == 's' && b[2] == 'n' && b[3] == 'd';
313 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
315 return size > 12
316 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
317 && b[8] == 'W' && b[9] == 'A' && b[10] == 'V' && b[11] == 'E';
320 static BOOL image_gif_filter(const BYTE *b, DWORD size)
322 return size >= 6
323 && (b[0] == 'G' || b[0] == 'g')
324 && (b[1] == 'I' || b[1] == 'i')
325 && (b[2] == 'F' || b[2] == 'f')
326 && b[3] == '8'
327 && (b[4] == '7' || b[4] == '9')
328 && (b[5] == 'A' || b[5] == 'a');
331 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
333 return size > 2 && b[0] == 0xff && b[1] == 0xd8;
336 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
338 static const BYTE magic1[] = {0x4d,0x4d,0x00,0x2a};
339 static const BYTE magic2[] = {0x49,0x49,0x2a,0xff};
341 return size >= 4 && (!memcmp(b, magic1, 4) || !memcmp(b, magic2, 4));
344 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
346 static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
347 return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header));
350 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
352 return size >= 14
353 && b[0] == 0x42 && b[1] == 0x4d
354 && *(const DWORD *)(b+6) == 0;
357 static BOOL video_avi_filter(const BYTE *b, DWORD size)
359 return size > 12
360 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
361 && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20;
364 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
366 return size > 4
367 && !b[0] && !b[1] && b[2] == 0x01
368 && (b[3] == 0xb3 || b[3] == 0xba);
371 static BOOL application_postscript_filter(const BYTE *b, DWORD size)
373 return size > 2 && b[0] == '%' && b[1] == '!';
376 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
378 return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
381 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
383 return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
386 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
388 return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
391 static BOOL application_java_filter(const BYTE *b, DWORD size)
393 return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
396 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
398 return size > 2 && b[0] == 'M' && b[1] == 'Z';
401 static inline BOOL is_text_plain_char(BYTE b)
403 if(b < 0x20 && b != '\n' && b != '\r' && b != '\t')
404 return FALSE;
405 return TRUE;
408 static BOOL text_plain_filter(const BYTE *b, DWORD size)
410 const BYTE *ptr;
412 for(ptr = b; ptr < b+size-1; ptr++) {
413 if(!is_text_plain_char(*ptr))
414 return FALSE;
417 return TRUE;
420 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
422 return TRUE;
425 HRESULT find_mime_from_ext(const WCHAR *ext, WCHAR **ret)
427 DWORD res, size;
428 WCHAR mime[64];
429 HKEY hkey;
431 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ext, &hkey);
432 if(res != ERROR_SUCCESS)
433 return HRESULT_FROM_WIN32(res);
435 size = sizeof(mime);
436 res = RegQueryValueExW(hkey, L"Content Type", NULL, NULL, (BYTE*)mime, &size);
437 RegCloseKey(hkey);
438 if(res != ERROR_SUCCESS)
439 return HRESULT_FROM_WIN32(res);
441 TRACE("found MIME %s\n", debugstr_w(mime));
443 *ret = CoTaskMemAlloc(size);
444 memcpy(*ret, mime, size);
445 return S_OK;
448 static HRESULT find_mime_from_url(const WCHAR *url, WCHAR **ret)
450 const WCHAR *ptr, *end_ptr;
451 WCHAR *ext = NULL;
452 HRESULT hres;
454 for(end_ptr = url; *end_ptr; end_ptr++) {
455 if(*end_ptr == '?' || *end_ptr == '#')
456 break;
459 for(ptr = end_ptr; ptr >= url; ptr--) {
460 if(*ptr == '.')
461 break;
464 if(ptr < url)
465 return E_FAIL;
467 if(*end_ptr) {
468 unsigned len = end_ptr-ptr;
470 ext = heap_alloc((len+1)*sizeof(WCHAR));
471 if(!ext)
472 return E_OUTOFMEMORY;
474 memcpy(ext, ptr, len*sizeof(WCHAR));
475 ext[len] = 0;
478 hres = find_mime_from_ext(ext ? ext : ptr, ret);
479 heap_free(ext);
480 return hres;
483 static const WCHAR text_plainW[] = L"text/plain";
484 static const WCHAR app_octetstreamW[] = L"application/octet-stream";
486 static const struct {
487 const WCHAR *mime;
488 BOOL (*filter)(const BYTE *,DWORD);
489 } mime_filters_any_pos[] = {
490 {L"text/html", text_html_filter},
491 {L"text/xml", text_xml_filter}
492 }, mime_filters[] = {
493 {L"text/richtext", text_richtext_filter},
494 /* {L"audio/x-aiff", audio_xaiff_filter}, */
495 {L"audio/basic", audio_basic_filter},
496 {L"audio/wav", audio_wav_filter},
497 {L"image/gif", image_gif_filter},
498 {L"image/pjpeg", image_pjpeg_filter},
499 {L"image/tiff", image_tiff_filter},
500 {L"image/x-png", image_xpng_filter},
501 /* {L"image/x-bitmap", image_xbitmap_filter}, */
502 {L"image/bmp", image_bmp_filter},
503 /* {L"image/x-jg", image_xjg_filter}, */
504 /* {L"image/x-emf", image_xemf_filter}, */
505 /* {L"image/x-wmf", image_xwmf_filter}, */
506 {L"video/avi", video_avi_filter},
507 {L"video/mpeg", video_mpeg_filter},
508 {L"application/postscript", application_postscript_filter},
509 /* {L"application/base64", application_base64_filter}, */
510 /* {L"application/mac-binhex40", application_macbinhex40_filter}, */
511 {L"application/pdf", application_pdf_filter},
512 /* {L"application/x-compressed", application_xcompressed_filter}, */
513 {L"application/x-zip-compressed", application_xzip_filter},
514 {L"application/x-gzip-compressed", application_xgzip_filter},
515 {L"application/java", application_java_filter},
516 {L"application/x-msdownload", application_xmsdownload},
517 {text_plainW, text_plain_filter},
518 {app_octetstreamW, application_octet_stream_filter}
521 static BOOL is_known_mime_type(const WCHAR *mime)
523 unsigned i;
525 for(i=0; i < ARRAY_SIZE(mime_filters_any_pos); i++) {
526 if(!wcscmp(mime, mime_filters_any_pos[i].mime))
527 return TRUE;
530 for(i=0; i < ARRAY_SIZE(mime_filters); i++) {
531 if(!wcscmp(mime, mime_filters[i].mime))
532 return TRUE;
535 return FALSE;
538 static HRESULT find_mime_from_buffer(const BYTE *buf, DWORD size, const WCHAR *proposed_mime, const WCHAR *url, WCHAR **ret_mime)
540 int len, i, any_pos_mime = -1;
541 const WCHAR *ret = NULL;
543 if(!buf || !size) {
544 if(!proposed_mime)
545 return E_FAIL;
547 len = lstrlenW(proposed_mime)+1;
548 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
549 if(!*ret_mime)
550 return E_OUTOFMEMORY;
552 memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR));
553 return S_OK;
556 if(proposed_mime && (!wcscmp(proposed_mime, app_octetstreamW)
557 || !wcscmp(proposed_mime, text_plainW)))
558 proposed_mime = NULL;
560 if(proposed_mime) {
561 ret = proposed_mime;
563 for(i=0; i < ARRAY_SIZE(mime_filters_any_pos); i++) {
564 if(!wcscmp(proposed_mime, mime_filters_any_pos[i].mime)) {
565 any_pos_mime = i;
566 for(len=size; len>0; len--) {
567 if(mime_filters_any_pos[i].filter(buf+size-len, len))
568 break;
570 if(!len)
571 ret = NULL;
572 break;
576 if(i == ARRAY_SIZE(mime_filters_any_pos)) {
577 for(i=0; i < ARRAY_SIZE(mime_filters); i++) {
578 if(!wcscmp(proposed_mime, mime_filters[i].mime)) {
579 if(!mime_filters[i].filter(buf, size))
580 ret = NULL;
581 break;
587 /* Looks like a bug in native implementation, html and xml mimes
588 * are not looked for if none of them was proposed */
589 if(!proposed_mime || any_pos_mime!=-1) {
590 for(len=size; !ret && len>0; len--) {
591 for(i=0; i<ARRAY_SIZE(mime_filters_any_pos); i++) {
592 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
593 ret = mime_filters_any_pos[i].mime;
594 break;
600 i=0;
601 while(!ret) {
602 if(mime_filters[i].filter(buf, size))
603 ret = mime_filters[i].mime;
604 i++;
607 if(any_pos_mime!=-1 && ret==text_plainW)
608 ret = mime_filters_any_pos[any_pos_mime].mime;
609 else if(proposed_mime && ret==app_octetstreamW) {
610 for(len=size; ret==app_octetstreamW && len>0; len--) {
611 if(!is_text_plain_char(buf[size-len]))
612 break;
613 for(i=0; i<ARRAY_SIZE(mime_filters_any_pos); i++) {
614 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
615 ret = text_plainW;
616 break;
621 if(ret == app_octetstreamW)
622 ret = proposed_mime;
625 if(url && (ret == app_octetstreamW || ret == text_plainW)) {
626 WCHAR *url_mime;
627 HRESULT hres;
629 hres = find_mime_from_url(url, &url_mime);
630 if(SUCCEEDED(hres)) {
631 if(!is_known_mime_type(url_mime)) {
632 *ret_mime = url_mime;
633 return hres;
635 CoTaskMemFree(url_mime);
639 TRACE("found %s for %s\n", debugstr_w(ret), debugstr_an((const char*)buf, min(32, size)));
641 len = lstrlenW(ret)+1;
642 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
643 if(!*ret_mime)
644 return E_OUTOFMEMORY;
646 memcpy(*ret_mime, ret, len*sizeof(WCHAR));
647 return S_OK;
650 /***********************************************************************
651 * FindMimeFromData (URLMON.@)
653 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
655 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
656 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
657 LPWSTR* ppwzMimeOut, DWORD dwReserved)
659 TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
660 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
662 if(dwMimeFlags)
663 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
664 if(dwReserved)
665 WARN("dwReserved=%d\n", dwReserved);
667 /* pBC seems to not be used */
669 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
670 return E_INVALIDARG;
672 if(pwzMimeProposed || pBuffer)
673 return find_mime_from_buffer(pBuffer, cbSize, pwzMimeProposed, pwzUrl, ppwzMimeOut);
675 return find_mime_from_url(pwzUrl, ppwzMimeOut);