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