Fix segmentation fault caused by incorrect referencing of client audio
[wine] / dlls / quartz / 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 "quartz_private.h"
22
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
26
27 HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
28 {
29     memcpy(pDest, pSrc, sizeof(AM_MEDIA_TYPE));
30     if (!pSrc->pbFormat) return S_OK;
31     if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
32         return E_OUTOFMEMORY;
33     memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
34     return S_OK;
35 }
36
37 void FreeMediaType(AM_MEDIA_TYPE * pMediaType)
38 {
39     if (pMediaType->pbFormat)
40     {
41         CoTaskMemFree(pMediaType->pbFormat);
42         pMediaType->pbFormat = NULL;
43     }
44     if (pMediaType->pUnk)
45     {
46         IUnknown_Release(pMediaType->pUnk);
47         pMediaType->pUnk = NULL;
48     }
49 }
50
51 void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
52 {
53     FreeMediaType(pMediaType);
54     CoTaskMemFree(pMediaType);
55 }
56
57
58 BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
59 {
60     TRACE("pmt1: ");
61     dump_AM_MEDIA_TYPE(pmt1);
62     TRACE("pmt2: ");
63     dump_AM_MEDIA_TYPE(pmt2);
64     return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
65             ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL)   || IsEqualGUID(&pmt2->subtype, &GUID_NULL)))   || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
66 }
67
68 void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt)
69 {
70     if (!pmt)
71         return;
72     TRACE("\t%s\n\t%s\n\t...\n\t%s\n", qzdebugstr_guid(&pmt->majortype), qzdebugstr_guid(&pmt->subtype), qzdebugstr_guid(&pmt->formattype));
73 }
74
75 typedef struct IEnumMediaTypesImpl
76 {
77     const IEnumMediaTypesVtbl * lpVtbl;
78     ULONG refCount;
79     ENUMMEDIADETAILS enumMediaDetails;
80     ULONG uIndex;
81 } IEnumMediaTypesImpl;
82
83 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
84
85 HRESULT IEnumMediaTypesImpl_Construct(const ENUMMEDIADETAILS * pDetails, IEnumMediaTypes ** ppEnum)
86 {
87     ULONG i;
88     IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
89
90     if (!pEnumMediaTypes)
91     {
92         *ppEnum = NULL;
93         return E_OUTOFMEMORY;
94     }
95     pEnumMediaTypes->lpVtbl = &IEnumMediaTypesImpl_Vtbl;
96     pEnumMediaTypes->refCount = 1;
97     pEnumMediaTypes->uIndex = 0;
98     pEnumMediaTypes->enumMediaDetails.cMediaTypes = pDetails->cMediaTypes;
99     pEnumMediaTypes->enumMediaDetails.pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * pDetails->cMediaTypes);
100     for (i = 0; i < pDetails->cMediaTypes; i++)
101         if (FAILED(CopyMediaType(&pEnumMediaTypes->enumMediaDetails.pMediaTypes[i], &pDetails->pMediaTypes[i]))) {
102            while (i--)
103               CoTaskMemFree(pEnumMediaTypes->enumMediaDetails.pMediaTypes[i].pbFormat);
104            CoTaskMemFree(pEnumMediaTypes->enumMediaDetails.pMediaTypes);
105            return E_OUTOFMEMORY;
106         }
107     *ppEnum = (IEnumMediaTypes *)(&pEnumMediaTypes->lpVtbl);
108     return S_OK;
109 }
110
111 static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
112 {
113     TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
114
115     *ppv = NULL;
116
117     if (IsEqualIID(riid, &IID_IUnknown))
118         *ppv = (LPVOID)iface;
119     else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
120         *ppv = (LPVOID)iface;
121
122     if (*ppv)
123     {
124         IUnknown_AddRef((IUnknown *)(*ppv));
125         return S_OK;
126     }
127
128     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
129
130     return E_NOINTERFACE;
131 }
132
133 static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
134 {
135     IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
136     ULONG refCount = InterlockedIncrement(&This->refCount);
137
138     TRACE("()\n");
139
140     return refCount;
141 }
142
143 static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
144 {
145     IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
146     ULONG refCount = InterlockedDecrement(&This->refCount);
147
148     TRACE("()\n");
149
150     if (!refCount)
151     {
152         int i;
153         for (i = 0; i < This->enumMediaDetails.cMediaTypes; i++)
154             if (This->enumMediaDetails.pMediaTypes[i].pbFormat)
155                 CoTaskMemFree(This->enumMediaDetails.pMediaTypes[i].pbFormat);
156         CoTaskMemFree(This->enumMediaDetails.pMediaTypes);
157         CoTaskMemFree(This);
158     }
159     return refCount;
160 }
161
162 static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
163 {
164     ULONG cFetched; 
165     IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
166
167     cFetched = min(This->enumMediaDetails.cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
168
169     TRACE("(%lu, %p, %p)\n", cMediaTypes, ppMediaTypes, pcFetched);
170     TRACE("Next uIndex: %lu, cFetched: %lu\n", This->uIndex, cFetched);
171
172     if (cFetched > 0)
173     {
174         ULONG i;
175         *ppMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cFetched);
176         for (i = 0; i < cFetched; i++)
177             if (FAILED(CopyMediaType(&(*ppMediaTypes)[i], &This->enumMediaDetails.pMediaTypes[This->uIndex + i]))) {
178                 while (i--)
179                     CoTaskMemFree((*ppMediaTypes)[i].pbFormat);
180                 CoTaskMemFree(*ppMediaTypes);
181                 *ppMediaTypes = NULL;
182                 return E_OUTOFMEMORY;
183             }
184     }
185
186     if ((cMediaTypes != 1) || pcFetched)
187         *pcFetched = cFetched;
188
189     This->uIndex += cFetched;
190
191     if (cFetched != cMediaTypes)
192         return S_FALSE;
193     return S_OK;
194 }
195
196 static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
197 {
198     IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
199
200     TRACE("(%lu)\n", cMediaTypes);
201
202     if (This->uIndex + cMediaTypes < This->enumMediaDetails.cMediaTypes)
203     {
204         This->uIndex += cMediaTypes;
205         return S_OK;
206     }
207     return S_FALSE;
208 }
209
210 static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
211 {
212     IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
213
214     TRACE("()\n");
215
216     This->uIndex = 0;
217     return S_OK;
218 }
219
220 static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
221 {
222     HRESULT hr;
223     IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
224
225     TRACE("(%p)\n", ppEnum);
226
227     hr = IEnumMediaTypesImpl_Construct(&This->enumMediaDetails, ppEnum);
228     if (FAILED(hr))
229         return hr;
230     return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
231 }
232
233 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
234 {
235     IEnumMediaTypesImpl_QueryInterface,
236     IEnumMediaTypesImpl_AddRef,
237     IEnumMediaTypesImpl_Release,
238     IEnumMediaTypesImpl_Next,
239     IEnumMediaTypesImpl_Skip,
240     IEnumMediaTypesImpl_Reset,
241     IEnumMediaTypesImpl_Clone
242 };