windowscodecs: Implement CopyPalette for the PNG decoder.
[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 } ComponentEnum;
730
731 typedef struct {
732     struct list entry;
733     IUnknown *unk;
734 } ComponentEnumItem;
735
736 static const IEnumUnknownVtbl ComponentEnumVtbl;
737
738 static HRESULT WINAPI ComponentEnum_QueryInterface(IEnumUnknown *iface, REFIID iid,
739     void **ppv)
740 {
741     ComponentEnum *This = (ComponentEnum*)iface;
742     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
743
744     if (!ppv) return E_INVALIDARG;
745
746     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IEnumUnknown, iid))
747     {
748         *ppv = This;
749     }
750     else
751     {
752         *ppv = NULL;
753         return E_NOINTERFACE;
754     }
755
756     IUnknown_AddRef((IUnknown*)*ppv);
757     return S_OK;
758 }
759
760 static ULONG WINAPI ComponentEnum_AddRef(IEnumUnknown *iface)
761 {
762     ComponentEnum *This = (ComponentEnum*)iface;
763     ULONG ref = InterlockedIncrement(&This->ref);
764
765     TRACE("(%p) refcount=%u\n", iface, ref);
766
767     return ref;
768 }
769
770 static ULONG WINAPI ComponentEnum_Release(IEnumUnknown *iface)
771 {
772     ComponentEnum *This = (ComponentEnum*)iface;
773     ULONG ref = InterlockedDecrement(&This->ref);
774     ComponentEnumItem *cursor, *cursor2;
775
776     TRACE("(%p) refcount=%u\n", iface, ref);
777
778     if (ref == 0)
779     {
780         LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->objects, ComponentEnumItem, entry)
781         {
782             IUnknown_Release(cursor->unk);
783             list_remove(&cursor->entry);
784             HeapFree(GetProcessHeap(), 0, cursor);
785         }
786         HeapFree(GetProcessHeap(), 0, This);
787     }
788
789     return ref;
790 }
791
792 static HRESULT WINAPI ComponentEnum_Next(IEnumUnknown *iface, ULONG celt,
793     IUnknown **rgelt, ULONG *pceltFetched)
794 {
795     ComponentEnum *This = (ComponentEnum*)iface;
796     int num_fetched=0;
797     ComponentEnumItem *item;
798
799     TRACE("(%p,%u,%p,%p)\n", iface, celt, rgelt, pceltFetched);
800
801     while (num_fetched<celt)
802     {
803         if (!This->cursor)
804         {
805             *pceltFetched = num_fetched;
806             return S_FALSE;
807         }
808         item = LIST_ENTRY(This->cursor, ComponentEnumItem, entry);
809         IUnknown_AddRef(item->unk);
810         rgelt[num_fetched] = item->unk;
811         num_fetched++;
812         This->cursor = list_next(&This->objects, This->cursor);
813     }
814     *pceltFetched = num_fetched;
815     return S_OK;
816 }
817
818 static HRESULT WINAPI ComponentEnum_Skip(IEnumUnknown *iface, ULONG celt)
819 {
820     ComponentEnum *This = (ComponentEnum*)iface;
821     int i;
822
823     TRACE("(%p,%u)\n", iface, celt);
824
825     for (i=0; i<celt; i++)
826     {
827         if (!This->cursor)
828             return S_FALSE;
829         This->cursor = list_next(&This->objects, This->cursor);
830     }
831     return S_OK;
832 }
833
834 static HRESULT WINAPI ComponentEnum_Reset(IEnumUnknown *iface)
835 {
836     ComponentEnum *This = (ComponentEnum*)iface;
837
838     TRACE("(%p)\n", iface);
839
840     This->cursor = list_head(&This->objects);
841     return S_OK;
842 }
843
844 static HRESULT WINAPI ComponentEnum_Clone(IEnumUnknown *iface, IEnumUnknown **ppenum)
845 {
846     ComponentEnum *This = (ComponentEnum*)iface;
847     ComponentEnum *new_enum;
848     ComponentEnumItem *old_item, *new_item;
849     HRESULT ret=S_OK;
850
851     new_enum = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnum));
852     if (!new_enum)
853     {
854         *ppenum = NULL;
855         return E_OUTOFMEMORY;
856     }
857
858     new_enum->IEnumUnknown_Vtbl = &ComponentEnumVtbl;
859     new_enum->ref = 1;
860     new_enum->cursor = NULL;
861
862     list_init(&new_enum->objects);
863     LIST_FOR_EACH_ENTRY(old_item, &This->objects, ComponentEnumItem, entry)
864     {
865         new_item = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnumItem));
866         if (!new_item)
867         {
868             ret = E_OUTOFMEMORY;
869             break;
870         }
871         new_item->unk = old_item->unk;
872         list_add_tail(&new_enum->objects, &new_item->entry);
873         IUnknown_AddRef(new_item->unk);
874         if (&old_item->entry == This->cursor) new_enum->cursor = &new_item->entry;
875     }
876
877     if (FAILED(ret))
878     {
879         IUnknown_Release((IUnknown*)new_enum);
880         *ppenum = NULL;
881     }
882     else
883         *ppenum = (IEnumUnknown*)new_enum;
884
885     return ret;
886 }
887
888 static const IEnumUnknownVtbl ComponentEnumVtbl = {
889     ComponentEnum_QueryInterface,
890     ComponentEnum_AddRef,
891     ComponentEnum_Release,
892     ComponentEnum_Next,
893     ComponentEnum_Skip,
894     ComponentEnum_Reset,
895     ComponentEnum_Clone
896 };
897
898 HRESULT CreateComponentEnumerator(DWORD componentTypes, DWORD options, IEnumUnknown **ppIEnumUnknown)
899 {
900     ComponentEnum *This;
901     ComponentEnumItem *item;
902     const struct category *category;
903     HKEY clsidkey, catidkey, instancekey;
904     WCHAR guidstring[39];
905     LONG res;
906     int i;
907     HRESULT hr=S_OK;
908     CLSID clsid;
909
910     if (options) FIXME("ignoring flags %x\n", options);
911
912     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, KEY_READ, &clsidkey);
913     if (res != ERROR_SUCCESS)
914         return HRESULT_FROM_WIN32(res);
915
916     This = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnum));
917     if (!This)
918     {
919         RegCloseKey(clsidkey);
920         return E_OUTOFMEMORY;
921     }
922
923     This->IEnumUnknown_Vtbl = &ComponentEnumVtbl;
924     This->ref = 1;
925     list_init(&This->objects);
926
927     for (category=categories; category->type && hr == S_OK; category++)
928     {
929         if ((category->type & componentTypes) == 0) continue;
930         StringFromGUID2(category->catid, guidstring, 39);
931         res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &catidkey);
932         if (res == ERROR_SUCCESS)
933         {
934             res = RegOpenKeyExW(catidkey, instance_keyname, 0, KEY_READ, &instancekey);
935             if (res == ERROR_SUCCESS)
936             {
937                 i=0;
938                 for (;;i++)
939                 {
940                     DWORD guidstring_size = 39;
941                     res = RegEnumKeyExW(instancekey, i, guidstring, &guidstring_size, NULL, NULL, NULL, NULL);
942                     if (res != ERROR_SUCCESS) break;
943
944                     item = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnumItem));
945                     if (!item) { hr = E_OUTOFMEMORY; break; }
946
947                     hr = CLSIDFromString(guidstring, &clsid);
948                     if (SUCCEEDED(hr))
949                     {
950                         hr = CreateComponentInfo(&clsid, (IWICComponentInfo**)&item->unk);
951                         if (SUCCEEDED(hr))
952                             list_add_tail(&This->objects, &item->entry);
953                     }
954
955                     if (!SUCCEEDED(hr))
956                     {
957                         HeapFree(GetProcessHeap(), 0, item);
958                         hr = S_OK;
959                     }
960                 }
961                 RegCloseKey(instancekey);
962             }
963             RegCloseKey(catidkey);
964         }
965         if (res != ERROR_SUCCESS && res != ERROR_NO_MORE_ITEMS)
966             hr = HRESULT_FROM_WIN32(res);
967     }
968     RegCloseKey(clsidkey);
969
970     if (SUCCEEDED(hr))
971     {
972         IEnumUnknown_Reset((IEnumUnknown*)This);
973         *ppIEnumUnknown = (IEnumUnknown*)This;
974     }
975     else
976     {
977         *ppIEnumUnknown = NULL;
978         IUnknown_Release((IUnknown*)This);
979     }
980
981     return hr;
982 }
983
984 HRESULT WINAPI WICConvertBitmapSource(REFWICPixelFormatGUID dstFormat, IWICBitmapSource *pISrc, IWICBitmapSource **ppIDst)
985 {
986     HRESULT res;
987     IEnumUnknown *enumconverters;
988     IUnknown *unkconverterinfo;
989     IWICFormatConverterInfo *converterinfo=NULL;
990     IWICFormatConverter *converter=NULL;
991     GUID srcFormat;
992     WCHAR srcformatstr[39], dstformatstr[39];
993     BOOL canconvert;
994     ULONG num_fetched;
995
996     res = IWICBitmapSource_GetPixelFormat(pISrc, &srcFormat);
997     if (FAILED(res)) return res;
998
999     if (IsEqualGUID(&srcFormat, dstFormat))
1000     {
1001         IWICBitmapSource_AddRef(pISrc);
1002         *ppIDst = pISrc;
1003         return S_OK;
1004     }
1005
1006     StringFromGUID2(&srcFormat, srcformatstr, 39);
1007     StringFromGUID2(dstFormat, dstformatstr, 39);
1008
1009     res = CreateComponentEnumerator(WICPixelFormatConverter, 0, &enumconverters);
1010     if (FAILED(res)) return res;
1011
1012     while (!converter)
1013     {
1014         res = IEnumUnknown_Next(enumconverters, 1, &unkconverterinfo, &num_fetched);
1015
1016         if (res == S_OK)
1017         {
1018             res = IUnknown_QueryInterface(unkconverterinfo, &IID_IWICFormatConverterInfo, (void**)&converterinfo);
1019
1020             if (SUCCEEDED(res))
1021             {
1022                 canconvert = ConverterSupportsFormat(converterinfo, srcformatstr);
1023
1024                 if (canconvert)
1025                     canconvert = ConverterSupportsFormat(converterinfo, dstformatstr);
1026
1027                 if (canconvert)
1028                 {
1029                     res = IWICFormatConverterInfo_CreateInstance(converterinfo, &converter);
1030
1031                     if (SUCCEEDED(res))
1032                         res = IWICFormatConverter_CanConvert(converter, &srcFormat, dstFormat, &canconvert);
1033
1034                     if (SUCCEEDED(res) && canconvert)
1035                         res = IWICFormatConverter_Initialize(converter, pISrc, dstFormat, WICBitmapDitherTypeNone,
1036                             NULL, 0.0, WICBitmapPaletteTypeCustom);
1037
1038                     if (FAILED(res) || !canconvert)
1039                     {
1040                         if (converter)
1041                         {
1042                             IWICFormatConverter_Release(converter);
1043                             converter = NULL;
1044                         }
1045                         res = S_OK;
1046                     }
1047                 }
1048
1049                 IWICFormatConverterInfo_Release(converterinfo);
1050             }
1051
1052             IUnknown_Release(unkconverterinfo);
1053         }
1054         else
1055             break;
1056     }
1057
1058     IEnumUnknown_Release(enumconverters);
1059
1060     if (converter)
1061     {
1062         *ppIDst = (IWICBitmapSource*)converter;
1063         return S_OK;
1064     }
1065     else
1066     {
1067         FIXME("cannot convert %s to %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1068         *ppIDst = NULL;
1069         return WINCODEC_ERR_COMPONENTNOTFOUND;
1070     }
1071 }