Fix merge r65567.
[reactos.git] / dll / win32 / urlmon / mimefilter.c
1 /*
2 * Copyright 2009 Jacek Caban for CodeWeavers
3 *
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.
8 *
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.
13 *
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
17 */
18
19 #include "urlmon_main.h"
20
21 typedef struct {
22 IInternetProtocol IInternetProtocol_iface;
23 IInternetProtocolSink IInternetProtocolSink_iface;
24
25 LONG ref;
26 } MimeFilter;
27
28 static inline MimeFilter *impl_from_IInternetProtocol(IInternetProtocol *iface)
29 {
30 return CONTAINING_RECORD(iface, MimeFilter, IInternetProtocol_iface);
31 }
32
33 static HRESULT WINAPI MimeFilterProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
34 {
35 MimeFilter *This = impl_from_IInternetProtocol(iface);
36
37 *ppv = NULL;
38 if(IsEqualGUID(&IID_IUnknown, riid)) {
39 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
40 *ppv = &This->IInternetProtocol_iface;
41 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
42 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
43 *ppv = &This->IInternetProtocol_iface;
44 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
45 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
46 *ppv = &This->IInternetProtocol_iface;
47 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
48 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
49 *ppv = &This->IInternetProtocolSink_iface;
50 }
51
52 if(*ppv) {
53 IInternetProtocol_AddRef(iface);
54 return S_OK;
55 }
56
57 WARN("not supported interface %s\n", debugstr_guid(riid));
58 return E_NOINTERFACE;
59 }
60
61 static ULONG WINAPI MimeFilterProtocol_AddRef(IInternetProtocol *iface)
62 {
63 MimeFilter *This = impl_from_IInternetProtocol(iface);
64 LONG ref = InterlockedIncrement(&This->ref);
65 TRACE("(%p) ref=%d\n", This, ref);
66 return ref;
67 }
68
69 static ULONG WINAPI MimeFilterProtocol_Release(IInternetProtocol *iface)
70 {
71 MimeFilter *This = impl_from_IInternetProtocol(iface);
72 LONG ref = InterlockedDecrement(&This->ref);
73
74 TRACE("(%p) ref=%d\n", This, ref);
75
76 if(!ref) {
77 heap_free(This);
78
79 URLMON_UnlockModule();
80 }
81
82 return ref;
83 }
84
85 static HRESULT WINAPI MimeFilterProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
86 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
87 DWORD grfPI, HANDLE_PTR dwReserved)
88 {
89 MimeFilter *This = impl_from_IInternetProtocol(iface);
90 FIXME("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
91 pOIBindInfo, grfPI, dwReserved);
92 return E_NOTIMPL;
93 }
94
95 static HRESULT WINAPI MimeFilterProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
96 {
97 MimeFilter *This = impl_from_IInternetProtocol(iface);
98 FIXME("(%p)->(%p)\n", This, pProtocolData);
99 return E_NOTIMPL;
100 }
101
102 static HRESULT WINAPI MimeFilterProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
103 DWORD dwOptions)
104 {
105 MimeFilter *This = impl_from_IInternetProtocol(iface);
106 FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
107 return E_NOTIMPL;
108 }
109
110 static HRESULT WINAPI MimeFilterProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
111 {
112 MimeFilter *This = impl_from_IInternetProtocol(iface);
113 FIXME("(%p)->(%08x)\n", This, dwOptions);
114 return E_NOTIMPL;
115 }
116
117 static HRESULT WINAPI MimeFilterProtocol_Suspend(IInternetProtocol *iface)
118 {
119 MimeFilter *This = impl_from_IInternetProtocol(iface);
120 FIXME("(%p)\n", This);
121 return E_NOTIMPL;
122 }
123
124 static HRESULT WINAPI MimeFilterProtocol_Resume(IInternetProtocol *iface)
125 {
126 MimeFilter *This = impl_from_IInternetProtocol(iface);
127 FIXME("(%p)\n", This);
128 return E_NOTIMPL;
129 }
130
131 static HRESULT WINAPI MimeFilterProtocol_Read(IInternetProtocol *iface, void *pv,
132 ULONG cb, ULONG *pcbRead)
133 {
134 MimeFilter *This = impl_from_IInternetProtocol(iface);
135 FIXME("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
136 return E_NOTIMPL;
137 }
138
139 static HRESULT WINAPI MimeFilterProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
140 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
141 {
142 MimeFilter *This = impl_from_IInternetProtocol(iface);
143 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
144 return E_NOTIMPL;
145 }
146
147 static HRESULT WINAPI MimeFilterProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
148 {
149 MimeFilter *This = impl_from_IInternetProtocol(iface);
150 FIXME("(%p)->(%08x)\n", This, dwOptions);
151 return E_NOTIMPL;
152 }
153
154 static HRESULT WINAPI MimeFilterProtocol_UnlockRequest(IInternetProtocol *iface)
155 {
156 MimeFilter *This = impl_from_IInternetProtocol(iface);
157 FIXME("(%p)\n", This);
158 return E_NOTIMPL;
159 }
160
161 static const IInternetProtocolVtbl MimeFilterProtocolVtbl = {
162 MimeFilterProtocol_QueryInterface,
163 MimeFilterProtocol_AddRef,
164 MimeFilterProtocol_Release,
165 MimeFilterProtocol_Start,
166 MimeFilterProtocol_Continue,
167 MimeFilterProtocol_Abort,
168 MimeFilterProtocol_Terminate,
169 MimeFilterProtocol_Suspend,
170 MimeFilterProtocol_Resume,
171 MimeFilterProtocol_Read,
172 MimeFilterProtocol_Seek,
173 MimeFilterProtocol_LockRequest,
174 MimeFilterProtocol_UnlockRequest
175 };
176
177 static inline MimeFilter *impl_from_IInternetProtocolSink(IInternetProtocolSink *iface)
178 {
179 return CONTAINING_RECORD(iface, MimeFilter, IInternetProtocolSink_iface);
180 }
181
182 static HRESULT WINAPI MimeFilterSink_QueryInterface(IInternetProtocolSink *iface,
183 REFIID riid, void **ppv)
184 {
185 MimeFilter *This = impl_from_IInternetProtocolSink(iface);
186 return IInternetProtocol_QueryInterface(&This->IInternetProtocol_iface, riid, ppv);
187 }
188
189 static ULONG WINAPI MimeFilterSink_AddRef(IInternetProtocolSink *iface)
190 {
191 MimeFilter *This = impl_from_IInternetProtocolSink(iface);
192 return IInternetProtocol_AddRef(&This->IInternetProtocol_iface);
193 }
194
195 static ULONG WINAPI MimeFilterSink_Release(IInternetProtocolSink *iface)
196 {
197 MimeFilter *This = impl_from_IInternetProtocolSink(iface);
198 return IInternetProtocol_Release(&This->IInternetProtocol_iface);
199 }
200
201 static HRESULT WINAPI MimeFilterSink_Switch(IInternetProtocolSink *iface,
202 PROTOCOLDATA *pProtocolData)
203 {
204 MimeFilter *This = impl_from_IInternetProtocolSink(iface);
205 FIXME("(%p)->(%p)\n", This, pProtocolData);
206 return E_NOTIMPL;
207 }
208
209 static HRESULT WINAPI MimeFilterSink_ReportProgress(IInternetProtocolSink *iface,
210 ULONG ulStatusCode, LPCWSTR szStatusText)
211 {
212 MimeFilter *This = impl_from_IInternetProtocolSink(iface);
213 FIXME("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
214 return E_NOTIMPL;
215 }
216
217 static HRESULT WINAPI MimeFilterSink_ReportData(IInternetProtocolSink *iface,
218 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
219 {
220 MimeFilter *This = impl_from_IInternetProtocolSink(iface);
221 FIXME("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
222 return E_NOTIMPL;
223 }
224
225 static HRESULT WINAPI MimeFilterSink_ReportResult(IInternetProtocolSink *iface,
226 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
227 {
228 MimeFilter *This = impl_from_IInternetProtocolSink(iface);
229 FIXME("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
230 return E_NOTIMPL;
231 }
232
233 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
234 MimeFilterSink_QueryInterface,
235 MimeFilterSink_AddRef,
236 MimeFilterSink_Release,
237 MimeFilterSink_Switch,
238 MimeFilterSink_ReportProgress,
239 MimeFilterSink_ReportData,
240 MimeFilterSink_ReportResult
241 };
242
243 HRESULT MimeFilter_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
244 {
245 MimeFilter *ret;
246
247 TRACE("(%p %p)\n", pUnkOuter, ppobj);
248
249 URLMON_LockModule();
250
251 ret = heap_alloc_zero(sizeof(MimeFilter));
252
253 ret->IInternetProtocol_iface.lpVtbl = &MimeFilterProtocolVtbl;
254 ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl;
255 ret->ref = 1;
256
257 *ppobj = &ret->IInternetProtocol_iface;
258 return S_OK;
259 }
260
261 static BOOL text_richtext_filter(const BYTE *b, DWORD size)
262 {
263 return size > 5 && !memcmp(b, "{\\rtf", 5);
264 }
265
266 static BOOL text_html_filter(const BYTE *b, DWORD size)
267 {
268 if(size < 6)
269 return FALSE;
270
271 if((b[0] == '<'
272 && (b[1] == 'h' || b[1] == 'H')
273 && (b[2] == 't' || b[2] == 'T')
274 && (b[3] == 'm' || b[3] == 'M')
275 && (b[4] == 'l' || b[4] == 'L'))
276 || (b[0] == '<'
277 && (b[1] == 'h' || b[1] == 'H')
278 && (b[2] == 'e' || b[2] == 'E')
279 && (b[3] == 'a' || b[3] == 'A')
280 && (b[4] == 'd' || b[4] == 'D'))
281 || (b[0] == '<'
282 && (b[1] == 'b' || b[1] == 'B')
283 && (b[2] == 'o' || b[2] == 'O')
284 && (b[3] == 'd' || b[3] == 'D')
285 && (b[4] == 'y' || b[4] == 'Y'))) return TRUE;
286
287 return FALSE;
288 }
289
290 static BOOL text_xml_filter(const BYTE *b, DWORD size)
291 {
292 if(size < 7)
293 return FALSE;
294
295 if(b[0] == '<' && b[1] == '?'
296 && (b[2] == 'x' || b[2] == 'X')
297 && (b[3] == 'm' || b[3] == 'M')
298 && (b[4] == 'l' || b[4] == 'L')
299 && b[5] == ' ') return TRUE;
300
301 return FALSE;
302 }
303
304 static BOOL audio_basic_filter(const BYTE *b, DWORD size)
305 {
306 return size > 4
307 && b[0] == '.' && b[1] == 's' && b[2] == 'n' && b[3] == 'd';
308 }
309
310 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
311 {
312 return size > 12
313 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
314 && b[8] == 'W' && b[9] == 'A' && b[10] == 'V' && b[11] == 'E';
315 }
316
317 static BOOL image_gif_filter(const BYTE *b, DWORD size)
318 {
319 return size >= 6
320 && (b[0] == 'G' || b[0] == 'g')
321 && (b[1] == 'I' || b[1] == 'i')
322 && (b[2] == 'F' || b[2] == 'f')
323 && b[3] == '8'
324 && (b[4] == '7' || b[4] == '9')
325 && (b[5] == 'A' || b[5] == 'a');
326 }
327
328 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
329 {
330 return size > 2 && b[0] == 0xff && b[1] == 0xd8;
331 }
332
333 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
334 {
335 static const BYTE magic1[] = {0x4d,0x4d,0x00,0x2a};
336 static const BYTE magic2[] = {0x49,0x49,0x2a,0xff};
337
338 return size >= 4 && (!memcmp(b, magic1, 4) || !memcmp(b, magic2, 4));
339 }
340
341 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
342 {
343 static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
344 return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header));
345 }
346
347 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
348 {
349 return size >= 14
350 && b[0] == 0x42 && b[1] == 0x4d
351 && *(const DWORD *)(b+6) == 0;
352 }
353
354 static BOOL video_avi_filter(const BYTE *b, DWORD size)
355 {
356 return size > 12
357 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
358 && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20;
359 }
360
361 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
362 {
363 return size > 4
364 && !b[0] && !b[1] && b[2] == 0x01
365 && (b[3] == 0xb3 || b[3] == 0xba);
366 }
367
368 static BOOL application_postscript_filter(const BYTE *b, DWORD size)
369 {
370 return size > 2 && b[0] == '%' && b[1] == '!';
371 }
372
373 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
374 {
375 return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
376 }
377
378 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
379 {
380 return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
381 }
382
383 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
384 {
385 return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
386 }
387
388 static BOOL application_java_filter(const BYTE *b, DWORD size)
389 {
390 return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
391 }
392
393 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
394 {
395 return size > 2 && b[0] == 'M' && b[1] == 'Z';
396 }
397
398 static inline BOOL is_text_plain_char(BYTE b)
399 {
400 if(b < 0x20 && b != '\n' && b != '\r' && b != '\t')
401 return FALSE;
402 return TRUE;
403 }
404
405 static BOOL text_plain_filter(const BYTE *b, DWORD size)
406 {
407 const BYTE *ptr;
408
409 for(ptr = b; ptr < b+size-1; ptr++) {
410 if(!is_text_plain_char(*ptr))
411 return FALSE;
412 }
413
414 return TRUE;
415 }
416
417 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
418 {
419 return TRUE;
420 }
421
422 static HRESULT find_mime_from_url(const WCHAR *url, WCHAR **ret)
423 {
424 const WCHAR *ptr;
425 DWORD res, size;
426 WCHAR mime[64];
427 HKEY hkey;
428
429 static const WCHAR content_typeW[] = {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
430
431 ptr = strrchrW(url, '.');
432 if(!ptr)
433 return E_FAIL;
434
435 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
436 if(res != ERROR_SUCCESS)
437 return HRESULT_FROM_WIN32(res);
438
439 size = sizeof(mime);
440 res = RegQueryValueExW(hkey, content_typeW, NULL, NULL, (LPBYTE)mime, &size);
441 RegCloseKey(hkey);
442 if(res != ERROR_SUCCESS)
443 return HRESULT_FROM_WIN32(res);
444
445 TRACE("found MIME %s\n", debugstr_w(mime));
446
447 *ret = CoTaskMemAlloc(size);
448 memcpy(*ret, mime, size);
449 return S_OK;
450 }
451
452 static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0};
453 static const WCHAR text_richtextW[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0};
454 static const WCHAR text_xmlW[] = {'t','e','x','t','/','x','m','l',0};
455 static const WCHAR audio_basicW[] = {'a','u','d','i','o','/','b','a','s','i','c',0};
456 static const WCHAR audio_wavW[] = {'a','u','d','i','o','/','w','a','v',0};
457 static const WCHAR image_gifW[] = {'i','m','a','g','e','/','g','i','f',0};
458 static const WCHAR image_pjpegW[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
459 static const WCHAR image_tiffW[] = {'i','m','a','g','e','/','t','i','f','f',0};
460 static const WCHAR image_xpngW[] = {'i','m','a','g','e','/','x','-','p','n','g',0};
461 static const WCHAR image_bmpW[] = {'i','m','a','g','e','/','b','m','p',0};
462 static const WCHAR video_aviW[] = {'v','i','d','e','o','/','a','v','i',0};
463 static const WCHAR video_mpegW[] = {'v','i','d','e','o','/','m','p','e','g',0};
464 static const WCHAR app_postscriptW[] =
465 {'a','p','p','l','i','c','a','t','i','o','n','/','p','o','s','t','s','c','r','i','p','t',0};
466 static const WCHAR app_pdfW[] = {'a','p','p','l','i','c','a','t','i','o','n','/','p','d','f',0};
467 static const WCHAR app_xzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
468 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
469 static const WCHAR app_xgzipW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
470 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
471 static const WCHAR app_javaW[] = {'a','p','p','l','i','c','a','t','i','o','n','/','j','a','v','a',0};
472 static const WCHAR app_xmsdownloadW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
473 'x','-','m','s','d','o','w','n','l','o','a','d',0};
474 static const WCHAR text_plainW[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
475 static const WCHAR app_octetstreamW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
476 'o','c','t','e','t','-','s','t','r','e','a','m','\0'};
477
478 static const struct {
479 const WCHAR *mime;
480 BOOL (*filter)(const BYTE *,DWORD);
481 } mime_filters_any_pos[] = {
482 {text_htmlW, text_html_filter},
483 {text_xmlW, text_xml_filter}
484 }, mime_filters[] = {
485 {text_richtextW, text_richtext_filter},
486 /* {audio_xaiffW, audio_xaiff_filter}, */
487 {audio_basicW, audio_basic_filter},
488 {audio_wavW, audio_wav_filter},
489 {image_gifW, image_gif_filter},
490 {image_pjpegW, image_pjpeg_filter},
491 {image_tiffW, image_tiff_filter},
492 {image_xpngW, image_xpng_filter},
493 /* {image_xbitmapW, image_xbitmap_filter}, */
494 {image_bmpW, image_bmp_filter},
495 /* {image_xjgW, image_xjg_filter}, */
496 /* {image_xemfW, image_xemf_filter}, */
497 /* {image_xwmfW, image_xwmf_filter}, */
498 {video_aviW, video_avi_filter},
499 {video_mpegW, video_mpeg_filter},
500 {app_postscriptW, application_postscript_filter},
501 /* {app_base64W, application_base64_filter}, */
502 /* {app_macbinhex40W, application_macbinhex40_filter}, */
503 {app_pdfW, application_pdf_filter},
504 /* {app_zcompressedW, application_xcompressed_filter}, */
505 {app_xzipW, application_xzip_filter},
506 {app_xgzipW, application_xgzip_filter},
507 {app_javaW, application_java_filter},
508 {app_xmsdownloadW, application_xmsdownload},
509 {text_plainW, text_plain_filter},
510 {app_octetstreamW, application_octet_stream_filter}
511 };
512
513 static BOOL is_known_mime_type(const WCHAR *mime)
514 {
515 unsigned i;
516
517 for(i=0; i < sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
518 if(!strcmpW(mime, mime_filters_any_pos[i].mime))
519 return TRUE;
520 }
521
522 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
523 if(!strcmpW(mime, mime_filters[i].mime))
524 return TRUE;
525 }
526
527 return FALSE;
528 }
529
530 static HRESULT find_mime_from_buffer(const BYTE *buf, DWORD size, const WCHAR *proposed_mime, const WCHAR *url, WCHAR **ret_mime)
531 {
532 int len, i, any_pos_mime = -1;
533 const WCHAR *ret = NULL;
534
535 if(!buf || !size) {
536 if(!proposed_mime)
537 return E_FAIL;
538
539 len = strlenW(proposed_mime)+1;
540 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
541 if(!*ret_mime)
542 return E_OUTOFMEMORY;
543
544 memcpy(*ret_mime, proposed_mime, len*sizeof(WCHAR));
545 return S_OK;
546 }
547
548 if(proposed_mime && (!strcmpW(proposed_mime, app_octetstreamW)
549 || !strcmpW(proposed_mime, text_plainW)))
550 proposed_mime = NULL;
551
552 if(proposed_mime) {
553 ret = proposed_mime;
554
555 for(i=0; i < sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
556 if(!strcmpW(proposed_mime, mime_filters_any_pos[i].mime)) {
557 any_pos_mime = i;
558 for(len=size; len>0; len--) {
559 if(mime_filters_any_pos[i].filter(buf+size-len, len))
560 break;
561 }
562 if(!len)
563 ret = NULL;
564 break;
565 }
566 }
567
568 if(i == sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos)) {
569 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
570 if(!strcmpW(proposed_mime, mime_filters[i].mime)) {
571 if(!mime_filters[i].filter(buf, size))
572 ret = NULL;
573 break;
574 }
575 }
576 }
577 }
578
579 /* Looks like a bug in native implementation, html and xml mimes
580 * are not looked for if none of them was proposed */
581 if(!proposed_mime || any_pos_mime!=-1) {
582 for(len=size; !ret && len>0; len--) {
583 for(i=0; i<sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
584 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
585 ret = mime_filters_any_pos[i].mime;
586 break;
587 }
588 }
589 }
590 }
591
592 i=0;
593 while(!ret) {
594 if(mime_filters[i].filter(buf, size))
595 ret = mime_filters[i].mime;
596 i++;
597 }
598
599 if(any_pos_mime!=-1 && ret==text_plainW)
600 ret = mime_filters_any_pos[any_pos_mime].mime;
601 else if(proposed_mime && ret==app_octetstreamW) {
602 for(len=size; ret==app_octetstreamW && len>0; len--) {
603 if(!is_text_plain_char(buf[size-len]))
604 break;
605 for(i=0; i<sizeof(mime_filters_any_pos)/sizeof(*mime_filters_any_pos); i++) {
606 if(mime_filters_any_pos[i].filter(buf+size-len, len)) {
607 ret = text_plainW;
608 break;
609 }
610 }
611 }
612
613 if(ret == app_octetstreamW)
614 ret = proposed_mime;
615 }
616
617 if(url && (ret == app_octetstreamW || ret == text_plainW)) {
618 WCHAR *url_mime;
619 HRESULT hres;
620
621 hres = find_mime_from_url(url, &url_mime);
622 if(SUCCEEDED(hres)) {
623 if(!is_known_mime_type(url_mime)) {
624 *ret_mime = url_mime;
625 return hres;
626 }
627 CoTaskMemFree(url_mime);
628 }
629 }
630
631 TRACE("found %s for %s\n", debugstr_w(ret), debugstr_an((const char*)buf, min(32, size)));
632
633 len = strlenW(ret)+1;
634 *ret_mime = CoTaskMemAlloc(len*sizeof(WCHAR));
635 if(!*ret_mime)
636 return E_OUTOFMEMORY;
637
638 memcpy(*ret_mime, ret, len*sizeof(WCHAR));
639 return S_OK;
640 }
641
642 /***********************************************************************
643 * FindMimeFromData (URLMON.@)
644 *
645 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
646 */
647 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
648 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
649 LPWSTR* ppwzMimeOut, DWORD dwReserved)
650 {
651 TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
652 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
653
654 if(dwMimeFlags)
655 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
656 if(dwReserved)
657 WARN("dwReserved=%d\n", dwReserved);
658
659 /* pBC seams to not be used */
660
661 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
662 return E_INVALIDARG;
663
664 if(pwzMimeProposed || pBuffer)
665 return find_mime_from_buffer(pBuffer, cbSize, pwzMimeProposed, pwzUrl, ppwzMimeOut);
666
667 if(pwzUrl)
668 return find_mime_from_url(pwzUrl, ppwzMimeOut);
669
670 return E_FAIL;
671 }