include: Assorted spelling fixes.
[wine] / dlls / windowscodecs / icnsformat.c
1 /*
2  * Copyright 2010 Damjan Jovanovic
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 #include "wine/port.h"
21
22 #include <stdarg.h>
23
24 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
25 #define GetCurrentProcess GetCurrentProcess_Mac
26 #define GetCurrentThread GetCurrentThread_Mac
27 #define LoadResource LoadResource_Mac
28 #define AnimatePalette AnimatePalette_Mac
29 #define EqualRgn EqualRgn_Mac
30 #define FillRgn FillRgn_Mac
31 #define FrameRgn FrameRgn_Mac
32 #define GetPixel GetPixel_Mac
33 #define InvertRgn InvertRgn_Mac
34 #define LineTo LineTo_Mac
35 #define OffsetRgn OffsetRgn_Mac
36 #define PaintRgn PaintRgn_Mac
37 #define Polygon Polygon_Mac
38 #define ResizePalette ResizePalette_Mac
39 #define SetRectRgn SetRectRgn_Mac
40 #define EqualRect EqualRect_Mac
41 #define FillRect FillRect_Mac
42 #define FrameRect FrameRect_Mac
43 #define GetCursor GetCursor_Mac
44 #define InvertRect InvertRect_Mac
45 #define OffsetRect OffsetRect_Mac
46 #define PtInRect PtInRect_Mac
47 #define SetCursor SetCursor_Mac
48 #define SetRect SetRect_Mac
49 #define ShowCursor ShowCursor_Mac
50 #define UnionRect UnionRect_Mac
51 #include <ApplicationServices/ApplicationServices.h>
52 #undef GetCurrentProcess
53 #undef GetCurrentThread
54 #undef LoadResource
55 #undef AnimatePalette
56 #undef EqualRgn
57 #undef FillRgn
58 #undef FrameRgn
59 #undef GetPixel
60 #undef InvertRgn
61 #undef LineTo
62 #undef OffsetRgn
63 #undef PaintRgn
64 #undef Polygon
65 #undef ResizePalette
66 #undef SetRectRgn
67 #undef EqualRect
68 #undef FillRect
69 #undef FrameRect
70 #undef GetCursor
71 #undef InvertRect
72 #undef OffsetRect
73 #undef PtInRect
74 #undef SetCursor
75 #undef SetRect
76 #undef ShowCursor
77 #undef UnionRect
78 #undef DPRINTF
79 #endif
80
81 #define COBJMACROS
82
83 #include "windef.h"
84 #include "winbase.h"
85 #include "objbase.h"
86 #include "wincodec.h"
87
88 #include "wincodecs_private.h"
89
90 #include "wine/debug.h"
91 #include "wine/library.h"
92
93 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
94
95 #if defined(HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H) && \
96     MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
97
98 typedef struct IcnsEncoder {
99     IWICBitmapEncoder IWICBitmapEncoder_iface;
100     LONG ref;
101     IStream *stream;
102     IconFamilyHandle icns_family;
103     BOOL any_frame_committed;
104     int outstanding_commits;
105     BOOL committed;
106     CRITICAL_SECTION lock;
107 } IcnsEncoder;
108
109 static inline IcnsEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
110 {
111     return CONTAINING_RECORD(iface, IcnsEncoder, IWICBitmapEncoder_iface);
112 }
113
114 typedef struct IcnsFrameEncode {
115     IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
116     IcnsEncoder *encoder;
117     LONG ref;
118     BOOL initialized;
119     UINT size;
120     OSType icns_type;
121     BYTE* icns_image;
122     int lines_written;
123     BOOL committed;
124 } IcnsFrameEncode;
125
126 static inline IcnsFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
127 {
128     return CONTAINING_RECORD(iface, IcnsFrameEncode, IWICBitmapFrameEncode_iface);
129 }
130
131 static HRESULT WINAPI IcnsFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
132     void **ppv)
133 {
134     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
135     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
136
137     if (!ppv) return E_INVALIDARG;
138
139     if (IsEqualIID(&IID_IUnknown, iid) ||
140         IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
141     {
142         *ppv = &This->IWICBitmapFrameEncode_iface;
143     }
144     else
145     {
146         *ppv = NULL;
147         return E_NOINTERFACE;
148     }
149
150     IUnknown_AddRef((IUnknown*)*ppv);
151     return S_OK;
152 }
153
154 static ULONG WINAPI IcnsFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
155 {
156     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
157     ULONG ref = InterlockedIncrement(&This->ref);
158
159     TRACE("(%p) refcount=%u\n", iface, ref);
160
161     return ref;
162 }
163
164 static ULONG WINAPI IcnsFrameEncode_Release(IWICBitmapFrameEncode *iface)
165 {
166     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
167     ULONG ref = InterlockedDecrement(&This->ref);
168
169     TRACE("(%p) refcount=%u\n", iface, ref);
170
171     if (ref == 0)
172     {
173         if (!This->committed)
174         {
175             EnterCriticalSection(&This->encoder->lock);
176             This->encoder->outstanding_commits--;
177             LeaveCriticalSection(&This->encoder->lock);
178         }
179         if (This->icns_image != NULL)
180             HeapFree(GetProcessHeap(), 0, This->icns_image);
181
182         IUnknown_Release((IUnknown*)This->encoder);
183         HeapFree(GetProcessHeap(), 0, This);
184     }
185
186     return ref;
187 }
188
189 static HRESULT WINAPI IcnsFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
190     IPropertyBag2 *pIEncoderOptions)
191 {
192     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
193     HRESULT hr = S_OK;
194
195     TRACE("(%p,%p)\n", iface, pIEncoderOptions);
196
197     EnterCriticalSection(&This->encoder->lock);
198
199     if (This->initialized)
200     {
201         hr = WINCODEC_ERR_WRONGSTATE;
202         goto end;
203     }
204     This->initialized = TRUE;
205
206 end:
207     LeaveCriticalSection(&This->encoder->lock);
208     return hr;
209 }
210
211 static HRESULT WINAPI IcnsFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
212     UINT uiWidth, UINT uiHeight)
213 {
214     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
215     HRESULT hr = S_OK;
216
217     TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
218
219     EnterCriticalSection(&This->encoder->lock);
220
221     if (!This->initialized || This->icns_image)
222     {
223         hr = WINCODEC_ERR_WRONGSTATE;
224         goto end;
225     }
226
227     if (uiWidth != uiHeight)
228     {
229         WARN("cannot generate ICNS icon from %dx%d image\n", uiWidth, uiHeight);
230         hr = E_INVALIDARG;
231         goto end;
232     }
233
234     switch (uiWidth)
235     {
236         case 16:
237         case 32:
238         case 48:
239         case 128:
240         case 256:
241         case 512:
242             break;
243         default:
244             WARN("cannot generate ICNS icon from %dx%d image\n", This->size, This->size);
245             hr = E_INVALIDARG;
246             goto end;
247     }
248
249     This->size = uiWidth;
250
251 end:
252     LeaveCriticalSection(&This->encoder->lock);
253     return hr;
254 }
255
256 static HRESULT WINAPI IcnsFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
257     double dpiX, double dpiY)
258 {
259     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
260     HRESULT hr = S_OK;
261
262     TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
263
264     EnterCriticalSection(&This->encoder->lock);
265
266     if (!This->initialized || This->icns_image)
267     {
268         hr = WINCODEC_ERR_WRONGSTATE;
269         goto end;
270     }
271
272 end:
273     LeaveCriticalSection(&This->encoder->lock);
274     return S_OK;
275 }
276
277 static HRESULT WINAPI IcnsFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
278     WICPixelFormatGUID *pPixelFormat)
279 {
280     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
281     HRESULT hr = S_OK;
282
283     TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
284
285     EnterCriticalSection(&This->encoder->lock);
286
287     if (!This->initialized || This->icns_image)
288     {
289         hr = WINCODEC_ERR_WRONGSTATE;
290         goto end;
291     }
292
293     memcpy(pPixelFormat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));
294
295 end:
296     LeaveCriticalSection(&This->encoder->lock);
297     return S_OK;
298 }
299
300 static HRESULT WINAPI IcnsFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface,
301     UINT cCount, IWICColorContext **ppIColorContext)
302 {
303     FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
304     return E_NOTIMPL;
305 }
306
307 static HRESULT WINAPI IcnsFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
308     IWICPalette *pIPalette)
309 {
310     FIXME("(%p,%p): stub\n", iface, pIPalette);
311     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
312 }
313
314 static HRESULT WINAPI IcnsFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
315     IWICBitmapSource *pIThumbnail)
316 {
317     FIXME("(%p,%p): stub\n", iface, pIThumbnail);
318     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
319 }
320
321 static HRESULT WINAPI IcnsFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
322     UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
323 {
324     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
325     HRESULT hr = S_OK;
326     UINT i;
327
328     TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
329
330     EnterCriticalSection(&This->encoder->lock);
331
332     if (!This->initialized || !This->size)
333     {
334         hr = WINCODEC_ERR_WRONGSTATE;
335         goto end;
336     }
337     if (lineCount == 0 || lineCount + This->lines_written > This->size)
338     {
339         hr = E_INVALIDARG;
340         goto end;
341     }
342
343     if (!This->icns_image)
344     {
345         switch (This->size)
346         {
347             case 16:  This->icns_type = kIconServices16PixelDataARGB;  break;
348             case 32:  This->icns_type = kIconServices32PixelDataARGB;  break;
349             case 48:  This->icns_type = kIconServices48PixelDataARGB;  break;
350             case 128: This->icns_type = kIconServices128PixelDataARGB; break;
351             case 256: This->icns_type = kIconServices256PixelDataARGB; break;
352             case 512: This->icns_type = kIconServices512PixelDataARGB; break;
353             default:
354                 WARN("cannot generate ICNS icon from %dx%d image\n", This->size, This->size);
355                 hr = E_INVALIDARG;
356                 goto end;
357         }
358         This->icns_image = HeapAlloc(GetProcessHeap(), 0, This->size * This->size * 4);
359         if (!This->icns_image)
360         {
361             WARN("failed to allocate image buffer\n");
362             hr = E_FAIL;
363             goto end;
364         }
365     }
366
367     for (i = 0; i < lineCount; i++)
368     {
369         BYTE *src_row, *dst_row;
370         UINT j;
371         src_row = pbPixels + cbStride * i;
372         dst_row = This->icns_image + (This->lines_written + i)*(This->size*4);
373         /* swap bgr -> rgb */
374         for (j = 0; j < This->size*4; j += 4)
375         {
376             dst_row[j] = src_row[j+3];
377             dst_row[j+1] = src_row[j+2];
378             dst_row[j+2] = src_row[j+1];
379             dst_row[j+3] = src_row[j];
380         }
381     }
382     This->lines_written += lineCount;
383
384 end:
385     LeaveCriticalSection(&This->encoder->lock);
386     return hr;
387 }
388
389 static HRESULT WINAPI IcnsFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
390     IWICBitmapSource *pIBitmapSource, WICRect *prc)
391 {
392     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
393     HRESULT hr;
394     WICRect rc;
395     WICPixelFormatGUID guid;
396     UINT stride;
397     BYTE *pixeldata = NULL;
398
399     TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc);
400
401     if (!This->initialized || !This->size)
402     {
403         hr = WINCODEC_ERR_WRONGSTATE;
404         goto end;
405     }
406
407     hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
408     if (FAILED(hr))
409         goto end;
410     if (!IsEqualGUID(&guid, &GUID_WICPixelFormat32bppBGRA))
411     {
412         FIXME("format %s unsupported, could use WICConvertBitmapSource to convert\n", debugstr_guid(&guid));
413         hr = E_FAIL;
414         goto end;
415     }
416
417     if (!prc)
418     {
419         UINT width, height;
420         hr = IWICBitmapSource_GetSize(pIBitmapSource, &width, &height);
421         if (FAILED(hr))
422             goto end;
423         rc.X = 0;
424         rc.Y = 0;
425         rc.Width = width;
426         rc.Height = height;
427         prc = &rc;
428     }
429
430     if (prc->Width != This->size)
431     {
432         hr = E_INVALIDARG;
433         goto end;
434     }
435
436     stride = (32 * This->size + 7)/8;
437     pixeldata = HeapAlloc(GetProcessHeap(), 0, stride * prc->Height);
438     if (!pixeldata)
439     {
440         hr = E_OUTOFMEMORY;
441         goto end;
442     }
443
444     hr = IWICBitmapSource_CopyPixels(pIBitmapSource, prc, stride,
445         stride*prc->Height, pixeldata);
446     if (SUCCEEDED(hr))
447     {
448         hr = IWICBitmapFrameEncode_WritePixels(iface, prc->Height, stride,
449             stride*prc->Height, pixeldata);
450     }
451
452 end:
453     HeapFree(GetProcessHeap(), 0, pixeldata);
454     return hr;
455 }
456
457 static HRESULT WINAPI IcnsFrameEncode_Commit(IWICBitmapFrameEncode *iface)
458 {
459     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
460     Handle handle;
461     OSErr ret;
462     HRESULT hr = S_OK;
463
464     TRACE("(%p): stub\n", iface);
465
466     EnterCriticalSection(&This->encoder->lock);
467
468     if (!This->icns_image || This->lines_written != This->size || This->committed)
469     {
470         hr = WINCODEC_ERR_WRONGSTATE;
471         goto end;
472     }
473
474     ret = PtrToHand(This->icns_image, &handle, This->size * This->size * 4);
475     if (ret != noErr || !handle)
476     {
477         WARN("PtrToHand failed with error %d\n", ret);
478         hr = E_FAIL;
479         goto end;
480     }
481
482     ret = SetIconFamilyData(This->encoder->icns_family, This->icns_type, handle);
483     DisposeHandle(handle);
484
485     if (ret != noErr)
486         {
487         WARN("SetIconFamilyData failed for image with error %d\n", ret);
488         hr = E_FAIL;
489         goto end;
490         }
491
492     This->committed = TRUE;
493     This->encoder->any_frame_committed = TRUE;
494     This->encoder->outstanding_commits--;
495
496 end:
497     LeaveCriticalSection(&This->encoder->lock);
498     return hr;
499 }
500
501 static HRESULT WINAPI IcnsFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
502     IWICMetadataQueryWriter **ppIMetadataQueryWriter)
503 {
504     FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
505     return E_NOTIMPL;
506 }
507
508 static const IWICBitmapFrameEncodeVtbl IcnsEncoder_FrameVtbl = {
509     IcnsFrameEncode_QueryInterface,
510     IcnsFrameEncode_AddRef,
511     IcnsFrameEncode_Release,
512     IcnsFrameEncode_Initialize,
513     IcnsFrameEncode_SetSize,
514     IcnsFrameEncode_SetResolution,
515     IcnsFrameEncode_SetPixelFormat,
516     IcnsFrameEncode_SetColorContexts,
517     IcnsFrameEncode_SetPalette,
518     IcnsFrameEncode_SetThumbnail,
519     IcnsFrameEncode_WritePixels,
520     IcnsFrameEncode_WriteSource,
521     IcnsFrameEncode_Commit,
522     IcnsFrameEncode_GetMetadataQueryWriter
523 };
524
525 static HRESULT WINAPI IcnsEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
526     void **ppv)
527 {
528     IcnsEncoder *This = impl_from_IWICBitmapEncoder(iface);
529     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
530
531     if (!ppv) return E_INVALIDARG;
532
533     if (IsEqualIID(&IID_IUnknown, iid) ||
534         IsEqualIID(&IID_IWICBitmapEncoder, iid))
535     {
536         *ppv = This;
537     }
538     else
539     {
540         *ppv = NULL;
541         return E_NOINTERFACE;
542     }
543
544     IUnknown_AddRef((IUnknown*)*ppv);
545     return S_OK;
546 }
547
548 static ULONG WINAPI IcnsEncoder_AddRef(IWICBitmapEncoder *iface)
549 {
550     IcnsEncoder *This = impl_from_IWICBitmapEncoder(iface);
551     ULONG ref = InterlockedIncrement(&This->ref);
552
553     TRACE("(%p) refcount=%u\n", iface, ref);
554
555     return ref;
556 }
557
558 static ULONG WINAPI IcnsEncoder_Release(IWICBitmapEncoder *iface)
559 {
560     IcnsEncoder *This = impl_from_IWICBitmapEncoder(iface);
561     ULONG ref = InterlockedDecrement(&This->ref);
562
563     TRACE("(%p) refcount=%u\n", iface, ref);
564
565     if (ref == 0)
566     {
567         This->lock.DebugInfo->Spare[0] = 0;
568         DeleteCriticalSection(&This->lock);
569         if (This->icns_family)
570             DisposeHandle((Handle)This->icns_family);
571         if (This->stream)
572             IStream_Release(This->stream);
573         HeapFree(GetProcessHeap(), 0, This);
574     }
575
576     return ref;
577 }
578
579 static HRESULT WINAPI IcnsEncoder_Initialize(IWICBitmapEncoder *iface,
580     IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
581 {
582     IcnsEncoder *This = impl_from_IWICBitmapEncoder(iface);
583     HRESULT hr = S_OK;
584
585     TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
586
587     EnterCriticalSection(&This->lock);
588
589     if (This->icns_family)
590     {
591         hr = WINCODEC_ERR_WRONGSTATE;
592         goto end;
593     }
594     This->icns_family = (IconFamilyHandle)NewHandle(0);
595     if (!This->icns_family)
596     {
597         WARN("error creating icns family\n");
598         hr = E_FAIL;
599         goto end;
600     }
601     IStream_AddRef(pIStream);
602     This->stream = pIStream;
603
604 end:
605     LeaveCriticalSection(&This->lock);
606
607     return hr;
608 }
609
610 static HRESULT WINAPI IcnsEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
611     GUID *pguidContainerFormat)
612 {
613     FIXME("(%p,%s): stub\n", iface, debugstr_guid(pguidContainerFormat));
614     return E_NOTIMPL;
615 }
616
617 static HRESULT WINAPI IcnsEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
618     IWICBitmapEncoderInfo **ppIEncoderInfo)
619 {
620     FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo);
621     return E_NOTIMPL;
622 }
623
624 static HRESULT WINAPI IcnsEncoder_SetColorContexts(IWICBitmapEncoder *iface,
625     UINT cCount, IWICColorContext **ppIColorContext)
626 {
627     FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
628     return E_NOTIMPL;
629 }
630
631 static HRESULT WINAPI IcnsEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette)
632 {
633     TRACE("(%p,%p)\n", iface, pIPalette);
634     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
635 }
636
637 static HRESULT WINAPI IcnsEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
638 {
639     TRACE("(%p,%p)\n", iface, pIThumbnail);
640     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
641 }
642
643 static HRESULT WINAPI IcnsEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
644 {
645     TRACE("(%p,%p)\n", iface, pIPreview);
646     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
647 }
648
649 static HRESULT WINAPI IcnsEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
650     IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
651 {
652     IcnsEncoder *This = impl_from_IWICBitmapEncoder(iface);
653     HRESULT hr = S_OK;
654     IcnsFrameEncode *frameEncode = NULL;
655
656     TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
657
658     EnterCriticalSection(&This->lock);
659
660     if (!This->icns_family)
661     {
662         hr = WINCODEC_ERR_NOTINITIALIZED;
663         goto end;
664     }
665
666     hr = CreatePropertyBag2(ppIEncoderOptions);
667     if (FAILED(hr))
668         goto end;
669
670     frameEncode = HeapAlloc(GetProcessHeap(), 0, sizeof(IcnsFrameEncode));
671     if (frameEncode == NULL)
672     {
673         hr = E_OUTOFMEMORY;
674         goto end;
675     }
676     frameEncode->IWICBitmapFrameEncode_iface.lpVtbl = &IcnsEncoder_FrameVtbl;
677     frameEncode->encoder = This;
678     frameEncode->ref = 1;
679     frameEncode->initialized = FALSE;
680     frameEncode->size = 0;
681     frameEncode->icns_image = NULL;
682     frameEncode->lines_written = 0;
683     frameEncode->committed = FALSE;
684     *ppIFrameEncode = &frameEncode->IWICBitmapFrameEncode_iface;
685     This->outstanding_commits++;
686     IUnknown_AddRef((IUnknown*)This);
687
688 end:
689     LeaveCriticalSection(&This->lock);
690
691     return hr;
692 }
693
694 static HRESULT WINAPI IcnsEncoder_Commit(IWICBitmapEncoder *iface)
695 {
696     IcnsEncoder *This = impl_from_IWICBitmapEncoder(iface);
697     size_t buffer_size;
698     HRESULT hr = S_OK;
699     ULONG byteswritten;
700
701     TRACE("(%p)\n", iface);
702
703     EnterCriticalSection(&This->lock);
704
705     if (!This->any_frame_committed || This->outstanding_commits > 0 || This->committed)
706     {
707         hr = WINCODEC_ERR_WRONGSTATE;
708         goto end;
709     }
710
711     buffer_size = GetHandleSize((Handle)This->icns_family);
712     hr = IStream_Write(This->stream, *This->icns_family, buffer_size, &byteswritten);
713     if (FAILED(hr) || byteswritten != buffer_size)
714     {
715         WARN("writing file failed, hr = 0x%08X\n", hr);
716         hr = E_FAIL;
717         goto end;
718     }
719
720     This->committed = TRUE;
721
722 end:
723     LeaveCriticalSection(&This->lock);
724     return hr;
725 }
726
727 static HRESULT WINAPI IcnsEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
728     IWICMetadataQueryWriter **ppIMetadataQueryWriter)
729 {
730     FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
731     return E_NOTIMPL;
732 }
733
734 static const IWICBitmapEncoderVtbl IcnsEncoder_Vtbl = {
735     IcnsEncoder_QueryInterface,
736     IcnsEncoder_AddRef,
737     IcnsEncoder_Release,
738     IcnsEncoder_Initialize,
739     IcnsEncoder_GetContainerFormat,
740     IcnsEncoder_GetEncoderInfo,
741     IcnsEncoder_SetColorContexts,
742     IcnsEncoder_SetPalette,
743     IcnsEncoder_SetThumbnail,
744     IcnsEncoder_SetPreview,
745     IcnsEncoder_CreateNewFrame,
746     IcnsEncoder_Commit,
747     IcnsEncoder_GetMetadataQueryWriter
748 };
749
750 HRESULT IcnsEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
751 {
752     IcnsEncoder *This;
753     HRESULT ret;
754
755     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
756
757     *ppv = NULL;
758
759     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
760
761     This = HeapAlloc(GetProcessHeap(), 0, sizeof(IcnsEncoder));
762     if (!This) return E_OUTOFMEMORY;
763
764     This->IWICBitmapEncoder_iface.lpVtbl = &IcnsEncoder_Vtbl;
765     This->ref = 1;
766     This->stream = NULL;
767     This->icns_family = NULL;
768     This->any_frame_committed = FALSE;
769     This->outstanding_commits = 0;
770     This->committed = FALSE;
771     InitializeCriticalSection(&This->lock);
772     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IcnsEncoder.lock");
773
774     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
775     IUnknown_Release((IUnknown*)This);
776
777     return ret;
778 }
779
780 #else /* !defined(HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H) ||
781          MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 */
782
783 HRESULT IcnsEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
784 {
785     ERR("Trying to save ICNS picture, but ICNS support is not compiled in.\n");
786     return E_FAIL;
787 }
788
789 #endif