winspool: Remove unused code.
[wine] / dlls / windowscodecs / stream.c
1 /*
2  * Copyright 2009 Tony Wasserka
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include "wine/debug.h"
20
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"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
31
32 /******************************************
33  * StreamOnMemory implementation
34  *
35  * Used by IWICStream_InitializeFromMemory
36  *
37  */
38 typedef struct StreamOnMemory {
39     const IStreamVtbl *lpVtbl;
40     LONG ref;
41
42     BYTE *pbMemory;
43     DWORD dwMemsize;
44     DWORD dwCurPos;
45
46     CRITICAL_SECTION lock; /* must be held when pbMemory or dwCurPos is accessed */
47 } StreamOnMemory;
48
49 static HRESULT WINAPI StreamOnMemory_QueryInterface(IStream *iface,
50     REFIID iid, void **ppv)
51 {
52     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
53
54     if (!ppv) return E_INVALIDARG;
55
56     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) ||
57         IsEqualIID(&IID_ISequentialStream, iid))
58     {
59         *ppv = iface;
60         IUnknown_AddRef((IUnknown*)*ppv);
61         return S_OK;
62     }
63     else
64     {
65         *ppv = NULL;
66         return E_NOINTERFACE;
67     }
68 }
69
70 static ULONG WINAPI StreamOnMemory_AddRef(IStream *iface)
71 {
72     StreamOnMemory *This = (StreamOnMemory*)iface;
73     ULONG ref = InterlockedIncrement(&This->ref);
74
75     TRACE("(%p) refcount=%u\n", iface, ref);
76
77     return ref;
78 }
79
80 static ULONG WINAPI StreamOnMemory_Release(IStream *iface)
81 {
82     StreamOnMemory *This = (StreamOnMemory*)iface;
83     ULONG ref = InterlockedDecrement(&This->ref);
84
85     TRACE("(%p) refcount=%u\n", iface, ref);
86
87     if (ref == 0) {
88         This->lock.DebugInfo->Spare[0] = 0;
89         DeleteCriticalSection(&This->lock);
90         HeapFree(GetProcessHeap(), 0, This);
91     }
92     return ref;
93 }
94
95 static HRESULT WINAPI StreamOnMemory_Read(IStream *iface,
96     void *pv, ULONG cb, ULONG *pcbRead)
97 {
98     StreamOnMemory *This = (StreamOnMemory*)iface;
99     ULONG uBytesRead;
100     TRACE("(%p)\n", This);
101
102     if (!pv) return E_INVALIDARG;
103
104     EnterCriticalSection(&This->lock);
105     uBytesRead = min(cb, This->dwMemsize - This->dwCurPos);
106     memcpy(pv, This->pbMemory + This->dwCurPos, uBytesRead);
107     This->dwCurPos += uBytesRead;
108     LeaveCriticalSection(&This->lock);
109
110     if (pcbRead) *pcbRead = uBytesRead;
111
112     return S_OK;
113 }
114
115 static HRESULT WINAPI StreamOnMemory_Write(IStream *iface,
116     void const *pv, ULONG cb, ULONG *pcbWritten)
117 {
118     StreamOnMemory *This = (StreamOnMemory*)iface;
119     HRESULT hr;
120     TRACE("(%p)\n", This);
121
122     if (!pv) return E_INVALIDARG;
123
124     EnterCriticalSection(&This->lock);
125     if (cb > This->dwMemsize - This->dwCurPos) {
126         hr = STG_E_MEDIUMFULL;
127     }
128     else {
129         memcpy(This->pbMemory + This->dwCurPos, pv, cb);
130         This->dwCurPos += cb;
131         hr = S_OK;
132         if (pcbWritten) *pcbWritten = cb;
133     }
134     LeaveCriticalSection(&This->lock);
135
136     return hr;
137 }
138
139 static HRESULT WINAPI StreamOnMemory_Seek(IStream *iface,
140     LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
141 {
142     StreamOnMemory *This = (StreamOnMemory*)iface;
143     LARGE_INTEGER NewPosition;
144     HRESULT hr=S_OK;
145     TRACE("(%p)\n", This);
146
147     EnterCriticalSection(&This->lock);
148     if (dwOrigin == STREAM_SEEK_SET) NewPosition.QuadPart = dlibMove.QuadPart;
149     else if (dwOrigin == STREAM_SEEK_CUR) NewPosition.QuadPart = This->dwCurPos + dlibMove.QuadPart;
150     else if (dwOrigin == STREAM_SEEK_END) NewPosition.QuadPart = This->dwMemsize + dlibMove.QuadPart;
151     else hr = E_INVALIDARG;
152
153     if (SUCCEEDED(hr)) {
154         if (NewPosition.u.HighPart) hr = HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
155         else if (NewPosition.QuadPart > This->dwMemsize) hr = E_INVALIDARG;
156         else if (NewPosition.QuadPart < 0) hr = E_INVALIDARG;
157     }
158
159     if (SUCCEEDED(hr)) {
160         This->dwCurPos = NewPosition.u.LowPart;
161
162         if(plibNewPosition) plibNewPosition->QuadPart = This->dwCurPos;
163     }
164     LeaveCriticalSection(&This->lock);
165
166     return hr;
167 }
168
169 /* SetSize isn't implemented in the native windowscodecs DLL either */
170 static HRESULT WINAPI StreamOnMemory_SetSize(IStream *iface,
171     ULARGE_INTEGER libNewSize)
172 {
173     TRACE("(%p)\n", iface);
174     return E_NOTIMPL;
175 }
176
177 /* CopyTo isn't implemented in the native windowscodecs DLL either */
178 static HRESULT WINAPI StreamOnMemory_CopyTo(IStream *iface,
179     IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
180 {
181     TRACE("(%p)\n", iface);
182     return E_NOTIMPL;
183 }
184
185 /* Commit isn't implemented in the native windowscodecs DLL either */
186 static HRESULT WINAPI StreamOnMemory_Commit(IStream *iface,
187     DWORD grfCommitFlags)
188 {
189     TRACE("(%p)\n", iface);
190     return E_NOTIMPL;
191 }
192
193 /* Revert isn't implemented in the native windowscodecs DLL either */
194 static HRESULT WINAPI StreamOnMemory_Revert(IStream *iface)
195 {
196     TRACE("(%p)\n", iface);
197     return E_NOTIMPL;
198 }
199
200 /* LockRegion isn't implemented in the native windowscodecs DLL either */
201 static HRESULT WINAPI StreamOnMemory_LockRegion(IStream *iface,
202     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
203 {
204     TRACE("(%p)\n", iface);
205     return E_NOTIMPL;
206 }
207
208 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */
209 static HRESULT WINAPI StreamOnMemory_UnlockRegion(IStream *iface,
210     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
211 {
212     TRACE("(%p)\n", iface);
213     return E_NOTIMPL;
214 }
215
216 static HRESULT WINAPI StreamOnMemory_Stat(IStream *iface,
217     STATSTG *pstatstg, DWORD grfStatFlag)
218 {
219     StreamOnMemory *This = (StreamOnMemory*)iface;
220     TRACE("(%p)\n", This);
221
222     if (!pstatstg) return E_INVALIDARG;
223
224     ZeroMemory(pstatstg, sizeof(STATSTG));
225     pstatstg->type = STGTY_STREAM;
226     pstatstg->cbSize.QuadPart = This->dwMemsize;
227
228     return S_OK;
229 }
230
231 /* Clone isn't implemented in the native windowscodecs DLL either */
232 static HRESULT WINAPI StreamOnMemory_Clone(IStream *iface,
233     IStream **ppstm)
234 {
235     TRACE("(%p)\n", iface);
236     return E_NOTIMPL;
237 }
238
239
240 const IStreamVtbl StreamOnMemory_Vtbl =
241 {
242     /*** IUnknown methods ***/
243     StreamOnMemory_QueryInterface,
244     StreamOnMemory_AddRef,
245     StreamOnMemory_Release,
246     /*** ISequentialStream methods ***/
247     StreamOnMemory_Read,
248     StreamOnMemory_Write,
249     /*** IStream methods ***/
250     StreamOnMemory_Seek,
251     StreamOnMemory_SetSize,
252     StreamOnMemory_CopyTo,
253     StreamOnMemory_Commit,
254     StreamOnMemory_Revert,
255     StreamOnMemory_LockRegion,
256     StreamOnMemory_UnlockRegion,
257     StreamOnMemory_Stat,
258     StreamOnMemory_Clone,
259 };
260
261 /******************************************
262  * StreamOnStreamRange implementation
263  *
264  * Used by IWICStream_InitializeFromIStreamRegion
265  *
266  */
267 typedef struct StreamOnStreamRange {
268     const IStreamVtbl *lpVtbl;
269     LONG ref;
270
271     IStream *stream;
272     ULARGE_INTEGER pos;
273     ULARGE_INTEGER offset;
274     ULARGE_INTEGER max_size;
275
276     CRITICAL_SECTION lock;
277 } StreamOnStreamRange;
278
279 static HRESULT WINAPI StreamOnStreamRange_QueryInterface(IStream *iface,
280     REFIID iid, void **ppv)
281 {
282     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
283
284     if (!ppv) return E_INVALIDARG;
285
286     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) ||
287         IsEqualIID(&IID_ISequentialStream, iid))
288     {
289         *ppv = iface;
290         IUnknown_AddRef((IUnknown*)*ppv);
291         return S_OK;
292     }
293     else
294     {
295         *ppv = NULL;
296         return E_NOINTERFACE;
297     }
298 }
299
300 static ULONG WINAPI StreamOnStreamRange_AddRef(IStream *iface)
301 {
302     StreamOnStreamRange *This = (StreamOnStreamRange*)iface;
303     ULONG ref = InterlockedIncrement(&This->ref);
304
305     TRACE("(%p) refcount=%u\n", iface, ref);
306
307     return ref;
308 }
309
310 static ULONG WINAPI StreamOnStreamRange_Release(IStream *iface)
311 {
312     StreamOnStreamRange *This = (StreamOnStreamRange*)iface;
313     ULONG ref = InterlockedDecrement(&This->ref);
314
315     TRACE("(%p) refcount=%u\n", iface, ref);
316
317     if (ref == 0) {
318         This->lock.DebugInfo->Spare[0] = 0;
319         DeleteCriticalSection(&This->lock);
320         IStream_Release(This->stream);
321         HeapFree(GetProcessHeap(), 0, This);
322     }
323     return ref;
324 }
325
326 static HRESULT WINAPI StreamOnStreamRange_Read(IStream *iface,
327     void *pv, ULONG cb, ULONG *pcbRead)
328 {
329     StreamOnStreamRange *This = (StreamOnStreamRange*)iface;
330     ULONG uBytesRead=0;
331     HRESULT hr;
332     ULARGE_INTEGER OldPosition;
333     LARGE_INTEGER SetPosition;
334     TRACE("(%p)\n", This);
335
336     if (!pv) return E_INVALIDARG;
337
338     EnterCriticalSection(&This->lock);
339     SetPosition.QuadPart = 0;
340     hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_CUR, &OldPosition);
341     if (SUCCEEDED(hr))
342     {
343         SetPosition.QuadPart = This->pos.QuadPart + This->offset.QuadPart;
344         hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL);
345     }
346     if (SUCCEEDED(hr))
347     {
348         if (This->pos.QuadPart + cb > This->max_size.QuadPart)
349         {
350             /* This would read past the end of the stream. */
351             if (This->pos.QuadPart > This->max_size.QuadPart)
352                 cb = 0;
353             else
354                 cb = This->max_size.QuadPart - This->pos.QuadPart;
355         }
356         hr = IStream_Read(This->stream, pv, cb, &uBytesRead);
357         SetPosition.QuadPart = OldPosition.QuadPart;
358         IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL);
359     }
360     if (SUCCEEDED(hr))
361         This->pos.QuadPart += uBytesRead;
362     LeaveCriticalSection(&This->lock);
363
364     if (pcbRead) *pcbRead = uBytesRead;
365
366     return hr;
367 }
368
369 static HRESULT WINAPI StreamOnStreamRange_Write(IStream *iface,
370     void const *pv, ULONG cb, ULONG *pcbWritten)
371 {
372     StreamOnStreamRange *This = (StreamOnStreamRange*)iface;
373     HRESULT hr;
374     ULARGE_INTEGER OldPosition;
375     LARGE_INTEGER SetPosition;
376     ULONG uBytesWritten=0;
377     TRACE("(%p)\n", This);
378
379     if (!pv) return E_INVALIDARG;
380
381     EnterCriticalSection(&This->lock);
382     SetPosition.QuadPart = 0;
383     hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_CUR, &OldPosition);
384     if (SUCCEEDED(hr))
385     {
386         SetPosition.QuadPart = This->pos.QuadPart + This->offset.QuadPart;
387         hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL);
388     }
389     if (SUCCEEDED(hr))
390     {
391         if (This->pos.QuadPart + cb > This->max_size.QuadPart)
392         {
393             /* This would read past the end of the stream. */
394             if (This->pos.QuadPart > This->max_size.QuadPart)
395                 cb = 0;
396             else
397                 cb = This->max_size.QuadPart - This->pos.QuadPart;
398         }
399         hr = IStream_Write(This->stream, pv, cb, &uBytesWritten);
400         SetPosition.QuadPart = OldPosition.QuadPart;
401         IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL);
402     }
403     if (SUCCEEDED(hr))
404         This->pos.QuadPart += uBytesWritten;
405     LeaveCriticalSection(&This->lock);
406
407     if (pcbWritten) *pcbWritten = uBytesWritten;
408
409     return hr;
410 }
411
412 static HRESULT WINAPI StreamOnStreamRange_Seek(IStream *iface,
413     LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
414 {
415     StreamOnStreamRange *This = (StreamOnStreamRange*)iface;
416     ULARGE_INTEGER NewPosition, actual_size;
417     HRESULT hr=S_OK;
418     STATSTG statstg;
419     TRACE("(%p)\n", This);
420
421     EnterCriticalSection(&This->lock);
422     actual_size = This->max_size;
423     if (dwOrigin == STREAM_SEEK_SET)
424         NewPosition.QuadPart = dlibMove.QuadPart;
425     else if (dwOrigin == STREAM_SEEK_CUR)
426         NewPosition.QuadPart = This->pos.QuadPart + dlibMove.QuadPart;
427     else if (dwOrigin == STREAM_SEEK_END)
428     {
429         hr = IStream_Stat(This->stream, &statstg, STATFLAG_NONAME);
430         if (SUCCEEDED(hr))
431         {
432             if (This->max_size.QuadPart + This->offset.QuadPart > statstg.cbSize.QuadPart)
433                 actual_size.QuadPart = statstg.cbSize.QuadPart - This->offset.QuadPart;
434             NewPosition.QuadPart = dlibMove.QuadPart + actual_size.QuadPart;
435         }
436     }
437     else hr = E_INVALIDARG;
438
439     if (SUCCEEDED(hr) && (NewPosition.u.HighPart != 0 || NewPosition.QuadPart > actual_size.QuadPart))
440         hr = WINCODEC_ERR_VALUEOUTOFRANGE;
441
442     if (SUCCEEDED(hr)) {
443         This->pos.QuadPart = NewPosition.QuadPart;
444
445         if(plibNewPosition) plibNewPosition->QuadPart = This->pos.QuadPart;
446     }
447     LeaveCriticalSection(&This->lock);
448
449     return hr;
450 }
451
452 /* SetSize isn't implemented in the native windowscodecs DLL either */
453 static HRESULT WINAPI StreamOnStreamRange_SetSize(IStream *iface,
454     ULARGE_INTEGER libNewSize)
455 {
456     TRACE("(%p)\n", iface);
457     return E_NOTIMPL;
458 }
459
460 /* CopyTo isn't implemented in the native windowscodecs DLL either */
461 static HRESULT WINAPI StreamOnStreamRange_CopyTo(IStream *iface,
462     IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
463 {
464     TRACE("(%p)\n", iface);
465     return E_NOTIMPL;
466 }
467
468 /* Commit isn't implemented in the native windowscodecs DLL either */
469 static HRESULT WINAPI StreamOnStreamRange_Commit(IStream *iface,
470     DWORD grfCommitFlags)
471 {
472     TRACE("(%p)\n", iface);
473     return E_NOTIMPL;
474 }
475
476 /* Revert isn't implemented in the native windowscodecs DLL either */
477 static HRESULT WINAPI StreamOnStreamRange_Revert(IStream *iface)
478 {
479     TRACE("(%p)\n", iface);
480     return E_NOTIMPL;
481 }
482
483 /* LockRegion isn't implemented in the native windowscodecs DLL either */
484 static HRESULT WINAPI StreamOnStreamRange_LockRegion(IStream *iface,
485     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
486 {
487     TRACE("(%p)\n", iface);
488     return E_NOTIMPL;
489 }
490
491 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */
492 static HRESULT WINAPI StreamOnStreamRange_UnlockRegion(IStream *iface,
493     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
494 {
495     TRACE("(%p)\n", iface);
496     return E_NOTIMPL;
497 }
498
499 static HRESULT WINAPI StreamOnStreamRange_Stat(IStream *iface,
500     STATSTG *pstatstg, DWORD grfStatFlag)
501 {
502     StreamOnStreamRange *This = (StreamOnStreamRange*)iface;
503     HRESULT hr;
504     TRACE("(%p)\n", This);
505
506     if (!pstatstg) return E_INVALIDARG;
507
508     EnterCriticalSection(&This->lock);
509     hr = IStream_Stat(This->stream, pstatstg, grfStatFlag);
510     if (SUCCEEDED(hr))
511     {
512         pstatstg->cbSize.QuadPart -= This->offset.QuadPart;
513         if (This->max_size.QuadPart < pstatstg->cbSize.QuadPart)
514             pstatstg->cbSize.QuadPart = This->max_size.QuadPart;
515     }
516
517     LeaveCriticalSection(&This->lock);
518
519     return hr;
520 }
521
522 /* Clone isn't implemented in the native windowscodecs DLL either */
523 static HRESULT WINAPI StreamOnStreamRange_Clone(IStream *iface,
524     IStream **ppstm)
525 {
526     TRACE("(%p)\n", iface);
527     return E_NOTIMPL;
528 }
529
530
531 const IStreamVtbl StreamOnStreamRange_Vtbl =
532 {
533     /*** IUnknown methods ***/
534     StreamOnStreamRange_QueryInterface,
535     StreamOnStreamRange_AddRef,
536     StreamOnStreamRange_Release,
537     /*** ISequentialStream methods ***/
538     StreamOnStreamRange_Read,
539     StreamOnStreamRange_Write,
540     /*** IStream methods ***/
541     StreamOnStreamRange_Seek,
542     StreamOnStreamRange_SetSize,
543     StreamOnStreamRange_CopyTo,
544     StreamOnStreamRange_Commit,
545     StreamOnStreamRange_Revert,
546     StreamOnStreamRange_LockRegion,
547     StreamOnStreamRange_UnlockRegion,
548     StreamOnStreamRange_Stat,
549     StreamOnStreamRange_Clone,
550 };
551
552
553 /******************************************
554  * IWICStream implementation
555  *
556  */
557 typedef struct IWICStreamImpl
558 {
559     const IWICStreamVtbl *lpVtbl;
560     LONG ref;
561
562     IStream *pStream;
563 } IWICStreamImpl;
564
565 static HRESULT WINAPI IWICStreamImpl_QueryInterface(IWICStream *iface,
566     REFIID iid, void **ppv)
567 {
568     IWICStreamImpl *This = (IWICStreamImpl*)iface;
569     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
570
571     if (!ppv) return E_INVALIDARG;
572
573     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) ||
574         IsEqualIID(&IID_ISequentialStream, iid) || IsEqualIID(&IID_IWICStream, iid))
575     {
576         *ppv = This;
577         IUnknown_AddRef((IUnknown*)*ppv);
578         return S_OK;
579     }
580     else
581     {
582         *ppv = NULL;
583         return E_NOINTERFACE;
584     }
585 }
586
587 static ULONG WINAPI IWICStreamImpl_AddRef(IWICStream *iface)
588 {
589     IWICStreamImpl *This = (IWICStreamImpl*)iface;
590     ULONG ref = InterlockedIncrement(&This->ref);
591
592     TRACE("(%p) refcount=%u\n", iface, ref);
593
594     return ref;
595 }
596
597 static ULONG WINAPI IWICStreamImpl_Release(IWICStream *iface)
598 {
599     IWICStreamImpl *This = (IWICStreamImpl*)iface;
600     ULONG ref = InterlockedDecrement(&This->ref);
601
602     TRACE("(%p) refcount=%u\n", iface, ref);
603
604     if (ref == 0) {
605         if (This->pStream) IStream_Release(This->pStream);
606         HeapFree(GetProcessHeap(), 0, This);
607     }
608     return ref;
609 }
610
611 static HRESULT WINAPI IWICStreamImpl_Read(IWICStream *iface,
612     void *pv, ULONG cb, ULONG *pcbRead)
613 {
614     IWICStreamImpl *This = (IWICStreamImpl*)iface;
615     TRACE("(%p): relay\n", This);
616
617     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
618     return IStream_Read(This->pStream, pv, cb, pcbRead);
619 }
620
621 static HRESULT WINAPI IWICStreamImpl_Write(IWICStream *iface,
622     void const *pv, ULONG cb, ULONG *pcbWritten)
623 {
624     IWICStreamImpl *This = (IWICStreamImpl*)iface;
625     TRACE("(%p): relay\n", This);
626
627     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
628     return IStream_Write(This->pStream, pv, cb, pcbWritten);
629 }
630
631 static HRESULT WINAPI IWICStreamImpl_Seek(IWICStream *iface,
632     LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
633 {
634     IWICStreamImpl *This = (IWICStreamImpl*)iface;
635     TRACE("(%p): relay\n", This);
636
637     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
638     return IStream_Seek(This->pStream, dlibMove, dwOrigin, plibNewPosition);
639 }
640
641 static HRESULT WINAPI IWICStreamImpl_SetSize(IWICStream *iface,
642     ULARGE_INTEGER libNewSize)
643 {
644     IWICStreamImpl *This = (IWICStreamImpl*)iface;
645     TRACE("(%p): relay\n", This);
646
647     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
648     return IStream_SetSize(This->pStream, libNewSize);
649 }
650
651 static HRESULT WINAPI IWICStreamImpl_CopyTo(IWICStream *iface,
652     IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
653 {
654     IWICStreamImpl *This = (IWICStreamImpl*)iface;
655     TRACE("(%p): relay\n", This);
656
657     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
658     return IStream_CopyTo(This->pStream, pstm, cb, pcbRead, pcbWritten);
659 }
660
661 static HRESULT WINAPI IWICStreamImpl_Commit(IWICStream *iface,
662     DWORD grfCommitFlags)
663 {
664     IWICStreamImpl *This = (IWICStreamImpl*)iface;
665     TRACE("(%p): relay\n", This);
666
667     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
668     return IStream_Commit(This->pStream, grfCommitFlags);
669 }
670
671 static HRESULT WINAPI IWICStreamImpl_Revert(IWICStream *iface)
672 {
673     IWICStreamImpl *This = (IWICStreamImpl*)iface;
674     TRACE("(%p): relay\n", This);
675
676     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
677     return IStream_Revert(This->pStream);
678 }
679
680 static HRESULT WINAPI IWICStreamImpl_LockRegion(IWICStream *iface,
681     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
682 {
683     IWICStreamImpl *This = (IWICStreamImpl*)iface;
684     TRACE("(%p): relay\n", This);
685
686     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
687     return IStream_LockRegion(This->pStream, libOffset, cb, dwLockType);
688 }
689
690 static HRESULT WINAPI IWICStreamImpl_UnlockRegion(IWICStream *iface,
691     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
692 {
693     IWICStreamImpl *This = (IWICStreamImpl*)iface;
694     TRACE("(%p): relay\n", This);
695
696     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
697     return IStream_UnlockRegion(This->pStream, libOffset, cb, dwLockType);
698 }
699
700 static HRESULT WINAPI IWICStreamImpl_Stat(IWICStream *iface,
701     STATSTG *pstatstg, DWORD grfStatFlag)
702 {
703     IWICStreamImpl *This = (IWICStreamImpl*)iface;
704     TRACE("(%p): relay\n", This);
705
706     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
707     return IStream_Stat(This->pStream, pstatstg, grfStatFlag);
708 }
709
710 static HRESULT WINAPI IWICStreamImpl_Clone(IWICStream *iface,
711     IStream **ppstm)
712 {
713     IWICStreamImpl *This = (IWICStreamImpl*)iface;
714     TRACE("(%p): relay\n", This);
715
716     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
717     return IStream_Clone(This->pStream, ppstm);
718 }
719
720 static HRESULT WINAPI IWICStreamImpl_InitializeFromIStream(IWICStream *iface,
721     IStream *pIStream)
722 {
723     FIXME("(%p): stub\n", iface);
724     return E_NOTIMPL;
725 }
726
727 static HRESULT WINAPI IWICStreamImpl_InitializeFromFilename(IWICStream *iface,
728     LPCWSTR wzFileName, DWORD dwDesiredAccess)
729 {
730     IWICStreamImpl *This = (IWICStreamImpl*)iface;
731     HRESULT hr;
732     DWORD dwMode;
733     IStream *stream;
734
735     TRACE("(%p, %s, %u)\n", iface, debugstr_w(wzFileName), dwDesiredAccess);
736
737     if (This->pStream) return WINCODEC_ERR_WRONGSTATE;
738
739     if(dwDesiredAccess & GENERIC_WRITE)
740         dwMode = STGM_SHARE_DENY_WRITE | STGM_WRITE | STGM_CREATE;
741     else if(dwDesiredAccess & GENERIC_READ)
742         dwMode = STGM_SHARE_DENY_WRITE | STGM_READ | STGM_FAILIFTHERE;
743     else
744         return E_INVALIDARG;
745
746     hr = SHCreateStreamOnFileW(wzFileName, dwMode, &stream);
747
748     if (SUCCEEDED(hr))
749     {
750         if (InterlockedCompareExchangePointer((void**)&This->pStream, stream, NULL))
751         {
752             /* Some other thread set the stream first. */
753             IStream_Release(stream);
754             hr = WINCODEC_ERR_WRONGSTATE;
755         }
756     }
757
758     return hr;
759 }
760
761 /******************************************
762  * IWICStream_InitializeFromMemory
763  *
764  * Initializes the internal IStream object to retrieve its data from a memory chunk.
765  *
766  * PARAMS
767  *   pbBuffer     [I] pointer to the memory chunk
768  *   cbBufferSize [I] number of bytes to use from the memory chunk
769  *
770  * RETURNS
771  *   SUCCESS: S_OK
772  *   FAILURE: E_INVALIDARG, if pbBuffer is NULL
773  *            E_OUTOFMEMORY, if we run out of memory
774  *            WINCODEC_ERR_WRONGSTATE, if the IStream object has already been initialized before
775  *
776  */
777 static HRESULT WINAPI IWICStreamImpl_InitializeFromMemory(IWICStream *iface,
778     BYTE *pbBuffer, DWORD cbBufferSize)
779 {
780     IWICStreamImpl *This = (IWICStreamImpl*)iface;
781     StreamOnMemory *pObject;
782     TRACE("(%p,%p)\n", iface, pbBuffer);
783
784     if (!pbBuffer) return E_INVALIDARG;
785     if (This->pStream) return WINCODEC_ERR_WRONGSTATE;
786
787     pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnMemory));
788     if (!pObject) return E_OUTOFMEMORY;
789
790     pObject->lpVtbl = &StreamOnMemory_Vtbl;
791     pObject->ref = 1;
792     pObject->pbMemory = pbBuffer;
793     pObject->dwMemsize = cbBufferSize;
794     pObject->dwCurPos = 0;
795     InitializeCriticalSection(&pObject->lock);
796     pObject->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": StreamOnMemory.lock");
797
798     if (InterlockedCompareExchangePointer((void**)&This->pStream, pObject, NULL))
799     {
800         /* Some other thread set the stream first. */
801         IStream_Release((IStream*)pObject);
802         return WINCODEC_ERR_WRONGSTATE;
803     }
804
805     return S_OK;
806 }
807
808 static HRESULT WINAPI IWICStreamImpl_InitializeFromIStreamRegion(IWICStream *iface,
809     IStream *pIStream, ULARGE_INTEGER ulOffset, ULARGE_INTEGER ulMaxSize)
810 {
811     IWICStreamImpl *This = (IWICStreamImpl*)iface;
812     StreamOnStreamRange *pObject;
813     TRACE("(%p,%p)\n", iface, pIStream);
814
815     if (!pIStream) return E_INVALIDARG;
816     if (This->pStream) return WINCODEC_ERR_WRONGSTATE;
817
818     pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnStreamRange));
819     if (!pObject) return E_OUTOFMEMORY;
820
821     pObject->lpVtbl = &StreamOnStreamRange_Vtbl;
822     pObject->ref = 1;
823     IStream_AddRef(pIStream);
824     pObject->stream = pIStream;
825     pObject->pos.QuadPart = 0;
826     pObject->offset = ulOffset;
827     pObject->max_size = ulMaxSize;
828     InitializeCriticalSection(&pObject->lock);
829     pObject->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": StreamOnStreamRange.lock");
830
831     if (InterlockedCompareExchangePointer((void**)&This->pStream, pObject, NULL))
832     {
833         /* Some other thread set the stream first. */
834         IStream_Release((IStream*)pObject);
835         return WINCODEC_ERR_WRONGSTATE;
836     }
837
838     return S_OK;
839 }
840
841
842 const IWICStreamVtbl WICStream_Vtbl =
843 {
844     /*** IUnknown methods ***/
845     IWICStreamImpl_QueryInterface,
846     IWICStreamImpl_AddRef,
847     IWICStreamImpl_Release,
848     /*** ISequentialStream methods ***/
849     IWICStreamImpl_Read,
850     IWICStreamImpl_Write,
851     /*** IStream methods ***/
852     IWICStreamImpl_Seek,
853     IWICStreamImpl_SetSize,
854     IWICStreamImpl_CopyTo,
855     IWICStreamImpl_Commit,
856     IWICStreamImpl_Revert,
857     IWICStreamImpl_LockRegion,
858     IWICStreamImpl_UnlockRegion,
859     IWICStreamImpl_Stat,
860     IWICStreamImpl_Clone,
861     /*** IWICStream methods ***/
862     IWICStreamImpl_InitializeFromIStream,
863     IWICStreamImpl_InitializeFromFilename,
864     IWICStreamImpl_InitializeFromMemory,
865     IWICStreamImpl_InitializeFromIStreamRegion,
866 };
867
868 HRESULT StreamImpl_Create(IWICStream **stream)
869 {
870     IWICStreamImpl *pObject;
871
872     if( !stream ) return E_INVALIDARG;
873
874     pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(IWICStreamImpl));
875     if( !pObject ) {
876         *stream = NULL;
877         return E_OUTOFMEMORY;
878     }
879
880     pObject->lpVtbl = &WICStream_Vtbl;
881     pObject->ref = 1;
882     pObject->pStream = NULL;
883
884     *stream = (IWICStream*)pObject;
885
886     return S_OK;
887 }