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