include: Move some definitions from iptypes.h to nldef.h.
[wine.git] / dlls / windowscodecs / stream.c
blobcd235a3f0307eac53b968c229d6f8e1dc20672b4
1 /*
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"
21 #define COBJMACROS
22 #include "windef.h"
23 #include "winbase.h"
24 #include "winreg.h"
25 #include "objbase.h"
26 #include "shlwapi.h"
27 #include "wincodec.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;
40 LONG ref;
42 BYTE *pbMemory;
43 DWORD dwMemsize;
44 DWORD dwCurPos;
46 CRITICAL_SECTION lock; /* must be held when pbMemory or dwCurPos is accessed */
47 } StreamOnMemory;
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))
64 *ppv = iface;
65 IUnknown_AddRef((IUnknown*)*ppv);
66 return S_OK;
68 else
70 *ppv = NULL;
71 return E_NOINTERFACE;
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);
82 return 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);
92 if (ref == 0) {
93 This->lock.DebugInfo->Spare[0] = 0;
94 DeleteCriticalSection(&This->lock);
95 HeapFree(GetProcessHeap(), 0, This);
97 return ref;
100 static HRESULT WINAPI StreamOnMemory_Read(IStream *iface,
101 void *pv, ULONG cb, ULONG *pcbRead)
103 StreamOnMemory *This = StreamOnMemory_from_IStream(iface);
104 ULONG uBytesRead;
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;
117 return S_OK;
120 static HRESULT WINAPI StreamOnMemory_Write(IStream *iface,
121 void const *pv, ULONG cb, ULONG *pcbWritten)
123 StreamOnMemory *This = StreamOnMemory_from_IStream(iface);
124 HRESULT hr;
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;
133 else {
134 memmove(This->pbMemory + This->dwCurPos, pv, cb);
135 This->dwCurPos += cb;
136 hr = S_OK;
137 if (pcbWritten) *pcbWritten = cb;
139 LeaveCriticalSection(&This->lock);
141 return hr;
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;
149 HRESULT hr=S_OK;
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;
158 if (SUCCEEDED(hr)) {
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;
164 if (SUCCEEDED(hr)) {
165 This->dwCurPos = NewPosition.u.LowPart;
167 if(plibNewPosition) plibNewPosition->QuadPart = This->dwCurPos;
169 LeaveCriticalSection(&This->lock);
171 return hr;
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);
179 return E_NOTIMPL;
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);
187 return E_NOTIMPL;
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);
195 return E_NOTIMPL;
198 /* Revert isn't implemented in the native windowscodecs DLL either */
199 static HRESULT WINAPI StreamOnMemory_Revert(IStream *iface)
201 TRACE("(%p)\n", iface);
202 return E_NOTIMPL;
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);
210 return E_NOTIMPL;
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);
218 return E_NOTIMPL;
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;
233 return S_OK;
236 /* Clone isn't implemented in the native windowscodecs DLL either */
237 static HRESULT WINAPI StreamOnMemory_Clone(IStream *iface,
238 IStream **ppstm)
240 TRACE("(%p)\n", iface);
241 return E_NOTIMPL;
245 static const IStreamVtbl StreamOnMemory_Vtbl =
247 /*** IUnknown methods ***/
248 StreamOnMemory_QueryInterface,
249 StreamOnMemory_AddRef,
250 StreamOnMemory_Release,
251 /*** ISequentialStream methods ***/
252 StreamOnMemory_Read,
253 StreamOnMemory_Write,
254 /*** IStream methods ***/
255 StreamOnMemory_Seek,
256 StreamOnMemory_SetSize,
257 StreamOnMemory_CopyTo,
258 StreamOnMemory_Commit,
259 StreamOnMemory_Revert,
260 StreamOnMemory_LockRegion,
261 StreamOnMemory_UnlockRegion,
262 StreamOnMemory_Stat,
263 StreamOnMemory_Clone,
266 /******************************************
267 * StreamOnStreamRange implementation
269 * Used by IWICStream_InitializeFromIStreamRegion
272 typedef struct StreamOnStreamRange {
273 IStream IStream_iface;
274 LONG ref;
276 IStream *stream;
277 ULARGE_INTEGER pos;
278 ULARGE_INTEGER offset;
279 ULARGE_INTEGER max_size;
281 CRITICAL_SECTION lock;
282 } StreamOnStreamRange;
284 static inline StreamOnStreamRange *StreamOnStreamRange_from_IStream(IStream *iface)
286 return CONTAINING_RECORD(iface, StreamOnStreamRange, IStream_iface);
289 static HRESULT WINAPI StreamOnStreamRange_QueryInterface(IStream *iface,
290 REFIID iid, void **ppv)
292 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
294 if (!ppv) return E_INVALIDARG;
296 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) ||
297 IsEqualIID(&IID_ISequentialStream, iid))
299 *ppv = iface;
300 IUnknown_AddRef((IUnknown*)*ppv);
301 return S_OK;
303 else
305 *ppv = NULL;
306 return E_NOINTERFACE;
310 static ULONG WINAPI StreamOnStreamRange_AddRef(IStream *iface)
312 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
313 ULONG ref = InterlockedIncrement(&This->ref);
315 TRACE("(%p) refcount=%u\n", iface, ref);
317 return ref;
320 static ULONG WINAPI StreamOnStreamRange_Release(IStream *iface)
322 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
323 ULONG ref = InterlockedDecrement(&This->ref);
325 TRACE("(%p) refcount=%u\n", iface, ref);
327 if (ref == 0) {
328 This->lock.DebugInfo->Spare[0] = 0;
329 DeleteCriticalSection(&This->lock);
330 IStream_Release(This->stream);
331 HeapFree(GetProcessHeap(), 0, This);
333 return ref;
336 static HRESULT WINAPI StreamOnStreamRange_Read(IStream *iface,
337 void *pv, ULONG cb, ULONG *pcbRead)
339 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
340 ULONG uBytesRead=0;
341 HRESULT hr;
342 ULARGE_INTEGER OldPosition;
343 LARGE_INTEGER SetPosition;
344 TRACE("(%p)\n", This);
346 if (!pv) return E_INVALIDARG;
348 EnterCriticalSection(&This->lock);
349 SetPosition.QuadPart = 0;
350 hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_CUR, &OldPosition);
351 if (SUCCEEDED(hr))
353 SetPosition.QuadPart = This->pos.QuadPart + This->offset.QuadPart;
354 hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL);
356 if (SUCCEEDED(hr))
358 if (This->pos.QuadPart + cb > This->max_size.QuadPart)
360 /* This would read past the end of the stream. */
361 if (This->pos.QuadPart > This->max_size.QuadPart)
362 cb = 0;
363 else
364 cb = This->max_size.QuadPart - This->pos.QuadPart;
366 hr = IStream_Read(This->stream, pv, cb, &uBytesRead);
367 SetPosition.QuadPart = OldPosition.QuadPart;
368 IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL);
370 if (SUCCEEDED(hr))
371 This->pos.QuadPart += uBytesRead;
372 LeaveCriticalSection(&This->lock);
374 if (SUCCEEDED(hr) && pcbRead) *pcbRead = uBytesRead;
376 return hr;
379 static HRESULT WINAPI StreamOnStreamRange_Write(IStream *iface,
380 void const *pv, ULONG cb, ULONG *pcbWritten)
382 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
383 HRESULT hr;
384 ULARGE_INTEGER OldPosition;
385 LARGE_INTEGER SetPosition;
386 ULONG uBytesWritten=0;
387 TRACE("(%p)\n", This);
389 if (!pv) return E_INVALIDARG;
391 EnterCriticalSection(&This->lock);
392 SetPosition.QuadPart = 0;
393 hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_CUR, &OldPosition);
394 if (SUCCEEDED(hr))
396 SetPosition.QuadPart = This->pos.QuadPart + This->offset.QuadPart;
397 hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL);
399 if (SUCCEEDED(hr))
401 if (This->pos.QuadPart + cb > This->max_size.QuadPart)
403 /* This would read past the end of the stream. */
404 if (This->pos.QuadPart > This->max_size.QuadPart)
405 cb = 0;
406 else
407 cb = This->max_size.QuadPart - This->pos.QuadPart;
409 hr = IStream_Write(This->stream, pv, cb, &uBytesWritten);
410 SetPosition.QuadPart = OldPosition.QuadPart;
411 IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL);
413 if (SUCCEEDED(hr))
414 This->pos.QuadPart += uBytesWritten;
415 LeaveCriticalSection(&This->lock);
417 if (SUCCEEDED(hr) && pcbWritten) *pcbWritten = uBytesWritten;
419 return hr;
422 static HRESULT WINAPI StreamOnStreamRange_Seek(IStream *iface,
423 LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
425 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
426 ULARGE_INTEGER NewPosition, actual_size;
427 HRESULT hr=S_OK;
428 STATSTG statstg;
429 TRACE("(%p)\n", This);
431 EnterCriticalSection(&This->lock);
432 actual_size = This->max_size;
433 if (dwOrigin == STREAM_SEEK_SET)
434 NewPosition.QuadPart = dlibMove.QuadPart;
435 else if (dwOrigin == STREAM_SEEK_CUR)
436 NewPosition.QuadPart = This->pos.QuadPart + dlibMove.QuadPart;
437 else if (dwOrigin == STREAM_SEEK_END)
439 hr = IStream_Stat(This->stream, &statstg, STATFLAG_NONAME);
440 if (SUCCEEDED(hr))
442 if (This->max_size.QuadPart + This->offset.QuadPart > statstg.cbSize.QuadPart)
443 actual_size.QuadPart = statstg.cbSize.QuadPart - This->offset.QuadPart;
444 NewPosition.QuadPart = dlibMove.QuadPart + actual_size.QuadPart;
447 else hr = E_INVALIDARG;
449 if (SUCCEEDED(hr) && (NewPosition.u.HighPart != 0 || NewPosition.QuadPart > actual_size.QuadPart))
450 hr = WINCODEC_ERR_VALUEOUTOFRANGE;
452 if (SUCCEEDED(hr)) {
453 This->pos.QuadPart = NewPosition.QuadPart;
455 if(plibNewPosition) plibNewPosition->QuadPart = This->pos.QuadPart;
457 LeaveCriticalSection(&This->lock);
459 return hr;
462 /* SetSize isn't implemented in the native windowscodecs DLL either */
463 static HRESULT WINAPI StreamOnStreamRange_SetSize(IStream *iface,
464 ULARGE_INTEGER libNewSize)
466 TRACE("(%p)\n", iface);
467 return E_NOTIMPL;
470 /* CopyTo isn't implemented in the native windowscodecs DLL either */
471 static HRESULT WINAPI StreamOnStreamRange_CopyTo(IStream *iface,
472 IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
474 TRACE("(%p)\n", iface);
475 return E_NOTIMPL;
478 /* Commit isn't implemented in the native windowscodecs DLL either */
479 static HRESULT WINAPI StreamOnStreamRange_Commit(IStream *iface,
480 DWORD grfCommitFlags)
482 TRACE("(%p)\n", iface);
483 return E_NOTIMPL;
486 /* Revert isn't implemented in the native windowscodecs DLL either */
487 static HRESULT WINAPI StreamOnStreamRange_Revert(IStream *iface)
489 TRACE("(%p)\n", iface);
490 return E_NOTIMPL;
493 /* LockRegion isn't implemented in the native windowscodecs DLL either */
494 static HRESULT WINAPI StreamOnStreamRange_LockRegion(IStream *iface,
495 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
497 TRACE("(%p)\n", iface);
498 return E_NOTIMPL;
501 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */
502 static HRESULT WINAPI StreamOnStreamRange_UnlockRegion(IStream *iface,
503 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
505 TRACE("(%p)\n", iface);
506 return E_NOTIMPL;
509 static HRESULT WINAPI StreamOnStreamRange_Stat(IStream *iface,
510 STATSTG *pstatstg, DWORD grfStatFlag)
512 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
513 HRESULT hr;
514 TRACE("(%p)\n", This);
516 if (!pstatstg) return E_INVALIDARG;
518 EnterCriticalSection(&This->lock);
519 hr = IStream_Stat(This->stream, pstatstg, grfStatFlag);
520 if (SUCCEEDED(hr))
522 pstatstg->cbSize.QuadPart -= This->offset.QuadPart;
523 if (This->max_size.QuadPart < pstatstg->cbSize.QuadPart)
524 pstatstg->cbSize.QuadPart = This->max_size.QuadPart;
527 LeaveCriticalSection(&This->lock);
529 return hr;
532 /* Clone isn't implemented in the native windowscodecs DLL either */
533 static HRESULT WINAPI StreamOnStreamRange_Clone(IStream *iface,
534 IStream **ppstm)
536 TRACE("(%p)\n", iface);
537 return E_NOTIMPL;
541 static const IStreamVtbl StreamOnStreamRange_Vtbl =
543 /*** IUnknown methods ***/
544 StreamOnStreamRange_QueryInterface,
545 StreamOnStreamRange_AddRef,
546 StreamOnStreamRange_Release,
547 /*** ISequentialStream methods ***/
548 StreamOnStreamRange_Read,
549 StreamOnStreamRange_Write,
550 /*** IStream methods ***/
551 StreamOnStreamRange_Seek,
552 StreamOnStreamRange_SetSize,
553 StreamOnStreamRange_CopyTo,
554 StreamOnStreamRange_Commit,
555 StreamOnStreamRange_Revert,
556 StreamOnStreamRange_LockRegion,
557 StreamOnStreamRange_UnlockRegion,
558 StreamOnStreamRange_Stat,
559 StreamOnStreamRange_Clone,
563 /******************************************
564 * IWICStream implementation
567 typedef struct IWICStreamImpl
569 IWICStream IWICStream_iface;
570 LONG ref;
572 IStream *pStream;
573 } IWICStreamImpl;
575 static inline IWICStreamImpl *impl_from_IWICStream(IWICStream *iface)
577 return CONTAINING_RECORD(iface, IWICStreamImpl, IWICStream_iface);
580 static HRESULT WINAPI IWICStreamImpl_QueryInterface(IWICStream *iface,
581 REFIID iid, void **ppv)
583 IWICStreamImpl *This = impl_from_IWICStream(iface);
584 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
586 if (!ppv) return E_INVALIDARG;
588 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) ||
589 IsEqualIID(&IID_ISequentialStream, iid) || IsEqualIID(&IID_IWICStream, iid))
591 *ppv = This;
592 IUnknown_AddRef((IUnknown*)*ppv);
593 return S_OK;
595 else
597 *ppv = NULL;
598 return E_NOINTERFACE;
602 static ULONG WINAPI IWICStreamImpl_AddRef(IWICStream *iface)
604 IWICStreamImpl *This = impl_from_IWICStream(iface);
605 ULONG ref = InterlockedIncrement(&This->ref);
607 TRACE("(%p) refcount=%u\n", iface, ref);
609 return ref;
612 static ULONG WINAPI IWICStreamImpl_Release(IWICStream *iface)
614 IWICStreamImpl *This = impl_from_IWICStream(iface);
615 ULONG ref = InterlockedDecrement(&This->ref);
617 TRACE("(%p) refcount=%u\n", iface, ref);
619 if (ref == 0) {
620 if (This->pStream) IStream_Release(This->pStream);
621 HeapFree(GetProcessHeap(), 0, This);
623 return ref;
626 static HRESULT WINAPI IWICStreamImpl_Read(IWICStream *iface,
627 void *pv, ULONG cb, ULONG *pcbRead)
629 IWICStreamImpl *This = impl_from_IWICStream(iface);
630 TRACE("(%p): relay\n", This);
632 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
633 return IStream_Read(This->pStream, pv, cb, pcbRead);
636 static HRESULT WINAPI IWICStreamImpl_Write(IWICStream *iface,
637 void const *pv, ULONG cb, ULONG *pcbWritten)
639 IWICStreamImpl *This = impl_from_IWICStream(iface);
640 TRACE("(%p): relay\n", This);
642 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
643 return IStream_Write(This->pStream, pv, cb, pcbWritten);
646 static HRESULT WINAPI IWICStreamImpl_Seek(IWICStream *iface,
647 LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
649 IWICStreamImpl *This = impl_from_IWICStream(iface);
650 TRACE("(%p): relay\n", This);
652 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
653 return IStream_Seek(This->pStream, dlibMove, dwOrigin, plibNewPosition);
656 static HRESULT WINAPI IWICStreamImpl_SetSize(IWICStream *iface,
657 ULARGE_INTEGER libNewSize)
659 IWICStreamImpl *This = impl_from_IWICStream(iface);
660 TRACE("(%p): relay\n", This);
662 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
663 return IStream_SetSize(This->pStream, libNewSize);
666 static HRESULT WINAPI IWICStreamImpl_CopyTo(IWICStream *iface,
667 IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
669 IWICStreamImpl *This = impl_from_IWICStream(iface);
670 TRACE("(%p): relay\n", This);
672 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
673 return IStream_CopyTo(This->pStream, pstm, cb, pcbRead, pcbWritten);
676 static HRESULT WINAPI IWICStreamImpl_Commit(IWICStream *iface,
677 DWORD grfCommitFlags)
679 IWICStreamImpl *This = impl_from_IWICStream(iface);
680 TRACE("(%p): relay\n", This);
682 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
683 return IStream_Commit(This->pStream, grfCommitFlags);
686 static HRESULT WINAPI IWICStreamImpl_Revert(IWICStream *iface)
688 IWICStreamImpl *This = impl_from_IWICStream(iface);
689 TRACE("(%p): relay\n", This);
691 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
692 return IStream_Revert(This->pStream);
695 static HRESULT WINAPI IWICStreamImpl_LockRegion(IWICStream *iface,
696 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
698 IWICStreamImpl *This = impl_from_IWICStream(iface);
699 TRACE("(%p): relay\n", This);
701 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
702 return IStream_LockRegion(This->pStream, libOffset, cb, dwLockType);
705 static HRESULT WINAPI IWICStreamImpl_UnlockRegion(IWICStream *iface,
706 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
708 IWICStreamImpl *This = impl_from_IWICStream(iface);
709 TRACE("(%p): relay\n", This);
711 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
712 return IStream_UnlockRegion(This->pStream, libOffset, cb, dwLockType);
715 static HRESULT WINAPI IWICStreamImpl_Stat(IWICStream *iface,
716 STATSTG *pstatstg, DWORD grfStatFlag)
718 IWICStreamImpl *This = impl_from_IWICStream(iface);
719 TRACE("(%p): relay\n", This);
721 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
722 return IStream_Stat(This->pStream, pstatstg, grfStatFlag);
725 static HRESULT WINAPI IWICStreamImpl_Clone(IWICStream *iface,
726 IStream **ppstm)
728 IWICStreamImpl *This = impl_from_IWICStream(iface);
729 TRACE("(%p): relay\n", This);
731 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
732 return IStream_Clone(This->pStream, ppstm);
735 static HRESULT WINAPI IWICStreamImpl_InitializeFromIStream(IWICStream *iface,
736 IStream *pIStream)
738 FIXME("(%p): stub\n", iface);
739 return E_NOTIMPL;
742 static HRESULT WINAPI IWICStreamImpl_InitializeFromFilename(IWICStream *iface,
743 LPCWSTR wzFileName, DWORD dwDesiredAccess)
745 IWICStreamImpl *This = impl_from_IWICStream(iface);
746 HRESULT hr;
747 DWORD dwMode;
748 IStream *stream;
750 TRACE("(%p, %s, %u)\n", iface, debugstr_w(wzFileName), dwDesiredAccess);
752 if (This->pStream) return WINCODEC_ERR_WRONGSTATE;
754 if(dwDesiredAccess & GENERIC_WRITE)
755 dwMode = STGM_SHARE_DENY_WRITE | STGM_WRITE | STGM_CREATE;
756 else if(dwDesiredAccess & GENERIC_READ)
757 dwMode = STGM_SHARE_DENY_WRITE | STGM_READ | STGM_FAILIFTHERE;
758 else
759 return E_INVALIDARG;
761 hr = SHCreateStreamOnFileW(wzFileName, dwMode, &stream);
763 if (SUCCEEDED(hr))
765 if (InterlockedCompareExchangePointer((void**)&This->pStream, stream, NULL))
767 /* Some other thread set the stream first. */
768 IStream_Release(stream);
769 hr = WINCODEC_ERR_WRONGSTATE;
773 return hr;
776 /******************************************
777 * IWICStream_InitializeFromMemory
779 * Initializes the internal IStream object to retrieve its data from a memory chunk.
781 * PARAMS
782 * pbBuffer [I] pointer to the memory chunk
783 * cbBufferSize [I] number of bytes to use from the memory chunk
785 * RETURNS
786 * SUCCESS: S_OK
787 * FAILURE: E_INVALIDARG, if pbBuffer is NULL
788 * E_OUTOFMEMORY, if we run out of memory
789 * WINCODEC_ERR_WRONGSTATE, if the IStream object has already been initialized before
792 static HRESULT WINAPI IWICStreamImpl_InitializeFromMemory(IWICStream *iface,
793 BYTE *pbBuffer, DWORD cbBufferSize)
795 IWICStreamImpl *This = impl_from_IWICStream(iface);
796 StreamOnMemory *pObject;
797 TRACE("(%p,%p)\n", iface, pbBuffer);
799 if (!pbBuffer) return E_INVALIDARG;
800 if (This->pStream) return WINCODEC_ERR_WRONGSTATE;
802 pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnMemory));
803 if (!pObject) return E_OUTOFMEMORY;
805 pObject->IStream_iface.lpVtbl = &StreamOnMemory_Vtbl;
806 pObject->ref = 1;
807 pObject->pbMemory = pbBuffer;
808 pObject->dwMemsize = cbBufferSize;
809 pObject->dwCurPos = 0;
810 InitializeCriticalSection(&pObject->lock);
811 pObject->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": StreamOnMemory.lock");
813 if (InterlockedCompareExchangePointer((void**)&This->pStream, pObject, NULL))
815 /* Some other thread set the stream first. */
816 IStream_Release(&pObject->IStream_iface);
817 return WINCODEC_ERR_WRONGSTATE;
820 return S_OK;
823 static HRESULT WINAPI IWICStreamImpl_InitializeFromIStreamRegion(IWICStream *iface,
824 IStream *pIStream, ULARGE_INTEGER ulOffset, ULARGE_INTEGER ulMaxSize)
826 IWICStreamImpl *This = impl_from_IWICStream(iface);
827 StreamOnStreamRange *pObject;
828 TRACE("(%p,%p)\n", iface, pIStream);
830 if (!pIStream) return E_INVALIDARG;
831 if (This->pStream) return WINCODEC_ERR_WRONGSTATE;
833 pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnStreamRange));
834 if (!pObject) return E_OUTOFMEMORY;
836 pObject->IStream_iface.lpVtbl = &StreamOnStreamRange_Vtbl;
837 pObject->ref = 1;
838 IStream_AddRef(pIStream);
839 pObject->stream = pIStream;
840 pObject->pos.QuadPart = 0;
841 pObject->offset = ulOffset;
842 pObject->max_size = ulMaxSize;
843 InitializeCriticalSection(&pObject->lock);
844 pObject->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": StreamOnStreamRange.lock");
846 if (InterlockedCompareExchangePointer((void**)&This->pStream, pObject, NULL))
848 /* Some other thread set the stream first. */
849 IStream_Release(&pObject->IStream_iface);
850 return WINCODEC_ERR_WRONGSTATE;
853 return S_OK;
857 static const IWICStreamVtbl WICStream_Vtbl =
859 /*** IUnknown methods ***/
860 IWICStreamImpl_QueryInterface,
861 IWICStreamImpl_AddRef,
862 IWICStreamImpl_Release,
863 /*** ISequentialStream methods ***/
864 IWICStreamImpl_Read,
865 IWICStreamImpl_Write,
866 /*** IStream methods ***/
867 IWICStreamImpl_Seek,
868 IWICStreamImpl_SetSize,
869 IWICStreamImpl_CopyTo,
870 IWICStreamImpl_Commit,
871 IWICStreamImpl_Revert,
872 IWICStreamImpl_LockRegion,
873 IWICStreamImpl_UnlockRegion,
874 IWICStreamImpl_Stat,
875 IWICStreamImpl_Clone,
876 /*** IWICStream methods ***/
877 IWICStreamImpl_InitializeFromIStream,
878 IWICStreamImpl_InitializeFromFilename,
879 IWICStreamImpl_InitializeFromMemory,
880 IWICStreamImpl_InitializeFromIStreamRegion,
883 HRESULT StreamImpl_Create(IWICStream **stream)
885 IWICStreamImpl *pObject;
887 if( !stream ) return E_INVALIDARG;
889 pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(IWICStreamImpl));
890 if( !pObject ) {
891 *stream = NULL;
892 return E_OUTOFMEMORY;
895 pObject->IWICStream_iface.lpVtbl = &WICStream_Vtbl;
896 pObject->ref = 1;
897 pObject->pStream = NULL;
899 *stream = &pObject->IWICStream_iface;
901 return S_OK;