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 "wincodecs_private.h"
24 /******************************************
25 * StreamOnMemory implementation
27 * Used by IWICStream_InitializeFromMemory
30 typedef struct StreamOnMemory
{
31 IStream IStream_iface
;
38 CRITICAL_SECTION lock
; /* must be held when pbMemory or dwCurPos is accessed */
41 static inline StreamOnMemory
*StreamOnMemory_from_IStream(IStream
*iface
)
43 return CONTAINING_RECORD(iface
, StreamOnMemory
, IStream_iface
);
46 static HRESULT WINAPI
StreamOnMemory_QueryInterface(IStream
*iface
,
47 REFIID iid
, void **ppv
)
49 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
51 if (!ppv
) return E_INVALIDARG
;
53 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IStream
, iid
) ||
54 IsEqualIID(&IID_ISequentialStream
, iid
))
57 IUnknown_AddRef((IUnknown
*)*ppv
);
67 static ULONG WINAPI
StreamOnMemory_AddRef(IStream
*iface
)
69 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
70 ULONG ref
= InterlockedIncrement(&This
->ref
);
72 TRACE("(%p) refcount=%u\n", iface
, ref
);
77 static ULONG WINAPI
StreamOnMemory_Release(IStream
*iface
)
79 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
80 ULONG ref
= InterlockedDecrement(&This
->ref
);
82 TRACE("(%p) refcount=%u\n", iface
, ref
);
85 This
->lock
.DebugInfo
->Spare
[0] = 0;
86 DeleteCriticalSection(&This
->lock
);
87 HeapFree(GetProcessHeap(), 0, This
);
92 static HRESULT WINAPI
StreamOnMemory_Read(IStream
*iface
,
93 void *pv
, ULONG cb
, ULONG
*pcbRead
)
95 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
97 TRACE("(%p)\n", This
);
99 if (!pv
) return E_INVALIDARG
;
101 EnterCriticalSection(&This
->lock
);
102 uBytesRead
= min(cb
, This
->dwMemsize
- This
->dwCurPos
);
103 memmove(pv
, This
->pbMemory
+ This
->dwCurPos
, uBytesRead
);
104 This
->dwCurPos
+= uBytesRead
;
105 LeaveCriticalSection(&This
->lock
);
107 if (pcbRead
) *pcbRead
= uBytesRead
;
112 static HRESULT WINAPI
StreamOnMemory_Write(IStream
*iface
,
113 void const *pv
, ULONG cb
, ULONG
*pcbWritten
)
115 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
117 TRACE("(%p)\n", This
);
119 if (!pv
) return E_INVALIDARG
;
121 EnterCriticalSection(&This
->lock
);
122 if (cb
> This
->dwMemsize
- This
->dwCurPos
) {
123 hr
= STG_E_MEDIUMFULL
;
126 memmove(This
->pbMemory
+ This
->dwCurPos
, pv
, cb
);
127 This
->dwCurPos
+= cb
;
129 if (pcbWritten
) *pcbWritten
= cb
;
131 LeaveCriticalSection(&This
->lock
);
136 static HRESULT WINAPI
StreamOnMemory_Seek(IStream
*iface
,
137 LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
139 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
140 LARGE_INTEGER NewPosition
;
142 TRACE("(%p)\n", This
);
144 EnterCriticalSection(&This
->lock
);
145 if (dwOrigin
== STREAM_SEEK_SET
) NewPosition
.QuadPart
= dlibMove
.QuadPart
;
146 else if (dwOrigin
== STREAM_SEEK_CUR
) NewPosition
.QuadPart
= This
->dwCurPos
+ dlibMove
.QuadPart
;
147 else if (dwOrigin
== STREAM_SEEK_END
) NewPosition
.QuadPart
= This
->dwMemsize
+ dlibMove
.QuadPart
;
148 else hr
= E_INVALIDARG
;
151 if (NewPosition
.u
.HighPart
) hr
= HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW
);
152 else if (NewPosition
.QuadPart
> This
->dwMemsize
) hr
= E_INVALIDARG
;
153 else if (NewPosition
.QuadPart
< 0) hr
= E_INVALIDARG
;
157 This
->dwCurPos
= NewPosition
.u
.LowPart
;
159 if(plibNewPosition
) plibNewPosition
->QuadPart
= This
->dwCurPos
;
161 LeaveCriticalSection(&This
->lock
);
166 /* SetSize isn't implemented in the native windowscodecs DLL either */
167 static HRESULT WINAPI
StreamOnMemory_SetSize(IStream
*iface
,
168 ULARGE_INTEGER libNewSize
)
170 TRACE("(%p)\n", iface
);
174 /* CopyTo isn't implemented in the native windowscodecs DLL either */
175 static HRESULT WINAPI
StreamOnMemory_CopyTo(IStream
*iface
,
176 IStream
*pstm
, ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
178 TRACE("(%p)\n", iface
);
182 /* Commit isn't implemented in the native windowscodecs DLL either */
183 static HRESULT WINAPI
StreamOnMemory_Commit(IStream
*iface
,
184 DWORD grfCommitFlags
)
186 TRACE("(%p)\n", iface
);
190 /* Revert isn't implemented in the native windowscodecs DLL either */
191 static HRESULT WINAPI
StreamOnMemory_Revert(IStream
*iface
)
193 TRACE("(%p)\n", iface
);
197 /* LockRegion isn't implemented in the native windowscodecs DLL either */
198 static HRESULT WINAPI
StreamOnMemory_LockRegion(IStream
*iface
,
199 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
201 TRACE("(%p)\n", iface
);
205 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */
206 static HRESULT WINAPI
StreamOnMemory_UnlockRegion(IStream
*iface
,
207 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
209 TRACE("(%p)\n", iface
);
213 static HRESULT WINAPI
StreamOnMemory_Stat(IStream
*iface
,
214 STATSTG
*pstatstg
, DWORD grfStatFlag
)
216 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
217 TRACE("(%p)\n", This
);
219 if (!pstatstg
) return E_INVALIDARG
;
221 ZeroMemory(pstatstg
, sizeof(STATSTG
));
222 pstatstg
->type
= STGTY_STREAM
;
223 pstatstg
->cbSize
.QuadPart
= This
->dwMemsize
;
228 /* Clone isn't implemented in the native windowscodecs DLL either */
229 static HRESULT WINAPI
StreamOnMemory_Clone(IStream
*iface
,
232 TRACE("(%p)\n", iface
);
237 static const IStreamVtbl StreamOnMemory_Vtbl
=
239 /*** IUnknown methods ***/
240 StreamOnMemory_QueryInterface
,
241 StreamOnMemory_AddRef
,
242 StreamOnMemory_Release
,
243 /*** ISequentialStream methods ***/
245 StreamOnMemory_Write
,
246 /*** IStream methods ***/
248 StreamOnMemory_SetSize
,
249 StreamOnMemory_CopyTo
,
250 StreamOnMemory_Commit
,
251 StreamOnMemory_Revert
,
252 StreamOnMemory_LockRegion
,
253 StreamOnMemory_UnlockRegion
,
255 StreamOnMemory_Clone
,
258 /******************************************
259 * StreamOnFileHandle implementation (internal)
262 typedef struct StreamOnFileHandle
{
263 IStream IStream_iface
;
269 } StreamOnFileHandle
;
271 static inline StreamOnFileHandle
*StreamOnFileHandle_from_IStream(IStream
*iface
)
273 return CONTAINING_RECORD(iface
, StreamOnFileHandle
, IStream_iface
);
276 static HRESULT WINAPI
StreamOnFileHandle_QueryInterface(IStream
*iface
,
277 REFIID iid
, void **ppv
)
279 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
281 if (!ppv
) return E_INVALIDARG
;
283 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IStream
, iid
) ||
284 IsEqualIID(&IID_ISequentialStream
, iid
))
287 IUnknown_AddRef((IUnknown
*)*ppv
);
293 return E_NOINTERFACE
;
297 static ULONG WINAPI
StreamOnFileHandle_AddRef(IStream
*iface
)
299 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
300 ULONG ref
= InterlockedIncrement(&This
->ref
);
302 TRACE("(%p) refcount=%u\n", iface
, ref
);
307 static ULONG WINAPI
StreamOnFileHandle_Release(IStream
*iface
)
309 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
310 ULONG ref
= InterlockedDecrement(&This
->ref
);
312 TRACE("(%p) refcount=%u\n", iface
, ref
);
315 IWICStream_Release(This
->stream
);
316 UnmapViewOfFile(This
->mem
);
317 CloseHandle(This
->map
);
318 HeapFree(GetProcessHeap(), 0, This
);
323 static HRESULT WINAPI
StreamOnFileHandle_Read(IStream
*iface
,
324 void *pv
, ULONG cb
, ULONG
*pcbRead
)
326 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
327 TRACE("(%p)\n", This
);
329 return IWICStream_Read(This
->stream
, pv
, cb
, pcbRead
);
332 static HRESULT WINAPI
StreamOnFileHandle_Write(IStream
*iface
,
333 void const *pv
, ULONG cb
, ULONG
*pcbWritten
)
335 ERR("(%p)\n", iface
);
336 return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED
);
339 static HRESULT WINAPI
StreamOnFileHandle_Seek(IStream
*iface
,
340 LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
342 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
343 TRACE("(%p)\n", This
);
345 return IWICStream_Seek(This
->stream
, dlibMove
, dwOrigin
, plibNewPosition
);
348 static HRESULT WINAPI
StreamOnFileHandle_SetSize(IStream
*iface
,
349 ULARGE_INTEGER libNewSize
)
351 TRACE("(%p)\n", iface
);
355 static HRESULT WINAPI
StreamOnFileHandle_CopyTo(IStream
*iface
,
356 IStream
*pstm
, ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
358 TRACE("(%p)\n", iface
);
362 static HRESULT WINAPI
StreamOnFileHandle_Commit(IStream
*iface
,
363 DWORD grfCommitFlags
)
365 TRACE("(%p)\n", iface
);
369 static HRESULT WINAPI
StreamOnFileHandle_Revert(IStream
*iface
)
371 TRACE("(%p)\n", iface
);
375 static HRESULT WINAPI
StreamOnFileHandle_LockRegion(IStream
*iface
,
376 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
378 TRACE("(%p)\n", iface
);
382 static HRESULT WINAPI
StreamOnFileHandle_UnlockRegion(IStream
*iface
,
383 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
385 TRACE("(%p)\n", iface
);
389 static HRESULT WINAPI
StreamOnFileHandle_Stat(IStream
*iface
,
390 STATSTG
*pstatstg
, DWORD grfStatFlag
)
392 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
393 TRACE("(%p)\n", This
);
395 return IWICStream_Stat(This
->stream
, pstatstg
, grfStatFlag
);
398 static HRESULT WINAPI
StreamOnFileHandle_Clone(IStream
*iface
,
401 TRACE("(%p)\n", iface
);
406 static const IStreamVtbl StreamOnFileHandle_Vtbl
=
408 /*** IUnknown methods ***/
409 StreamOnFileHandle_QueryInterface
,
410 StreamOnFileHandle_AddRef
,
411 StreamOnFileHandle_Release
,
412 /*** ISequentialStream methods ***/
413 StreamOnFileHandle_Read
,
414 StreamOnFileHandle_Write
,
415 /*** IStream methods ***/
416 StreamOnFileHandle_Seek
,
417 StreamOnFileHandle_SetSize
,
418 StreamOnFileHandle_CopyTo
,
419 StreamOnFileHandle_Commit
,
420 StreamOnFileHandle_Revert
,
421 StreamOnFileHandle_LockRegion
,
422 StreamOnFileHandle_UnlockRegion
,
423 StreamOnFileHandle_Stat
,
424 StreamOnFileHandle_Clone
,
427 /******************************************
428 * StreamOnStreamRange implementation
430 * Used by IWICStream_InitializeFromIStreamRegion
433 typedef struct StreamOnStreamRange
{
434 IStream IStream_iface
;
439 ULARGE_INTEGER offset
;
440 ULARGE_INTEGER max_size
;
442 CRITICAL_SECTION lock
;
443 } StreamOnStreamRange
;
445 static inline StreamOnStreamRange
*StreamOnStreamRange_from_IStream(IStream
*iface
)
447 return CONTAINING_RECORD(iface
, StreamOnStreamRange
, IStream_iface
);
450 static HRESULT WINAPI
StreamOnStreamRange_QueryInterface(IStream
*iface
,
451 REFIID iid
, void **ppv
)
453 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
455 if (!ppv
) return E_INVALIDARG
;
457 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IStream
, iid
) ||
458 IsEqualIID(&IID_ISequentialStream
, iid
))
461 IUnknown_AddRef((IUnknown
*)*ppv
);
467 return E_NOINTERFACE
;
471 static ULONG WINAPI
StreamOnStreamRange_AddRef(IStream
*iface
)
473 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
474 ULONG ref
= InterlockedIncrement(&This
->ref
);
476 TRACE("(%p) refcount=%u\n", iface
, ref
);
481 static ULONG WINAPI
StreamOnStreamRange_Release(IStream
*iface
)
483 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
484 ULONG ref
= InterlockedDecrement(&This
->ref
);
486 TRACE("(%p) refcount=%u\n", iface
, ref
);
489 This
->lock
.DebugInfo
->Spare
[0] = 0;
490 DeleteCriticalSection(&This
->lock
);
491 IStream_Release(This
->stream
);
492 HeapFree(GetProcessHeap(), 0, This
);
497 static HRESULT WINAPI
StreamOnStreamRange_Read(IStream
*iface
,
498 void *pv
, ULONG cb
, ULONG
*pcbRead
)
500 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
503 ULARGE_INTEGER OldPosition
;
504 LARGE_INTEGER SetPosition
;
505 TRACE("(%p)\n", This
);
507 if (!pv
) return E_INVALIDARG
;
509 EnterCriticalSection(&This
->lock
);
510 SetPosition
.QuadPart
= 0;
511 hr
= IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_CUR
, &OldPosition
);
514 SetPosition
.QuadPart
= This
->pos
.QuadPart
+ This
->offset
.QuadPart
;
515 hr
= IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_SET
, NULL
);
519 if (This
->pos
.QuadPart
+ cb
> This
->max_size
.QuadPart
)
521 /* This would read past the end of the stream. */
522 if (This
->pos
.QuadPart
> This
->max_size
.QuadPart
)
525 cb
= This
->max_size
.QuadPart
- This
->pos
.QuadPart
;
527 hr
= IStream_Read(This
->stream
, pv
, cb
, &uBytesRead
);
528 SetPosition
.QuadPart
= OldPosition
.QuadPart
;
529 IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_SET
, NULL
);
532 This
->pos
.QuadPart
+= uBytesRead
;
533 LeaveCriticalSection(&This
->lock
);
535 if (SUCCEEDED(hr
) && pcbRead
) *pcbRead
= uBytesRead
;
540 static HRESULT WINAPI
StreamOnStreamRange_Write(IStream
*iface
,
541 void const *pv
, ULONG cb
, ULONG
*pcbWritten
)
543 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
545 ULARGE_INTEGER OldPosition
;
546 LARGE_INTEGER SetPosition
;
547 ULONG uBytesWritten
=0;
548 TRACE("(%p)\n", This
);
550 if (!pv
) return E_INVALIDARG
;
552 EnterCriticalSection(&This
->lock
);
553 SetPosition
.QuadPart
= 0;
554 hr
= IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_CUR
, &OldPosition
);
557 SetPosition
.QuadPart
= This
->pos
.QuadPart
+ This
->offset
.QuadPart
;
558 hr
= IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_SET
, NULL
);
562 if (This
->pos
.QuadPart
+ cb
> This
->max_size
.QuadPart
)
564 /* This would read past the end of the stream. */
565 if (This
->pos
.QuadPart
> This
->max_size
.QuadPart
)
568 cb
= This
->max_size
.QuadPart
- This
->pos
.QuadPart
;
570 hr
= IStream_Write(This
->stream
, pv
, cb
, &uBytesWritten
);
571 SetPosition
.QuadPart
= OldPosition
.QuadPart
;
572 IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_SET
, NULL
);
575 This
->pos
.QuadPart
+= uBytesWritten
;
576 LeaveCriticalSection(&This
->lock
);
578 if (SUCCEEDED(hr
) && pcbWritten
) *pcbWritten
= uBytesWritten
;
583 static HRESULT WINAPI
StreamOnStreamRange_Seek(IStream
*iface
,
584 LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
586 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
587 ULARGE_INTEGER NewPosition
, actual_size
;
590 TRACE("(%p)\n", This
);
592 EnterCriticalSection(&This
->lock
);
593 actual_size
= This
->max_size
;
594 if (dwOrigin
== STREAM_SEEK_SET
)
595 NewPosition
.QuadPart
= dlibMove
.QuadPart
;
596 else if (dwOrigin
== STREAM_SEEK_CUR
)
597 NewPosition
.QuadPart
= This
->pos
.QuadPart
+ dlibMove
.QuadPart
;
598 else if (dwOrigin
== STREAM_SEEK_END
)
600 hr
= IStream_Stat(This
->stream
, &statstg
, STATFLAG_NONAME
);
603 if (This
->max_size
.QuadPart
+ This
->offset
.QuadPart
> statstg
.cbSize
.QuadPart
)
604 actual_size
.QuadPart
= statstg
.cbSize
.QuadPart
- This
->offset
.QuadPart
;
605 NewPosition
.QuadPart
= dlibMove
.QuadPart
+ actual_size
.QuadPart
;
608 else hr
= E_INVALIDARG
;
610 if (SUCCEEDED(hr
) && (NewPosition
.u
.HighPart
!= 0 || NewPosition
.QuadPart
> actual_size
.QuadPart
))
611 hr
= WINCODEC_ERR_VALUEOUTOFRANGE
;
614 This
->pos
.QuadPart
= NewPosition
.QuadPart
;
616 if(plibNewPosition
) plibNewPosition
->QuadPart
= This
->pos
.QuadPart
;
618 LeaveCriticalSection(&This
->lock
);
623 /* SetSize isn't implemented in the native windowscodecs DLL either */
624 static HRESULT WINAPI
StreamOnStreamRange_SetSize(IStream
*iface
,
625 ULARGE_INTEGER libNewSize
)
627 TRACE("(%p)\n", iface
);
631 /* CopyTo isn't implemented in the native windowscodecs DLL either */
632 static HRESULT WINAPI
StreamOnStreamRange_CopyTo(IStream
*iface
,
633 IStream
*pstm
, ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
635 TRACE("(%p)\n", iface
);
639 /* Commit isn't implemented in the native windowscodecs DLL either */
640 static HRESULT WINAPI
StreamOnStreamRange_Commit(IStream
*iface
,
641 DWORD grfCommitFlags
)
643 TRACE("(%p)\n", iface
);
647 /* Revert isn't implemented in the native windowscodecs DLL either */
648 static HRESULT WINAPI
StreamOnStreamRange_Revert(IStream
*iface
)
650 TRACE("(%p)\n", iface
);
654 /* LockRegion isn't implemented in the native windowscodecs DLL either */
655 static HRESULT WINAPI
StreamOnStreamRange_LockRegion(IStream
*iface
,
656 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
658 TRACE("(%p)\n", iface
);
662 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */
663 static HRESULT WINAPI
StreamOnStreamRange_UnlockRegion(IStream
*iface
,
664 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
666 TRACE("(%p)\n", iface
);
670 static HRESULT WINAPI
StreamOnStreamRange_Stat(IStream
*iface
,
671 STATSTG
*pstatstg
, DWORD grfStatFlag
)
673 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
675 TRACE("(%p)\n", This
);
677 if (!pstatstg
) return E_INVALIDARG
;
679 EnterCriticalSection(&This
->lock
);
680 hr
= IStream_Stat(This
->stream
, pstatstg
, grfStatFlag
);
683 pstatstg
->cbSize
.QuadPart
-= This
->offset
.QuadPart
;
684 if (This
->max_size
.QuadPart
< pstatstg
->cbSize
.QuadPart
)
685 pstatstg
->cbSize
.QuadPart
= This
->max_size
.QuadPart
;
688 LeaveCriticalSection(&This
->lock
);
693 /* Clone isn't implemented in the native windowscodecs DLL either */
694 static HRESULT WINAPI
StreamOnStreamRange_Clone(IStream
*iface
,
697 TRACE("(%p)\n", iface
);
702 static const IStreamVtbl StreamOnStreamRange_Vtbl
=
704 /*** IUnknown methods ***/
705 StreamOnStreamRange_QueryInterface
,
706 StreamOnStreamRange_AddRef
,
707 StreamOnStreamRange_Release
,
708 /*** ISequentialStream methods ***/
709 StreamOnStreamRange_Read
,
710 StreamOnStreamRange_Write
,
711 /*** IStream methods ***/
712 StreamOnStreamRange_Seek
,
713 StreamOnStreamRange_SetSize
,
714 StreamOnStreamRange_CopyTo
,
715 StreamOnStreamRange_Commit
,
716 StreamOnStreamRange_Revert
,
717 StreamOnStreamRange_LockRegion
,
718 StreamOnStreamRange_UnlockRegion
,
719 StreamOnStreamRange_Stat
,
720 StreamOnStreamRange_Clone
,
724 /******************************************
725 * IWICStream implementation
728 typedef struct IWICStreamImpl
730 IWICStream IWICStream_iface
;
736 static inline IWICStreamImpl
*impl_from_IWICStream(IWICStream
*iface
)
738 return CONTAINING_RECORD(iface
, IWICStreamImpl
, IWICStream_iface
);
741 static HRESULT WINAPI
IWICStreamImpl_QueryInterface(IWICStream
*iface
,
742 REFIID iid
, void **ppv
)
744 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
745 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
747 if (!ppv
) return E_INVALIDARG
;
749 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IStream
, iid
) ||
750 IsEqualIID(&IID_ISequentialStream
, iid
) || IsEqualIID(&IID_IWICStream
, iid
))
753 IUnknown_AddRef((IUnknown
*)*ppv
);
759 return E_NOINTERFACE
;
763 static ULONG WINAPI
IWICStreamImpl_AddRef(IWICStream
*iface
)
765 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
766 ULONG ref
= InterlockedIncrement(&This
->ref
);
768 TRACE("(%p) refcount=%u\n", iface
, ref
);
773 static ULONG WINAPI
IWICStreamImpl_Release(IWICStream
*iface
)
775 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
776 ULONG ref
= InterlockedDecrement(&This
->ref
);
778 TRACE("(%p) refcount=%u\n", iface
, ref
);
781 if (This
->pStream
) IStream_Release(This
->pStream
);
782 HeapFree(GetProcessHeap(), 0, This
);
787 static HRESULT WINAPI
IWICStreamImpl_Read(IWICStream
*iface
,
788 void *pv
, ULONG cb
, ULONG
*pcbRead
)
790 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
791 TRACE("(%p): relay\n", This
);
793 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
794 return IStream_Read(This
->pStream
, pv
, cb
, pcbRead
);
797 static HRESULT WINAPI
IWICStreamImpl_Write(IWICStream
*iface
,
798 void const *pv
, ULONG cb
, ULONG
*pcbWritten
)
800 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
801 TRACE("(%p): relay\n", This
);
803 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
804 return IStream_Write(This
->pStream
, pv
, cb
, pcbWritten
);
807 static HRESULT WINAPI
IWICStreamImpl_Seek(IWICStream
*iface
,
808 LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
810 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
811 TRACE("(%p): relay\n", This
);
813 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
814 return IStream_Seek(This
->pStream
, dlibMove
, dwOrigin
, plibNewPosition
);
817 static HRESULT WINAPI
IWICStreamImpl_SetSize(IWICStream
*iface
,
818 ULARGE_INTEGER libNewSize
)
820 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
821 TRACE("(%p): relay\n", This
);
823 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
824 return IStream_SetSize(This
->pStream
, libNewSize
);
827 static HRESULT WINAPI
IWICStreamImpl_CopyTo(IWICStream
*iface
,
828 IStream
*pstm
, ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
830 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
831 TRACE("(%p): relay\n", This
);
833 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
834 return IStream_CopyTo(This
->pStream
, pstm
, cb
, pcbRead
, pcbWritten
);
837 static HRESULT WINAPI
IWICStreamImpl_Commit(IWICStream
*iface
,
838 DWORD grfCommitFlags
)
840 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
841 TRACE("(%p): relay\n", This
);
843 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
844 return IStream_Commit(This
->pStream
, grfCommitFlags
);
847 static HRESULT WINAPI
IWICStreamImpl_Revert(IWICStream
*iface
)
849 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
850 TRACE("(%p): relay\n", This
);
852 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
853 return IStream_Revert(This
->pStream
);
856 static HRESULT WINAPI
IWICStreamImpl_LockRegion(IWICStream
*iface
,
857 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
859 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
860 TRACE("(%p): relay\n", This
);
862 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
863 return IStream_LockRegion(This
->pStream
, libOffset
, cb
, dwLockType
);
866 static HRESULT WINAPI
IWICStreamImpl_UnlockRegion(IWICStream
*iface
,
867 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
869 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
870 TRACE("(%p): relay\n", This
);
872 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
873 return IStream_UnlockRegion(This
->pStream
, libOffset
, cb
, dwLockType
);
876 static HRESULT WINAPI
IWICStreamImpl_Stat(IWICStream
*iface
,
877 STATSTG
*pstatstg
, DWORD grfStatFlag
)
879 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
880 TRACE("(%p): relay\n", This
);
882 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
883 return IStream_Stat(This
->pStream
, pstatstg
, grfStatFlag
);
886 static HRESULT WINAPI
IWICStreamImpl_Clone(IWICStream
*iface
,
889 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
890 TRACE("(%p): relay\n", This
);
892 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
893 return IStream_Clone(This
->pStream
, ppstm
);
896 static HRESULT WINAPI
IWICStreamImpl_InitializeFromIStream(IWICStream
*iface
,
899 ULARGE_INTEGER offset
, size
;
900 TRACE("(%p): relay\n", iface
);
903 size
.u
.LowPart
= 0xffffffff;
904 size
.u
.HighPart
= 0xffffffff;
905 return IWICStream_InitializeFromIStreamRegion(iface
, pIStream
, offset
, size
);
908 static HRESULT WINAPI
IWICStreamImpl_InitializeFromFilename(IWICStream
*iface
,
909 LPCWSTR wzFileName
, DWORD dwDesiredAccess
)
911 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
916 TRACE("(%p, %s, %u)\n", iface
, debugstr_w(wzFileName
), dwDesiredAccess
);
918 if (This
->pStream
) return WINCODEC_ERR_WRONGSTATE
;
920 if(dwDesiredAccess
& GENERIC_WRITE
)
921 dwMode
= STGM_SHARE_DENY_WRITE
| STGM_WRITE
| STGM_CREATE
;
922 else if(dwDesiredAccess
& GENERIC_READ
)
923 dwMode
= STGM_SHARE_DENY_WRITE
| STGM_READ
| STGM_FAILIFTHERE
;
927 hr
= SHCreateStreamOnFileW(wzFileName
, dwMode
, &stream
);
931 if (InterlockedCompareExchangePointer((void**)&This
->pStream
, stream
, NULL
))
933 /* Some other thread set the stream first. */
934 IStream_Release(stream
);
935 hr
= WINCODEC_ERR_WRONGSTATE
;
942 /******************************************
943 * IWICStream_InitializeFromMemory
945 * Initializes the internal IStream object to retrieve its data from a memory chunk.
948 * pbBuffer [I] pointer to the memory chunk
949 * cbBufferSize [I] number of bytes to use from the memory chunk
953 * FAILURE: E_INVALIDARG, if pbBuffer is NULL
954 * E_OUTOFMEMORY, if we run out of memory
955 * WINCODEC_ERR_WRONGSTATE, if the IStream object has already been initialized before
958 static HRESULT WINAPI
IWICStreamImpl_InitializeFromMemory(IWICStream
*iface
,
959 BYTE
*pbBuffer
, DWORD cbBufferSize
)
961 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
962 StreamOnMemory
*pObject
;
963 TRACE("(%p,%p)\n", iface
, pbBuffer
);
965 if (!pbBuffer
) return E_INVALIDARG
;
966 if (This
->pStream
) return WINCODEC_ERR_WRONGSTATE
;
968 pObject
= HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnMemory
));
969 if (!pObject
) return E_OUTOFMEMORY
;
971 pObject
->IStream_iface
.lpVtbl
= &StreamOnMemory_Vtbl
;
973 pObject
->pbMemory
= pbBuffer
;
974 pObject
->dwMemsize
= cbBufferSize
;
975 pObject
->dwCurPos
= 0;
976 InitializeCriticalSection(&pObject
->lock
);
977 pObject
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": StreamOnMemory.lock");
979 if (InterlockedCompareExchangePointer((void**)&This
->pStream
, pObject
, NULL
))
981 /* Some other thread set the stream first. */
982 IStream_Release(&pObject
->IStream_iface
);
983 return WINCODEC_ERR_WRONGSTATE
;
989 static HRESULT
map_file(HANDLE file
, HANDLE
*map
, void **mem
, LARGE_INTEGER
*size
)
992 if (!GetFileSizeEx(file
, size
)) return HRESULT_FROM_WIN32(GetLastError());
993 if (size
->u
.HighPart
)
995 WARN("file too large\n");
998 if (!(*map
= CreateFileMappingW(file
, NULL
, PAGE_READONLY
, 0, size
->u
.LowPart
, NULL
)))
1000 return HRESULT_FROM_WIN32(GetLastError());
1002 if (!(*mem
= MapViewOfFile(*map
, FILE_MAP_READ
, 0, 0, size
->u
.LowPart
)))
1005 return HRESULT_FROM_WIN32(GetLastError());
1010 HRESULT
stream_initialize_from_filehandle(IWICStream
*iface
, HANDLE file
)
1012 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
1013 StreamOnFileHandle
*pObject
;
1014 IWICStream
*stream
= NULL
;
1019 TRACE("(%p,%p)\n", iface
, file
);
1021 if (This
->pStream
) return WINCODEC_ERR_WRONGSTATE
;
1023 hr
= map_file(file
, &map
, &mem
, &size
);
1024 if (FAILED(hr
)) return hr
;
1026 hr
= StreamImpl_Create(&stream
);
1027 if (FAILED(hr
)) goto error
;
1029 hr
= IWICStreamImpl_InitializeFromMemory(stream
, mem
, size
.u
.LowPart
);
1030 if (FAILED(hr
)) goto error
;
1032 pObject
= HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnFileHandle
));
1038 pObject
->IStream_iface
.lpVtbl
= &StreamOnFileHandle_Vtbl
;
1042 pObject
->stream
= stream
;
1044 if (InterlockedCompareExchangePointer((void**)&This
->pStream
, pObject
, NULL
))
1046 /* Some other thread set the stream first. */
1047 IStream_Release(&pObject
->IStream_iface
);
1048 return WINCODEC_ERR_WRONGSTATE
;
1053 if (stream
) IWICStream_Release(stream
);
1054 UnmapViewOfFile(mem
);
1059 static HRESULT WINAPI
IWICStreamImpl_InitializeFromIStreamRegion(IWICStream
*iface
,
1060 IStream
*pIStream
, ULARGE_INTEGER ulOffset
, ULARGE_INTEGER ulMaxSize
)
1062 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
1063 StreamOnStreamRange
*pObject
;
1064 TRACE("(%p,%p)\n", iface
, pIStream
);
1066 if (!pIStream
) return E_INVALIDARG
;
1067 if (This
->pStream
) return WINCODEC_ERR_WRONGSTATE
;
1069 pObject
= HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnStreamRange
));
1070 if (!pObject
) return E_OUTOFMEMORY
;
1072 pObject
->IStream_iface
.lpVtbl
= &StreamOnStreamRange_Vtbl
;
1074 IStream_AddRef(pIStream
);
1075 pObject
->stream
= pIStream
;
1076 pObject
->pos
.QuadPart
= 0;
1077 pObject
->offset
= ulOffset
;
1078 pObject
->max_size
= ulMaxSize
;
1079 InitializeCriticalSection(&pObject
->lock
);
1080 pObject
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": StreamOnStreamRange.lock");
1082 if (InterlockedCompareExchangePointer((void**)&This
->pStream
, pObject
, NULL
))
1084 /* Some other thread set the stream first. */
1085 IStream_Release(&pObject
->IStream_iface
);
1086 return WINCODEC_ERR_WRONGSTATE
;
1093 static const IWICStreamVtbl WICStream_Vtbl
=
1095 /*** IUnknown methods ***/
1096 IWICStreamImpl_QueryInterface
,
1097 IWICStreamImpl_AddRef
,
1098 IWICStreamImpl_Release
,
1099 /*** ISequentialStream methods ***/
1100 IWICStreamImpl_Read
,
1101 IWICStreamImpl_Write
,
1102 /*** IStream methods ***/
1103 IWICStreamImpl_Seek
,
1104 IWICStreamImpl_SetSize
,
1105 IWICStreamImpl_CopyTo
,
1106 IWICStreamImpl_Commit
,
1107 IWICStreamImpl_Revert
,
1108 IWICStreamImpl_LockRegion
,
1109 IWICStreamImpl_UnlockRegion
,
1110 IWICStreamImpl_Stat
,
1111 IWICStreamImpl_Clone
,
1112 /*** IWICStream methods ***/
1113 IWICStreamImpl_InitializeFromIStream
,
1114 IWICStreamImpl_InitializeFromFilename
,
1115 IWICStreamImpl_InitializeFromMemory
,
1116 IWICStreamImpl_InitializeFromIStreamRegion
,
1119 HRESULT
StreamImpl_Create(IWICStream
**stream
)
1121 IWICStreamImpl
*pObject
;
1123 if( !stream
) return E_INVALIDARG
;
1125 pObject
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWICStreamImpl
));
1128 return E_OUTOFMEMORY
;
1131 pObject
->IWICStream_iface
.lpVtbl
= &WICStream_Vtbl
;
1133 pObject
->pStream
= NULL
;
1135 *stream
= &pObject
->IWICStream_iface
;