Moved the implementation of a couple of system.drv entry points to
[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, LPDIRECTMUSICLOADER8 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     This->pLoader = pLoader;
70     lstrcpynW (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, 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 static const IStreamVtbl DirectMusicLoaderFileStream_Stream_Vtbl = {
234         IDirectMusicLoaderFileStream_IStream_QueryInterface,
235         IDirectMusicLoaderFileStream_IStream_AddRef,
236         IDirectMusicLoaderFileStream_IStream_Release,
237         IDirectMusicLoaderFileStream_IStream_Read,
238         IDirectMusicLoaderFileStream_IStream_Write,
239         IDirectMusicLoaderFileStream_IStream_Seek,
240         IDirectMusicLoaderFileStream_IStream_SetSize,
241         IDirectMusicLoaderFileStream_IStream_CopyTo,
242         IDirectMusicLoaderFileStream_IStream_Commit,
243         IDirectMusicLoaderFileStream_IStream_Revert,
244         IDirectMusicLoaderFileStream_IStream_LockRegion,
245         IDirectMusicLoaderFileStream_IStream_UnlockRegion,
246         IDirectMusicLoaderFileStream_IStream_Stat,
247         IDirectMusicLoaderFileStream_IStream_Clone
248 };
249
250 /* IDirectMusicGetLoader part: */
251 HRESULT WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj) {
252         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface);
253         return IDirectMusicLoaderFileStream_IStream_QueryInterface ((LPSTREAM)&This->StreamVtbl, riid, ppobj);
254 }
255
256 ULONG WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface) {
257         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface);
258         return IDirectMusicLoaderFileStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl);
259 }
260
261 ULONG WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface) {
262         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface);
263         return IDirectMusicLoaderFileStream_IStream_Release ((LPSTREAM)&This->StreamVtbl);
264 }
265
266 HRESULT WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader) {
267         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface);
268
269         TRACE("(%p, %p)\n", This, ppLoader);
270         *ppLoader = (LPDIRECTMUSICLOADER)This->pLoader;
271         IDirectMusicLoader8_AddRef ((LPDIRECTMUSICLOADER8)*ppLoader);
272         
273         return S_OK;
274 }
275
276 static const IDirectMusicGetLoaderVtbl DirectMusicLoaderFileStream_GetLoader_Vtbl = {
277         IDirectMusicLoaderFileStream_IDirectMusicGetLoader_QueryInterface,
278         IDirectMusicLoaderFileStream_IDirectMusicGetLoader_AddRef,
279         IDirectMusicLoaderFileStream_IDirectMusicGetLoader_Release,
280         IDirectMusicLoaderFileStream_IDirectMusicGetLoader_GetLoader
281 };
282
283 HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderFileStream (LPVOID* ppobj) {
284         IDirectMusicLoaderFileStream *obj;
285
286         TRACE("(%p)\n", ppobj);
287         obj = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderFileStream));
288         if (NULL == obj) {
289                 *ppobj = NULL;
290                 return E_OUTOFMEMORY;
291         }
292         obj->StreamVtbl = &DirectMusicLoaderFileStream_Stream_Vtbl;
293         obj->GetLoaderVtbl = &DirectMusicLoaderFileStream_GetLoader_Vtbl;
294         obj->dwRef = 0; /* will be inited with QueryInterface */
295
296         return IDirectMusicLoaderFileStream_IStream_QueryInterface ((LPSTREAM)&obj->StreamVtbl, &IID_IStream, ppobj);
297 }
298
299 HRESULT WINAPI DMUSIC_DestroyDirectMusicLoaderFileStream (LPSTREAM iface) {
300         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface);
301         
302         TRACE("(%p)\n", iface);
303         if (This->hFile)
304                 IDirectMusicLoaderFileStream_Detach (iface);
305         HeapFree (GetProcessHeap(), 0, This);
306
307         return S_OK;    
308 }
309
310
311 /*****************************************************************************
312  * IDirectMusicLoaderResourceStream implementation
313  */
314 /* Custom : */
315 HRESULT WINAPI IDirectMusicLoaderResourceStream_Attach (LPSTREAM iface, LPBYTE pbMemData, LONGLONG llMemLength, LONGLONG llPos, LPDIRECTMUSICLOADER8 pLoader) {
316         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface);
317     
318         TRACE("(%p, %p, 0x%08llX, 0x%08llx, %p)\n", This, pbMemData, llMemLength, llPos, pLoader);
319         if (!pbMemData || !llMemLength) {
320                 WARN(": invalid pbMemData or llMemLength\n");
321                 return E_FAIL;
322         }
323         IDirectMusicLoaderResourceStream_Detach (iface);
324         This->pbMemData = pbMemData;
325         This->llMemLength = llMemLength;
326         This->llPos = llPos;
327         This->pLoader = pLoader;
328         
329     return S_OK;
330 }
331
332 void WINAPI IDirectMusicLoaderResourceStream_Detach (LPSTREAM iface) {
333         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface);
334         TRACE("(%p)\n", This);
335         
336         This->pbMemData = NULL;
337         This->llMemLength = 0;
338 }
339
340
341 /* IUnknown/IStream part: */
342 HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_QueryInterface (LPSTREAM iface, REFIID riid, void** ppobj) {
343         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface);
344         
345         TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj);
346         if (IsEqualIID (riid, &IID_IUnknown) ||
347                 IsEqualIID (riid, &IID_IStream)) {
348                 *ppobj = (LPVOID)&This->StreamVtbl;
349                 IDirectMusicLoaderResourceStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl);
350                 return S_OK;
351         } else if (IsEqualIID (riid, &IID_IDirectMusicGetLoader)) {
352                 *ppobj = (LPVOID)&This->GetLoaderVtbl;
353                 IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_AddRef ((LPDIRECTMUSICGETLOADER)&This->GetLoaderVtbl);           
354                 return S_OK;
355         }
356
357         WARN(": not found\n");
358         return E_NOINTERFACE;
359 }
360
361 ULONG WINAPI IDirectMusicLoaderResourceStream_IStream_AddRef (LPSTREAM iface) {
362         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface);
363         TRACE("(%p): AddRef from %ld\n", This, This->dwRef);
364         return InterlockedIncrement (&This->dwRef);
365 }
366
367 ULONG WINAPI IDirectMusicLoaderResourceStream_IStream_Release (LPSTREAM iface) {
368         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface);
369         
370         DWORD dwRef = InterlockedDecrement (&This->dwRef);
371         TRACE("(%p): ReleaseRef to %ld\n", This, dwRef);
372         if (dwRef == 0) {
373                 DMUSIC_DestroyDirectMusicLoaderResourceStream (iface);
374         }
375         
376         return dwRef;
377 }
378
379 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%08lX, %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%08lX): '%s'\n", cb, debugstr_an(pv, cb));
396     return S_OK;
397 }
398
399 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, 0x%08llX, %s, %p)\n", This, 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 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 = (IStream*)pOther;
456         return S_OK;
457 }
458
459 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 HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_SetSize (LPSTREAM iface, ULARGE_INTEGER libNewSize) {
465         ERR(": should not be needed\n");
466     return E_NOTIMPL;
467 }
468
469 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 HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Commit (LPSTREAM iface, DWORD grfCommitFlags) {
475         ERR(": should not be needed\n");
476     return E_NOTIMPL;
477 }
478
479 HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Revert (LPSTREAM iface) {
480         ERR(": should not be needed\n");
481     return E_NOTIMPL;
482 }
483
484 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 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 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 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 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 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 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 HRESULT WINAPI DMUSIC_DestroyDirectMusicLoaderResourceStream (LPSTREAM iface) {
566         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface);
567         
568         TRACE("(%p)\n", iface);
569         IDirectMusicLoaderResourceStream_Detach (iface);
570         HeapFree (GetProcessHeap(), 0, This);
571
572         return S_OK;    
573 }
574
575 /*****************************************************************************
576  * IDirectMusicLoaderGenericStream implementation
577  */
578 /* Custom : */
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 void WINAPI IDirectMusicLoaderGenericStream_Detach (LPSTREAM iface) {
600         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
601         
602         if (This->pStream)
603                 IStream_Release (This->pStream);
604         This->pStream = NULL;
605 }
606
607
608 /* IUnknown/IStream part: */
609 HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_QueryInterface (LPSTREAM iface, REFIID riid, void** ppobj) {
610         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
611         
612         TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj);
613         if (IsEqualIID (riid, &IID_IUnknown) ||
614                 IsEqualIID (riid, &IID_IStream)) {
615                 *ppobj = (LPVOID)&This->StreamVtbl;
616                 IDirectMusicLoaderGenericStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl);
617                 return S_OK;
618         } else if (IsEqualIID (riid, &IID_IDirectMusicGetLoader)) {
619                 *ppobj = (LPVOID)&This->GetLoaderVtbl;
620                 IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_AddRef ((LPDIRECTMUSICGETLOADER)&This->GetLoaderVtbl);            
621                 return S_OK;
622         }
623
624         WARN(": not found\n");
625         return E_NOINTERFACE;
626 }
627
628 ULONG WINAPI IDirectMusicLoaderGenericStream_IStream_AddRef (LPSTREAM iface) {
629         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
630         TRACE("(%p): AddRef from %ld\n", This, This->dwRef);
631         return InterlockedIncrement (&This->dwRef);
632 }
633
634 ULONG WINAPI IDirectMusicLoaderGenericStream_IStream_Release (LPSTREAM iface) {
635         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
636         
637         DWORD dwRef = InterlockedDecrement (&This->dwRef);
638         TRACE("(%p): ReleaseRef to %ld\n", This, dwRef);
639         if (dwRef == 0) {
640                 DMUSIC_DestroyDirectMusicLoaderGenericStream (iface);
641         }
642         
643         return dwRef;
644 }
645
646 HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Read (LPSTREAM iface, void* pv, ULONG cb, ULONG* pcbRead) {
647         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
648
649         TRACE_(dmfileraw)("(%p, %p, 0x%08lX, %p): redirecting to low-level stream\n", This, pv, cb, pcbRead);
650         if (!This->pStream)
651                 return E_FAIL;
652
653         return IStream_Read (This->pStream, pv, cb, pcbRead);
654 }
655
656 HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Seek (LPSTREAM iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) {
657         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
658         TRACE_(dmfileraw)("(%p, 0x%08llX, %s, %p): redirecting to low-level stream\n", This, dlibMove.QuadPart, resolve_STREAM_SEEK(dwOrigin), plibNewPosition);
659         if (!This->pStream)
660                 return E_FAIL;
661
662         return IStream_Seek (This->pStream, dlibMove, dwOrigin, plibNewPosition);
663 }
664
665 HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Clone (LPSTREAM iface, IStream** ppstm) {
666         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
667         LPSTREAM pOther = NULL;
668         LPSTREAM pLowLevel = NULL;
669         HRESULT result;
670
671         TRACE("(%p, %p)\n", iface, ppstm);
672         result = DMUSIC_CreateDirectMusicLoaderGenericStream ((LPVOID*)&pOther);
673         if (FAILED(result)) return result;
674         
675         if (FAILED(IStream_Clone (This->pStream, &pLowLevel)))
676                 return E_FAIL;
677         
678         IDirectMusicLoaderGenericStream_Attach (pOther, pLowLevel, This->pLoader);
679
680         TRACE(": succeeded\n");
681         *ppstm = (IStream*)pOther;
682         return S_OK;
683 }
684
685 HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Write (LPSTREAM iface, const void* pv, ULONG cb, ULONG* pcbWritten) {
686         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
687         TRACE_(dmfileraw)("(%p, %p, 0x%08lX, %p): redirecting to low-level stream\n", This, pv, cb, pcbWritten);
688         if (!This->pStream)
689                 return E_FAIL;
690
691         return IStream_Write (This->pStream, pv, cb, pcbWritten);
692 }
693
694 HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_SetSize (LPSTREAM iface, ULARGE_INTEGER libNewSize) {
695         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
696         TRACE("(%p, 0x%08llX): redirecting to low-level stream\n", This, libNewSize.QuadPart);
697         if (!This->pStream)
698                 return E_FAIL;
699
700         return IStream_SetSize (This->pStream, libNewSize);
701 }
702
703 HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_CopyTo (LPSTREAM iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) {
704         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
705         TRACE("(%p, %p, 0x%08llX, %p, %p): redirecting to low-level stream\n", This, pstm, cb.QuadPart, pcbRead, pcbWritten);
706         if (!This->pStream)
707                 return E_FAIL;
708
709         return IStream_CopyTo (This->pStream, pstm, cb, pcbRead, pcbWritten);
710 }
711
712 HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Commit (LPSTREAM iface, DWORD grfCommitFlags) {
713         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
714         TRACE("(%p, 0x%08lX): redirecting to low-level stream\n", This, grfCommitFlags);
715         if (!This->pStream)
716                 return E_FAIL;
717
718         return IStream_Commit (This->pStream, grfCommitFlags);
719 }
720
721 HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Revert (LPSTREAM iface) {
722         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
723         TRACE("(%p): redirecting to low-level stream\n", This);
724         if (!This->pStream)
725                 return E_FAIL;
726
727         return IStream_Revert (This->pStream);
728 }
729
730 HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_LockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {
731         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
732         TRACE("(%p, 0x%08llX, 0x%08llX, 0x%08lX): redirecting to low-level stream\n", This, libOffset.QuadPart, cb.QuadPart, dwLockType);
733         if (!This->pStream)
734                 return E_FAIL;
735
736         return IStream_LockRegion (This->pStream, libOffset, cb, dwLockType);
737 }
738
739 HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_UnlockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {
740         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
741         TRACE("(%p, 0x%08llX, 0x%08llX, 0x%08lX): redirecting to low-level stream\n", This, libOffset.QuadPart, cb.QuadPart, dwLockType);
742         if (!This->pStream)
743                 return E_FAIL;
744
745         return IStream_UnlockRegion (This->pStream, libOffset, cb, dwLockType);
746 }
747
748 HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Stat (LPSTREAM iface, STATSTG* pstatstg, DWORD grfStatFlag) {
749         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
750         TRACE("(%p, %p, 0x%08lX): redirecting to low-level stream\n", This, pstatstg, grfStatFlag);
751         if (!This->pStream)
752                 return E_FAIL;
753
754         return IStream_Stat (This->pStream, pstatstg, grfStatFlag);
755 }
756
757 static const IStreamVtbl DirectMusicLoaderGenericStream_Stream_Vtbl = {
758         IDirectMusicLoaderGenericStream_IStream_QueryInterface,
759         IDirectMusicLoaderGenericStream_IStream_AddRef,
760         IDirectMusicLoaderGenericStream_IStream_Release,
761         IDirectMusicLoaderGenericStream_IStream_Read,
762         IDirectMusicLoaderGenericStream_IStream_Write,
763         IDirectMusicLoaderGenericStream_IStream_Seek,
764         IDirectMusicLoaderGenericStream_IStream_SetSize,
765         IDirectMusicLoaderGenericStream_IStream_CopyTo,
766         IDirectMusicLoaderGenericStream_IStream_Commit,
767         IDirectMusicLoaderGenericStream_IStream_Revert,
768         IDirectMusicLoaderGenericStream_IStream_LockRegion,
769         IDirectMusicLoaderGenericStream_IStream_UnlockRegion,
770         IDirectMusicLoaderGenericStream_IStream_Stat,
771         IDirectMusicLoaderGenericStream_IStream_Clone
772 };
773
774 /* IDirectMusicGetLoader part: */
775 HRESULT WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj) {
776         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface);
777         return IDirectMusicLoaderGenericStream_IStream_QueryInterface ((LPSTREAM)&This->StreamVtbl, riid, ppobj);
778 }
779
780 ULONG WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface) {
781         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface);
782         return IDirectMusicLoaderGenericStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl);
783 }
784
785 ULONG WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface) {
786         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface);
787         return IDirectMusicLoaderGenericStream_IStream_Release ((LPSTREAM)&This->StreamVtbl);
788 }
789
790 HRESULT WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader) {
791         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface);
792
793         TRACE("(%p, %p)\n", This, ppLoader);
794         *ppLoader = (LPDIRECTMUSICLOADER)This->pLoader;
795         IDirectMusicLoader8_AddRef ((LPDIRECTMUSICLOADER8)*ppLoader);
796         
797         return S_OK;
798 }
799
800 static const IDirectMusicGetLoaderVtbl DirectMusicLoaderGenericStream_GetLoader_Vtbl = {
801         IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_QueryInterface,
802         IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_AddRef,
803         IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_Release,
804         IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_GetLoader
805 };
806
807 HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderGenericStream (LPVOID* ppobj) {
808         IDirectMusicLoaderGenericStream *obj;
809
810         TRACE("(%p)\n", ppobj);
811         obj = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderGenericStream));
812         if (NULL == obj) {
813                 *ppobj = NULL;
814                 return E_OUTOFMEMORY;
815         }
816         obj->StreamVtbl = &DirectMusicLoaderGenericStream_Stream_Vtbl;
817         obj->GetLoaderVtbl = &DirectMusicLoaderGenericStream_GetLoader_Vtbl;
818         obj->dwRef = 0; /* will be inited with QueryInterface */
819
820         return IDirectMusicLoaderGenericStream_IStream_QueryInterface ((LPSTREAM)&obj->StreamVtbl, &IID_IStream, ppobj);
821 }
822
823 HRESULT WINAPI DMUSIC_DestroyDirectMusicLoaderGenericStream (LPSTREAM iface) {
824         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
825         
826         TRACE("(%p)\n", iface);
827         IDirectMusicLoaderGenericStream_Detach (iface);
828         HeapFree (GetProcessHeap(), 0, This);
829
830         return S_OK;    
831 }