| /* | |
| * Copyright 2009 Tony Wasserka | |
| * | |
| * 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 "wine/debug.h" | |
| #define COBJMACROS | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "winreg.h" | |
| #include "objbase.h" | |
| #include "wincodec.h" | |
| #include "wincodecs_private.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); | |
| /****************************************** | |
| * StreamOnMemory implementation | |
| * | |
| * Used by IWICStream_InitializeFromMemory | |
| * | |
| */ | |
| typedef struct StreamOnMemory { | |
| const IStreamVtbl *lpVtbl; | |
| LONG ref; | |
| BYTE *pbMemory; | |
| DWORD dwMemsize; | |
| DWORD dwCurPos; | |
| } StreamOnMemory; | |
| static HRESULT WINAPI StreamOnMemory_QueryInterface(IStream *iface, | |
| REFIID iid, void **ppv) | |
| { | |
| TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); | |
| if (!ppv) return E_INVALIDARG; | |
| if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) || | |
| IsEqualIID(&IID_ISequentialStream, iid)) | |
| { | |
| *ppv = iface; | |
| IUnknown_AddRef((IUnknown*)*ppv); | |
| return S_OK; | |
| } | |
| else | |
| { | |
| *ppv = NULL; | |
| return E_NOINTERFACE; | |
| } | |
| } | |
| static ULONG WINAPI StreamOnMemory_AddRef(IStream *iface) | |
| { | |
| StreamOnMemory *This = (StreamOnMemory*)iface; | |
| ULONG ref = InterlockedIncrement(&This->ref); | |
| TRACE("(%p) refcount=%u\n", iface, ref); | |
| return ref; | |
| } | |
| static ULONG WINAPI StreamOnMemory_Release(IStream *iface) | |
| { | |
| StreamOnMemory *This = (StreamOnMemory*)iface; | |
| ULONG ref = InterlockedDecrement(&This->ref); | |
| TRACE("(%p) refcount=%u\n", iface, ref); | |
| if (ref == 0) { | |
| HeapFree(GetProcessHeap(), 0, This); | |
| } | |
| return ref; | |
| } | |
| static HRESULT WINAPI StreamOnMemory_Read(IStream *iface, | |
| void *pv, ULONG cb, ULONG *pcbRead) | |
| { | |
| StreamOnMemory *This = (StreamOnMemory*)iface; | |
| ULONG uBytesRead; | |
| TRACE("(%p)\n", This); | |
| if (!pv) return E_INVALIDARG; | |
| uBytesRead = min(cb, This->dwMemsize - This->dwCurPos); | |
| memcpy(pv, This->pbMemory + This->dwCurPos, uBytesRead); | |
| This->dwCurPos += uBytesRead; | |
| if (pcbRead) *pcbRead = uBytesRead; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI StreamOnMemory_Write(IStream *iface, | |
| void const *pv, ULONG cb, ULONG *pcbWritten) | |
| { | |
| StreamOnMemory *This = (StreamOnMemory*)iface; | |
| TRACE("(%p)\n", This); | |
| if (!pv) return E_INVALIDARG; | |
| if (cb > This->dwMemsize - This->dwCurPos) return STG_E_MEDIUMFULL; | |
| if (cb) { | |
| memcpy(This->pbMemory + This->dwCurPos, pv, cb); | |
| This->dwCurPos += cb; | |
| } | |
| if (pcbWritten) *pcbWritten = cb; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI StreamOnMemory_Seek(IStream *iface, | |
| LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) | |
| { | |
| StreamOnMemory *This = (StreamOnMemory*)iface; | |
| LARGE_INTEGER NewPosition; | |
| TRACE("(%p)\n", This); | |
| if (dwOrigin == STREAM_SEEK_SET) NewPosition.QuadPart = dlibMove.QuadPart; | |
| else if (dwOrigin == STREAM_SEEK_CUR) NewPosition.QuadPart = This->dwCurPos + dlibMove.QuadPart; | |
| else if (dwOrigin == STREAM_SEEK_END) NewPosition.QuadPart = This->dwMemsize + dlibMove.QuadPart; | |
| else return E_INVALIDARG; | |
| if (NewPosition.u.HighPart) return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); | |
| if (NewPosition.QuadPart > This->dwMemsize) return E_INVALIDARG; | |
| if (NewPosition.QuadPart < 0) return E_INVALIDARG; | |
| This->dwCurPos = NewPosition.u.LowPart; | |
| if(plibNewPosition) plibNewPosition->QuadPart = This->dwCurPos; | |
| return S_OK; | |
| } | |
| /* SetSize isn't implemented in the native windowscodecs DLL either */ | |
| static HRESULT WINAPI StreamOnMemory_SetSize(IStream *iface, | |
| ULARGE_INTEGER libNewSize) | |
| { | |
| TRACE("(%p)\n", iface); | |
| return E_NOTIMPL; | |
| } | |
| /* CopyTo isn't implemented in the native windowscodecs DLL either */ | |
| static HRESULT WINAPI StreamOnMemory_CopyTo(IStream *iface, | |
| IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) | |
| { | |
| TRACE("(%p)\n", iface); | |
| return E_NOTIMPL; | |
| } | |
| /* Commit isn't implemented in the native windowscodecs DLL either */ | |
| static HRESULT WINAPI StreamOnMemory_Commit(IStream *iface, | |
| DWORD grfCommitFlags) | |
| { | |
| TRACE("(%p)\n", iface); | |
| return E_NOTIMPL; | |
| } | |
| /* Revert isn't implemented in the native windowscodecs DLL either */ | |
| static HRESULT WINAPI StreamOnMemory_Revert(IStream *iface) | |
| { | |
| TRACE("(%p)\n", iface); | |
| return E_NOTIMPL; | |
| } | |
| /* LockRegion isn't implemented in the native windowscodecs DLL either */ | |
| static HRESULT WINAPI StreamOnMemory_LockRegion(IStream *iface, | |
| ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) | |
| { | |
| TRACE("(%p)\n", iface); | |
| return E_NOTIMPL; | |
| } | |
| /* UnlockRegion isn't implemented in the native windowscodecs DLL either */ | |
| static HRESULT WINAPI StreamOnMemory_UnlockRegion(IStream *iface, | |
| ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) | |
| { | |
| TRACE("(%p)\n", iface); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI StreamOnMemory_Stat(IStream *iface, | |
| STATSTG *pstatstg, DWORD grfStatFlag) | |
| { | |
| StreamOnMemory *This = (StreamOnMemory*)iface; | |
| TRACE("(%p)\n", This); | |
| if (!pstatstg) return E_INVALIDARG; | |
| ZeroMemory(pstatstg, sizeof(STATSTG)); | |
| pstatstg->type = STGTY_STREAM; | |
| pstatstg->cbSize.QuadPart = This->dwMemsize; | |
| return S_OK; | |
| } | |
| /* Clone isn't implemented in the native windowscodecs DLL either */ | |
| static HRESULT WINAPI StreamOnMemory_Clone(IStream *iface, | |
| IStream **ppstm) | |
| { | |
| TRACE("(%p)\n", iface); | |
| return E_NOTIMPL; | |
| } | |
| const IStreamVtbl StreamOnMemory_Vtbl = | |
| { | |
| /*** IUnknown methods ***/ | |
| StreamOnMemory_QueryInterface, | |
| StreamOnMemory_AddRef, | |
| StreamOnMemory_Release, | |
| /*** ISequentialStream methods ***/ | |
| StreamOnMemory_Read, | |
| StreamOnMemory_Write, | |
| /*** IStream methods ***/ | |
| StreamOnMemory_Seek, | |
| StreamOnMemory_SetSize, | |
| StreamOnMemory_CopyTo, | |
| StreamOnMemory_Commit, | |
| StreamOnMemory_Revert, | |
| StreamOnMemory_LockRegion, | |
| StreamOnMemory_UnlockRegion, | |
| StreamOnMemory_Stat, | |
| StreamOnMemory_Clone, | |
| }; | |
| /****************************************** | |
| * IWICStream implementation | |
| * | |
| */ | |
| typedef struct IWICStreamImpl | |
| { | |
| const IWICStreamVtbl *lpVtbl; | |
| LONG ref; | |
| IStream *pStream; | |
| } IWICStreamImpl; | |
| static HRESULT WINAPI IWICStreamImpl_QueryInterface(IWICStream *iface, | |
| REFIID iid, void **ppv) | |
| { | |
| IWICStreamImpl *This = (IWICStreamImpl*)iface; | |
| TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); | |
| if (!ppv) return E_INVALIDARG; | |
| if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) || | |
| IsEqualIID(&IID_ISequentialStream, iid) || IsEqualIID(&IID_IWICStream, iid)) | |
| { | |
| *ppv = This; | |
| IUnknown_AddRef((IUnknown*)*ppv); | |
| return S_OK; | |
| } | |
| else | |
| { | |
| *ppv = NULL; | |
| return E_NOINTERFACE; | |
| } | |
| } | |
| static ULONG WINAPI IWICStreamImpl_AddRef(IWICStream *iface) | |
| { | |
| IWICStreamImpl *This = (IWICStreamImpl*)iface; | |
| ULONG ref = InterlockedIncrement(&This->ref); | |
| TRACE("(%p) refcount=%u\n", iface, ref); | |
| return ref; | |
| } | |
| static ULONG WINAPI IWICStreamImpl_Release(IWICStream *iface) | |
| { | |
| IWICStreamImpl *This = (IWICStreamImpl*)iface; | |
| ULONG ref = InterlockedDecrement(&This->ref); | |
| TRACE("(%p) refcount=%u\n", iface, ref); | |
| if (ref == 0) { | |
| if (This->pStream) IStream_Release(This->pStream); | |
| HeapFree(GetProcessHeap(), 0, This); | |
| } | |
| return ref; | |
| } | |
| static HRESULT WINAPI IWICStreamImpl_Read(IWICStream *iface, | |
| void *pv, ULONG cb, ULONG *pcbRead) | |
| { | |
| IWICStreamImpl *This = (IWICStreamImpl*)iface; | |
| TRACE("(%p): relay\n", This); | |
| if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; | |
| return IStream_Read(This->pStream, pv, cb, pcbRead); | |
| } | |
| static HRESULT WINAPI IWICStreamImpl_Write(IWICStream *iface, | |
| void const *pv, ULONG cb, ULONG *pcbWritten) | |
| { | |
| IWICStreamImpl *This = (IWICStreamImpl*)iface; | |
| TRACE("(%p): relay\n", This); | |
| if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; | |
| return IStream_Write(This->pStream, pv, cb, pcbWritten); | |
| } | |
| static HRESULT WINAPI IWICStreamImpl_Seek(IWICStream *iface, | |
| LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) | |
| { | |
| IWICStreamImpl *This = (IWICStreamImpl*)iface; | |
| TRACE("(%p): relay\n", This); | |
| if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; | |
| return IStream_Seek(This->pStream, dlibMove, dwOrigin, plibNewPosition); | |
| } | |
| static HRESULT WINAPI IWICStreamImpl_SetSize(IWICStream *iface, | |
| ULARGE_INTEGER libNewSize) | |
| { | |
| IWICStreamImpl *This = (IWICStreamImpl*)iface; | |
| TRACE("(%p): relay\n", This); | |
| if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; | |
| return IStream_SetSize(This->pStream, libNewSize); | |
| } | |
| static HRESULT WINAPI IWICStreamImpl_CopyTo(IWICStream *iface, | |
| IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) | |
| { | |
| IWICStreamImpl *This = (IWICStreamImpl*)iface; | |
| TRACE("(%p): relay\n", This); | |
| if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; | |
| return IStream_CopyTo(This->pStream, pstm, cb, pcbRead, pcbWritten); | |
| } | |
| static HRESULT WINAPI IWICStreamImpl_Commit(IWICStream *iface, | |
| DWORD grfCommitFlags) | |
| { | |
| IWICStreamImpl *This = (IWICStreamImpl*)iface; | |
| TRACE("(%p): relay\n", This); | |
| if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; | |
| return IStream_Commit(This->pStream, grfCommitFlags); | |
| } | |
| static HRESULT WINAPI IWICStreamImpl_Revert(IWICStream *iface) | |
| { | |
| IWICStreamImpl *This = (IWICStreamImpl*)iface; | |
| TRACE("(%p): relay\n", This); | |
| if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; | |
| return IStream_Revert(This->pStream); | |
| } | |
| static HRESULT WINAPI IWICStreamImpl_LockRegion(IWICStream *iface, | |
| ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) | |
| { | |
| IWICStreamImpl *This = (IWICStreamImpl*)iface; | |
| TRACE("(%p): relay\n", This); | |
| if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; | |
| return IStream_LockRegion(This->pStream, libOffset, cb, dwLockType); | |
| } | |
| static HRESULT WINAPI IWICStreamImpl_UnlockRegion(IWICStream *iface, | |
| ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) | |
| { | |
| IWICStreamImpl *This = (IWICStreamImpl*)iface; | |
| TRACE("(%p): relay\n", This); | |
| if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; | |
| return IStream_UnlockRegion(This->pStream, libOffset, cb, dwLockType); | |
| } | |
| static HRESULT WINAPI IWICStreamImpl_Stat(IWICStream *iface, | |
| STATSTG *pstatstg, DWORD grfStatFlag) | |
| { | |
| IWICStreamImpl *This = (IWICStreamImpl*)iface; | |
| TRACE("(%p): relay\n", This); | |
| if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; | |
| return IStream_Stat(This->pStream, pstatstg, grfStatFlag); | |
| } | |
| static HRESULT WINAPI IWICStreamImpl_Clone(IWICStream *iface, | |
| IStream **ppstm) | |
| { | |
| IWICStreamImpl *This = (IWICStreamImpl*)iface; | |
| TRACE("(%p): relay\n", This); | |
| if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; | |
| return IStream_Clone(This->pStream, ppstm); | |
| } | |
| static HRESULT WINAPI IWICStreamImpl_InitializeFromIStream(IWICStream *iface, | |
| IStream *pIStream) | |
| { | |
| FIXME("(%p): stub\n", iface); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI IWICStreamImpl_InitializeFromFilename(IWICStream *iface, | |
| LPCWSTR wzFileName, DWORD dwDesiredAccess) | |
| { | |
| FIXME("(%p): stub\n", iface); | |
| return E_NOTIMPL; | |
| } | |
| /****************************************** | |
| * IWICStream_InitializeFromMemory | |
| * | |
| * Initializes the internal IStream object to retrieve its data from a memory chunk. | |
| * | |
| * PARAMS | |
| * pbBuffer [I] pointer to the memory chunk | |
| * cbBufferSize [I] number of bytes to use from the memory chunk | |
| * | |
| * RETURNS | |
| * SUCCESS: S_OK | |
| * FAILURE: E_INVALIDARG, if pbBuffer is NULL | |
| * E_OUTOFMEMORY, if we run out of memory | |
| * WINCODEC_ERR_WRONGSTATE, if the IStream object has already been initialized before | |
| * | |
| */ | |
| static HRESULT WINAPI IWICStreamImpl_InitializeFromMemory(IWICStream *iface, | |
| BYTE *pbBuffer, DWORD cbBufferSize) | |
| { | |
| IWICStreamImpl *This = (IWICStreamImpl*)iface; | |
| StreamOnMemory *pObject; | |
| TRACE("(%p,%p)\n", iface, pbBuffer); | |
| if (!pbBuffer) return E_INVALIDARG; | |
| if (This->pStream) return WINCODEC_ERR_WRONGSTATE; | |
| pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnMemory)); | |
| if (!pObject) return E_OUTOFMEMORY; | |
| pObject->lpVtbl = &StreamOnMemory_Vtbl; | |
| pObject->ref = 1; | |
| pObject->pbMemory = pbBuffer; | |
| pObject->dwMemsize = cbBufferSize; | |
| pObject->dwCurPos = 0; | |
| This->pStream = (IStream*)pObject; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI IWICStreamImpl_InitializeFromIStreamRegion(IWICStream *iface, | |
| IStream *pIStream, ULARGE_INTEGER ulOffset, ULARGE_INTEGER ulMaxSize) | |
| { | |
| FIXME("(%p): stub\n", iface); | |
| return E_NOTIMPL; | |
| } | |
| const IWICStreamVtbl WICStream_Vtbl = | |
| { | |
| /*** IUnknown methods ***/ | |
| IWICStreamImpl_QueryInterface, | |
| IWICStreamImpl_AddRef, | |
| IWICStreamImpl_Release, | |
| /*** ISequentialStream methods ***/ | |
| IWICStreamImpl_Read, | |
| IWICStreamImpl_Write, | |
| /*** IStream methods ***/ | |
| IWICStreamImpl_Seek, | |
| IWICStreamImpl_SetSize, | |
| IWICStreamImpl_CopyTo, | |
| IWICStreamImpl_Commit, | |
| IWICStreamImpl_Revert, | |
| IWICStreamImpl_LockRegion, | |
| IWICStreamImpl_UnlockRegion, | |
| IWICStreamImpl_Stat, | |
| IWICStreamImpl_Clone, | |
| /*** IWICStream methods ***/ | |
| IWICStreamImpl_InitializeFromIStream, | |
| IWICStreamImpl_InitializeFromFilename, | |
| IWICStreamImpl_InitializeFromMemory, | |
| IWICStreamImpl_InitializeFromIStreamRegion, | |
| }; | |
| HRESULT StreamImpl_Create(IWICStream **stream) | |
| { | |
| IWICStreamImpl *pObject; | |
| if( !stream ) return E_INVALIDARG; | |
| pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(IWICStreamImpl)); | |
| if( !pObject ) { | |
| *stream = NULL; | |
| return E_OUTOFMEMORY; | |
| } | |
| pObject->lpVtbl = &WICStream_Vtbl; | |
| pObject->ref = 1; | |
| pObject->pStream = NULL; | |
| *stream = (IWICStream*)pObject; | |
| return S_OK; | |
| } |