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"
28 #include "wincodecs_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
32 /******************************************
33 * StreamOnMemory implementation
35 * Used by IWICStream_InitializeFromMemory
38 typedef struct StreamOnMemory
{
39 IStream IStream_iface
;
46 CRITICAL_SECTION lock
; /* must be held when pbMemory or dwCurPos is accessed */
49 static inline StreamOnMemory
*StreamOnMemory_from_IStream(IStream
*iface
)
51 return CONTAINING_RECORD(iface
, StreamOnMemory
, IStream_iface
);
54 static HRESULT WINAPI
StreamOnMemory_QueryInterface(IStream
*iface
,
55 REFIID iid
, void **ppv
)
57 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
59 if (!ppv
) return E_INVALIDARG
;
61 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IStream
, iid
) ||
62 IsEqualIID(&IID_ISequentialStream
, iid
))
65 IUnknown_AddRef((IUnknown
*)*ppv
);
75 static ULONG WINAPI
StreamOnMemory_AddRef(IStream
*iface
)
77 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
78 ULONG ref
= InterlockedIncrement(&This
->ref
);
80 TRACE("(%p) refcount=%u\n", iface
, ref
);
85 static ULONG WINAPI
StreamOnMemory_Release(IStream
*iface
)
87 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
88 ULONG ref
= InterlockedDecrement(&This
->ref
);
90 TRACE("(%p) refcount=%u\n", iface
, ref
);
93 This
->lock
.DebugInfo
->Spare
[0] = 0;
94 DeleteCriticalSection(&This
->lock
);
95 HeapFree(GetProcessHeap(), 0, This
);
100 static HRESULT WINAPI
StreamOnMemory_Read(IStream
*iface
,
101 void *pv
, ULONG cb
, ULONG
*pcbRead
)
103 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
105 TRACE("(%p)\n", This
);
107 if (!pv
) return E_INVALIDARG
;
109 EnterCriticalSection(&This
->lock
);
110 uBytesRead
= min(cb
, This
->dwMemsize
- This
->dwCurPos
);
111 memmove(pv
, This
->pbMemory
+ This
->dwCurPos
, uBytesRead
);
112 This
->dwCurPos
+= uBytesRead
;
113 LeaveCriticalSection(&This
->lock
);
115 if (pcbRead
) *pcbRead
= uBytesRead
;
120 static HRESULT WINAPI
StreamOnMemory_Write(IStream
*iface
,
121 void const *pv
, ULONG cb
, ULONG
*pcbWritten
)
123 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
125 TRACE("(%p)\n", This
);
127 if (!pv
) return E_INVALIDARG
;
129 EnterCriticalSection(&This
->lock
);
130 if (cb
> This
->dwMemsize
- This
->dwCurPos
) {
131 hr
= STG_E_MEDIUMFULL
;
134 memmove(This
->pbMemory
+ This
->dwCurPos
, pv
, cb
);
135 This
->dwCurPos
+= cb
;
137 if (pcbWritten
) *pcbWritten
= cb
;
139 LeaveCriticalSection(&This
->lock
);
144 static HRESULT WINAPI
StreamOnMemory_Seek(IStream
*iface
,
145 LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
147 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
148 LARGE_INTEGER NewPosition
;
150 TRACE("(%p)\n", This
);
152 EnterCriticalSection(&This
->lock
);
153 if (dwOrigin
== STREAM_SEEK_SET
) NewPosition
.QuadPart
= dlibMove
.QuadPart
;
154 else if (dwOrigin
== STREAM_SEEK_CUR
) NewPosition
.QuadPart
= This
->dwCurPos
+ dlibMove
.QuadPart
;
155 else if (dwOrigin
== STREAM_SEEK_END
) NewPosition
.QuadPart
= This
->dwMemsize
+ dlibMove
.QuadPart
;
156 else hr
= E_INVALIDARG
;
159 if (NewPosition
.u
.HighPart
) hr
= HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW
);
160 else if (NewPosition
.QuadPart
> This
->dwMemsize
) hr
= E_INVALIDARG
;
161 else if (NewPosition
.QuadPart
< 0) hr
= E_INVALIDARG
;
165 This
->dwCurPos
= NewPosition
.u
.LowPart
;
167 if(plibNewPosition
) plibNewPosition
->QuadPart
= This
->dwCurPos
;
169 LeaveCriticalSection(&This
->lock
);
174 /* SetSize isn't implemented in the native windowscodecs DLL either */
175 static HRESULT WINAPI
StreamOnMemory_SetSize(IStream
*iface
,
176 ULARGE_INTEGER libNewSize
)
178 TRACE("(%p)\n", iface
);
182 /* CopyTo isn't implemented in the native windowscodecs DLL either */
183 static HRESULT WINAPI
StreamOnMemory_CopyTo(IStream
*iface
,
184 IStream
*pstm
, ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
186 TRACE("(%p)\n", iface
);
190 /* Commit isn't implemented in the native windowscodecs DLL either */
191 static HRESULT WINAPI
StreamOnMemory_Commit(IStream
*iface
,
192 DWORD grfCommitFlags
)
194 TRACE("(%p)\n", iface
);
198 /* Revert isn't implemented in the native windowscodecs DLL either */
199 static HRESULT WINAPI
StreamOnMemory_Revert(IStream
*iface
)
201 TRACE("(%p)\n", iface
);
205 /* LockRegion isn't implemented in the native windowscodecs DLL either */
206 static HRESULT WINAPI
StreamOnMemory_LockRegion(IStream
*iface
,
207 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
209 TRACE("(%p)\n", iface
);
213 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */
214 static HRESULT WINAPI
StreamOnMemory_UnlockRegion(IStream
*iface
,
215 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
217 TRACE("(%p)\n", iface
);
221 static HRESULT WINAPI
StreamOnMemory_Stat(IStream
*iface
,
222 STATSTG
*pstatstg
, DWORD grfStatFlag
)
224 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
225 TRACE("(%p)\n", This
);
227 if (!pstatstg
) return E_INVALIDARG
;
229 ZeroMemory(pstatstg
, sizeof(STATSTG
));
230 pstatstg
->type
= STGTY_STREAM
;
231 pstatstg
->cbSize
.QuadPart
= This
->dwMemsize
;
236 /* Clone isn't implemented in the native windowscodecs DLL either */
237 static HRESULT WINAPI
StreamOnMemory_Clone(IStream
*iface
,
240 TRACE("(%p)\n", iface
);
245 static const IStreamVtbl StreamOnMemory_Vtbl
=
247 /*** IUnknown methods ***/
248 StreamOnMemory_QueryInterface
,
249 StreamOnMemory_AddRef
,
250 StreamOnMemory_Release
,
251 /*** ISequentialStream methods ***/
253 StreamOnMemory_Write
,
254 /*** IStream methods ***/
256 StreamOnMemory_SetSize
,
257 StreamOnMemory_CopyTo
,
258 StreamOnMemory_Commit
,
259 StreamOnMemory_Revert
,
260 StreamOnMemory_LockRegion
,
261 StreamOnMemory_UnlockRegion
,
263 StreamOnMemory_Clone
,
266 /******************************************
267 * StreamOnFileHandle implementation (internal)
270 typedef struct StreamOnFileHandle
{
271 IStream IStream_iface
;
277 } StreamOnFileHandle
;
279 static inline StreamOnFileHandle
*StreamOnFileHandle_from_IStream(IStream
*iface
)
281 return CONTAINING_RECORD(iface
, StreamOnFileHandle
, IStream_iface
);
284 static HRESULT WINAPI
StreamOnFileHandle_QueryInterface(IStream
*iface
,
285 REFIID iid
, void **ppv
)
287 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
289 if (!ppv
) return E_INVALIDARG
;
291 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IStream
, iid
) ||
292 IsEqualIID(&IID_ISequentialStream
, iid
))
295 IUnknown_AddRef((IUnknown
*)*ppv
);
301 return E_NOINTERFACE
;
305 static ULONG WINAPI
StreamOnFileHandle_AddRef(IStream
*iface
)
307 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
308 ULONG ref
= InterlockedIncrement(&This
->ref
);
310 TRACE("(%p) refcount=%u\n", iface
, ref
);
315 static ULONG WINAPI
StreamOnFileHandle_Release(IStream
*iface
)
317 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
318 ULONG ref
= InterlockedDecrement(&This
->ref
);
320 TRACE("(%p) refcount=%u\n", iface
, ref
);
323 IWICStream_Release(This
->stream
);
324 UnmapViewOfFile(This
->mem
);
325 CloseHandle(This
->map
);
326 HeapFree(GetProcessHeap(), 0, This
);
331 static HRESULT WINAPI
StreamOnFileHandle_Read(IStream
*iface
,
332 void *pv
, ULONG cb
, ULONG
*pcbRead
)
334 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
335 TRACE("(%p)\n", This
);
337 return IWICStream_Read(This
->stream
, pv
, cb
, pcbRead
);
340 static HRESULT WINAPI
StreamOnFileHandle_Write(IStream
*iface
,
341 void const *pv
, ULONG cb
, ULONG
*pcbWritten
)
343 ERR("(%p)\n", iface
);
344 return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED
);
347 static HRESULT WINAPI
StreamOnFileHandle_Seek(IStream
*iface
,
348 LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
350 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
351 TRACE("(%p)\n", This
);
353 return IWICStream_Seek(This
->stream
, dlibMove
, dwOrigin
, plibNewPosition
);
356 static HRESULT WINAPI
StreamOnFileHandle_SetSize(IStream
*iface
,
357 ULARGE_INTEGER libNewSize
)
359 TRACE("(%p)\n", iface
);
363 static HRESULT WINAPI
StreamOnFileHandle_CopyTo(IStream
*iface
,
364 IStream
*pstm
, ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
366 TRACE("(%p)\n", iface
);
370 static HRESULT WINAPI
StreamOnFileHandle_Commit(IStream
*iface
,
371 DWORD grfCommitFlags
)
373 TRACE("(%p)\n", iface
);
377 static HRESULT WINAPI
StreamOnFileHandle_Revert(IStream
*iface
)
379 TRACE("(%p)\n", iface
);
383 static HRESULT WINAPI
StreamOnFileHandle_LockRegion(IStream
*iface
,
384 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
386 TRACE("(%p)\n", iface
);
390 static HRESULT WINAPI
StreamOnFileHandle_UnlockRegion(IStream
*iface
,
391 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
393 TRACE("(%p)\n", iface
);
397 static HRESULT WINAPI
StreamOnFileHandle_Stat(IStream
*iface
,
398 STATSTG
*pstatstg
, DWORD grfStatFlag
)
400 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
401 TRACE("(%p)\n", This
);
403 return IWICStream_Stat(This
->stream
, pstatstg
, grfStatFlag
);
406 static HRESULT WINAPI
StreamOnFileHandle_Clone(IStream
*iface
,
409 TRACE("(%p)\n", iface
);
414 static const IStreamVtbl StreamOnFileHandle_Vtbl
=
416 /*** IUnknown methods ***/
417 StreamOnFileHandle_QueryInterface
,
418 StreamOnFileHandle_AddRef
,
419 StreamOnFileHandle_Release
,
420 /*** ISequentialStream methods ***/
421 StreamOnFileHandle_Read
,
422 StreamOnFileHandle_Write
,
423 /*** IStream methods ***/
424 StreamOnFileHandle_Seek
,
425 StreamOnFileHandle_SetSize
,
426 StreamOnFileHandle_CopyTo
,
427 StreamOnFileHandle_Commit
,
428 StreamOnFileHandle_Revert
,
429 StreamOnFileHandle_LockRegion
,
430 StreamOnFileHandle_UnlockRegion
,
431 StreamOnFileHandle_Stat
,
432 StreamOnFileHandle_Clone
,
435 /******************************************
436 * StreamOnStreamRange implementation
438 * Used by IWICStream_InitializeFromIStreamRegion
441 typedef struct StreamOnStreamRange
{
442 IStream IStream_iface
;
447 ULARGE_INTEGER offset
;
448 ULARGE_INTEGER max_size
;
450 CRITICAL_SECTION lock
;
451 } StreamOnStreamRange
;
453 static inline StreamOnStreamRange
*StreamOnStreamRange_from_IStream(IStream
*iface
)
455 return CONTAINING_RECORD(iface
, StreamOnStreamRange
, IStream_iface
);
458 static HRESULT WINAPI
StreamOnStreamRange_QueryInterface(IStream
*iface
,
459 REFIID iid
, void **ppv
)
461 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
463 if (!ppv
) return E_INVALIDARG
;
465 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IStream
, iid
) ||
466 IsEqualIID(&IID_ISequentialStream
, iid
))
469 IUnknown_AddRef((IUnknown
*)*ppv
);
475 return E_NOINTERFACE
;
479 static ULONG WINAPI
StreamOnStreamRange_AddRef(IStream
*iface
)
481 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
482 ULONG ref
= InterlockedIncrement(&This
->ref
);
484 TRACE("(%p) refcount=%u\n", iface
, ref
);
489 static ULONG WINAPI
StreamOnStreamRange_Release(IStream
*iface
)
491 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
492 ULONG ref
= InterlockedDecrement(&This
->ref
);
494 TRACE("(%p) refcount=%u\n", iface
, ref
);
497 This
->lock
.DebugInfo
->Spare
[0] = 0;
498 DeleteCriticalSection(&This
->lock
);
499 IStream_Release(This
->stream
);
500 HeapFree(GetProcessHeap(), 0, This
);
505 static HRESULT WINAPI
StreamOnStreamRange_Read(IStream
*iface
,
506 void *pv
, ULONG cb
, ULONG
*pcbRead
)
508 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
511 ULARGE_INTEGER OldPosition
;
512 LARGE_INTEGER SetPosition
;
513 TRACE("(%p)\n", This
);
515 if (!pv
) return E_INVALIDARG
;
517 EnterCriticalSection(&This
->lock
);
518 SetPosition
.QuadPart
= 0;
519 hr
= IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_CUR
, &OldPosition
);
522 SetPosition
.QuadPart
= This
->pos
.QuadPart
+ This
->offset
.QuadPart
;
523 hr
= IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_SET
, NULL
);
527 if (This
->pos
.QuadPart
+ cb
> This
->max_size
.QuadPart
)
529 /* This would read past the end of the stream. */
530 if (This
->pos
.QuadPart
> This
->max_size
.QuadPart
)
533 cb
= This
->max_size
.QuadPart
- This
->pos
.QuadPart
;
535 hr
= IStream_Read(This
->stream
, pv
, cb
, &uBytesRead
);
536 SetPosition
.QuadPart
= OldPosition
.QuadPart
;
537 IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_SET
, NULL
);
540 This
->pos
.QuadPart
+= uBytesRead
;
541 LeaveCriticalSection(&This
->lock
);
543 if (SUCCEEDED(hr
) && pcbRead
) *pcbRead
= uBytesRead
;
548 static HRESULT WINAPI
StreamOnStreamRange_Write(IStream
*iface
,
549 void const *pv
, ULONG cb
, ULONG
*pcbWritten
)
551 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
553 ULARGE_INTEGER OldPosition
;
554 LARGE_INTEGER SetPosition
;
555 ULONG uBytesWritten
=0;
556 TRACE("(%p)\n", This
);
558 if (!pv
) return E_INVALIDARG
;
560 EnterCriticalSection(&This
->lock
);
561 SetPosition
.QuadPart
= 0;
562 hr
= IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_CUR
, &OldPosition
);
565 SetPosition
.QuadPart
= This
->pos
.QuadPart
+ This
->offset
.QuadPart
;
566 hr
= IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_SET
, NULL
);
570 if (This
->pos
.QuadPart
+ cb
> This
->max_size
.QuadPart
)
572 /* This would read past the end of the stream. */
573 if (This
->pos
.QuadPart
> This
->max_size
.QuadPart
)
576 cb
= This
->max_size
.QuadPart
- This
->pos
.QuadPart
;
578 hr
= IStream_Write(This
->stream
, pv
, cb
, &uBytesWritten
);
579 SetPosition
.QuadPart
= OldPosition
.QuadPart
;
580 IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_SET
, NULL
);
583 This
->pos
.QuadPart
+= uBytesWritten
;
584 LeaveCriticalSection(&This
->lock
);
586 if (SUCCEEDED(hr
) && pcbWritten
) *pcbWritten
= uBytesWritten
;
591 static HRESULT WINAPI
StreamOnStreamRange_Seek(IStream
*iface
,
592 LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
594 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
595 ULARGE_INTEGER NewPosition
, actual_size
;
598 TRACE("(%p)\n", This
);
600 EnterCriticalSection(&This
->lock
);
601 actual_size
= This
->max_size
;
602 if (dwOrigin
== STREAM_SEEK_SET
)
603 NewPosition
.QuadPart
= dlibMove
.QuadPart
;
604 else if (dwOrigin
== STREAM_SEEK_CUR
)
605 NewPosition
.QuadPart
= This
->pos
.QuadPart
+ dlibMove
.QuadPart
;
606 else if (dwOrigin
== STREAM_SEEK_END
)
608 hr
= IStream_Stat(This
->stream
, &statstg
, STATFLAG_NONAME
);
611 if (This
->max_size
.QuadPart
+ This
->offset
.QuadPart
> statstg
.cbSize
.QuadPart
)
612 actual_size
.QuadPart
= statstg
.cbSize
.QuadPart
- This
->offset
.QuadPart
;
613 NewPosition
.QuadPart
= dlibMove
.QuadPart
+ actual_size
.QuadPart
;
616 else hr
= E_INVALIDARG
;
618 if (SUCCEEDED(hr
) && (NewPosition
.u
.HighPart
!= 0 || NewPosition
.QuadPart
> actual_size
.QuadPart
))
619 hr
= WINCODEC_ERR_VALUEOUTOFRANGE
;
622 This
->pos
.QuadPart
= NewPosition
.QuadPart
;
624 if(plibNewPosition
) plibNewPosition
->QuadPart
= This
->pos
.QuadPart
;
626 LeaveCriticalSection(&This
->lock
);
631 /* SetSize isn't implemented in the native windowscodecs DLL either */
632 static HRESULT WINAPI
StreamOnStreamRange_SetSize(IStream
*iface
,
633 ULARGE_INTEGER libNewSize
)
635 TRACE("(%p)\n", iface
);
639 /* CopyTo isn't implemented in the native windowscodecs DLL either */
640 static HRESULT WINAPI
StreamOnStreamRange_CopyTo(IStream
*iface
,
641 IStream
*pstm
, ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
643 TRACE("(%p)\n", iface
);
647 /* Commit isn't implemented in the native windowscodecs DLL either */
648 static HRESULT WINAPI
StreamOnStreamRange_Commit(IStream
*iface
,
649 DWORD grfCommitFlags
)
651 TRACE("(%p)\n", iface
);
655 /* Revert isn't implemented in the native windowscodecs DLL either */
656 static HRESULT WINAPI
StreamOnStreamRange_Revert(IStream
*iface
)
658 TRACE("(%p)\n", iface
);
662 /* LockRegion isn't implemented in the native windowscodecs DLL either */
663 static HRESULT WINAPI
StreamOnStreamRange_LockRegion(IStream
*iface
,
664 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
666 TRACE("(%p)\n", iface
);
670 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */
671 static HRESULT WINAPI
StreamOnStreamRange_UnlockRegion(IStream
*iface
,
672 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
674 TRACE("(%p)\n", iface
);
678 static HRESULT WINAPI
StreamOnStreamRange_Stat(IStream
*iface
,
679 STATSTG
*pstatstg
, DWORD grfStatFlag
)
681 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
683 TRACE("(%p)\n", This
);
685 if (!pstatstg
) return E_INVALIDARG
;
687 EnterCriticalSection(&This
->lock
);
688 hr
= IStream_Stat(This
->stream
, pstatstg
, grfStatFlag
);
691 pstatstg
->cbSize
.QuadPart
-= This
->offset
.QuadPart
;
692 if (This
->max_size
.QuadPart
< pstatstg
->cbSize
.QuadPart
)
693 pstatstg
->cbSize
.QuadPart
= This
->max_size
.QuadPart
;
696 LeaveCriticalSection(&This
->lock
);
701 /* Clone isn't implemented in the native windowscodecs DLL either */
702 static HRESULT WINAPI
StreamOnStreamRange_Clone(IStream
*iface
,
705 TRACE("(%p)\n", iface
);
710 static const IStreamVtbl StreamOnStreamRange_Vtbl
=
712 /*** IUnknown methods ***/
713 StreamOnStreamRange_QueryInterface
,
714 StreamOnStreamRange_AddRef
,
715 StreamOnStreamRange_Release
,
716 /*** ISequentialStream methods ***/
717 StreamOnStreamRange_Read
,
718 StreamOnStreamRange_Write
,
719 /*** IStream methods ***/
720 StreamOnStreamRange_Seek
,
721 StreamOnStreamRange_SetSize
,
722 StreamOnStreamRange_CopyTo
,
723 StreamOnStreamRange_Commit
,
724 StreamOnStreamRange_Revert
,
725 StreamOnStreamRange_LockRegion
,
726 StreamOnStreamRange_UnlockRegion
,
727 StreamOnStreamRange_Stat
,
728 StreamOnStreamRange_Clone
,
732 /******************************************
733 * IWICStream implementation
736 typedef struct IWICStreamImpl
738 IWICStream IWICStream_iface
;
744 static inline IWICStreamImpl
*impl_from_IWICStream(IWICStream
*iface
)
746 return CONTAINING_RECORD(iface
, IWICStreamImpl
, IWICStream_iface
);
749 static HRESULT WINAPI
IWICStreamImpl_QueryInterface(IWICStream
*iface
,
750 REFIID iid
, void **ppv
)
752 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
753 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
755 if (!ppv
) return E_INVALIDARG
;
757 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IStream
, iid
) ||
758 IsEqualIID(&IID_ISequentialStream
, iid
) || IsEqualIID(&IID_IWICStream
, iid
))
760 *ppv
= &This
->IWICStream_iface
;
761 IUnknown_AddRef((IUnknown
*)*ppv
);
767 return E_NOINTERFACE
;
771 static ULONG WINAPI
IWICStreamImpl_AddRef(IWICStream
*iface
)
773 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
774 ULONG ref
= InterlockedIncrement(&This
->ref
);
776 TRACE("(%p) refcount=%u\n", iface
, ref
);
781 static ULONG WINAPI
IWICStreamImpl_Release(IWICStream
*iface
)
783 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
784 ULONG ref
= InterlockedDecrement(&This
->ref
);
786 TRACE("(%p) refcount=%u\n", iface
, ref
);
789 if (This
->pStream
) IStream_Release(This
->pStream
);
790 HeapFree(GetProcessHeap(), 0, This
);
795 static HRESULT WINAPI
IWICStreamImpl_Read(IWICStream
*iface
,
796 void *pv
, ULONG cb
, ULONG
*pcbRead
)
798 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
799 TRACE("(%p): relay\n", This
);
801 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
802 return IStream_Read(This
->pStream
, pv
, cb
, pcbRead
);
805 static HRESULT WINAPI
IWICStreamImpl_Write(IWICStream
*iface
,
806 void const *pv
, ULONG cb
, ULONG
*pcbWritten
)
808 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
809 TRACE("(%p): relay\n", This
);
811 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
812 return IStream_Write(This
->pStream
, pv
, cb
, pcbWritten
);
815 static HRESULT WINAPI
IWICStreamImpl_Seek(IWICStream
*iface
,
816 LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
818 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
819 TRACE("(%p): relay\n", This
);
821 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
822 return IStream_Seek(This
->pStream
, dlibMove
, dwOrigin
, plibNewPosition
);
825 static HRESULT WINAPI
IWICStreamImpl_SetSize(IWICStream
*iface
,
826 ULARGE_INTEGER libNewSize
)
828 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
829 TRACE("(%p): relay\n", This
);
831 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
832 return IStream_SetSize(This
->pStream
, libNewSize
);
835 static HRESULT WINAPI
IWICStreamImpl_CopyTo(IWICStream
*iface
,
836 IStream
*pstm
, ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
838 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
839 TRACE("(%p): relay\n", This
);
841 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
842 return IStream_CopyTo(This
->pStream
, pstm
, cb
, pcbRead
, pcbWritten
);
845 static HRESULT WINAPI
IWICStreamImpl_Commit(IWICStream
*iface
,
846 DWORD grfCommitFlags
)
848 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
849 TRACE("(%p): relay\n", This
);
851 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
852 return IStream_Commit(This
->pStream
, grfCommitFlags
);
855 static HRESULT WINAPI
IWICStreamImpl_Revert(IWICStream
*iface
)
857 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
858 TRACE("(%p): relay\n", This
);
860 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
861 return IStream_Revert(This
->pStream
);
864 static HRESULT WINAPI
IWICStreamImpl_LockRegion(IWICStream
*iface
,
865 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
867 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
868 TRACE("(%p): relay\n", This
);
870 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
871 return IStream_LockRegion(This
->pStream
, libOffset
, cb
, dwLockType
);
874 static HRESULT WINAPI
IWICStreamImpl_UnlockRegion(IWICStream
*iface
,
875 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
877 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
878 TRACE("(%p): relay\n", This
);
880 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
881 return IStream_UnlockRegion(This
->pStream
, libOffset
, cb
, dwLockType
);
884 static HRESULT WINAPI
IWICStreamImpl_Stat(IWICStream
*iface
,
885 STATSTG
*pstatstg
, DWORD grfStatFlag
)
887 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
888 TRACE("(%p): relay\n", This
);
890 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
891 return IStream_Stat(This
->pStream
, pstatstg
, grfStatFlag
);
894 static HRESULT WINAPI
IWICStreamImpl_Clone(IWICStream
*iface
,
897 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
898 TRACE("(%p): relay\n", This
);
900 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
901 return IStream_Clone(This
->pStream
, ppstm
);
904 static HRESULT WINAPI
IWICStreamImpl_InitializeFromIStream(IWICStream
*iface
,
907 ULARGE_INTEGER offset
, size
;
908 TRACE("(%p): relay\n", iface
);
911 size
.u
.LowPart
= 0xffffffff;
912 size
.u
.HighPart
= 0xffffffff;
913 return IWICStream_InitializeFromIStreamRegion(iface
, pIStream
, offset
, size
);
916 static HRESULT WINAPI
IWICStreamImpl_InitializeFromFilename(IWICStream
*iface
,
917 LPCWSTR wzFileName
, DWORD dwDesiredAccess
)
919 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
924 TRACE("(%p, %s, %u)\n", iface
, debugstr_w(wzFileName
), dwDesiredAccess
);
926 if (This
->pStream
) return WINCODEC_ERR_WRONGSTATE
;
928 if(dwDesiredAccess
& GENERIC_WRITE
)
929 dwMode
= STGM_SHARE_DENY_WRITE
| STGM_WRITE
| STGM_CREATE
;
930 else if(dwDesiredAccess
& GENERIC_READ
)
931 dwMode
= STGM_SHARE_DENY_WRITE
| STGM_READ
| STGM_FAILIFTHERE
;
935 hr
= SHCreateStreamOnFileW(wzFileName
, dwMode
, &stream
);
939 if (InterlockedCompareExchangePointer((void**)&This
->pStream
, stream
, NULL
))
941 /* Some other thread set the stream first. */
942 IStream_Release(stream
);
943 hr
= WINCODEC_ERR_WRONGSTATE
;
950 /******************************************
951 * IWICStream_InitializeFromMemory
953 * Initializes the internal IStream object to retrieve its data from a memory chunk.
956 * pbBuffer [I] pointer to the memory chunk
957 * cbBufferSize [I] number of bytes to use from the memory chunk
961 * FAILURE: E_INVALIDARG, if pbBuffer is NULL
962 * E_OUTOFMEMORY, if we run out of memory
963 * WINCODEC_ERR_WRONGSTATE, if the IStream object has already been initialized before
966 static HRESULT WINAPI
IWICStreamImpl_InitializeFromMemory(IWICStream
*iface
,
967 BYTE
*pbBuffer
, DWORD cbBufferSize
)
969 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
970 StreamOnMemory
*pObject
;
971 TRACE("(%p,%p)\n", iface
, pbBuffer
);
973 if (!pbBuffer
) return E_INVALIDARG
;
974 if (This
->pStream
) return WINCODEC_ERR_WRONGSTATE
;
976 pObject
= HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnMemory
));
977 if (!pObject
) return E_OUTOFMEMORY
;
979 pObject
->IStream_iface
.lpVtbl
= &StreamOnMemory_Vtbl
;
981 pObject
->pbMemory
= pbBuffer
;
982 pObject
->dwMemsize
= cbBufferSize
;
983 pObject
->dwCurPos
= 0;
984 InitializeCriticalSection(&pObject
->lock
);
985 pObject
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": StreamOnMemory.lock");
987 if (InterlockedCompareExchangePointer((void**)&This
->pStream
, pObject
, NULL
))
989 /* Some other thread set the stream first. */
990 IStream_Release(&pObject
->IStream_iface
);
991 return WINCODEC_ERR_WRONGSTATE
;
997 static HRESULT
map_file(HANDLE file
, HANDLE
*map
, void **mem
, LARGE_INTEGER
*size
)
1000 if (!GetFileSizeEx(file
, size
)) return HRESULT_FROM_WIN32(GetLastError());
1001 if (size
->u
.HighPart
)
1003 WARN("file too large\n");
1006 if (!(*map
= CreateFileMappingW(file
, NULL
, PAGE_READONLY
, 0, size
->u
.LowPart
, NULL
)))
1008 return HRESULT_FROM_WIN32(GetLastError());
1010 if (!(*mem
= MapViewOfFile(*map
, FILE_MAP_READ
, 0, 0, size
->u
.LowPart
)))
1013 return HRESULT_FROM_WIN32(GetLastError());
1018 HRESULT
stream_initialize_from_filehandle(IWICStream
*iface
, HANDLE file
)
1020 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
1021 StreamOnFileHandle
*pObject
;
1022 IWICStream
*stream
= NULL
;
1027 TRACE("(%p,%p)\n", iface
, file
);
1029 if (This
->pStream
) return WINCODEC_ERR_WRONGSTATE
;
1031 hr
= map_file(file
, &map
, &mem
, &size
);
1032 if (FAILED(hr
)) return hr
;
1034 hr
= StreamImpl_Create(&stream
);
1035 if (FAILED(hr
)) goto error
;
1037 hr
= IWICStreamImpl_InitializeFromMemory(stream
, mem
, size
.u
.LowPart
);
1038 if (FAILED(hr
)) goto error
;
1040 pObject
= HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnFileHandle
));
1046 pObject
->IStream_iface
.lpVtbl
= &StreamOnFileHandle_Vtbl
;
1050 pObject
->stream
= stream
;
1052 if (InterlockedCompareExchangePointer((void**)&This
->pStream
, pObject
, NULL
))
1054 /* Some other thread set the stream first. */
1055 IStream_Release(&pObject
->IStream_iface
);
1056 return WINCODEC_ERR_WRONGSTATE
;
1061 if (stream
) IWICStream_Release(stream
);
1062 UnmapViewOfFile(mem
);
1067 static HRESULT WINAPI
IWICStreamImpl_InitializeFromIStreamRegion(IWICStream
*iface
,
1068 IStream
*pIStream
, ULARGE_INTEGER ulOffset
, ULARGE_INTEGER ulMaxSize
)
1070 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
1071 StreamOnStreamRange
*pObject
;
1072 TRACE("(%p,%p)\n", iface
, pIStream
);
1074 if (!pIStream
) return E_INVALIDARG
;
1075 if (This
->pStream
) return WINCODEC_ERR_WRONGSTATE
;
1077 pObject
= HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnStreamRange
));
1078 if (!pObject
) return E_OUTOFMEMORY
;
1080 pObject
->IStream_iface
.lpVtbl
= &StreamOnStreamRange_Vtbl
;
1082 IStream_AddRef(pIStream
);
1083 pObject
->stream
= pIStream
;
1084 pObject
->pos
.QuadPart
= 0;
1085 pObject
->offset
= ulOffset
;
1086 pObject
->max_size
= ulMaxSize
;
1087 InitializeCriticalSection(&pObject
->lock
);
1088 pObject
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": StreamOnStreamRange.lock");
1090 if (InterlockedCompareExchangePointer((void**)&This
->pStream
, pObject
, NULL
))
1092 /* Some other thread set the stream first. */
1093 IStream_Release(&pObject
->IStream_iface
);
1094 return WINCODEC_ERR_WRONGSTATE
;
1101 static const IWICStreamVtbl WICStream_Vtbl
=
1103 /*** IUnknown methods ***/
1104 IWICStreamImpl_QueryInterface
,
1105 IWICStreamImpl_AddRef
,
1106 IWICStreamImpl_Release
,
1107 /*** ISequentialStream methods ***/
1108 IWICStreamImpl_Read
,
1109 IWICStreamImpl_Write
,
1110 /*** IStream methods ***/
1111 IWICStreamImpl_Seek
,
1112 IWICStreamImpl_SetSize
,
1113 IWICStreamImpl_CopyTo
,
1114 IWICStreamImpl_Commit
,
1115 IWICStreamImpl_Revert
,
1116 IWICStreamImpl_LockRegion
,
1117 IWICStreamImpl_UnlockRegion
,
1118 IWICStreamImpl_Stat
,
1119 IWICStreamImpl_Clone
,
1120 /*** IWICStream methods ***/
1121 IWICStreamImpl_InitializeFromIStream
,
1122 IWICStreamImpl_InitializeFromFilename
,
1123 IWICStreamImpl_InitializeFromMemory
,
1124 IWICStreamImpl_InitializeFromIStreamRegion
,
1127 HRESULT
StreamImpl_Create(IWICStream
**stream
)
1129 IWICStreamImpl
*pObject
;
1131 if( !stream
) return E_INVALIDARG
;
1133 pObject
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWICStreamImpl
));
1136 return E_OUTOFMEMORY
;
1139 pObject
->IWICStream_iface
.lpVtbl
= &WICStream_Vtbl
;
1141 pObject
->pStream
= NULL
;
1143 *stream
= &pObject
->IWICStream_iface
;