msvcrtd: Fix _CrtDbgReport calling convention.
[wine.git] / dlls / windowscodecs / stream.c
blob308ef8e02b414f95eeb23058c4702d1c44db2018
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 "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;
39 LONG ref;
41 BYTE *pbMemory;
42 DWORD dwMemsize;
43 DWORD dwCurPos;
45 CRITICAL_SECTION lock; /* must be held when pbMemory or dwCurPos is accessed */
46 } StreamOnMemory;
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))
63 *ppv = iface;
64 IUnknown_AddRef((IUnknown*)*ppv);
65 return S_OK;
67 else
69 *ppv = NULL;
70 return E_NOINTERFACE;
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);
81 return 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);
91 if (ref == 0) {
92 This->lock.DebugInfo->Spare[0] = 0;
93 DeleteCriticalSection(&This->lock);
94 HeapFree(GetProcessHeap(), 0, This);
96 return ref;
99 static HRESULT WINAPI StreamOnMemory_Read(IStream *iface,
100 void *pv, ULONG cb, ULONG *pcbRead)
102 StreamOnMemory *This = StreamOnMemory_from_IStream(iface);
103 ULONG uBytesRead;
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;
116 return S_OK;
119 static HRESULT WINAPI StreamOnMemory_Write(IStream *iface,
120 void const *pv, ULONG cb, ULONG *pcbWritten)
122 StreamOnMemory *This = StreamOnMemory_from_IStream(iface);
123 HRESULT hr;
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;
132 else {
133 memmove(This->pbMemory + This->dwCurPos, pv, cb);
134 This->dwCurPos += cb;
135 hr = S_OK;
136 if (pcbWritten) *pcbWritten = cb;
138 LeaveCriticalSection(&This->lock);
140 return hr;
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;
148 HRESULT hr=S_OK;
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;
157 if (SUCCEEDED(hr)) {
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;
163 if (SUCCEEDED(hr)) {
164 This->dwCurPos = NewPosition.u.LowPart;
166 if(plibNewPosition) plibNewPosition->QuadPart = This->dwCurPos;
168 LeaveCriticalSection(&This->lock);
170 return hr;
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);
178 return E_NOTIMPL;
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);
186 return E_NOTIMPL;
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);
194 return E_NOTIMPL;
197 /* Revert isn't implemented in the native windowscodecs DLL either */
198 static HRESULT WINAPI StreamOnMemory_Revert(IStream *iface)
200 TRACE("(%p)\n", iface);
201 return E_NOTIMPL;
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);
209 return E_NOTIMPL;
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);
217 return E_NOTIMPL;
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;
232 return S_OK;
235 /* Clone isn't implemented in the native windowscodecs DLL either */
236 static HRESULT WINAPI StreamOnMemory_Clone(IStream *iface,
237 IStream **ppstm)
239 TRACE("(%p)\n", iface);
240 return E_NOTIMPL;
244 static const IStreamVtbl StreamOnMemory_Vtbl =
246 /*** IUnknown methods ***/
247 StreamOnMemory_QueryInterface,
248 StreamOnMemory_AddRef,
249 StreamOnMemory_Release,
250 /*** ISequentialStream methods ***/
251 StreamOnMemory_Read,
252 StreamOnMemory_Write,
253 /*** IStream methods ***/
254 StreamOnMemory_Seek,
255 StreamOnMemory_SetSize,
256 StreamOnMemory_CopyTo,
257 StreamOnMemory_Commit,
258 StreamOnMemory_Revert,
259 StreamOnMemory_LockRegion,
260 StreamOnMemory_UnlockRegion,
261 StreamOnMemory_Stat,
262 StreamOnMemory_Clone,
265 /******************************************
266 * StreamOnFileHandle implementation (internal)
269 typedef struct StreamOnFileHandle {
270 IStream IStream_iface;
271 LONG ref;
273 HANDLE map;
274 void *mem;
275 IWICStream *stream;
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))
293 *ppv = iface;
294 IUnknown_AddRef((IUnknown*)*ppv);
295 return S_OK;
297 else
299 *ppv = NULL;
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);
311 return 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);
321 if (ref == 0) {
322 IWICStream_Release(This->stream);
323 UnmapViewOfFile(This->mem);
324 CloseHandle(This->map);
325 HeapFree(GetProcessHeap(), 0, This);
327 return ref;
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);
359 return E_NOTIMPL;
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);
366 return E_NOTIMPL;
369 static HRESULT WINAPI StreamOnFileHandle_Commit(IStream *iface,
370 DWORD grfCommitFlags)
372 TRACE("(%p)\n", iface);
373 return E_NOTIMPL;
376 static HRESULT WINAPI StreamOnFileHandle_Revert(IStream *iface)
378 TRACE("(%p)\n", iface);
379 return E_NOTIMPL;
382 static HRESULT WINAPI StreamOnFileHandle_LockRegion(IStream *iface,
383 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
385 TRACE("(%p)\n", iface);
386 return E_NOTIMPL;
389 static HRESULT WINAPI StreamOnFileHandle_UnlockRegion(IStream *iface,
390 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
392 TRACE("(%p)\n", iface);
393 return E_NOTIMPL;
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,
406 IStream **ppstm)
408 TRACE("(%p)\n", iface);
409 return E_NOTIMPL;
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;
442 LONG ref;
444 IStream *stream;
445 ULARGE_INTEGER pos;
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))
467 *ppv = iface;
468 IUnknown_AddRef((IUnknown*)*ppv);
469 return S_OK;
471 else
473 *ppv = NULL;
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);
485 return 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);
495 if (ref == 0) {
496 This->lock.DebugInfo->Spare[0] = 0;
497 DeleteCriticalSection(&This->lock);
498 IStream_Release(This->stream);
499 HeapFree(GetProcessHeap(), 0, This);
501 return ref;
504 static HRESULT WINAPI StreamOnStreamRange_Read(IStream *iface,
505 void *pv, ULONG cb, ULONG *pcbRead)
507 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
508 ULONG uBytesRead=0;
509 HRESULT hr;
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);
519 if (SUCCEEDED(hr))
521 SetPosition.QuadPart = This->pos.QuadPart + This->offset.QuadPart;
522 hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL);
524 if (SUCCEEDED(hr))
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)
530 cb = 0;
531 else
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);
538 if (SUCCEEDED(hr))
539 This->pos.QuadPart += uBytesRead;
540 LeaveCriticalSection(&This->lock);
542 if (SUCCEEDED(hr) && pcbRead) *pcbRead = uBytesRead;
544 return hr;
547 static HRESULT WINAPI StreamOnStreamRange_Write(IStream *iface,
548 void const *pv, ULONG cb, ULONG *pcbWritten)
550 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
551 HRESULT hr;
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);
562 if (SUCCEEDED(hr))
564 SetPosition.QuadPart = This->pos.QuadPart + This->offset.QuadPart;
565 hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL);
567 if (SUCCEEDED(hr))
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)
573 cb = 0;
574 else
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);
581 if (SUCCEEDED(hr))
582 This->pos.QuadPart += uBytesWritten;
583 LeaveCriticalSection(&This->lock);
585 if (SUCCEEDED(hr) && pcbWritten) *pcbWritten = uBytesWritten;
587 return hr;
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;
595 HRESULT hr=S_OK;
596 STATSTG statstg;
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);
608 if (SUCCEEDED(hr))
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;
620 if (SUCCEEDED(hr)) {
621 This->pos.QuadPart = NewPosition.QuadPart;
623 if(plibNewPosition) plibNewPosition->QuadPart = This->pos.QuadPart;
625 LeaveCriticalSection(&This->lock);
627 return hr;
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);
635 return E_NOTIMPL;
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);
643 return E_NOTIMPL;
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);
651 return E_NOTIMPL;
654 /* Revert isn't implemented in the native windowscodecs DLL either */
655 static HRESULT WINAPI StreamOnStreamRange_Revert(IStream *iface)
657 TRACE("(%p)\n", iface);
658 return E_NOTIMPL;
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);
666 return E_NOTIMPL;
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);
674 return E_NOTIMPL;
677 static HRESULT WINAPI StreamOnStreamRange_Stat(IStream *iface,
678 STATSTG *pstatstg, DWORD grfStatFlag)
680 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
681 HRESULT hr;
682 TRACE("(%p)\n", This);
684 if (!pstatstg) return E_INVALIDARG;
686 EnterCriticalSection(&This->lock);
687 hr = IStream_Stat(This->stream, pstatstg, grfStatFlag);
688 if (SUCCEEDED(hr))
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);
697 return hr;
700 /* Clone isn't implemented in the native windowscodecs DLL either */
701 static HRESULT WINAPI StreamOnStreamRange_Clone(IStream *iface,
702 IStream **ppstm)
704 TRACE("(%p)\n", iface);
705 return E_NOTIMPL;
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;
738 LONG ref;
740 IStream *pStream;
741 } IWICStreamImpl;
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);
761 return S_OK;
763 else
765 *ppv = NULL;
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);
777 return 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);
787 if (ref == 0) {
788 if (This->pStream) IStream_Release(This->pStream);
789 HeapFree(GetProcessHeap(), 0, This);
791 return ref;
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,
894 IStream **ppstm)
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,
904 IStream *pIStream)
906 ULARGE_INTEGER offset, size;
907 TRACE("(%p): relay\n", iface);
909 offset.QuadPart = 0;
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);
919 HRESULT hr;
920 DWORD dwMode;
921 IStream *stream;
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;
931 else
932 return E_INVALIDARG;
934 hr = SHCreateStreamOnFileW(wzFileName, dwMode, &stream);
936 if (SUCCEEDED(hr))
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;
946 return hr;
949 /******************************************
950 * IWICStream_InitializeFromMemory
952 * Initializes the internal IStream object to retrieve its data from a memory chunk.
954 * PARAMS
955 * pbBuffer [I] pointer to the memory chunk
956 * cbBufferSize [I] number of bytes to use from the memory chunk
958 * RETURNS
959 * SUCCESS: S_OK
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;
979 pObject->ref = 1;
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;
993 return S_OK;
996 static HRESULT map_file(HANDLE file, HANDLE *map, void **mem, LARGE_INTEGER *size)
998 *map = NULL;
999 if (!GetFileSizeEx(file, size)) return HRESULT_FROM_WIN32(GetLastError());
1000 if (size->u.HighPart)
1002 WARN("file too large\n");
1003 return E_FAIL;
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)))
1011 CloseHandle(*map);
1012 return HRESULT_FROM_WIN32(GetLastError());
1014 return S_OK;
1017 HRESULT stream_initialize_from_filehandle(IWICStream *iface, HANDLE file)
1019 IWICStreamImpl *This = impl_from_IWICStream(iface);
1020 StreamOnFileHandle *pObject;
1021 IWICStream *stream = NULL;
1022 HANDLE map;
1023 void *mem;
1024 LARGE_INTEGER size;
1025 HRESULT hr;
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));
1040 if (!pObject)
1042 hr = E_OUTOFMEMORY;
1043 goto error;
1045 pObject->IStream_iface.lpVtbl = &StreamOnFileHandle_Vtbl;
1046 pObject->ref = 1;
1047 pObject->map = map;
1048 pObject->mem = mem;
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;
1057 return S_OK;
1059 error:
1060 if (stream) IWICStream_Release(stream);
1061 UnmapViewOfFile(mem);
1062 CloseHandle(map);
1063 return hr;
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;
1080 pObject->ref = 1;
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;
1096 return S_OK;
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));
1133 if( !pObject ) {
1134 *stream = NULL;
1135 return E_OUTOFMEMORY;
1138 pObject->IWICStream_iface.lpVtbl = &WICStream_Vtbl;
1139 pObject->ref = 1;
1140 pObject->pStream = NULL;
1142 *stream = &pObject->IWICStream_iface;
1144 return S_OK;