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