1c2c66affSColin Finck /*
2c2c66affSColin Finck  * Copyright 2009 Vincent Povirk for CodeWeavers
3c2c66affSColin Finck  * Copyright 2013 Ludger Sprenker
4c2c66affSColin Finck  *
5c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
6c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
7c2c66affSColin Finck  * License as published by the Free Software Foundation; either
8c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
9c2c66affSColin Finck  *
10c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
11c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13c2c66affSColin Finck  * Lesser General Public License for more details.
14c2c66affSColin Finck  *
15c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
16c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
17c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18c2c66affSColin Finck  */
19c2c66affSColin Finck 
20*ae80686dSAmine Khaldi #include "config.h"
21*ae80686dSAmine Khaldi 
22*ae80686dSAmine Khaldi #include <stdarg.h>
23*ae80686dSAmine Khaldi 
24*ae80686dSAmine Khaldi #define COBJMACROS
25*ae80686dSAmine Khaldi 
26*ae80686dSAmine Khaldi #include "windef.h"
27*ae80686dSAmine Khaldi #include "winbase.h"
28*ae80686dSAmine Khaldi #include "objbase.h"
29*ae80686dSAmine Khaldi #include "wine/unicode.h"
30*ae80686dSAmine Khaldi 
31c2c66affSColin Finck #include "wincodecs_private.h"
32c2c66affSColin Finck 
33*ae80686dSAmine Khaldi #include "wine/debug.h"
34*ae80686dSAmine Khaldi 
35*ae80686dSAmine Khaldi WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
36*ae80686dSAmine Khaldi 
37c2c66affSColin Finck typedef struct PropertyBag {
38c2c66affSColin Finck     IPropertyBag2 IPropertyBag2_iface;
39c2c66affSColin Finck     LONG ref;
40c2c66affSColin Finck     UINT prop_count;
41c2c66affSColin Finck     PROPBAG2 *properties;
42c2c66affSColin Finck     VARIANT *values;
43c2c66affSColin Finck } PropertyBag;
44c2c66affSColin Finck 
impl_from_IPropertyBag2(IPropertyBag2 * iface)45c2c66affSColin Finck static inline PropertyBag *impl_from_IPropertyBag2(IPropertyBag2 *iface)
46c2c66affSColin Finck {
47c2c66affSColin Finck     return CONTAINING_RECORD(iface, PropertyBag, IPropertyBag2_iface);
48c2c66affSColin Finck }
49c2c66affSColin Finck 
PropertyBag_QueryInterface(IPropertyBag2 * iface,REFIID iid,void ** ppv)50c2c66affSColin Finck static HRESULT WINAPI PropertyBag_QueryInterface(IPropertyBag2 *iface, REFIID iid,
51c2c66affSColin Finck     void **ppv)
52c2c66affSColin Finck {
53c2c66affSColin Finck     PropertyBag *This = impl_from_IPropertyBag2(iface);
54c2c66affSColin Finck     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
55c2c66affSColin Finck 
56c2c66affSColin Finck     if (!ppv) return E_INVALIDARG;
57c2c66affSColin Finck 
58c2c66affSColin Finck     if (IsEqualIID(&IID_IUnknown, iid) ||
59c2c66affSColin Finck         IsEqualIID(&IID_IPropertyBag2, iid))
60c2c66affSColin Finck     {
61c2c66affSColin Finck         *ppv = &This->IPropertyBag2_iface;
62c2c66affSColin Finck     }
63c2c66affSColin Finck     else
64c2c66affSColin Finck     {
65c2c66affSColin Finck         *ppv = NULL;
66c2c66affSColin Finck         return E_NOINTERFACE;
67c2c66affSColin Finck     }
68c2c66affSColin Finck 
69c2c66affSColin Finck     IUnknown_AddRef((IUnknown*)*ppv);
70c2c66affSColin Finck     return S_OK;
71c2c66affSColin Finck }
72c2c66affSColin Finck 
PropertyBag_AddRef(IPropertyBag2 * iface)73c2c66affSColin Finck static ULONG WINAPI PropertyBag_AddRef(IPropertyBag2 *iface)
74c2c66affSColin Finck {
75c2c66affSColin Finck     PropertyBag *This = impl_from_IPropertyBag2(iface);
76c2c66affSColin Finck     ULONG ref = InterlockedIncrement(&This->ref);
77c2c66affSColin Finck 
78c2c66affSColin Finck     TRACE("(%p) refcount=%u\n", iface, ref);
79c2c66affSColin Finck 
80c2c66affSColin Finck     return ref;
81c2c66affSColin Finck }
82c2c66affSColin Finck 
PropertyBag_Release(IPropertyBag2 * iface)83c2c66affSColin Finck static ULONG WINAPI PropertyBag_Release(IPropertyBag2 *iface)
84c2c66affSColin Finck {
85c2c66affSColin Finck     PropertyBag *This = impl_from_IPropertyBag2(iface);
86c2c66affSColin Finck     ULONG ref = InterlockedDecrement(&This->ref);
87c2c66affSColin Finck 
88c2c66affSColin Finck     TRACE("(%p) refcount=%u\n", iface, ref);
89c2c66affSColin Finck 
90c2c66affSColin Finck     if (ref == 0)
91c2c66affSColin Finck     {
92c2c66affSColin Finck         ULONG i;
93c2c66affSColin Finck         if (This->properties && This->values)
94c2c66affSColin Finck         {
95c2c66affSColin Finck             for (i=0; i < This->prop_count; i++)
96c2c66affSColin Finck             {
97c2c66affSColin Finck                 CoTaskMemFree(This->properties[i].pstrName);
98c2c66affSColin Finck                 VariantClear( This->values+i );
99c2c66affSColin Finck             }
100c2c66affSColin Finck         }
101c2c66affSColin Finck 
102c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, This->properties);
103c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, This->values);
104c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, This);
105c2c66affSColin Finck     }
106c2c66affSColin Finck 
107c2c66affSColin Finck     return ref;
108c2c66affSColin Finck }
109c2c66affSColin Finck 
find_item(PropertyBag * This,LPCOLESTR name)110c2c66affSColin Finck static LONG find_item(PropertyBag *This, LPCOLESTR name)
111c2c66affSColin Finck {
112c2c66affSColin Finck     LONG i;
113c2c66affSColin Finck     if (!This->properties)
114c2c66affSColin Finck         return -1;
115c2c66affSColin Finck     if (!name)
116c2c66affSColin Finck         return -1;
117c2c66affSColin Finck 
118c2c66affSColin Finck     for (i=0; i < This->prop_count; i++)
119c2c66affSColin Finck     {
120c2c66affSColin Finck         if (strcmpW(name, This->properties[i].pstrName) == 0)
121c2c66affSColin Finck             return i;
122c2c66affSColin Finck     }
123c2c66affSColin Finck 
124c2c66affSColin Finck     return -1;
125c2c66affSColin Finck }
126c2c66affSColin Finck 
PropertyBag_Read(IPropertyBag2 * iface,ULONG cProperties,PROPBAG2 * pPropBag,IErrorLog * pErrLog,VARIANT * pvarValue,HRESULT * phrError)127c2c66affSColin Finck static HRESULT WINAPI PropertyBag_Read(IPropertyBag2 *iface, ULONG cProperties,
128c2c66affSColin Finck     PROPBAG2 *pPropBag, IErrorLog *pErrLog, VARIANT *pvarValue, HRESULT *phrError)
129c2c66affSColin Finck {
130c2c66affSColin Finck     HRESULT res = S_OK;
131c2c66affSColin Finck     ULONG i;
132c2c66affSColin Finck     PropertyBag *This = impl_from_IPropertyBag2(iface);
133c2c66affSColin Finck 
134c2c66affSColin Finck     TRACE("(%p,%u,%p,%p,%p,%p)\n", iface, cProperties, pPropBag, pErrLog, pvarValue, phrError);
135c2c66affSColin Finck 
136c2c66affSColin Finck     for (i=0; i < cProperties; i++)
137c2c66affSColin Finck     {
138c2c66affSColin Finck         LONG idx;
139c2c66affSColin Finck         if (pPropBag[i].dwHint && pPropBag[i].dwHint <= This->prop_count)
140c2c66affSColin Finck             idx = pPropBag[i].dwHint-1;
141c2c66affSColin Finck         else
142c2c66affSColin Finck             idx = find_item(This, pPropBag[i].pstrName);
143c2c66affSColin Finck 
144c2c66affSColin Finck         if (idx > -1)
145c2c66affSColin Finck         {
146c2c66affSColin Finck             VariantInit(pvarValue+i);
147c2c66affSColin Finck             res = VariantCopy(pvarValue+i, This->values+idx);
148c2c66affSColin Finck             if (FAILED(res))
149c2c66affSColin Finck                 break;
150c2c66affSColin Finck             phrError[i] = res;
151c2c66affSColin Finck         }
152c2c66affSColin Finck         else
153c2c66affSColin Finck         {
154c2c66affSColin Finck             res = E_FAIL;
155c2c66affSColin Finck             break;
156c2c66affSColin Finck         }
157c2c66affSColin Finck     }
158c2c66affSColin Finck 
159c2c66affSColin Finck     return res;
160c2c66affSColin Finck }
161c2c66affSColin Finck 
PropertyBag_Write(IPropertyBag2 * iface,ULONG cProperties,PROPBAG2 * pPropBag,VARIANT * pvarValue)162c2c66affSColin Finck static HRESULT WINAPI PropertyBag_Write(IPropertyBag2 *iface, ULONG cProperties,
163c2c66affSColin Finck     PROPBAG2 *pPropBag, VARIANT *pvarValue)
164c2c66affSColin Finck {
165c2c66affSColin Finck     HRESULT res = S_OK;
166c2c66affSColin Finck     ULONG i;
167c2c66affSColin Finck     PropertyBag *This = impl_from_IPropertyBag2(iface);
168c2c66affSColin Finck 
169c2c66affSColin Finck     TRACE("(%p,%u,%p,%p)\n", iface, cProperties, pPropBag, pvarValue);
170c2c66affSColin Finck 
171c2c66affSColin Finck     for (i=0; i < cProperties; i++)
172c2c66affSColin Finck     {
173c2c66affSColin Finck         LONG idx;
174c2c66affSColin Finck         if (pPropBag[i].dwHint && pPropBag[i].dwHint <= This->prop_count)
175c2c66affSColin Finck             idx = pPropBag[i].dwHint-1;
176c2c66affSColin Finck         else
177c2c66affSColin Finck             idx = find_item(This, pPropBag[i].pstrName);
178c2c66affSColin Finck 
179c2c66affSColin Finck         if (idx > -1)
180c2c66affSColin Finck         {
181c2c66affSColin Finck             if (This->properties[idx].vt != V_VT(pvarValue+i))
182c2c66affSColin Finck                 return WINCODEC_ERR_PROPERTYUNEXPECTEDTYPE;
183c2c66affSColin Finck             res = VariantCopy(This->values+idx, pvarValue+i);
184c2c66affSColin Finck             if (FAILED(res))
185c2c66affSColin Finck                 return E_FAIL;
186c2c66affSColin Finck         }
187c2c66affSColin Finck         else
188c2c66affSColin Finck         {
189c2c66affSColin Finck             if (pPropBag[i].pstrName)
190c2c66affSColin Finck                 FIXME("Application tried to set the unknown option %s.\n",
191c2c66affSColin Finck                       debugstr_w(pPropBag[i].pstrName));
192c2c66affSColin Finck 
193c2c66affSColin Finck             /* FIXME: Function is not atomar on error, but MSDN does not say anything about it
194c2c66affSColin Finck              *        (no reset of items between 0 and i-1) */
195c2c66affSColin Finck             return E_FAIL;
196c2c66affSColin Finck         }
197c2c66affSColin Finck     }
198c2c66affSColin Finck 
199c2c66affSColin Finck     return res;
200c2c66affSColin Finck }
201c2c66affSColin Finck 
PropertyBag_CountProperties(IPropertyBag2 * iface,ULONG * pcProperties)202c2c66affSColin Finck static HRESULT WINAPI PropertyBag_CountProperties(IPropertyBag2 *iface, ULONG *pcProperties)
203c2c66affSColin Finck {
204c2c66affSColin Finck     PropertyBag *This = impl_from_IPropertyBag2(iface);
205c2c66affSColin Finck 
206c2c66affSColin Finck     TRACE("(%p,%p)\n", iface, pcProperties);
207c2c66affSColin Finck 
208c2c66affSColin Finck     if (!pcProperties)
209c2c66affSColin Finck         return E_INVALIDARG;
210c2c66affSColin Finck 
211c2c66affSColin Finck     *pcProperties = This->prop_count;
212c2c66affSColin Finck 
213c2c66affSColin Finck     return S_OK;
214c2c66affSColin Finck }
215c2c66affSColin Finck 
copy_propbag2(PROPBAG2 * dest,const PROPBAG2 * src)216*ae80686dSAmine Khaldi static HRESULT copy_propbag2(PROPBAG2 *dest, const PROPBAG2 *src)
217c2c66affSColin Finck {
218c2c66affSColin Finck     dest->cfType = src->cfType;
219c2c66affSColin Finck     dest->clsid = src->clsid;
220c2c66affSColin Finck     dest->dwHint = src->dwHint;
221c2c66affSColin Finck     dest->dwType = src->dwType;
222c2c66affSColin Finck     dest->vt = src->vt;
223c2c66affSColin Finck     dest->pstrName = CoTaskMemAlloc((strlenW(src->pstrName)+1) * sizeof(WCHAR));
224c2c66affSColin Finck     if(!dest->pstrName)
225c2c66affSColin Finck         return E_OUTOFMEMORY;
226c2c66affSColin Finck 
227c2c66affSColin Finck     strcpyW(dest->pstrName, src->pstrName);
228c2c66affSColin Finck 
229c2c66affSColin Finck     return S_OK;
230c2c66affSColin Finck }
231c2c66affSColin Finck 
PropertyBag_GetPropertyInfo(IPropertyBag2 * iface,ULONG iProperty,ULONG cProperties,PROPBAG2 * pPropBag,ULONG * pcProperties)232c2c66affSColin Finck static HRESULT WINAPI PropertyBag_GetPropertyInfo(IPropertyBag2 *iface, ULONG iProperty,
233c2c66affSColin Finck     ULONG cProperties, PROPBAG2 *pPropBag, ULONG *pcProperties)
234c2c66affSColin Finck {
235c2c66affSColin Finck     HRESULT res = S_OK;
236c2c66affSColin Finck     ULONG i;
237c2c66affSColin Finck     PropertyBag *This = impl_from_IPropertyBag2(iface);
238c2c66affSColin Finck 
239c2c66affSColin Finck     TRACE("(%p,%u,%u,%p,%p)\n", iface, iProperty, cProperties, pPropBag, pcProperties);
240c2c66affSColin Finck 
241c2c66affSColin Finck     if (iProperty >= This->prop_count && iProperty > 0)
242c2c66affSColin Finck         return WINCODEC_ERR_VALUEOUTOFRANGE;
243c2c66affSColin Finck     if (iProperty+cProperties > This->prop_count )
244c2c66affSColin Finck         return WINCODEC_ERR_VALUEOUTOFRANGE;
245c2c66affSColin Finck 
246c2c66affSColin Finck     *pcProperties = min(cProperties, This->prop_count-iProperty);
247c2c66affSColin Finck 
248c2c66affSColin Finck     for (i=0; i < *pcProperties; i++)
249c2c66affSColin Finck     {
250c2c66affSColin Finck         res = copy_propbag2(pPropBag+i, This->properties+iProperty+i);
251c2c66affSColin Finck         if (FAILED(res))
252c2c66affSColin Finck         {
253c2c66affSColin Finck             do {
254c2c66affSColin Finck                 CoTaskMemFree( pPropBag[--i].pstrName );
255c2c66affSColin Finck             } while (i);
256c2c66affSColin Finck             break;
257c2c66affSColin Finck         }
258c2c66affSColin Finck     }
259c2c66affSColin Finck 
260c2c66affSColin Finck     return res;
261c2c66affSColin Finck }
262c2c66affSColin Finck 
PropertyBag_LoadObject(IPropertyBag2 * iface,LPCOLESTR pstrName,DWORD dwHint,IUnknown * pUnkObject,IErrorLog * pErrLog)263c2c66affSColin Finck static HRESULT WINAPI PropertyBag_LoadObject(IPropertyBag2 *iface, LPCOLESTR pstrName,
264c2c66affSColin Finck     DWORD dwHint, IUnknown *pUnkObject, IErrorLog *pErrLog)
265c2c66affSColin Finck {
266c2c66affSColin Finck     FIXME("(%p,%s,%u,%p,%p): stub\n", iface, debugstr_w(pstrName), dwHint, pUnkObject, pErrLog);
267c2c66affSColin Finck     return E_NOTIMPL;
268c2c66affSColin Finck }
269c2c66affSColin Finck 
270c2c66affSColin Finck static const IPropertyBag2Vtbl PropertyBag_Vtbl = {
271c2c66affSColin Finck     PropertyBag_QueryInterface,
272c2c66affSColin Finck     PropertyBag_AddRef,
273c2c66affSColin Finck     PropertyBag_Release,
274c2c66affSColin Finck     PropertyBag_Read,
275c2c66affSColin Finck     PropertyBag_Write,
276c2c66affSColin Finck     PropertyBag_CountProperties,
277c2c66affSColin Finck     PropertyBag_GetPropertyInfo,
278c2c66affSColin Finck     PropertyBag_LoadObject
279c2c66affSColin Finck };
280c2c66affSColin Finck 
CreatePropertyBag2(const PROPBAG2 * options,UINT count,IPropertyBag2 ** ppPropertyBag2)281*ae80686dSAmine Khaldi HRESULT CreatePropertyBag2(const PROPBAG2 *options, UINT count,
282c2c66affSColin Finck                            IPropertyBag2 **ppPropertyBag2)
283c2c66affSColin Finck {
284c2c66affSColin Finck     UINT i;
285c2c66affSColin Finck     HRESULT res = S_OK;
286c2c66affSColin Finck     PropertyBag *This;
287c2c66affSColin Finck 
288c2c66affSColin Finck     This = HeapAlloc(GetProcessHeap(), 0, sizeof(PropertyBag));
289c2c66affSColin Finck     if (!This) return E_OUTOFMEMORY;
290c2c66affSColin Finck 
291c2c66affSColin Finck     This->IPropertyBag2_iface.lpVtbl = &PropertyBag_Vtbl;
292c2c66affSColin Finck     This->ref = 1;
293c2c66affSColin Finck     This->prop_count = count;
294c2c66affSColin Finck 
295c2c66affSColin Finck     if (count == 0)
296c2c66affSColin Finck     {
297c2c66affSColin Finck         This->properties = NULL;
298c2c66affSColin Finck         This->values = NULL;
299c2c66affSColin Finck     }
300c2c66affSColin Finck     else
301c2c66affSColin Finck     {
302c2c66affSColin Finck         This->properties = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PROPBAG2)*count);
303c2c66affSColin Finck         This->values = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*count);
304c2c66affSColin Finck 
305c2c66affSColin Finck         if (!This->properties || !This->values)
306c2c66affSColin Finck             res = E_OUTOFMEMORY;
307c2c66affSColin Finck         else
308c2c66affSColin Finck             for (i=0; i < count; i++)
309c2c66affSColin Finck             {
310c2c66affSColin Finck                 res = copy_propbag2(This->properties+i, options+i);
311c2c66affSColin Finck                 if (FAILED(res))
312c2c66affSColin Finck                     break;
313c2c66affSColin Finck                 This->properties[i].dwHint = i+1; /* 0 means unset, so we start with 1 */
314c2c66affSColin Finck             }
315c2c66affSColin Finck     }
316c2c66affSColin Finck 
317c2c66affSColin Finck     if (FAILED(res))
318c2c66affSColin Finck     {
319c2c66affSColin Finck         PropertyBag_Release(&This->IPropertyBag2_iface);
320c2c66affSColin Finck         *ppPropertyBag2 = NULL;
321c2c66affSColin Finck     }
322c2c66affSColin Finck     else
323c2c66affSColin Finck         *ppPropertyBag2 = &This->IPropertyBag2_iface;
324c2c66affSColin Finck 
325c2c66affSColin Finck     return res;
326c2c66affSColin Finck }
327