2 * Copyright 2009 Tony Wasserka
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "wine/debug.h"
27 #include "wincodecs_private.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
31 /******************************************
32 * StreamOnMemory implementation
34 * Used by IWICStream_InitializeFromMemory
37 typedef struct StreamOnMemory
{
38 const IStreamVtbl
*lpVtbl
;
45 CRITICAL_SECTION lock
; /* must be held when pbMemory or dwCurPos is accessed */
48 static HRESULT WINAPI
StreamOnMemory_QueryInterface(IStream
*iface
,
49 REFIID iid
, void **ppv
)
51 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
53 if (!ppv
) return E_INVALIDARG
;
55 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IStream
, iid
) ||
56 IsEqualIID(&IID_ISequentialStream
, iid
))
59 IUnknown_AddRef((IUnknown
*)*ppv
);
69 static ULONG WINAPI
StreamOnMemory_AddRef(IStream
*iface
)
71 StreamOnMemory
*This
= (StreamOnMemory
*)iface
;
72 ULONG ref
= InterlockedIncrement(&This
->ref
);
74 TRACE("(%p) refcount=%u\n", iface
, ref
);
79 static ULONG WINAPI
StreamOnMemory_Release(IStream
*iface
)
81 StreamOnMemory
*This
= (StreamOnMemory
*)iface
;
82 ULONG ref
= InterlockedDecrement(&This
->ref
);
84 TRACE("(%p) refcount=%u\n", iface
, ref
);
87 This
->lock
.DebugInfo
->Spare
[0] = 0;
88 DeleteCriticalSection(&This
->lock
);
89 HeapFree(GetProcessHeap(), 0, This
);
94 static HRESULT WINAPI
StreamOnMemory_Read(IStream
*iface
,
95 void *pv
, ULONG cb
, ULONG
*pcbRead
)
97 StreamOnMemory
*This
= (StreamOnMemory
*)iface
;
99 TRACE("(%p)\n", This
);
101 if (!pv
) return E_INVALIDARG
;
103 EnterCriticalSection(&This
->lock
);
104 uBytesRead
= min(cb
, This
->dwMemsize
- This
->dwCurPos
);
105 memcpy(pv
, This
->pbMemory
+ This
->dwCurPos
, uBytesRead
);
106 This
->dwCurPos
+= uBytesRead
;
107 LeaveCriticalSection(&This
->lock
);
109 if (pcbRead
) *pcbRead
= uBytesRead
;
114 static HRESULT WINAPI
StreamOnMemory_Write(IStream
*iface
,
115 void const *pv
, ULONG cb
, ULONG
*pcbWritten
)
117 StreamOnMemory
*This
= (StreamOnMemory
*)iface
;
119 TRACE("(%p)\n", This
);
121 if (!pv
) return E_INVALIDARG
;
123 EnterCriticalSection(&This
->lock
);
124 if (cb
> This
->dwMemsize
- This
->dwCurPos
) {
125 hr
= STG_E_MEDIUMFULL
;
128 memcpy(This
->pbMemory
+ This
->dwCurPos
, pv
, cb
);
129 This
->dwCurPos
+= cb
;
131 if (pcbWritten
) *pcbWritten
= cb
;
133 LeaveCriticalSection(&This
->lock
);
138 static HRESULT WINAPI
StreamOnMemory_Seek(IStream
*iface
,
139 LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
141 StreamOnMemory
*This
= (StreamOnMemory
*)iface
;
142 LARGE_INTEGER NewPosition
;
144 TRACE("(%p)\n", This
);
146 EnterCriticalSection(&This
->lock
);
147 if (dwOrigin
== STREAM_SEEK_SET
) NewPosition
.QuadPart
= dlibMove
.QuadPart
;
148 else if (dwOrigin
== STREAM_SEEK_CUR
) NewPosition
.QuadPart
= This
->dwCurPos
+ dlibMove
.QuadPart
;
149 else if (dwOrigin
== STREAM_SEEK_END
) NewPosition
.QuadPart
= This
->dwMemsize
+ dlibMove
.QuadPart
;
150 else hr
= E_INVALIDARG
;
153 if (NewPosition
.u
.HighPart
) hr
= HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW
);
154 else if (NewPosition
.QuadPart
> This
->dwMemsize
) hr
= E_INVALIDARG
;
155 else if (NewPosition
.QuadPart
< 0) hr
= E_INVALIDARG
;
159 This
->dwCurPos
= NewPosition
.u
.LowPart
;
161 if(plibNewPosition
) plibNewPosition
->QuadPart
= This
->dwCurPos
;
163 LeaveCriticalSection(&This
->lock
);
168 /* SetSize isn't implemented in the native windowscodecs DLL either */
169 static HRESULT WINAPI
StreamOnMemory_SetSize(IStream
*iface
,
170 ULARGE_INTEGER libNewSize
)
172 TRACE("(%p)\n", iface
);
176 /* CopyTo isn't implemented in the native windowscodecs DLL either */
177 static HRESULT WINAPI
StreamOnMemory_CopyTo(IStream
*iface
,
178 IStream
*pstm
, ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
180 TRACE("(%p)\n", iface
);
184 /* Commit isn't implemented in the native windowscodecs DLL either */
185 static HRESULT WINAPI
StreamOnMemory_Commit(IStream
*iface
,
186 DWORD grfCommitFlags
)
188 TRACE("(%p)\n", iface
);
192 /* Revert isn't implemented in the native windowscodecs DLL either */
193 static HRESULT WINAPI
StreamOnMemory_Revert(IStream
*iface
)
195 TRACE("(%p)\n", iface
);
199 /* LockRegion isn't implemented in the native windowscodecs DLL either */
200 static HRESULT WINAPI
StreamOnMemory_LockRegion(IStream
*iface
,
201 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
203 TRACE("(%p)\n", iface
);
207 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */
208 static HRESULT WINAPI
StreamOnMemory_UnlockRegion(IStream
*iface
,
209 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
211 TRACE("(%p)\n", iface
);
215 static HRESULT WINAPI
StreamOnMemory_Stat(IStream
*iface
,
216 STATSTG
*pstatstg
, DWORD grfStatFlag
)
218 StreamOnMemory
*This
= (StreamOnMemory
*)iface
;
219 TRACE("(%p)\n", This
);
221 if (!pstatstg
) return E_INVALIDARG
;
223 ZeroMemory(pstatstg
, sizeof(STATSTG
));
224 pstatstg
->type
= STGTY_STREAM
;
225 pstatstg
->cbSize
.QuadPart
= This
->dwMemsize
;
230 /* Clone isn't implemented in the native windowscodecs DLL either */
231 static HRESULT WINAPI
StreamOnMemory_Clone(IStream
*iface
,
234 TRACE("(%p)\n", iface
);
239 const IStreamVtbl StreamOnMemory_Vtbl
=
241 /*** IUnknown methods ***/
242 StreamOnMemory_QueryInterface
,
243 StreamOnMemory_AddRef
,
244 StreamOnMemory_Release
,
245 /*** ISequentialStream methods ***/
247 StreamOnMemory_Write
,
248 /*** IStream methods ***/
250 StreamOnMemory_SetSize
,
251 StreamOnMemory_CopyTo
,
252 StreamOnMemory_Commit
,
253 StreamOnMemory_Revert
,
254 StreamOnMemory_LockRegion
,
255 StreamOnMemory_UnlockRegion
,
257 StreamOnMemory_Clone
,
260 /******************************************
261 * IWICStream implementation
264 typedef struct IWICStreamImpl
266 const IWICStreamVtbl
*lpVtbl
;
272 static HRESULT WINAPI
IWICStreamImpl_QueryInterface(IWICStream
*iface
,
273 REFIID iid
, void **ppv
)
275 IWICStreamImpl
*This
= (IWICStreamImpl
*)iface
;
276 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
278 if (!ppv
) return E_INVALIDARG
;
280 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IStream
, iid
) ||
281 IsEqualIID(&IID_ISequentialStream
, iid
) || IsEqualIID(&IID_IWICStream
, iid
))
284 IUnknown_AddRef((IUnknown
*)*ppv
);
290 return E_NOINTERFACE
;
294 static ULONG WINAPI
IWICStreamImpl_AddRef(IWICStream
*iface
)
296 IWICStreamImpl
*This
= (IWICStreamImpl
*)iface
;
297 ULONG ref
= InterlockedIncrement(&This
->ref
);
299 TRACE("(%p) refcount=%u\n", iface
, ref
);
304 static ULONG WINAPI
IWICStreamImpl_Release(IWICStream
*iface
)
306 IWICStreamImpl
*This
= (IWICStreamImpl
*)iface
;
307 ULONG ref
= InterlockedDecrement(&This
->ref
);
309 TRACE("(%p) refcount=%u\n", iface
, ref
);
312 if (This
->pStream
) IStream_Release(This
->pStream
);
313 HeapFree(GetProcessHeap(), 0, This
);
318 static HRESULT WINAPI
IWICStreamImpl_Read(IWICStream
*iface
,
319 void *pv
, ULONG cb
, ULONG
*pcbRead
)
321 IWICStreamImpl
*This
= (IWICStreamImpl
*)iface
;
322 TRACE("(%p): relay\n", This
);
324 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
325 return IStream_Read(This
->pStream
, pv
, cb
, pcbRead
);
328 static HRESULT WINAPI
IWICStreamImpl_Write(IWICStream
*iface
,
329 void const *pv
, ULONG cb
, ULONG
*pcbWritten
)
331 IWICStreamImpl
*This
= (IWICStreamImpl
*)iface
;
332 TRACE("(%p): relay\n", This
);
334 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
335 return IStream_Write(This
->pStream
, pv
, cb
, pcbWritten
);
338 static HRESULT WINAPI
IWICStreamImpl_Seek(IWICStream
*iface
,
339 LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
341 IWICStreamImpl
*This
= (IWICStreamImpl
*)iface
;
342 TRACE("(%p): relay\n", This
);
344 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
345 return IStream_Seek(This
->pStream
, dlibMove
, dwOrigin
, plibNewPosition
);
348 static HRESULT WINAPI
IWICStreamImpl_SetSize(IWICStream
*iface
,
349 ULARGE_INTEGER libNewSize
)
351 IWICStreamImpl
*This
= (IWICStreamImpl
*)iface
;
352 TRACE("(%p): relay\n", This
);
354 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
355 return IStream_SetSize(This
->pStream
, libNewSize
);
358 static HRESULT WINAPI
IWICStreamImpl_CopyTo(IWICStream
*iface
,
359 IStream
*pstm
, ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
361 IWICStreamImpl
*This
= (IWICStreamImpl
*)iface
;
362 TRACE("(%p): relay\n", This
);
364 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
365 return IStream_CopyTo(This
->pStream
, pstm
, cb
, pcbRead
, pcbWritten
);
368 static HRESULT WINAPI
IWICStreamImpl_Commit(IWICStream
*iface
,
369 DWORD grfCommitFlags
)
371 IWICStreamImpl
*This
= (IWICStreamImpl
*)iface
;
372 TRACE("(%p): relay\n", This
);
374 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
375 return IStream_Commit(This
->pStream
, grfCommitFlags
);
378 static HRESULT WINAPI
IWICStreamImpl_Revert(IWICStream
*iface
)
380 IWICStreamImpl
*This
= (IWICStreamImpl
*)iface
;
381 TRACE("(%p): relay\n", This
);
383 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
384 return IStream_Revert(This
->pStream
);
387 static HRESULT WINAPI
IWICStreamImpl_LockRegion(IWICStream
*iface
,
388 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
390 IWICStreamImpl
*This
= (IWICStreamImpl
*)iface
;
391 TRACE("(%p): relay\n", This
);
393 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
394 return IStream_LockRegion(This
->pStream
, libOffset
, cb
, dwLockType
);
397 static HRESULT WINAPI
IWICStreamImpl_UnlockRegion(IWICStream
*iface
,
398 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
400 IWICStreamImpl
*This
= (IWICStreamImpl
*)iface
;
401 TRACE("(%p): relay\n", This
);
403 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
404 return IStream_UnlockRegion(This
->pStream
, libOffset
, cb
, dwLockType
);
407 static HRESULT WINAPI
IWICStreamImpl_Stat(IWICStream
*iface
,
408 STATSTG
*pstatstg
, DWORD grfStatFlag
)
410 IWICStreamImpl
*This
= (IWICStreamImpl
*)iface
;
411 TRACE("(%p): relay\n", This
);
413 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
414 return IStream_Stat(This
->pStream
, pstatstg
, grfStatFlag
);
417 static HRESULT WINAPI
IWICStreamImpl_Clone(IWICStream
*iface
,
420 IWICStreamImpl
*This
= (IWICStreamImpl
*)iface
;
421 TRACE("(%p): relay\n", This
);
423 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
424 return IStream_Clone(This
->pStream
, ppstm
);
427 static HRESULT WINAPI
IWICStreamImpl_InitializeFromIStream(IWICStream
*iface
,
430 FIXME("(%p): stub\n", iface
);
434 static HRESULT WINAPI
IWICStreamImpl_InitializeFromFilename(IWICStream
*iface
,
435 LPCWSTR wzFileName
, DWORD dwDesiredAccess
)
437 FIXME("(%p): stub\n", iface
);
441 /******************************************
442 * IWICStream_InitializeFromMemory
444 * Initializes the internal IStream object to retrieve its data from a memory chunk.
447 * pbBuffer [I] pointer to the memory chunk
448 * cbBufferSize [I] number of bytes to use from the memory chunk
452 * FAILURE: E_INVALIDARG, if pbBuffer is NULL
453 * E_OUTOFMEMORY, if we run out of memory
454 * WINCODEC_ERR_WRONGSTATE, if the IStream object has already been initialized before
457 static HRESULT WINAPI
IWICStreamImpl_InitializeFromMemory(IWICStream
*iface
,
458 BYTE
*pbBuffer
, DWORD cbBufferSize
)
460 IWICStreamImpl
*This
= (IWICStreamImpl
*)iface
;
461 StreamOnMemory
*pObject
;
462 TRACE("(%p,%p)\n", iface
, pbBuffer
);
464 if (!pbBuffer
) return E_INVALIDARG
;
465 if (This
->pStream
) return WINCODEC_ERR_WRONGSTATE
;
467 pObject
= HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnMemory
));
468 if (!pObject
) return E_OUTOFMEMORY
;
470 pObject
->lpVtbl
= &StreamOnMemory_Vtbl
;
472 pObject
->pbMemory
= pbBuffer
;
473 pObject
->dwMemsize
= cbBufferSize
;
474 pObject
->dwCurPos
= 0;
475 InitializeCriticalSection(&pObject
->lock
);
476 pObject
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": StreamOnMemory.lock");
478 if (InterlockedCompareExchangePointer((void**)&This
->pStream
, pObject
, NULL
))
480 /* Some other thread set the stream first. */
481 IStream_Release((IStream
*)pObject
);
482 return WINCODEC_ERR_WRONGSTATE
;
488 static HRESULT WINAPI
IWICStreamImpl_InitializeFromIStreamRegion(IWICStream
*iface
,
489 IStream
*pIStream
, ULARGE_INTEGER ulOffset
, ULARGE_INTEGER ulMaxSize
)
491 FIXME("(%p): stub\n", iface
);
496 const IWICStreamVtbl WICStream_Vtbl
=
498 /*** IUnknown methods ***/
499 IWICStreamImpl_QueryInterface
,
500 IWICStreamImpl_AddRef
,
501 IWICStreamImpl_Release
,
502 /*** ISequentialStream methods ***/
504 IWICStreamImpl_Write
,
505 /*** IStream methods ***/
507 IWICStreamImpl_SetSize
,
508 IWICStreamImpl_CopyTo
,
509 IWICStreamImpl_Commit
,
510 IWICStreamImpl_Revert
,
511 IWICStreamImpl_LockRegion
,
512 IWICStreamImpl_UnlockRegion
,
514 IWICStreamImpl_Clone
,
515 /*** IWICStream methods ***/
516 IWICStreamImpl_InitializeFromIStream
,
517 IWICStreamImpl_InitializeFromFilename
,
518 IWICStreamImpl_InitializeFromMemory
,
519 IWICStreamImpl_InitializeFromIStreamRegion
,
522 HRESULT
StreamImpl_Create(IWICStream
**stream
)
524 IWICStreamImpl
*pObject
;
526 if( !stream
) return E_INVALIDARG
;
528 pObject
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWICStreamImpl
));
531 return E_OUTOFMEMORY
;
534 pObject
->lpVtbl
= &WICStream_Vtbl
;
536 pObject
->pStream
= NULL
;
538 *stream
= (IWICStream
*)pObject
;