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
);
105 TRACE("(%p, %p, %u, %p)\n", This
, pv
, cb
, pcbRead
);
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
);
126 TRACE("(%p, %p, %u, %p)\n", This
, pv
, cb
, pcbWritten
);
128 if (!pv
) return E_INVALIDARG
;
130 EnterCriticalSection(&This
->lock
);
131 if (cb
> This
->dwMemsize
- This
->dwCurPos
) {
132 hr
= STG_E_MEDIUMFULL
;
135 memmove(This
->pbMemory
+ This
->dwCurPos
, pv
, cb
);
136 This
->dwCurPos
+= cb
;
138 if (pcbWritten
) *pcbWritten
= cb
;
140 LeaveCriticalSection(&This
->lock
);
145 static HRESULT WINAPI
StreamOnMemory_Seek(IStream
*iface
,
146 LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
148 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
149 LARGE_INTEGER NewPosition
;
152 TRACE("(%p, %s, %d, %p)\n", This
, wine_dbgstr_longlong(dlibMove
.QuadPart
), dwOrigin
, plibNewPosition
);
154 EnterCriticalSection(&This
->lock
);
155 if (dwOrigin
== STREAM_SEEK_SET
) NewPosition
.QuadPart
= dlibMove
.QuadPart
;
156 else if (dwOrigin
== STREAM_SEEK_CUR
) NewPosition
.QuadPart
= This
->dwCurPos
+ dlibMove
.QuadPart
;
157 else if (dwOrigin
== STREAM_SEEK_END
) NewPosition
.QuadPart
= This
->dwMemsize
+ dlibMove
.QuadPart
;
158 else hr
= E_INVALIDARG
;
161 if (NewPosition
.u
.HighPart
) hr
= HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW
);
162 else if (NewPosition
.QuadPart
> This
->dwMemsize
) hr
= E_INVALIDARG
;
163 else if (NewPosition
.QuadPart
< 0) hr
= E_INVALIDARG
;
167 This
->dwCurPos
= NewPosition
.u
.LowPart
;
169 if(plibNewPosition
) plibNewPosition
->QuadPart
= This
->dwCurPos
;
171 LeaveCriticalSection(&This
->lock
);
176 /* SetSize isn't implemented in the native windowscodecs DLL either */
177 static HRESULT WINAPI
StreamOnMemory_SetSize(IStream
*iface
,
178 ULARGE_INTEGER libNewSize
)
180 TRACE("(%p, %s)\n", iface
, wine_dbgstr_longlong(libNewSize
.QuadPart
));
184 /* CopyTo isn't implemented in the native windowscodecs DLL either */
185 static HRESULT WINAPI
StreamOnMemory_CopyTo(IStream
*iface
,
186 IStream
*pstm
, ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
188 TRACE("(%p, %p, %s, %p, %p)\n", iface
, pstm
, wine_dbgstr_longlong(cb
.QuadPart
), pcbRead
, pcbWritten
);
192 static HRESULT WINAPI
StreamOnMemory_Commit(IStream
*iface
,
193 DWORD grfCommitFlags
)
195 TRACE("(%p, %#x)\n", iface
, grfCommitFlags
);
199 /* Revert isn't implemented in the native windowscodecs DLL either */
200 static HRESULT WINAPI
StreamOnMemory_Revert(IStream
*iface
)
202 TRACE("(%p)\n", iface
);
206 /* LockRegion isn't implemented in the native windowscodecs DLL either */
207 static HRESULT WINAPI
StreamOnMemory_LockRegion(IStream
*iface
,
208 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
210 TRACE("(%p, %s, %s, %d)\n", iface
, wine_dbgstr_longlong(libOffset
.QuadPart
),
211 wine_dbgstr_longlong(cb
.QuadPart
), dwLockType
);
215 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */
216 static HRESULT WINAPI
StreamOnMemory_UnlockRegion(IStream
*iface
,
217 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
219 TRACE("(%p, %s, %s, %d)\n", iface
, wine_dbgstr_longlong(libOffset
.QuadPart
),
220 wine_dbgstr_longlong(cb
.QuadPart
), dwLockType
);
224 static HRESULT WINAPI
StreamOnMemory_Stat(IStream
*iface
,
225 STATSTG
*pstatstg
, DWORD grfStatFlag
)
227 StreamOnMemory
*This
= StreamOnMemory_from_IStream(iface
);
228 TRACE("(%p, %p, %#x)\n", This
, pstatstg
, grfStatFlag
);
230 if (!pstatstg
) return E_INVALIDARG
;
232 ZeroMemory(pstatstg
, sizeof(STATSTG
));
233 pstatstg
->type
= STGTY_STREAM
;
234 pstatstg
->cbSize
.QuadPart
= This
->dwMemsize
;
239 /* Clone isn't implemented in the native windowscodecs DLL either */
240 static HRESULT WINAPI
StreamOnMemory_Clone(IStream
*iface
,
243 TRACE("(%p, %p)\n", iface
, ppstm
);
248 static const IStreamVtbl StreamOnMemory_Vtbl
=
250 /*** IUnknown methods ***/
251 StreamOnMemory_QueryInterface
,
252 StreamOnMemory_AddRef
,
253 StreamOnMemory_Release
,
254 /*** ISequentialStream methods ***/
256 StreamOnMemory_Write
,
257 /*** IStream methods ***/
259 StreamOnMemory_SetSize
,
260 StreamOnMemory_CopyTo
,
261 StreamOnMemory_Commit
,
262 StreamOnMemory_Revert
,
263 StreamOnMemory_LockRegion
,
264 StreamOnMemory_UnlockRegion
,
266 StreamOnMemory_Clone
,
269 /******************************************
270 * StreamOnFileHandle implementation (internal)
273 typedef struct StreamOnFileHandle
{
274 IStream IStream_iface
;
280 } StreamOnFileHandle
;
282 static inline StreamOnFileHandle
*StreamOnFileHandle_from_IStream(IStream
*iface
)
284 return CONTAINING_RECORD(iface
, StreamOnFileHandle
, IStream_iface
);
287 static HRESULT WINAPI
StreamOnFileHandle_QueryInterface(IStream
*iface
,
288 REFIID iid
, void **ppv
)
290 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
292 if (!ppv
) return E_INVALIDARG
;
294 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IStream
, iid
) ||
295 IsEqualIID(&IID_ISequentialStream
, iid
))
298 IUnknown_AddRef((IUnknown
*)*ppv
);
304 return E_NOINTERFACE
;
308 static ULONG WINAPI
StreamOnFileHandle_AddRef(IStream
*iface
)
310 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
311 ULONG ref
= InterlockedIncrement(&This
->ref
);
313 TRACE("(%p) refcount=%u\n", iface
, ref
);
318 static ULONG WINAPI
StreamOnFileHandle_Release(IStream
*iface
)
320 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
321 ULONG ref
= InterlockedDecrement(&This
->ref
);
323 TRACE("(%p) refcount=%u\n", iface
, ref
);
326 IWICStream_Release(This
->stream
);
327 UnmapViewOfFile(This
->mem
);
328 CloseHandle(This
->map
);
329 HeapFree(GetProcessHeap(), 0, This
);
334 static HRESULT WINAPI
StreamOnFileHandle_Read(IStream
*iface
,
335 void *pv
, ULONG cb
, ULONG
*pcbRead
)
337 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
338 TRACE("(%p, %p, %u, %p)\n", This
, pv
, cb
, pcbRead
);
340 return IWICStream_Read(This
->stream
, pv
, cb
, pcbRead
);
343 static HRESULT WINAPI
StreamOnFileHandle_Write(IStream
*iface
,
344 void const *pv
, ULONG cb
, ULONG
*pcbWritten
)
346 ERR("(%p, %p, %u, %p)\n", iface
, pv
, cb
, pcbWritten
);
347 return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED
);
350 static HRESULT WINAPI
StreamOnFileHandle_Seek(IStream
*iface
,
351 LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
353 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
354 TRACE("(%p, %s, %d, %p)\n", This
, wine_dbgstr_longlong(dlibMove
.QuadPart
), dwOrigin
, plibNewPosition
);
356 return IWICStream_Seek(This
->stream
, dlibMove
, dwOrigin
, plibNewPosition
);
359 static HRESULT WINAPI
StreamOnFileHandle_SetSize(IStream
*iface
,
360 ULARGE_INTEGER libNewSize
)
362 TRACE("(%p, %s)\n", iface
, wine_dbgstr_longlong(libNewSize
.QuadPart
));
366 static HRESULT WINAPI
StreamOnFileHandle_CopyTo(IStream
*iface
,
367 IStream
*pstm
, ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
369 TRACE("(%p, %p, %s, %p, %p)\n", iface
, pstm
, wine_dbgstr_longlong(cb
.QuadPart
), pcbRead
, pcbWritten
);
373 static HRESULT WINAPI
StreamOnFileHandle_Commit(IStream
*iface
,
374 DWORD grfCommitFlags
)
376 TRACE("(%p, %#x)\n", iface
, grfCommitFlags
);
380 static HRESULT WINAPI
StreamOnFileHandle_Revert(IStream
*iface
)
382 TRACE("(%p)\n", iface
);
386 static HRESULT WINAPI
StreamOnFileHandle_LockRegion(IStream
*iface
,
387 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
389 TRACE("(%p, %s, %s, %d)\n", iface
, wine_dbgstr_longlong(libOffset
.QuadPart
),
390 wine_dbgstr_longlong(cb
.QuadPart
), dwLockType
);
394 static HRESULT WINAPI
StreamOnFileHandle_UnlockRegion(IStream
*iface
,
395 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
397 TRACE("(%p, %s, %s, %d)\n", iface
, wine_dbgstr_longlong(libOffset
.QuadPart
),
398 wine_dbgstr_longlong(cb
.QuadPart
), dwLockType
);
402 static HRESULT WINAPI
StreamOnFileHandle_Stat(IStream
*iface
,
403 STATSTG
*pstatstg
, DWORD grfStatFlag
)
405 StreamOnFileHandle
*This
= StreamOnFileHandle_from_IStream(iface
);
406 TRACE("(%p, %p, %#x)\n", This
, pstatstg
, grfStatFlag
);
408 return IWICStream_Stat(This
->stream
, pstatstg
, grfStatFlag
);
411 static HRESULT WINAPI
StreamOnFileHandle_Clone(IStream
*iface
,
414 TRACE("(%p, %p)\n", iface
, ppstm
);
418 static const IStreamVtbl StreamOnFileHandle_Vtbl
=
420 /*** IUnknown methods ***/
421 StreamOnFileHandle_QueryInterface
,
422 StreamOnFileHandle_AddRef
,
423 StreamOnFileHandle_Release
,
424 /*** ISequentialStream methods ***/
425 StreamOnFileHandle_Read
,
426 StreamOnFileHandle_Write
,
427 /*** IStream methods ***/
428 StreamOnFileHandle_Seek
,
429 StreamOnFileHandle_SetSize
,
430 StreamOnFileHandle_CopyTo
,
431 StreamOnFileHandle_Commit
,
432 StreamOnFileHandle_Revert
,
433 StreamOnFileHandle_LockRegion
,
434 StreamOnFileHandle_UnlockRegion
,
435 StreamOnFileHandle_Stat
,
436 StreamOnFileHandle_Clone
,
439 /******************************************
440 * StreamOnStreamRange implementation
442 * Used by IWICStream_InitializeFromIStreamRegion
445 typedef struct StreamOnStreamRange
{
446 IStream IStream_iface
;
451 ULARGE_INTEGER offset
;
452 ULARGE_INTEGER max_size
;
454 CRITICAL_SECTION lock
;
455 } StreamOnStreamRange
;
457 static inline StreamOnStreamRange
*StreamOnStreamRange_from_IStream(IStream
*iface
)
459 return CONTAINING_RECORD(iface
, StreamOnStreamRange
, IStream_iface
);
462 static HRESULT WINAPI
StreamOnStreamRange_QueryInterface(IStream
*iface
,
463 REFIID iid
, void **ppv
)
465 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
467 if (!ppv
) return E_INVALIDARG
;
469 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IStream
, iid
) ||
470 IsEqualIID(&IID_ISequentialStream
, iid
))
473 IUnknown_AddRef((IUnknown
*)*ppv
);
479 return E_NOINTERFACE
;
483 static ULONG WINAPI
StreamOnStreamRange_AddRef(IStream
*iface
)
485 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
486 ULONG ref
= InterlockedIncrement(&This
->ref
);
488 TRACE("(%p) refcount=%u\n", iface
, ref
);
493 static ULONG WINAPI
StreamOnStreamRange_Release(IStream
*iface
)
495 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
496 ULONG ref
= InterlockedDecrement(&This
->ref
);
498 TRACE("(%p) refcount=%u\n", iface
, ref
);
501 This
->lock
.DebugInfo
->Spare
[0] = 0;
502 DeleteCriticalSection(&This
->lock
);
503 IStream_Release(This
->stream
);
504 HeapFree(GetProcessHeap(), 0, This
);
509 static HRESULT WINAPI
StreamOnStreamRange_Read(IStream
*iface
,
510 void *pv
, ULONG cb
, ULONG
*pcbRead
)
512 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
515 ULARGE_INTEGER OldPosition
;
516 LARGE_INTEGER SetPosition
;
518 TRACE("(%p, %p, %u, %p)\n", This
, pv
, cb
, pcbRead
);
520 if (!pv
) return E_INVALIDARG
;
522 EnterCriticalSection(&This
->lock
);
523 SetPosition
.QuadPart
= 0;
524 hr
= IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_CUR
, &OldPosition
);
527 SetPosition
.QuadPart
= This
->pos
.QuadPart
+ This
->offset
.QuadPart
;
528 hr
= IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_SET
, NULL
);
532 if (This
->pos
.QuadPart
+ cb
> This
->max_size
.QuadPart
)
534 /* This would read past the end of the stream. */
535 if (This
->pos
.QuadPart
> This
->max_size
.QuadPart
)
538 cb
= This
->max_size
.QuadPart
- This
->pos
.QuadPart
;
540 hr
= IStream_Read(This
->stream
, pv
, cb
, &uBytesRead
);
541 SetPosition
.QuadPart
= OldPosition
.QuadPart
;
542 IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_SET
, NULL
);
545 This
->pos
.QuadPart
+= uBytesRead
;
546 LeaveCriticalSection(&This
->lock
);
548 if (SUCCEEDED(hr
) && pcbRead
) *pcbRead
= uBytesRead
;
553 static HRESULT WINAPI
StreamOnStreamRange_Write(IStream
*iface
,
554 void const *pv
, ULONG cb
, ULONG
*pcbWritten
)
556 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
558 ULARGE_INTEGER OldPosition
;
559 LARGE_INTEGER SetPosition
;
560 ULONG uBytesWritten
=0;
561 TRACE("(%p, %p, %u, %p)\n", This
, pv
, cb
, pcbWritten
);
563 if (!pv
) return E_INVALIDARG
;
565 EnterCriticalSection(&This
->lock
);
566 SetPosition
.QuadPart
= 0;
567 hr
= IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_CUR
, &OldPosition
);
570 SetPosition
.QuadPart
= This
->pos
.QuadPart
+ This
->offset
.QuadPart
;
571 hr
= IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_SET
, NULL
);
575 if (This
->pos
.QuadPart
+ cb
> This
->max_size
.QuadPart
)
577 /* This would read past the end of the stream. */
578 if (This
->pos
.QuadPart
> This
->max_size
.QuadPart
)
581 cb
= This
->max_size
.QuadPart
- This
->pos
.QuadPart
;
583 hr
= IStream_Write(This
->stream
, pv
, cb
, &uBytesWritten
);
584 SetPosition
.QuadPart
= OldPosition
.QuadPart
;
585 IStream_Seek(This
->stream
, SetPosition
, STREAM_SEEK_SET
, NULL
);
588 This
->pos
.QuadPart
+= uBytesWritten
;
589 LeaveCriticalSection(&This
->lock
);
591 if (SUCCEEDED(hr
) && pcbWritten
) *pcbWritten
= uBytesWritten
;
596 static HRESULT WINAPI
StreamOnStreamRange_Seek(IStream
*iface
,
597 LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
599 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
600 ULARGE_INTEGER NewPosition
, actual_size
;
603 TRACE("(%p, %s, %d, %p)\n", This
, wine_dbgstr_longlong(dlibMove
.QuadPart
), dwOrigin
, plibNewPosition
);
605 EnterCriticalSection(&This
->lock
);
606 actual_size
= This
->max_size
;
607 if (dwOrigin
== STREAM_SEEK_SET
)
608 NewPosition
.QuadPart
= dlibMove
.QuadPart
;
609 else if (dwOrigin
== STREAM_SEEK_CUR
)
610 NewPosition
.QuadPart
= This
->pos
.QuadPart
+ dlibMove
.QuadPart
;
611 else if (dwOrigin
== STREAM_SEEK_END
)
613 hr
= IStream_Stat(This
->stream
, &statstg
, STATFLAG_NONAME
);
616 if (This
->max_size
.QuadPart
+ This
->offset
.QuadPart
> statstg
.cbSize
.QuadPart
)
617 actual_size
.QuadPart
= statstg
.cbSize
.QuadPart
- This
->offset
.QuadPart
;
618 NewPosition
.QuadPart
= dlibMove
.QuadPart
+ actual_size
.QuadPart
;
621 else hr
= E_INVALIDARG
;
623 if (SUCCEEDED(hr
) && (NewPosition
.u
.HighPart
!= 0 || NewPosition
.QuadPart
> actual_size
.QuadPart
))
624 hr
= WINCODEC_ERR_VALUEOUTOFRANGE
;
627 This
->pos
.QuadPart
= NewPosition
.QuadPart
;
629 if(plibNewPosition
) plibNewPosition
->QuadPart
= This
->pos
.QuadPart
;
631 LeaveCriticalSection(&This
->lock
);
636 /* SetSize isn't implemented in the native windowscodecs DLL either */
637 static HRESULT WINAPI
StreamOnStreamRange_SetSize(IStream
*iface
,
638 ULARGE_INTEGER libNewSize
)
640 TRACE("(%p, %s)\n", iface
, wine_dbgstr_longlong(libNewSize
.QuadPart
));
644 /* CopyTo isn't implemented in the native windowscodecs DLL either */
645 static HRESULT WINAPI
StreamOnStreamRange_CopyTo(IStream
*iface
,
646 IStream
*pstm
, ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
648 TRACE("(%p, %p, %s, %p, %p)\n", iface
, pstm
, wine_dbgstr_longlong(cb
.QuadPart
),
649 pcbRead
, pcbWritten
);
653 /* Commit isn't implemented in the native windowscodecs DLL either */
654 static HRESULT WINAPI
StreamOnStreamRange_Commit(IStream
*iface
,
655 DWORD grfCommitFlags
)
657 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
658 TRACE("(%p, %#x)\n", This
, grfCommitFlags
);
659 return IStream_Commit(This
->stream
, grfCommitFlags
);
662 /* Revert isn't implemented in the native windowscodecs DLL either */
663 static HRESULT WINAPI
StreamOnStreamRange_Revert(IStream
*iface
)
665 TRACE("(%p)\n", iface
);
669 /* LockRegion isn't implemented in the native windowscodecs DLL either */
670 static HRESULT WINAPI
StreamOnStreamRange_LockRegion(IStream
*iface
,
671 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
673 TRACE("(%p, %s, %s, %d)\n", iface
, wine_dbgstr_longlong(libOffset
.QuadPart
),
674 wine_dbgstr_longlong(cb
.QuadPart
), dwLockType
);
678 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */
679 static HRESULT WINAPI
StreamOnStreamRange_UnlockRegion(IStream
*iface
,
680 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
682 TRACE("(%p, %s, %s, %d)\n", iface
, wine_dbgstr_longlong(libOffset
.QuadPart
),
683 wine_dbgstr_longlong(cb
.QuadPart
), dwLockType
);
687 static HRESULT WINAPI
StreamOnStreamRange_Stat(IStream
*iface
,
688 STATSTG
*pstatstg
, DWORD grfStatFlag
)
690 StreamOnStreamRange
*This
= StreamOnStreamRange_from_IStream(iface
);
692 TRACE("(%p, %p, %#x)\n", This
, pstatstg
, grfStatFlag
);
694 if (!pstatstg
) return E_INVALIDARG
;
696 EnterCriticalSection(&This
->lock
);
697 hr
= IStream_Stat(This
->stream
, pstatstg
, grfStatFlag
);
700 pstatstg
->cbSize
.QuadPart
-= This
->offset
.QuadPart
;
701 if (This
->max_size
.QuadPart
< pstatstg
->cbSize
.QuadPart
)
702 pstatstg
->cbSize
.QuadPart
= This
->max_size
.QuadPart
;
705 LeaveCriticalSection(&This
->lock
);
710 /* Clone isn't implemented in the native windowscodecs DLL either */
711 static HRESULT WINAPI
StreamOnStreamRange_Clone(IStream
*iface
,
714 TRACE("(%p, %p)\n", iface
, ppstm
);
718 static const IStreamVtbl StreamOnStreamRange_Vtbl
=
720 /*** IUnknown methods ***/
721 StreamOnStreamRange_QueryInterface
,
722 StreamOnStreamRange_AddRef
,
723 StreamOnStreamRange_Release
,
724 /*** ISequentialStream methods ***/
725 StreamOnStreamRange_Read
,
726 StreamOnStreamRange_Write
,
727 /*** IStream methods ***/
728 StreamOnStreamRange_Seek
,
729 StreamOnStreamRange_SetSize
,
730 StreamOnStreamRange_CopyTo
,
731 StreamOnStreamRange_Commit
,
732 StreamOnStreamRange_Revert
,
733 StreamOnStreamRange_LockRegion
,
734 StreamOnStreamRange_UnlockRegion
,
735 StreamOnStreamRange_Stat
,
736 StreamOnStreamRange_Clone
,
740 /******************************************
741 * IWICStream implementation
744 typedef struct IWICStreamImpl
746 IWICStream IWICStream_iface
;
752 static inline IWICStreamImpl
*impl_from_IWICStream(IWICStream
*iface
)
754 return CONTAINING_RECORD(iface
, IWICStreamImpl
, IWICStream_iface
);
757 static HRESULT WINAPI
IWICStreamImpl_QueryInterface(IWICStream
*iface
,
758 REFIID iid
, void **ppv
)
760 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
761 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
763 if (!ppv
) return E_INVALIDARG
;
765 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IStream
, iid
) ||
766 IsEqualIID(&IID_ISequentialStream
, iid
) || IsEqualIID(&IID_IWICStream
, iid
))
768 *ppv
= &This
->IWICStream_iface
;
769 IUnknown_AddRef((IUnknown
*)*ppv
);
775 return E_NOINTERFACE
;
779 static ULONG WINAPI
IWICStreamImpl_AddRef(IWICStream
*iface
)
781 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
782 ULONG ref
= InterlockedIncrement(&This
->ref
);
784 TRACE("(%p) refcount=%u\n", iface
, ref
);
789 static ULONG WINAPI
IWICStreamImpl_Release(IWICStream
*iface
)
791 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
792 ULONG ref
= InterlockedDecrement(&This
->ref
);
794 TRACE("(%p) refcount=%u\n", iface
, ref
);
797 if (This
->pStream
) IStream_Release(This
->pStream
);
798 HeapFree(GetProcessHeap(), 0, This
);
803 static HRESULT WINAPI
IWICStreamImpl_Read(IWICStream
*iface
,
804 void *pv
, ULONG cb
, ULONG
*pcbRead
)
806 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
807 TRACE("(%p, %p, %u, %p)\n", This
, pv
, cb
, pcbRead
);
809 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
810 return IStream_Read(This
->pStream
, pv
, cb
, pcbRead
);
813 static HRESULT WINAPI
IWICStreamImpl_Write(IWICStream
*iface
,
814 void const *pv
, ULONG cb
, ULONG
*pcbWritten
)
816 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
817 TRACE("(%p, %p, %u, %p)\n", This
, pv
, cb
, pcbWritten
);
819 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
820 return IStream_Write(This
->pStream
, pv
, cb
, pcbWritten
);
823 static HRESULT WINAPI
IWICStreamImpl_Seek(IWICStream
*iface
,
824 LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
826 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
827 TRACE("(%p, %s, %d, %p)\n", This
, wine_dbgstr_longlong(dlibMove
.QuadPart
),
828 dwOrigin
, plibNewPosition
);
830 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
831 return IStream_Seek(This
->pStream
, dlibMove
, dwOrigin
, plibNewPosition
);
834 static HRESULT WINAPI
IWICStreamImpl_SetSize(IWICStream
*iface
,
835 ULARGE_INTEGER libNewSize
)
837 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
838 TRACE("(%p, %s)\n", This
, wine_dbgstr_longlong(libNewSize
.QuadPart
));
840 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
841 return IStream_SetSize(This
->pStream
, libNewSize
);
844 static HRESULT WINAPI
IWICStreamImpl_CopyTo(IWICStream
*iface
,
845 IStream
*pstm
, ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
847 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
848 TRACE("(%p, %p, %s, %p, %p)\n", This
, pstm
, wine_dbgstr_longlong(cb
.QuadPart
), pcbRead
, pcbWritten
);
850 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
851 return IStream_CopyTo(This
->pStream
, pstm
, cb
, pcbRead
, pcbWritten
);
854 static HRESULT WINAPI
IWICStreamImpl_Commit(IWICStream
*iface
,
855 DWORD grfCommitFlags
)
857 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
858 TRACE("(%p, %#x)\n", This
, grfCommitFlags
);
860 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
861 return IStream_Commit(This
->pStream
, grfCommitFlags
);
864 static HRESULT WINAPI
IWICStreamImpl_Revert(IWICStream
*iface
)
866 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
867 TRACE("(%p)\n", This
);
869 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
870 return IStream_Revert(This
->pStream
);
873 static HRESULT WINAPI
IWICStreamImpl_LockRegion(IWICStream
*iface
,
874 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
876 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
877 TRACE("(%p, %s, %s, %d)\n", This
, wine_dbgstr_longlong(libOffset
.QuadPart
),
878 wine_dbgstr_longlong(cb
.QuadPart
), dwLockType
);
880 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
881 return IStream_LockRegion(This
->pStream
, libOffset
, cb
, dwLockType
);
884 static HRESULT WINAPI
IWICStreamImpl_UnlockRegion(IWICStream
*iface
,
885 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
887 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
888 TRACE("(%p, %s, %s, %d)\n", This
, wine_dbgstr_longlong(libOffset
.QuadPart
),
889 wine_dbgstr_longlong(cb
.QuadPart
), dwLockType
);
891 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
892 return IStream_UnlockRegion(This
->pStream
, libOffset
, cb
, dwLockType
);
895 static HRESULT WINAPI
IWICStreamImpl_Stat(IWICStream
*iface
,
896 STATSTG
*pstatstg
, DWORD grfStatFlag
)
898 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
899 TRACE("(%p, %p, %#x)\n", This
, pstatstg
, grfStatFlag
);
901 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
902 return IStream_Stat(This
->pStream
, pstatstg
, grfStatFlag
);
905 static HRESULT WINAPI
IWICStreamImpl_Clone(IWICStream
*iface
,
908 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
909 TRACE("(%p, %p)\n", This
, ppstm
);
911 if (!This
->pStream
) return WINCODEC_ERR_NOTINITIALIZED
;
912 return IStream_Clone(This
->pStream
, ppstm
);
915 static HRESULT WINAPI
IWICStreamImpl_InitializeFromIStream(IWICStream
*iface
, IStream
*stream
)
917 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
920 TRACE("(%p, %p)\n", iface
, stream
);
922 if (!stream
) return E_INVALIDARG
;
923 if (This
->pStream
) return WINCODEC_ERR_WRONGSTATE
;
925 IStream_AddRef(stream
);
927 if (InterlockedCompareExchangePointer((void **)&This
->pStream
, stream
, NULL
))
929 /* Some other thread set the stream first. */
930 IStream_Release(stream
);
931 hr
= WINCODEC_ERR_WRONGSTATE
;
937 static HRESULT WINAPI
IWICStreamImpl_InitializeFromFilename(IWICStream
*iface
,
938 LPCWSTR wzFileName
, DWORD dwDesiredAccess
)
940 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
945 TRACE("(%p, %s, %u)\n", iface
, debugstr_w(wzFileName
), dwDesiredAccess
);
947 if (This
->pStream
) return WINCODEC_ERR_WRONGSTATE
;
949 if(dwDesiredAccess
& GENERIC_WRITE
)
950 dwMode
= STGM_SHARE_DENY_WRITE
| STGM_WRITE
| STGM_CREATE
;
951 else if(dwDesiredAccess
& GENERIC_READ
)
952 dwMode
= STGM_SHARE_DENY_WRITE
| STGM_READ
| STGM_FAILIFTHERE
;
956 hr
= SHCreateStreamOnFileW(wzFileName
, dwMode
, &stream
);
960 if (InterlockedCompareExchangePointer((void**)&This
->pStream
, stream
, NULL
))
962 /* Some other thread set the stream first. */
963 IStream_Release(stream
);
964 hr
= WINCODEC_ERR_WRONGSTATE
;
971 /******************************************
972 * IWICStream_InitializeFromMemory
974 * Initializes the internal IStream object to retrieve its data from a memory chunk.
977 * pbBuffer [I] pointer to the memory chunk
978 * cbBufferSize [I] number of bytes to use from the memory chunk
982 * FAILURE: E_INVALIDARG, if pbBuffer is NULL
983 * E_OUTOFMEMORY, if we run out of memory
984 * WINCODEC_ERR_WRONGSTATE, if the IStream object has already been initialized before
987 static HRESULT WINAPI
IWICStreamImpl_InitializeFromMemory(IWICStream
*iface
,
988 BYTE
*pbBuffer
, DWORD cbBufferSize
)
990 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
991 StreamOnMemory
*pObject
;
992 TRACE("(%p, %p, %u)\n", iface
, pbBuffer
, cbBufferSize
);
994 if (!pbBuffer
) return E_INVALIDARG
;
995 if (This
->pStream
) return WINCODEC_ERR_WRONGSTATE
;
997 pObject
= HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnMemory
));
998 if (!pObject
) return E_OUTOFMEMORY
;
1000 pObject
->IStream_iface
.lpVtbl
= &StreamOnMemory_Vtbl
;
1002 pObject
->pbMemory
= pbBuffer
;
1003 pObject
->dwMemsize
= cbBufferSize
;
1004 pObject
->dwCurPos
= 0;
1005 InitializeCriticalSection(&pObject
->lock
);
1006 pObject
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": StreamOnMemory.lock");
1008 if (InterlockedCompareExchangePointer((void**)&This
->pStream
, pObject
, NULL
))
1010 /* Some other thread set the stream first. */
1011 IStream_Release(&pObject
->IStream_iface
);
1012 return WINCODEC_ERR_WRONGSTATE
;
1018 static HRESULT
map_file(HANDLE file
, HANDLE
*map
, void **mem
, LARGE_INTEGER
*size
)
1021 if (!GetFileSizeEx(file
, size
)) return HRESULT_FROM_WIN32(GetLastError());
1022 if (size
->u
.HighPart
)
1024 WARN("file too large\n");
1027 if (!(*map
= CreateFileMappingW(file
, NULL
, PAGE_READONLY
, 0, size
->u
.LowPart
, NULL
)))
1029 return HRESULT_FROM_WIN32(GetLastError());
1031 if (!(*mem
= MapViewOfFile(*map
, FILE_MAP_READ
, 0, 0, size
->u
.LowPart
)))
1034 return HRESULT_FROM_WIN32(GetLastError());
1039 HRESULT
stream_initialize_from_filehandle(IWICStream
*iface
, HANDLE file
)
1041 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
1042 StreamOnFileHandle
*pObject
;
1043 IWICStream
*stream
= NULL
;
1048 TRACE("(%p,%p)\n", iface
, file
);
1050 if (This
->pStream
) return WINCODEC_ERR_WRONGSTATE
;
1052 hr
= map_file(file
, &map
, &mem
, &size
);
1053 if (FAILED(hr
)) return hr
;
1055 hr
= StreamImpl_Create(&stream
);
1056 if (FAILED(hr
)) goto error
;
1058 hr
= IWICStreamImpl_InitializeFromMemory(stream
, mem
, size
.u
.LowPart
);
1059 if (FAILED(hr
)) goto error
;
1061 pObject
= HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnFileHandle
));
1067 pObject
->IStream_iface
.lpVtbl
= &StreamOnFileHandle_Vtbl
;
1071 pObject
->stream
= stream
;
1073 if (InterlockedCompareExchangePointer((void**)&This
->pStream
, pObject
, NULL
))
1075 /* Some other thread set the stream first. */
1076 IStream_Release(&pObject
->IStream_iface
);
1077 return WINCODEC_ERR_WRONGSTATE
;
1082 if (stream
) IWICStream_Release(stream
);
1083 UnmapViewOfFile(mem
);
1088 static HRESULT WINAPI
IWICStreamImpl_InitializeFromIStreamRegion(IWICStream
*iface
,
1089 IStream
*pIStream
, ULARGE_INTEGER ulOffset
, ULARGE_INTEGER ulMaxSize
)
1091 IWICStreamImpl
*This
= impl_from_IWICStream(iface
);
1092 StreamOnStreamRange
*pObject
;
1094 TRACE("(%p,%p,%s,%s)\n", iface
, pIStream
, wine_dbgstr_longlong(ulOffset
.QuadPart
),
1095 wine_dbgstr_longlong(ulMaxSize
.QuadPart
));
1097 if (!pIStream
) return E_INVALIDARG
;
1098 if (This
->pStream
) return WINCODEC_ERR_WRONGSTATE
;
1100 pObject
= HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnStreamRange
));
1101 if (!pObject
) return E_OUTOFMEMORY
;
1103 pObject
->IStream_iface
.lpVtbl
= &StreamOnStreamRange_Vtbl
;
1105 IStream_AddRef(pIStream
);
1106 pObject
->stream
= pIStream
;
1107 pObject
->pos
.QuadPart
= 0;
1108 pObject
->offset
= ulOffset
;
1109 pObject
->max_size
= ulMaxSize
;
1110 InitializeCriticalSection(&pObject
->lock
);
1111 pObject
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": StreamOnStreamRange.lock");
1113 if (InterlockedCompareExchangePointer((void**)&This
->pStream
, pObject
, NULL
))
1115 /* Some other thread set the stream first. */
1116 IStream_Release(&pObject
->IStream_iface
);
1117 return WINCODEC_ERR_WRONGSTATE
;
1124 static const IWICStreamVtbl WICStream_Vtbl
=
1126 /*** IUnknown methods ***/
1127 IWICStreamImpl_QueryInterface
,
1128 IWICStreamImpl_AddRef
,
1129 IWICStreamImpl_Release
,
1130 /*** ISequentialStream methods ***/
1131 IWICStreamImpl_Read
,
1132 IWICStreamImpl_Write
,
1133 /*** IStream methods ***/
1134 IWICStreamImpl_Seek
,
1135 IWICStreamImpl_SetSize
,
1136 IWICStreamImpl_CopyTo
,
1137 IWICStreamImpl_Commit
,
1138 IWICStreamImpl_Revert
,
1139 IWICStreamImpl_LockRegion
,
1140 IWICStreamImpl_UnlockRegion
,
1141 IWICStreamImpl_Stat
,
1142 IWICStreamImpl_Clone
,
1143 /*** IWICStream methods ***/
1144 IWICStreamImpl_InitializeFromIStream
,
1145 IWICStreamImpl_InitializeFromFilename
,
1146 IWICStreamImpl_InitializeFromMemory
,
1147 IWICStreamImpl_InitializeFromIStreamRegion
,
1150 HRESULT
StreamImpl_Create(IWICStream
**stream
)
1152 IWICStreamImpl
*pObject
;
1154 if( !stream
) return E_INVALIDARG
;
1156 pObject
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWICStreamImpl
));
1159 return E_OUTOFMEMORY
;
1162 pObject
->IWICStream_iface
.lpVtbl
= &WICStream_Vtbl
;
1164 pObject
->pStream
= NULL
;
1166 *stream
= &pObject
->IWICStream_iface
;