sapi: Add SpMMAudioOut stub.
[wine.git] / dlls / windowscodecs / stream.c
bloba1138c8626ac11a8daf9f7ecf99245219c3b5a2b
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=%lu\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=%lu\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;
105 TRACE("(%p, %p, %lu, %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;
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;
126 TRACE("(%p, %p, %lu, %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;
134 else {
135 memmove(This->pbMemory + This->dwCurPos, pv, cb);
136 This->dwCurPos += cb;
137 hr = S_OK;
138 if (pcbWritten) *pcbWritten = cb;
140 LeaveCriticalSection(&This->lock);
142 return hr;
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;
150 HRESULT hr=S_OK;
152 TRACE("(%p, %s, %ld, %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;
160 if (SUCCEEDED(hr)) {
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;
166 if (SUCCEEDED(hr)) {
167 This->dwCurPos = NewPosition.u.LowPart;
169 if(plibNewPosition) plibNewPosition->QuadPart = This->dwCurPos;
171 LeaveCriticalSection(&This->lock);
173 return hr;
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));
181 return E_NOTIMPL;
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);
189 return E_NOTIMPL;
192 static HRESULT WINAPI StreamOnMemory_Commit(IStream *iface,
193 DWORD grfCommitFlags)
195 TRACE("(%p, %#lx)\n", iface, grfCommitFlags);
196 return S_OK;
199 /* Revert isn't implemented in the native windowscodecs DLL either */
200 static HRESULT WINAPI StreamOnMemory_Revert(IStream *iface)
202 TRACE("(%p)\n", iface);
203 return E_NOTIMPL;
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, %ld)\n", iface, wine_dbgstr_longlong(libOffset.QuadPart),
211 wine_dbgstr_longlong(cb.QuadPart), dwLockType);
212 return E_NOTIMPL;
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, %ld)\n", iface, wine_dbgstr_longlong(libOffset.QuadPart),
220 wine_dbgstr_longlong(cb.QuadPart), dwLockType);
221 return E_NOTIMPL;
224 static HRESULT WINAPI StreamOnMemory_Stat(IStream *iface,
225 STATSTG *pstatstg, DWORD grfStatFlag)
227 StreamOnMemory *This = StreamOnMemory_from_IStream(iface);
228 TRACE("(%p, %p, %#lx)\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;
236 return S_OK;
239 /* Clone isn't implemented in the native windowscodecs DLL either */
240 static HRESULT WINAPI StreamOnMemory_Clone(IStream *iface,
241 IStream **ppstm)
243 TRACE("(%p, %p)\n", iface, ppstm);
244 return E_NOTIMPL;
248 static const IStreamVtbl StreamOnMemory_Vtbl =
250 /*** IUnknown methods ***/
251 StreamOnMemory_QueryInterface,
252 StreamOnMemory_AddRef,
253 StreamOnMemory_Release,
254 /*** ISequentialStream methods ***/
255 StreamOnMemory_Read,
256 StreamOnMemory_Write,
257 /*** IStream methods ***/
258 StreamOnMemory_Seek,
259 StreamOnMemory_SetSize,
260 StreamOnMemory_CopyTo,
261 StreamOnMemory_Commit,
262 StreamOnMemory_Revert,
263 StreamOnMemory_LockRegion,
264 StreamOnMemory_UnlockRegion,
265 StreamOnMemory_Stat,
266 StreamOnMemory_Clone,
269 /******************************************
270 * StreamOnFileHandle implementation (internal)
273 typedef struct StreamOnFileHandle {
274 IStream IStream_iface;
275 LONG ref;
277 HANDLE map;
278 void *mem;
279 IWICStream *stream;
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))
297 *ppv = iface;
298 IUnknown_AddRef((IUnknown*)*ppv);
299 return S_OK;
301 else
303 *ppv = NULL;
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=%lu\n", iface, ref);
315 return 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=%lu\n", iface, ref);
325 if (ref == 0) {
326 IWICStream_Release(This->stream);
327 UnmapViewOfFile(This->mem);
328 CloseHandle(This->map);
329 HeapFree(GetProcessHeap(), 0, This);
331 return ref;
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, %lu, %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, %lu, %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, %ld, %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));
363 return E_NOTIMPL;
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);
370 return E_NOTIMPL;
373 static HRESULT WINAPI StreamOnFileHandle_Commit(IStream *iface,
374 DWORD grfCommitFlags)
376 TRACE("(%p, %#lx)\n", iface, grfCommitFlags);
377 return S_OK;
380 static HRESULT WINAPI StreamOnFileHandle_Revert(IStream *iface)
382 TRACE("(%p)\n", iface);
383 return E_NOTIMPL;
386 static HRESULT WINAPI StreamOnFileHandle_LockRegion(IStream *iface,
387 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
389 TRACE("(%p, %s, %s, %ld)\n", iface, wine_dbgstr_longlong(libOffset.QuadPart),
390 wine_dbgstr_longlong(cb.QuadPart), dwLockType);
391 return E_NOTIMPL;
394 static HRESULT WINAPI StreamOnFileHandle_UnlockRegion(IStream *iface,
395 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
397 TRACE("(%p, %s, %s, %ld)\n", iface, wine_dbgstr_longlong(libOffset.QuadPart),
398 wine_dbgstr_longlong(cb.QuadPart), dwLockType);
399 return E_NOTIMPL;
402 static HRESULT WINAPI StreamOnFileHandle_Stat(IStream *iface,
403 STATSTG *pstatstg, DWORD grfStatFlag)
405 StreamOnFileHandle *This = StreamOnFileHandle_from_IStream(iface);
406 TRACE("(%p, %p, %#lx)\n", This, pstatstg, grfStatFlag);
408 return IWICStream_Stat(This->stream, pstatstg, grfStatFlag);
411 static HRESULT WINAPI StreamOnFileHandle_Clone(IStream *iface,
412 IStream **ppstm)
414 TRACE("(%p, %p)\n", iface, ppstm);
415 return E_NOTIMPL;
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;
447 LONG ref;
449 IStream *stream;
450 ULARGE_INTEGER pos;
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))
472 *ppv = iface;
473 IUnknown_AddRef((IUnknown*)*ppv);
474 return S_OK;
476 else
478 *ppv = NULL;
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=%lu\n", iface, ref);
490 return 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=%lu\n", iface, ref);
500 if (ref == 0) {
501 This->lock.DebugInfo->Spare[0] = 0;
502 DeleteCriticalSection(&This->lock);
503 IStream_Release(This->stream);
504 HeapFree(GetProcessHeap(), 0, This);
506 return ref;
509 static HRESULT WINAPI StreamOnStreamRange_Read(IStream *iface,
510 void *pv, ULONG cb, ULONG *pcbRead)
512 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
513 ULONG uBytesRead=0;
514 HRESULT hr;
515 ULARGE_INTEGER OldPosition;
516 LARGE_INTEGER SetPosition;
518 TRACE("(%p, %p, %lu, %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);
525 if (SUCCEEDED(hr))
527 SetPosition.QuadPart = This->pos.QuadPart + This->offset.QuadPart;
528 hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL);
530 if (SUCCEEDED(hr))
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)
536 cb = 0;
537 else
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);
544 if (SUCCEEDED(hr))
545 This->pos.QuadPart += uBytesRead;
546 LeaveCriticalSection(&This->lock);
548 if (SUCCEEDED(hr) && pcbRead) *pcbRead = uBytesRead;
550 return hr;
553 static HRESULT WINAPI StreamOnStreamRange_Write(IStream *iface,
554 void const *pv, ULONG cb, ULONG *pcbWritten)
556 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
557 HRESULT hr;
558 ULARGE_INTEGER OldPosition;
559 LARGE_INTEGER SetPosition;
560 ULONG uBytesWritten=0;
561 TRACE("(%p, %p, %lu, %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);
568 if (SUCCEEDED(hr))
570 SetPosition.QuadPart = This->pos.QuadPart + This->offset.QuadPart;
571 hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL);
573 if (SUCCEEDED(hr))
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)
579 cb = 0;
580 else
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);
587 if (SUCCEEDED(hr))
588 This->pos.QuadPart += uBytesWritten;
589 LeaveCriticalSection(&This->lock);
591 if (SUCCEEDED(hr) && pcbWritten) *pcbWritten = uBytesWritten;
593 return hr;
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;
601 HRESULT hr=S_OK;
602 STATSTG statstg;
603 TRACE("(%p, %s, %ld, %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);
614 if (SUCCEEDED(hr))
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;
626 if (SUCCEEDED(hr)) {
627 This->pos.QuadPart = NewPosition.QuadPart;
629 if(plibNewPosition) plibNewPosition->QuadPart = This->pos.QuadPart;
631 LeaveCriticalSection(&This->lock);
633 return hr;
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));
641 return E_NOTIMPL;
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);
650 return E_NOTIMPL;
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, %#lx)\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);
666 return E_NOTIMPL;
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, %ld)\n", iface, wine_dbgstr_longlong(libOffset.QuadPart),
674 wine_dbgstr_longlong(cb.QuadPart), dwLockType);
675 return E_NOTIMPL;
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, %ld)\n", iface, wine_dbgstr_longlong(libOffset.QuadPart),
683 wine_dbgstr_longlong(cb.QuadPart), dwLockType);
684 return E_NOTIMPL;
687 static HRESULT WINAPI StreamOnStreamRange_Stat(IStream *iface,
688 STATSTG *pstatstg, DWORD grfStatFlag)
690 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
691 HRESULT hr;
692 TRACE("(%p, %p, %#lx)\n", This, pstatstg, grfStatFlag);
694 if (!pstatstg) return E_INVALIDARG;
696 EnterCriticalSection(&This->lock);
697 hr = IStream_Stat(This->stream, pstatstg, grfStatFlag);
698 if (SUCCEEDED(hr))
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);
707 return hr;
710 /* Clone isn't implemented in the native windowscodecs DLL either */
711 static HRESULT WINAPI StreamOnStreamRange_Clone(IStream *iface,
712 IStream **ppstm)
714 TRACE("(%p, %p)\n", iface, ppstm);
715 return E_NOTIMPL;
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;
747 LONG ref;
749 IStream *pStream;
750 } IWICStreamImpl;
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);
770 return S_OK;
772 else
774 *ppv = NULL;
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=%lu\n", iface, ref);
786 return 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=%lu\n", iface, ref);
796 if (ref == 0) {
797 if (This->pStream) IStream_Release(This->pStream);
798 HeapFree(GetProcessHeap(), 0, This);
800 return ref;
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, %lu, %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, %lu, %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, %ld, %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, %#lx)\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, %ld)\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, %ld)\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, %#lx)\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,
906 IStream **ppstm)
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);
918 HRESULT hr = S_OK;
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;
934 return hr;
937 static HRESULT WINAPI IWICStreamImpl_InitializeFromFilename(IWICStream *iface,
938 LPCWSTR wzFileName, DWORD dwDesiredAccess)
940 IWICStreamImpl *This = impl_from_IWICStream(iface);
941 HRESULT hr;
942 DWORD dwMode;
943 IStream *stream;
945 TRACE("(%p, %s, %lu)\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;
953 else
954 return E_INVALIDARG;
956 hr = SHCreateStreamOnFileW(wzFileName, dwMode, &stream);
958 if (SUCCEEDED(hr))
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;
968 return hr;
971 /******************************************
972 * IWICStream_InitializeFromMemory
974 * Initializes the internal IStream object to retrieve its data from a memory chunk.
976 * PARAMS
977 * pbBuffer [I] pointer to the memory chunk
978 * cbBufferSize [I] number of bytes to use from the memory chunk
980 * RETURNS
981 * SUCCESS: S_OK
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, %lu)\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;
1001 pObject->ref = 1;
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;
1015 return S_OK;
1018 static HRESULT map_file(HANDLE file, HANDLE *map, void **mem, LARGE_INTEGER *size)
1020 *map = NULL;
1021 if (!GetFileSizeEx(file, size)) return HRESULT_FROM_WIN32(GetLastError());
1022 if (size->u.HighPart)
1024 WARN("file too large\n");
1025 return E_FAIL;
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)))
1033 CloseHandle(*map);
1034 return HRESULT_FROM_WIN32(GetLastError());
1036 return S_OK;
1039 HRESULT stream_initialize_from_filehandle(IWICStream *iface, HANDLE file)
1041 IWICStreamImpl *This = impl_from_IWICStream(iface);
1042 StreamOnFileHandle *pObject;
1043 IWICStream *stream = NULL;
1044 HANDLE map;
1045 void *mem;
1046 LARGE_INTEGER size;
1047 HRESULT hr;
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));
1062 if (!pObject)
1064 hr = E_OUTOFMEMORY;
1065 goto error;
1067 pObject->IStream_iface.lpVtbl = &StreamOnFileHandle_Vtbl;
1068 pObject->ref = 1;
1069 pObject->map = map;
1070 pObject->mem = mem;
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;
1079 return S_OK;
1081 error:
1082 if (stream) IWICStream_Release(stream);
1083 UnmapViewOfFile(mem);
1084 CloseHandle(map);
1085 return hr;
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;
1104 pObject->ref = 1;
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;
1120 return S_OK;
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));
1157 if( !pObject ) {
1158 *stream = NULL;
1159 return E_OUTOFMEMORY;
1162 pObject->IWICStream_iface.lpVtbl = &WICStream_Vtbl;
1163 pObject->ref = 1;
1164 pObject->pStream = NULL;
1166 *stream = &pObject->IWICStream_iface;
1168 return S_OK;