Fixed qcap's inherited enummedia bugs.
[wine] / dlls / qcap / enummedia.c
1 /*
2  * Implementation of IEnumMediaTypes Interface
3  *
4  * Copyright 2003 Robert Shearman
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wtypes.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "dshow.h"
31
32 #include "qcap_main.h"
33
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(qcap);
37
38 HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
39 {
40     memcpy(pDest, pSrc, sizeof(AM_MEDIA_TYPE));
41     if (!pSrc->pbFormat) return S_OK;
42     if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
43         return E_OUTOFMEMORY;
44     memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
45     return S_OK;
46 }
47
48 void FreeMediaType(AM_MEDIA_TYPE * pMediaType)
49 {
50     if (pMediaType->pbFormat)
51     {
52         CoTaskMemFree(pMediaType->pbFormat);
53         pMediaType->pbFormat = NULL;
54     }
55     if (pMediaType->pUnk)
56     {
57         IUnknown_Release(pMediaType->pUnk);
58         pMediaType->pUnk = NULL;
59     }
60 }
61
62 void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
63 {
64    FreeMediaType(pMediaType);
65    CoTaskMemFree(pMediaType);
66 }
67
68 BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2,
69                        BOOL bWildcards)
70 {
71     TRACE("pmt1: ");
72     dump_AM_MEDIA_TYPE(pmt1);
73     TRACE("pmt2: ");
74     dump_AM_MEDIA_TYPE(pmt2);
75     return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) ||
76               IsEqualGUID(&pmt2->majortype, &GUID_NULL))) ||
77               IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
78               ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) ||
79               IsEqualGUID(&pmt2->subtype, &GUID_NULL))) ||
80               IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
81 }
82
83 void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt)
84 {
85     if (!pmt)
86         return;
87     TRACE("\t%s\n\t%s\n\t...\n\t%s\n", debugstr_guid(&pmt->majortype),
88           debugstr_guid(&pmt->subtype), debugstr_guid(&pmt->formattype));
89 }
90
91 typedef struct IEnumMediaTypesImpl
92 {
93     const IEnumMediaTypesVtbl * lpVtbl;
94     ULONG refCount;
95     ENUMMEDIADETAILS enumMediaDetails;
96     ULONG uIndex;
97 } IEnumMediaTypesImpl;
98
99 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
100
101 HRESULT IEnumMediaTypesImpl_Construct(const ENUMMEDIADETAILS * pDetails,
102                                       IEnumMediaTypes ** ppEnum)
103 {
104     ULONG i;
105     IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
106
107     if (!pEnumMediaTypes)
108     {
109         *ppEnum = NULL;
110         return E_OUTOFMEMORY;
111     }
112     ObjectRefCount(TRUE);
113     pEnumMediaTypes->lpVtbl = &IEnumMediaTypesImpl_Vtbl;
114     pEnumMediaTypes->refCount = 1;
115     pEnumMediaTypes->uIndex = 0;
116     pEnumMediaTypes->enumMediaDetails.cMediaTypes = pDetails->cMediaTypes;
117     pEnumMediaTypes->enumMediaDetails.pMediaTypes =
118                       CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * pDetails->cMediaTypes);
119     for (i = 0; i < pDetails->cMediaTypes; i++)
120         if (FAILED(CopyMediaType(&pEnumMediaTypes->enumMediaDetails.pMediaTypes[i], &pDetails->pMediaTypes[i]))) {
121            while (i--) CoTaskMemFree(pEnumMediaTypes->enumMediaDetails.pMediaTypes[i].pbFormat);
122            CoTaskMemFree(pEnumMediaTypes->enumMediaDetails.pMediaTypes);
123            return E_OUTOFMEMORY;
124         }
125     *ppEnum = (IEnumMediaTypes *)(&pEnumMediaTypes->lpVtbl);
126     return S_OK;
127 }
128
129 static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface,
130                                                          REFIID riid,
131                                                          LPVOID * ppv)
132 {
133     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
134
135     *ppv = NULL;
136
137     if (IsEqualIID(riid, &IID_IUnknown))
138         *ppv = (LPVOID)iface;
139     else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
140         *ppv = (LPVOID)iface;
141
142     if (*ppv)
143     {
144         IUnknown_AddRef((IUnknown *)(*ppv));
145         return S_OK;
146     }
147
148     FIXME("No interface for %s!\n", debugstr_guid(riid));
149
150     return E_NOINTERFACE;
151 }
152
153 static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
154 {
155     IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
156     ULONG refCount = InterlockedIncrement(&This->refCount);
157
158     TRACE("()\n");
159
160     return refCount;
161 }
162
163 static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
164 {
165     IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
166     ULONG refCount = InterlockedDecrement(&This->refCount);
167
168     TRACE("()\n");
169
170     if (!refCount)
171     {
172         int i;
173         for (i = 0; i < This->enumMediaDetails.cMediaTypes; i++)
174            if (This->enumMediaDetails.pMediaTypes[i].pbFormat)
175               CoTaskMemFree(This->enumMediaDetails.pMediaTypes[i].pbFormat);
176         CoTaskMemFree(This->enumMediaDetails.pMediaTypes);
177         CoTaskMemFree(This);
178         ObjectRefCount(FALSE);
179     }
180     return refCount;
181 }
182
183 static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface,
184                                                ULONG cMediaTypes,
185                                                AM_MEDIA_TYPE ** ppMediaTypes,
186                                                ULONG * pcFetched)
187 {
188     ULONG cFetched;
189     IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
190
191     cFetched = min(This->enumMediaDetails.cMediaTypes,
192                    This->uIndex + cMediaTypes) - This->uIndex;
193
194     TRACE("(%lu, %p, %p)\n", cMediaTypes, ppMediaTypes, pcFetched);
195     TRACE("Next uIndex: %lu, cFetched: %lu\n", This->uIndex, cFetched);
196
197     if (cFetched > 0)
198     {
199         ULONG i;
200         *ppMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cFetched);
201         for (i = 0; i < cFetched; i++)
202             if (FAILED(CopyMediaType(&(*ppMediaTypes)[i], &This->enumMediaDetails.pMediaTypes[This->uIndex + i]))) {
203                 while (i--)
204                     CoTaskMemFree((*ppMediaTypes)[i].pbFormat);
205                 CoTaskMemFree(*ppMediaTypes);
206                 *ppMediaTypes = NULL;
207                 return E_OUTOFMEMORY;
208             }
209     }
210
211     if ((cMediaTypes != 1) || pcFetched)
212         *pcFetched = cFetched;
213
214     This->uIndex += cFetched;
215
216     if (cFetched != cMediaTypes)
217         return S_FALSE;
218     return S_OK;
219 }
220
221 static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface,
222                                                ULONG cMediaTypes)
223 {
224     IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
225
226     TRACE("(%lu)\n", cMediaTypes);
227
228     if (This->uIndex + cMediaTypes < This->enumMediaDetails.cMediaTypes)
229     {
230         This->uIndex += cMediaTypes;
231         return S_OK;
232     }
233     return S_FALSE;
234 }
235
236 static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
237 {
238     IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
239
240     TRACE("()\n");
241
242     This->uIndex = 0;
243     return S_OK;
244 }
245
246 static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface,
247                                                 IEnumMediaTypes ** ppEnum)
248 {
249     HRESULT hr;
250     IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
251
252     TRACE("(%p)\n", ppEnum);
253
254     hr = IEnumMediaTypesImpl_Construct(&This->enumMediaDetails, ppEnum);
255     if (FAILED(hr))
256         return hr;
257     return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
258 }
259
260 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
261 {
262     IEnumMediaTypesImpl_QueryInterface,
263     IEnumMediaTypesImpl_AddRef,
264     IEnumMediaTypesImpl_Release,
265     IEnumMediaTypesImpl_Next,
266     IEnumMediaTypesImpl_Skip,
267     IEnumMediaTypesImpl_Reset,
268     IEnumMediaTypesImpl_Clone
269 };