kernel32: Remove superfluous heap reallocation calls in FormatMessageA/W.
[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
45     CRITICAL_SECTION lock; /* must be held when pbMemory or dwCurPos is accessed */
46 } StreamOnMemory;
47
48 static HRESULT WINAPI StreamOnMemory_QueryInterface(IStream *iface,
49     REFIID iid, void **ppv)
50 {
51     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
52
53     if (!ppv) return E_INVALIDARG;
54
55     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) ||
56         IsEqualIID(&IID_ISequentialStream, iid))
57     {
58         *ppv = iface;
59         IUnknown_AddRef((IUnknown*)*ppv);
60         return S_OK;
61     }
62     else
63     {
64         *ppv = NULL;
65         return E_NOINTERFACE;
66     }
67 }
68
69 static ULONG WINAPI StreamOnMemory_AddRef(IStream *iface)
70 {
71     StreamOnMemory *This = (StreamOnMemory*)iface;
72     ULONG ref = InterlockedIncrement(&This->ref);
73
74     TRACE("(%p) refcount=%u\n", iface, ref);
75
76     return ref;
77 }
78
79 static ULONG WINAPI StreamOnMemory_Release(IStream *iface)
80 {
81     StreamOnMemory *This = (StreamOnMemory*)iface;
82     ULONG ref = InterlockedDecrement(&This->ref);
83
84     TRACE("(%p) refcount=%u\n", iface, ref);
85
86     if (ref == 0) {
87         This->lock.DebugInfo->Spare[0] = 0;
88         DeleteCriticalSection(&This->lock);
89         HeapFree(GetProcessHeap(), 0, This);
90     }
91     return ref;
92 }
93
94 static HRESULT WINAPI StreamOnMemory_Read(IStream *iface,
95     void *pv, ULONG cb, ULONG *pcbRead)
96 {
97     StreamOnMemory *This = (StreamOnMemory*)iface;
98     ULONG uBytesRead;
99     TRACE("(%p)\n", This);
100
101     if (!pv) return E_INVALIDARG;
102
103     EnterCriticalSection(&This->lock);
104     uBytesRead = min(cb, This->dwMemsize - This->dwCurPos);
105     memcpy(pv, This->pbMemory + This->dwCurPos, uBytesRead);
106     This->dwCurPos += uBytesRead;
107     LeaveCriticalSection(&This->lock);
108
109     if (pcbRead) *pcbRead = uBytesRead;
110
111     return S_OK;
112 }
113
114 static HRESULT WINAPI StreamOnMemory_Write(IStream *iface,
115     void const *pv, ULONG cb, ULONG *pcbWritten)
116 {
117     StreamOnMemory *This = (StreamOnMemory*)iface;
118     HRESULT hr;
119     TRACE("(%p)\n", This);
120
121     if (!pv) return E_INVALIDARG;
122
123     EnterCriticalSection(&This->lock);
124     if (cb > This->dwMemsize - This->dwCurPos) {
125         hr = STG_E_MEDIUMFULL;
126     }
127     else {
128         memcpy(This->pbMemory + This->dwCurPos, pv, cb);
129         This->dwCurPos += cb;
130         hr = S_OK;
131         if (pcbWritten) *pcbWritten = cb;
132     }
133     LeaveCriticalSection(&This->lock);
134
135     return hr;
136 }
137
138 static HRESULT WINAPI StreamOnMemory_Seek(IStream *iface,
139     LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
140 {
141     StreamOnMemory *This = (StreamOnMemory*)iface;
142     LARGE_INTEGER NewPosition;
143     HRESULT hr=S_OK;
144     TRACE("(%p)\n", This);
145
146     EnterCriticalSection(&This->lock);
147     if (dwOrigin == STREAM_SEEK_SET) NewPosition.QuadPart = dlibMove.QuadPart;
148     else if (dwOrigin == STREAM_SEEK_CUR) NewPosition.QuadPart = This->dwCurPos + dlibMove.QuadPart;
149     else if (dwOrigin == STREAM_SEEK_END) NewPosition.QuadPart = This->dwMemsize + dlibMove.QuadPart;
150     else hr = E_INVALIDARG;
151
152     if (SUCCEEDED(hr)) {
153         if (NewPosition.u.HighPart) hr = HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
154         else if (NewPosition.QuadPart > This->dwMemsize) hr = E_INVALIDARG;
155         else if (NewPosition.QuadPart < 0) hr = E_INVALIDARG;
156     }
157
158     if (SUCCEEDED(hr)) {
159         This->dwCurPos = NewPosition.u.LowPart;
160
161         if(plibNewPosition) plibNewPosition->QuadPart = This->dwCurPos;
162     }
163     LeaveCriticalSection(&This->lock);
164
165     return hr;
166 }
167
168 /* SetSize isn't implemented in the native windowscodecs DLL either */
169 static HRESULT WINAPI StreamOnMemory_SetSize(IStream *iface,
170     ULARGE_INTEGER libNewSize)
171 {
172     TRACE("(%p)\n", iface);
173     return E_NOTIMPL;
174 }
175
176 /* CopyTo isn't implemented in the native windowscodecs DLL either */
177 static HRESULT WINAPI StreamOnMemory_CopyTo(IStream *iface,
178     IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
179 {
180     TRACE("(%p)\n", iface);
181     return E_NOTIMPL;
182 }
183
184 /* Commit isn't implemented in the native windowscodecs DLL either */
185 static HRESULT WINAPI StreamOnMemory_Commit(IStream *iface,
186     DWORD grfCommitFlags)
187 {
188     TRACE("(%p)\n", iface);
189     return E_NOTIMPL;
190 }
191
192 /* Revert isn't implemented in the native windowscodecs DLL either */
193 static HRESULT WINAPI StreamOnMemory_Revert(IStream *iface)
194 {
195     TRACE("(%p)\n", iface);
196     return E_NOTIMPL;
197 }
198
199 /* LockRegion isn't implemented in the native windowscodecs DLL either */
200 static HRESULT WINAPI StreamOnMemory_LockRegion(IStream *iface,
201     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
202 {
203     TRACE("(%p)\n", iface);
204     return E_NOTIMPL;
205 }
206
207 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */
208 static HRESULT WINAPI StreamOnMemory_UnlockRegion(IStream *iface,
209     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
210 {
211     TRACE("(%p)\n", iface);
212     return E_NOTIMPL;
213 }
214
215 static HRESULT WINAPI StreamOnMemory_Stat(IStream *iface,
216     STATSTG *pstatstg, DWORD grfStatFlag)
217 {
218     StreamOnMemory *This = (StreamOnMemory*)iface;
219     TRACE("(%p)\n", This);
220
221     if (!pstatstg) return E_INVALIDARG;
222
223     ZeroMemory(pstatstg, sizeof(STATSTG));
224     pstatstg->type = STGTY_STREAM;
225     pstatstg->cbSize.QuadPart = This->dwMemsize;
226
227     return S_OK;
228 }
229
230 /* Clone isn't implemented in the native windowscodecs DLL either */
231 static HRESULT WINAPI StreamOnMemory_Clone(IStream *iface,
232     IStream **ppstm)
233 {
234     TRACE("(%p)\n", iface);
235     return E_NOTIMPL;
236 }
237
238
239 const IStreamVtbl StreamOnMemory_Vtbl =
240 {
241     /*** IUnknown methods ***/
242     StreamOnMemory_QueryInterface,
243     StreamOnMemory_AddRef,
244     StreamOnMemory_Release,
245     /*** ISequentialStream methods ***/
246     StreamOnMemory_Read,
247     StreamOnMemory_Write,
248     /*** IStream methods ***/
249     StreamOnMemory_Seek,
250     StreamOnMemory_SetSize,
251     StreamOnMemory_CopyTo,
252     StreamOnMemory_Commit,
253     StreamOnMemory_Revert,
254     StreamOnMemory_LockRegion,
255     StreamOnMemory_UnlockRegion,
256     StreamOnMemory_Stat,
257     StreamOnMemory_Clone,
258 };
259
260 /******************************************
261  * IWICStream implementation
262  *
263  */
264 typedef struct IWICStreamImpl
265 {
266     const IWICStreamVtbl *lpVtbl;
267     LONG ref;
268
269     IStream *pStream;
270 } IWICStreamImpl;
271
272 static HRESULT WINAPI IWICStreamImpl_QueryInterface(IWICStream *iface,
273     REFIID iid, void **ppv)
274 {
275     IWICStreamImpl *This = (IWICStreamImpl*)iface;
276     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
277
278     if (!ppv) return E_INVALIDARG;
279
280     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) ||
281         IsEqualIID(&IID_ISequentialStream, iid) || IsEqualIID(&IID_IWICStream, iid))
282     {
283         *ppv = This;
284         IUnknown_AddRef((IUnknown*)*ppv);
285         return S_OK;
286     }
287     else
288     {
289         *ppv = NULL;
290         return E_NOINTERFACE;
291     }
292 }
293
294 static ULONG WINAPI IWICStreamImpl_AddRef(IWICStream *iface)
295 {
296     IWICStreamImpl *This = (IWICStreamImpl*)iface;
297     ULONG ref = InterlockedIncrement(&This->ref);
298
299     TRACE("(%p) refcount=%u\n", iface, ref);
300
301     return ref;
302 }
303
304 static ULONG WINAPI IWICStreamImpl_Release(IWICStream *iface)
305 {
306     IWICStreamImpl *This = (IWICStreamImpl*)iface;
307     ULONG ref = InterlockedDecrement(&This->ref);
308
309     TRACE("(%p) refcount=%u\n", iface, ref);
310
311     if (ref == 0) {
312         if (This->pStream) IStream_Release(This->pStream);
313         HeapFree(GetProcessHeap(), 0, This);
314     }
315     return ref;
316 }
317
318 static HRESULT WINAPI IWICStreamImpl_Read(IWICStream *iface,
319     void *pv, ULONG cb, ULONG *pcbRead)
320 {
321     IWICStreamImpl *This = (IWICStreamImpl*)iface;
322     TRACE("(%p): relay\n", This);
323
324     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
325     return IStream_Read(This->pStream, pv, cb, pcbRead);
326 }
327
328 static HRESULT WINAPI IWICStreamImpl_Write(IWICStream *iface,
329     void const *pv, ULONG cb, ULONG *pcbWritten)
330 {
331     IWICStreamImpl *This = (IWICStreamImpl*)iface;
332     TRACE("(%p): relay\n", This);
333
334     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
335     return IStream_Write(This->pStream, pv, cb, pcbWritten);
336 }
337
338 static HRESULT WINAPI IWICStreamImpl_Seek(IWICStream *iface,
339     LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
340 {
341     IWICStreamImpl *This = (IWICStreamImpl*)iface;
342     TRACE("(%p): relay\n", This);
343
344     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
345     return IStream_Seek(This->pStream, dlibMove, dwOrigin, plibNewPosition);
346 }
347
348 static HRESULT WINAPI IWICStreamImpl_SetSize(IWICStream *iface,
349     ULARGE_INTEGER libNewSize)
350 {
351     IWICStreamImpl *This = (IWICStreamImpl*)iface;
352     TRACE("(%p): relay\n", This);
353
354     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
355     return IStream_SetSize(This->pStream, libNewSize);
356 }
357
358 static HRESULT WINAPI IWICStreamImpl_CopyTo(IWICStream *iface,
359     IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
360 {
361     IWICStreamImpl *This = (IWICStreamImpl*)iface;
362     TRACE("(%p): relay\n", This);
363
364     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
365     return IStream_CopyTo(This->pStream, pstm, cb, pcbRead, pcbWritten);
366 }
367
368 static HRESULT WINAPI IWICStreamImpl_Commit(IWICStream *iface,
369     DWORD grfCommitFlags)
370 {
371     IWICStreamImpl *This = (IWICStreamImpl*)iface;
372     TRACE("(%p): relay\n", This);
373
374     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
375     return IStream_Commit(This->pStream, grfCommitFlags);
376 }
377
378 static HRESULT WINAPI IWICStreamImpl_Revert(IWICStream *iface)
379 {
380     IWICStreamImpl *This = (IWICStreamImpl*)iface;
381     TRACE("(%p): relay\n", This);
382
383     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
384     return IStream_Revert(This->pStream);
385 }
386
387 static HRESULT WINAPI IWICStreamImpl_LockRegion(IWICStream *iface,
388     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
389 {
390     IWICStreamImpl *This = (IWICStreamImpl*)iface;
391     TRACE("(%p): relay\n", This);
392
393     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
394     return IStream_LockRegion(This->pStream, libOffset, cb, dwLockType);
395 }
396
397 static HRESULT WINAPI IWICStreamImpl_UnlockRegion(IWICStream *iface,
398     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
399 {
400     IWICStreamImpl *This = (IWICStreamImpl*)iface;
401     TRACE("(%p): relay\n", This);
402
403     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
404     return IStream_UnlockRegion(This->pStream, libOffset, cb, dwLockType);
405 }
406
407 static HRESULT WINAPI IWICStreamImpl_Stat(IWICStream *iface,
408     STATSTG *pstatstg, DWORD grfStatFlag)
409 {
410     IWICStreamImpl *This = (IWICStreamImpl*)iface;
411     TRACE("(%p): relay\n", This);
412
413     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
414     return IStream_Stat(This->pStream, pstatstg, grfStatFlag);
415 }
416
417 static HRESULT WINAPI IWICStreamImpl_Clone(IWICStream *iface,
418     IStream **ppstm)
419 {
420     IWICStreamImpl *This = (IWICStreamImpl*)iface;
421     TRACE("(%p): relay\n", This);
422
423     if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
424     return IStream_Clone(This->pStream, ppstm);
425 }
426
427 static HRESULT WINAPI IWICStreamImpl_InitializeFromIStream(IWICStream *iface,
428     IStream *pIStream)
429 {
430     FIXME("(%p): stub\n", iface);
431     return E_NOTIMPL;
432 }
433
434 static HRESULT WINAPI IWICStreamImpl_InitializeFromFilename(IWICStream *iface,
435     LPCWSTR wzFileName, DWORD dwDesiredAccess)
436 {
437     FIXME("(%p): stub\n", iface);
438     return E_NOTIMPL;
439 }
440
441 /******************************************
442  * IWICStream_InitializeFromMemory
443  *
444  * Initializes the internal IStream object to retrieve its data from a memory chunk.
445  *
446  * PARAMS
447  *   pbBuffer     [I] pointer to the memory chunk
448  *   cbBufferSize [I] number of bytes to use from the memory chunk
449  *
450  * RETURNS
451  *   SUCCESS: S_OK
452  *   FAILURE: E_INVALIDARG, if pbBuffer is NULL
453  *            E_OUTOFMEMORY, if we run out of memory
454  *            WINCODEC_ERR_WRONGSTATE, if the IStream object has already been initialized before
455  *
456  */
457 static HRESULT WINAPI IWICStreamImpl_InitializeFromMemory(IWICStream *iface,
458     BYTE *pbBuffer, DWORD cbBufferSize)
459 {
460     IWICStreamImpl *This = (IWICStreamImpl*)iface;
461     StreamOnMemory *pObject;
462     TRACE("(%p,%p)\n", iface, pbBuffer);
463
464     if (!pbBuffer) return E_INVALIDARG;
465     if (This->pStream) return WINCODEC_ERR_WRONGSTATE;
466
467     pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnMemory));
468     if (!pObject) return E_OUTOFMEMORY;
469
470     pObject->lpVtbl = &StreamOnMemory_Vtbl;
471     pObject->ref = 1;
472     pObject->pbMemory = pbBuffer;
473     pObject->dwMemsize = cbBufferSize;
474     pObject->dwCurPos = 0;
475     InitializeCriticalSection(&pObject->lock);
476     pObject->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": StreamOnMemory.lock");
477
478     if (InterlockedCompareExchangePointer((void**)&This->pStream, pObject, NULL))
479     {
480         /* Some other thread set the stream first. */
481         IStream_Release((IStream*)pObject);
482         return WINCODEC_ERR_WRONGSTATE;
483     }
484
485     return S_OK;
486 }
487
488 static HRESULT WINAPI IWICStreamImpl_InitializeFromIStreamRegion(IWICStream *iface,
489     IStream *pIStream, ULARGE_INTEGER ulOffset, ULARGE_INTEGER ulMaxSize)
490 {
491     FIXME("(%p): stub\n", iface);
492     return E_NOTIMPL;
493 }
494
495
496 const IWICStreamVtbl WICStream_Vtbl =
497 {
498     /*** IUnknown methods ***/
499     IWICStreamImpl_QueryInterface,
500     IWICStreamImpl_AddRef,
501     IWICStreamImpl_Release,
502     /*** ISequentialStream methods ***/
503     IWICStreamImpl_Read,
504     IWICStreamImpl_Write,
505     /*** IStream methods ***/
506     IWICStreamImpl_Seek,
507     IWICStreamImpl_SetSize,
508     IWICStreamImpl_CopyTo,
509     IWICStreamImpl_Commit,
510     IWICStreamImpl_Revert,
511     IWICStreamImpl_LockRegion,
512     IWICStreamImpl_UnlockRegion,
513     IWICStreamImpl_Stat,
514     IWICStreamImpl_Clone,
515     /*** IWICStream methods ***/
516     IWICStreamImpl_InitializeFromIStream,
517     IWICStreamImpl_InitializeFromFilename,
518     IWICStreamImpl_InitializeFromMemory,
519     IWICStreamImpl_InitializeFromIStreamRegion,
520 };
521
522 HRESULT StreamImpl_Create(IWICStream **stream)
523 {
524     IWICStreamImpl *pObject;
525
526     if( !stream ) return E_INVALIDARG;
527
528     pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(IWICStreamImpl));
529     if( !pObject ) {
530         *stream = NULL;
531         return E_OUTOFMEMORY;
532     }
533
534     pObject->lpVtbl = &WICStream_Vtbl;
535     pObject->ref = 1;
536     pObject->pStream = NULL;
537
538     *stream = (IWICStream*)pObject;
539
540     return S_OK;
541 }