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