wined3d: Move point scale render states to the state table.
[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., 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 HRESULT WINAPI IDirectMusicLoaderFileStream_Attach (LPSTREAM iface, LPCWSTR wzFile, LPDIRECTMUSICLOADER8 pLoader) {
68         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface);
69     TRACE("(%p, %s, %p)\n", This, debugstr_w(wzFile), pLoader);
70     IDirectMusicLoaderFileStream_Detach (iface);
71     This->hFile = CreateFileW (wzFile, (GENERIC_READ | GENERIC_WRITE), (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
72     if (This->hFile == INVALID_HANDLE_VALUE) {
73         WARN(": failed\n");
74         return DMUS_E_LOADER_FAILEDOPEN;
75     }
76     /* create IDirectMusicGetLoader */
77     This->pLoader = pLoader;
78     lstrcpynW (This->wzFileName, wzFile, MAX_PATH);
79     TRACE(": succeeded\n");
80     return S_OK;
81 }
82
83 void WINAPI IDirectMusicLoaderFileStream_Detach (LPSTREAM iface) {
84         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface);
85         TRACE("(%p)\n", This);
86         if (This->hFile != INVALID_HANDLE_VALUE) {
87         CloseHandle(This->hFile);
88     }
89     This->wzFileName[0] = (L'\0');
90 }
91
92
93 /* IUnknown/IStream part: */
94 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_QueryInterface (LPSTREAM iface, REFIID riid, void** ppobj) {
95         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface);
96         
97         TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj);
98         if (IsEqualIID (riid, &IID_IUnknown) ||
99                 IsEqualIID (riid, &IID_IStream)) {
100                 *ppobj = (LPVOID)&This->StreamVtbl;
101                 IDirectMusicLoaderFileStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl);
102                 return S_OK;
103         } else if (IsEqualIID (riid, &IID_IDirectMusicGetLoader)) {
104                 *ppobj = (LPVOID)&This->GetLoaderVtbl;
105                 IDirectMusicLoaderFileStream_IDirectMusicGetLoader_AddRef ((LPDIRECTMUSICGETLOADER)&This->GetLoaderVtbl);               
106                 return S_OK;
107         }
108
109         WARN(": not found\n");
110         return E_NOINTERFACE;
111 }
112
113 static ULONG WINAPI IDirectMusicLoaderFileStream_IStream_AddRef (LPSTREAM iface) {
114         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface);
115         TRACE("(%p): AddRef from %d\n", This, This->dwRef);
116         return InterlockedIncrement (&This->dwRef);
117 }
118
119 static ULONG WINAPI IDirectMusicLoaderFileStream_IStream_Release (LPSTREAM iface) {
120         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface);
121         
122         DWORD dwRef = InterlockedDecrement (&This->dwRef);
123         TRACE("(%p): ReleaseRef to %d\n", This, dwRef);
124         if (dwRef == 0) {
125                 if (This->hFile)
126                         IDirectMusicLoaderFileStream_Detach (iface);
127                 HeapFree (GetProcessHeap(), 0, This);
128         }
129         
130         return dwRef;
131 }
132
133 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Read (LPSTREAM iface, void* pv, ULONG cb, ULONG* pcbRead) {
134         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface);
135     ULONG cbRead;
136         
137         TRACE_(dmfileraw)("(%p, %p, 0x%08X, %p)\n", This, pv, cb, pcbRead);
138     if (This->hFile == INVALID_HANDLE_VALUE) return E_FAIL;
139     if (pcbRead == NULL) pcbRead = &cbRead;
140     if (!ReadFile (This->hFile, pv, cb, pcbRead, NULL) || *pcbRead != cb) return E_FAIL;
141         
142         TRACE_(dmfileraw)(": data (size = 0x%08X): '%s'\n", *pcbRead, debugstr_an(pv, *pcbRead));
143     return S_OK;
144 }
145
146 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Seek (LPSTREAM iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) {
147         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface);
148     LARGE_INTEGER liNewPos;
149         
150         TRACE_(dmfileraw)("(%p, 0x%08llX, %s, %p)\n", This, dlibMove.QuadPart, resolve_STREAM_SEEK(dwOrigin), plibNewPosition);
151
152         if (This->hFile == INVALID_HANDLE_VALUE) return E_FAIL;
153
154     liNewPos.u.HighPart = dlibMove.u.HighPart;
155     liNewPos.u.LowPart = SetFilePointer (This->hFile, dlibMove.u.LowPart, &liNewPos.u.HighPart, dwOrigin);
156
157     if (liNewPos.u.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) return E_FAIL;
158     if (plibNewPosition) plibNewPosition->QuadPart = liNewPos.QuadPart;
159     
160     return S_OK;
161 }
162
163 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Clone (LPSTREAM iface, IStream** ppstm) {
164         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface);
165         LPSTREAM pOther = NULL;
166         HRESULT result;
167
168         TRACE("(%p, %p)\n", iface, ppstm);
169         result = DMUSIC_CreateDirectMusicLoaderFileStream ((LPVOID*)&pOther);
170         if (FAILED(result)) return result;
171         if (This->hFile != INVALID_HANDLE_VALUE) {
172                 ULARGE_INTEGER ullCurrentPosition;
173                 result = IDirectMusicLoaderFileStream_Attach (pOther, This->wzFileName, This->pLoader);
174                 if (SUCCEEDED(result)) {
175                         LARGE_INTEGER liZero;
176                         liZero.QuadPart = 0;
177                         result = IDirectMusicLoaderFileStream_IStream_Seek (iface, liZero, STREAM_SEEK_CUR, &ullCurrentPosition); /* get current position in current stream */
178         }
179                 if (SUCCEEDED(result)) {
180                         LARGE_INTEGER liNewPosition;
181                         liNewPosition.QuadPart = ullCurrentPosition.QuadPart;
182                         result = IDirectMusicLoaderFileStream_IStream_Seek ((LPSTREAM)pOther, liNewPosition, STREAM_SEEK_SET, &ullCurrentPosition);
183                 }
184                 if (FAILED(result)) {
185                         TRACE(": failed\n");
186                         IDirectMusicLoaderFileStream_IStream_Release ((LPSTREAM)pOther);
187                         return result;
188                 }
189         }
190         TRACE(": succeeded\n");
191         *ppstm = (IStream*)pOther;
192         return S_OK;
193 }
194
195 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Write (LPSTREAM iface, const void* pv, ULONG cb, ULONG* pcbWritten) {
196         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface);
197     ULONG cbWrite;
198         
199         TRACE_(dmfileraw)("(%p, %p, 0x%08X, %p)\n", This, pv, cb, pcbWritten);
200     if (This->hFile == INVALID_HANDLE_VALUE) return E_FAIL;
201     if (pcbWritten == NULL) pcbWritten = &cbWrite;
202     if (!WriteFile (This->hFile, pv, cb, pcbWritten, NULL) || *pcbWritten != cb) return E_FAIL;
203         
204         TRACE_(dmfileraw)(": data (size = 0x%08X): '%s'\n", *pcbWritten, debugstr_an(pv, *pcbWritten));
205     return S_OK;
206 }
207
208 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_SetSize (LPSTREAM iface, ULARGE_INTEGER libNewSize) {
209         ERR(": should not be needed\n");
210     return E_NOTIMPL;
211 }
212
213 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_CopyTo (LPSTREAM iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) {
214         ERR(": should not be needed\n");
215     return E_NOTIMPL;
216 }
217
218 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Commit (LPSTREAM iface, DWORD grfCommitFlags) {
219         ERR(": should not be needed\n");
220     return E_NOTIMPL;
221 }
222
223 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Revert (LPSTREAM iface) {
224         ERR(": should not be needed\n");
225     return E_NOTIMPL;
226 }
227
228 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_LockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {
229         ERR(": should not be needed\n");
230     return E_NOTIMPL;
231 }
232
233 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_UnlockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {
234         ERR(": should not be needed\n");
235     return E_NOTIMPL;
236 }
237
238 static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Stat (LPSTREAM iface, STATSTG* pstatstg, DWORD grfStatFlag) {
239         ERR(": should not be needed\n");
240     return E_NOTIMPL;
241 }
242
243 static const IStreamVtbl DirectMusicLoaderFileStream_Stream_Vtbl = {
244         IDirectMusicLoaderFileStream_IStream_QueryInterface,
245         IDirectMusicLoaderFileStream_IStream_AddRef,
246         IDirectMusicLoaderFileStream_IStream_Release,
247         IDirectMusicLoaderFileStream_IStream_Read,
248         IDirectMusicLoaderFileStream_IStream_Write,
249         IDirectMusicLoaderFileStream_IStream_Seek,
250         IDirectMusicLoaderFileStream_IStream_SetSize,
251         IDirectMusicLoaderFileStream_IStream_CopyTo,
252         IDirectMusicLoaderFileStream_IStream_Commit,
253         IDirectMusicLoaderFileStream_IStream_Revert,
254         IDirectMusicLoaderFileStream_IStream_LockRegion,
255         IDirectMusicLoaderFileStream_IStream_UnlockRegion,
256         IDirectMusicLoaderFileStream_IStream_Stat,
257         IDirectMusicLoaderFileStream_IStream_Clone
258 };
259
260 /* IDirectMusicGetLoader part: */
261 static HRESULT WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj) {
262         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface);
263         return IDirectMusicLoaderFileStream_IStream_QueryInterface ((LPSTREAM)&This->StreamVtbl, riid, ppobj);
264 }
265
266 static ULONG WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface) {
267         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface);
268         return IDirectMusicLoaderFileStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl);
269 }
270
271 static ULONG WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface) {
272         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface);
273         return IDirectMusicLoaderFileStream_IStream_Release ((LPSTREAM)&This->StreamVtbl);
274 }
275
276 static HRESULT WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader) {
277         ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface);
278
279         TRACE("(%p, %p)\n", This, ppLoader);
280         *ppLoader = (LPDIRECTMUSICLOADER)This->pLoader;
281         IDirectMusicLoader8_AddRef ((LPDIRECTMUSICLOADER8)*ppLoader);
282         
283         return S_OK;
284 }
285
286 static const IDirectMusicGetLoaderVtbl DirectMusicLoaderFileStream_GetLoader_Vtbl = {
287         IDirectMusicLoaderFileStream_IDirectMusicGetLoader_QueryInterface,
288         IDirectMusicLoaderFileStream_IDirectMusicGetLoader_AddRef,
289         IDirectMusicLoaderFileStream_IDirectMusicGetLoader_Release,
290         IDirectMusicLoaderFileStream_IDirectMusicGetLoader_GetLoader
291 };
292
293 HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderFileStream (LPVOID* ppobj) {
294         IDirectMusicLoaderFileStream *obj;
295
296         TRACE("(%p)\n", ppobj);
297         obj = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderFileStream));
298         if (NULL == obj) {
299                 *ppobj = NULL;
300                 return E_OUTOFMEMORY;
301         }
302         obj->StreamVtbl = &DirectMusicLoaderFileStream_Stream_Vtbl;
303         obj->GetLoaderVtbl = &DirectMusicLoaderFileStream_GetLoader_Vtbl;
304         obj->dwRef = 0; /* will be inited with QueryInterface */
305
306         return IDirectMusicLoaderFileStream_IStream_QueryInterface ((LPSTREAM)&obj->StreamVtbl, &IID_IStream, ppobj);
307 }
308
309
310 /*****************************************************************************
311  * IDirectMusicLoaderResourceStream implementation
312  */
313 /* Custom : */
314 HRESULT WINAPI IDirectMusicLoaderResourceStream_Attach (LPSTREAM iface, LPBYTE pbMemData, LONGLONG llMemLength, LONGLONG llPos, LPDIRECTMUSICLOADER8 pLoader) {
315         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface);
316     
317         TRACE("(%p, %p, 0x%08llX, 0x%08llx, %p)\n", This, pbMemData, llMemLength, llPos, pLoader);
318         if (!pbMemData || !llMemLength) {
319                 WARN(": invalid pbMemData or llMemLength\n");
320                 return E_FAIL;
321         }
322         IDirectMusicLoaderResourceStream_Detach (iface);
323         This->pbMemData = pbMemData;
324         This->llMemLength = llMemLength;
325         This->llPos = llPos;
326         This->pLoader = pLoader;
327         
328     return S_OK;
329 }
330
331 void WINAPI IDirectMusicLoaderResourceStream_Detach (LPSTREAM iface) {
332         ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface);
333         TRACE("(%p)\n", This);
334         
335         This->pbMemData = NULL;
336         This->llMemLength = 0;
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 = (LPVOID)&This->StreamVtbl;
348                 IDirectMusicLoaderResourceStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl);
349                 return S_OK;
350         } else if (IsEqualIID (riid, &IID_IDirectMusicGetLoader)) {
351                 *ppobj = (LPVOID)&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, 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 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 = (IStream*)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 HRESULT WINAPI IDirectMusicLoaderGenericStream_Attach (LPSTREAM iface, LPSTREAM pStream, LPDIRECTMUSICLOADER8 pLoader) {
571         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
572     
573         TRACE("(%p, %p, %p)\n", This, pStream, pLoader);
574         if (!pStream) {
575                 WARN(": invalid pStream\n");
576                 return E_FAIL;
577         }
578         if (!pLoader) {
579                 WARN(": invalid pLoader\n");
580                 return E_FAIL;
581         }       
582         
583         IDirectMusicLoaderGenericStream_Detach (iface);
584         IStream_Clone (pStream, &This->pStream);
585         This->pLoader = pLoader;
586         
587     return S_OK;
588 }
589
590 void WINAPI IDirectMusicLoaderGenericStream_Detach (LPSTREAM iface) {
591         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
592         
593         if (This->pStream)
594                 IStream_Release (This->pStream);
595         This->pStream = NULL;
596 }
597
598
599 /* IUnknown/IStream part: */
600 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_QueryInterface (LPSTREAM iface, REFIID riid, void** ppobj) {
601         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
602         
603         TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj);
604         if (IsEqualIID (riid, &IID_IUnknown) ||
605                 IsEqualIID (riid, &IID_IStream)) {
606                 *ppobj = (LPVOID)&This->StreamVtbl;
607                 IDirectMusicLoaderGenericStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl);
608                 return S_OK;
609         } else if (IsEqualIID (riid, &IID_IDirectMusicGetLoader)) {
610                 *ppobj = (LPVOID)&This->GetLoaderVtbl;
611                 IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_AddRef ((LPDIRECTMUSICGETLOADER)&This->GetLoaderVtbl);            
612                 return S_OK;
613         }
614
615         WARN(": not found\n");
616         return E_NOINTERFACE;
617 }
618
619 static ULONG WINAPI IDirectMusicLoaderGenericStream_IStream_AddRef (LPSTREAM iface) {
620         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
621         TRACE("(%p): AddRef from %d\n", This, This->dwRef);
622         return InterlockedIncrement (&This->dwRef);
623 }
624
625 static ULONG WINAPI IDirectMusicLoaderGenericStream_IStream_Release (LPSTREAM iface) {
626         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
627         
628         DWORD dwRef = InterlockedDecrement (&This->dwRef);
629         TRACE("(%p): ReleaseRef to %d\n", This, dwRef);
630         if (dwRef == 0) {
631                 IDirectMusicLoaderGenericStream_Detach (iface);
632                 HeapFree (GetProcessHeap(), 0, This);
633         }
634         
635         return dwRef;
636 }
637
638 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Read (LPSTREAM iface, void* pv, ULONG cb, ULONG* pcbRead) {
639         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
640
641         TRACE_(dmfileraw)("(%p, %p, 0x%08X, %p): redirecting to low-level stream\n", This, pv, cb, pcbRead);
642         if (!This->pStream)
643                 return E_FAIL;
644
645         return IStream_Read (This->pStream, pv, cb, pcbRead);
646 }
647
648 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Seek (LPSTREAM iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) {
649         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
650         TRACE_(dmfileraw)("(%p, 0x%08llX, %s, %p): redirecting to low-level stream\n", This, dlibMove.QuadPart, resolve_STREAM_SEEK(dwOrigin), plibNewPosition);
651         if (!This->pStream)
652                 return E_FAIL;
653
654         return IStream_Seek (This->pStream, dlibMove, dwOrigin, plibNewPosition);
655 }
656
657 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Clone (LPSTREAM iface, IStream** ppstm) {
658         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);
659         LPSTREAM pOther = NULL;
660         LPSTREAM pLowLevel = NULL;
661         HRESULT result;
662
663         TRACE("(%p, %p)\n", iface, ppstm);
664         result = DMUSIC_CreateDirectMusicLoaderGenericStream ((LPVOID*)&pOther);
665         if (FAILED(result)) return result;
666         
667         if (FAILED(IStream_Clone (This->pStream, &pLowLevel)))
668                 return E_FAIL;
669         
670         IDirectMusicLoaderGenericStream_Attach (pOther, pLowLevel, This->pLoader);
671
672         TRACE(": succeeded\n");
673         *ppstm = (IStream*)pOther;
674         return S_OK;
675 }
676
677 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Write (LPSTREAM iface, const void* pv, ULONG cb, ULONG* pcbWritten) {
678         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
679         TRACE_(dmfileraw)("(%p, %p, 0x%08X, %p): redirecting to low-level stream\n", This, pv, cb, pcbWritten);
680         if (!This->pStream)
681                 return E_FAIL;
682
683         return IStream_Write (This->pStream, pv, cb, pcbWritten);
684 }
685
686 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_SetSize (LPSTREAM iface, ULARGE_INTEGER libNewSize) {
687         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
688         TRACE("(%p, 0x%08llX): redirecting to low-level stream\n", This, libNewSize.QuadPart);
689         if (!This->pStream)
690                 return E_FAIL;
691
692         return IStream_SetSize (This->pStream, libNewSize);
693 }
694
695 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_CopyTo (LPSTREAM iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) {
696         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
697         TRACE("(%p, %p, 0x%08llX, %p, %p): redirecting to low-level stream\n", This, pstm, cb.QuadPart, pcbRead, pcbWritten);
698         if (!This->pStream)
699                 return E_FAIL;
700
701         return IStream_CopyTo (This->pStream, pstm, cb, pcbRead, pcbWritten);
702 }
703
704 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Commit (LPSTREAM iface, DWORD grfCommitFlags) {
705         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
706         TRACE("(%p, 0x%08X): redirecting to low-level stream\n", This, grfCommitFlags);
707         if (!This->pStream)
708                 return E_FAIL;
709
710         return IStream_Commit (This->pStream, grfCommitFlags);
711 }
712
713 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Revert (LPSTREAM iface) {
714         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
715         TRACE("(%p): redirecting to low-level stream\n", This);
716         if (!This->pStream)
717                 return E_FAIL;
718
719         return IStream_Revert (This->pStream);
720 }
721
722 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_LockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {
723         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
724         TRACE("(%p, 0x%08llX, 0x%08llX, 0x%08X): redirecting to low-level stream\n", This, libOffset.QuadPart, cb.QuadPart, dwLockType);
725         if (!This->pStream)
726                 return E_FAIL;
727
728         return IStream_LockRegion (This->pStream, libOffset, cb, dwLockType);
729 }
730
731 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_UnlockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {
732         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
733         TRACE("(%p, 0x%08llX, 0x%08llX, 0x%08X): redirecting to low-level stream\n", This, libOffset.QuadPart, cb.QuadPart, dwLockType);
734         if (!This->pStream)
735                 return E_FAIL;
736
737         return IStream_UnlockRegion (This->pStream, libOffset, cb, dwLockType);
738 }
739
740 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Stat (LPSTREAM iface, STATSTG* pstatstg, DWORD grfStatFlag) {
741         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface);    
742         TRACE("(%p, %p, 0x%08X): redirecting to low-level stream\n", This, pstatstg, grfStatFlag);
743         if (!This->pStream)
744                 return E_FAIL;
745
746         return IStream_Stat (This->pStream, pstatstg, grfStatFlag);
747 }
748
749 static const IStreamVtbl DirectMusicLoaderGenericStream_Stream_Vtbl = {
750         IDirectMusicLoaderGenericStream_IStream_QueryInterface,
751         IDirectMusicLoaderGenericStream_IStream_AddRef,
752         IDirectMusicLoaderGenericStream_IStream_Release,
753         IDirectMusicLoaderGenericStream_IStream_Read,
754         IDirectMusicLoaderGenericStream_IStream_Write,
755         IDirectMusicLoaderGenericStream_IStream_Seek,
756         IDirectMusicLoaderGenericStream_IStream_SetSize,
757         IDirectMusicLoaderGenericStream_IStream_CopyTo,
758         IDirectMusicLoaderGenericStream_IStream_Commit,
759         IDirectMusicLoaderGenericStream_IStream_Revert,
760         IDirectMusicLoaderGenericStream_IStream_LockRegion,
761         IDirectMusicLoaderGenericStream_IStream_UnlockRegion,
762         IDirectMusicLoaderGenericStream_IStream_Stat,
763         IDirectMusicLoaderGenericStream_IStream_Clone
764 };
765
766 /* IDirectMusicGetLoader part: */
767 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj) {
768         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface);
769         return IDirectMusicLoaderGenericStream_IStream_QueryInterface ((LPSTREAM)&This->StreamVtbl, riid, ppobj);
770 }
771
772 static ULONG WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface) {
773         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface);
774         return IDirectMusicLoaderGenericStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl);
775 }
776
777 static ULONG WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface) {
778         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface);
779         return IDirectMusicLoaderGenericStream_IStream_Release ((LPSTREAM)&This->StreamVtbl);
780 }
781
782 static HRESULT WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader) {
783         ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface);
784
785         TRACE("(%p, %p)\n", This, ppLoader);
786         *ppLoader = (LPDIRECTMUSICLOADER)This->pLoader;
787         IDirectMusicLoader8_AddRef ((LPDIRECTMUSICLOADER8)*ppLoader);
788         
789         return S_OK;
790 }
791
792 static const IDirectMusicGetLoaderVtbl DirectMusicLoaderGenericStream_GetLoader_Vtbl = {
793         IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_QueryInterface,
794         IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_AddRef,
795         IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_Release,
796         IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_GetLoader
797 };
798
799 HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderGenericStream (LPVOID* ppobj) {
800         IDirectMusicLoaderGenericStream *obj;
801
802         TRACE("(%p)\n", ppobj);
803         obj = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderGenericStream));
804         if (NULL == obj) {
805                 *ppobj = NULL;
806                 return E_OUTOFMEMORY;
807         }
808         obj->StreamVtbl = &DirectMusicLoaderGenericStream_Stream_Vtbl;
809         obj->GetLoaderVtbl = &DirectMusicLoaderGenericStream_GetLoader_Vtbl;
810         obj->dwRef = 0; /* will be inited with QueryInterface */
811
812         return IDirectMusicLoaderGenericStream_IStream_QueryInterface ((LPSTREAM)&obj->StreamVtbl, &IID_IStream, ppobj);
813 }