mmsystem: Use PeekMessageW instead of UserYield.
[wine] / dlls / windowscodecs / stream.c
1 /*
2  * Copyright 2009 Tony Wasserka
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "wine/debug.h"
20
21 #define COBJMACROS
22 #include "windef.h"
23 #include "winbase.h"
24 #include "winreg.h"
25 #include "objbase.h"
26 #include "wincodec.h"
27 #include "wincodecs_private.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
30
31 /******************************************
32  * StreamOnMemory implementation
33  *
34  * Used by IWICStream_InitializeFromMemory
35  *
36  */
37 typedef struct StreamOnMemory {
38     const IStreamVtbl *lpVtbl;
39     LONG ref;
40
41     BYTE *pbMemory;
42     DWORD dwMemsize;
43     DWORD dwCurPos;
44 } StreamOnMemory;
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*)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*)iface;
80     ULONG ref = InterlockedDecrement(&This->ref);
81
82     TRACE("(%p) refcount=%u\n", iface, ref);
83
84     if (ref == 0) {
85         HeapFree(GetProcessHeap(), 0, This);
86     }
87     return ref;
88 }
89
90 static HRESULT WINAPI StreamOnMemory_Read(IStream *iface,
91     void *pv, ULONG cb, ULONG *pcbRead)
92 {
93     StreamOnMemory *This = (StreamOnMemory*)iface;
94     ULONG uBytesRead;
95     TRACE("(%p)\n", This);
96
97     if (!pv) return E_INVALIDARG;
98
99     uBytesRead = min(cb, This->dwMemsize - This->dwCurPos);
100     memcpy(pv, This->pbMemory + This->dwCurPos, uBytesRead);
101     This->dwCurPos += uBytesRead;
102     if (pcbRead) *pcbRead = uBytesRead;
103
104     return S_OK;
105 }
106
107 static HRESULT WINAPI StreamOnMemory_Write(IStream *iface,
108     void const *pv, ULONG cb, ULONG *pcbWritten)
109 {
110     StreamOnMemory *This = (StreamOnMemory*)iface;
111     TRACE("(%p)\n", This);
112
113     if (!pv) return E_INVALIDARG;
114
115     if (cb > This->dwMemsize - This->dwCurPos) return STG_E_MEDIUMFULL;
116     if (cb) {
117         memcpy(This->pbMemory + This->dwCurPos, pv, cb);
118         This->dwCurPos += cb;
119     }
120     if (pcbWritten) *pcbWritten = cb;
121
122     return S_OK;
123 }
124
125 static HRESULT WINAPI StreamOnMemory_Seek(IStream *iface,
126     LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
127 {
128     StreamOnMemory *This = (StreamOnMemory*)iface;
129     LARGE_INTEGER NewPosition;
130     TRACE("(%p)\n", This);
131
132     if (dwOrigin == STREAM_SEEK_SET) NewPosition.QuadPart = dlibMove.QuadPart;
133     else if (dwOrigin == STREAM_SEEK_CUR) NewPosition.QuadPart = This->dwCurPos + dlibMove.QuadPart;
134     else if (dwOrigin == STREAM_SEEK_END) NewPosition.QuadPart = This->dwMemsize + dlibMove.QuadPart;
135     else return E_INVALIDARG;
136
137     if (NewPosition.u.HighPart) return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
138     if (NewPosition.QuadPart > This->dwMemsize) return E_INVALIDARG;
139     if (NewPosition.QuadPart < 0) return E_INVALIDARG;
140     This->dwCurPos = NewPosition.u.LowPart;
141
142     if(plibNewPosition) plibNewPosition->QuadPart = This->dwCurPos;
143     return S_OK;
144 }
145
146 /* SetSize isn't implemented in the native windowscodecs DLL either */
147 static HRESULT WINAPI StreamOnMemory_SetSize(IStream *iface,
148     ULARGE_INTEGER libNewSize)
149 {
150     TRACE("(%p)\n", iface);
151     return E_NOTIMPL;
152 }
153
154 /* CopyTo isn't implemented in the native windowscodecs DLL either */
155 static HRESULT WINAPI StreamOnMemory_CopyTo(IStream *iface,
156     IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
157 {
158     TRACE("(%p)\n", iface);
159     return E_NOTIMPL;
160 }
161
162 /* Commit isn't implemented in the native windowscodecs DLL either */
163 static HRESULT WINAPI StreamOnMemory_Commit(IStream *iface,
164     DWORD grfCommitFlags)
165 {
166     TRACE("(%p)\n", iface);
167     return E_NOTIMPL;
168 }
169
170 /* Revert isn't implemented in the native windowscodecs DLL either */
171 static HRESULT WINAPI StreamOnMemory_Revert(IStream *iface)
172 {
173     TRACE("(%p)\n", iface);
174     return E_NOTIMPL;
175 }
176
177 /* LockRegion isn't implemented in the native windowscodecs DLL either */
178 static HRESULT WINAPI StreamOnMemory_LockRegion(IStream *iface,
179     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
180 {
181     TRACE("(%p)\n", iface);
182     return E_NOTIMPL;
183 }
184
185 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */
186 static HRESULT WINAPI StreamOnMemory_UnlockRegion(IStream *iface,
187     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
188 {
189     TRACE("(%p)\n", iface);
190     return E_NOTIMPL;
191 }
192
193 static HRESULT WINAPI StreamOnMemory_Stat(IStream *iface,
194     STATSTG *pstatstg, DWORD grfStatFlag)
195 {
196     StreamOnMemory *This = (StreamOnMemory*)iface;
197     TRACE("(%p)\n", This);
198
199     if (!pstatstg) return E_INVALIDARG;
200
201     ZeroMemory(pstatstg, sizeof(STATSTG));
202     pstatstg->type = STGTY_STREAM;
203     pstatstg->cbSize.QuadPart = This->dwMemsize;
204
205     return S_OK;
206 }
207
208 /* Clone isn't implemented in the native windowscodecs DLL either */
209 static HRESULT WINAPI StreamOnMemory_Clone(IStream *iface,
210     IStream **ppstm)
211 {
212     TRACE("(%p)\n", iface);
213     return E_NOTIMPL;
214 }
215
216
217 const IStreamVtbl StreamOnMemory_Vtbl =
218 {
219     /*** IUnknown methods ***/
220     StreamOnMemory_QueryInterface,
221     StreamOnMemory_AddRef,
222     StreamOnMemory_Release,
223     /*** ISequentialStream methods ***/
224     StreamOnMemory_Read,
225     StreamOnMemory_Write,
226     /*** IStream methods ***/
227     StreamOnMemory_Seek,
228     StreamOnMemory_SetSize,
229     StreamOnMemory_CopyTo,
230     StreamOnMemory_Commit,
231     StreamOnMemory_Revert,
232     StreamOnMemory_LockRegion,
233     StreamOnMemory_UnlockRegion,
234     StreamOnMemory_Stat,
235     StreamOnMemory_Clone,
236 };
237
238 /******************************************
239  * IWICStream implementation
240  *
241  */
242 typedef struct IWICStreamImpl
243 {
244     const IWICStreamVtbl *lpVtbl;
245     LONG ref;
246
247     IStream *pStream;
248 } IWICStreamImpl;
249
250 static HRESULT WINAPI IWICStreamImpl_QueryInterface(IWICStream *iface,
251     REFIID iid, void **ppv)
252 {
253     IWICStreamImpl *This = (IWICStreamImpl*)iface;
254     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
255
256     if (!ppv) return E_INVALIDARG;
257
258     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) ||
259         IsEqualIID(&IID_ISequentialStream, iid) || IsEqualIID(&IID_IWICStream, iid))
260     {
261         *ppv = This;
262         IUnknown_AddRef((IUnknown*)*ppv);
263         return S_OK;
264     }
265     else
266     {
267         *ppv = NULL;
268         return E_NOINTERFACE;
269     }
270 }
271
272 static ULONG WINAPI IWICStreamImpl_AddRef(IWICStream *iface)
273 {
274     IWICStreamImpl *This = (IWICStreamImpl*)iface;
275     ULONG ref = InterlockedIncrement(&This->ref);
276
277     TRACE("(%p) refcount=%u\n", iface, ref);
278
279     return ref;
280 }
281
282 static ULONG WINAPI IWICStreamImpl_Release(IWICStream *iface)
283 {
284     IWICStreamImpl *This = (IWICStreamImpl*)iface;
285     ULONG ref = InterlockedDecrement(&This->ref);
286
287     TRACE("(%p) refcount=%u\n", iface, ref);
288
289     if (ref == 0) {
290         if (This->pStream) IStream_Release(This->pStream);
291         HeapFree(GetProcessHeap(), 0, This);
292     }
293     return ref;
294 }
295
296 static HRESULT WINAPI IWICStreamImpl_Read(IWICStream *iface,
297     void *pv, ULONG cb, ULONG *pcbRead)
298 {
299     IWICStreamImpl *This = (IWICStreamImpl*)iface;
300     TRACE("(%p): relay\n", This);
301
302     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
303     return IStream_Read(This->pStream, pv, cb, pcbRead);
304 }
305
306 static HRESULT WINAPI IWICStreamImpl_Write(IWICStream *iface,
307     void const *pv, ULONG cb, ULONG *pcbWritten)
308 {
309     IWICStreamImpl *This = (IWICStreamImpl*)iface;
310     TRACE("(%p): relay\n", This);
311
312     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
313     return IStream_Write(This->pStream, pv, cb, pcbWritten);
314 }
315
316 static HRESULT WINAPI IWICStreamImpl_Seek(IWICStream *iface,
317     LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
318 {
319     IWICStreamImpl *This = (IWICStreamImpl*)iface;
320     TRACE("(%p): relay\n", This);
321
322     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
323     return IStream_Seek(This->pStream, dlibMove, dwOrigin, plibNewPosition);
324 }
325
326 static HRESULT WINAPI IWICStreamImpl_SetSize(IWICStream *iface,
327     ULARGE_INTEGER libNewSize)
328 {
329     IWICStreamImpl *This = (IWICStreamImpl*)iface;
330     TRACE("(%p): relay\n", This);
331
332     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
333     return IStream_SetSize(This->pStream, libNewSize);
334 }
335
336 static HRESULT WINAPI IWICStreamImpl_CopyTo(IWICStream *iface,
337     IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
338 {
339     IWICStreamImpl *This = (IWICStreamImpl*)iface;
340     TRACE("(%p): relay\n", This);
341
342     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
343     return IStream_CopyTo(This->pStream, pstm, cb, pcbRead, pcbWritten);
344 }
345
346 static HRESULT WINAPI IWICStreamImpl_Commit(IWICStream *iface,
347     DWORD grfCommitFlags)
348 {
349     IWICStreamImpl *This = (IWICStreamImpl*)iface;
350     TRACE("(%p): relay\n", This);
351
352     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
353     return IStream_Commit(This->pStream, grfCommitFlags);
354 }
355
356 static HRESULT WINAPI IWICStreamImpl_Revert(IWICStream *iface)
357 {
358     IWICStreamImpl *This = (IWICStreamImpl*)iface;
359     TRACE("(%p): relay\n", This);
360
361     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
362     return IStream_Revert(This->pStream);
363 }
364
365 static HRESULT WINAPI IWICStreamImpl_LockRegion(IWICStream *iface,
366     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
367 {
368     IWICStreamImpl *This = (IWICStreamImpl*)iface;
369     TRACE("(%p): relay\n", This);
370
371     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
372     return IStream_LockRegion(This->pStream, libOffset, cb, dwLockType);
373 }
374
375 static HRESULT WINAPI IWICStreamImpl_UnlockRegion(IWICStream *iface,
376     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
377 {
378     IWICStreamImpl *This = (IWICStreamImpl*)iface;
379     TRACE("(%p): relay\n", This);
380
381     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
382     return IStream_UnlockRegion(This->pStream, libOffset, cb, dwLockType);
383 }
384
385 static HRESULT WINAPI IWICStreamImpl_Stat(IWICStream *iface,
386     STATSTG *pstatstg, DWORD grfStatFlag)
387 {
388     IWICStreamImpl *This = (IWICStreamImpl*)iface;
389     TRACE("(%p): relay\n", This);
390
391     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
392     return IStream_Stat(This->pStream, pstatstg, grfStatFlag);
393 }
394
395 static HRESULT WINAPI IWICStreamImpl_Clone(IWICStream *iface,
396     IStream **ppstm)
397 {
398     IWICStreamImpl *This = (IWICStreamImpl*)iface;
399     TRACE("(%p): relay\n", This);
400
401     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
402     return IStream_Clone(This->pStream, ppstm);
403 }
404
405 static HRESULT WINAPI IWICStreamImpl_InitializeFromIStream(IWICStream *iface,
406     IStream *pIStream)
407 {
408     FIXME("(%p): stub\n", iface);
409     return E_NOTIMPL;
410 }
411
412 static HRESULT WINAPI IWICStreamImpl_InitializeFromFilename(IWICStream *iface,
413     LPCWSTR wzFileName, DWORD dwDesiredAccess)
414 {
415     FIXME("(%p): stub\n", iface);
416     return E_NOTIMPL;
417 }
418
419 /******************************************
420  * IWICStream_InitializeFromMemory
421  *
422  * Initializes the internal IStream object to retrieve its data from a memory chunk.
423  *
424  * PARAMS
425  *   pbBuffer     [I] pointer to the memory chunk
426  *   cbBufferSize [I] number of bytes to use from the memory chunk
427  *
428  * RETURNS
429  *   SUCCESS: S_OK
430  *   FAILURE: E_INVALIDARG, if pbBuffer is NULL
431  *            E_OUTOFMEMORY, if we run out of memory
432  *            WINCODEC_ERR_WRONGSTATE, if the IStream object has already been initialized before
433  *
434  */
435 static HRESULT WINAPI IWICStreamImpl_InitializeFromMemory(IWICStream *iface,
436     BYTE *pbBuffer, DWORD cbBufferSize)
437 {
438     IWICStreamImpl *This = (IWICStreamImpl*)iface;
439     StreamOnMemory *pObject;
440     TRACE("(%p,%p)\n", iface, pbBuffer);
441
442     if (!pbBuffer) return E_INVALIDARG;
443     if (This->pStream) return WINCODEC_ERR_WRONGSTATE;
444
445     pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnMemory));
446     if (!pObject) return E_OUTOFMEMORY;
447
448     pObject->lpVtbl = &StreamOnMemory_Vtbl;
449     pObject->ref = 1;
450     pObject->pbMemory = pbBuffer;
451     pObject->dwMemsize = cbBufferSize;
452     pObject->dwCurPos = 0;
453
454     This->pStream = (IStream*)pObject;
455     return S_OK;
456 }
457
458 static HRESULT WINAPI IWICStreamImpl_InitializeFromIStreamRegion(IWICStream *iface,
459     IStream *pIStream, ULARGE_INTEGER ulOffset, ULARGE_INTEGER ulMaxSize)
460 {
461     FIXME("(%p): stub\n", iface);
462     return E_NOTIMPL;
463 }
464
465
466 const IWICStreamVtbl WICStream_Vtbl =
467 {
468     /*** IUnknown methods ***/
469     IWICStreamImpl_QueryInterface,
470     IWICStreamImpl_AddRef,
471     IWICStreamImpl_Release,
472     /*** ISequentialStream methods ***/
473     IWICStreamImpl_Read,
474     IWICStreamImpl_Write,
475     /*** IStream methods ***/
476     IWICStreamImpl_Seek,
477     IWICStreamImpl_SetSize,
478     IWICStreamImpl_CopyTo,
479     IWICStreamImpl_Commit,
480     IWICStreamImpl_Revert,
481     IWICStreamImpl_LockRegion,
482     IWICStreamImpl_UnlockRegion,
483     IWICStreamImpl_Stat,
484     IWICStreamImpl_Clone,
485     /*** IWICStream methods ***/
486     IWICStreamImpl_InitializeFromIStream,
487     IWICStreamImpl_InitializeFromFilename,
488     IWICStreamImpl_InitializeFromMemory,
489     IWICStreamImpl_InitializeFromIStreamRegion,
490 };
491
492 HRESULT StreamImpl_Create(IWICStream **stream)
493 {
494     IWICStreamImpl *pObject;
495
496     if( !stream ) return E_INVALIDARG;
497
498     pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(IWICStreamImpl));
499     if( !pObject ) {
500         *stream = NULL;
501         return E_OUTOFMEMORY;
502     }
503
504     pObject->lpVtbl = &WICStream_Vtbl;
505     pObject->ref = 1;
506     pObject->pStream = NULL;
507
508     *stream = (IWICStream*)pObject;
509
510     return S_OK;
511 }