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