wined3d: Use a shader for unconverted blits.
[wine.git] / dlls / windowscodecs / stream.c
blobf6bfedfc018a292ab6050c09091a9c836af8245f
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 * StreamOnFileHandle implementation (internal)
270 typedef struct StreamOnFileHandle {
271 IStream IStream_iface;
272 LONG ref;
274 HANDLE map;
275 void *mem;
276 IWICStream *stream;
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))
294 *ppv = iface;
295 IUnknown_AddRef((IUnknown*)*ppv);
296 return S_OK;
298 else
300 *ppv = NULL;
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);
312 return 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);
322 if (ref == 0) {
323 IWICStream_Release(This->stream);
324 UnmapViewOfFile(This->mem);
325 CloseHandle(This->map);
326 HeapFree(GetProcessHeap(), 0, This);
328 return ref;
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);
360 return E_NOTIMPL;
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);
367 return E_NOTIMPL;
370 static HRESULT WINAPI StreamOnFileHandle_Commit(IStream *iface,
371 DWORD grfCommitFlags)
373 TRACE("(%p)\n", iface);
374 return E_NOTIMPL;
377 static HRESULT WINAPI StreamOnFileHandle_Revert(IStream *iface)
379 TRACE("(%p)\n", iface);
380 return E_NOTIMPL;
383 static HRESULT WINAPI StreamOnFileHandle_LockRegion(IStream *iface,
384 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
386 TRACE("(%p)\n", iface);
387 return E_NOTIMPL;
390 static HRESULT WINAPI StreamOnFileHandle_UnlockRegion(IStream *iface,
391 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
393 TRACE("(%p)\n", iface);
394 return E_NOTIMPL;
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,
407 IStream **ppstm)
409 TRACE("(%p)\n", iface);
410 return E_NOTIMPL;
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;
443 LONG ref;
445 IStream *stream;
446 ULARGE_INTEGER pos;
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))
468 *ppv = iface;
469 IUnknown_AddRef((IUnknown*)*ppv);
470 return S_OK;
472 else
474 *ppv = NULL;
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);
486 return 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);
496 if (ref == 0) {
497 This->lock.DebugInfo->Spare[0] = 0;
498 DeleteCriticalSection(&This->lock);
499 IStream_Release(This->stream);
500 HeapFree(GetProcessHeap(), 0, This);
502 return ref;
505 static HRESULT WINAPI StreamOnStreamRange_Read(IStream *iface,
506 void *pv, ULONG cb, ULONG *pcbRead)
508 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
509 ULONG uBytesRead=0;
510 HRESULT hr;
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);
520 if (SUCCEEDED(hr))
522 SetPosition.QuadPart = This->pos.QuadPart + This->offset.QuadPart;
523 hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL);
525 if (SUCCEEDED(hr))
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)
531 cb = 0;
532 else
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);
539 if (SUCCEEDED(hr))
540 This->pos.QuadPart += uBytesRead;
541 LeaveCriticalSection(&This->lock);
543 if (SUCCEEDED(hr) && pcbRead) *pcbRead = uBytesRead;
545 return hr;
548 static HRESULT WINAPI StreamOnStreamRange_Write(IStream *iface,
549 void const *pv, ULONG cb, ULONG *pcbWritten)
551 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
552 HRESULT hr;
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);
563 if (SUCCEEDED(hr))
565 SetPosition.QuadPart = This->pos.QuadPart + This->offset.QuadPart;
566 hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL);
568 if (SUCCEEDED(hr))
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)
574 cb = 0;
575 else
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);
582 if (SUCCEEDED(hr))
583 This->pos.QuadPart += uBytesWritten;
584 LeaveCriticalSection(&This->lock);
586 if (SUCCEEDED(hr) && pcbWritten) *pcbWritten = uBytesWritten;
588 return hr;
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;
596 HRESULT hr=S_OK;
597 STATSTG statstg;
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);
609 if (SUCCEEDED(hr))
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;
621 if (SUCCEEDED(hr)) {
622 This->pos.QuadPart = NewPosition.QuadPart;
624 if(plibNewPosition) plibNewPosition->QuadPart = This->pos.QuadPart;
626 LeaveCriticalSection(&This->lock);
628 return hr;
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);
636 return E_NOTIMPL;
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);
644 return E_NOTIMPL;
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);
652 return E_NOTIMPL;
655 /* Revert isn't implemented in the native windowscodecs DLL either */
656 static HRESULT WINAPI StreamOnStreamRange_Revert(IStream *iface)
658 TRACE("(%p)\n", iface);
659 return E_NOTIMPL;
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);
667 return E_NOTIMPL;
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);
675 return E_NOTIMPL;
678 static HRESULT WINAPI StreamOnStreamRange_Stat(IStream *iface,
679 STATSTG *pstatstg, DWORD grfStatFlag)
681 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
682 HRESULT hr;
683 TRACE("(%p)\n", This);
685 if (!pstatstg) return E_INVALIDARG;
687 EnterCriticalSection(&This->lock);
688 hr = IStream_Stat(This->stream, pstatstg, grfStatFlag);
689 if (SUCCEEDED(hr))
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);
698 return hr;
701 /* Clone isn't implemented in the native windowscodecs DLL either */
702 static HRESULT WINAPI StreamOnStreamRange_Clone(IStream *iface,
703 IStream **ppstm)
705 TRACE("(%p)\n", iface);
706 return E_NOTIMPL;
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;
739 LONG ref;
741 IStream *pStream;
742 } IWICStreamImpl;
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;
761 IUnknown_AddRef((IUnknown*)*ppv);
762 return S_OK;
764 else
766 *ppv = NULL;
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);
778 return 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);
788 if (ref == 0) {
789 if (This->pStream) IStream_Release(This->pStream);
790 HeapFree(GetProcessHeap(), 0, This);
792 return ref;
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,
895 IStream **ppstm)
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,
905 IStream *pIStream)
907 ULARGE_INTEGER offset, size;
908 TRACE("(%p): relay\n", iface);
910 offset.QuadPart = 0;
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);
920 HRESULT hr;
921 DWORD dwMode;
922 IStream *stream;
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;
932 else
933 return E_INVALIDARG;
935 hr = SHCreateStreamOnFileW(wzFileName, dwMode, &stream);
937 if (SUCCEEDED(hr))
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;
947 return hr;
950 /******************************************
951 * IWICStream_InitializeFromMemory
953 * Initializes the internal IStream object to retrieve its data from a memory chunk.
955 * PARAMS
956 * pbBuffer [I] pointer to the memory chunk
957 * cbBufferSize [I] number of bytes to use from the memory chunk
959 * RETURNS
960 * SUCCESS: S_OK
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;
980 pObject->ref = 1;
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;
994 return S_OK;
997 static HRESULT map_file(HANDLE file, HANDLE *map, void **mem, LARGE_INTEGER *size)
999 *map = NULL;
1000 if (!GetFileSizeEx(file, size)) return HRESULT_FROM_WIN32(GetLastError());
1001 if (size->u.HighPart)
1003 WARN("file too large\n");
1004 return E_FAIL;
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)))
1012 CloseHandle(*map);
1013 return HRESULT_FROM_WIN32(GetLastError());
1015 return S_OK;
1018 HRESULT stream_initialize_from_filehandle(IWICStream *iface, HANDLE file)
1020 IWICStreamImpl *This = impl_from_IWICStream(iface);
1021 StreamOnFileHandle *pObject;
1022 IWICStream *stream = NULL;
1023 HANDLE map;
1024 void *mem;
1025 LARGE_INTEGER size;
1026 HRESULT hr;
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));
1041 if (!pObject)
1043 hr = E_OUTOFMEMORY;
1044 goto error;
1046 pObject->IStream_iface.lpVtbl = &StreamOnFileHandle_Vtbl;
1047 pObject->ref = 1;
1048 pObject->map = map;
1049 pObject->mem = mem;
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;
1058 return S_OK;
1060 error:
1061 if (stream) IWICStream_Release(stream);
1062 UnmapViewOfFile(mem);
1063 CloseHandle(map);
1064 return hr;
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;
1081 pObject->ref = 1;
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;
1097 return S_OK;
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));
1134 if( !pObject ) {
1135 *stream = NULL;
1136 return E_OUTOFMEMORY;
1139 pObject->IWICStream_iface.lpVtbl = &WICStream_Vtbl;
1140 pObject->ref = 1;
1141 pObject->pStream = NULL;
1143 *stream = &pObject->IWICStream_iface;
1145 return S_OK;