imm32: Retrieve the graphics driver module from gdi32.
[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     IStream IStream_iface;
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 inline StreamOnMemory *StreamOnMemory_from_IStream(IStream *iface)
50 {
51     return CONTAINING_RECORD(iface, StreamOnMemory, IStream_iface);
52 }
53
54 static HRESULT WINAPI StreamOnMemory_QueryInterface(IStream *iface,
55     REFIID iid, void **ppv)
56 {
57     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
58
59     if (!ppv) return E_INVALIDARG;
60
61     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) ||
62         IsEqualIID(&IID_ISequentialStream, iid))
63     {
64         *ppv = iface;
65         IUnknown_AddRef((IUnknown*)*ppv);
66         return S_OK;
67     }
68     else
69     {
70         *ppv = NULL;
71         return E_NOINTERFACE;
72     }
73 }
74
75 static ULONG WINAPI StreamOnMemory_AddRef(IStream *iface)
76 {
77     StreamOnMemory *This = StreamOnMemory_from_IStream(iface);
78     ULONG ref = InterlockedIncrement(&This->ref);
79
80     TRACE("(%p) refcount=%u\n", iface, ref);
81
82     return ref;
83 }
84
85 static ULONG WINAPI StreamOnMemory_Release(IStream *iface)
86 {
87     StreamOnMemory *This = StreamOnMemory_from_IStream(iface);
88     ULONG ref = InterlockedDecrement(&This->ref);
89
90     TRACE("(%p) refcount=%u\n", iface, ref);
91
92     if (ref == 0) {
93         This->lock.DebugInfo->Spare[0] = 0;
94         DeleteCriticalSection(&This->lock);
95         HeapFree(GetProcessHeap(), 0, This);
96     }
97     return ref;
98 }
99
100 static HRESULT WINAPI StreamOnMemory_Read(IStream *iface,
101     void *pv, ULONG cb, ULONG *pcbRead)
102 {
103     StreamOnMemory *This = StreamOnMemory_from_IStream(iface);
104     ULONG uBytesRead;
105     TRACE("(%p)\n", This);
106
107     if (!pv) return E_INVALIDARG;
108
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);
114
115     if (pcbRead) *pcbRead = uBytesRead;
116
117     return S_OK;
118 }
119
120 static HRESULT WINAPI StreamOnMemory_Write(IStream *iface,
121     void const *pv, ULONG cb, ULONG *pcbWritten)
122 {
123     StreamOnMemory *This = StreamOnMemory_from_IStream(iface);
124     HRESULT hr;
125     TRACE("(%p)\n", This);
126
127     if (!pv) return E_INVALIDARG;
128
129     EnterCriticalSection(&This->lock);
130     if (cb > This->dwMemsize - This->dwCurPos) {
131         hr = STG_E_MEDIUMFULL;
132     }
133     else {
134         memmove(This->pbMemory + This->dwCurPos, pv, cb);
135         This->dwCurPos += cb;
136         hr = S_OK;
137         if (pcbWritten) *pcbWritten = cb;
138     }
139     LeaveCriticalSection(&This->lock);
140
141     return hr;
142 }
143
144 static HRESULT WINAPI StreamOnMemory_Seek(IStream *iface,
145     LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
146 {
147     StreamOnMemory *This = StreamOnMemory_from_IStream(iface);
148     LARGE_INTEGER NewPosition;
149     HRESULT hr=S_OK;
150     TRACE("(%p)\n", This);
151
152     EnterCriticalSection(&This->lock);
153     if (dwOrigin == STREAM_SEEK_SET) NewPosition.QuadPart = dlibMove.QuadPart;
154     else if (dwOrigin == STREAM_SEEK_CUR) NewPosition.QuadPart = This->dwCurPos + dlibMove.QuadPart;
155     else if (dwOrigin == STREAM_SEEK_END) NewPosition.QuadPart = This->dwMemsize + dlibMove.QuadPart;
156     else hr = E_INVALIDARG;
157
158     if (SUCCEEDED(hr)) {
159         if (NewPosition.u.HighPart) hr = HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
160         else if (NewPosition.QuadPart > This->dwMemsize) hr = E_INVALIDARG;
161         else if (NewPosition.QuadPart < 0) hr = E_INVALIDARG;
162     }
163
164     if (SUCCEEDED(hr)) {
165         This->dwCurPos = NewPosition.u.LowPart;
166
167         if(plibNewPosition) plibNewPosition->QuadPart = This->dwCurPos;
168     }
169     LeaveCriticalSection(&This->lock);
170
171     return hr;
172 }
173
174 /* SetSize isn't implemented in the native windowscodecs DLL either */
175 static HRESULT WINAPI StreamOnMemory_SetSize(IStream *iface,
176     ULARGE_INTEGER libNewSize)
177 {
178     TRACE("(%p)\n", iface);
179     return E_NOTIMPL;
180 }
181
182 /* CopyTo isn't implemented in the native windowscodecs DLL either */
183 static HRESULT WINAPI StreamOnMemory_CopyTo(IStream *iface,
184     IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
185 {
186     TRACE("(%p)\n", iface);
187     return E_NOTIMPL;
188 }
189
190 /* Commit isn't implemented in the native windowscodecs DLL either */
191 static HRESULT WINAPI StreamOnMemory_Commit(IStream *iface,
192     DWORD grfCommitFlags)
193 {
194     TRACE("(%p)\n", iface);
195     return E_NOTIMPL;
196 }
197
198 /* Revert isn't implemented in the native windowscodecs DLL either */
199 static HRESULT WINAPI StreamOnMemory_Revert(IStream *iface)
200 {
201     TRACE("(%p)\n", iface);
202     return E_NOTIMPL;
203 }
204
205 /* LockRegion isn't implemented in the native windowscodecs DLL either */
206 static HRESULT WINAPI StreamOnMemory_LockRegion(IStream *iface,
207     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
208 {
209     TRACE("(%p)\n", iface);
210     return E_NOTIMPL;
211 }
212
213 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */
214 static HRESULT WINAPI StreamOnMemory_UnlockRegion(IStream *iface,
215     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
216 {
217     TRACE("(%p)\n", iface);
218     return E_NOTIMPL;
219 }
220
221 static HRESULT WINAPI StreamOnMemory_Stat(IStream *iface,
222     STATSTG *pstatstg, DWORD grfStatFlag)
223 {
224     StreamOnMemory *This = StreamOnMemory_from_IStream(iface);
225     TRACE("(%p)\n", This);
226
227     if (!pstatstg) return E_INVALIDARG;
228
229     ZeroMemory(pstatstg, sizeof(STATSTG));
230     pstatstg->type = STGTY_STREAM;
231     pstatstg->cbSize.QuadPart = This->dwMemsize;
232
233     return S_OK;
234 }
235
236 /* Clone isn't implemented in the native windowscodecs DLL either */
237 static HRESULT WINAPI StreamOnMemory_Clone(IStream *iface,
238     IStream **ppstm)
239 {
240     TRACE("(%p)\n", iface);
241     return E_NOTIMPL;
242 }
243
244
245 static const IStreamVtbl StreamOnMemory_Vtbl =
246 {
247     /*** IUnknown methods ***/
248     StreamOnMemory_QueryInterface,
249     StreamOnMemory_AddRef,
250     StreamOnMemory_Release,
251     /*** ISequentialStream methods ***/
252     StreamOnMemory_Read,
253     StreamOnMemory_Write,
254     /*** IStream methods ***/
255     StreamOnMemory_Seek,
256     StreamOnMemory_SetSize,
257     StreamOnMemory_CopyTo,
258     StreamOnMemory_Commit,
259     StreamOnMemory_Revert,
260     StreamOnMemory_LockRegion,
261     StreamOnMemory_UnlockRegion,
262     StreamOnMemory_Stat,
263     StreamOnMemory_Clone,
264 };
265
266 /******************************************
267  * StreamOnFileHandle implementation (internal)
268  *
269  */
270 typedef struct StreamOnFileHandle {
271     IStream IStream_iface;
272     LONG ref;
273
274     HANDLE map;
275     void *mem;
276     IWICStream *stream;
277 } StreamOnFileHandle;
278
279 static inline StreamOnFileHandle *StreamOnFileHandle_from_IStream(IStream *iface)
280 {
281     return CONTAINING_RECORD(iface, StreamOnFileHandle, IStream_iface);
282 }
283
284 static HRESULT WINAPI StreamOnFileHandle_QueryInterface(IStream *iface,
285     REFIID iid, void **ppv)
286 {
287     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
288
289     if (!ppv) return E_INVALIDARG;
290
291     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) ||
292         IsEqualIID(&IID_ISequentialStream, iid))
293     {
294         *ppv = iface;
295         IUnknown_AddRef((IUnknown*)*ppv);
296         return S_OK;
297     }
298     else
299     {
300         *ppv = NULL;
301         return E_NOINTERFACE;
302     }
303 }
304
305 static ULONG WINAPI StreamOnFileHandle_AddRef(IStream *iface)
306 {
307     StreamOnFileHandle *This = StreamOnFileHandle_from_IStream(iface);
308     ULONG ref = InterlockedIncrement(&This->ref);
309
310     TRACE("(%p) refcount=%u\n", iface, ref);
311
312     return ref;
313 }
314
315 static ULONG WINAPI StreamOnFileHandle_Release(IStream *iface)
316 {
317     StreamOnFileHandle *This = StreamOnFileHandle_from_IStream(iface);
318     ULONG ref = InterlockedDecrement(&This->ref);
319
320     TRACE("(%p) refcount=%u\n", iface, ref);
321
322     if (ref == 0) {
323         IWICStream_Release(This->stream);
324         UnmapViewOfFile(This->mem);
325         CloseHandle(This->map);
326         HeapFree(GetProcessHeap(), 0, This);
327     }
328     return ref;
329 }
330
331 static HRESULT WINAPI StreamOnFileHandle_Read(IStream *iface,
332     void *pv, ULONG cb, ULONG *pcbRead)
333 {
334     StreamOnFileHandle *This = StreamOnFileHandle_from_IStream(iface);
335     TRACE("(%p)\n", This);
336
337     return IWICStream_Read(This->stream, pv, cb, pcbRead);
338 }
339
340 static HRESULT WINAPI StreamOnFileHandle_Write(IStream *iface,
341     void const *pv, ULONG cb, ULONG *pcbWritten)
342 {
343     ERR("(%p)\n", iface);
344     return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
345 }
346
347 static HRESULT WINAPI StreamOnFileHandle_Seek(IStream *iface,
348     LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
349 {
350     StreamOnFileHandle *This = StreamOnFileHandle_from_IStream(iface);
351     TRACE("(%p)\n", This);
352
353     return IWICStream_Seek(This->stream, dlibMove, dwOrigin, plibNewPosition);
354 }
355
356 static HRESULT WINAPI StreamOnFileHandle_SetSize(IStream *iface,
357     ULARGE_INTEGER libNewSize)
358 {
359     TRACE("(%p)\n", iface);
360     return E_NOTIMPL;
361 }
362
363 static HRESULT WINAPI StreamOnFileHandle_CopyTo(IStream *iface,
364     IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
365 {
366     TRACE("(%p)\n", iface);
367     return E_NOTIMPL;
368 }
369
370 static HRESULT WINAPI StreamOnFileHandle_Commit(IStream *iface,
371     DWORD grfCommitFlags)
372 {
373     TRACE("(%p)\n", iface);
374     return E_NOTIMPL;
375 }
376
377 static HRESULT WINAPI StreamOnFileHandle_Revert(IStream *iface)
378 {
379     TRACE("(%p)\n", iface);
380     return E_NOTIMPL;
381 }
382
383 static HRESULT WINAPI StreamOnFileHandle_LockRegion(IStream *iface,
384     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
385 {
386     TRACE("(%p)\n", iface);
387     return E_NOTIMPL;
388 }
389
390 static HRESULT WINAPI StreamOnFileHandle_UnlockRegion(IStream *iface,
391     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
392 {
393     TRACE("(%p)\n", iface);
394     return E_NOTIMPL;
395 }
396
397 static HRESULT WINAPI StreamOnFileHandle_Stat(IStream *iface,
398     STATSTG *pstatstg, DWORD grfStatFlag)
399 {
400     StreamOnFileHandle *This = StreamOnFileHandle_from_IStream(iface);
401     TRACE("(%p)\n", This);
402
403     return IWICStream_Stat(This->stream, pstatstg, grfStatFlag);
404 }
405
406 static HRESULT WINAPI StreamOnFileHandle_Clone(IStream *iface,
407     IStream **ppstm)
408 {
409     TRACE("(%p)\n", iface);
410     return E_NOTIMPL;
411 }
412
413
414 static const IStreamVtbl StreamOnFileHandle_Vtbl =
415 {
416     /*** IUnknown methods ***/
417     StreamOnFileHandle_QueryInterface,
418     StreamOnFileHandle_AddRef,
419     StreamOnFileHandle_Release,
420     /*** ISequentialStream methods ***/
421     StreamOnFileHandle_Read,
422     StreamOnFileHandle_Write,
423     /*** IStream methods ***/
424     StreamOnFileHandle_Seek,
425     StreamOnFileHandle_SetSize,
426     StreamOnFileHandle_CopyTo,
427     StreamOnFileHandle_Commit,
428     StreamOnFileHandle_Revert,
429     StreamOnFileHandle_LockRegion,
430     StreamOnFileHandle_UnlockRegion,
431     StreamOnFileHandle_Stat,
432     StreamOnFileHandle_Clone,
433 };
434
435 /******************************************
436  * StreamOnStreamRange implementation
437  *
438  * Used by IWICStream_InitializeFromIStreamRegion
439  *
440  */
441 typedef struct StreamOnStreamRange {
442     IStream IStream_iface;
443     LONG ref;
444
445     IStream *stream;
446     ULARGE_INTEGER pos;
447     ULARGE_INTEGER offset;
448     ULARGE_INTEGER max_size;
449
450     CRITICAL_SECTION lock;
451 } StreamOnStreamRange;
452
453 static inline StreamOnStreamRange *StreamOnStreamRange_from_IStream(IStream *iface)
454 {
455     return CONTAINING_RECORD(iface, StreamOnStreamRange, IStream_iface);
456 }
457
458 static HRESULT WINAPI StreamOnStreamRange_QueryInterface(IStream *iface,
459     REFIID iid, void **ppv)
460 {
461     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
462
463     if (!ppv) return E_INVALIDARG;
464
465     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) ||
466         IsEqualIID(&IID_ISequentialStream, iid))
467     {
468         *ppv = iface;
469         IUnknown_AddRef((IUnknown*)*ppv);
470         return S_OK;
471     }
472     else
473     {
474         *ppv = NULL;
475         return E_NOINTERFACE;
476     }
477 }
478
479 static ULONG WINAPI StreamOnStreamRange_AddRef(IStream *iface)
480 {
481     StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
482     ULONG ref = InterlockedIncrement(&This->ref);
483
484     TRACE("(%p) refcount=%u\n", iface, ref);
485
486     return ref;
487 }
488
489 static ULONG WINAPI StreamOnStreamRange_Release(IStream *iface)
490 {
491     StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
492     ULONG ref = InterlockedDecrement(&This->ref);
493
494     TRACE("(%p) refcount=%u\n", iface, ref);
495
496     if (ref == 0) {
497         This->lock.DebugInfo->Spare[0] = 0;
498         DeleteCriticalSection(&This->lock);
499         IStream_Release(This->stream);
500         HeapFree(GetProcessHeap(), 0, This);
501     }
502     return ref;
503 }
504
505 static HRESULT WINAPI StreamOnStreamRange_Read(IStream *iface,
506     void *pv, ULONG cb, ULONG *pcbRead)
507 {
508     StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
509     ULONG uBytesRead=0;
510     HRESULT hr;
511     ULARGE_INTEGER OldPosition;
512     LARGE_INTEGER SetPosition;
513     TRACE("(%p)\n", This);
514
515     if (!pv) return E_INVALIDARG;
516
517     EnterCriticalSection(&This->lock);
518     SetPosition.QuadPart = 0;
519     hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_CUR, &OldPosition);
520     if (SUCCEEDED(hr))
521     {
522         SetPosition.QuadPart = This->pos.QuadPart + This->offset.QuadPart;
523         hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL);
524     }
525     if (SUCCEEDED(hr))
526     {
527         if (This->pos.QuadPart + cb > This->max_size.QuadPart)
528         {
529             /* This would read past the end of the stream. */
530             if (This->pos.QuadPart > This->max_size.QuadPart)
531                 cb = 0;
532             else
533                 cb = This->max_size.QuadPart - This->pos.QuadPart;
534         }
535         hr = IStream_Read(This->stream, pv, cb, &uBytesRead);
536         SetPosition.QuadPart = OldPosition.QuadPart;
537         IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL);
538     }
539     if (SUCCEEDED(hr))
540         This->pos.QuadPart += uBytesRead;
541     LeaveCriticalSection(&This->lock);
542
543     if (SUCCEEDED(hr) && pcbRead) *pcbRead = uBytesRead;
544
545     return hr;
546 }
547
548 static HRESULT WINAPI StreamOnStreamRange_Write(IStream *iface,
549     void const *pv, ULONG cb, ULONG *pcbWritten)
550 {
551     StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
552     HRESULT hr;
553     ULARGE_INTEGER OldPosition;
554     LARGE_INTEGER SetPosition;
555     ULONG uBytesWritten=0;
556     TRACE("(%p)\n", This);
557
558     if (!pv) return E_INVALIDARG;
559
560     EnterCriticalSection(&This->lock);
561     SetPosition.QuadPart = 0;
562     hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_CUR, &OldPosition);
563     if (SUCCEEDED(hr))
564     {
565         SetPosition.QuadPart = This->pos.QuadPart + This->offset.QuadPart;
566         hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL);
567     }
568     if (SUCCEEDED(hr))
569     {
570         if (This->pos.QuadPart + cb > This->max_size.QuadPart)
571         {
572             /* This would read past the end of the stream. */
573             if (This->pos.QuadPart > This->max_size.QuadPart)
574                 cb = 0;
575             else
576                 cb = This->max_size.QuadPart - This->pos.QuadPart;
577         }
578         hr = IStream_Write(This->stream, pv, cb, &uBytesWritten);
579         SetPosition.QuadPart = OldPosition.QuadPart;
580         IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL);
581     }
582     if (SUCCEEDED(hr))
583         This->pos.QuadPart += uBytesWritten;
584     LeaveCriticalSection(&This->lock);
585
586     if (SUCCEEDED(hr) && pcbWritten) *pcbWritten = uBytesWritten;
587
588     return hr;
589 }
590
591 static HRESULT WINAPI StreamOnStreamRange_Seek(IStream *iface,
592     LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
593 {
594     StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
595     ULARGE_INTEGER NewPosition, actual_size;
596     HRESULT hr=S_OK;
597     STATSTG statstg;
598     TRACE("(%p)\n", This);
599
600     EnterCriticalSection(&This->lock);
601     actual_size = This->max_size;
602     if (dwOrigin == STREAM_SEEK_SET)
603         NewPosition.QuadPart = dlibMove.QuadPart;
604     else if (dwOrigin == STREAM_SEEK_CUR)
605         NewPosition.QuadPart = This->pos.QuadPart + dlibMove.QuadPart;
606     else if (dwOrigin == STREAM_SEEK_END)
607     {
608         hr = IStream_Stat(This->stream, &statstg, STATFLAG_NONAME);
609         if (SUCCEEDED(hr))
610         {
611             if (This->max_size.QuadPart + This->offset.QuadPart > statstg.cbSize.QuadPart)
612                 actual_size.QuadPart = statstg.cbSize.QuadPart - This->offset.QuadPart;
613             NewPosition.QuadPart = dlibMove.QuadPart + actual_size.QuadPart;
614         }
615     }
616     else hr = E_INVALIDARG;
617
618     if (SUCCEEDED(hr) && (NewPosition.u.HighPart != 0 || NewPosition.QuadPart > actual_size.QuadPart))
619         hr = WINCODEC_ERR_VALUEOUTOFRANGE;
620
621     if (SUCCEEDED(hr)) {
622         This->pos.QuadPart = NewPosition.QuadPart;
623
624         if(plibNewPosition) plibNewPosition->QuadPart = This->pos.QuadPart;
625     }
626     LeaveCriticalSection(&This->lock);
627
628     return hr;
629 }
630
631 /* SetSize isn't implemented in the native windowscodecs DLL either */
632 static HRESULT WINAPI StreamOnStreamRange_SetSize(IStream *iface,
633     ULARGE_INTEGER libNewSize)
634 {
635     TRACE("(%p)\n", iface);
636     return E_NOTIMPL;
637 }
638
639 /* CopyTo isn't implemented in the native windowscodecs DLL either */
640 static HRESULT WINAPI StreamOnStreamRange_CopyTo(IStream *iface,
641     IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
642 {
643     TRACE("(%p)\n", iface);
644     return E_NOTIMPL;
645 }
646
647 /* Commit isn't implemented in the native windowscodecs DLL either */
648 static HRESULT WINAPI StreamOnStreamRange_Commit(IStream *iface,
649     DWORD grfCommitFlags)
650 {
651     TRACE("(%p)\n", iface);
652     return E_NOTIMPL;
653 }
654
655 /* Revert isn't implemented in the native windowscodecs DLL either */
656 static HRESULT WINAPI StreamOnStreamRange_Revert(IStream *iface)
657 {
658     TRACE("(%p)\n", iface);
659     return E_NOTIMPL;
660 }
661
662 /* LockRegion isn't implemented in the native windowscodecs DLL either */
663 static HRESULT WINAPI StreamOnStreamRange_LockRegion(IStream *iface,
664     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
665 {
666     TRACE("(%p)\n", iface);
667     return E_NOTIMPL;
668 }
669
670 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */
671 static HRESULT WINAPI StreamOnStreamRange_UnlockRegion(IStream *iface,
672     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
673 {
674     TRACE("(%p)\n", iface);
675     return E_NOTIMPL;
676 }
677
678 static HRESULT WINAPI StreamOnStreamRange_Stat(IStream *iface,
679     STATSTG *pstatstg, DWORD grfStatFlag)
680 {
681     StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface);
682     HRESULT hr;
683     TRACE("(%p)\n", This);
684
685     if (!pstatstg) return E_INVALIDARG;
686
687     EnterCriticalSection(&This->lock);
688     hr = IStream_Stat(This->stream, pstatstg, grfStatFlag);
689     if (SUCCEEDED(hr))
690     {
691         pstatstg->cbSize.QuadPart -= This->offset.QuadPart;
692         if (This->max_size.QuadPart < pstatstg->cbSize.QuadPart)
693             pstatstg->cbSize.QuadPart = This->max_size.QuadPart;
694     }
695
696     LeaveCriticalSection(&This->lock);
697
698     return hr;
699 }
700
701 /* Clone isn't implemented in the native windowscodecs DLL either */
702 static HRESULT WINAPI StreamOnStreamRange_Clone(IStream *iface,
703     IStream **ppstm)
704 {
705     TRACE("(%p)\n", iface);
706     return E_NOTIMPL;
707 }
708
709
710 static const IStreamVtbl StreamOnStreamRange_Vtbl =
711 {
712     /*** IUnknown methods ***/
713     StreamOnStreamRange_QueryInterface,
714     StreamOnStreamRange_AddRef,
715     StreamOnStreamRange_Release,
716     /*** ISequentialStream methods ***/
717     StreamOnStreamRange_Read,
718     StreamOnStreamRange_Write,
719     /*** IStream methods ***/
720     StreamOnStreamRange_Seek,
721     StreamOnStreamRange_SetSize,
722     StreamOnStreamRange_CopyTo,
723     StreamOnStreamRange_Commit,
724     StreamOnStreamRange_Revert,
725     StreamOnStreamRange_LockRegion,
726     StreamOnStreamRange_UnlockRegion,
727     StreamOnStreamRange_Stat,
728     StreamOnStreamRange_Clone,
729 };
730
731
732 /******************************************
733  * IWICStream implementation
734  *
735  */
736 typedef struct IWICStreamImpl
737 {
738     IWICStream IWICStream_iface;
739     LONG ref;
740
741     IStream *pStream;
742 } IWICStreamImpl;
743
744 static inline IWICStreamImpl *impl_from_IWICStream(IWICStream *iface)
745 {
746     return CONTAINING_RECORD(iface, IWICStreamImpl, IWICStream_iface);
747 }
748
749 static HRESULT WINAPI IWICStreamImpl_QueryInterface(IWICStream *iface,
750     REFIID iid, void **ppv)
751 {
752     IWICStreamImpl *This = impl_from_IWICStream(iface);
753     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
754
755     if (!ppv) return E_INVALIDARG;
756
757     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) ||
758         IsEqualIID(&IID_ISequentialStream, iid) || IsEqualIID(&IID_IWICStream, iid))
759     {
760         *ppv = This;
761         IUnknown_AddRef((IUnknown*)*ppv);
762         return S_OK;
763     }
764     else
765     {
766         *ppv = NULL;
767         return E_NOINTERFACE;
768     }
769 }
770
771 static ULONG WINAPI IWICStreamImpl_AddRef(IWICStream *iface)
772 {
773     IWICStreamImpl *This = impl_from_IWICStream(iface);
774     ULONG ref = InterlockedIncrement(&This->ref);
775
776     TRACE("(%p) refcount=%u\n", iface, ref);
777
778     return ref;
779 }
780
781 static ULONG WINAPI IWICStreamImpl_Release(IWICStream *iface)
782 {
783     IWICStreamImpl *This = impl_from_IWICStream(iface);
784     ULONG ref = InterlockedDecrement(&This->ref);
785
786     TRACE("(%p) refcount=%u\n", iface, ref);
787
788     if (ref == 0) {
789         if (This->pStream) IStream_Release(This->pStream);
790         HeapFree(GetProcessHeap(), 0, This);
791     }
792     return ref;
793 }
794
795 static HRESULT WINAPI IWICStreamImpl_Read(IWICStream *iface,
796     void *pv, ULONG cb, ULONG *pcbRead)
797 {
798     IWICStreamImpl *This = impl_from_IWICStream(iface);
799     TRACE("(%p): relay\n", This);
800
801     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
802     return IStream_Read(This->pStream, pv, cb, pcbRead);
803 }
804
805 static HRESULT WINAPI IWICStreamImpl_Write(IWICStream *iface,
806     void const *pv, ULONG cb, ULONG *pcbWritten)
807 {
808     IWICStreamImpl *This = impl_from_IWICStream(iface);
809     TRACE("(%p): relay\n", This);
810
811     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
812     return IStream_Write(This->pStream, pv, cb, pcbWritten);
813 }
814
815 static HRESULT WINAPI IWICStreamImpl_Seek(IWICStream *iface,
816     LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
817 {
818     IWICStreamImpl *This = impl_from_IWICStream(iface);
819     TRACE("(%p): relay\n", This);
820
821     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
822     return IStream_Seek(This->pStream, dlibMove, dwOrigin, plibNewPosition);
823 }
824
825 static HRESULT WINAPI IWICStreamImpl_SetSize(IWICStream *iface,
826     ULARGE_INTEGER libNewSize)
827 {
828     IWICStreamImpl *This = impl_from_IWICStream(iface);
829     TRACE("(%p): relay\n", This);
830
831     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
832     return IStream_SetSize(This->pStream, libNewSize);
833 }
834
835 static HRESULT WINAPI IWICStreamImpl_CopyTo(IWICStream *iface,
836     IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
837 {
838     IWICStreamImpl *This = impl_from_IWICStream(iface);
839     TRACE("(%p): relay\n", This);
840
841     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
842     return IStream_CopyTo(This->pStream, pstm, cb, pcbRead, pcbWritten);
843 }
844
845 static HRESULT WINAPI IWICStreamImpl_Commit(IWICStream *iface,
846     DWORD grfCommitFlags)
847 {
848     IWICStreamImpl *This = impl_from_IWICStream(iface);
849     TRACE("(%p): relay\n", This);
850
851     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
852     return IStream_Commit(This->pStream, grfCommitFlags);
853 }
854
855 static HRESULT WINAPI IWICStreamImpl_Revert(IWICStream *iface)
856 {
857     IWICStreamImpl *This = impl_from_IWICStream(iface);
858     TRACE("(%p): relay\n", This);
859
860     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
861     return IStream_Revert(This->pStream);
862 }
863
864 static HRESULT WINAPI IWICStreamImpl_LockRegion(IWICStream *iface,
865     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
866 {
867     IWICStreamImpl *This = impl_from_IWICStream(iface);
868     TRACE("(%p): relay\n", This);
869
870     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
871     return IStream_LockRegion(This->pStream, libOffset, cb, dwLockType);
872 }
873
874 static HRESULT WINAPI IWICStreamImpl_UnlockRegion(IWICStream *iface,
875     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
876 {
877     IWICStreamImpl *This = impl_from_IWICStream(iface);
878     TRACE("(%p): relay\n", This);
879
880     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
881     return IStream_UnlockRegion(This->pStream, libOffset, cb, dwLockType);
882 }
883
884 static HRESULT WINAPI IWICStreamImpl_Stat(IWICStream *iface,
885     STATSTG *pstatstg, DWORD grfStatFlag)
886 {
887     IWICStreamImpl *This = impl_from_IWICStream(iface);
888     TRACE("(%p): relay\n", This);
889
890     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
891     return IStream_Stat(This->pStream, pstatstg, grfStatFlag);
892 }
893
894 static HRESULT WINAPI IWICStreamImpl_Clone(IWICStream *iface,
895     IStream **ppstm)
896 {
897     IWICStreamImpl *This = impl_from_IWICStream(iface);
898     TRACE("(%p): relay\n", This);
899
900     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
901     return IStream_Clone(This->pStream, ppstm);
902 }
903
904 static HRESULT WINAPI IWICStreamImpl_InitializeFromIStream(IWICStream *iface,
905     IStream *pIStream)
906 {
907     ULARGE_INTEGER offset, size;
908     TRACE("(%p): relay\n", iface);
909
910     offset.QuadPart = 0;
911     size.u.LowPart = 0xffffffff;
912     size.u.HighPart = 0xffffffff;
913     return IWICStream_InitializeFromIStreamRegion(iface, pIStream, offset, size);
914 }
915
916 static HRESULT WINAPI IWICStreamImpl_InitializeFromFilename(IWICStream *iface,
917     LPCWSTR wzFileName, DWORD dwDesiredAccess)
918 {
919     IWICStreamImpl *This = impl_from_IWICStream(iface);
920     HRESULT hr;
921     DWORD dwMode;
922     IStream *stream;
923
924     TRACE("(%p, %s, %u)\n", iface, debugstr_w(wzFileName), dwDesiredAccess);
925
926     if (This->pStream) return WINCODEC_ERR_WRONGSTATE;
927
928     if(dwDesiredAccess & GENERIC_WRITE)
929         dwMode = STGM_SHARE_DENY_WRITE | STGM_WRITE | STGM_CREATE;
930     else if(dwDesiredAccess & GENERIC_READ)
931         dwMode = STGM_SHARE_DENY_WRITE | STGM_READ | STGM_FAILIFTHERE;
932     else
933         return E_INVALIDARG;
934
935     hr = SHCreateStreamOnFileW(wzFileName, dwMode, &stream);
936
937     if (SUCCEEDED(hr))
938     {
939         if (InterlockedCompareExchangePointer((void**)&This->pStream, stream, NULL))
940         {
941             /* Some other thread set the stream first. */
942             IStream_Release(stream);
943             hr = WINCODEC_ERR_WRONGSTATE;
944         }
945     }
946
947     return hr;
948 }
949
950 /******************************************
951  * IWICStream_InitializeFromMemory
952  *
953  * Initializes the internal IStream object to retrieve its data from a memory chunk.
954  *
955  * PARAMS
956  *   pbBuffer     [I] pointer to the memory chunk
957  *   cbBufferSize [I] number of bytes to use from the memory chunk
958  *
959  * RETURNS
960  *   SUCCESS: S_OK
961  *   FAILURE: E_INVALIDARG, if pbBuffer is NULL
962  *            E_OUTOFMEMORY, if we run out of memory
963  *            WINCODEC_ERR_WRONGSTATE, if the IStream object has already been initialized before
964  *
965  */
966 static HRESULT WINAPI IWICStreamImpl_InitializeFromMemory(IWICStream *iface,
967     BYTE *pbBuffer, DWORD cbBufferSize)
968 {
969     IWICStreamImpl *This = impl_from_IWICStream(iface);
970     StreamOnMemory *pObject;
971     TRACE("(%p,%p)\n", iface, pbBuffer);
972
973     if (!pbBuffer) return E_INVALIDARG;
974     if (This->pStream) return WINCODEC_ERR_WRONGSTATE;
975
976     pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnMemory));
977     if (!pObject) return E_OUTOFMEMORY;
978
979     pObject->IStream_iface.lpVtbl = &StreamOnMemory_Vtbl;
980     pObject->ref = 1;
981     pObject->pbMemory = pbBuffer;
982     pObject->dwMemsize = cbBufferSize;
983     pObject->dwCurPos = 0;
984     InitializeCriticalSection(&pObject->lock);
985     pObject->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": StreamOnMemory.lock");
986
987     if (InterlockedCompareExchangePointer((void**)&This->pStream, pObject, NULL))
988     {
989         /* Some other thread set the stream first. */
990         IStream_Release(&pObject->IStream_iface);
991         return WINCODEC_ERR_WRONGSTATE;
992     }
993
994     return S_OK;
995 }
996
997 static HRESULT map_file(HANDLE file, HANDLE *map, void **mem, LARGE_INTEGER *size)
998 {
999     *map = NULL;
1000     if (!GetFileSizeEx(file, size)) return HRESULT_FROM_WIN32(GetLastError());
1001     if (size->u.HighPart)
1002     {
1003         WARN("file too large\n");
1004         return E_FAIL;
1005     }
1006     if (!(*map = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, size->u.LowPart, NULL)))
1007     {
1008         return HRESULT_FROM_WIN32(GetLastError());
1009     }
1010     if (!(*mem = MapViewOfFile(*map, FILE_MAP_READ, 0, 0, size->u.LowPart)))
1011     {
1012         CloseHandle(*map);
1013         return HRESULT_FROM_WIN32(GetLastError());
1014     }
1015     return S_OK;
1016 }
1017
1018 HRESULT stream_initialize_from_filehandle(IWICStream *iface, HANDLE file)
1019 {
1020     IWICStreamImpl *This = impl_from_IWICStream(iface);
1021     StreamOnFileHandle *pObject;
1022     IWICStream *stream = NULL;
1023     HANDLE map;
1024     void *mem;
1025     LARGE_INTEGER size;
1026     HRESULT hr;
1027     TRACE("(%p,%p)\n", iface, file);
1028
1029     if (This->pStream) return WINCODEC_ERR_WRONGSTATE;
1030
1031     hr = map_file(file, &map, &mem, &size);
1032     if (FAILED(hr)) return hr;
1033
1034     hr = StreamImpl_Create(&stream);
1035     if (FAILED(hr)) goto error;
1036
1037     hr = IWICStreamImpl_InitializeFromMemory(stream, mem, size.u.LowPart);
1038     if (FAILED(hr)) goto error;
1039
1040     pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnFileHandle));
1041     if (!pObject)
1042     {
1043         hr = E_OUTOFMEMORY;
1044         goto error;
1045     }
1046     pObject->IStream_iface.lpVtbl = &StreamOnFileHandle_Vtbl;
1047     pObject->ref = 1;
1048     pObject->map = map;
1049     pObject->mem = mem;
1050     pObject->stream = stream;
1051
1052     if (InterlockedCompareExchangePointer((void**)&This->pStream, pObject, NULL))
1053     {
1054         /* Some other thread set the stream first. */
1055         IStream_Release(&pObject->IStream_iface);
1056         return WINCODEC_ERR_WRONGSTATE;
1057     }
1058     return S_OK;
1059
1060 error:
1061     if (stream) IWICStream_Release(stream);
1062     UnmapViewOfFile(mem);
1063     CloseHandle(map);
1064     return hr;
1065 }
1066
1067 static HRESULT WINAPI IWICStreamImpl_InitializeFromIStreamRegion(IWICStream *iface,
1068     IStream *pIStream, ULARGE_INTEGER ulOffset, ULARGE_INTEGER ulMaxSize)
1069 {
1070     IWICStreamImpl *This = impl_from_IWICStream(iface);
1071     StreamOnStreamRange *pObject;
1072     TRACE("(%p,%p)\n", iface, pIStream);
1073
1074     if (!pIStream) return E_INVALIDARG;
1075     if (This->pStream) return WINCODEC_ERR_WRONGSTATE;
1076
1077     pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnStreamRange));
1078     if (!pObject) return E_OUTOFMEMORY;
1079
1080     pObject->IStream_iface.lpVtbl = &StreamOnStreamRange_Vtbl;
1081     pObject->ref = 1;
1082     IStream_AddRef(pIStream);
1083     pObject->stream = pIStream;
1084     pObject->pos.QuadPart = 0;
1085     pObject->offset = ulOffset;
1086     pObject->max_size = ulMaxSize;
1087     InitializeCriticalSection(&pObject->lock);
1088     pObject->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": StreamOnStreamRange.lock");
1089
1090     if (InterlockedCompareExchangePointer((void**)&This->pStream, pObject, NULL))
1091     {
1092         /* Some other thread set the stream first. */
1093         IStream_Release(&pObject->IStream_iface);
1094         return WINCODEC_ERR_WRONGSTATE;
1095     }
1096
1097     return S_OK;
1098 }
1099
1100
1101 static const IWICStreamVtbl WICStream_Vtbl =
1102 {
1103     /*** IUnknown methods ***/
1104     IWICStreamImpl_QueryInterface,
1105     IWICStreamImpl_AddRef,
1106     IWICStreamImpl_Release,
1107     /*** ISequentialStream methods ***/
1108     IWICStreamImpl_Read,
1109     IWICStreamImpl_Write,
1110     /*** IStream methods ***/
1111     IWICStreamImpl_Seek,
1112     IWICStreamImpl_SetSize,
1113     IWICStreamImpl_CopyTo,
1114     IWICStreamImpl_Commit,
1115     IWICStreamImpl_Revert,
1116     IWICStreamImpl_LockRegion,
1117     IWICStreamImpl_UnlockRegion,
1118     IWICStreamImpl_Stat,
1119     IWICStreamImpl_Clone,
1120     /*** IWICStream methods ***/
1121     IWICStreamImpl_InitializeFromIStream,
1122     IWICStreamImpl_InitializeFromFilename,
1123     IWICStreamImpl_InitializeFromMemory,
1124     IWICStreamImpl_InitializeFromIStreamRegion,
1125 };
1126
1127 HRESULT StreamImpl_Create(IWICStream **stream)
1128 {
1129     IWICStreamImpl *pObject;
1130
1131     if( !stream ) return E_INVALIDARG;
1132
1133     pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(IWICStreamImpl));
1134     if( !pObject ) {
1135         *stream = NULL;
1136         return E_OUTOFMEMORY;
1137     }
1138
1139     pObject->IWICStream_iface.lpVtbl = &WICStream_Vtbl;
1140     pObject->ref = 1;
1141     pObject->pStream = NULL;
1142
1143     *stream = &pObject->IWICStream_iface;
1144
1145     return S_OK;
1146 }