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