Implement ResetDC and PHYSICALOFFSET[X|Y] devcaps.
[wine] / dlls / quartz / fmap.c
1 /*
2  * Implementation of CLSID_FilterMapper and CLSID_FilterMapper2.
3  *
4  * FIXME - some stubs
5  *
6  * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winreg.h"
31 #include "winerror.h"
32 #include "strmif.h"
33 #include "uuids.h"
34
35 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
37
38 #include "quartz_private.h"
39 #include "fmap.h"
40 #include "regsvr.h"
41 #include "devenum.h"
42 #include "complist.h"
43 #include "enumunk.h"
44
45 /***************************************************************************/
46
47 typedef struct QUARTZ_REGFILTERDATA
48 {
49         DWORD   dwVersion; /* =2 */
50         DWORD   dwMerit;
51         DWORD   cPins; /* count of pins */
52         DWORD   dwZero; /* padding??? */
53 } QUARTZ_REGFILTERDATA;
54
55 typedef struct QUARTZ_REGPINDATA
56 {
57         CHAR    id[4]; /* '0pi3', '1pi3', ... */
58         DWORD   dwFlags; /* flags */
59         UINT    cInstances; /* FIXME - is this correct? */
60         UINT    nMediaTypes; /* count of media types('0ty3') */
61         UINT    nMediums; /* FIXME - is this correct? */
62         UINT    nOfsClsPinCategory; /* FIXME - is this correct? */
63 } QUARTZ_REGPINDATA;
64
65 typedef struct QUARTZ_REGMEDIATYPE
66 {
67         CHAR    id[4]; /* '0ty3', '1ty3', ... */
68         DWORD   nZero; /* padding??? */
69         UINT    nOfsMajorType;
70         UINT    nOfsMinorType;
71 } QUARTZ_REGMEDIATYPE;
72
73
74
75 /***************************************************************************/
76
77 static
78 REGFILTER2* QUARTZ_RegFilterV2FromFilterData(
79         const BYTE* pData, DWORD cbData )
80 {
81         REGFILTER2*     pFilter;
82         REGFILTERPINS2* pPin;
83         REGPINTYPES*    pTypes;
84         BYTE* pDst;
85         const QUARTZ_REGFILTERDATA*     pRegFilter;
86         const QUARTZ_REGPINDATA*        pRegPin;
87         const QUARTZ_REGMEDIATYPE*      pRegMediaType;
88         DWORD   cPins;
89         DWORD   cbBufSize;
90         UINT    n;
91
92         TRACE("(%p,%lu)\n",pData,cbData);
93
94         if ( cbData < sizeof(QUARTZ_REGFILTERDATA) )
95                 return NULL;
96
97         pRegFilter = (QUARTZ_REGFILTERDATA*)pData;
98
99         if ( pRegFilter->dwVersion != 2 ) return NULL; /* FIXME */
100
101         if ( cbData < (sizeof(QUARTZ_REGFILTERDATA)+sizeof(QUARTZ_REGPINDATA)*pRegFilter->cPins) )
102                 return NULL;
103
104         cbBufSize = sizeof(REGFILTER2);
105         cPins = pRegFilter->cPins;
106         pRegPin = (const QUARTZ_REGPINDATA*)(pRegFilter+1);
107         while ( cPins-- > 0 )
108         {
109                 if ( pRegPin->nMediums != 0 ||
110                          pRegPin->nOfsClsPinCategory != 0 )
111                         return NULL; /* FIXME */
112
113                 cbBufSize += sizeof(REGFILTERPINS2) +
114                         pRegPin->nMediaTypes * (sizeof(REGPINTYPES) + sizeof(GUID)*2) +
115                         pRegPin->nMediums * sizeof(REGPINMEDIUM) +
116                         sizeof(CLSID);
117                 pRegPin = (const QUARTZ_REGPINDATA*)( ((const BYTE*)pRegPin) +
118                         sizeof(QUARTZ_REGPINDATA) +
119                         sizeof(QUARTZ_REGMEDIATYPE) * pRegPin->nMediaTypes );
120         }
121
122         pFilter = (REGFILTER2*)QUARTZ_AllocMem( cbBufSize );
123         if ( pFilter == NULL ) return NULL;
124         ZeroMemory( pFilter, cbBufSize );
125         pPin = (REGFILTERPINS2*)(pFilter+1);
126         pDst = (BYTE*)(pPin + pRegFilter->cPins);
127
128         pFilter->dwVersion = 2;
129         pFilter->dwMerit = pRegFilter->dwMerit;
130         pFilter->u.s2.cPins2 = pRegFilter->cPins;
131         pFilter->u.s2.rgPins2 = pPin;
132
133         cPins = pRegFilter->cPins;
134         TRACE("cPins = %lu\n",cPins);
135
136         pRegPin = (const QUARTZ_REGPINDATA*)(pRegFilter+1);
137         while ( cPins-- > 0 )
138         {
139                 pPin->dwFlags = pRegPin->dwFlags;
140                 pPin->cInstances = pRegPin->cInstances;
141                 pPin->nMediaTypes = pRegPin->nMediaTypes;
142                 pPin->lpMediaType = NULL;
143                 pPin->nMediums = pRegPin->nMediums;
144                 pPin->lpMedium = NULL;
145                 pPin->clsPinCategory = NULL;
146
147                 pTypes = (REGPINTYPES*)pDst;
148                 pPin->lpMediaType = pTypes;
149                 pDst += sizeof(REGPINTYPES) * pRegPin->nMediaTypes;
150
151                 pRegPin = (const QUARTZ_REGPINDATA*)( ((const BYTE*)pRegPin) +
152                         sizeof(QUARTZ_REGPINDATA) );
153
154                 for ( n = 0; n < pPin->nMediaTypes; n++ )
155                 {
156                         pRegMediaType = ((const QUARTZ_REGMEDIATYPE*)pRegPin);
157                         TRACE("ofsMajor = %u, ofsMinor = %u\n", pRegMediaType->nOfsMajorType, pRegMediaType->nOfsMinorType);
158                         memcpy( pDst, pData+pRegMediaType->nOfsMajorType, sizeof(GUID) );
159                         pTypes->clsMajorType = (const GUID*)pDst; pDst += sizeof(GUID);
160                         memcpy( pDst, pData+pRegMediaType->nOfsMinorType, sizeof(GUID) );
161                         pTypes->clsMinorType = (const GUID*)pDst; pDst += sizeof(GUID);
162
163                         pRegPin = (const QUARTZ_REGPINDATA*)( ((const BYTE*)pRegPin) +
164                                 sizeof(QUARTZ_REGMEDIATYPE) );
165                         pTypes ++;
166                 }
167
168                 /* FIXME - pPin->lpMedium */
169                 /* FIXME - pPin->clsPinCategory */
170
171                 pPin ++;
172         }
173
174         return pFilter;
175 }
176
177 static
178 BYTE* QUARTZ_RegFilterV2ToFilterData(
179         const REGFILTER2* pFilter, DWORD* pcbData )
180 {
181         DWORD   cbData;
182         DWORD   cbPinData;
183         DWORD   cPins;
184         const REGFILTERPINS2*   pPin;
185         const REGPINTYPES*      pTypes;
186         BYTE*   pRet = NULL;
187         BYTE*   pDst;
188         QUARTZ_REGFILTERDATA*   pRegFilter;
189         QUARTZ_REGPINDATA*      pRegPin;
190         QUARTZ_REGMEDIATYPE*    pRegMediaType;
191         UINT    n;
192
193         if ( pFilter->dwVersion != 2 ) return NULL; /* FIXME */
194
195         cbData = sizeof(QUARTZ_REGFILTERDATA);
196         cPins = pFilter->u.s2.cPins2;
197         pPin = pFilter->u.s2.rgPins2;
198         if ( cPins > 10 ) return NULL; /* FIXME */
199
200         cbPinData = 0;
201         while ( cPins-- > 0 )
202         {
203                 if ( pPin->cInstances != 0 ||
204                          pPin->nMediaTypes > 10 ||
205                          pPin->nMediums != 0 ||
206                          pPin->clsPinCategory != 0 )
207                 {
208                         FIXME( "not implemented.\n" );
209                         return NULL; /* FIXME */
210                 }
211
212                 cbPinData += sizeof(QUARTZ_REGPINDATA) +
213                         pPin->nMediaTypes * sizeof(QUARTZ_REGMEDIATYPE);
214                 cbData += pPin->nMediaTypes * (sizeof(GUID)*2);
215                 pPin ++;
216         }
217         cbData += cbPinData;
218         TRACE("cbData %lu, cbPinData %lu\n",cbData,cbPinData);
219
220         pRet = (BYTE*)QUARTZ_AllocMem( cbData );
221         if ( pRet == NULL ) return NULL;
222         ZeroMemory( pRet, cbData );
223         pDst = pRet;
224
225         pRegFilter = (QUARTZ_REGFILTERDATA*)pDst;
226         pDst += sizeof(QUARTZ_REGFILTERDATA);
227
228         pRegFilter->dwVersion = 2;
229         pRegFilter->dwMerit = pFilter->dwMerit;
230         pRegFilter->cPins = pFilter->u.s2.cPins2;
231
232         pRegPin = (QUARTZ_REGPINDATA*)pDst;
233         pDst += cbPinData;
234
235         pPin = pFilter->u.s2.rgPins2;
236         for ( cPins = 0; cPins < pFilter->u.s2.cPins2; cPins++ )
237         {
238                 pRegPin->id[0] = '0'+cPins;
239                 pRegPin->id[1] = 'p';
240                 pRegPin->id[2] = 'i';
241                 pRegPin->id[3] = '3';
242                 pRegPin->dwFlags = pPin->dwFlags; /* flags */
243                 pRegPin->cInstances = pPin->cInstances;
244                 pRegPin->nMediaTypes = pPin->nMediaTypes;
245                 pRegPin->nMediums = pPin->nMediums;
246                 pRegPin->nOfsClsPinCategory = 0; /* FIXME */
247
248                 pTypes = pPin->lpMediaType;
249                 pRegPin = (QUARTZ_REGPINDATA*)( ((const BYTE*)pRegPin) +
250                         sizeof(QUARTZ_REGPINDATA) );
251                 for ( n = 0; n < pPin->nMediaTypes; n++ )
252                 {
253                         pRegMediaType = ((QUARTZ_REGMEDIATYPE*)pRegPin);
254
255                         pRegMediaType->id[0] = '0'+n;
256                         pRegMediaType->id[1] = 't';
257                         pRegMediaType->id[2] = 'y';
258                         pRegMediaType->id[3] = '3';
259
260                         /* FIXME - CLSID should be shared. */
261                         pRegMediaType->nOfsMajorType = pDst - pRet;
262                         memcpy( pDst, pTypes->clsMajorType, sizeof(GUID) );
263                         pDst += sizeof(GUID);
264                         pRegMediaType->nOfsMinorType = pDst - pRet;
265                         memcpy( pDst, pTypes->clsMinorType, sizeof(GUID) );
266                         pDst += sizeof(GUID);
267
268                         pRegPin = (QUARTZ_REGPINDATA*)( ((const BYTE*)pRegPin) +
269                                 sizeof(QUARTZ_REGMEDIATYPE) );
270                         pTypes ++;
271                 }
272                 pPin ++;
273         }
274
275         *pcbData = pDst - pRet;
276         TRACE("cbData %lu/%lu\n",*pcbData,cbData);
277
278         return pRet;
279 }
280
281 static
282 REGFILTER2* QUARTZ_RegFilterV1ToV2( const REGFILTER2* prfV1 )
283 {
284         REGFILTER2*     prfV2;
285         const REGFILTERPINS*    pPinV1;
286         REGFILTERPINS2* pPinV2;
287         DWORD   cPins;
288
289         if ( prfV1->dwVersion != 1 ) return NULL;
290
291         prfV2 = (REGFILTER2*)QUARTZ_AllocMem(
292                 sizeof(REGFILTER2) + sizeof(REGFILTERPINS2) * prfV1->u.s1.cPins );
293         if ( prfV2 == NULL ) return NULL;
294         ZeroMemory( prfV2, sizeof(REGFILTER2) + sizeof(REGFILTERPINS2) * prfV1->u.s1.cPins );
295         pPinV1 = prfV1->u.s1.rgPins;
296         pPinV2 = (REGFILTERPINS2*)(prfV2+1);
297         prfV2->dwVersion = 2;
298         prfV2->dwMerit = prfV1->dwMerit;
299         prfV2->u.s2.cPins2 = prfV1->u.s1.cPins;
300         prfV2->u.s2.rgPins2 = pPinV2;
301
302         cPins = prfV1->u.s1.cPins;
303         while ( cPins-- > 0 )
304         {
305                 pPinV2->dwFlags = 0;
306                 pPinV2->cInstances = 0;
307                 pPinV2->nMediaTypes = pPinV1->nMediaTypes;
308                 pPinV2->lpMediaType = pPinV1->lpMediaType;
309                 pPinV2->nMediums = 0;
310                 pPinV2->lpMedium = NULL;
311                 pPinV2->clsPinCategory = NULL;
312
313                 if ( pPinV1->bRendered )
314                         pPinV2->dwFlags |= REG_PINFLAG_B_RENDERER;
315                 if ( pPinV1->bOutput )
316                         pPinV2->dwFlags |= REG_PINFLAG_B_OUTPUT;
317                 if ( pPinV1->bZero )
318                         pPinV2->dwFlags |= REG_PINFLAG_B_ZERO;
319                 if ( pPinV1->bMany )
320                         pPinV2->dwFlags |= REG_PINFLAG_B_MANY;
321
322                 pPinV1 ++;
323                 pPinV2 ++;
324         }
325
326         return prfV2;
327 }
328
329 static
330 BYTE* QUARTZ_RegFilterToFilterData(
331         const REGFILTER2* pFilter, DWORD* pcbData )
332 {
333         REGFILTER2*     prfV2;
334         BYTE*   pRet = NULL;
335
336         *pcbData = 0;
337         switch ( pFilter->dwVersion )
338         {
339         case 1:
340                 prfV2 = QUARTZ_RegFilterV1ToV2( pFilter );
341                 if ( prfV2 != NULL )
342                 {
343                         pRet = QUARTZ_RegFilterV2ToFilterData( prfV2, pcbData );
344                         QUARTZ_FreeMem( prfV2 );
345                 }
346                 break;
347         case 2:
348                 pRet = QUARTZ_RegFilterV2ToFilterData( pFilter, pcbData );
349                 break;
350         default:
351                 FIXME( "unknown REGFILTER2 version - %08lu\n", pFilter->dwVersion );
352                 break;
353         }
354
355         return pRet;
356 }
357
358 /***************************************************************************/
359
360 static
361 BOOL QUARTZ_CheckPinType( BOOL bExactMatch, const REGFILTERPINS2* pPin, DWORD cTypes, const GUID* pTypes, const REGPINMEDIUM* pMedium, const CLSID* pCategory, BOOL bRender )
362 {
363         DWORD   n1, n2;
364         BOOL    bMatch;
365
366         if ( cTypes > 0 && pTypes != NULL )
367         {
368                 bMatch = FALSE;
369                 for ( n1 = 0; n1 < pPin->nMediaTypes; n1++ )
370                 {
371                         for ( n2 = 0; n2 < cTypes; n2++ )
372                         {
373                                 if ( IsEqualGUID(pPin->lpMediaType[n1].clsMajorType,&GUID_NULL) || IsEqualGUID(pPin->lpMediaType[n1].clsMajorType, &pTypes[n2*2+0]) || (!bExactMatch && IsEqualGUID(pPin->lpMediaType[n1].clsMajorType,&GUID_NULL)) )
374                                 {
375                                         if ( IsEqualGUID(pPin->lpMediaType[n1].clsMinorType,&GUID_NULL) || IsEqualGUID(pPin->lpMediaType[n1].clsMinorType, &pTypes[n2*2+1]) || (!bExactMatch && IsEqualGUID(pPin->lpMediaType[n1].clsMinorType,&GUID_NULL)) )
376                                         {
377                                                 bMatch = TRUE;
378                                                 break;
379                                         }
380                                 }
381                         }
382                 }
383                 TRACE("Check media type %d\n",(int)bMatch);
384                 if ( !bMatch )
385                         return FALSE;
386         }
387
388         if ( pMedium != NULL )
389         {
390                 bMatch = FALSE;
391                 for ( n1 = 0; n1 < pPin->nMediums; n1++ )
392                 {
393                         if ( IsEqualGUID( &pPin->lpMedium[n1].clsMedium, &pMedium->clsMedium ) && pPin->lpMedium[n1].dw1 == pMedium->dw1 && pPin->lpMedium[n1].dw2 == pMedium->dw2 )
394                         {
395                                 bMatch = TRUE;
396                                 break;
397                         }
398                 }
399                 TRACE("Check medium %d\n",(int)bMatch);
400                 if ( !bMatch )
401                         return FALSE;
402         }
403
404         if ( pCategory != NULL )
405         {
406                 if ( pPin->clsPinCategory == NULL )
407                         return FALSE;
408                 if ( (!bExactMatch && IsEqualGUID(pCategory,&GUID_NULL)) || IsEqualGUID(pCategory,pPin->clsPinCategory) )
409                         return TRUE;
410                 return FALSE;
411         }
412
413         if ( bRender && (!(pPin->dwFlags & REG_PINFLAG_B_RENDERER)) )
414         {
415                 TRACE("not a renderer\n");
416                 return FALSE;
417         }
418
419         return TRUE;
420 }
421
422
423
424
425 /***************************************************************************
426  *
427  *      new/delete for CLSID_FilterMapper
428  *
429  */
430
431 /* can I use offsetof safely? - FIXME? */
432 static QUARTZ_IFEntry FMapIFEntries[] =
433 {
434   { &IID_IFilterMapper, offsetof(CFilterMapper,fmap)-offsetof(CFilterMapper,unk) },
435 };
436
437
438 static void QUARTZ_DestroyFilterMapper(IUnknown* punk)
439 {
440         CFilterMapper_THIS(punk,unk);
441
442         CFilterMapper_UninitIFilterMapper( This );
443 }
444
445 HRESULT QUARTZ_CreateFilterMapper(IUnknown* punkOuter,void** ppobj)
446 {
447         CFilterMapper*  pfm;
448         HRESULT hr;
449
450         TRACE("(%p,%p)\n",punkOuter,ppobj);
451
452         pfm = (CFilterMapper*)QUARTZ_AllocObj( sizeof(CFilterMapper) );
453         if ( pfm == NULL )
454                 return E_OUTOFMEMORY;
455
456         QUARTZ_IUnkInit( &pfm->unk, punkOuter );
457         hr = CFilterMapper_InitIFilterMapper( pfm );
458         if ( FAILED(hr) )
459         {
460                 QUARTZ_FreeObj( pfm );
461                 return hr;
462         }
463
464         pfm->unk.pEntries = FMapIFEntries;
465         pfm->unk.dwEntries = sizeof(FMapIFEntries)/sizeof(FMapIFEntries[0]);
466         pfm->unk.pOnFinalRelease = QUARTZ_DestroyFilterMapper;
467
468         *ppobj = (void*)(&pfm->unk);
469
470         return S_OK;
471 }
472
473 /***************************************************************************
474  *
475  *      CLSID_FilterMapper::IFilterMapper
476  *
477  */
478
479 static HRESULT WINAPI
480 IFilterMapper_fnQueryInterface(IFilterMapper* iface,REFIID riid,void** ppobj)
481 {
482         CFilterMapper_THIS(iface,fmap);
483
484         TRACE("(%p)->()\n",This);
485
486         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
487 }
488
489 static ULONG WINAPI
490 IFilterMapper_fnAddRef(IFilterMapper* iface)
491 {
492         CFilterMapper_THIS(iface,fmap);
493
494         TRACE("(%p)->()\n",This);
495
496         return IUnknown_AddRef(This->unk.punkControl);
497 }
498
499 static ULONG WINAPI
500 IFilterMapper_fnRelease(IFilterMapper* iface)
501 {
502         CFilterMapper_THIS(iface,fmap);
503
504         TRACE("(%p)->()\n",This);
505
506         return IUnknown_Release(This->unk.punkControl);
507 }
508
509
510 static HRESULT WINAPI
511 IFilterMapper_fnRegisterFilter(IFilterMapper* iface,CLSID clsid,LPCWSTR lpwszName,DWORD dwMerit)
512 {
513         CFilterMapper_THIS(iface,fmap);
514
515         FIXME("(%p)->(%s,%s,%08lx)\n",This,
516                 debugstr_guid(&clsid),debugstr_w(lpwszName),dwMerit);
517
518         /* FIXME */
519         /* FIXME - handle dwMerit! */
520         return QUARTZ_RegisterAMovieFilter(
521                 &CLSID_LegacyAmFilterCategory,
522                 &clsid,
523                 NULL, 0,
524                 lpwszName, NULL, TRUE );
525 }
526
527 static HRESULT WINAPI
528 IFilterMapper_fnRegisterFilterInstance(IFilterMapper* iface,CLSID clsid,LPCWSTR lpwszName,CLSID* pclsidMedia)
529 {
530         CFilterMapper_THIS(iface,fmap);
531         HRESULT hr;
532
533         FIXME("(%p)->()\n",This);
534
535         if ( pclsidMedia == NULL )
536                 return E_POINTER;
537         hr = CoCreateGuid(pclsidMedia);
538         if ( FAILED(hr) )
539                 return hr;
540
541         /* FIXME */
542         /* this doesn't work. */
543         /* return IFilterMapper_RegisterFilter(iface,
544                 *pclsidMedia,lpwszName,0x60000000); */
545
546         return E_NOTIMPL;
547 }
548
549 static HRESULT WINAPI
550 IFilterMapper_fnRegisterPin(IFilterMapper* iface,CLSID clsidFilter,LPCWSTR lpwszName,BOOL bRendered,BOOL bOutput,BOOL bZero,BOOL bMany,CLSID clsidReserved,LPCWSTR lpwszReserved)
551 {
552         CFilterMapper_THIS(iface,fmap);
553
554         FIXME("(%p)->() stub!\n",This);
555
556         return E_NOTIMPL;
557 }
558
559 static HRESULT WINAPI
560 IFilterMapper_fnRegisterPinType(IFilterMapper* iface,CLSID clsidFilter,LPCWSTR lpwszName,CLSID clsidMajorType,CLSID clsidSubType)
561 {
562         CFilterMapper_THIS(iface,fmap);
563
564         FIXME("(%p)->() stub!\n",This);
565
566         return E_NOTIMPL;
567 }
568
569 static HRESULT WINAPI
570 IFilterMapper_fnUnregisterFilter(IFilterMapper* iface,CLSID clsidFilter)
571 {
572         CFilterMapper_THIS(iface,fmap);
573
574         FIXME("(%p)->(%s)\n",This,debugstr_guid(&clsidFilter));
575
576         /* FIXME */
577         return QUARTZ_RegisterAMovieFilter(
578                 &CLSID_LegacyAmFilterCategory,
579                 &clsidFilter,
580                 NULL, 0, NULL, NULL, FALSE );
581 }
582
583 static HRESULT WINAPI
584 IFilterMapper_fnUnregisterFilterInstance(IFilterMapper* iface,CLSID clsidMedia)
585 {
586         CFilterMapper_THIS(iface,fmap);
587
588         FIXME("(%p)->(%s)\n",This,debugstr_guid(&clsidMedia));
589
590         /* FIXME */
591         /* this doesn't work. */
592         /* return IFilterMapper_UnregisterFilter(iface,clsidMedia); */
593
594         return E_NOTIMPL;
595 }
596
597 static HRESULT WINAPI
598 IFilterMapper_fnUnregisterPin(IFilterMapper* iface,CLSID clsidPin,LPCWSTR lpwszName)
599 {
600         CFilterMapper_THIS(iface,fmap);
601
602         FIXME("(%p)->(%s,%s) stub!\n",This,
603                 debugstr_guid(&clsidPin),debugstr_w(lpwszName));
604
605         return E_NOTIMPL;
606 }
607
608 static HRESULT WINAPI
609 IFilterMapper_fnEnumMatchingFilters(IFilterMapper* iface,IEnumRegFilters** ppobj,DWORD dwMerit,BOOL bInputNeeded,CLSID clsInMajorType,CLSID clsidSubType,BOOL bRender,BOOL bOutputNeeded,CLSID clsOutMajorType,CLSID clsOutSubType)
610 {
611         CFilterMapper_THIS(iface,fmap);
612
613         FIXME("(%p)->() stub!\n",This);
614
615         return E_NOTIMPL;
616 }
617
618
619
620 static ICOM_VTABLE(IFilterMapper) ifmap =
621 {
622         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
623         /* IUnknown fields */
624         IFilterMapper_fnQueryInterface,
625         IFilterMapper_fnAddRef,
626         IFilterMapper_fnRelease,
627         /* IFilterMapper fields */
628         IFilterMapper_fnRegisterFilter,
629         IFilterMapper_fnRegisterFilterInstance,
630         IFilterMapper_fnRegisterPin,
631         IFilterMapper_fnRegisterPinType,
632         IFilterMapper_fnUnregisterFilter,
633         IFilterMapper_fnUnregisterFilterInstance,
634         IFilterMapper_fnUnregisterPin,
635         IFilterMapper_fnEnumMatchingFilters,
636 };
637
638
639 HRESULT CFilterMapper_InitIFilterMapper( CFilterMapper* pfm )
640 {
641         TRACE("(%p)\n",pfm);
642         ICOM_VTBL(&pfm->fmap) = &ifmap;
643
644         return NOERROR;
645 }
646
647 void CFilterMapper_UninitIFilterMapper( CFilterMapper* pfm )
648 {
649         TRACE("(%p)\n",pfm);
650 }
651
652
653 /***************************************************************************
654  *
655  *      new/delete for CLSID_FilterMapper2
656  *
657  */
658
659 /* can I use offsetof safely? - FIXME? */
660 static QUARTZ_IFEntry FMap2IFEntries[] =
661 {
662   { &IID_IFilterMapper2, offsetof(CFilterMapper2,fmap2)-offsetof(CFilterMapper2,unk) },
663 };
664
665
666 static void QUARTZ_DestroyFilterMapper2(IUnknown* punk)
667 {
668         CFilterMapper2_THIS(punk,unk);
669
670         CFilterMapper2_UninitIFilterMapper2( This );
671 }
672
673 HRESULT QUARTZ_CreateFilterMapper2(IUnknown* punkOuter,void** ppobj)
674 {
675         CFilterMapper2* pfm;
676         HRESULT hr;
677
678         TRACE("(%p,%p)\n",punkOuter,ppobj);
679
680         pfm = (CFilterMapper2*)QUARTZ_AllocObj( sizeof(CFilterMapper2) );
681         if ( pfm == NULL )
682                 return E_OUTOFMEMORY;
683
684         QUARTZ_IUnkInit( &pfm->unk, punkOuter );
685         hr = CFilterMapper2_InitIFilterMapper2( pfm );
686         if ( FAILED(hr) )
687         {
688                 QUARTZ_FreeObj( pfm );
689                 return hr;
690         }
691
692         pfm->unk.pEntries = FMap2IFEntries;
693         pfm->unk.dwEntries = sizeof(FMap2IFEntries)/sizeof(FMap2IFEntries[0]);
694         pfm->unk.pOnFinalRelease = QUARTZ_DestroyFilterMapper2;
695
696         *ppobj = (void*)(&pfm->unk);
697
698         return S_OK;
699 }
700
701 /***************************************************************************
702  *
703  *      CLSID_FilterMapper2::IFilterMapper2
704  *
705  */
706
707
708 static HRESULT WINAPI
709 IFilterMapper2_fnQueryInterface(IFilterMapper2* iface,REFIID riid,void** ppobj)
710 {
711         CFilterMapper2_THIS(iface,fmap2);
712
713         TRACE("(%p)->()\n",This);
714
715         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
716 }
717
718 static ULONG WINAPI
719 IFilterMapper2_fnAddRef(IFilterMapper2* iface)
720 {
721         CFilterMapper2_THIS(iface,fmap2);
722
723         TRACE("(%p)->()\n",This);
724
725         return IUnknown_AddRef(This->unk.punkControl);
726 }
727
728 static ULONG WINAPI
729 IFilterMapper2_fnRelease(IFilterMapper2* iface)
730 {
731         CFilterMapper2_THIS(iface,fmap2);
732
733         TRACE("(%p)->()\n",This);
734
735         return IUnknown_Release(This->unk.punkControl);
736 }
737
738 static HRESULT WINAPI
739 IFilterMapper2_fnCreateCategory(IFilterMapper2* iface,REFCLSID rclsidCategory,DWORD dwMerit,LPCWSTR lpwszDesc)
740 {
741         CFilterMapper2_THIS(iface,fmap2);
742
743         FIXME("(%p)->(%s,%lu,%s) stub!\n",This,
744                 debugstr_guid(rclsidCategory),
745                 (unsigned long)dwMerit,debugstr_w(lpwszDesc));
746
747         return E_NOTIMPL;
748 }
749
750
751 static HRESULT WINAPI
752 IFilterMapper2_fnUnregisterFilter(IFilterMapper2* iface,const CLSID* pclsidCategory,const OLECHAR* lpwszInst,REFCLSID rclsidFilter)
753 {
754         CFilterMapper2_THIS(iface,fmap2);
755         WCHAR*  pwszPath = NULL;
756         HRESULT hr;
757
758         TRACE("(%p)->(%s,%s,%s)\n",This,
759                 debugstr_guid(pclsidCategory),
760                 debugstr_w(lpwszInst),
761                 debugstr_guid(rclsidFilter));
762
763         if ( pclsidCategory == NULL )
764                 pclsidCategory = &CLSID_LegacyAmFilterCategory;
765
766         hr = QUARTZ_GetFilterRegPath(
767                 &pwszPath, pclsidCategory, rclsidFilter, lpwszInst );
768         if ( FAILED(hr) )
769                 return hr;
770
771         hr = QUARTZ_RegDeleteKey(HKEY_CLASSES_ROOT,pwszPath);
772         QUARTZ_FreeMem(pwszPath);
773
774         return hr;
775 }
776
777
778 static HRESULT WINAPI
779 IFilterMapper2_fnRegisterFilter(IFilterMapper2* iface,REFCLSID rclsidFilter,LPCWSTR lpName,IMoniker** ppMoniker,const CLSID* pclsidCategory,const OLECHAR* lpwszInst,const REGFILTER2* pRF2)
780 {
781         CFilterMapper2_THIS(iface,fmap2);
782         WCHAR*  pwszPath = NULL;
783         IMoniker*       pMoniker = NULL;
784         BYTE*   pFilterData = NULL;
785         DWORD   cbFilterData = 0;
786         HRESULT hr;
787
788         TRACE( "(%p)->(%s,%s,%p,%s,%s,%p) stub!\n",This,
789                 debugstr_guid(rclsidFilter),debugstr_w(lpName),
790                 ppMoniker,debugstr_guid(pclsidCategory),
791                 debugstr_w(lpwszInst),pRF2 );
792
793         if ( lpName == NULL || pRF2 == NULL )
794                 return E_POINTER;
795
796         if ( ppMoniker != NULL && *ppMoniker != NULL )
797         {
798                 FIXME( "ppMoniker != NULL - not implemented! *ppMoniker = %p\n",*ppMoniker );
799                 return E_NOTIMPL;
800         }
801
802         if ( pclsidCategory == NULL )
803                 pclsidCategory = &CLSID_LegacyAmFilterCategory;
804
805         if ( pMoniker == NULL )
806         {
807                 hr = QUARTZ_GetFilterRegPath(
808                         &pwszPath, pclsidCategory, rclsidFilter, lpwszInst );
809                 if ( FAILED(hr) )
810                         return hr;
811                 hr = QUARTZ_CreateDeviceMoniker(
812                         HKEY_CLASSES_ROOT,pwszPath,&pMoniker);
813                 QUARTZ_FreeMem(pwszPath);
814                 if ( FAILED(hr) )
815                         return hr;
816         }
817
818         pFilterData = QUARTZ_RegFilterToFilterData( pRF2, &cbFilterData );
819         if ( pFilterData == NULL || cbFilterData == 0 )
820         {
821                 hr = E_FAIL;
822                 goto err;
823         }
824
825         hr = QUARTZ_RegisterFilterToMoniker(
826                 pMoniker, rclsidFilter, lpName, pFilterData, cbFilterData );
827         if ( FAILED(hr) )
828                 goto err;
829
830         if ( ppMoniker != NULL )
831         {
832                 *ppMoniker = pMoniker;
833                 pMoniker = NULL;
834         }
835 err:
836         if ( pFilterData != NULL )
837                 QUARTZ_FreeMem(pFilterData);
838         if ( pMoniker != NULL )
839                 IMoniker_Release(pMoniker);
840
841         return hr;
842 }
843
844 struct MATCHED_ITEM
845 {
846         IMoniker*       pMonFilter;
847         DWORD           dwMerit;
848 };
849
850 static int sort_comp_merit(const void* p1,const void* p2)
851 {
852         const struct MATCHED_ITEM*      pItem1 = (const struct MATCHED_ITEM*)p1;
853         const struct MATCHED_ITEM*      pItem2 = (const struct MATCHED_ITEM*)p2;
854
855         return (int)pItem2->dwMerit - (int)pItem1->dwMerit;
856 }
857
858 static HRESULT WINAPI
859 IFilterMapper2_fnEnumMatchingFilters(IFilterMapper2* iface,
860         IEnumMoniker** ppEnumMoniker,DWORD dwFlags,BOOL bExactMatch,DWORD dwMerit,
861         BOOL bInputNeeded,DWORD cInputTypes,const GUID* pguidInputTypes,const REGPINMEDIUM* pPinMediumIn,const CLSID* pPinCategoryIn,BOOL bRender,
862         BOOL bOutputNeeded,DWORD cOutputTypes,const GUID* pguidOutputTypes,const REGPINMEDIUM* pPinMediumOut,const CLSID* pPinCategoryOut)
863 {
864         CFilterMapper2_THIS(iface,fmap2);
865         ICreateDevEnum* pEnum = NULL;
866         IEnumMoniker*   pCategories = NULL;
867         IMoniker*       pCat = NULL;
868         DWORD   dwCatMerit;
869         IEnumMoniker*   pCatFilters = NULL;
870         IMoniker*       pFilter = NULL;
871         CLSID   clsid;
872         ULONG   cReturned;
873         BYTE*   pbFilterData = NULL;
874         DWORD   cbFilterData = 0;
875         REGFILTER2*     prf2 = NULL;
876         QUARTZ_CompList*        pListFilters = NULL;
877         struct MATCHED_ITEM*    pItems = NULL;
878         struct MATCHED_ITEM*    pItemsTmp;
879         int                     cItems = 0;
880         const REGFILTERPINS2*   pRegFilterPin;
881         DWORD   n;
882         BOOL    bMatch;
883         HRESULT hr;
884
885         FIXME("(%p)->(%p,%08lx,%d,%08lx,%d,%lu,%p,%p,%p,%d,%d,%lu,%p,%p,%p)\n",This,ppEnumMoniker,dwFlags,bExactMatch,dwMerit,bInputNeeded,cInputTypes,pguidInputTypes,pPinMediumIn,pPinCategoryIn,bRender,bOutputNeeded,cOutputTypes,pguidOutputTypes,pPinMediumOut,pPinCategoryOut);
886
887         if ( ppEnumMoniker == NULL )
888                 return E_POINTER;
889         *ppEnumMoniker = NULL;
890         if ( dwFlags != 0 )
891                 return E_INVALIDARG;
892
893         hr = CoCreateInstance(
894                 &CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
895                 &IID_ICreateDevEnum, (void**)&pEnum );
896         if ( FAILED(hr) )
897                 goto err;
898
899         hr = ICreateDevEnum_CreateClassEnumerator(pEnum,&CLSID_ActiveMovieCategories,&pCategories,0);
900         if ( hr != S_OK )
901                 goto err;
902
903         while ( 1 )
904         {
905                 if ( pCat != NULL )
906                 {
907                         IMoniker_Release(pCat);
908                         pCat = NULL;
909                 }
910                 hr = IEnumMoniker_Next(pCategories,1,&pCat,&cReturned);
911                 if ( FAILED(hr) )
912                         goto err;
913                 if ( hr != S_OK )
914                         break;
915                 hr = QUARTZ_GetMeritFromMoniker(pCat,&dwCatMerit);
916                 if ( hr != S_OK || dwMerit > dwCatMerit )
917                         continue;
918                 hr = QUARTZ_GetCLSIDFromMoniker(pCat,&clsid);
919                 if ( hr != S_OK )
920                         continue;
921
922                 if ( pCatFilters != NULL )
923                 {
924                         IEnumMoniker_Release(pCatFilters);
925                         pCatFilters = NULL;
926                 }
927                 hr = ICreateDevEnum_CreateClassEnumerator(pEnum,&clsid,&pCatFilters,0);
928                 if ( FAILED(hr) )
929                         goto err;
930                 if ( hr != S_OK )
931                         continue;
932
933                 while ( 1 )
934                 {
935                         if ( pFilter != NULL )
936                         {
937                                 IMoniker_Release(pFilter);
938                                 pFilter = NULL;
939                         }
940                         hr = IEnumMoniker_Next(pCatFilters,1,&pFilter,&cReturned);
941                         if ( FAILED(hr) )
942                                 goto err;
943                         if ( hr != S_OK )
944                                 break;
945                         if ( pbFilterData != NULL )
946                         {
947                                 QUARTZ_FreeMem(pbFilterData);
948                                 pbFilterData = NULL;
949                         }
950                         if(TRACE_ON(quartz))
951                         {
952                                 CLSID clsidTrace;
953                                 if (SUCCEEDED(QUARTZ_GetCLSIDFromMoniker(pFilter,&clsidTrace)))
954                                 {
955                                         TRACE("moniker clsid %s\n",debugstr_guid(&clsidTrace));
956                                 }
957                         }
958                         hr = QUARTZ_GetFilterDataFromMoniker(pFilter,&pbFilterData,&cbFilterData);
959                         if ( hr != S_OK )
960                                 continue;
961
962                         if ( prf2 != NULL )
963                         {
964                                 QUARTZ_FreeMem(prf2);
965                                 prf2 = NULL;
966                         }
967                         prf2 = QUARTZ_RegFilterV2FromFilterData(pbFilterData,cbFilterData);
968                         if ( prf2 == NULL )
969                                 continue;
970                         TRACE("prf2 %p, Merit %08lx\n",prf2,prf2->dwMerit);
971                         if ( prf2->dwMerit < dwMerit || prf2->dwVersion != 2 )
972                                 continue;
973
974                         /* check input pins. */
975                         if ( bInputNeeded )
976                         {
977                                 bMatch = FALSE;
978                                 for ( n = 0; n < prf2->u.s2.cPins2; n++ )
979                                 {
980                                         pRegFilterPin = &prf2->u.s2.rgPins2[n];
981                                         if ( pRegFilterPin->dwFlags & REG_PINFLAG_B_OUTPUT )
982                                                 continue;
983                                         bMatch = QUARTZ_CheckPinType( bExactMatch, pRegFilterPin, cInputTypes, pguidInputTypes, pPinMediumIn, pPinCategoryIn, bRender );
984                                         if ( bMatch )
985                                                 break;
986                                 }
987                                 if ( !bMatch )
988                                 {
989                                         TRACE("no matching input pin\n");
990                                         continue;
991                                 }
992                         }
993
994                         /* check output pins. */
995                         if ( bOutputNeeded )
996                         {
997                                 bMatch = FALSE;
998                                 for ( n = 0; n < prf2->u.s2.cPins2; n++ )
999                                 {
1000                                         pRegFilterPin = &prf2->u.s2.rgPins2[n];
1001                                         if ( !(pRegFilterPin->dwFlags & REG_PINFLAG_B_OUTPUT) )
1002                                                 continue;
1003                                         bMatch = QUARTZ_CheckPinType( bExactMatch, pRegFilterPin, cOutputTypes, pguidOutputTypes, pPinMediumOut, pPinCategoryOut, FALSE );
1004                                         if ( bMatch )
1005                                                 break;
1006                                 }
1007                                 if ( !bMatch )
1008                                 {
1009                                         TRACE("no matching output pin\n");
1010                                         continue;
1011                                 }
1012                         }
1013
1014                         /* matched - add pFilter to the list. */
1015                         pItemsTmp = QUARTZ_ReallocMem( pItems, sizeof(struct MATCHED_ITEM) * (cItems+1) );
1016                         if ( pItemsTmp == NULL )
1017                         {
1018                                 hr = E_OUTOFMEMORY;
1019                                 goto err;
1020                         }
1021                         pItems = pItemsTmp;
1022                         pItemsTmp = pItems + cItems; cItems ++;
1023                         pItemsTmp->pMonFilter = pFilter; pFilter = NULL;
1024                         pItemsTmp->dwMerit = prf2->dwMerit;
1025                 }
1026         }
1027
1028         if ( pItems == NULL || cItems == 0 )
1029         {
1030                 hr = S_FALSE;
1031                 goto err;
1032         }
1033
1034         /* FIXME - sort in Merit order */
1035         TRACE("sort in Merit order\n");
1036         qsort( pItems, cItems, sizeof(struct MATCHED_ITEM), sort_comp_merit );
1037
1038         pListFilters = QUARTZ_CompList_Alloc();
1039         if ( pListFilters == NULL )
1040         {
1041                 hr = E_OUTOFMEMORY;
1042                 goto err;
1043         }
1044         for ( n = 0; n < cItems; n++ )
1045         {
1046                 TRACE("merit %08lx\n",pItems[n].dwMerit);
1047                 hr = QUARTZ_CompList_AddComp( pListFilters, (IUnknown*)pItems[n].pMonFilter, NULL, 0 );
1048                 if ( FAILED(hr) )
1049                         goto err;
1050         }
1051
1052         hr = QUARTZ_CreateEnumUnknown( &IID_IEnumMoniker, (void**)ppEnumMoniker, pListFilters );
1053         if ( FAILED(hr) )
1054                 goto err;
1055
1056         hr = S_OK;
1057 err:
1058         if ( pEnum != NULL )
1059                 ICreateDevEnum_Release(pEnum);
1060         if ( pCategories != NULL )
1061                 IEnumMoniker_Release(pCategories);
1062         if ( pCat != NULL )
1063                 IMoniker_Release(pCat);
1064         if ( pCatFilters != NULL )
1065                 IEnumMoniker_Release(pCatFilters);
1066         if ( pFilter != NULL )
1067                 IMoniker_Release(pFilter);
1068         if ( pbFilterData != NULL )
1069                 QUARTZ_FreeMem(pbFilterData);
1070         if ( prf2 != NULL )
1071                 QUARTZ_FreeMem(prf2);
1072         if ( pItems != NULL && cItems > 0 )
1073         {
1074                 for ( n = 0; n < cItems; n++ )
1075                 {
1076                         if ( pItems[n].pMonFilter != NULL )
1077                                 IMoniker_Release(pItems[n].pMonFilter);
1078                 }
1079                 QUARTZ_FreeMem(pItems);
1080         }
1081         if ( pListFilters != NULL )
1082                 QUARTZ_CompList_Free( pListFilters );
1083
1084         TRACE("returns %08lx\n",hr);
1085
1086         return hr;
1087 }
1088
1089
1090
1091
1092 static ICOM_VTABLE(IFilterMapper2) ifmap2 =
1093 {
1094         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1095         /* IUnknown fields */
1096         IFilterMapper2_fnQueryInterface,
1097         IFilterMapper2_fnAddRef,
1098         IFilterMapper2_fnRelease,
1099         /* IFilterMapper2 fields */
1100         IFilterMapper2_fnCreateCategory,
1101         IFilterMapper2_fnUnregisterFilter,
1102         IFilterMapper2_fnRegisterFilter,
1103         IFilterMapper2_fnEnumMatchingFilters,
1104 };
1105
1106
1107 HRESULT CFilterMapper2_InitIFilterMapper2( CFilterMapper2* pfm )
1108 {
1109         TRACE("(%p)\n",pfm);
1110         ICOM_VTBL(&pfm->fmap2) = &ifmap2;
1111
1112         return NOERROR;
1113 }
1114
1115 void CFilterMapper2_UninitIFilterMapper2( CFilterMapper2* pfm )
1116 {
1117         TRACE("(%p)\n",pfm);
1118 }
1119