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