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 IStream IStream_iface
;
45 CRITICAL_SECTION lock
; /* must be held when pbMemory or dwCurPos is accessed */
48 static inline StreamOnMemory
*StreamOnMemory_from_IStream(IStream
*iface
)
50 return CONTAINING_RECORD(iface
, StreamOnMemory
, IStream_iface
);
53 static HRESULT WINAPI
StreamOnMemory_QueryInterface(IStream
*iface
,
54 REFIID iid
, void **ppv
)
56 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
58 if (!ppv
) return E_INVALIDARG
;
60 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IStream
, iid
) ||
61 IsEqualIID(&IID_ISequentialStream
, iid
))
64 IUnknown_AddRef((IUnknown
*)*ppv
);
74 static ULONG WINAPI
StreamOnMemory_AddRef(IStream
*iface
)
76 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
77 ULONG ref
= InterlockedIncrement(&This
->ref
);
79 TRACE("(%p) refcount=%u\n", iface
, ref
);
84 static ULONG WINAPI
StreamOnMemory_Release(IStream
*iface
)
86 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
87 ULONG ref
= InterlockedDecrement(&This
->ref
);
89 TRACE("(%p) refcount=%u\n", iface
, ref
);
92 This
->lock
.DebugInfo
->Spare
[0] = 0;
93 DeleteCriticalSection(&This
->lock
);
94 HeapFree(GetProcessHeap(), 0, This
);
99 static HRESULT WINAPI
StreamOnMemory_Read(IStream
*iface
,
100 void *pv
, ULONG cb
, ULONG
*pcbRead
)
102 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
104 TRACE("(%p)\n", This
);
106 if (!pv
) return E_INVALIDARG
;
108 EnterCriticalSection(&This
->lock
);
109 uBytesRead
= min(cb
, This
->dwMemsize
- This
->dwCurPos
);
110 memmove(pv
, This
->pbMemory
+ This
->dwCurPos
, uBytesRead
);
111 This
->dwCurPos
+= uBytesRead
;
112 LeaveCriticalSection(&This
->lock
);
114 if (pcbRead
) *pcbRead
= uBytesRead
;
119 static HRESULT WINAPI
StreamOnMemory_Write(IStream
*iface
,
120 void const *pv
, ULONG cb
, ULONG
*pcbWritten
)
122 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
124 TRACE("(%p)\n", This
);
126 if (!pv
) return E_INVALIDARG
;
128 EnterCriticalSection(&This
->lock
);
129 if (cb
> This
->dwMemsize
- This
->dwCurPos
) {
130 hr
= STG_E_MEDIUMFULL
;
133 memmove(This
->pbMemory
+ This
->dwCurPos
, pv
, cb
);
134 This
->dwCurPos
+= cb
;
136 if (pcbWritten
) *pcbWritten
= cb
;
138 LeaveCriticalSection(&This
->lock
);
143 static HRESULT WINAPI
StreamOnMemory_Seek(IStream
*iface
,
144 LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
146 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
147 LARGE_INTEGER NewPosition
;
149 TRACE("(%p)\n", This
);
151 EnterCriticalSection(&This
->lock
);
152 if (dwOrigin
== STREAM_SEEK_SET
) NewPosition
.QuadPart
= dlibMove
.QuadPart
;
153 else if (dwOrigin
== STREAM_SEEK_CUR
) NewPosition
.QuadPart
= This
->dwCurPos
+ dlibMove
.QuadPart
;
154 else if (dwOrigin
== STREAM_SEEK_END
) NewPosition
.QuadPart
= This
->dwMemsize
+ dlibMove
.QuadPart
;
155 else hr
= E_INVALIDARG
;
158 if (NewPosition
.u
.HighPart
) hr
= HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW
);
159 else if (NewPosition
.QuadPart
> This
->dwMemsize
) hr
= E_INVALIDARG
;
160 else if (NewPosition
.QuadPart
< 0) hr
= E_INVALIDARG
;
164 This
->dwCurPos
= NewPosition
.u
.LowPart
;
166 if(plibNewPosition
) plibNewPosition
->QuadPart
= This
->dwCurPos
;
168 LeaveCriticalSection(&This
->lock
);
173 /* SetSize isn't implemented in the native windowscodecs DLL either */
174 static HRESULT WINAPI
StreamOnMemory_SetSize(IStream
*iface
,
175 ULARGE_INTEGER libNewSize
)
177 TRACE("(%p)\n", iface
);
181 /* CopyTo isn't implemented in the native windowscodecs DLL either */
182 static HRESULT WINAPI
StreamOnMemory_CopyTo(IStream
*iface
,
183 IStream
*pstm
, ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
185 TRACE("(%p)\n", iface
);
189 /* Commit isn't implemented in the native windowscodecs DLL either */
190 static HRESULT WINAPI
StreamOnMemory_Commit(IStream
*iface
,
191 DWORD grfCommitFlags
)
193 TRACE("(%p)\n", iface
);
197 /* Revert isn't implemented in the native windowscodecs DLL either */
198 static HRESULT WINAPI
StreamOnMemory_Revert(IStream
*iface
)
200 TRACE("(%p)\n", iface
);
204 /* LockRegion isn't implemented in the native windowscodecs DLL either */
205 static HRESULT WINAPI
StreamOnMemory_LockRegion(IStream
*iface
,
206 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
208 TRACE("(%p)\n", iface
);
212 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */
213 static HRESULT WINAPI
StreamOnMemory_UnlockRegion(IStream
*iface
,
214 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
216 TRACE("(%p)\n", iface
);
220 static HRESULT WINAPI
StreamOnMemory_Stat(IStream
*iface
,
221 STATSTG
*pstatstg
, DWORD grfStatFlag
)
223 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
224 TRACE("(%p)\n", This
);
226 if (!pstatstg
) return E_INVALIDARG
;
228 ZeroMemory(pstatstg
, sizeof(STATSTG
));
229 pstatstg
->type
= STGTY_STREAM
;
230 pstatstg
->cbSize
.QuadPart
= This
->dwMemsize
;
235 /* Clone isn't implemented in the native windowscodecs DLL either */
236 static HRESULT WINAPI
StreamOnMemory_Clone(IStream
*iface
,
239 TRACE("(%p)\n", iface
);
244 static const IStreamVtbl StreamOnMemory_Vtbl
=
246 /*** IUnknown methods ***/
247 StreamOnMemory_QueryInterface
,
248 StreamOnMemory_AddRef
,
249 StreamOnMemory_Release
,
250 /*** ISequentialStream methods ***/
252 StreamOnMemory_Write
,
253 /*** IStream methods ***/
255 StreamOnMemory_SetSize
,
256 StreamOnMemory_CopyTo
,
257 StreamOnMemory_Commit
,
258 StreamOnMemory_Revert
,
259 StreamOnMemory_LockRegion
,
260 StreamOnMemory_UnlockRegion
,
262 StreamOnMemory_Clone
,
265 /******************************************
266 * StreamOnFileHandle implementation (internal)
269 typedef struct StreamOnFileHandle
{
270 IStream IStream_iface
;
276 } StreamOnFileHandle
;
278 static inline StreamOnFileHandle
*StreamOnFileHandle_from_IStream(IStream
*iface
)
280 return CONTAINING_RECORD(iface
, StreamOnFileHandle
, IStream_iface
);
283 static HRESULT WINAPI
StreamOnFileHandle_QueryInterface(IStream
*iface
,
284 REFIID iid
, void **ppv
)
286 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
288 if (!ppv
) return E_INVALIDARG
;
290 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IStream
, iid
) ||
291 IsEqualIID(&IID_ISequentialStream
, iid
))
294 IUnknown_AddRef((IUnknown
*)*ppv
);
300 return E_NOINTERFACE
;
304 static ULONG WINAPI
StreamOnFileHandle_AddRef(IStream
*iface
)
306 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
307 ULONG ref
= InterlockedIncrement(&This
->ref
);
309 TRACE("(%p) refcount=%u\n", iface
, ref
);
314 static ULONG WINAPI
StreamOnFileHandle_Release(IStream
*iface
)
316 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
317 ULONG ref
= InterlockedDecrement(&This
->ref
);
319 TRACE("(%p) refcount=%u\n", iface
, ref
);
322 IWICStream_Release(This
->stream
);
323 UnmapViewOfFile(This
->mem
);
324 CloseHandle(This
->map
);
325 HeapFree(GetProcessHeap(), 0, This
);
330 static HRESULT WINAPI
StreamOnFileHandle_Read(IStream
*iface
,
331 void *pv
, ULONG cb
, ULONG
*pcbRead
)
333 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
334 TRACE("(%p)\n", This
);
336 return IWICStream_Read(This
->stream
, pv
, cb
, pcbRead
);
339 static HRESULT WINAPI
StreamOnFileHandle_Write(IStream
*iface
,
340 void const *pv
, ULONG cb
, ULONG
*pcbWritten
)
342 ERR("(%p)\n", iface
);
343 return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED
);
346 static HRESULT WINAPI
StreamOnFileHandle_Seek(IStream
*iface
,
347 LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
349 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
350 TRACE("(%p)\n", This
);
352 return IWICStream_Seek(This
->stream
, dlibMove
, dwOrigin
, plibNewPosition
);
355 static HRESULT WINAPI
StreamOnFileHandle_SetSize(IStream
*iface
,
356 ULARGE_INTEGER libNewSize
)
358 TRACE("(%p)\n", iface
);
362 static HRESULT WINAPI
StreamOnFileHandle_CopyTo(IStream
*iface
,
363 IStream
*pstm
, ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
365 TRACE("(%p)\n", iface
);
369 static HRESULT WINAPI
StreamOnFileHandle_Commit(IStream
*iface
,
370 DWORD grfCommitFlags
)
372 TRACE("(%p)\n", iface
);
376 static HRESULT WINAPI
StreamOnFileHandle_Revert(IStream
*iface
)
378 TRACE("(%p)\n", iface
);
382 static HRESULT WINAPI
StreamOnFileHandle_LockRegion(IStream
*iface
,
383 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
385 TRACE("(%p)\n", iface
);
389 static HRESULT WINAPI
StreamOnFileHandle_UnlockRegion(IStream
*iface
,
390 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
392 TRACE("(%p)\n", iface
);
396 static HRESULT WINAPI
StreamOnFileHandle_Stat(IStream
*iface
,
397 STATSTG
*pstatstg
, DWORD grfStatFlag
)
399 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
400 TRACE("(%p)\n", This
);
402 return IWICStream_Stat(This
->stream
, pstatstg
, grfStatFlag
);
405 static HRESULT WINAPI
StreamOnFileHandle_Clone(IStream
*iface
,
408 TRACE("(%p)\n", iface
);
413 static const IStreamVtbl StreamOnFileHandle_Vtbl
=
415 /*** IUnknown methods ***/
416 StreamOnFileHandle_QueryInterface
,
417 StreamOnFileHandle_AddRef
,
418 StreamOnFileHandle_Release
,
419 /*** ISequentialStream methods ***/
420 StreamOnFileHandle_Read
,
421 StreamOnFileHandle_Write
,
422 /*** IStream methods ***/
423 StreamOnFileHandle_Seek
,
424 StreamOnFileHandle_SetSize
,
425 StreamOnFileHandle_CopyTo
,
426 StreamOnFileHandle_Commit
,
427 StreamOnFileHandle_Revert
,
428 StreamOnFileHandle_LockRegion
,
429 StreamOnFileHandle_UnlockRegion
,
430 StreamOnFileHandle_Stat
,
431 StreamOnFileHandle_Clone
,
434 /******************************************
435 * StreamOnStreamRange implementation
437 * Used by IWICStream_InitializeFromIStreamRegion
440 typedef struct StreamOnStreamRange
{
441 IStream IStream_iface
;
446 ULARGE_INTEGER offset
;
447 ULARGE_INTEGER max_size
;
449 CRITICAL_SECTION lock
;
450 } StreamOnStreamRange
;
452 static inline StreamOnStreamRange
*StreamOnStreamRange_from_IStream(IStream
*iface
)
454 return CONTAINING_RECORD(iface
, StreamOnStreamRange
, IStream_iface
);
457 static HRESULT WINAPI
StreamOnStreamRange_QueryInterface(IStream
*iface
,
458 REFIID iid
, void **ppv
)
460 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
462 if (!ppv
) return E_INVALIDARG
;
464 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IStream
, iid
) ||
465 IsEqualIID(&IID_ISequentialStream
, iid
))
468 IUnknown_AddRef((IUnknown
*)*ppv
);
474 return E_NOINTERFACE
;
478 static ULONG WINAPI
StreamOnStreamRange_AddRef(IStream
*iface
)
480 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
481 ULONG ref
= InterlockedIncrement(&This
->ref
);
483 TRACE("(%p) refcount=%u\n", iface
, ref
);
488 static ULONG WINAPI
StreamOnStreamRange_Release(IStream
*iface
)
490 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
491 ULONG ref
= InterlockedDecrement(&This
->ref
);
493 TRACE("(%p) refcount=%u\n", iface
, ref
);
496 This
->lock
.DebugInfo
->Spare
[0] = 0;
497 DeleteCriticalSection(&This
->lock
);
498 IStream_Release(This
->stream
);
499 HeapFree(GetProcessHeap(), 0, This
);
504 static HRESULT WINAPI
StreamOnStreamRange_Read(IStream
*iface
,
505 void *pv
, ULONG cb
, ULONG
*pcbRead
)
507 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
510 ULARGE_INTEGER OldPosition
;
511 LARGE_INTEGER SetPosition
;
512 TRACE("(%p)\n", This
);
514 if (!pv
) return E_INVALIDARG
;
516 EnterCriticalSection(&This
->lock
);
517 SetPosition
.QuadPart
= 0;
518 hr
= IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_CUR
, &OldPosition
);
521 SetPosition
.QuadPart
= This
->pos
.QuadPart
+ This
->offset
.QuadPart
;
522 hr
= IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_SET
, NULL
);
526 if (This
->pos
.QuadPart
+ cb
> This
->max_size
.QuadPart
)
528 /* This would read past the end of the stream. */
529 if (This
->pos
.QuadPart
> This
->max_size
.QuadPart
)
532 cb
= This
->max_size
.QuadPart
- This
->pos
.QuadPart
;
534 hr
= IStream_Read(This
->stream
, pv
, cb
, &uBytesRead
);
535 SetPosition
.QuadPart
= OldPosition
.QuadPart
;
536 IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_SET
, NULL
);
539 This
->pos
.QuadPart
+= uBytesRead
;
540 LeaveCriticalSection(&This
->lock
);
542 if (SUCCEEDED(hr
) && pcbRead
) *pcbRead
= uBytesRead
;
547 static HRESULT WINAPI
StreamOnStreamRange_Write(IStream
*iface
,
548 void const *pv
, ULONG cb
, ULONG
*pcbWritten
)
550 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
552 ULARGE_INTEGER OldPosition
;
553 LARGE_INTEGER SetPosition
;
554 ULONG uBytesWritten
=0;
555 TRACE("(%p)\n", This
);
557 if (!pv
) return E_INVALIDARG
;
559 EnterCriticalSection(&This
->lock
);
560 SetPosition
.QuadPart
= 0;
561 hr
= IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_CUR
, &OldPosition
);
564 SetPosition
.QuadPart
= This
->pos
.QuadPart
+ This
->offset
.QuadPart
;
565 hr
= IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_SET
, NULL
);
569 if (This
->pos
.QuadPart
+ cb
> This
->max_size
.QuadPart
)
571 /* This would read past the end of the stream. */
572 if (This
->pos
.QuadPart
> This
->max_size
.QuadPart
)
575 cb
= This
->max_size
.QuadPart
- This
->pos
.QuadPart
;
577 hr
= IStream_Write(This
->stream
, pv
, cb
, &uBytesWritten
);
578 SetPosition
.QuadPart
= OldPosition
.QuadPart
;
579 IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_SET
, NULL
);
582 This
->pos
.QuadPart
+= uBytesWritten
;
583 LeaveCriticalSection(&This
->lock
);
585 if (SUCCEEDED(hr
) && pcbWritten
) *pcbWritten
= uBytesWritten
;
590 static HRESULT WINAPI
StreamOnStreamRange_Seek(IStream
*iface
,
591 LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
593 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
594 ULARGE_INTEGER NewPosition
, actual_size
;
597 TRACE("(%p)\n", This
);
599 EnterCriticalSection(&This
->lock
);
600 actual_size
= This
->max_size
;
601 if (dwOrigin
== STREAM_SEEK_SET
)
602 NewPosition
.QuadPart
= dlibMove
.QuadPart
;
603 else if (dwOrigin
== STREAM_SEEK_CUR
)
604 NewPosition
.QuadPart
= This
->pos
.QuadPart
+ dlibMove
.QuadPart
;
605 else if (dwOrigin
== STREAM_SEEK_END
)
607 hr
= IStream_Stat(This
->stream
, &statstg
, STATFLAG_NONAME
);
610 if (This
->max_size
.QuadPart
+ This
->offset
.QuadPart
> statstg
.cbSize
.QuadPart
)
611 actual_size
.QuadPart
= statstg
.cbSize
.QuadPart
- This
->offset
.QuadPart
;
612 NewPosition
.QuadPart
= dlibMove
.QuadPart
+ actual_size
.QuadPart
;
615 else hr
= E_INVALIDARG
;
617 if (SUCCEEDED(hr
) && (NewPosition
.u
.HighPart
!= 0 || NewPosition
.QuadPart
> actual_size
.QuadPart
))
618 hr
= WINCODEC_ERR_VALUEOUTOFRANGE
;
621 This
->pos
.QuadPart
= NewPosition
.QuadPart
;
623 if(plibNewPosition
) plibNewPosition
->QuadPart
= This
->pos
.QuadPart
;
625 LeaveCriticalSection(&This
->lock
);
630 /* SetSize isn't implemented in the native windowscodecs DLL either */
631 static HRESULT WINAPI
StreamOnStreamRange_SetSize(IStream
*iface
,
632 ULARGE_INTEGER libNewSize
)
634 TRACE("(%p)\n", iface
);
638 /* CopyTo isn't implemented in the native windowscodecs DLL either */
639 static HRESULT WINAPI
StreamOnStreamRange_CopyTo(IStream
*iface
,
640 IStream
*pstm
, ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
642 TRACE("(%p)\n", iface
);
646 /* Commit isn't implemented in the native windowscodecs DLL either */
647 static HRESULT WINAPI
StreamOnStreamRange_Commit(IStream
*iface
,
648 DWORD grfCommitFlags
)
650 TRACE("(%p)\n", iface
);
654 /* Revert isn't implemented in the native windowscodecs DLL either */
655 static HRESULT WINAPI
StreamOnStreamRange_Revert(IStream
*iface
)
657 TRACE("(%p)\n", iface
);
661 /* LockRegion isn't implemented in the native windowscodecs DLL either */
662 static HRESULT WINAPI
StreamOnStreamRange_LockRegion(IStream
*iface
,
663 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
665 TRACE("(%p)\n", iface
);
669 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */
670 static HRESULT WINAPI
StreamOnStreamRange_UnlockRegion(IStream
*iface
,
671 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
673 TRACE("(%p)\n", iface
);
677 static HRESULT WINAPI
StreamOnStreamRange_Stat(IStream
*iface
,
678 STATSTG
*pstatstg
, DWORD grfStatFlag
)
680 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
682 TRACE("(%p)\n", This
);
684 if (!pstatstg
) return E_INVALIDARG
;
686 EnterCriticalSection(&This
->lock
);
687 hr
= IStream_Stat(This
->stream
, pstatstg
, grfStatFlag
);
690 pstatstg
->cbSize
.QuadPart
-= This
->offset
.QuadPart
;
691 if (This
->max_size
.QuadPart
< pstatstg
->cbSize
.QuadPart
)
692 pstatstg
->cbSize
.QuadPart
= This
->max_size
.QuadPart
;
695 LeaveCriticalSection(&This
->lock
);
700 /* Clone isn't implemented in the native windowscodecs DLL either */
701 static HRESULT WINAPI
StreamOnStreamRange_Clone(IStream
*iface
,
704 TRACE("(%p)\n", iface
);
709 static const IStreamVtbl StreamOnStreamRange_Vtbl
=
711 /*** IUnknown methods ***/
712 StreamOnStreamRange_QueryInterface
,
713 StreamOnStreamRange_AddRef
,
714 StreamOnStreamRange_Release
,
715 /*** ISequentialStream methods ***/
716 StreamOnStreamRange_Read
,
717 StreamOnStreamRange_Write
,
718 /*** IStream methods ***/
719 StreamOnStreamRange_Seek
,
720 StreamOnStreamRange_SetSize
,
721 StreamOnStreamRange_CopyTo
,
722 StreamOnStreamRange_Commit
,
723 StreamOnStreamRange_Revert
,
724 StreamOnStreamRange_LockRegion
,
725 StreamOnStreamRange_UnlockRegion
,
726 StreamOnStreamRange_Stat
,
727 StreamOnStreamRange_Clone
,
731 /******************************************
732 * IWICStream implementation
735 typedef struct IWICStreamImpl
737 IWICStream IWICStream_iface
;
743 static inline IWICStreamImpl
*impl_from_IWICStream(IWICStream
*iface
)
745 return CONTAINING_RECORD(iface
, IWICStreamImpl
, IWICStream_iface
);
748 static HRESULT WINAPI
IWICStreamImpl_QueryInterface(IWICStream
*iface
,
749 REFIID iid
, void **ppv
)
751 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
752 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
754 if (!ppv
) return E_INVALIDARG
;
756 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IStream
, iid
) ||
757 IsEqualIID(&IID_ISequentialStream
, iid
) || IsEqualIID(&IID_IWICStream
, iid
))
759 *ppv
= &This
->IWICStream_iface
;
760 IUnknown_AddRef((IUnknown
*)*ppv
);
766 return E_NOINTERFACE
;
770 static ULONG WINAPI
IWICStreamImpl_AddRef(IWICStream
*iface
)
772 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
773 ULONG ref
= InterlockedIncrement(&This
->ref
);
775 TRACE("(%p) refcount=%u\n", iface
, ref
);
780 static ULONG WINAPI
IWICStreamImpl_Release(IWICStream
*iface
)
782 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
783 ULONG ref
= InterlockedDecrement(&This
->ref
);
785 TRACE("(%p) refcount=%u\n", iface
, ref
);
788 if (This
->pStream
) IStream_Release(This
->pStream
);
789 HeapFree(GetProcessHeap(), 0, This
);
794 static HRESULT WINAPI
IWICStreamImpl_Read(IWICStream
*iface
,
795 void *pv
, ULONG cb
, ULONG
*pcbRead
)
797 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
798 TRACE("(%p): relay\n", This
);
800 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
801 return IStream_Read(This
->pStream
, pv
, cb
, pcbRead
);
804 static HRESULT WINAPI
IWICStreamImpl_Write(IWICStream
*iface
,
805 void const *pv
, ULONG cb
, ULONG
*pcbWritten
)
807 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
808 TRACE("(%p): relay\n", This
);
810 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
811 return IStream_Write(This
->pStream
, pv
, cb
, pcbWritten
);
814 static HRESULT WINAPI
IWICStreamImpl_Seek(IWICStream
*iface
,
815 LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
817 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
818 TRACE("(%p): relay\n", This
);
820 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
821 return IStream_Seek(This
->pStream
, dlibMove
, dwOrigin
, plibNewPosition
);
824 static HRESULT WINAPI
IWICStreamImpl_SetSize(IWICStream
*iface
,
825 ULARGE_INTEGER libNewSize
)
827 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
828 TRACE("(%p): relay\n", This
);
830 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
831 return IStream_SetSize(This
->pStream
, libNewSize
);
834 static HRESULT WINAPI
IWICStreamImpl_CopyTo(IWICStream
*iface
,
835 IStream
*pstm
, ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
837 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
838 TRACE("(%p): relay\n", This
);
840 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
841 return IStream_CopyTo(This
->pStream
, pstm
, cb
, pcbRead
, pcbWritten
);
844 static HRESULT WINAPI
IWICStreamImpl_Commit(IWICStream
*iface
,
845 DWORD grfCommitFlags
)
847 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
848 TRACE("(%p): relay\n", This
);
850 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
851 return IStream_Commit(This
->pStream
, grfCommitFlags
);
854 static HRESULT WINAPI
IWICStreamImpl_Revert(IWICStream
*iface
)
856 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
857 TRACE("(%p): relay\n", This
);
859 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
860 return IStream_Revert(This
->pStream
);
863 static HRESULT WINAPI
IWICStreamImpl_LockRegion(IWICStream
*iface
,
864 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
866 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
867 TRACE("(%p): relay\n", This
);
869 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
870 return IStream_LockRegion(This
->pStream
, libOffset
, cb
, dwLockType
);
873 static HRESULT WINAPI
IWICStreamImpl_UnlockRegion(IWICStream
*iface
,
874 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
876 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
877 TRACE("(%p): relay\n", This
);
879 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
880 return IStream_UnlockRegion(This
->pStream
, libOffset
, cb
, dwLockType
);
883 static HRESULT WINAPI
IWICStreamImpl_Stat(IWICStream
*iface
,
884 STATSTG
*pstatstg
, DWORD grfStatFlag
)
886 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
887 TRACE("(%p): relay\n", This
);
889 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
890 return IStream_Stat(This
->pStream
, pstatstg
, grfStatFlag
);
893 static HRESULT WINAPI
IWICStreamImpl_Clone(IWICStream
*iface
,
896 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
897 TRACE("(%p): relay\n", This
);
899 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
900 return IStream_Clone(This
->pStream
, ppstm
);
903 static HRESULT WINAPI
IWICStreamImpl_InitializeFromIStream(IWICStream
*iface
,
906 ULARGE_INTEGER offset
, size
;
907 TRACE("(%p): relay\n", iface
);
910 size
.u
.LowPart
= 0xffffffff;
911 size
.u
.HighPart
= 0xffffffff;
912 return IWICStream_InitializeFromIStreamRegion(iface
, pIStream
, offset
, size
);
915 static HRESULT WINAPI
IWICStreamImpl_InitializeFromFilename(IWICStream
*iface
,
916 LPCWSTR wzFileName
, DWORD dwDesiredAccess
)
918 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
923 TRACE("(%p, %s, %u)\n", iface
, debugstr_w(wzFileName
), dwDesiredAccess
);
925 if (This
->pStream
) return WINCODEC_ERR_WRONGSTATE
;
927 if(dwDesiredAccess
& GENERIC_WRITE
)
928 dwMode
= STGM_SHARE_DENY_WRITE
| STGM_WRITE
| STGM_CREATE
;
929 else if(dwDesiredAccess
& GENERIC_READ
)
930 dwMode
= STGM_SHARE_DENY_WRITE
| STGM_READ
| STGM_FAILIFTHERE
;
934 hr
= SHCreateStreamOnFileW(wzFileName
, dwMode
, &stream
);
938 if (InterlockedCompareExchangePointer((void**)&This
->pStream
, stream
, NULL
))
940 /* Some other thread set the stream first. */
941 IStream_Release(stream
);
942 hr
= WINCODEC_ERR_WRONGSTATE
;
949 /******************************************
950 * IWICStream_InitializeFromMemory
952 * Initializes the internal IStream object to retrieve its data from a memory chunk.
955 * pbBuffer [I] pointer to the memory chunk
956 * cbBufferSize [I] number of bytes to use from the memory chunk
960 * FAILURE: E_INVALIDARG, if pbBuffer is NULL
961 * E_OUTOFMEMORY, if we run out of memory
962 * WINCODEC_ERR_WRONGSTATE, if the IStream object has already been initialized before
965 static HRESULT WINAPI
IWICStreamImpl_InitializeFromMemory(IWICStream
*iface
,
966 BYTE
*pbBuffer
, DWORD cbBufferSize
)
968 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
969 StreamOnMemory
*pObject
;
970 TRACE("(%p,%p)\n", iface
, pbBuffer
);
972 if (!pbBuffer
) return E_INVALIDARG
;
973 if (This
->pStream
) return WINCODEC_ERR_WRONGSTATE
;
975 pObject
= HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnMemory
));
976 if (!pObject
) return E_OUTOFMEMORY
;
978 pObject
->IStream_iface
.lpVtbl
= &StreamOnMemory_Vtbl
;
980 pObject
->pbMemory
= pbBuffer
;
981 pObject
->dwMemsize
= cbBufferSize
;
982 pObject
->dwCurPos
= 0;
983 InitializeCriticalSection(&pObject
->lock
);
984 pObject
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": StreamOnMemory.lock");
986 if (InterlockedCompareExchangePointer((void**)&This
->pStream
, pObject
, NULL
))
988 /* Some other thread set the stream first. */
989 IStream_Release(&pObject
->IStream_iface
);
990 return WINCODEC_ERR_WRONGSTATE
;
996 static HRESULT
map_file(HANDLE file
, HANDLE
*map
, void **mem
, LARGE_INTEGER
*size
)
999 if (!GetFileSizeEx(file
, size
)) return HRESULT_FROM_WIN32(GetLastError());
1000 if (size
->u
.HighPart
)
1002 WARN("file too large\n");
1005 if (!(*map
= CreateFileMappingW(file
, NULL
, PAGE_READONLY
, 0, size
->u
.LowPart
, NULL
)))
1007 return HRESULT_FROM_WIN32(GetLastError());
1009 if (!(*mem
= MapViewOfFile(*map
, FILE_MAP_READ
, 0, 0, size
->u
.LowPart
)))
1012 return HRESULT_FROM_WIN32(GetLastError());
1017 HRESULT
stream_initialize_from_filehandle(IWICStream
*iface
, HANDLE file
)
1019 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
1020 StreamOnFileHandle
*pObject
;
1021 IWICStream
*stream
= NULL
;
1026 TRACE("(%p,%p)\n", iface
, file
);
1028 if (This
->pStream
) return WINCODEC_ERR_WRONGSTATE
;
1030 hr
= map_file(file
, &map
, &mem
, &size
);
1031 if (FAILED(hr
)) return hr
;
1033 hr
= StreamImpl_Create(&stream
);
1034 if (FAILED(hr
)) goto error
;
1036 hr
= IWICStreamImpl_InitializeFromMemory(stream
, mem
, size
.u
.LowPart
);
1037 if (FAILED(hr
)) goto error
;
1039 pObject
= HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnFileHandle
));
1045 pObject
->IStream_iface
.lpVtbl
= &StreamOnFileHandle_Vtbl
;
1049 pObject
->stream
= stream
;
1051 if (InterlockedCompareExchangePointer((void**)&This
->pStream
, pObject
, NULL
))
1053 /* Some other thread set the stream first. */
1054 IStream_Release(&pObject
->IStream_iface
);
1055 return WINCODEC_ERR_WRONGSTATE
;
1060 if (stream
) IWICStream_Release(stream
);
1061 UnmapViewOfFile(mem
);
1066 static HRESULT WINAPI
IWICStreamImpl_InitializeFromIStreamRegion(IWICStream
*iface
,
1067 IStream
*pIStream
, ULARGE_INTEGER ulOffset
, ULARGE_INTEGER ulMaxSize
)
1069 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
1070 StreamOnStreamRange
*pObject
;
1071 TRACE("(%p,%p)\n", iface
, pIStream
);
1073 if (!pIStream
) return E_INVALIDARG
;
1074 if (This
->pStream
) return WINCODEC_ERR_WRONGSTATE
;
1076 pObject
= HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnStreamRange
));
1077 if (!pObject
) return E_OUTOFMEMORY
;
1079 pObject
->IStream_iface
.lpVtbl
= &StreamOnStreamRange_Vtbl
;
1081 IStream_AddRef(pIStream
);
1082 pObject
->stream
= pIStream
;
1083 pObject
->pos
.QuadPart
= 0;
1084 pObject
->offset
= ulOffset
;
1085 pObject
->max_size
= ulMaxSize
;
1086 InitializeCriticalSection(&pObject
->lock
);
1087 pObject
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": StreamOnStreamRange.lock");
1089 if (InterlockedCompareExchangePointer((void**)&This
->pStream
, pObject
, NULL
))
1091 /* Some other thread set the stream first. */
1092 IStream_Release(&pObject
->IStream_iface
);
1093 return WINCODEC_ERR_WRONGSTATE
;
1100 static const IWICStreamVtbl WICStream_Vtbl
=
1102 /*** IUnknown methods ***/
1103 IWICStreamImpl_QueryInterface
,
1104 IWICStreamImpl_AddRef
,
1105 IWICStreamImpl_Release
,
1106 /*** ISequentialStream methods ***/
1107 IWICStreamImpl_Read
,
1108 IWICStreamImpl_Write
,
1109 /*** IStream methods ***/
1110 IWICStreamImpl_Seek
,
1111 IWICStreamImpl_SetSize
,
1112 IWICStreamImpl_CopyTo
,
1113 IWICStreamImpl_Commit
,
1114 IWICStreamImpl_Revert
,
1115 IWICStreamImpl_LockRegion
,
1116 IWICStreamImpl_UnlockRegion
,
1117 IWICStreamImpl_Stat
,
1118 IWICStreamImpl_Clone
,
1119 /*** IWICStream methods ***/
1120 IWICStreamImpl_InitializeFromIStream
,
1121 IWICStreamImpl_InitializeFromFilename
,
1122 IWICStreamImpl_InitializeFromMemory
,
1123 IWICStreamImpl_InitializeFromIStreamRegion
,
1126 HRESULT
StreamImpl_Create(IWICStream
**stream
)
1128 IWICStreamImpl
*pObject
;
1130 if( !stream
) return E_INVALIDARG
;
1132 pObject
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWICStreamImpl
));
1135 return E_OUTOFMEMORY
;
1138 pObject
->IWICStream_iface
.lpVtbl
= &WICStream_Vtbl
;
1140 pObject
->pStream
= NULL
;
1142 *stream
= &pObject
->IWICStream_iface
;