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