kernel32: Add support for completion routine invocation in ReadDirectoryChangesW.
[wine] / dlls / dmloader / loaderstream.c
1 /* IDirectMusicLoaderFileStream
2  * IDirectMusicLoaderResourceStream
3  * IDirectMusicLoaderGenericStream
4  *
5  * Copyright (C) 2003-2004 Rok Mandeljc
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22
23 /* SIDE NOTES:
24  * After extensive testing and structure dumping I came to a conclusion that
25  * DirectMusic as in present state implements three types of streams:
26  *  1. IDirectMusicLoaderFileStream: stream that was most obvious, since 
27  *     it's used for loading from files; it is sort of wrapper around 
28  *     CreateFile, ReadFile, WriteFile and SetFilePointer and it supports 
29  *     both read and write
30  *  2. IDirectMusicLoaderResourceStream: a stream that had to exist, since 
31  *     according to MSDN, IDirectMusicLoader supports loading from resource 
32  *     as well; in this case, data is represented as a big chunk of bytes, 
33  *     from which we "read" (copy) data and keep the trace of our position; 
34  *      it supports read only
35  *  3. IDirectMusicLoaderGenericStream: this one was the most problematic, 
36  *     since I thought it was URL-related; besides, there's no obvious need 
37  *     for it, since input streams can simply be cloned, lest loading from 
38  *     stream is requested; but if one really thinks about it, input stream 
39  *     could be none of 1. or 2.; in this case, a wrapper that offers
40  *     IDirectMusicGetLoader interface would be nice, and this is what this 
41  *     stream is; as such, all functions are supported, as long as underlying 
42  *     ("low-level") stream supports them
43  *
44  * - Rok Mandeljc; 24. april, 2004
45 */
46
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
49
50 #include "dmloader_private.h"
51
52 WINE_DEFAULT_DEBUG_CHANNEL(dmloader);
53 WINE_DECLARE_DEBUG_CHANNEL(dmfileraw);
54
55 static ULONG WINAPI IDirectMusicLoaderFileStream_IStream_AddRef (LPSTREAM iface);
56 static ULONG WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface);
57 static ULONG WINAPI IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface);
58 static ULONG WINAPI IDirectMusicLoaderResourceStream_IStream_AddRef (LPSTREAM iface);
59 static ULONG WINAPI IDirectMusicLoaderGenericStream_IStream_AddRef (LPSTREAM iface);
60 static ULONG WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface);
61
62
63 /*****************************************************************************
64  * IDirectMusicLoaderFileStream implementation
65  */
66 /* Custom : */
67
68 static void IDirectMusicLoaderFileStream_Detach (LPSTREAM iface) {
69     ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface);
70     TRACE("(%p)\n", This);
71     if (This->hFile != INVALID_HANDLE_VALUE) CloseHandle(This->hFile);
72     This->wzFileName[0] = '\0';
73 }
74
75 HRESULT WINAPI IDirectMusicLoaderFileStream_Attach (LPSTREAM iface, LPCWSTR wzFile, LPDIRECTMUSICLOADER8 pLoader) {
76         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface);
77     TRACE("(%p, %s, %p)\n", This, debugstr_w(wzFile), pLoader);
78     IDirectMusicLoaderFileStream_Detach (iface);
79     This->hFile = CreateFileW (wzFile, (GENERIC_READ | GENERIC_WRITE), (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
80     if (This->hFile == INVALID_HANDLE_VALUE) {
81         WARN(": failed\n");
82         return DMUS_E_LOADER_FAILEDOPEN;
83     }
84     /* create IDirectMusicGetLoader */
85     This->pLoader = pLoader;
86     lstrcpynW (This->wzFileName, wzFile, MAX_PATH);
87     TRACE(": succeeded\n");
88     return S_OK;
89 }
90
91
92 /* IUnknown/IStream part: */
93 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_QueryInterface (LPSTREAM iface, REFIID riid, void** ppobj) {
94         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface);
95         
96         TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj);
97         if (IsEqualIID (riid, &IID_IUnknown) ||
98                 IsEqualIID (riid, &IID_IStream)) {
99                 *ppobj = &This->StreamVtbl;
100                 IDirectMusicLoaderFileStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl);
101                 return S_OK;
102         } else if (IsEqualIID (riid, &IID_IDirectMusicGetLoader)) {
103                 *ppobj = &This->GetLoaderVtbl;
104                 IDirectMusicLoaderFileStream_IDirectMusicGetLoader_AddRef ((LPDIRECTMUSICGETLOADER)&This->GetLoaderVtbl);               
105                 return S_OK;
106         }
107
108         WARN(": not found\n");
109         return E_NOINTERFACE;
110 }
111
112 static ULONG WINAPI IDirectMusicLoaderFileStream_IStream_AddRef (LPSTREAM iface) {
113         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface);
114         TRACE("(%p): AddRef from %d\n", This, This->dwRef);
115         return InterlockedIncrement (&This->dwRef);
116 }
117
118 static ULONG WINAPI IDirectMusicLoaderFileStream_IStream_Release (LPSTREAM iface) {
119         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface);
120         
121         DWORD dwRef = InterlockedDecrement (&This->dwRef);
122         TRACE("(%p): ReleaseRef to %d\n", This, dwRef);
123         if (dwRef == 0) {
124                 if (This->hFile)
125                         IDirectMusicLoaderFileStream_Detach (iface);
126                 HeapFree (GetProcessHeap(), 0, This);
127         }
128         
129         return dwRef;
130 }
131
132 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Read (LPSTREAM iface, void* pv, ULONG cb, ULONG* pcbRead) {
133         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface);
134     ULONG cbRead;
135         
136         TRACE_(dmfileraw)("(%p, %p, 0x%08X, %p)\n", This, pv, cb, pcbRead);
137     if (This->hFile == INVALID_HANDLE_VALUE) return E_FAIL;
138     if (pcbRead == NULL) pcbRead = &cbRead;
139     if (!ReadFile (This->hFile, pv, cb, pcbRead, NULL) || *pcbRead != cb) return E_FAIL;
140         
141         TRACE_(dmfileraw)(": data (size = 0x%08X): %s\n", *pcbRead, debugstr_an(pv, *pcbRead));
142     return S_OK;
143 }
144
145 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Seek (LPSTREAM iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) {
146         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface);
147     LARGE_INTEGER liNewPos;
148         
149     TRACE_(dmfileraw)("(%p, %s, %s, %p)\n", This, wine_dbgstr_longlong(dlibMove.QuadPart), resolve_STREAM_SEEK(dwOrigin), plibNewPosition);
150
151     if (This->hFile == INVALID_HANDLE_VALUE) return E_FAIL;
152
153     liNewPos.u.HighPart = dlibMove.u.HighPart;
154     liNewPos.u.LowPart = SetFilePointer (This->hFile, dlibMove.u.LowPart, &liNewPos.u.HighPart, dwOrigin);
155
156     if (liNewPos.u.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) return E_FAIL;
157     if (plibNewPosition) plibNewPosition->QuadPart = liNewPos.QuadPart;
158     
159     return S_OK;
160 }
161
162 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Clone (LPSTREAM iface, IStream** ppstm) {
163         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface);
164         LPSTREAM pOther = NULL;
165         HRESULT result;
166
167         TRACE("(%p, %p)\n", iface, ppstm);
168         result = DMUSIC_CreateDirectMusicLoaderFileStream ((LPVOID*)&pOther);
169         if (FAILED(result)) return result;
170         if (This->hFile != INVALID_HANDLE_VALUE) {
171                 ULARGE_INTEGER ullCurrentPosition;
172                 result = IDirectMusicLoaderFileStream_Attach (pOther, This->wzFileName, This->pLoader);
173                 if (SUCCEEDED(result)) {
174                         LARGE_INTEGER liZero;
175                         liZero.QuadPart = 0;
176                         result = IDirectMusicLoaderFileStream_IStream_Seek (iface, liZero, STREAM_SEEK_CUR, &ullCurrentPosition); /* get current position in current stream */
177         }
178                 if (SUCCEEDED(result)) {
179                         LARGE_INTEGER liNewPosition;
180                         liNewPosition.QuadPart = ullCurrentPosition.QuadPart;
181                         result = IDirectMusicLoaderFileStream_IStream_Seek (pOther, liNewPosition, STREAM_SEEK_SET, &ullCurrentPosition);
182                 }
183                 if (FAILED(result)) {
184                         TRACE(": failed\n");
185                         IDirectMusicLoaderFileStream_IStream_Release (pOther);
186                         return result;
187                 }
188         }
189         TRACE(": succeeded\n");
190         *ppstm = pOther;
191         return S_OK;
192 }
193
194 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Write (LPSTREAM iface, const void* pv, ULONG cb, ULONG* pcbWritten) {
195         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface);
196     ULONG cbWrite;
197         
198         TRACE_(dmfileraw)("(%p, %p, 0x%08X, %p)\n", This, pv, cb, pcbWritten);
199     if (This->hFile == INVALID_HANDLE_VALUE) return E_FAIL;
200     if (pcbWritten == NULL) pcbWritten = &cbWrite;
201     if (!WriteFile (This->hFile, pv, cb, pcbWritten, NULL) || *pcbWritten != cb) return E_FAIL;
202         
203         TRACE_(dmfileraw)(": data (size = 0x%08X): %s\n", *pcbWritten, debugstr_an(pv, *pcbWritten));
204     return S_OK;
205 }
206
207 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_SetSize (LPSTREAM iface, ULARGE_INTEGER libNewSize) {
208         ERR(": should not be needed\n");
209     return E_NOTIMPL;
210 }
211
212 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_CopyTo (LPSTREAM iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) {
213         ERR(": should not be needed\n");
214     return E_NOTIMPL;
215 }
216
217 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Commit (LPSTREAM iface, DWORD grfCommitFlags) {
218         ERR(": should not be needed\n");
219     return E_NOTIMPL;
220 }
221
222 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Revert (LPSTREAM iface) {
223         ERR(": should not be needed\n");
224     return E_NOTIMPL;
225 }
226
227 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_LockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {
228         ERR(": should not be needed\n");
229     return E_NOTIMPL;
230 }
231
232 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_UnlockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {
233         ERR(": should not be needed\n");
234     return E_NOTIMPL;
235 }
236
237 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Stat (LPSTREAM iface, STATSTG* pstatstg, DWORD grfStatFlag) {
238         ERR(": should not be needed\n");
239     return E_NOTIMPL;
240 }
241
242 static const IStreamVtbl DirectMusicLoaderFileStream_Stream_Vtbl = {
243         IDirectMusicLoaderFileStream_IStream_QueryInterface,
244         IDirectMusicLoaderFileStream_IStream_AddRef,
245         IDirectMusicLoaderFileStream_IStream_Release,
246         IDirectMusicLoaderFileStream_IStream_Read,
247         IDirectMusicLoaderFileStream_IStream_Write,
248         IDirectMusicLoaderFileStream_IStream_Seek,
249         IDirectMusicLoaderFileStream_IStream_SetSize,
250         IDirectMusicLoaderFileStream_IStream_CopyTo,
251         IDirectMusicLoaderFileStream_IStream_Commit,
252         IDirectMusicLoaderFileStream_IStream_Revert,
253         IDirectMusicLoaderFileStream_IStream_LockRegion,
254         IDirectMusicLoaderFileStream_IStream_UnlockRegion,
255         IDirectMusicLoaderFileStream_IStream_Stat,
256         IDirectMusicLoaderFileStream_IStream_Clone
257 };
258
259 /* IDirectMusicGetLoader part: */
260 static HRESULT WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj) {
261         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface);
262         return IDirectMusicLoaderFileStream_IStream_QueryInterface ((LPSTREAM)&This->StreamVtbl, riid, ppobj);
263 }
264
265 static ULONG WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface) {
266         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface);
267         return IDirectMusicLoaderFileStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl);
268 }
269
270 static ULONG WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface) {
271         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface);
272         return IDirectMusicLoaderFileStream_IStream_Release ((LPSTREAM)&This->StreamVtbl);
273 }
274
275 static HRESULT WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader) {
276         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface);
277
278         TRACE("(%p, %p)\n", This, ppLoader);
279         *ppLoader = (LPDIRECTMUSICLOADER)This->pLoader;
280         IDirectMusicLoader8_AddRef ((LPDIRECTMUSICLOADER8)*ppLoader);
281         
282         return S_OK;
283 }
284
285 static const IDirectMusicGetLoaderVtbl DirectMusicLoaderFileStream_GetLoader_Vtbl = {
286         IDirectMusicLoaderFileStream_IDirectMusicGetLoader_QueryInterface,
287         IDirectMusicLoaderFileStream_IDirectMusicGetLoader_AddRef,
288         IDirectMusicLoaderFileStream_IDirectMusicGetLoader_Release,
289         IDirectMusicLoaderFileStream_IDirectMusicGetLoader_GetLoader
290 };
291
292 HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderFileStream (LPVOID* ppobj) {
293         IDirectMusicLoaderFileStream *obj;
294
295         TRACE("(%p)\n", ppobj);
296         obj = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderFileStream));
297         if (NULL == obj) {
298                 *ppobj = NULL;
299                 return E_OUTOFMEMORY;
300         }
301         obj->StreamVtbl = &DirectMusicLoaderFileStream_Stream_Vtbl;
302         obj->GetLoaderVtbl = &DirectMusicLoaderFileStream_GetLoader_Vtbl;
303         obj->dwRef = 0; /* will be inited with QueryInterface */
304
305         return IDirectMusicLoaderFileStream_IStream_QueryInterface ((LPSTREAM)&obj->StreamVtbl, &IID_IStream, ppobj);
306 }
307
308
309 /*****************************************************************************
310  * IDirectMusicLoaderResourceStream implementation
311  */
312 /* Custom : */
313
314 static void IDirectMusicLoaderResourceStream_Detach (LPSTREAM iface) {
315         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface);
316         TRACE("(%p)\n", This);
317
318         This->pbMemData = NULL;
319         This->llMemLength = 0;
320 }
321
322 HRESULT WINAPI IDirectMusicLoaderResourceStream_Attach (LPSTREAM iface, LPBYTE pbMemData, LONGLONG llMemLength, LONGLONG llPos, LPDIRECTMUSICLOADER8 pLoader) {
323         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface);
324     
325         TRACE("(%p, %p, %s, %s, %p)\n", This, pbMemData, wine_dbgstr_longlong(llMemLength), wine_dbgstr_longlong(llPos), pLoader);
326         if (!pbMemData || !llMemLength) {
327                 WARN(": invalid pbMemData or llMemLength\n");
328                 return E_FAIL;
329         }
330         IDirectMusicLoaderResourceStream_Detach (iface);
331         This->pbMemData = pbMemData;
332         This->llMemLength = llMemLength;
333         This->llPos = llPos;
334         This->pLoader = pLoader;
335         
336     return S_OK;
337 }
338
339
340 /* IUnknown/IStream part: */
341 static HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_QueryInterface (LPSTREAM iface, REFIID riid, void** ppobj) {
342         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface);
343         
344         TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj);
345         if (IsEqualIID (riid, &IID_IUnknown) ||
346                 IsEqualIID (riid, &IID_IStream)) {
347                 *ppobj = &This->StreamVtbl;
348                 IDirectMusicLoaderResourceStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl);
349                 return S_OK;
350         } else if (IsEqualIID (riid, &IID_IDirectMusicGetLoader)) {
351                 *ppobj = &This->GetLoaderVtbl;
352                 IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_AddRef ((LPDIRECTMUSICGETLOADER)&This->GetLoaderVtbl);           
353                 return S_OK;
354         }
355
356         WARN(": not found\n");
357         return E_NOINTERFACE;
358 }
359
360 static ULONG WINAPI IDirectMusicLoaderResourceStream_IStream_AddRef (LPSTREAM iface) {
361         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface);
362         TRACE("(%p): AddRef from %d\n", This, This->dwRef);
363         return InterlockedIncrement (&This->dwRef);
364 }
365
366 static ULONG WINAPI IDirectMusicLoaderResourceStream_IStream_Release (LPSTREAM iface) {
367         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface);
368         
369         DWORD dwRef = InterlockedDecrement (&This->dwRef);
370         TRACE("(%p): ReleaseRef to %d\n", This, dwRef);
371         if (dwRef == 0) {
372                 IDirectMusicLoaderResourceStream_Detach (iface);
373                 HeapFree (GetProcessHeap(), 0, This);
374         }
375         
376         return dwRef;
377 }
378
379 static HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Read (LPSTREAM iface, void* pv, ULONG cb, ULONG* pcbRead) {
380         LPBYTE pByte;
381         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface);
382         
383         TRACE_(dmfileraw)("(%p, %p, 0x%08X, %p)\n", This, pv, cb, pcbRead);
384         if ((This->llPos + cb) > This->llMemLength) {
385                 WARN_(dmfileraw)(": requested size out of range\n");
386                 return E_FAIL;
387         }
388         
389         pByte = &This->pbMemData[This->llPos];
390         memcpy (pv, pByte, cb);
391         This->llPos += cb; /* move pointer */
392         /* FIXME: error checking would be nice */
393         if (pcbRead) *pcbRead = cb;
394         
395         TRACE_(dmfileraw)(": data (size = 0x%08X): %s\n", cb, debugstr_an(pv, cb));
396     return S_OK;
397 }
398
399 static HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Seek (LPSTREAM iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) {
400         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface);   
401         TRACE_(dmfileraw)("(%p, %s, %s, %p)\n", This, wine_dbgstr_longlong(dlibMove.QuadPart), resolve_STREAM_SEEK(dwOrigin), plibNewPosition);
402         
403         switch (dwOrigin) {
404                 case STREAM_SEEK_CUR: {
405                         if ((This->llPos + dlibMove.QuadPart) > This->llMemLength) {
406                                 WARN_(dmfileraw)(": requested offset out of range\n");
407                                 return E_FAIL;
408                         }
409                         break;
410                 }
411                 case STREAM_SEEK_SET: {
412                         if (dlibMove.QuadPart > This->llMemLength) {
413                                 WARN_(dmfileraw)(": requested offset out of range\n");
414                                 return E_FAIL;
415                         }
416                         /* set to the beginning of the stream */
417                         This->llPos = 0;
418                         break;
419                 }
420                 case STREAM_SEEK_END: {
421                         /* TODO: check if this is true... I do think offset should be negative in this case */
422                         if (dlibMove.QuadPart > 0) {
423                                 WARN_(dmfileraw)(": requested offset out of range\n");
424                                 return E_FAIL;
425                         }
426                         /* set to the end of the stream */
427                         This->llPos = This->llMemLength;
428                         break;
429                 }
430                 default: {
431                         ERR_(dmfileraw)(": invalid dwOrigin\n");
432                         return E_FAIL;
433                 }
434         }
435         /* now simply add */
436         This->llPos += dlibMove.QuadPart;
437
438         if (plibNewPosition) plibNewPosition->QuadPart = This->llPos;
439         
440     return S_OK;
441 }
442
443 static HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Clone (LPSTREAM iface, IStream** ppstm) {
444         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface);
445         LPSTREAM pOther = NULL;
446         HRESULT result;
447
448         TRACE("(%p, %p)\n", iface, ppstm);
449         result = DMUSIC_CreateDirectMusicLoaderResourceStream ((LPVOID*)&pOther);
450         if (FAILED(result)) return result;
451         
452         IDirectMusicLoaderResourceStream_Attach (pOther, This->pbMemData, This->llMemLength, This->llPos, This->pLoader);
453
454         TRACE(": succeeded\n");
455         *ppstm = pOther;
456         return S_OK;
457 }
458
459 static HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Write (LPSTREAM iface, const void* pv, ULONG cb, ULONG* pcbWritten) {
460         ERR(": should not be needed\n");
461     return E_NOTIMPL;
462 }
463
464 static HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_SetSize (LPSTREAM iface, ULARGE_INTEGER libNewSize) {
465         ERR(": should not be needed\n");
466     return E_NOTIMPL;
467 }
468
469 static HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_CopyTo (LPSTREAM iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) {
470         ERR(": should not be needed\n");
471     return E_NOTIMPL;
472 }
473
474 static HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Commit (LPSTREAM iface, DWORD grfCommitFlags) {
475         ERR(": should not be needed\n");
476     return E_NOTIMPL;
477 }
478
479 static HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Revert (LPSTREAM iface) {
480         ERR(": should not be needed\n");
481     return E_NOTIMPL;
482 }
483
484 static HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_LockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {
485         ERR(": should not be needed\n");
486     return E_NOTIMPL;
487 }
488
489 static HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_UnlockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {
490         ERR(": should not be needed\n");
491     return E_NOTIMPL;
492 }
493
494 static HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Stat (LPSTREAM iface, STATSTG* pstatstg, DWORD grfStatFlag) {
495         ERR(": should not be needed\n");
496     return E_NOTIMPL;
497 }
498
499 static const IStreamVtbl DirectMusicLoaderResourceStream_Stream_Vtbl = {
500         IDirectMusicLoaderResourceStream_IStream_QueryInterface,
501         IDirectMusicLoaderResourceStream_IStream_AddRef,
502         IDirectMusicLoaderResourceStream_IStream_Release,
503         IDirectMusicLoaderResourceStream_IStream_Read,
504         IDirectMusicLoaderResourceStream_IStream_Write,
505         IDirectMusicLoaderResourceStream_IStream_Seek,
506         IDirectMusicLoaderResourceStream_IStream_SetSize,
507         IDirectMusicLoaderResourceStream_IStream_CopyTo,
508         IDirectMusicLoaderResourceStream_IStream_Commit,
509         IDirectMusicLoaderResourceStream_IStream_Revert,
510         IDirectMusicLoaderResourceStream_IStream_LockRegion,
511         IDirectMusicLoaderResourceStream_IStream_UnlockRegion,
512         IDirectMusicLoaderResourceStream_IStream_Stat,
513         IDirectMusicLoaderResourceStream_IStream_Clone
514 };
515
516 /* IDirectMusicGetLoader part: */
517 static HRESULT WINAPI IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj) {
518         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, GetLoaderVtbl, iface);
519         return IDirectMusicLoaderResourceStream_IStream_QueryInterface ((LPSTREAM)&This->StreamVtbl, riid, ppobj);
520 }
521
522 static ULONG WINAPI IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface) {
523         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, GetLoaderVtbl, iface);
524         return IDirectMusicLoaderResourceStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl);
525 }
526
527 static ULONG WINAPI IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface) {
528         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, GetLoaderVtbl, iface);
529         return IDirectMusicLoaderResourceStream_IStream_Release ((LPSTREAM)&This->StreamVtbl);
530 }
531
532 static HRESULT WINAPI IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader) {
533         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, GetLoaderVtbl, iface);
534
535         TRACE("(%p, %p)\n", This, ppLoader);
536         *ppLoader = (LPDIRECTMUSICLOADER)This->pLoader;
537         IDirectMusicLoader8_AddRef ((LPDIRECTMUSICLOADER8)*ppLoader);
538         
539         return S_OK;
540 }
541
542 static const IDirectMusicGetLoaderVtbl DirectMusicLoaderResourceStream_GetLoader_Vtbl = {
543         IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_QueryInterface,
544         IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_AddRef,
545         IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_Release,
546         IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_GetLoader
547 };
548
549 HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderResourceStream (LPVOID* ppobj) {
550         IDirectMusicLoaderResourceStream *obj;
551
552         TRACE("(%p)\n", ppobj);
553         obj = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderResourceStream));
554         if (NULL == obj) {
555                 *ppobj = NULL;
556                 return E_OUTOFMEMORY;
557         }
558         obj->StreamVtbl = &DirectMusicLoaderResourceStream_Stream_Vtbl;
559         obj->GetLoaderVtbl = &DirectMusicLoaderResourceStream_GetLoader_Vtbl;
560         obj->dwRef = 0; /* will be inited with QueryInterface */
561
562         return IDirectMusicLoaderResourceStream_IStream_QueryInterface ((LPSTREAM)&obj->StreamVtbl, &IID_IStream, ppobj);
563 }
564
565
566 /*****************************************************************************
567  * IDirectMusicLoaderGenericStream implementation
568  */
569 /* Custom : */
570
571 static void IDirectMusicLoaderGenericStream_Detach (LPSTREAM iface) {
572         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
573
574         if (This->pStream)
575                 IStream_Release (This->pStream);
576         This->pStream = NULL;
577 }
578
579 HRESULT WINAPI IDirectMusicLoaderGenericStream_Attach (LPSTREAM iface, LPSTREAM pStream, LPDIRECTMUSICLOADER8 pLoader) {
580         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
581     
582         TRACE("(%p, %p, %p)\n", This, pStream, pLoader);
583         if (!pStream) {
584                 WARN(": invalid pStream\n");
585                 return E_FAIL;
586         }
587         if (!pLoader) {
588                 WARN(": invalid pLoader\n");
589                 return E_FAIL;
590         }       
591         
592         IDirectMusicLoaderGenericStream_Detach (iface);
593         IStream_Clone (pStream, &This->pStream);
594         This->pLoader = pLoader;
595         
596     return S_OK;
597 }
598
599
600 /* IUnknown/IStream part: */
601 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_QueryInterface (LPSTREAM iface, REFIID riid, void** ppobj) {
602         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
603         
604         TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj);
605         if (IsEqualIID (riid, &IID_IUnknown) ||
606                 IsEqualIID (riid, &IID_IStream)) {
607                 *ppobj = &This->StreamVtbl;
608                 IDirectMusicLoaderGenericStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl);
609                 return S_OK;
610         } else if (IsEqualIID (riid, &IID_IDirectMusicGetLoader)) {
611                 *ppobj = &This->GetLoaderVtbl;
612                 IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_AddRef ((LPDIRECTMUSICGETLOADER)&This->GetLoaderVtbl);            
613                 return S_OK;
614         }
615
616         WARN(": not found\n");
617         return E_NOINTERFACE;
618 }
619
620 static ULONG WINAPI IDirectMusicLoaderGenericStream_IStream_AddRef (LPSTREAM iface) {
621         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
622         TRACE("(%p): AddRef from %d\n", This, This->dwRef);
623         return InterlockedIncrement (&This->dwRef);
624 }
625
626 static ULONG WINAPI IDirectMusicLoaderGenericStream_IStream_Release (LPSTREAM iface) {
627         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
628         
629         DWORD dwRef = InterlockedDecrement (&This->dwRef);
630         TRACE("(%p): ReleaseRef to %d\n", This, dwRef);
631         if (dwRef == 0) {
632                 IDirectMusicLoaderGenericStream_Detach (iface);
633                 HeapFree (GetProcessHeap(), 0, This);
634         }
635         
636         return dwRef;
637 }
638
639 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Read (LPSTREAM iface, void* pv, ULONG cb, ULONG* pcbRead) {
640         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
641
642         TRACE_(dmfileraw)("(%p, %p, 0x%08X, %p): redirecting to low-level stream\n", This, pv, cb, pcbRead);
643         if (!This->pStream)
644                 return E_FAIL;
645
646         return IStream_Read (This->pStream, pv, cb, pcbRead);
647 }
648
649 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Seek (LPSTREAM iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) {
650         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
651         TRACE_(dmfileraw)("(%p, %s, %s, %p): redirecting to low-level stream\n", This, wine_dbgstr_longlong(dlibMove.QuadPart), resolve_STREAM_SEEK(dwOrigin), plibNewPosition);
652         if (!This->pStream)
653                 return E_FAIL;
654
655         return IStream_Seek (This->pStream, dlibMove, dwOrigin, plibNewPosition);
656 }
657
658 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Clone (LPSTREAM iface, IStream** ppstm) {
659         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
660         LPSTREAM pOther = NULL;
661         LPSTREAM pLowLevel = NULL;
662         HRESULT result;
663
664         TRACE("(%p, %p)\n", iface, ppstm);
665         result = DMUSIC_CreateDirectMusicLoaderGenericStream ((LPVOID*)&pOther);
666         if (FAILED(result)) return result;
667         
668         if (FAILED(IStream_Clone (This->pStream, &pLowLevel)))
669                 return E_FAIL;
670         
671         IDirectMusicLoaderGenericStream_Attach (pOther, pLowLevel, This->pLoader);
672
673         TRACE(": succeeded\n");
674         *ppstm = pOther;
675         return S_OK;
676 }
677
678 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Write (LPSTREAM iface, const void* pv, ULONG cb, ULONG* pcbWritten) {
679         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
680         TRACE_(dmfileraw)("(%p, %p, 0x%08X, %p): redirecting to low-level stream\n", This, pv, cb, pcbWritten);
681         if (!This->pStream)
682                 return E_FAIL;
683
684         return IStream_Write (This->pStream, pv, cb, pcbWritten);
685 }
686
687 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_SetSize (LPSTREAM iface, ULARGE_INTEGER libNewSize) {
688         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
689         TRACE("(%p, %s): redirecting to low-level stream\n", This, wine_dbgstr_longlong(libNewSize.QuadPart));
690         if (!This->pStream)
691                 return E_FAIL;
692
693         return IStream_SetSize (This->pStream, libNewSize);
694 }
695
696 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_CopyTo (LPSTREAM iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) {
697         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
698         TRACE("(%p, %p, %s, %p, %p): redirecting to low-level stream\n", This, pstm, wine_dbgstr_longlong(cb.QuadPart), pcbRead, pcbWritten);
699         if (!This->pStream)
700                 return E_FAIL;
701
702         return IStream_CopyTo (This->pStream, pstm, cb, pcbRead, pcbWritten);
703 }
704
705 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Commit (LPSTREAM iface, DWORD grfCommitFlags) {
706         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
707         TRACE("(%p, 0x%08X): redirecting to low-level stream\n", This, grfCommitFlags);
708         if (!This->pStream)
709                 return E_FAIL;
710
711         return IStream_Commit (This->pStream, grfCommitFlags);
712 }
713
714 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Revert (LPSTREAM iface) {
715         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
716         TRACE("(%p): redirecting to low-level stream\n", This);
717         if (!This->pStream)
718                 return E_FAIL;
719
720         return IStream_Revert (This->pStream);
721 }
722
723 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_LockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {
724         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
725         TRACE("(%p, %s, %s, 0x%08X): redirecting to low-level stream\n", This, wine_dbgstr_longlong(libOffset.QuadPart), wine_dbgstr_longlong(cb.QuadPart), dwLockType);
726         if (!This->pStream)
727                 return E_FAIL;
728
729         return IStream_LockRegion (This->pStream, libOffset, cb, dwLockType);
730 }
731
732 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_UnlockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {
733         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
734         TRACE("(%p, %s, %s, 0x%08X): redirecting to low-level stream\n", This, wine_dbgstr_longlong(libOffset.QuadPart), wine_dbgstr_longlong(cb.QuadPart), dwLockType);
735         if (!This->pStream)
736                 return E_FAIL;
737
738         return IStream_UnlockRegion (This->pStream, libOffset, cb, dwLockType);
739 }
740
741 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Stat (LPSTREAM iface, STATSTG* pstatstg, DWORD grfStatFlag) {
742         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
743         TRACE("(%p, %p, 0x%08X): redirecting to low-level stream\n", This, pstatstg, grfStatFlag);
744         if (!This->pStream)
745                 return E_FAIL;
746
747         return IStream_Stat (This->pStream, pstatstg, grfStatFlag);
748 }
749
750 static const IStreamVtbl DirectMusicLoaderGenericStream_Stream_Vtbl = {
751         IDirectMusicLoaderGenericStream_IStream_QueryInterface,
752         IDirectMusicLoaderGenericStream_IStream_AddRef,
753         IDirectMusicLoaderGenericStream_IStream_Release,
754         IDirectMusicLoaderGenericStream_IStream_Read,
755         IDirectMusicLoaderGenericStream_IStream_Write,
756         IDirectMusicLoaderGenericStream_IStream_Seek,
757         IDirectMusicLoaderGenericStream_IStream_SetSize,
758         IDirectMusicLoaderGenericStream_IStream_CopyTo,
759         IDirectMusicLoaderGenericStream_IStream_Commit,
760         IDirectMusicLoaderGenericStream_IStream_Revert,
761         IDirectMusicLoaderGenericStream_IStream_LockRegion,
762         IDirectMusicLoaderGenericStream_IStream_UnlockRegion,
763         IDirectMusicLoaderGenericStream_IStream_Stat,
764         IDirectMusicLoaderGenericStream_IStream_Clone
765 };
766
767 /* IDirectMusicGetLoader part: */
768 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj) {
769         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface);
770         return IDirectMusicLoaderGenericStream_IStream_QueryInterface ((LPSTREAM)&This->StreamVtbl, riid, ppobj);
771 }
772
773 static ULONG WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface) {
774         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface);
775         return IDirectMusicLoaderGenericStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl);
776 }
777
778 static ULONG WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface) {
779         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface);
780         return IDirectMusicLoaderGenericStream_IStream_Release ((LPSTREAM)&This->StreamVtbl);
781 }
782
783 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader) {
784         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface);
785
786         TRACE("(%p, %p)\n", This, ppLoader);
787         *ppLoader = (LPDIRECTMUSICLOADER)This->pLoader;
788         IDirectMusicLoader8_AddRef ((LPDIRECTMUSICLOADER8)*ppLoader);
789         
790         return S_OK;
791 }
792
793 static const IDirectMusicGetLoaderVtbl DirectMusicLoaderGenericStream_GetLoader_Vtbl = {
794         IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_QueryInterface,
795         IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_AddRef,
796         IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_Release,
797         IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_GetLoader
798 };
799
800 HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderGenericStream (LPVOID* ppobj) {
801         IDirectMusicLoaderGenericStream *obj;
802
803         TRACE("(%p)\n", ppobj);
804         obj = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderGenericStream));
805         if (NULL == obj) {
806                 *ppobj = NULL;
807                 return E_OUTOFMEMORY;
808         }
809         obj->StreamVtbl = &DirectMusicLoaderGenericStream_Stream_Vtbl;
810         obj->GetLoaderVtbl = &DirectMusicLoaderGenericStream_GetLoader_Vtbl;
811         obj->dwRef = 0; /* will be inited with QueryInterface */
812
813         return IDirectMusicLoaderGenericStream_IStream_QueryInterface ((LPSTREAM)&obj->StreamVtbl, &IID_IStream, ppobj);
814 }