comdlg32: Fix an error in a Catalan resource.
[wine] / dlls / windowscodecs / info.c
1 /*
2  * Copyright 2009 Vincent Povirk 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 "config.h"
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winreg.h"
28 #include "objbase.h"
29 #include "wincodec.h"
30
31 #include "wincodecs_private.h"
32
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
35 #include "wine/list.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
38
39 static WCHAR const pixelformats_keyname[] = {'P','i','x','e','l','F','o','r','m','a','t','s',0};
40
41 typedef struct {
42     const IWICBitmapDecoderInfoVtbl *lpIWICBitmapDecoderInfoVtbl;
43     LONG ref;
44     HKEY classkey;
45     CLSID clsid;
46 } BitmapDecoderInfo;
47
48 static HRESULT WINAPI BitmapDecoderInfo_QueryInterface(IWICBitmapDecoderInfo *iface, REFIID iid,
49     void **ppv)
50 {
51     BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
52     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
53
54     if (!ppv) return E_INVALIDARG;
55
56     if (IsEqualIID(&IID_IUnknown, iid) ||
57         IsEqualIID(&IID_IWICComponentInfo, iid) ||
58         IsEqualIID(&IID_IWICBitmapCodecInfo, iid) ||
59         IsEqualIID(&IID_IWICBitmapDecoderInfo ,iid))
60     {
61         *ppv = This;
62     }
63     else
64     {
65         *ppv = NULL;
66         return E_NOINTERFACE;
67     }
68
69     IUnknown_AddRef((IUnknown*)*ppv);
70     return S_OK;
71 }
72
73 static ULONG WINAPI BitmapDecoderInfo_AddRef(IWICBitmapDecoderInfo *iface)
74 {
75     BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
76     ULONG ref = InterlockedIncrement(&This->ref);
77
78     TRACE("(%p) refcount=%u\n", iface, ref);
79
80     return ref;
81 }
82
83 static ULONG WINAPI BitmapDecoderInfo_Release(IWICBitmapDecoderInfo *iface)
84 {
85     BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
86     ULONG ref = InterlockedDecrement(&This->ref);
87
88     TRACE("(%p) refcount=%u\n", iface, ref);
89
90     if (ref == 0)
91     {
92         RegCloseKey(This->classkey);
93         HeapFree(GetProcessHeap(), 0, This);
94     }
95
96     return ref;
97 }
98
99 static HRESULT WINAPI BitmapDecoderInfo_GetComponentType(IWICBitmapDecoderInfo *iface,
100     WICComponentType *pType)
101 {
102     TRACE("(%p,%p)\n", iface, pType);
103     *pType = WICDecoder;
104     return S_OK;
105 }
106
107 static HRESULT WINAPI BitmapDecoderInfo_GetCLSID(IWICBitmapDecoderInfo *iface, CLSID *pclsid)
108 {
109     FIXME("(%p,%p): stub\n", iface, pclsid);
110     return E_NOTIMPL;
111 }
112
113 static HRESULT WINAPI BitmapDecoderInfo_GetSigningStatus(IWICBitmapDecoderInfo *iface, DWORD *pStatus)
114 {
115     FIXME("(%p,%p): stub\n", iface, pStatus);
116     return E_NOTIMPL;
117 }
118
119 static HRESULT WINAPI BitmapDecoderInfo_GetAuthor(IWICBitmapDecoderInfo *iface, UINT cchAuthor,
120     WCHAR *wzAuthor, UINT *pcchActual)
121 {
122     FIXME("(%p,%u,%p,%p): stub\n", iface, cchAuthor, wzAuthor, pcchActual);
123     return E_NOTIMPL;
124 }
125
126 static HRESULT WINAPI BitmapDecoderInfo_GetVendorGUID(IWICBitmapDecoderInfo *iface, GUID *pguidVendor)
127 {
128     FIXME("(%p,%p): stub\n", iface, pguidVendor);
129     return E_NOTIMPL;
130 }
131
132 static HRESULT WINAPI BitmapDecoderInfo_GetVersion(IWICBitmapDecoderInfo *iface, UINT cchVersion,
133     WCHAR *wzVersion, UINT *pcchActual)
134 {
135     FIXME("(%p,%u,%p,%p): stub\n", iface, cchVersion, wzVersion, pcchActual);
136     return E_NOTIMPL;
137 }
138
139 static HRESULT WINAPI BitmapDecoderInfo_GetSpecVersion(IWICBitmapDecoderInfo *iface, UINT cchSpecVersion,
140     WCHAR *wzSpecVersion, UINT *pcchActual)
141 {
142     FIXME("(%p,%u,%p,%p): stub\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
143     return E_NOTIMPL;
144 }
145
146 static HRESULT WINAPI BitmapDecoderInfo_GetFriendlyName(IWICBitmapDecoderInfo *iface, UINT cchFriendlyName,
147     WCHAR *wzFriendlyName, UINT *pcchActual)
148 {
149     FIXME("(%p,%u,%p,%p): stub\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
150     return E_NOTIMPL;
151 }
152
153 static HRESULT WINAPI BitmapDecoderInfo_GetContainerFormat(IWICBitmapDecoderInfo *iface,
154     GUID *pguidContainerFormat)
155 {
156     FIXME("(%p,%p): stub\n", iface, pguidContainerFormat);
157     return E_NOTIMPL;
158 }
159
160 static HRESULT WINAPI BitmapDecoderInfo_GetPixelFormats(IWICBitmapDecoderInfo *iface,
161     UINT cFormats, GUID *pguidPixelFormats, UINT *pcActual)
162 {
163     FIXME("(%p,%u,%p,%p): stub\n", iface, cFormats, pguidPixelFormats, pcActual);
164     return E_NOTIMPL;
165 }
166
167 static HRESULT WINAPI BitmapDecoderInfo_GetColorManagementVersion(IWICBitmapDecoderInfo *iface,
168     UINT cchColorManagementVersion, WCHAR *wzColorManagementVersion, UINT *pcchActual)
169 {
170     FIXME("(%p,%u,%p,%p): stub\n", iface, cchColorManagementVersion, wzColorManagementVersion, pcchActual);
171     return E_NOTIMPL;
172 }
173
174 static HRESULT WINAPI BitmapDecoderInfo_GetDeviceManufacturer(IWICBitmapDecoderInfo *iface,
175     UINT cchDeviceManufacturer, WCHAR *wzDeviceManufacturer, UINT *pcchActual)
176 {
177     FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceManufacturer, wzDeviceManufacturer, pcchActual);
178     return E_NOTIMPL;
179 }
180
181 static HRESULT WINAPI BitmapDecoderInfo_GetDeviceModels(IWICBitmapDecoderInfo *iface,
182     UINT cchDeviceModels, WCHAR *wzDeviceModels, UINT *pcchActual)
183 {
184     FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceModels, wzDeviceModels, pcchActual);
185     return E_NOTIMPL;
186 }
187
188 static HRESULT WINAPI BitmapDecoderInfo_GetMimeTypes(IWICBitmapDecoderInfo *iface,
189     UINT cchMimeTypes, WCHAR *wzMimeTypes, UINT *pcchActual)
190 {
191     FIXME("(%p,%u,%p,%p): stub\n", iface, cchMimeTypes, wzMimeTypes, pcchActual);
192     return E_NOTIMPL;
193 }
194
195 static HRESULT WINAPI BitmapDecoderInfo_GetFileExtensions(IWICBitmapDecoderInfo *iface,
196     UINT cchFileExtensions, WCHAR *wzFileExtensions, UINT *pcchActual)
197 {
198     FIXME("(%p,%u,%p,%p): stub\n", iface, cchFileExtensions, wzFileExtensions, pcchActual);
199     return E_NOTIMPL;
200 }
201
202 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportAnimation(IWICBitmapDecoderInfo *iface,
203     BOOL *pfSupportAnimation)
204 {
205     FIXME("(%p,%p): stub\n", iface, pfSupportAnimation);
206     return E_NOTIMPL;
207 }
208
209 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportChromaKey(IWICBitmapDecoderInfo *iface,
210     BOOL *pfSupportChromaKey)
211 {
212     FIXME("(%p,%p): stub\n", iface, pfSupportChromaKey);
213     return E_NOTIMPL;
214 }
215
216 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportLossless(IWICBitmapDecoderInfo *iface,
217     BOOL *pfSupportLossless)
218 {
219     FIXME("(%p,%p): stub\n", iface, pfSupportLossless);
220     return E_NOTIMPL;
221 }
222
223 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportMultiframe(IWICBitmapDecoderInfo *iface,
224     BOOL *pfSupportMultiframe)
225 {
226     FIXME("(%p,%p): stub\n", iface, pfSupportMultiframe);
227     return E_NOTIMPL;
228 }
229
230 static HRESULT WINAPI BitmapDecoderInfo_MatchesMimeType(IWICBitmapDecoderInfo *iface,
231     LPCWSTR wzMimeType, BOOL *pfMatches)
232 {
233     FIXME("(%p,%s,%p): stub\n", iface, debugstr_w(wzMimeType), pfMatches);
234     return E_NOTIMPL;
235 }
236
237 static HRESULT WINAPI BitmapDecoderInfo_GetPatterns(IWICBitmapDecoderInfo *iface,
238     UINT cbSizePatterns, WICBitmapPattern *pPatterns, UINT *pcPatterns, UINT *pcbPatternsActual)
239 {
240     BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
241     UINT pattern_count=0, patterns_size=0;
242     WCHAR subkeyname[11];
243     LONG res;
244     HKEY patternskey, patternkey;
245     static const WCHAR uintformatW[] = {'%','u',0};
246     static const WCHAR patternsW[] = {'P','a','t','t','e','r','n','s',0};
247     static const WCHAR positionW[] = {'P','o','s','i','t','i','o','n',0};
248     static const WCHAR lengthW[] = {'L','e','n','g','t','h',0};
249     static const WCHAR patternW[] = {'P','a','t','t','e','r','n',0};
250     static const WCHAR maskW[] = {'M','a','s','k',0};
251     static const WCHAR endofstreamW[] = {'E','n','d','O','f','S','t','r','e','a','m',0};
252     HRESULT hr=S_OK;
253     UINT i;
254     BYTE *bPatterns=(BYTE*)pPatterns;
255     DWORD length, valuesize;
256
257     TRACE("(%p,%i,%p,%p,%p)\n", iface, cbSizePatterns, pPatterns, pcPatterns, pcbPatternsActual);
258
259     res = RegOpenKeyExW(This->classkey, patternsW, 0, KEY_READ, &patternskey);
260     if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
261
262     res = RegQueryInfoKeyW(patternskey, NULL, NULL, NULL, &pattern_count, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
263     if (res == ERROR_SUCCESS)
264     {
265         patterns_size = pattern_count * sizeof(WICBitmapPattern);
266
267         for (i=0; i<pattern_count; i++)
268         {
269             snprintfW(subkeyname, 11, uintformatW, i);
270             res = RegOpenKeyExW(patternskey, subkeyname, 0, KEY_READ, &patternkey);
271             if (res == ERROR_SUCCESS)
272             {
273                 valuesize = sizeof(ULONG);
274                 res = RegGetValueW(patternkey, NULL, lengthW, RRF_RT_DWORD, NULL,
275                     &length, &valuesize);
276                 patterns_size += length*2;
277
278                 if ((cbSizePatterns >= patterns_size) && (res == ERROR_SUCCESS))
279                 {
280                     pPatterns[i].Length = length;
281
282                     pPatterns[i].EndOfStream = 0;
283                     valuesize = sizeof(BOOL);
284                     RegGetValueW(patternkey, NULL, endofstreamW, RRF_RT_DWORD, NULL,
285                         &pPatterns[i].EndOfStream, &valuesize);
286
287                     pPatterns[i].Position.QuadPart = 0;
288                     valuesize = sizeof(ULARGE_INTEGER);
289                     res = RegGetValueW(patternkey, NULL, positionW, RRF_RT_DWORD|RRF_RT_QWORD, NULL,
290                         &pPatterns[i].Position, &valuesize);
291
292                     if (res == ERROR_SUCCESS)
293                     {
294                         pPatterns[i].Pattern = bPatterns+patterns_size-length*2;
295                         valuesize = length;
296                         res = RegGetValueW(patternkey, NULL, patternW, RRF_RT_REG_BINARY, NULL,
297                             pPatterns[i].Pattern, &valuesize);
298                     }
299
300                     if (res == ERROR_SUCCESS)
301                     {
302                         pPatterns[i].Mask = bPatterns+patterns_size-length;
303                         valuesize = length;
304                         res = RegGetValueW(patternkey, NULL, maskW, RRF_RT_REG_BINARY, NULL,
305                             pPatterns[i].Mask, &valuesize);
306                     }
307                 }
308
309                 RegCloseKey(patternkey);
310             }
311             if (res != ERROR_SUCCESS)
312             {
313                 hr = HRESULT_FROM_WIN32(res);
314                 break;
315             }
316         }
317     }
318     else hr = HRESULT_FROM_WIN32(res);
319
320     RegCloseKey(patternskey);
321
322     if (hr == S_OK)
323     {
324         *pcPatterns = pattern_count;
325         *pcbPatternsActual = patterns_size;
326         if (pPatterns && cbSizePatterns < patterns_size)
327             hr = WINCODEC_ERR_INSUFFICIENTBUFFER;
328     }
329
330     return hr;
331 }
332
333 static HRESULT WINAPI BitmapDecoderInfo_MatchesPattern(IWICBitmapDecoderInfo *iface,
334     IStream *pIStream, BOOL *pfMatches)
335 {
336     WICBitmapPattern *patterns;
337     UINT pattern_count=0, patterns_size=0;
338     HRESULT hr;
339     int i, pos;
340     BYTE *data=NULL;
341     ULONG datasize=0;
342     ULONG bytesread;
343     LARGE_INTEGER seekpos;
344
345     TRACE("(%p,%p,%p)\n", iface, pIStream, pfMatches);
346
347     hr = BitmapDecoderInfo_GetPatterns(iface, 0, NULL, &pattern_count, &patterns_size);
348     if (FAILED(hr)) return hr;
349
350     patterns = HeapAlloc(GetProcessHeap(), 0, patterns_size);
351     if (!patterns) return E_OUTOFMEMORY;
352
353     hr = BitmapDecoderInfo_GetPatterns(iface, patterns_size, patterns, &pattern_count, &patterns_size);
354     if (FAILED(hr)) goto end;
355
356     for (i=0; i<pattern_count; i++)
357     {
358         if (datasize < patterns[i].Length)
359         {
360             HeapFree(GetProcessHeap(), 0, data);
361             datasize = patterns[i].Length;
362             data = HeapAlloc(GetProcessHeap(), 0, patterns[i].Length);
363             if (!data)
364             {
365                 hr = E_OUTOFMEMORY;
366                 break;
367             }
368         }
369
370         if (patterns[i].EndOfStream)
371             seekpos.QuadPart = -patterns[i].Position.QuadPart;
372         else
373             seekpos.QuadPart = patterns[i].Position.QuadPart;
374         hr = IStream_Seek(pIStream, seekpos, patterns[i].EndOfStream ? STREAM_SEEK_END : STREAM_SEEK_SET, NULL);
375         if (hr == STG_E_INVALIDFUNCTION) continue; /* before start of stream */
376         if (FAILED(hr)) break;
377
378         hr = IStream_Read(pIStream, data, patterns[i].Length, &bytesread);
379         if (hr == S_FALSE || (hr == S_OK && bytesread != patterns[i].Length)) /* past end of stream */
380             continue;
381         if (FAILED(hr)) break;
382
383         for (pos=0; pos<patterns[i].Length; pos++)
384         {
385             if ((data[pos] & patterns[i].Mask[pos]) != patterns[i].Pattern[pos])
386                 break;
387         }
388         if (pos == patterns[i].Length) /* matches pattern */
389         {
390             hr = S_OK;
391             *pfMatches = TRUE;
392             break;
393         }
394     }
395
396     if (i == pattern_count) /* does not match any pattern */
397     {
398         hr = S_OK;
399         *pfMatches = FALSE;
400     }
401
402 end:
403     HeapFree(GetProcessHeap(), 0, patterns);
404     HeapFree(GetProcessHeap(), 0, data);
405
406     return hr;
407 }
408
409 static HRESULT WINAPI BitmapDecoderInfo_CreateInstance(IWICBitmapDecoderInfo *iface,
410     IWICBitmapDecoder **ppIBitmapDecoder)
411 {
412     BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
413
414     TRACE("(%p,%p)\n", iface, ppIBitmapDecoder);
415
416     return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER,
417         &IID_IWICBitmapDecoder, (void**)ppIBitmapDecoder);
418 }
419
420 static const IWICBitmapDecoderInfoVtbl BitmapDecoderInfo_Vtbl = {
421     BitmapDecoderInfo_QueryInterface,
422     BitmapDecoderInfo_AddRef,
423     BitmapDecoderInfo_Release,
424     BitmapDecoderInfo_GetComponentType,
425     BitmapDecoderInfo_GetCLSID,
426     BitmapDecoderInfo_GetSigningStatus,
427     BitmapDecoderInfo_GetAuthor,
428     BitmapDecoderInfo_GetVendorGUID,
429     BitmapDecoderInfo_GetVersion,
430     BitmapDecoderInfo_GetSpecVersion,
431     BitmapDecoderInfo_GetFriendlyName,
432     BitmapDecoderInfo_GetContainerFormat,
433     BitmapDecoderInfo_GetPixelFormats,
434     BitmapDecoderInfo_GetColorManagementVersion,
435     BitmapDecoderInfo_GetDeviceManufacturer,
436     BitmapDecoderInfo_GetDeviceModels,
437     BitmapDecoderInfo_GetMimeTypes,
438     BitmapDecoderInfo_GetFileExtensions,
439     BitmapDecoderInfo_DoesSupportAnimation,
440     BitmapDecoderInfo_DoesSupportChromaKey,
441     BitmapDecoderInfo_DoesSupportLossless,
442     BitmapDecoderInfo_DoesSupportMultiframe,
443     BitmapDecoderInfo_MatchesMimeType,
444     BitmapDecoderInfo_GetPatterns,
445     BitmapDecoderInfo_MatchesPattern,
446     BitmapDecoderInfo_CreateInstance
447 };
448
449 static HRESULT BitmapDecoderInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
450 {
451     BitmapDecoderInfo *This;
452
453     This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapDecoderInfo));
454     if (!This)
455     {
456         RegCloseKey(classkey);
457         return E_OUTOFMEMORY;
458     }
459
460     This->lpIWICBitmapDecoderInfoVtbl = &BitmapDecoderInfo_Vtbl;
461     This->ref = 1;
462     This->classkey = classkey;
463     memcpy(&This->clsid, clsid, sizeof(CLSID));
464
465     *ppIInfo = (IWICComponentInfo*)This;
466     return S_OK;
467 }
468
469 typedef struct {
470     const IWICFormatConverterInfoVtbl *lpIWICFormatConverterInfoVtbl;
471     LONG ref;
472     HKEY classkey;
473     CLSID clsid;
474 } FormatConverterInfo;
475
476 static HRESULT WINAPI FormatConverterInfo_QueryInterface(IWICFormatConverterInfo *iface, REFIID iid,
477     void **ppv)
478 {
479     FormatConverterInfo *This = (FormatConverterInfo*)iface;
480     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
481
482     if (!ppv) return E_INVALIDARG;
483
484     if (IsEqualIID(&IID_IUnknown, iid) ||
485         IsEqualIID(&IID_IWICComponentInfo, iid) ||
486         IsEqualIID(&IID_IWICFormatConverterInfo ,iid))
487     {
488         *ppv = This;
489     }
490     else
491     {
492         *ppv = NULL;
493         return E_NOINTERFACE;
494     }
495
496     IUnknown_AddRef((IUnknown*)*ppv);
497     return S_OK;
498 }
499
500 static ULONG WINAPI FormatConverterInfo_AddRef(IWICFormatConverterInfo *iface)
501 {
502     FormatConverterInfo *This = (FormatConverterInfo*)iface;
503     ULONG ref = InterlockedIncrement(&This->ref);
504
505     TRACE("(%p) refcount=%u\n", iface, ref);
506
507     return ref;
508 }
509
510 static ULONG WINAPI FormatConverterInfo_Release(IWICFormatConverterInfo *iface)
511 {
512     FormatConverterInfo *This = (FormatConverterInfo*)iface;
513     ULONG ref = InterlockedDecrement(&This->ref);
514
515     TRACE("(%p) refcount=%u\n", iface, ref);
516
517     if (ref == 0)
518     {
519         RegCloseKey(This->classkey);
520         HeapFree(GetProcessHeap(), 0, This);
521     }
522
523     return ref;
524 }
525
526 static HRESULT WINAPI FormatConverterInfo_GetComponentType(IWICFormatConverterInfo *iface,
527     WICComponentType *pType)
528 {
529     TRACE("(%p,%p)\n", iface, pType);
530     *pType = WICPixelFormatConverter;
531     return S_OK;
532 }
533
534 static HRESULT WINAPI FormatConverterInfo_GetCLSID(IWICFormatConverterInfo *iface, CLSID *pclsid)
535 {
536     FIXME("(%p,%p): stub\n", iface, pclsid);
537     return E_NOTIMPL;
538 }
539
540 static HRESULT WINAPI FormatConverterInfo_GetSigningStatus(IWICFormatConverterInfo *iface, DWORD *pStatus)
541 {
542     FIXME("(%p,%p): stub\n", iface, pStatus);
543     return E_NOTIMPL;
544 }
545
546 static HRESULT WINAPI FormatConverterInfo_GetAuthor(IWICFormatConverterInfo *iface, UINT cchAuthor,
547     WCHAR *wzAuthor, UINT *pcchActual)
548 {
549     FIXME("(%p,%u,%p,%p): stub\n", iface, cchAuthor, wzAuthor, pcchActual);
550     return E_NOTIMPL;
551 }
552
553 static HRESULT WINAPI FormatConverterInfo_GetVendorGUID(IWICFormatConverterInfo *iface, GUID *pguidVendor)
554 {
555     FIXME("(%p,%p): stub\n", iface, pguidVendor);
556     return E_NOTIMPL;
557 }
558
559 static HRESULT WINAPI FormatConverterInfo_GetVersion(IWICFormatConverterInfo *iface, UINT cchVersion,
560     WCHAR *wzVersion, UINT *pcchActual)
561 {
562     FIXME("(%p,%u,%p,%p): stub\n", iface, cchVersion, wzVersion, pcchActual);
563     return E_NOTIMPL;
564 }
565
566 static HRESULT WINAPI FormatConverterInfo_GetSpecVersion(IWICFormatConverterInfo *iface, UINT cchSpecVersion,
567     WCHAR *wzSpecVersion, UINT *pcchActual)
568 {
569     FIXME("(%p,%u,%p,%p): stub\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
570     return E_NOTIMPL;
571 }
572
573 static HRESULT WINAPI FormatConverterInfo_GetFriendlyName(IWICFormatConverterInfo *iface, UINT cchFriendlyName,
574     WCHAR *wzFriendlyName, UINT *pcchActual)
575 {
576     FIXME("(%p,%u,%p,%p): stub\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
577     return E_NOTIMPL;
578 }
579
580 static HRESULT WINAPI FormatConverterInfo_GetPixelFormats(IWICFormatConverterInfo *iface,
581     UINT cFormats, GUID *pguidPixelFormats, UINT *pcActual)
582 {
583     FIXME("(%p,%u,%p,%p): stub\n", iface, cFormats, pguidPixelFormats, pcActual);
584     return E_NOTIMPL;
585 }
586
587 static HRESULT WINAPI FormatConverterInfo_CreateInstance(IWICFormatConverterInfo *iface,
588     IWICFormatConverter **ppIFormatConverter)
589 {
590     FormatConverterInfo *This = (FormatConverterInfo*)iface;
591
592     TRACE("(%p,%p)\n", iface, ppIFormatConverter);
593
594     return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER,
595         &IID_IWICFormatConverter, (void**)ppIFormatConverter);
596 }
597
598 static BOOL ConverterSupportsFormat(IWICFormatConverterInfo *iface, const WCHAR *formatguid)
599 {
600     LONG res;
601     FormatConverterInfo *This = (FormatConverterInfo*)iface;
602     HKEY formats_key, guid_key;
603
604     /* Avoid testing using IWICFormatConverter_GetPixelFormats because that
605         would be O(n). A registry test should do better. */
606
607     res = RegOpenKeyExW(This->classkey, pixelformats_keyname, 0, KEY_READ, &formats_key);
608     if (res != ERROR_SUCCESS) return FALSE;
609
610     res = RegOpenKeyExW(formats_key, formatguid, 0, KEY_READ, &guid_key);
611     if (res == ERROR_SUCCESS) RegCloseKey(guid_key);
612
613     RegCloseKey(formats_key);
614
615     return (res == ERROR_SUCCESS);
616 }
617
618 static const IWICFormatConverterInfoVtbl FormatConverterInfo_Vtbl = {
619     FormatConverterInfo_QueryInterface,
620     FormatConverterInfo_AddRef,
621     FormatConverterInfo_Release,
622     FormatConverterInfo_GetComponentType,
623     FormatConverterInfo_GetCLSID,
624     FormatConverterInfo_GetSigningStatus,
625     FormatConverterInfo_GetAuthor,
626     FormatConverterInfo_GetVendorGUID,
627     FormatConverterInfo_GetVersion,
628     FormatConverterInfo_GetSpecVersion,
629     FormatConverterInfo_GetFriendlyName,
630     FormatConverterInfo_GetPixelFormats,
631     FormatConverterInfo_CreateInstance
632 };
633
634 static HRESULT FormatConverterInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
635 {
636     FormatConverterInfo *This;
637
638     This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverterInfo));
639     if (!This)
640     {
641         RegCloseKey(classkey);
642         return E_OUTOFMEMORY;
643     }
644
645     This->lpIWICFormatConverterInfoVtbl = &FormatConverterInfo_Vtbl;
646     This->ref = 1;
647     This->classkey = classkey;
648     memcpy(&This->clsid, clsid, sizeof(CLSID));
649
650     *ppIInfo = (IWICComponentInfo*)This;
651     return S_OK;
652 }
653
654 static WCHAR const clsid_keyname[] = {'C','L','S','I','D',0};
655 static WCHAR const instance_keyname[] = {'I','n','s','t','a','n','c','e',0};
656
657 struct category {
658     WICComponentType type;
659     const GUID *catid;
660     HRESULT (*constructor)(HKEY,REFCLSID,IWICComponentInfo**);
661 };
662
663 static const struct category categories[] = {
664     {WICDecoder, &CATID_WICBitmapDecoders, BitmapDecoderInfo_Constructor},
665     {WICPixelFormatConverter, &CATID_WICFormatConverters, FormatConverterInfo_Constructor},
666     {0}
667 };
668
669 HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo)
670 {
671     HKEY clsidkey;
672     HKEY classkey;
673     HKEY catidkey;
674     HKEY instancekey;
675     WCHAR guidstring[39];
676     LONG res;
677     const struct category *category;
678     int found=0;
679     HRESULT hr;
680
681     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, KEY_READ, &clsidkey);
682     if (res != ERROR_SUCCESS)
683         return HRESULT_FROM_WIN32(res);
684
685     for (category=categories; category->type; category++)
686     {
687         StringFromGUID2(category->catid, guidstring, 39);
688         res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &catidkey);
689         if (res == ERROR_SUCCESS)
690         {
691             res = RegOpenKeyExW(catidkey, instance_keyname, 0, KEY_READ, &instancekey);
692             if (res == ERROR_SUCCESS)
693             {
694                 StringFromGUID2(clsid, guidstring, 39);
695                 res = RegOpenKeyExW(instancekey, guidstring, 0, KEY_READ, &classkey);
696                 if (res == ERROR_SUCCESS)
697                 {
698                     RegCloseKey(classkey);
699                     found = 1;
700                 }
701                 RegCloseKey(instancekey);
702             }
703             RegCloseKey(catidkey);
704         }
705         if (found) break;
706     }
707
708     if (found)
709     {
710         res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &classkey);
711         if (res == ERROR_SUCCESS)
712             hr = category->constructor(classkey, clsid, ppIInfo);
713         else
714             hr = HRESULT_FROM_WIN32(res);
715     }
716     else
717         hr = E_FAIL;
718
719     RegCloseKey(clsidkey);
720
721     return hr;
722 }
723
724 typedef struct {
725     const IEnumUnknownVtbl *IEnumUnknown_Vtbl;
726     LONG ref;
727     struct list objects;
728     struct list *cursor;
729     CRITICAL_SECTION lock; /* Must be held when reading or writing cursor */
730 } ComponentEnum;
731
732 typedef struct {
733     struct list entry;
734     IUnknown *unk;
735 } ComponentEnumItem;
736
737 static const IEnumUnknownVtbl ComponentEnumVtbl;
738
739 static HRESULT WINAPI ComponentEnum_QueryInterface(IEnumUnknown *iface, REFIID iid,
740     void **ppv)
741 {
742     ComponentEnum *This = (ComponentEnum*)iface;
743     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
744
745     if (!ppv) return E_INVALIDARG;
746
747     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IEnumUnknown, iid))
748     {
749         *ppv = This;
750     }
751     else
752     {
753         *ppv = NULL;
754         return E_NOINTERFACE;
755     }
756
757     IUnknown_AddRef((IUnknown*)*ppv);
758     return S_OK;
759 }
760
761 static ULONG WINAPI ComponentEnum_AddRef(IEnumUnknown *iface)
762 {
763     ComponentEnum *This = (ComponentEnum*)iface;
764     ULONG ref = InterlockedIncrement(&This->ref);
765
766     TRACE("(%p) refcount=%u\n", iface, ref);
767
768     return ref;
769 }
770
771 static ULONG WINAPI ComponentEnum_Release(IEnumUnknown *iface)
772 {
773     ComponentEnum *This = (ComponentEnum*)iface;
774     ULONG ref = InterlockedDecrement(&This->ref);
775     ComponentEnumItem *cursor, *cursor2;
776
777     TRACE("(%p) refcount=%u\n", iface, ref);
778
779     if (ref == 0)
780     {
781         LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->objects, ComponentEnumItem, entry)
782         {
783             IUnknown_Release(cursor->unk);
784             list_remove(&cursor->entry);
785             HeapFree(GetProcessHeap(), 0, cursor);
786         }
787         This->lock.DebugInfo->Spare[0] = 0;
788         DeleteCriticalSection(&This->lock);
789         HeapFree(GetProcessHeap(), 0, This);
790     }
791
792     return ref;
793 }
794
795 static HRESULT WINAPI ComponentEnum_Next(IEnumUnknown *iface, ULONG celt,
796     IUnknown **rgelt, ULONG *pceltFetched)
797 {
798     ComponentEnum *This = (ComponentEnum*)iface;
799     int num_fetched=0;
800     ComponentEnumItem *item;
801     HRESULT hr=S_OK;
802
803     TRACE("(%p,%u,%p,%p)\n", iface, celt, rgelt, pceltFetched);
804
805     EnterCriticalSection(&This->lock);
806     while (num_fetched<celt)
807     {
808         if (!This->cursor)
809         {
810             hr = S_FALSE;
811             break;
812         }
813         item = LIST_ENTRY(This->cursor, ComponentEnumItem, entry);
814         IUnknown_AddRef(item->unk);
815         rgelt[num_fetched] = item->unk;
816         num_fetched++;
817         This->cursor = list_next(&This->objects, This->cursor);
818     }
819     LeaveCriticalSection(&This->lock);
820     if (pceltFetched)
821         *pceltFetched = num_fetched;
822     return hr;
823 }
824
825 static HRESULT WINAPI ComponentEnum_Skip(IEnumUnknown *iface, ULONG celt)
826 {
827     ComponentEnum *This = (ComponentEnum*)iface;
828     int i;
829     HRESULT hr=S_OK;
830
831     TRACE("(%p,%u)\n", iface, celt);
832
833     EnterCriticalSection(&This->lock);
834     for (i=0; i<celt; i++)
835     {
836         if (!This->cursor)
837         {
838             hr = S_FALSE;
839             break;
840         }
841         This->cursor = list_next(&This->objects, This->cursor);
842     }
843     LeaveCriticalSection(&This->lock);
844     return hr;
845 }
846
847 static HRESULT WINAPI ComponentEnum_Reset(IEnumUnknown *iface)
848 {
849     ComponentEnum *This = (ComponentEnum*)iface;
850
851     TRACE("(%p)\n", iface);
852
853     EnterCriticalSection(&This->lock);
854     This->cursor = list_head(&This->objects);
855     LeaveCriticalSection(&This->lock);
856     return S_OK;
857 }
858
859 static HRESULT WINAPI ComponentEnum_Clone(IEnumUnknown *iface, IEnumUnknown **ppenum)
860 {
861     ComponentEnum *This = (ComponentEnum*)iface;
862     ComponentEnum *new_enum;
863     ComponentEnumItem *old_item, *new_item;
864     HRESULT ret=S_OK;
865     struct list *old_cursor;
866
867     new_enum = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnum));
868     if (!new_enum)
869     {
870         *ppenum = NULL;
871         return E_OUTOFMEMORY;
872     }
873
874     new_enum->IEnumUnknown_Vtbl = &ComponentEnumVtbl;
875     new_enum->ref = 1;
876     new_enum->cursor = NULL;
877     list_init(&new_enum->objects);
878     InitializeCriticalSection(&new_enum->lock);
879     new_enum->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ComponentEnum.lock");
880
881     EnterCriticalSection(&This->lock);
882     old_cursor = This->cursor;
883     LeaveCriticalSection(&This->lock);
884
885     LIST_FOR_EACH_ENTRY(old_item, &This->objects, ComponentEnumItem, entry)
886     {
887         new_item = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnumItem));
888         if (!new_item)
889         {
890             ret = E_OUTOFMEMORY;
891             break;
892         }
893         new_item->unk = old_item->unk;
894         list_add_tail(&new_enum->objects, &new_item->entry);
895         IUnknown_AddRef(new_item->unk);
896         if (&old_item->entry == old_cursor) new_enum->cursor = &new_item->entry;
897     }
898
899     if (FAILED(ret))
900     {
901         IUnknown_Release((IUnknown*)new_enum);
902         *ppenum = NULL;
903     }
904     else
905         *ppenum = (IEnumUnknown*)new_enum;
906
907     return ret;
908 }
909
910 static const IEnumUnknownVtbl ComponentEnumVtbl = {
911     ComponentEnum_QueryInterface,
912     ComponentEnum_AddRef,
913     ComponentEnum_Release,
914     ComponentEnum_Next,
915     ComponentEnum_Skip,
916     ComponentEnum_Reset,
917     ComponentEnum_Clone
918 };
919
920 HRESULT CreateComponentEnumerator(DWORD componentTypes, DWORD options, IEnumUnknown **ppIEnumUnknown)
921 {
922     ComponentEnum *This;
923     ComponentEnumItem *item;
924     const struct category *category;
925     HKEY clsidkey, catidkey, instancekey;
926     WCHAR guidstring[39];
927     LONG res;
928     int i;
929     HRESULT hr=S_OK;
930     CLSID clsid;
931
932     if (options) FIXME("ignoring flags %x\n", options);
933
934     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, KEY_READ, &clsidkey);
935     if (res != ERROR_SUCCESS)
936         return HRESULT_FROM_WIN32(res);
937
938     This = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnum));
939     if (!This)
940     {
941         RegCloseKey(clsidkey);
942         return E_OUTOFMEMORY;
943     }
944
945     This->IEnumUnknown_Vtbl = &ComponentEnumVtbl;
946     This->ref = 1;
947     list_init(&This->objects);
948     InitializeCriticalSection(&This->lock);
949     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ComponentEnum.lock");
950
951     for (category=categories; category->type && hr == S_OK; category++)
952     {
953         if ((category->type & componentTypes) == 0) continue;
954         StringFromGUID2(category->catid, guidstring, 39);
955         res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &catidkey);
956         if (res == ERROR_SUCCESS)
957         {
958             res = RegOpenKeyExW(catidkey, instance_keyname, 0, KEY_READ, &instancekey);
959             if (res == ERROR_SUCCESS)
960             {
961                 i=0;
962                 for (;;i++)
963                 {
964                     DWORD guidstring_size = 39;
965                     res = RegEnumKeyExW(instancekey, i, guidstring, &guidstring_size, NULL, NULL, NULL, NULL);
966                     if (res != ERROR_SUCCESS) break;
967
968                     item = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnumItem));
969                     if (!item) { hr = E_OUTOFMEMORY; break; }
970
971                     hr = CLSIDFromString(guidstring, &clsid);
972                     if (SUCCEEDED(hr))
973                     {
974                         hr = CreateComponentInfo(&clsid, (IWICComponentInfo**)&item->unk);
975                         if (SUCCEEDED(hr))
976                             list_add_tail(&This->objects, &item->entry);
977                     }
978
979                     if (FAILED(hr))
980                     {
981                         HeapFree(GetProcessHeap(), 0, item);
982                         hr = S_OK;
983                     }
984                 }
985                 RegCloseKey(instancekey);
986             }
987             RegCloseKey(catidkey);
988         }
989         if (res != ERROR_SUCCESS && res != ERROR_NO_MORE_ITEMS)
990             hr = HRESULT_FROM_WIN32(res);
991     }
992     RegCloseKey(clsidkey);
993
994     if (SUCCEEDED(hr))
995     {
996         IEnumUnknown_Reset((IEnumUnknown*)This);
997         *ppIEnumUnknown = (IEnumUnknown*)This;
998     }
999     else
1000     {
1001         *ppIEnumUnknown = NULL;
1002         IUnknown_Release((IUnknown*)This);
1003     }
1004
1005     return hr;
1006 }
1007
1008 HRESULT WINAPI WICConvertBitmapSource(REFWICPixelFormatGUID dstFormat, IWICBitmapSource *pISrc, IWICBitmapSource **ppIDst)
1009 {
1010     HRESULT res;
1011     IEnumUnknown *enumconverters;
1012     IUnknown *unkconverterinfo;
1013     IWICFormatConverterInfo *converterinfo=NULL;
1014     IWICFormatConverter *converter=NULL;
1015     GUID srcFormat;
1016     WCHAR srcformatstr[39], dstformatstr[39];
1017     BOOL canconvert;
1018     ULONG num_fetched;
1019
1020     res = IWICBitmapSource_GetPixelFormat(pISrc, &srcFormat);
1021     if (FAILED(res)) return res;
1022
1023     if (IsEqualGUID(&srcFormat, dstFormat))
1024     {
1025         IWICBitmapSource_AddRef(pISrc);
1026         *ppIDst = pISrc;
1027         return S_OK;
1028     }
1029
1030     StringFromGUID2(&srcFormat, srcformatstr, 39);
1031     StringFromGUID2(dstFormat, dstformatstr, 39);
1032
1033     res = CreateComponentEnumerator(WICPixelFormatConverter, 0, &enumconverters);
1034     if (FAILED(res)) return res;
1035
1036     while (!converter)
1037     {
1038         res = IEnumUnknown_Next(enumconverters, 1, &unkconverterinfo, &num_fetched);
1039
1040         if (res == S_OK)
1041         {
1042             res = IUnknown_QueryInterface(unkconverterinfo, &IID_IWICFormatConverterInfo, (void**)&converterinfo);
1043
1044             if (SUCCEEDED(res))
1045             {
1046                 canconvert = ConverterSupportsFormat(converterinfo, srcformatstr);
1047
1048                 if (canconvert)
1049                     canconvert = ConverterSupportsFormat(converterinfo, dstformatstr);
1050
1051                 if (canconvert)
1052                 {
1053                     res = IWICFormatConverterInfo_CreateInstance(converterinfo, &converter);
1054
1055                     if (SUCCEEDED(res))
1056                         res = IWICFormatConverter_CanConvert(converter, &srcFormat, dstFormat, &canconvert);
1057
1058                     if (SUCCEEDED(res) && canconvert)
1059                         res = IWICFormatConverter_Initialize(converter, pISrc, dstFormat, WICBitmapDitherTypeNone,
1060                             NULL, 0.0, WICBitmapPaletteTypeCustom);
1061
1062                     if (FAILED(res) || !canconvert)
1063                     {
1064                         if (converter)
1065                         {
1066                             IWICFormatConverter_Release(converter);
1067                             converter = NULL;
1068                         }
1069                         res = S_OK;
1070                     }
1071                 }
1072
1073                 IWICFormatConverterInfo_Release(converterinfo);
1074             }
1075
1076             IUnknown_Release(unkconverterinfo);
1077         }
1078         else
1079             break;
1080     }
1081
1082     IEnumUnknown_Release(enumconverters);
1083
1084     if (converter)
1085     {
1086         *ppIDst = (IWICBitmapSource*)converter;
1087         return S_OK;
1088     }
1089     else
1090     {
1091         FIXME("cannot convert %s to %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1092         *ppIDst = NULL;
1093         return WINCODEC_ERR_COMPONENTNOTFOUND;
1094     }
1095 }