/* * Copyright 2012 Vincent Povirk for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #include #define COBJMACROS #define NONAMELESSUNION #include "windef.h" #include "winbase.h" #include "objbase.h" #include "wincodec.h" #include "wincodecsdk.h" #include "wincodecs_private.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); typedef struct MetadataHandler { IWICMetadataWriter IWICMetadataWriter_iface; LONG ref; IWICPersistStream IWICPersistStream_iface; const MetadataHandlerVtbl *vtable; MetadataItem *items; DWORD item_count; CRITICAL_SECTION lock; } MetadataHandler; static inline MetadataHandler *impl_from_IWICMetadataWriter(IWICMetadataWriter *iface) { return CONTAINING_RECORD(iface, MetadataHandler, IWICMetadataWriter_iface); } static inline MetadataHandler *impl_from_IWICPersistStream(IWICPersistStream *iface) { return CONTAINING_RECORD(iface, MetadataHandler, IWICPersistStream_iface); } static void MetadataHandler_FreeItems(MetadataHandler *This) { int i; for (i=0; iitem_count; i++) { PropVariantClear(&This->items[i].schema); PropVariantClear(&This->items[i].id); PropVariantClear(&This->items[i].value); } HeapFree(GetProcessHeap(), 0, This->items); } static HRESULT MetadataHandlerEnum_Create(MetadataHandler *parent, DWORD index, IWICEnumMetadataItem **ppIEnumMetadataItem); static HRESULT WINAPI MetadataHandler_QueryInterface(IWICMetadataWriter *iface, REFIID iid, void **ppv) { MetadataHandler *This = impl_from_IWICMetadataWriter(iface); TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); if (!ppv) return E_INVALIDARG; if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICMetadataReader, iid) || (IsEqualIID(&IID_IWICMetadataWriter, iid) && This->vtable->is_writer)) { *ppv = &This->IWICMetadataWriter_iface; } else if (IsEqualIID(&IID_IPersist, iid) || IsEqualIID(&IID_IPersistStream, iid) || IsEqualIID(&IID_IWICPersistStream, iid)) { *ppv = &This->IWICPersistStream_iface; } else { *ppv = NULL; return E_NOINTERFACE; } IUnknown_AddRef((IUnknown*)*ppv); return S_OK; } static ULONG WINAPI MetadataHandler_AddRef(IWICMetadataWriter *iface) { MetadataHandler *This = impl_from_IWICMetadataWriter(iface); ULONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) refcount=%u\n", iface, ref); return ref; } static ULONG WINAPI MetadataHandler_Release(IWICMetadataWriter *iface) { MetadataHandler *This = impl_from_IWICMetadataWriter(iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) refcount=%u\n", iface, ref); if (ref == 0) { MetadataHandler_FreeItems(This); This->lock.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->lock); HeapFree(GetProcessHeap(), 0, This); } return ref; } static HRESULT WINAPI MetadataHandler_GetMetadataFormat(IWICMetadataWriter *iface, GUID *pguidMetadataFormat) { FIXME("(%p,%s): stub\n", iface, debugstr_guid(pguidMetadataFormat)); return E_NOTIMPL; } static HRESULT WINAPI MetadataHandler_GetMetadataHandlerInfo(IWICMetadataWriter *iface, IWICMetadataHandlerInfo **ppIHandler) { FIXME("(%p,%p): stub\n", iface, ppIHandler); return E_NOTIMPL; } static HRESULT WINAPI MetadataHandler_GetCount(IWICMetadataWriter *iface, UINT *pcCount) { FIXME("(%p,%p): stub\n", iface, pcCount); return E_NOTIMPL; } static HRESULT WINAPI MetadataHandler_GetValueByIndex(IWICMetadataWriter *iface, UINT nIndex, PROPVARIANT *pvarSchema, PROPVARIANT *pvarId, PROPVARIANT *pvarValue) { FIXME("(%p,%u,%p,%p,%p): stub\n", iface, nIndex, pvarSchema, pvarId, pvarValue); return E_NOTIMPL; } static HRESULT WINAPI MetadataHandler_GetValue(IWICMetadataWriter *iface, const PROPVARIANT *pvarSchema, const PROPVARIANT *pvarId, PROPVARIANT *pvarValue) { FIXME("(%p,%p,%p,%p): stub\n", iface, pvarSchema, pvarId, pvarValue); return E_NOTIMPL; } static HRESULT WINAPI MetadataHandler_GetEnumerator(IWICMetadataWriter *iface, IWICEnumMetadataItem **ppIEnumMetadata) { MetadataHandler *This = impl_from_IWICMetadataWriter(iface); TRACE("(%p,%p)\n", iface, ppIEnumMetadata); return MetadataHandlerEnum_Create(This, 0, ppIEnumMetadata); } static HRESULT WINAPI MetadataHandler_SetValue(IWICMetadataWriter *iface, const PROPVARIANT *pvarSchema, const PROPVARIANT *pvarId, const PROPVARIANT *pvarValue) { FIXME("(%p,%p,%p,%p): stub\n", iface, pvarSchema, pvarId, pvarValue); return E_NOTIMPL; } static HRESULT WINAPI MetadataHandler_SetValueByIndex(IWICMetadataWriter *iface, UINT nIndex, const PROPVARIANT *pvarSchema, const PROPVARIANT *pvarId, const PROPVARIANT *pvarValue) { FIXME("(%p,%u,%p,%p,%p): stub\n", iface, nIndex, pvarSchema, pvarId, pvarValue); return E_NOTIMPL; } static HRESULT WINAPI MetadataHandler_RemoveValue(IWICMetadataWriter *iface, const PROPVARIANT *pvarSchema, const PROPVARIANT *pvarId) { FIXME("(%p,%p,%p): stub\n", iface, pvarSchema, pvarId); return E_NOTIMPL; } static HRESULT WINAPI MetadataHandler_RemoveValueByIndex(IWICMetadataWriter *iface, UINT nIndex) { FIXME("(%p,%u): stub\n", iface, nIndex); return E_NOTIMPL; } static const IWICMetadataWriterVtbl MetadataHandler_Vtbl = { MetadataHandler_QueryInterface, MetadataHandler_AddRef, MetadataHandler_Release, MetadataHandler_GetMetadataFormat, MetadataHandler_GetMetadataHandlerInfo, MetadataHandler_GetCount, MetadataHandler_GetValueByIndex, MetadataHandler_GetValue, MetadataHandler_GetEnumerator, MetadataHandler_SetValue, MetadataHandler_SetValueByIndex, MetadataHandler_RemoveValue, MetadataHandler_RemoveValueByIndex }; static HRESULT WINAPI MetadataHandler_PersistStream_QueryInterface(IWICPersistStream *iface, REFIID iid, void **ppv) { MetadataHandler *This = impl_from_IWICPersistStream(iface); return IWICMetadataWriter_QueryInterface(&This->IWICMetadataWriter_iface, iid, ppv); } static ULONG WINAPI MetadataHandler_PersistStream_AddRef(IWICPersistStream *iface) { MetadataHandler *This = impl_from_IWICPersistStream(iface); return IWICMetadataWriter_AddRef(&This->IWICMetadataWriter_iface); } static ULONG WINAPI MetadataHandler_PersistStream_Release(IWICPersistStream *iface) { MetadataHandler *This = impl_from_IWICPersistStream(iface); return IWICMetadataWriter_Release(&This->IWICMetadataWriter_iface); } static HRESULT WINAPI MetadataHandler_GetClassID(IWICPersistStream *iface, CLSID *pClassID) { FIXME("(%p,%p): stub\n", iface, pClassID); return E_NOTIMPL; } static HRESULT WINAPI MetadataHandler_IsDirty(IWICPersistStream *iface) { FIXME("(%p): stub\n", iface); return E_NOTIMPL; } static HRESULT WINAPI MetadataHandler_Load(IWICPersistStream *iface, IStream *pStm) { FIXME("(%p,%p): stub\n", iface, pStm); return E_NOTIMPL; } static HRESULT WINAPI MetadataHandler_Save(IWICPersistStream *iface, IStream *pStm, BOOL fClearDirty) { FIXME("(%p,%p,%i): stub\n", iface, pStm, fClearDirty); return E_NOTIMPL; } static HRESULT WINAPI MetadataHandler_GetSizeMax(IWICPersistStream *iface, ULARGE_INTEGER *pcbSize) { FIXME("(%p,%p): stub\n", iface, pcbSize); return E_NOTIMPL; } static HRESULT WINAPI MetadataHandler_LoadEx(IWICPersistStream *iface, IStream *pIStream, const GUID *pguidPreferredVendor, DWORD dwPersistOptions) { MetadataHandler *This = impl_from_IWICPersistStream(iface); HRESULT hr; MetadataItem *new_items=NULL; DWORD item_count=0; TRACE("(%p,%p,%s,%x)\n", iface, pIStream, debugstr_guid(pguidPreferredVendor), dwPersistOptions); EnterCriticalSection(&This->lock); hr = This->vtable->fnLoad(pIStream, pguidPreferredVendor, dwPersistOptions, &new_items, &item_count); if (SUCCEEDED(hr)) { MetadataHandler_FreeItems(This); This->items = new_items; This->item_count = item_count; } LeaveCriticalSection(&This->lock); return hr; } static HRESULT WINAPI MetadataHandler_SaveEx(IWICPersistStream *iface, IStream *pIStream, DWORD dwPersistOptions, BOOL fClearDirty) { FIXME("(%p,%p,%x,%i): stub\n", iface, pIStream, dwPersistOptions, fClearDirty); return E_NOTIMPL; } static const IWICPersistStreamVtbl MetadataHandler_PersistStream_Vtbl = { MetadataHandler_PersistStream_QueryInterface, MetadataHandler_PersistStream_AddRef, MetadataHandler_PersistStream_Release, MetadataHandler_GetClassID, MetadataHandler_IsDirty, MetadataHandler_Load, MetadataHandler_Save, MetadataHandler_GetSizeMax, MetadataHandler_LoadEx, MetadataHandler_SaveEx }; HRESULT MetadataReader_Create(const MetadataHandlerVtbl *vtable, IUnknown *pUnkOuter, REFIID iid, void** ppv) { MetadataHandler *This; HRESULT hr; TRACE("%s\n", debugstr_guid(vtable->clsid)); *ppv = NULL; if (pUnkOuter) return CLASS_E_NOAGGREGATION; This = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataHandler)); if (!This) return E_OUTOFMEMORY; This->IWICMetadataWriter_iface.lpVtbl = &MetadataHandler_Vtbl; This->IWICPersistStream_iface.lpVtbl = &MetadataHandler_PersistStream_Vtbl; This->ref = 1; This->vtable = vtable; This->items = NULL; This->item_count = 0; InitializeCriticalSection(&This->lock); This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": MetadataHandler.lock"); hr = IWICMetadataWriter_QueryInterface(&This->IWICMetadataWriter_iface, iid, ppv); IWICMetadataWriter_Release(&This->IWICMetadataWriter_iface); return hr; } typedef struct MetadataHandlerEnum { IWICEnumMetadataItem IWICEnumMetadataItem_iface; LONG ref; MetadataHandler *parent; DWORD index; } MetadataHandlerEnum; static inline MetadataHandlerEnum *impl_from_IWICEnumMetadataItem(IWICEnumMetadataItem *iface) { return CONTAINING_RECORD(iface, MetadataHandlerEnum, IWICEnumMetadataItem_iface); } static HRESULT WINAPI MetadataHandlerEnum_QueryInterface(IWICEnumMetadataItem *iface, REFIID iid, void **ppv) { MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface); TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); if (!ppv) return E_INVALIDARG; if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICEnumMetadataItem, iid)) { *ppv = &This->IWICEnumMetadataItem_iface; } else { *ppv = NULL; return E_NOINTERFACE; } IUnknown_AddRef((IUnknown*)*ppv); return S_OK; } static ULONG WINAPI MetadataHandlerEnum_AddRef(IWICEnumMetadataItem *iface) { MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface); ULONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) refcount=%u\n", iface, ref); return ref; } static ULONG WINAPI MetadataHandlerEnum_Release(IWICEnumMetadataItem *iface) { MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) refcount=%u\n", iface, ref); if (ref == 0) { IWICMetadataWriter_Release(&This->parent->IWICMetadataWriter_iface); HeapFree(GetProcessHeap(), 0, This); } return ref; } static HRESULT WINAPI MetadataHandlerEnum_Next(IWICEnumMetadataItem *iface, ULONG celt, PROPVARIANT *rgeltSchema, PROPVARIANT *rgeltId, PROPVARIANT *rgeltValue, ULONG *pceltFetched) { MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface); ULONG new_index; HRESULT hr=S_FALSE; int i; TRACE("(%p,%i)\n", iface, celt); EnterCriticalSection(&This->parent->lock); if (This->index >= This->parent->item_count) { *pceltFetched = 0; LeaveCriticalSection(&This->parent->lock); return S_FALSE; } new_index = min(This->parent->item_count, This->index + celt); *pceltFetched = new_index - This->index; if (rgeltSchema) { for (i=0; SUCCEEDED(hr) && i < *pceltFetched; i++) hr = PropVariantCopy(&rgeltSchema[i], &This->parent->items[i+This->index].schema); } for (i=0; SUCCEEDED(hr) && i < *pceltFetched; i++) hr = PropVariantCopy(&rgeltId[i], &This->parent->items[i+This->index].id); if (rgeltValue) { for (i=0; SUCCEEDED(hr) && i < *pceltFetched; i++) hr = PropVariantCopy(&rgeltValue[i], &This->parent->items[i+This->index].value); } if (SUCCEEDED(hr)) { This->index = new_index; } LeaveCriticalSection(&This->parent->lock); return hr; } static HRESULT WINAPI MetadataHandlerEnum_Skip(IWICEnumMetadataItem *iface, ULONG celt) { MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface); EnterCriticalSection(&This->parent->lock); This->index += celt; LeaveCriticalSection(&This->parent->lock); return S_OK; } static HRESULT WINAPI MetadataHandlerEnum_Reset(IWICEnumMetadataItem *iface) { MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface); EnterCriticalSection(&This->parent->lock); This->index = 0; LeaveCriticalSection(&This->parent->lock); return S_OK; } static HRESULT WINAPI MetadataHandlerEnum_Clone(IWICEnumMetadataItem *iface, IWICEnumMetadataItem **ppIEnumMetadataItem) { MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface); HRESULT hr; EnterCriticalSection(&This->parent->lock); hr = MetadataHandlerEnum_Create(This->parent, This->index, ppIEnumMetadataItem); LeaveCriticalSection(&This->parent->lock); return hr; } static const IWICEnumMetadataItemVtbl MetadataHandlerEnum_Vtbl = { MetadataHandlerEnum_QueryInterface, MetadataHandlerEnum_AddRef, MetadataHandlerEnum_Release, MetadataHandlerEnum_Next, MetadataHandlerEnum_Skip, MetadataHandlerEnum_Reset, MetadataHandlerEnum_Clone }; static HRESULT MetadataHandlerEnum_Create(MetadataHandler *parent, DWORD index, IWICEnumMetadataItem **ppIEnumMetadataItem) { MetadataHandlerEnum *This; *ppIEnumMetadataItem = NULL; This = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataHandlerEnum)); if (!This) return E_OUTOFMEMORY; IWICMetadataWriter_AddRef(&parent->IWICMetadataWriter_iface); This->IWICEnumMetadataItem_iface.lpVtbl = &MetadataHandlerEnum_Vtbl; This->ref = 1; This->parent = parent; This->index = index; *ppIEnumMetadataItem = &This->IWICEnumMetadataItem_iface; return S_OK; } static HRESULT LoadUnknownMetadata(IStream *input, const GUID *preferred_vendor, DWORD persist_options, MetadataItem **items, DWORD *item_count) { HRESULT hr; MetadataItem *result; STATSTG stat; BYTE *data; ULONG bytesread; TRACE("\n"); hr = IStream_Stat(input, &stat, STATFLAG_NONAME); if (FAILED(hr)) return hr; data = HeapAlloc(GetProcessHeap(), 0, stat.cbSize.QuadPart); if (!data) return E_OUTOFMEMORY; hr = IStream_Read(input, data, stat.cbSize.QuadPart, &bytesread); if (FAILED(hr)) { HeapFree(GetProcessHeap(), 0, data); return hr; } result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem)); if (!result) { HeapFree(GetProcessHeap(), 0, data); return E_OUTOFMEMORY; } PropVariantInit(&result[0].schema); PropVariantInit(&result[0].id); PropVariantInit(&result[0].value); result[0].value.vt = VT_BLOB; result[0].value.u.blob.cbSize = bytesread; result[0].value.u.blob.pBlobData = data; *items = result; *item_count = 1; return S_OK; } static const MetadataHandlerVtbl UnknownMetadataReader_Vtbl = { 0, &CLSID_WICUnknownMetadataReader, LoadUnknownMetadata }; HRESULT UnknownMetadataReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv) { return MetadataReader_Create(&UnknownMetadataReader_Vtbl, pUnkOuter, iid, ppv); }