Fixed the behavior for SHGetFileInfo when the SHGFI_USEFILEATTRIBUTES
[wine] / dlls / quartz / mtype.c
1 /*
2  * Implements IEnumMediaTypes and helper functions. (internal)
3  *
4  * hidenori@a2.ctktv.ne.jp
5  */
6
7 #include "config.h"
8
9 #include "windef.h"
10 #include "winbase.h"
11 #include "wingdi.h"
12 #include "winuser.h"
13 #include "winerror.h"
14 #include "mmsystem.h"
15 #include "strmif.h"
16 #include "vfwmsgs.h"
17 #include "uuids.h"
18
19 #include "debugtools.h"
20 DEFAULT_DEBUG_CHANNEL(quartz);
21
22 #include "quartz_private.h"
23 #include "mtype.h"
24 #include "iunk.h"
25
26
27 /****************************************************************************/
28
29
30
31 HRESULT QUARTZ_MediaType_Copy(
32         AM_MEDIA_TYPE* pmtDst,
33         const AM_MEDIA_TYPE* pmtSrc )
34 {
35         memcpy( &pmtDst->majortype, &pmtSrc->majortype, sizeof(GUID) );
36         memcpy( &pmtDst->subtype, &pmtSrc->subtype, sizeof(GUID) );
37         pmtDst->bFixedSizeSamples = pmtSrc->bFixedSizeSamples;
38         pmtDst->bTemporalCompression = pmtSrc->bTemporalCompression;
39         pmtDst->lSampleSize = pmtSrc->lSampleSize;
40         memcpy( &pmtDst->formattype, &pmtSrc->formattype, sizeof(GUID) );
41         pmtDst->pUnk = NULL;
42         pmtDst->cbFormat = pmtSrc->cbFormat;
43         pmtDst->pbFormat = NULL;
44
45         if ( pmtSrc->pbFormat != NULL && pmtSrc->cbFormat != 0 )
46         {
47                 pmtDst->pbFormat = (BYTE*)CoTaskMemAlloc( pmtSrc->cbFormat );
48                 if ( pmtDst->pbFormat == NULL )
49                 {
50                         CoTaskMemFree( pmtDst );
51                         return E_OUTOFMEMORY;
52                 }
53                 memcpy( pmtDst->pbFormat, pmtSrc->pbFormat, pmtSrc->cbFormat );
54         }
55
56         if ( pmtSrc->pUnk != NULL )
57         {
58                 pmtDst->pUnk = pmtSrc->pUnk;
59                 IUnknown_AddRef( pmtSrc->pUnk );
60         }
61
62         return S_OK;
63 }
64
65 void QUARTZ_MediaType_Free(
66         AM_MEDIA_TYPE* pmt )
67 {
68         if ( pmt->pUnk != NULL )
69         {
70                 IUnknown_Release( pmt->pUnk );
71                 pmt->pUnk = NULL;
72         }
73         if ( pmt->pbFormat != NULL )
74         {
75                 CoTaskMemFree( pmt->pbFormat );
76                 pmt->cbFormat = 0;
77                 pmt->pbFormat = NULL;
78         }
79 }
80
81 AM_MEDIA_TYPE* QUARTZ_MediaType_Duplicate(
82         const AM_MEDIA_TYPE* pmtSrc )
83 {
84         AM_MEDIA_TYPE*  pmtDup;
85
86         pmtDup = (AM_MEDIA_TYPE*)CoTaskMemAlloc( sizeof(AM_MEDIA_TYPE) );
87         if ( pmtDup == NULL )
88                 return NULL;
89         if ( QUARTZ_MediaType_Copy( pmtDup, pmtSrc ) != S_OK )
90         {
91                 CoTaskMemFree( pmtDup );
92                 return NULL;
93         }
94
95         return pmtDup;
96 }
97
98 void QUARTZ_MediaType_Destroy(
99         AM_MEDIA_TYPE* pmt )
100 {
101         QUARTZ_MediaType_Free( pmt );
102         CoTaskMemFree( pmt );
103 }
104
105 void QUARTZ_MediaSubType_FromFourCC(
106         GUID* psubtype, DWORD dwFourCC )
107 {
108         memcpy( psubtype, &MEDIASUBTYPE_PCM, sizeof(GUID) );
109         psubtype->Data1 = dwFourCC;
110 }
111
112 BOOL QUARTZ_MediaSubType_IsFourCC(
113         const GUID* psubtype )
114 {
115         GUID guidTemp;
116
117         QUARTZ_MediaSubType_FromFourCC(
118                 &guidTemp, psubtype->Data1 );
119         return IsEqualGUID( psubtype, &guidTemp );
120 }
121
122 HRESULT QUARTZ_MediaSubType_FromBitmap(
123         GUID* psubtype, const BITMAPINFOHEADER* pbi )
124 {
125         HRESULT hr;
126         DWORD*  pdwBitf;
127
128         if ( (pbi->biCompression & 0xffff) != 0 )
129                 return S_FALSE;
130
131         if ( pbi->biWidth <= 0 || pbi->biHeight == 0 )
132                 return E_FAIL;
133
134         hr = E_FAIL;
135         switch ( pbi->biCompression )
136         {
137         case 0:
138                 if ( pbi->biPlanes != 1 )
139                         break;
140                 switch ( pbi->biBitCount )
141                 {
142                 case  1:
143                         memcpy( psubtype, &MEDIASUBTYPE_RGB1, sizeof(GUID) );
144                         hr = S_OK;
145                         break;
146                 case  4:
147                         memcpy( psubtype, &MEDIASUBTYPE_RGB4, sizeof(GUID) );
148                         hr = S_OK;
149                         break;
150                 case  8:
151                         memcpy( psubtype, &MEDIASUBTYPE_RGB8, sizeof(GUID) );
152                         hr = S_OK;
153                         break;
154                 case 16:
155                         memcpy( psubtype, &MEDIASUBTYPE_RGB555, sizeof(GUID) );
156                         hr = S_OK;
157                         break;
158                 case 24:
159                         memcpy( psubtype, &MEDIASUBTYPE_RGB24, sizeof(GUID) );
160                         hr = S_OK;
161                         break;
162                 case 32:
163                         memcpy( psubtype, &MEDIASUBTYPE_RGB32, sizeof(GUID) );
164                         hr = S_OK;
165                         break;
166                 }
167                 break;
168         case 1:
169                 if ( pbi->biPlanes == 1 && pbi->biHeight > 0 &&
170                          pbi->biBitCount == 8 )
171                 {
172                         QUARTZ_MediaSubType_FromFourCC( psubtype, mmioFOURCC('M','R','L','E') );
173                         hr = S_OK;
174                 }
175                 break;
176         case 2:
177                 if ( pbi->biPlanes == 1 && pbi->biHeight > 0 &&
178                          pbi->biBitCount == 4 )
179                 {
180                         QUARTZ_MediaSubType_FromFourCC( psubtype, mmioFOURCC('M','R','L','E') );
181                         hr = S_OK;
182                 }
183                 break;
184         case 3:
185                 if ( pbi->biPlanes != 1 )
186                         break;
187                 pdwBitf = (DWORD*)( (BYTE*)pbi + sizeof(BITMAPINFOHEADER) );
188                 switch ( pbi->biBitCount )
189                 {
190                 case 16:
191                         if ( pdwBitf[0] == 0x7c00 &&
192                                  pdwBitf[1] == 0x03e0 &&
193                                  pdwBitf[2] == 0x001f )
194                         {
195                                 memcpy( psubtype, &MEDIASUBTYPE_RGB555, sizeof(GUID) );
196                                 hr = S_OK;
197                         }
198                         if ( pdwBitf[0] == 0xf800 &&
199                                  pdwBitf[1] == 0x07e0 &&
200                                  pdwBitf[2] == 0x001f )
201                         {
202                                 memcpy( psubtype, &MEDIASUBTYPE_RGB565, sizeof(GUID) );
203                                 hr = S_OK;
204                         }
205                         break;
206                 case 32:
207                         if ( pdwBitf[0] == 0x00ff0000 &&
208                                  pdwBitf[1] == 0x0000ff00 &&
209                                  pdwBitf[2] == 0x000000ff )
210                         {
211                                 memcpy( psubtype, &MEDIASUBTYPE_RGB32, sizeof(GUID) );
212                                 hr = S_OK;
213                         }
214                         break;
215                 }
216                 break;
217         }
218
219         return hr;
220 }
221
222 BOOL QUARTZ_BitmapHasFixedSample( const BITMAPINFOHEADER* pbi )
223 {
224         switch ( pbi->biCompression )
225         {
226         case 0:
227         case 3:
228         case mmioFOURCC('I','4','2','0'):
229         case mmioFOURCC('I','Y','U','V'):
230         case mmioFOURCC('Y','U','Y','V'):
231         case mmioFOURCC('Y','V','U','9'):
232         case mmioFOURCC('Y','4','1','1'):
233         case mmioFOURCC('Y','4','1','P'):
234         case mmioFOURCC('Y','U','Y','2'):
235         case mmioFOURCC('Y','V','Y','U'):
236         case mmioFOURCC('U','Y','V','Y'):
237         case mmioFOURCC('Y','2','1','1'):
238         case mmioFOURCC('Y','V','1','2'):
239                 return TRUE;
240         }
241
242         return FALSE;
243 }
244
245
246 /****************************************************************************/
247
248 typedef struct IEnumMediaTypesImpl
249 {
250         ICOM_VFIELD(IEnumMediaTypes);
251 } IEnumMediaTypesImpl;
252
253 typedef struct
254 {
255         QUARTZ_IUnkImpl unk;
256         IEnumMediaTypesImpl     enummtype;
257         struct QUARTZ_IFEntry   IFEntries[1];
258         CRITICAL_SECTION        cs;
259         AM_MEDIA_TYPE*  pTypes;
260         ULONG   cTypes;
261         ULONG   cCur;
262 } CEnumMediaTypes;
263
264 #define CEnumMediaTypes_THIS(iface,member)              CEnumMediaTypes*        This = ((CEnumMediaTypes*)(((char*)iface)-offsetof(CEnumMediaTypes,member)))
265
266
267
268 static HRESULT WINAPI
269 IEnumMediaTypes_fnQueryInterface(IEnumMediaTypes* iface,REFIID riid,void** ppobj)
270 {
271         CEnumMediaTypes_THIS(iface,enummtype);
272
273         TRACE("(%p)->()\n",This);
274
275         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
276 }
277
278 static ULONG WINAPI
279 IEnumMediaTypes_fnAddRef(IEnumMediaTypes* iface)
280 {
281         CEnumMediaTypes_THIS(iface,enummtype);
282
283         TRACE("(%p)->()\n",This);
284
285         return IUnknown_AddRef(This->unk.punkControl);
286 }
287
288 static ULONG WINAPI
289 IEnumMediaTypes_fnRelease(IEnumMediaTypes* iface)
290 {
291         CEnumMediaTypes_THIS(iface,enummtype);
292
293         TRACE("(%p)->()\n",This);
294
295         return IUnknown_Release(This->unk.punkControl);
296 }
297
298 static HRESULT WINAPI
299 IEnumMediaTypes_fnNext(IEnumMediaTypes* iface,ULONG cReq,AM_MEDIA_TYPE** ppmtype,ULONG* pcFetched)
300 {
301         CEnumMediaTypes_THIS(iface,enummtype);
302         HRESULT hr;
303         ULONG   cFetched;
304
305         TRACE("(%p)->(%lu,%p,%p)\n",This,cReq,ppmtype,pcFetched);
306
307         if ( pcFetched == NULL && cReq > 1 )
308                 return E_INVALIDARG;
309         if ( ppmtype == NULL )
310                 return E_POINTER;
311
312         EnterCriticalSection( &This->cs );
313
314         hr = NOERROR;
315         cFetched = 0;
316         while ( cReq > 0 )
317         {
318                 if ( This->cCur >= This->cTypes )
319                 {
320                         hr = S_FALSE;
321                         break;
322                 }
323                 ppmtype[ cFetched ] =
324                         QUARTZ_MediaType_Duplicate( &This->pTypes[ This->cCur ] );
325                 if ( ppmtype[ cFetched ] == NULL )
326                 {
327                         hr = E_OUTOFMEMORY;
328                         while ( cFetched > 0 )
329                         {
330                                 cFetched --;
331                                 QUARTZ_MediaType_Destroy( ppmtype[ cFetched ] );
332                         }
333                         break;
334                 }
335
336                 cFetched ++;
337
338                 This->cCur ++;
339                 cReq --;
340         }
341
342         LeaveCriticalSection( &This->cs );
343
344         if ( pcFetched != NULL )
345                 *pcFetched = cFetched;
346
347         return hr;
348 }
349
350 static HRESULT WINAPI
351 IEnumMediaTypes_fnSkip(IEnumMediaTypes* iface,ULONG cSkip)
352 {
353         CEnumMediaTypes_THIS(iface,enummtype);
354         HRESULT hr;
355
356         TRACE("(%p)->()\n",This);
357
358         EnterCriticalSection( &This->cs );
359
360         hr = NOERROR;
361         while ( cSkip > 0 )
362         {
363                 if ( This->cCur >= This->cTypes )
364                 {
365                         hr = S_FALSE;
366                         break;
367                 }
368                 This->cCur ++;
369                 cSkip --;
370         }
371
372         LeaveCriticalSection( &This->cs );
373
374         return hr;
375 }
376
377 static HRESULT WINAPI
378 IEnumMediaTypes_fnReset(IEnumMediaTypes* iface)
379 {
380         CEnumMediaTypes_THIS(iface,enummtype);
381
382         TRACE("(%p)->()\n",This);
383
384         EnterCriticalSection( &This->cs );
385
386         This->cCur = 0;
387
388         LeaveCriticalSection( &This->cs );
389
390         return NOERROR;
391 }
392
393 static HRESULT WINAPI
394 IEnumMediaTypes_fnClone(IEnumMediaTypes* iface,IEnumMediaTypes** ppobj)
395 {
396         CEnumMediaTypes_THIS(iface,enummtype);
397         HRESULT hr;
398
399         TRACE("(%p)->()\n",This);
400
401         if ( ppobj == NULL )
402                 return E_POINTER;
403
404         EnterCriticalSection( &This->cs );
405
406         hr = QUARTZ_CreateEnumMediaTypes(
407                 ppobj,
408                 This->pTypes, This->cTypes );
409         if ( SUCCEEDED(hr) )
410                 IEnumMediaTypes_Skip( *ppobj, This->cCur );
411
412         LeaveCriticalSection( &This->cs );
413
414         return hr;
415 }
416
417
418 static ICOM_VTABLE(IEnumMediaTypes) ienummtype =
419 {
420         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
421         /* IUnknown fields */
422         IEnumMediaTypes_fnQueryInterface,
423         IEnumMediaTypes_fnAddRef,
424         IEnumMediaTypes_fnRelease,
425         /* IEnumMediaTypes fields */
426         IEnumMediaTypes_fnNext,
427         IEnumMediaTypes_fnSkip,
428         IEnumMediaTypes_fnReset,
429         IEnumMediaTypes_fnClone,
430 };
431
432
433 /* can I use offsetof safely? - FIXME? */
434 static QUARTZ_IFEntry IFEntries[] =
435 {
436   { &IID_IEnumMediaTypes, offsetof(CEnumMediaTypes,enummtype)-offsetof(CEnumMediaTypes,unk) },
437 };
438
439
440 void QUARTZ_DestroyEnumMediaTypes(IUnknown* punk)
441 {
442         CEnumMediaTypes_THIS(punk,unk);
443         ULONG   i;
444
445         if ( This->pTypes != NULL )
446         {
447                 for ( i = 0; i < This->cTypes; i++ )
448                         QUARTZ_MediaType_Free( &This->pTypes[i] );
449                 QUARTZ_FreeMem( This->pTypes );
450         }
451
452         DeleteCriticalSection( &This->cs );
453 }
454
455 HRESULT QUARTZ_CreateEnumMediaTypes(
456         IEnumMediaTypes** ppobj,
457         const AM_MEDIA_TYPE* pTypes, ULONG cTypes )
458 {
459         CEnumMediaTypes*        penum;
460         AM_MEDIA_TYPE*  pTypesDup = NULL;
461         ULONG   i;
462         HRESULT hr;
463
464         TRACE("(%p,%p,%lu)\n",ppobj,pTypes,cTypes);
465
466         if ( cTypes > 0 )
467         {
468                 pTypesDup = (AM_MEDIA_TYPE*)QUARTZ_AllocMem(
469                         sizeof( AM_MEDIA_TYPE ) * cTypes );
470                 if ( pTypesDup == NULL )
471                         return E_OUTOFMEMORY;
472
473                 i = 0;
474                 while ( i < cTypes )
475                 {
476                         hr = QUARTZ_MediaType_Copy( &pTypesDup[i], &pTypes[i] );
477                         if ( FAILED(hr) )
478                         {
479                                 while ( i > 0 )
480                                 {
481                                         i --;
482                                         QUARTZ_MediaType_Free( &pTypesDup[i] );
483                                 }
484                                 QUARTZ_FreeMem( pTypesDup );
485                                 return hr;
486                         }
487
488                         i ++;
489                 }
490         }
491
492         penum = (CEnumMediaTypes*)QUARTZ_AllocObj( sizeof(CEnumMediaTypes) );
493         if ( penum == NULL )
494         {
495                 return E_OUTOFMEMORY;
496         }
497         penum->pTypes = pTypesDup;
498         penum->cTypes = cTypes;
499         penum->cCur = 0;
500
501         QUARTZ_IUnkInit( &penum->unk, NULL );
502         ICOM_VTBL(&penum->enummtype) = &ienummtype;
503
504         penum->unk.pEntries = IFEntries;
505         penum->unk.dwEntries = sizeof(IFEntries)/sizeof(IFEntries[0]);
506         penum->unk.pOnFinalRelease = QUARTZ_DestroyEnumMediaTypes;
507
508         InitializeCriticalSection( &penum->cs );
509
510         *ppobj = (IEnumMediaTypes*)(&penum->enummtype);
511
512         return S_OK;
513 }
514
515