blob: c59a9d27861ca9a6c8d52418de80a76aa88bcc89 [file] [log] [blame]
Tony Wasserkaa18fc6e2009-08-18 17:48:49 +02001/*
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
29WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
30
31/******************************************
Tony Wasserkaaf6ece92009-08-21 12:02:10 +020032 * StreamOnMemory implementation
33 *
34 * Used by IWICStream_InitializeFromMemory
35 *
36 */
37typedef struct StreamOnMemory {
38 const IStreamVtbl *lpVtbl;
39 LONG ref;
Tony Wasserkabb83fb22009-08-21 11:07:37 +020040
41 BYTE *pbMemory;
42 DWORD dwMemsize;
43 DWORD dwCurPos;
Tony Wasserkaaf6ece92009-08-21 12:02:10 +020044} StreamOnMemory;
45
46static 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
67static 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
77static 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
90static HRESULT WINAPI StreamOnMemory_Read(IStream *iface,
91 void *pv, ULONG cb, ULONG *pcbRead)
92{
Tony Wasserkabb83fb22009-08-21 11:07:37 +020093 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;
Tony Wasserkaaf6ece92009-08-21 12:02:10 +0200105}
106
107static HRESULT WINAPI StreamOnMemory_Write(IStream *iface,
108 void const *pv, ULONG cb, ULONG *pcbWritten)
109{
Tony Wasserka0b6df192009-08-21 11:08:10 +0200110 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;
Tony Wasserkaaf6ece92009-08-21 12:02:10 +0200123}
124
125static HRESULT WINAPI StreamOnMemory_Seek(IStream *iface,
126 LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
127{
Tony Wasserka23952022009-08-21 11:11:39 +0200128 StreamOnMemory *This = (StreamOnMemory*)iface;
129 LARGE_INTEGER NewPosition;
130 TRACE("(%p)\n", This);
131
Tony Wasserka23952022009-08-21 11:11:39 +0200132 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
Alexandre Julliard77c39972009-09-25 15:57:41 +0200137 if (NewPosition.u.HighPart) return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
Tony Wasserka23952022009-08-21 11:11:39 +0200138 if (NewPosition.QuadPart > This->dwMemsize) return E_INVALIDARG;
139 if (NewPosition.QuadPart < 0) return E_INVALIDARG;
Francois Gouget2dd9b1d2009-08-31 11:52:57 +0200140 This->dwCurPos = NewPosition.u.LowPart;
Tony Wasserka23952022009-08-21 11:11:39 +0200141
142 if(plibNewPosition) plibNewPosition->QuadPart = This->dwCurPos;
143 return S_OK;
Tony Wasserkaaf6ece92009-08-21 12:02:10 +0200144}
145
146/* SetSize isn't implemented in the native windowscodecs DLL either */
147static 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 */
155static 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 */
163static 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 */
171static 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 */
178static 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 */
186static 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
193static HRESULT WINAPI StreamOnMemory_Stat(IStream *iface,
194 STATSTG *pstatstg, DWORD grfStatFlag)
195{
Tony Wasserkaa3edb732009-08-21 11:12:03 +0200196 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;
Tony Wasserkaaf6ece92009-08-21 12:02:10 +0200206}
207
208/* Clone isn't implemented in the native windowscodecs DLL either */
209static HRESULT WINAPI StreamOnMemory_Clone(IStream *iface,
210 IStream **ppstm)
211{
212 TRACE("(%p)\n", iface);
213 return E_NOTIMPL;
214}
215
216
217const 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/******************************************
Tony Wasserkaa18fc6e2009-08-18 17:48:49 +0200239 * IWICStream implementation
240 *
241 */
242typedef struct IWICStreamImpl
243{
244 const IWICStreamVtbl *lpVtbl;
245 LONG ref;
246
247 IStream *pStream;
248} IWICStreamImpl;
249
250static 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
272static 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
282static 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
296static 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
306static 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
316static 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
326static 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
336static 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
346static 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
356static 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
365static 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
375static 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
385static 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
395static 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
405static HRESULT WINAPI IWICStreamImpl_InitializeFromIStream(IWICStream *iface,
406 IStream *pIStream)
407{
408 FIXME("(%p): stub\n", iface);
409 return E_NOTIMPL;
410}
411
412static HRESULT WINAPI IWICStreamImpl_InitializeFromFilename(IWICStream *iface,
413 LPCWSTR wzFileName, DWORD dwDesiredAccess)
414{
415 FIXME("(%p): stub\n", iface);
416 return E_NOTIMPL;
417}
418
Tony Wasserkaaf6ece92009-08-21 12:02:10 +0200419/******************************************
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 */
Tony Wasserkaa18fc6e2009-08-18 17:48:49 +0200435static HRESULT WINAPI IWICStreamImpl_InitializeFromMemory(IWICStream *iface,
436 BYTE *pbBuffer, DWORD cbBufferSize)
437{
Tony Wasserkaaf6ece92009-08-21 12:02:10 +0200438 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;
Tony Wasserkabb83fb22009-08-21 11:07:37 +0200450 pObject->pbMemory = pbBuffer;
451 pObject->dwMemsize = cbBufferSize;
452 pObject->dwCurPos = 0;
Tony Wasserkaaf6ece92009-08-21 12:02:10 +0200453
454 This->pStream = (IStream*)pObject;
455 return S_OK;
Tony Wasserkaa18fc6e2009-08-18 17:48:49 +0200456}
457
458static 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
466const 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
492HRESULT 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}