d3d8: Get rid of the format switching code in d3d8_device_CopyRects().
[wine.git] / dlls / urlmon / mimefilter.c
blob55cd2009dc21033620ef3c912209e5f7ae85cd3f
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 static HRESULT find_mime_from_url(const WCHAR *url, WCHAR **ret)
427 const WCHAR *ptr;
428 DWORD res, size;
429 WCHAR mime[64];
430 HKEY hkey;
432 static const WCHAR content_typeW[] = {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
434 ptr = strrchrW(url, '.');
435 if(!ptr)
436 return E_FAIL;
438 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
439 if(res != ERROR_SUCCESS)
440 return HRESULT_FROM_WIN32(res);
442 size = sizeof(mime);
443 res = RegQueryValueExW(hkey, content_typeW, NULL, NULL, (LPBYTE)mime, &size);
444 RegCloseKey(hkey);
445 if(res != ERROR_SUCCESS)
446 return HRESULT_FROM_WIN32(res);
448 TRACE("found MIME %s\n", debugstr_w(mime));
450 *ret = CoTaskMemAlloc(size);
451 memcpy(*ret, mime, size);
452 return S_OK;
455 static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0};
456 static const WCHAR text_richtextW[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0};
457 static const WCHAR text_xmlW[] = {'t','e','x','t','/','x','m','l',0};
458 static const WCHAR audio_basicW[] = {'a','u','d','i','o','/','b','a','s','i','c',0};
459 static const WCHAR audio_wavW[] = {'a','u','d','i','o','/','w','a','v',0};
460 static const WCHAR image_gifW[] = {'i','m','a','g','e','/','g','i','f',0};
461 static const WCHAR image_pjpegW[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
462 static const WCHAR image_tiffW[] = {'i','m','a','g','e','/','t','i','f','f',0};
463 static const WCHAR image_xpngW[] = {'i','m','a','g','e','/','x','-','p','n','g',0};
464 static const WCHAR image_bmpW[] = {'i','m','a','g','e','/','b','m','p',0};
465 static const WCHAR video_aviW[] = {'v','i','d','e','o','/','a','v','i',0};
466 static const WCHAR video_mpegW[] = {'v','i','d','e','o','/','m','p','e','g',0};
467 static const WCHAR app_postscriptW[] =
468 {'a','p','p','l','i','c','a','t','i','o','n','/','p','o','s','t','s','c','r','i','p','t',0};
469 static const WCHAR app_pdfW[] = {'a','p','p','l','i','c','a','t','i','o','n','/','p','d','f',0};
470 static const WCHAR app_xzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
471 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
472 static const WCHAR app_xgzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
473 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
474 static const WCHAR app_javaW[] = {'a','p','p','l','i','c','a','t','i','o','n','/','j','a','v','a',0};
475 static const WCHAR app_xmsdownloadW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
476 'x','-','m','s','d','o','w','n','l','o','a','d',0};
477 static const WCHAR text_plainW[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
478 static const WCHAR app_octetstreamW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
479 'o','c','t','e','t','-','s','t','r','e','a','m','\0'};
481 static const struct {
482 const WCHAR *mime;
483 BOOL (*filter)(const BYTE *,DWORD);
484 } mime_filters_any_pos[] = {
485 {text_htmlW, text_html_filter},
486 {text_xmlW, text_xml_filter}
487 }, mime_filters[] = {
488 {text_richtextW, text_richtext_filter},
489 /* {audio_xaiffW, audio_xaiff_filter}, */
490 {audio_basicW, audio_basic_filter},
491 {audio_wavW, audio_wav_filter},
492 {image_gifW, image_gif_filter},
493 {image_pjpegW, image_pjpeg_filter},
494 {image_tiffW, image_tiff_filter},
495 {image_xpngW, image_xpng_filter},
496 /* {image_xbitmapW, image_xbitmap_filter}, */
497 {image_bmpW, image_bmp_filter},
498 /* {image_xjgW, image_xjg_filter}, */
499 /* {image_xemfW, image_xemf_filter}, */
500 /* {image_xwmfW, image_xwmf_filter}, */
501 {video_aviW, video_avi_filter},
502 {video_mpegW, video_mpeg_filter},
503 {app_postscriptW, application_postscript_filter},
504 /* {app_base64W, application_base64_filter}, */
505 /* {app_macbinhex40W, application_macbinhex40_filter}, */
506 {app_pdfW, application_pdf_filter},
507 /* {app_zcompressedW, application_xcompressed_filter}, */
508 {app_xzipW, application_xzip_filter},
509 {app_xgzipW, application_xgzip_filter},
510 {app_javaW, application_java_filter},
511 {app_xmsdownloadW, application_xmsdownload},
512 {text_plainW, text_plain_filter},
513 {app_octetstreamW, application_octet_stream_filter}
516 static BOOL is_known_mime_type(const WCHAR *mime)
518 unsigned i;
520 for(i=0; i < sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
521 if(!strcmpW(mime, mime_filters_any_pos[i].mime))
522 return TRUE;
525 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
526 if(!strcmpW(mime, mime_filters[i].mime))
527 return TRUE;
530 return FALSE;
533 static HRESULT find_mime_from_buffer(const BYTE *buf, DWORD size, const WCHAR *proposed_mime, const WCHAR *url, WCHAR **ret_mime)
535 int len, i, any_pos_mime = -1;
536 const WCHAR *ret = NULL;
538 if(!buf || !size) {
539 if(!proposed_mime)
540 return E_FAIL;
542 len = strlenW(proposed_mime)+1;
543 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
544 if(!*ret_mime)
545 return E_OUTOFMEMORY;
547 memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR));
548 return S_OK;
551 if(proposed_mime && (!strcmpW(proposed_mime, app_octetstreamW)
552 || !strcmpW(proposed_mime, text_plainW)))
553 proposed_mime = NULL;
555 if(proposed_mime) {
556 ret = proposed_mime;
558 for(i=0; i < sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
559 if(!strcmpW(proposed_mime, mime_filters_any_pos[i].mime)) {
560 any_pos_mime = i;
561 for(len=size; len>0; len--) {
562 if(mime_filters_any_pos[i].filter(buf+size-len, len))
563 break;
565 if(!len)
566 ret = NULL;
567 break;
571 if(i == sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos)) {
572 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
573 if(!strcmpW(proposed_mime, mime_filters[i].mime)) {
574 if(!mime_filters[i].filter(buf, size))
575 ret = NULL;
576 break;
582 /* Looks like a bug in native implementation, html and xml mimes
583 * are not looked for if none of them was proposed */
584 if(!proposed_mime || any_pos_mime!=-1) {
585 for(len=size; !ret && len>0; len--) {
586 for(i=0; i<sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
587 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
588 ret = mime_filters_any_pos[i].mime;
589 break;
595 i=0;
596 while(!ret) {
597 if(mime_filters[i].filter(buf, size))
598 ret = mime_filters[i].mime;
599 i++;
602 if(any_pos_mime!=-1 && ret==text_plainW)
603 ret = mime_filters_any_pos[any_pos_mime].mime;
604 else if(proposed_mime && ret==app_octetstreamW) {
605 for(len=size; ret==app_octetstreamW && len>0; len--) {
606 if(!is_text_plain_char(buf[size-len]))
607 break;
608 for(i=0; i<sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
609 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
610 ret = text_plainW;
611 break;
616 if(ret == app_octetstreamW)
617 ret = proposed_mime;
620 if(url && (ret == app_octetstreamW || ret == text_plainW)) {
621 WCHAR *url_mime;
622 HRESULT hres;
624 hres = find_mime_from_url(url, &url_mime);
625 if(SUCCEEDED(hres)) {
626 if(!is_known_mime_type(url_mime)) {
627 *ret_mime = url_mime;
628 return hres;
630 CoTaskMemFree(url_mime);
634 TRACE("found %s for %s\n", debugstr_w(ret), debugstr_an((const char*)buf, min(32, size)));
636 len = strlenW(ret)+1;
637 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
638 if(!*ret_mime)
639 return E_OUTOFMEMORY;
641 memcpy(*ret_mime, ret, len*sizeof(WCHAR));
642 return S_OK;
645 /***********************************************************************
646 * FindMimeFromData (URLMON.@)
648 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
650 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
651 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
652 LPWSTR* ppwzMimeOut, DWORD dwReserved)
654 TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
655 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
657 if(dwMimeFlags)
658 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
659 if(dwReserved)
660 WARN("dwReserved=%d\n", dwReserved);
662 /* pBC seams to not be used */
664 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
665 return E_INVALIDARG;
667 if(pwzMimeProposed || pBuffer)
668 return find_mime_from_buffer(pBuffer, cbSize, pwzMimeProposed, pwzUrl, ppwzMimeOut);
670 if(pwzUrl)
671 return find_mime_from_url(pwzUrl, ppwzMimeOut);
673 return E_FAIL;