xref: /reactos/dll/win32/windowscodecs/decoder.c (revision 197ed01e)
1 /*
2  * Copyright 2020 Esme Povirk
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 <stdarg.h>
20 
21 #define COBJMACROS
22 
23 #include "windef.h"
24 #include "winbase.h"
25 #include "objbase.h"
26 
27 #include "wincodecs_private.h"
28 
29 #include "wine/debug.h"
30 
31 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
32 
33 typedef struct {
34     IWICBitmapDecoder IWICBitmapDecoder_iface;
35     LONG ref;
36     CRITICAL_SECTION lock; /* must be held when stream or decoder is accessed */
37     IStream *stream;
38     struct decoder *decoder;
39     struct decoder_info decoder_info;
40     struct decoder_stat file_info;
41     WICDecodeOptions cache_options;
42 } CommonDecoder;
43 
impl_from_IWICBitmapDecoder(IWICBitmapDecoder * iface)44 static inline CommonDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
45 {
46     return CONTAINING_RECORD(iface, CommonDecoder, IWICBitmapDecoder_iface);
47 }
48 
CommonDecoder_QueryInterface(IWICBitmapDecoder * iface,REFIID iid,void ** ppv)49 static HRESULT WINAPI CommonDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
50     void **ppv)
51 {
52     CommonDecoder *This = impl_from_IWICBitmapDecoder(iface);
53     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
54 
55     if (!ppv) return E_INVALIDARG;
56 
57     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
58     {
59         *ppv = &This->IWICBitmapDecoder_iface;
60     }
61     else
62     {
63         *ppv = NULL;
64         return E_NOINTERFACE;
65     }
66 
67     IUnknown_AddRef((IUnknown*)*ppv);
68     return S_OK;
69 }
70 
CommonDecoder_AddRef(IWICBitmapDecoder * iface)71 static ULONG WINAPI CommonDecoder_AddRef(IWICBitmapDecoder *iface)
72 {
73     CommonDecoder *This = impl_from_IWICBitmapDecoder(iface);
74     ULONG ref = InterlockedIncrement(&This->ref);
75 
76     TRACE("(%p) refcount=%lu\n", iface, ref);
77 
78     return ref;
79 }
80 
CommonDecoder_Release(IWICBitmapDecoder * iface)81 static ULONG WINAPI CommonDecoder_Release(IWICBitmapDecoder *iface)
82 {
83     CommonDecoder *This = impl_from_IWICBitmapDecoder(iface);
84     ULONG ref = InterlockedDecrement(&This->ref);
85 
86     TRACE("(%p) refcount=%lu\n", iface, ref);
87 
88     if (ref == 0)
89     {
90         if (This->stream)
91             IStream_Release(This->stream);
92         This->lock.DebugInfo->Spare[0] = 0;
93         DeleteCriticalSection(&This->lock);
94         decoder_destroy(This->decoder);
95         free(This);
96     }
97 
98     return ref;
99 }
100 
CommonDecoder_QueryCapability(IWICBitmapDecoder * iface,IStream * stream,DWORD * capability)101 static HRESULT WINAPI CommonDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
102     DWORD *capability)
103 {
104     CommonDecoder *This = impl_from_IWICBitmapDecoder(iface);
105     HRESULT hr;
106 
107     TRACE("(%p,%p,%p)\n", iface, stream, capability);
108 
109     if (!stream || !capability) return E_INVALIDARG;
110 
111     hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand);
112     if (hr != S_OK) return hr;
113 
114     *capability = (This->file_info.flags & DECODER_FLAGS_CAPABILITY_MASK);
115     return S_OK;
116 }
117 
CommonDecoder_Initialize(IWICBitmapDecoder * iface,IStream * pIStream,WICDecodeOptions cacheOptions)118 static HRESULT WINAPI CommonDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
119     WICDecodeOptions cacheOptions)
120 {
121     CommonDecoder *This = impl_from_IWICBitmapDecoder(iface);
122     HRESULT hr=S_OK;
123 
124     TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
125 
126     EnterCriticalSection(&This->lock);
127 
128     if (This->stream)
129         hr = WINCODEC_ERR_WRONGSTATE;
130 
131     if (SUCCEEDED(hr))
132         hr = decoder_initialize(This->decoder, pIStream, &This->file_info);
133 
134     if (SUCCEEDED(hr))
135     {
136         This->cache_options = cacheOptions;
137         This->stream = pIStream;
138         IStream_AddRef(This->stream);
139     }
140 
141     LeaveCriticalSection(&This->lock);
142 
143     return hr;
144 }
145 
CommonDecoder_GetContainerFormat(IWICBitmapDecoder * iface,GUID * pguidContainerFormat)146 static HRESULT WINAPI CommonDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
147     GUID *pguidContainerFormat)
148 {
149     CommonDecoder *This = impl_from_IWICBitmapDecoder(iface);
150     memcpy(pguidContainerFormat, &This->decoder_info.container_format, sizeof(GUID));
151     return S_OK;
152 }
153 
CommonDecoder_GetDecoderInfo(IWICBitmapDecoder * iface,IWICBitmapDecoderInfo ** ppIDecoderInfo)154 static HRESULT WINAPI CommonDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
155     IWICBitmapDecoderInfo **ppIDecoderInfo)
156 {
157     CommonDecoder *This = impl_from_IWICBitmapDecoder(iface);
158     TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
159 
160     return get_decoder_info(&This->decoder_info.clsid, ppIDecoderInfo);
161 }
162 
CommonDecoder_CopyPalette(IWICBitmapDecoder * iface,IWICPalette * palette)163 static HRESULT WINAPI CommonDecoder_CopyPalette(IWICBitmapDecoder *iface,
164     IWICPalette *palette)
165 {
166     TRACE("(%p,%p)\n", iface, palette);
167     return WINCODEC_ERR_PALETTEUNAVAILABLE;
168 }
169 
CommonDecoder_GetMetadataQueryReader(IWICBitmapDecoder * iface,IWICMetadataQueryReader ** reader)170 static HRESULT WINAPI CommonDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
171     IWICMetadataQueryReader **reader)
172 {
173     TRACE("(%p,%p)\n", iface, reader);
174 
175     if (!reader) return E_INVALIDARG;
176 
177     *reader = NULL;
178     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
179 }
180 
CommonDecoder_GetPreview(IWICBitmapDecoder * iface,IWICBitmapSource ** ppIBitmapSource)181 static HRESULT WINAPI CommonDecoder_GetPreview(IWICBitmapDecoder *iface,
182     IWICBitmapSource **ppIBitmapSource)
183 {
184     TRACE("(%p,%p)\n", iface, ppIBitmapSource);
185 
186     if (!ppIBitmapSource) return E_INVALIDARG;
187 
188     *ppIBitmapSource = NULL;
189     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
190 }
191 
CommonDecoder_GetColorContexts(IWICBitmapDecoder * iface,UINT cCount,IWICColorContext ** ppIColorContexts,UINT * pcActualCount)192 static HRESULT WINAPI CommonDecoder_GetColorContexts(IWICBitmapDecoder *iface,
193     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
194 {
195     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
196     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
197 }
198 
CommonDecoder_GetThumbnail(IWICBitmapDecoder * iface,IWICBitmapSource ** ppIThumbnail)199 static HRESULT WINAPI CommonDecoder_GetThumbnail(IWICBitmapDecoder *iface,
200     IWICBitmapSource **ppIThumbnail)
201 {
202     TRACE("(%p,%p)\n", iface, ppIThumbnail);
203 
204     if (!ppIThumbnail) return E_INVALIDARG;
205 
206     *ppIThumbnail = NULL;
207     return WINCODEC_ERR_CODECNOTHUMBNAIL;
208 }
209 
CommonDecoder_GetFrameCount(IWICBitmapDecoder * iface,UINT * pCount)210 static HRESULT WINAPI CommonDecoder_GetFrameCount(IWICBitmapDecoder *iface,
211     UINT *pCount)
212 {
213     CommonDecoder *This = impl_from_IWICBitmapDecoder(iface);
214     if (!pCount) return E_INVALIDARG;
215 
216     if (This->stream)
217         *pCount = This->file_info.frame_count;
218     else
219         *pCount = 0;
220 
221     return S_OK;
222 }
223 
224 static HRESULT WINAPI CommonDecoder_GetFrame(IWICBitmapDecoder *iface,
225     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame);
226 
227 static const IWICBitmapDecoderVtbl CommonDecoder_Vtbl = {
228     CommonDecoder_QueryInterface,
229     CommonDecoder_AddRef,
230     CommonDecoder_Release,
231     CommonDecoder_QueryCapability,
232     CommonDecoder_Initialize,
233     CommonDecoder_GetContainerFormat,
234     CommonDecoder_GetDecoderInfo,
235     CommonDecoder_CopyPalette,
236     CommonDecoder_GetMetadataQueryReader,
237     CommonDecoder_GetPreview,
238     CommonDecoder_GetColorContexts,
239     CommonDecoder_GetThumbnail,
240     CommonDecoder_GetFrameCount,
241     CommonDecoder_GetFrame
242 };
243 
244 typedef struct {
245     IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
246     IWICMetadataBlockReader IWICMetadataBlockReader_iface;
247     LONG ref;
248     CommonDecoder *parent;
249     DWORD frame;
250     struct decoder_frame decoder_frame;
251     BOOL metadata_initialized;
252     UINT metadata_count;
253     struct decoder_block* metadata_blocks;
254 } CommonDecoderFrame;
255 
impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode * iface)256 static inline CommonDecoderFrame *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
257 {
258     return CONTAINING_RECORD(iface, CommonDecoderFrame, IWICBitmapFrameDecode_iface);
259 }
260 
impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader * iface)261 static inline CommonDecoderFrame *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
262 {
263     return CONTAINING_RECORD(iface, CommonDecoderFrame, IWICMetadataBlockReader_iface);
264 }
265 
CommonDecoderFrame_QueryInterface(IWICBitmapFrameDecode * iface,REFIID iid,void ** ppv)266 static HRESULT WINAPI CommonDecoderFrame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
267     void **ppv)
268 {
269     CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface);
270     if (!ppv) return E_INVALIDARG;
271 
272     if (IsEqualIID(&IID_IUnknown, iid) ||
273         IsEqualIID(&IID_IWICBitmapSource, iid) ||
274         IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
275     {
276         *ppv = &This->IWICBitmapFrameDecode_iface;
277     }
278     else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid) &&
279              (This->parent->file_info.flags & WICBitmapDecoderCapabilityCanEnumerateMetadata))
280     {
281         *ppv = &This->IWICMetadataBlockReader_iface;
282     }
283     else
284     {
285         *ppv = NULL;
286         return E_NOINTERFACE;
287     }
288 
289     IUnknown_AddRef((IUnknown*)*ppv);
290     return S_OK;
291 }
292 
CommonDecoderFrame_AddRef(IWICBitmapFrameDecode * iface)293 static ULONG WINAPI CommonDecoderFrame_AddRef(IWICBitmapFrameDecode *iface)
294 {
295     CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface);
296     ULONG ref = InterlockedIncrement(&This->ref);
297 
298     TRACE("(%p) refcount=%lu\n", iface, ref);
299 
300     return ref;
301 }
302 
CommonDecoderFrame_Release(IWICBitmapFrameDecode * iface)303 static ULONG WINAPI CommonDecoderFrame_Release(IWICBitmapFrameDecode *iface)
304 {
305     CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface);
306     ULONG ref = InterlockedDecrement(&This->ref);
307 
308     TRACE("(%p) refcount=%lu\n", iface, ref);
309 
310     if (ref == 0)
311     {
312         IWICBitmapDecoder_Release(&This->parent->IWICBitmapDecoder_iface);
313         free(This->metadata_blocks);
314         free(This);
315     }
316 
317     return ref;
318 }
319 
CommonDecoderFrame_GetSize(IWICBitmapFrameDecode * iface,UINT * puiWidth,UINT * puiHeight)320 static HRESULT WINAPI CommonDecoderFrame_GetSize(IWICBitmapFrameDecode *iface,
321     UINT *puiWidth, UINT *puiHeight)
322 {
323     CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface);
324 
325     TRACE("(%p,%p,%p)\n", This, puiWidth, puiHeight);
326 
327     if (!puiWidth || !puiHeight)
328         return E_POINTER;
329 
330     *puiWidth = This->decoder_frame.width;
331     *puiHeight = This->decoder_frame.height;
332     return S_OK;
333 }
334 
CommonDecoderFrame_GetPixelFormat(IWICBitmapFrameDecode * iface,WICPixelFormatGUID * pPixelFormat)335 static HRESULT WINAPI CommonDecoderFrame_GetPixelFormat(IWICBitmapFrameDecode *iface,
336     WICPixelFormatGUID *pPixelFormat)
337 {
338     CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface);
339 
340     TRACE("(%p,%p)\n", This, pPixelFormat);
341 
342     if (!pPixelFormat)
343         return E_POINTER;
344 
345     *pPixelFormat = This->decoder_frame.pixel_format;
346     return S_OK;
347 }
348 
CommonDecoderFrame_GetResolution(IWICBitmapFrameDecode * iface,double * pDpiX,double * pDpiY)349 static HRESULT WINAPI CommonDecoderFrame_GetResolution(IWICBitmapFrameDecode *iface,
350     double *pDpiX, double *pDpiY)
351 {
352     CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface);
353 
354     TRACE("(%p,%p,%p)\n", This, pDpiX, pDpiY);
355 
356     if (!pDpiX || !pDpiY)
357         return E_POINTER;
358 
359     *pDpiX = This->decoder_frame.dpix;
360     *pDpiY = This->decoder_frame.dpiy;
361     return S_OK;
362 }
363 
CommonDecoderFrame_CopyPalette(IWICBitmapFrameDecode * iface,IWICPalette * pIPalette)364 static HRESULT WINAPI CommonDecoderFrame_CopyPalette(IWICBitmapFrameDecode *iface,
365     IWICPalette *pIPalette)
366 {
367     CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface);
368     HRESULT hr=S_OK;
369 
370     TRACE("(%p,%p)\n", iface, pIPalette);
371 
372     if (This->decoder_frame.num_colors)
373     {
374         hr = IWICPalette_InitializeCustom(pIPalette, This->decoder_frame.palette, This->decoder_frame.num_colors);
375     }
376     else
377     {
378         hr = WINCODEC_ERR_PALETTEUNAVAILABLE;
379     }
380 
381     return hr;
382 }
383 
CommonDecoderFrame_CopyPixels(IWICBitmapFrameDecode * iface,const WICRect * prc,UINT cbStride,UINT cbBufferSize,BYTE * pbBuffer)384 static HRESULT WINAPI CommonDecoderFrame_CopyPixels(IWICBitmapFrameDecode *iface,
385     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
386 {
387     CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface);
388     HRESULT hr;
389     UINT bytesperrow;
390     WICRect rect;
391 
392     TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
393 
394     if (!pbBuffer)
395         return E_POINTER;
396 
397     if (!prc)
398     {
399         rect.X = 0;
400         rect.Y = 0;
401         rect.Width = This->decoder_frame.width;
402         rect.Height = This->decoder_frame.height;
403         prc = &rect;
404     }
405     else
406     {
407         if (prc->X < 0 || prc->Y < 0 ||
408             prc->X+prc->Width > This->decoder_frame.width ||
409             prc->Y+prc->Height > This->decoder_frame.height)
410             return E_INVALIDARG;
411     }
412 
413     bytesperrow = ((This->decoder_frame.bpp * prc->Width)+7)/8;
414 
415     if (cbStride < bytesperrow)
416         return E_INVALIDARG;
417 
418     if ((cbStride * (prc->Height-1)) + bytesperrow > cbBufferSize)
419         return E_INVALIDARG;
420 
421     EnterCriticalSection(&This->parent->lock);
422 
423     hr = decoder_copy_pixels(This->parent->decoder, This->frame,
424         prc, cbStride, cbBufferSize, pbBuffer);
425 
426     LeaveCriticalSection(&This->parent->lock);
427 
428     return hr;
429 }
430 
CommonDecoderFrame_GetMetadataQueryReader(IWICBitmapFrameDecode * iface,IWICMetadataQueryReader ** ppIMetadataQueryReader)431 static HRESULT WINAPI CommonDecoderFrame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
432     IWICMetadataQueryReader **ppIMetadataQueryReader)
433 {
434     CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface);
435     IWICComponentFactory* factory;
436     HRESULT hr;
437 
438     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
439 
440     if (!ppIMetadataQueryReader)
441         return E_INVALIDARG;
442 
443     if (!(This->parent->file_info.flags & WICBitmapDecoderCapabilityCanEnumerateMetadata))
444         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
445 
446     hr = create_instance(&CLSID_WICImagingFactory, &IID_IWICComponentFactory, (void**)&factory);
447 
448     if (SUCCEEDED(hr))
449     {
450         hr = IWICComponentFactory_CreateQueryReaderFromBlockReader(factory, &This->IWICMetadataBlockReader_iface, ppIMetadataQueryReader);
451         IWICComponentFactory_Release(factory);
452     }
453 
454     if (FAILED(hr))
455         *ppIMetadataQueryReader = NULL;
456 
457     return hr;
458 }
459 
CommonDecoderFrame_GetColorContexts(IWICBitmapFrameDecode * iface,UINT cCount,IWICColorContext ** ppIColorContexts,UINT * pcActualCount)460 static HRESULT WINAPI CommonDecoderFrame_GetColorContexts(IWICBitmapFrameDecode *iface,
461     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
462 {
463     CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface);
464     HRESULT hr=S_OK;
465     UINT i;
466     BYTE *profile;
467     DWORD profile_len;
468 
469     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
470 
471     if (!pcActualCount) return E_INVALIDARG;
472 
473     if (This->parent->file_info.flags & DECODER_FLAGS_UNSUPPORTED_COLOR_CONTEXT)
474     {
475         FIXME("not supported for %s\n", wine_dbgstr_guid(&This->parent->decoder_info.clsid));
476         *pcActualCount = 0;
477         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
478     }
479 
480     *pcActualCount = This->decoder_frame.num_color_contexts;
481 
482     if (This->decoder_frame.num_color_contexts && cCount && ppIColorContexts)
483     {
484         if (cCount >= This->decoder_frame.num_color_contexts)
485         {
486             EnterCriticalSection(&This->parent->lock);
487 
488             for (i=0; i<This->decoder_frame.num_color_contexts; i++)
489             {
490                 hr = decoder_get_color_context(This->parent->decoder, This->frame, i,
491                     &profile, &profile_len);
492                 if (SUCCEEDED(hr))
493                 {
494                     hr = IWICColorContext_InitializeFromMemory(ppIColorContexts[i], profile, profile_len);
495 
496                     free(profile);
497                 }
498 
499                 if (FAILED(hr))
500                     break;
501             }
502 
503             LeaveCriticalSection(&This->parent->lock);
504         }
505         else
506         {
507             hr = E_INVALIDARG;
508         }
509     }
510 
511     return hr;
512 }
513 
CommonDecoderFrame_GetThumbnail(IWICBitmapFrameDecode * iface,IWICBitmapSource ** ppIThumbnail)514 static HRESULT WINAPI CommonDecoderFrame_GetThumbnail(IWICBitmapFrameDecode *iface,
515     IWICBitmapSource **ppIThumbnail)
516 {
517     TRACE("(%p,%p)\n", iface, ppIThumbnail);
518 
519     if (!ppIThumbnail) return E_INVALIDARG;
520 
521     *ppIThumbnail = NULL;
522     return WINCODEC_ERR_CODECNOTHUMBNAIL;
523 }
524 
525 static const IWICBitmapFrameDecodeVtbl CommonDecoderFrameVtbl = {
526     CommonDecoderFrame_QueryInterface,
527     CommonDecoderFrame_AddRef,
528     CommonDecoderFrame_Release,
529     CommonDecoderFrame_GetSize,
530     CommonDecoderFrame_GetPixelFormat,
531     CommonDecoderFrame_GetResolution,
532     CommonDecoderFrame_CopyPalette,
533     CommonDecoderFrame_CopyPixels,
534     CommonDecoderFrame_GetMetadataQueryReader,
535     CommonDecoderFrame_GetColorContexts,
536     CommonDecoderFrame_GetThumbnail
537 };
538 
CommonDecoderFrame_Block_QueryInterface(IWICMetadataBlockReader * iface,REFIID iid,void ** ppv)539 static HRESULT WINAPI CommonDecoderFrame_Block_QueryInterface(IWICMetadataBlockReader *iface, REFIID iid,
540     void **ppv)
541 {
542     CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface);
543     return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv);
544 }
545 
CommonDecoderFrame_Block_AddRef(IWICMetadataBlockReader * iface)546 static ULONG WINAPI CommonDecoderFrame_Block_AddRef(IWICMetadataBlockReader *iface)
547 {
548     CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface);
549     return IWICBitmapFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface);
550 }
551 
CommonDecoderFrame_Block_Release(IWICMetadataBlockReader * iface)552 static ULONG WINAPI CommonDecoderFrame_Block_Release(IWICMetadataBlockReader *iface)
553 {
554     CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface);
555     return IWICBitmapFrameDecode_Release(&This->IWICBitmapFrameDecode_iface);
556 }
557 
CommonDecoderFrame_Block_GetContainerFormat(IWICMetadataBlockReader * iface,GUID * pguidContainerFormat)558 static HRESULT WINAPI CommonDecoderFrame_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
559     GUID *pguidContainerFormat)
560 {
561     CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface);
562     if (!pguidContainerFormat) return E_INVALIDARG;
563     *pguidContainerFormat = This->parent->decoder_info.block_format;
564     return S_OK;
565 }
566 
CommonDecoderFrame_InitializeMetadata(CommonDecoderFrame * This)567 static HRESULT CommonDecoderFrame_InitializeMetadata(CommonDecoderFrame *This)
568 {
569     HRESULT hr=S_OK;
570 
571     if (This->metadata_initialized)
572         return S_OK;
573 
574     EnterCriticalSection(&This->parent->lock);
575 
576     if (!This->metadata_initialized)
577     {
578         hr = decoder_get_metadata_blocks(This->parent->decoder, This->frame, &This->metadata_count, &This->metadata_blocks);
579         if (SUCCEEDED(hr))
580             This->metadata_initialized = TRUE;
581     }
582 
583     LeaveCriticalSection(&This->parent->lock);
584 
585     return hr;
586 }
587 
CommonDecoderFrame_Block_GetCount(IWICMetadataBlockReader * iface,UINT * pcCount)588 static HRESULT WINAPI CommonDecoderFrame_Block_GetCount(IWICMetadataBlockReader *iface,
589     UINT *pcCount)
590 {
591     CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface);
592     HRESULT hr;
593 
594     TRACE("%p,%p\n", iface, pcCount);
595 
596     if (!pcCount) return E_INVALIDARG;
597 
598     hr = CommonDecoderFrame_InitializeMetadata(This);
599     if (SUCCEEDED(hr))
600         *pcCount = This->metadata_count;
601 
602     return hr;
603 }
604 
CommonDecoderFrame_Block_GetReaderByIndex(IWICMetadataBlockReader * iface,UINT nIndex,IWICMetadataReader ** ppIMetadataReader)605 static HRESULT WINAPI CommonDecoderFrame_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
606     UINT nIndex, IWICMetadataReader **ppIMetadataReader)
607 {
608     CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface);
609     HRESULT hr;
610     IWICComponentFactory* factory = NULL;
611     IWICStream* stream;
612 
613     TRACE("%p,%d,%p\n", iface, nIndex, ppIMetadataReader);
614 
615     if (!ppIMetadataReader)
616         return E_INVALIDARG;
617 
618     hr = CommonDecoderFrame_InitializeMetadata(This);
619 
620     if (SUCCEEDED(hr) && nIndex >= This->metadata_count)
621         hr = E_INVALIDARG;
622 
623     if (SUCCEEDED(hr))
624         hr = create_instance(&CLSID_WICImagingFactory, &IID_IWICComponentFactory, (void**)&factory);
625 
626     if (SUCCEEDED(hr))
627         hr = IWICComponentFactory_CreateStream(factory, &stream);
628 
629     if (SUCCEEDED(hr))
630     {
631         if (This->metadata_blocks[nIndex].options & DECODER_BLOCK_FULL_STREAM)
632         {
633             LARGE_INTEGER offset;
634             offset.QuadPart = This->metadata_blocks[nIndex].offset;
635 
636             hr = IWICStream_InitializeFromIStream(stream, This->parent->stream);
637 
638             if (SUCCEEDED(hr))
639                 hr = IWICStream_Seek(stream, offset, STREAM_SEEK_SET, NULL);
640         }
641         else
642         {
643             ULARGE_INTEGER offset, length;
644 
645             offset.QuadPart = This->metadata_blocks[nIndex].offset;
646             length.QuadPart = This->metadata_blocks[nIndex].length;
647 
648             hr = IWICStream_InitializeFromIStreamRegion(stream, This->parent->stream,
649                 offset, length);
650         }
651 
652         if (This->metadata_blocks[nIndex].options & DECODER_BLOCK_READER_CLSID)
653         {
654             IWICMetadataReader *reader;
655             IWICPersistStream *persist;
656             if (SUCCEEDED(hr))
657             {
658                 hr = create_instance(&This->metadata_blocks[nIndex].reader_clsid,
659                     &IID_IWICMetadataReader, (void**)&reader);
660             }
661 
662             if (SUCCEEDED(hr))
663             {
664                 hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICPersistStream, (void**)&persist);
665 
666                 if (SUCCEEDED(hr))
667                 {
668                     hr = IWICPersistStream_LoadEx(persist, (IStream*)stream, NULL,
669                         This->metadata_blocks[nIndex].options & DECODER_BLOCK_OPTION_MASK);
670 
671                     IWICPersistStream_Release(persist);
672                 }
673 
674                 if (SUCCEEDED(hr))
675                     *ppIMetadataReader = reader;
676                 else
677                     IWICMetadataReader_Release(reader);
678             }
679         }
680         else
681         {
682             hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
683                 &This->parent->decoder_info.block_format, NULL,
684                 This->metadata_blocks[nIndex].options & DECODER_BLOCK_OPTION_MASK,
685                 (IStream*)stream, ppIMetadataReader);
686         }
687 
688         IWICStream_Release(stream);
689     }
690 
691     if (factory) IWICComponentFactory_Release(factory);
692 
693     if (FAILED(hr))
694         *ppIMetadataReader = NULL;
695 
696     return S_OK;
697 }
698 
CommonDecoderFrame_Block_GetEnumerator(IWICMetadataBlockReader * iface,IEnumUnknown ** ppIEnumMetadata)699 static HRESULT WINAPI CommonDecoderFrame_Block_GetEnumerator(IWICMetadataBlockReader *iface,
700     IEnumUnknown **ppIEnumMetadata)
701 {
702     FIXME("%p,%p\n", iface, ppIEnumMetadata);
703     return E_NOTIMPL;
704 }
705 
706 static const IWICMetadataBlockReaderVtbl CommonDecoderFrame_BlockVtbl = {
707     CommonDecoderFrame_Block_QueryInterface,
708     CommonDecoderFrame_Block_AddRef,
709     CommonDecoderFrame_Block_Release,
710     CommonDecoderFrame_Block_GetContainerFormat,
711     CommonDecoderFrame_Block_GetCount,
712     CommonDecoderFrame_Block_GetReaderByIndex,
713     CommonDecoderFrame_Block_GetEnumerator,
714 };
715 
CommonDecoder_GetFrame(IWICBitmapDecoder * iface,UINT index,IWICBitmapFrameDecode ** ppIBitmapFrame)716 static HRESULT WINAPI CommonDecoder_GetFrame(IWICBitmapDecoder *iface,
717     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
718 {
719     CommonDecoder *This = impl_from_IWICBitmapDecoder(iface);
720     HRESULT hr=S_OK;
721     CommonDecoderFrame *result;
722 
723     TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
724 
725     if (!ppIBitmapFrame)
726         return E_INVALIDARG;
727 
728     EnterCriticalSection(&This->lock);
729 
730     if (!This->stream || index >= This->file_info.frame_count)
731         hr = WINCODEC_ERR_FRAMEMISSING;
732 
733     if (SUCCEEDED(hr))
734     {
735         result = malloc(sizeof(*result));
736         if (!result)
737             hr = E_OUTOFMEMORY;
738     }
739 
740     if (SUCCEEDED(hr))
741     {
742         result->IWICBitmapFrameDecode_iface.lpVtbl = &CommonDecoderFrameVtbl;
743         result->IWICMetadataBlockReader_iface.lpVtbl = &CommonDecoderFrame_BlockVtbl;
744         result->ref = 1;
745         result->parent = This;
746         result->frame = index;
747         result->metadata_initialized = FALSE;
748         result->metadata_count = 0;
749         result->metadata_blocks = NULL;
750 
751         hr = decoder_get_frame_info(This->decoder, index, &result->decoder_frame);
752 
753         if (SUCCEEDED(hr) && This->cache_options == WICDecodeMetadataCacheOnLoad)
754             hr = CommonDecoderFrame_InitializeMetadata(result);
755 
756         if (FAILED(hr))
757             free(result);
758     }
759 
760     LeaveCriticalSection(&This->lock);
761 
762     if (SUCCEEDED(hr))
763     {
764         TRACE("-> %ux%u, %u-bit pixelformat=%s res=%f,%f colors=%lu contexts=%lu\n",
765             result->decoder_frame.width, result->decoder_frame.height,
766             result->decoder_frame.bpp, wine_dbgstr_guid(&result->decoder_frame.pixel_format),
767             result->decoder_frame.dpix, result->decoder_frame.dpiy,
768             result->decoder_frame.num_colors, result->decoder_frame.num_color_contexts);
769         IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
770         *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface;
771     }
772     else
773     {
774         *ppIBitmapFrame = NULL;
775     }
776 
777     return hr;
778 }
779 
CommonDecoder_CreateInstance(struct decoder * decoder,const struct decoder_info * decoder_info,REFIID iid,void ** ppv)780 HRESULT CommonDecoder_CreateInstance(struct decoder *decoder,
781     const struct decoder_info *decoder_info, REFIID iid, void** ppv)
782 {
783     CommonDecoder *This;
784     HRESULT hr;
785 
786     TRACE("(%s,%s,%p)\n", debugstr_guid(&decoder_info->clsid), debugstr_guid(iid), ppv);
787 
788     This = malloc(sizeof(*This));
789     if (!This)
790     {
791         decoder_destroy(decoder);
792         return E_OUTOFMEMORY;
793     }
794 
795     This->IWICBitmapDecoder_iface.lpVtbl = &CommonDecoder_Vtbl;
796     This->ref = 1;
797     This->stream = NULL;
798     This->decoder = decoder;
799     This->decoder_info = *decoder_info;
800 #ifdef __REACTOS__
801     InitializeCriticalSection(&This->lock);
802 #else
803     InitializeCriticalSectionEx(&This->lock, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO);
804 #endif
805     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": CommonDecoder.lock");
806 
807     hr = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
808     IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
809 
810     return hr;
811 }
812