Give SetErrorMode the right argument to suppress crash dialogs.
[wine] / dlls / dmime / graph.c
1 /* IDirectMusicGraph
2  *
3  * Copyright (C) 2003-2004 Rok Mandeljc
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #include "dmime_private.h"
21
22 WINE_DEFAULT_DEBUG_CHANNEL(dmime);
23 WINE_DECLARE_DEBUG_CHANNEL(dmfile);
24
25 /*****************************************************************************
26  * IDirectMusicGraphImpl implementation
27  */
28 /* IDirectMusicGraphImpl IUnknown part: */
29 HRESULT WINAPI IDirectMusicGraphImpl_IUnknown_QueryInterface (LPUNKNOWN iface, REFIID riid, LPVOID *ppobj) {
30         ICOM_THIS_MULTI(IDirectMusicGraphImpl, UnknownVtbl, iface);
31         TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
32         
33         if (IsEqualIID (riid, &IID_IUnknown)) {
34                 *ppobj = (LPVOID)&This->UnknownVtbl;
35                 IDirectMusicGraphImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
36                 return S_OK;    
37         } else if (IsEqualIID (riid, &IID_IDirectMusicGraph)) {
38                 *ppobj = (LPVOID)&This->GraphVtbl;
39                 IDirectMusicGraphImpl_IDirectMusicGraph_AddRef ((LPDIRECTMUSICGRAPH)&This->GraphVtbl);
40                 return S_OK;
41         } else if (IsEqualIID (riid, &IID_IDirectMusicObject)) {
42                 *ppobj = (LPVOID)&This->ObjectVtbl;
43                 IDirectMusicGraphImpl_IDirectMusicObject_AddRef ((LPDIRECTMUSICOBJECT)&This->ObjectVtbl);               
44                 return S_OK;
45         } else if (IsEqualIID (riid, &IID_IPersistStream)) {
46                 *ppobj = (LPVOID)&This->PersistStreamVtbl;
47                 IDirectMusicGraphImpl_IPersistStream_AddRef ((LPPERSISTSTREAM)&This->PersistStreamVtbl);                
48                 return S_OK;
49         }
50         
51         WARN("(%p, %s, %p): not found\n", This, debugstr_guid(riid), ppobj);
52         return E_NOINTERFACE;
53 }
54
55 ULONG WINAPI IDirectMusicGraphImpl_IUnknown_AddRef (LPUNKNOWN iface) {
56         ICOM_THIS_MULTI(IDirectMusicGraphImpl, UnknownVtbl, iface);
57         TRACE("(%p): AddRef from %ld\n", This, This->ref);
58         return ++(This->ref);
59 }
60
61 ULONG WINAPI IDirectMusicGraphImpl_IUnknown_Release (LPUNKNOWN iface) {
62         ICOM_THIS_MULTI(IDirectMusicGraphImpl, UnknownVtbl, iface);
63         ULONG ref = --This->ref;
64         TRACE("(%p): ReleaseRef to %ld\n", This, This->ref);
65         if (ref == 0) {
66                 HeapFree(GetProcessHeap(), 0, This);
67         }
68         return ref;
69 }
70
71 ICOM_VTABLE(IUnknown) DirectMusicGraph_Unknown_Vtbl = {
72     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
73         IDirectMusicGraphImpl_IUnknown_QueryInterface,
74         IDirectMusicGraphImpl_IUnknown_AddRef,
75         IDirectMusicGraphImpl_IUnknown_Release
76 };
77
78 /* IDirectMusicGraphImpl IDirectMusicGraph part: */
79 HRESULT WINAPI IDirectMusicGraphImpl_IDirectMusicGraph_QueryInterface (LPDIRECTMUSICGRAPH iface, REFIID riid, LPVOID *ppobj) {
80         ICOM_THIS_MULTI(IDirectMusicGraphImpl, GraphVtbl, iface);
81         return IDirectMusicGraphImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
82 }
83
84 ULONG WINAPI IDirectMusicGraphImpl_IDirectMusicGraph_AddRef (LPDIRECTMUSICGRAPH iface) {
85         ICOM_THIS_MULTI(IDirectMusicGraphImpl, GraphVtbl, iface);
86         return IDirectMusicGraphImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
87 }
88
89 ULONG WINAPI IDirectMusicGraphImpl_IDirectMusicGraph_Release (LPDIRECTMUSICGRAPH iface) {
90         ICOM_THIS_MULTI(IDirectMusicGraphImpl, GraphVtbl, iface);
91         return IDirectMusicGraphImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
92 }
93
94 HRESULT WINAPI IDirectMusicGraphImpl_IDirectMusicGraph_StampPMsg (LPDIRECTMUSICGRAPH iface, DMUS_PMSG* pPMSG) {
95         ICOM_THIS_MULTI(IDirectMusicGraphImpl, GraphVtbl, iface);
96         FIXME("(%p, %p): stub\n", This, pPMSG);
97         return S_OK;
98 }
99
100 HRESULT WINAPI IDirectMusicGraphImpl_IDirectMusicGraph_InsertTool (LPDIRECTMUSICGRAPH iface, IDirectMusicTool* pTool, DWORD* pdwPChannels, DWORD cPChannels, LONG lIndex) {
101     int i;
102         IDirectMusicTool8Impl* p;
103         IDirectMusicTool8Impl* toAdd = (IDirectMusicTool8Impl*) pTool;
104         ICOM_THIS_MULTI(IDirectMusicGraphImpl, GraphVtbl, iface);
105
106         FIXME("(%p, %p, %p, %ld, %li): use of pdwPChannels\n", This, pTool, pdwPChannels, cPChannels, lIndex);
107
108         if (0 == This->num_tools) {
109           This->pFirst = This->pLast = toAdd;
110           toAdd->pPrev = toAdd->pNext = NULL;
111         } else if (lIndex == 0 || lIndex <= -This->num_tools) {
112           This->pFirst->pPrev = toAdd;
113           toAdd->pNext = This->pFirst;
114           toAdd->pPrev = NULL;
115           This->pFirst = toAdd;
116         } else if (lIndex < 0) {
117           p = This->pLast;
118           for (i = 0; i < -lIndex; ++i) {
119             p = p->pPrev;
120           }
121           toAdd->pNext = p->pNext;
122           if (p->pNext) p->pNext->pPrev = toAdd;
123           p->pNext = toAdd;
124           toAdd->pPrev = p;
125         } else if (lIndex >= This->num_tools) {
126           This->pLast->pNext = toAdd;
127           toAdd->pPrev = This->pLast;
128           toAdd->pNext = NULL;
129           This->pLast = toAdd;
130         } else if (lIndex > 0) {
131           p = This->pFirst;
132           for (i = 0; i < lIndex; ++i) {
133             p = p->pNext;
134           }
135           toAdd->pPrev = p->pPrev;
136           if (p->pPrev) p->pPrev->pNext = toAdd;
137           p->pPrev = toAdd;
138           toAdd->pNext = p;
139         }
140         ++This->num_tools;
141         return DS_OK;
142 }
143
144 HRESULT WINAPI IDirectMusicGraphImpl_IDirectMusicGraph_GetTool (LPDIRECTMUSICGRAPH iface, DWORD dwIndex, IDirectMusicTool** ppTool) {
145         int i;
146         IDirectMusicTool8Impl* p = NULL;
147         ICOM_THIS_MULTI(IDirectMusicGraphImpl, GraphVtbl, iface);
148         
149         FIXME("(%p, %ld, %p): stub\n", This, dwIndex, ppTool);
150
151         p = This->pFirst;
152         for (i = 0; i < dwIndex && i < This->num_tools; ++i) {
153           p = p->pNext;
154         }
155         *ppTool = (IDirectMusicTool*) p;
156         if (NULL != *ppTool) {
157           IDirectMusicTool8Impl_AddRef((LPDIRECTMUSICTOOL8) *ppTool);
158         }
159         return S_OK;
160 }
161
162 HRESULT WINAPI IDirectMusicGraphImpl_IDirectMusicGraph_RemoveTool (LPDIRECTMUSICGRAPH iface, IDirectMusicTool* pTool) {
163         ICOM_THIS_MULTI(IDirectMusicGraphImpl, GraphVtbl, iface);
164         FIXME("(%p, %p): stub\n", This, pTool);
165         return S_OK;
166 }
167
168 ICOM_VTABLE(IDirectMusicGraph) DirectMusicGraph_Graph_Vtbl = {
169     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
170         IDirectMusicGraphImpl_IDirectMusicGraph_QueryInterface,
171         IDirectMusicGraphImpl_IDirectMusicGraph_AddRef,
172         IDirectMusicGraphImpl_IDirectMusicGraph_Release,
173         IDirectMusicGraphImpl_IDirectMusicGraph_StampPMsg,
174         IDirectMusicGraphImpl_IDirectMusicGraph_InsertTool,
175         IDirectMusicGraphImpl_IDirectMusicGraph_GetTool,
176         IDirectMusicGraphImpl_IDirectMusicGraph_RemoveTool
177 };
178
179
180 /* IDirectMusicGraphImpl IDirectMusicObject part: */
181 HRESULT WINAPI IDirectMusicGraphImpl_IDirectMusicObject_QueryInterface (LPDIRECTMUSICOBJECT iface, REFIID riid, LPVOID *ppobj) {
182         ICOM_THIS_MULTI(IDirectMusicGraphImpl, ObjectVtbl, iface);
183         return IDirectMusicGraphImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
184 }
185
186 ULONG WINAPI IDirectMusicGraphImpl_IDirectMusicObject_AddRef (LPDIRECTMUSICOBJECT iface) {
187         ICOM_THIS_MULTI(IDirectMusicGraphImpl, ObjectVtbl, iface);
188         return IDirectMusicGraphImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
189 }
190
191 ULONG WINAPI IDirectMusicGraphImpl_IDirectMusicObject_Release (LPDIRECTMUSICOBJECT iface) {
192         ICOM_THIS_MULTI(IDirectMusicGraphImpl, ObjectVtbl, iface);
193         return IDirectMusicGraphImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
194 }
195
196 HRESULT WINAPI IDirectMusicGraphImpl_IDirectMusicObject_GetDescriptor (LPDIRECTMUSICOBJECT iface, LPDMUS_OBJECTDESC pDesc) {
197         ICOM_THIS_MULTI(IDirectMusicGraphImpl, ObjectVtbl, iface);
198         TRACE("(%p, %p)\n", This, pDesc);
199         /* I think we shouldn't return pointer here since then values can be changed; it'd be a mess */
200         memcpy (pDesc, This->pDesc, This->pDesc->dwSize);
201         return S_OK;
202 }
203
204 HRESULT WINAPI IDirectMusicGraphImpl_IDirectMusicObject_SetDescriptor (LPDIRECTMUSICOBJECT iface, LPDMUS_OBJECTDESC pDesc) {
205         ICOM_THIS_MULTI(IDirectMusicGraphImpl, ObjectVtbl, iface);
206         TRACE("(%p, %p): setting descriptor:\n%s\n", This, pDesc, debugstr_DMUS_OBJECTDESC (pDesc));
207         
208         /* According to MSDN, we should copy only given values, not whole struct */     
209         if (pDesc->dwValidData & DMUS_OBJ_OBJECT)
210                 memcpy (&This->pDesc->guidObject, &pDesc->guidObject, sizeof (pDesc->guidObject));
211         if (pDesc->dwValidData & DMUS_OBJ_CLASS)
212                 memcpy (&This->pDesc->guidClass, &pDesc->guidClass, sizeof (pDesc->guidClass));         
213         if (pDesc->dwValidData & DMUS_OBJ_NAME)
214                 strncpyW (This->pDesc->wszName, pDesc->wszName, DMUS_MAX_NAME);
215         if (pDesc->dwValidData & DMUS_OBJ_CATEGORY)
216                 strncpyW (This->pDesc->wszCategory, pDesc->wszCategory, DMUS_MAX_CATEGORY);             
217         if (pDesc->dwValidData & DMUS_OBJ_FILENAME)
218                 strncpyW (This->pDesc->wszFileName, pDesc->wszFileName, DMUS_MAX_FILENAME);             
219         if (pDesc->dwValidData & DMUS_OBJ_VERSION)
220                 memcpy (&This->pDesc->vVersion, &pDesc->vVersion, sizeof (pDesc->vVersion));                            
221         if (pDesc->dwValidData & DMUS_OBJ_DATE)
222                 memcpy (&This->pDesc->ftDate, &pDesc->ftDate, sizeof (pDesc->ftDate));                          
223         if (pDesc->dwValidData & DMUS_OBJ_MEMORY) {
224                 memcpy (&This->pDesc->llMemLength, &pDesc->llMemLength, sizeof (pDesc->llMemLength));                           
225                 memcpy (This->pDesc->pbMemData, pDesc->pbMemData, sizeof (pDesc->pbMemData));
226         }
227         if (pDesc->dwValidData & DMUS_OBJ_STREAM) {
228                 /* according to MSDN, we copy the stream */
229                 IStream_Clone (pDesc->pStream, &This->pDesc->pStream);  
230         }
231         
232         /* add new flags */
233         This->pDesc->dwValidData |= pDesc->dwValidData;
234
235         return S_OK;
236 }
237
238 HRESULT WINAPI IDirectMusicGraphImpl_IDirectMusicObject_ParseDescriptor (LPDIRECTMUSICOBJECT iface, LPSTREAM pStream, LPDMUS_OBJECTDESC pDesc) {
239         ICOM_THIS_MULTI(IDirectMusicGraphImpl, ObjectVtbl, iface);
240         DMUS_PRIVATE_CHUNK Chunk;
241         DWORD StreamSize, StreamCount, ListSize[1], ListCount[1];
242         LARGE_INTEGER liMove; /* used when skipping chunks */
243
244         TRACE("(%p, %p, %p)\n", This, pStream, pDesc);
245         
246         /* FIXME: should this be determined from stream? */
247         pDesc->dwValidData |= DMUS_OBJ_CLASS;
248         memcpy (&pDesc->guidClass, &CLSID_DirectMusicGraph, sizeof(CLSID));
249         
250         IStream_Read (pStream, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
251         TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
252         switch (Chunk.fccID) {  
253                 case FOURCC_RIFF: {
254                         IStream_Read (pStream, &Chunk.fccID, sizeof(FOURCC), NULL);                             
255                         TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(Chunk.fccID));
256                         StreamSize = Chunk.dwSize - sizeof(FOURCC);
257                         StreamCount = 0;
258                         if (Chunk.fccID == DMUS_FOURCC_TOOLGRAPH_FORM) {
259                                 TRACE_(dmfile)(": graph form\n");
260                                 do {
261                                         IStream_Read (pStream, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
262                                         StreamCount += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
263                                         TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
264                                         switch (Chunk.fccID) {
265                                                 case DMUS_FOURCC_GUID_CHUNK: {
266                                                         TRACE_(dmfile)(": GUID chunk\n");
267                                                         pDesc->dwValidData |= DMUS_OBJ_OBJECT;
268                                                         IStream_Read (pStream, &pDesc->guidObject, Chunk.dwSize, NULL);
269                                                         break;
270                                                 }
271                                                 case DMUS_FOURCC_VERSION_CHUNK: {
272                                                         TRACE_(dmfile)(": version chunk\n");
273                                                         pDesc->dwValidData |= DMUS_OBJ_VERSION;
274                                                         IStream_Read (pStream, &pDesc->vVersion, Chunk.dwSize, NULL);
275                                                         break;
276                                                 }
277                                                 case DMUS_FOURCC_CATEGORY_CHUNK: {
278                                                         TRACE_(dmfile)(": category chunk\n");
279                                                         pDesc->dwValidData |= DMUS_OBJ_CATEGORY;
280                                                         IStream_Read (pStream, pDesc->wszCategory, Chunk.dwSize, NULL);
281                                                         break;
282                                                 }
283                                                 case FOURCC_LIST: {
284                                                         IStream_Read (pStream, &Chunk.fccID, sizeof(FOURCC), NULL);                             
285                                                         TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
286                                                         ListSize[0] = Chunk.dwSize - sizeof(FOURCC);
287                                                         ListCount[0] = 0;
288                                                         switch (Chunk.fccID) {
289                                                                 /* evil M$ UNFO list, which can (!?) contain INFO elements */
290                                                                 case DMUS_FOURCC_UNFO_LIST: {
291                                                                         TRACE_(dmfile)(": UNFO list\n");
292                                                                         do {
293                                                                                 IStream_Read (pStream, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
294                                                                                 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
295                                                                                 TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
296                                                                                 switch (Chunk.fccID) {
297                                                                                         /* don't ask me why, but M$ puts INFO elements in UNFO list sometimes
298                                              (though strings seem to be valid unicode) */
299                                                                                         case mmioFOURCC('I','N','A','M'):
300                                                                                         case DMUS_FOURCC_UNAM_CHUNK: {
301                                                                                                 TRACE_(dmfile)(": name chunk\n");
302                                                                                                 pDesc->dwValidData |= DMUS_OBJ_NAME;
303                                                                                                 IStream_Read (pStream, pDesc->wszName, Chunk.dwSize, NULL);
304                                                                                                 break;
305                                                                                         }
306                                                                                         case mmioFOURCC('I','A','R','T'):
307                                                                                         case DMUS_FOURCC_UART_CHUNK: {
308                                                                                                 TRACE_(dmfile)(": artist chunk (ignored)\n");
309                                                                                                 liMove.QuadPart = Chunk.dwSize;
310                                                                                                 IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
311                                                                                                 break;
312                                                                                         }
313                                                                                         case mmioFOURCC('I','C','O','P'):
314                                                                                         case DMUS_FOURCC_UCOP_CHUNK: {
315                                                                                                 TRACE_(dmfile)(": copyright chunk (ignored)\n");
316                                                                                                 liMove.QuadPart = Chunk.dwSize;
317                                                                                                 IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
318                                                                                                 break;
319                                                                                         }
320                                                                                         case mmioFOURCC('I','S','B','J'):
321                                                                                         case DMUS_FOURCC_USBJ_CHUNK: {
322                                                                                                 TRACE_(dmfile)(": subject chunk (ignored)\n");
323                                                                                                 liMove.QuadPart = Chunk.dwSize;
324                                                                                                 IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
325                                                                                                 break;
326                                                                                         }
327                                                                                         case mmioFOURCC('I','C','M','T'):
328                                                                                         case DMUS_FOURCC_UCMT_CHUNK: {
329                                                                                                 TRACE_(dmfile)(": comment chunk (ignored)\n");
330                                                                                                 liMove.QuadPart = Chunk.dwSize;
331                                                                                                 IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
332                                                                                                 break;
333                                                                                         }
334                                                                                         default: {
335                                                                                                 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
336                                                                                                 liMove.QuadPart = Chunk.dwSize;
337                                                                                                 IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
338                                                                                                 break;                                          
339                                                                                         }
340                                                                                 }
341                                                                                 TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]);
342                                                                         } while (ListCount[0] < ListSize[0]);
343                                                                         break;
344                                                                 }
345                                                                 default: {
346                                                                         TRACE_(dmfile)(": unknown (skipping)\n");
347                                                                         liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
348                                                                         IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
349                                                                         break;                                          
350                                                                 }
351                                                         }
352                                                         break;
353                                                 }       
354                                                 default: {
355                                                         TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
356                                                         liMove.QuadPart = Chunk.dwSize;
357                                                         IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
358                                                         break;                                          
359                                                 }
360                                         }
361                                         TRACE_(dmfile)(": StreamCount[0] = %ld < StreamSize[0] = %ld\n", StreamCount, StreamSize);
362                                 } while (StreamCount < StreamSize);
363                                 break;
364                         } else {
365                                 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
366                                 liMove.QuadPart = StreamSize;
367                                 IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
368                                 return E_FAIL;
369                         }
370                 
371                         TRACE_(dmfile)(": reading finished\n");
372                         break;
373                 }
374                 default: {
375                         TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
376                         liMove.QuadPart = Chunk.dwSize;
377                         IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
378                         return DMUS_E_INVALIDFILE;
379                 }
380         }       
381         
382         TRACE(": returning descriptor:\n%s\n", debugstr_DMUS_OBJECTDESC (pDesc));
383         
384         return S_OK;
385 }
386
387 ICOM_VTABLE(IDirectMusicObject) DirectMusicGraph_Object_Vtbl = {
388     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
389         IDirectMusicGraphImpl_IDirectMusicObject_QueryInterface,
390         IDirectMusicGraphImpl_IDirectMusicObject_AddRef,
391         IDirectMusicGraphImpl_IDirectMusicObject_Release,
392         IDirectMusicGraphImpl_IDirectMusicObject_GetDescriptor,
393         IDirectMusicGraphImpl_IDirectMusicObject_SetDescriptor,
394         IDirectMusicGraphImpl_IDirectMusicObject_ParseDescriptor
395 };
396
397 /* IDirectMusicGraphImpl IPersistStream part: */
398 HRESULT WINAPI IDirectMusicGraphImpl_IPersistStream_QueryInterface (LPPERSISTSTREAM iface, REFIID riid, LPVOID *ppobj) {
399         ICOM_THIS_MULTI(IDirectMusicGraphImpl, PersistStreamVtbl, iface);
400         return IDirectMusicGraphImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
401 }
402
403 ULONG WINAPI IDirectMusicGraphImpl_IPersistStream_AddRef (LPPERSISTSTREAM iface) {
404         ICOM_THIS_MULTI(IDirectMusicGraphImpl, PersistStreamVtbl, iface);
405         return IDirectMusicGraphImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
406 }
407
408 ULONG WINAPI IDirectMusicGraphImpl_IPersistStream_Release (LPPERSISTSTREAM iface) {
409         ICOM_THIS_MULTI(IDirectMusicGraphImpl, PersistStreamVtbl, iface);
410         return IDirectMusicGraphImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
411 }
412
413 HRESULT WINAPI IDirectMusicGraphImpl_IPersistStream_GetClassID (LPPERSISTSTREAM iface, CLSID* pClassID) {
414         return E_NOTIMPL;
415 }
416
417 HRESULT WINAPI IDirectMusicGraphImpl_IPersistStream_IsDirty (LPPERSISTSTREAM iface) {
418         return E_NOTIMPL;
419 }
420
421 HRESULT WINAPI IDirectMusicGraphImpl_IPersistStream_Load (LPPERSISTSTREAM iface, IStream* pStm) {
422         ICOM_THIS_MULTI(IDirectMusicGraphImpl, PersistStreamVtbl, iface);
423         FOURCC chunkID;
424         DWORD chunkSize, StreamSize, StreamCount, ListSize[3], ListCount[3];
425         LARGE_INTEGER liMove; /* used when skipping chunks */
426
427         FIXME("(%p, %p): Loading not implemented yet\n", This, pStm);
428         IStream_Read (pStm, &chunkID, sizeof(FOURCC), NULL);
429         IStream_Read (pStm, &chunkSize, sizeof(DWORD), NULL);
430         TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (chunkID), chunkSize);
431         switch (chunkID) {      
432                 case FOURCC_RIFF: {
433                         IStream_Read (pStm, &chunkID, sizeof(FOURCC), NULL);                            
434                         TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(chunkID));
435                         StreamSize = chunkSize - sizeof(FOURCC);
436                         StreamCount = 0;
437                         switch (chunkID) {
438                                 case DMUS_FOURCC_TOOLGRAPH_FORM: {
439                                         TRACE_(dmfile)(": graph form\n");
440                                         do {
441                                                 IStream_Read (pStm, &chunkID, sizeof(FOURCC), NULL);
442                                                 IStream_Read (pStm, &chunkSize, sizeof(FOURCC), NULL);
443                                                 StreamCount += sizeof(FOURCC) + sizeof(DWORD) + chunkSize;
444                                                 TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (chunkID), chunkSize);
445                                                 switch (chunkID) {
446                                                         case DMUS_FOURCC_GUID_CHUNK: {
447                                                                 TRACE_(dmfile)(": GUID chunk\n");
448                                                                 This->pDesc->dwValidData |= DMUS_OBJ_OBJECT;
449                                                                 IStream_Read (pStm, &This->pDesc->guidObject, chunkSize, NULL);
450                                                                 break;
451                                                         }
452                                                         case DMUS_FOURCC_VERSION_CHUNK: {
453                                                                 TRACE_(dmfile)(": version chunk\n");
454                                                                 This->pDesc->dwValidData |= DMUS_OBJ_VERSION;
455                                                                 IStream_Read (pStm, &This->pDesc->vVersion, chunkSize, NULL);
456                                                                 break;
457                                                         }
458                                                         case DMUS_FOURCC_CATEGORY_CHUNK: {
459                                                                 TRACE_(dmfile)(": category chunk\n");
460                                                                 This->pDesc->dwValidData |= DMUS_OBJ_CATEGORY;
461                                                                 IStream_Read (pStm, This->pDesc->wszCategory, chunkSize, NULL);
462                                                                 break;
463                                                         }
464                                                         case FOURCC_LIST: {
465                                                                 IStream_Read (pStm, &chunkID, sizeof(FOURCC), NULL);                            
466                                                                 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunkID));
467                                                                 ListSize[0] = chunkSize - sizeof(FOURCC);
468                                                                 ListCount[0] = 0;
469                                                                 switch (chunkID) {
470                                                                         case DMUS_FOURCC_UNFO_LIST: {
471                                                                                 TRACE_(dmfile)(": UNFO list\n");
472                                                                                 do {
473                                                                                         IStream_Read (pStm, &chunkID, sizeof(FOURCC), NULL);
474                                                                                         IStream_Read (pStm, &chunkSize, sizeof(FOURCC), NULL);
475                                                                                         ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + chunkSize;
476                                                                                         TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (chunkID), chunkSize);
477                                                                                         switch (chunkID) {
478                                                                                                 /* don't ask me why, but M$ puts INFO elements in UNFO list sometimes
479                                               (though strings seem to be valid unicode) */
480                                                                                                 case mmioFOURCC('I','N','A','M'):
481                                                                                                 case DMUS_FOURCC_UNAM_CHUNK: {
482                                                                                                         TRACE_(dmfile)(": name chunk\n");
483                                                                                                         This->pDesc->dwValidData |= DMUS_OBJ_NAME;
484                                                                                                         IStream_Read (pStm, This->pDesc->wszName, chunkSize, NULL);
485                                                                                                         break;
486                                                                                                 }
487                                                                                                 case mmioFOURCC('I','A','R','T'):
488                                                                                                 case DMUS_FOURCC_UART_CHUNK: {
489                                                                                                         TRACE_(dmfile)(": artist chunk (ignored)\n");
490                                                                                                         liMove.QuadPart = chunkSize;
491                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
492                                                                                                         break;
493                                                                                                 }
494                                                                                                 case mmioFOURCC('I','C','O','P'):
495                                                                                                 case DMUS_FOURCC_UCOP_CHUNK: {
496                                                                                                         TRACE_(dmfile)(": copyright chunk (ignored)\n");
497                                                                                                         liMove.QuadPart = chunkSize;
498                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
499                                                                                                         break;
500                                                                                                 }
501                                                                                                 case mmioFOURCC('I','S','B','J'):
502                                                                                                 case DMUS_FOURCC_USBJ_CHUNK: {
503                                                                                                         TRACE_(dmfile)(": subject chunk (ignored)\n");
504                                                                                                         liMove.QuadPart = chunkSize;
505                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
506                                                                                                         break;
507                                                                                                 }
508                                                                                                 case mmioFOURCC('I','C','M','T'):
509                                                                                                 case DMUS_FOURCC_UCMT_CHUNK: {
510                                                                                                         TRACE_(dmfile)(": comment chunk (ignored)\n");
511                                                                                                         liMove.QuadPart = chunkSize;
512                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
513                                                                                                         break;
514                                                                                                 }
515                                                                                                 default: {
516                                                                                                         TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
517                                                                                                         liMove.QuadPart = chunkSize;
518                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
519                                                                                                         break;                                          
520                                                                                                 }
521                                                                                         }
522                                                                                         TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]);
523                                                                                 } while (ListCount[0] < ListSize[0]);
524                                                                                 break;
525                                                                         }
526                                                                         default: {
527                                                                                 TRACE_(dmfile)(": unknown (skipping)\n");
528                                                                                 liMove.QuadPart = chunkSize - sizeof(FOURCC);
529                                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
530                                                                                 break;                                          
531                                                                         }
532                                                                 }
533                                                                 break;
534                                                         }       
535                                                         default: {
536                                                                 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
537                                                                 liMove.QuadPart = chunkSize;
538                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
539                                                                 break;                                          
540                                                         }
541                                                 }
542                                                 TRACE_(dmfile)(": StreamCount[0] = %ld < StreamSize[0] = %ld\n", StreamCount, StreamSize);
543                                         } while (StreamCount < StreamSize);
544                                         break;
545                                 }
546                                 default: {
547                                         TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
548                                         liMove.QuadPart = StreamSize;
549                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
550                                         return E_FAIL;
551                                 }
552                         }
553                         TRACE_(dmfile)(": reading finished\n");
554                         break;
555                 }
556                 default: {
557                         TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
558                         liMove.QuadPart = chunkSize;
559                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
560                         return E_FAIL;
561                 }
562         }
563
564         return S_OK;
565 }
566
567 HRESULT WINAPI IDirectMusicGraphImpl_IPersistStream_Save (LPPERSISTSTREAM iface, IStream* pStm, BOOL fClearDirty) {
568         return E_NOTIMPL;
569 }
570
571 HRESULT WINAPI IDirectMusicGraphImpl_IPersistStream_GetSizeMax (LPPERSISTSTREAM iface, ULARGE_INTEGER* pcbSize) {
572         return E_NOTIMPL;
573 }
574
575 ICOM_VTABLE(IPersistStream) DirectMusicGraph_PersistStream_Vtbl = {
576     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
577         IDirectMusicGraphImpl_IPersistStream_QueryInterface,
578         IDirectMusicGraphImpl_IPersistStream_AddRef,
579         IDirectMusicGraphImpl_IPersistStream_Release,
580         IDirectMusicGraphImpl_IPersistStream_GetClassID,
581         IDirectMusicGraphImpl_IPersistStream_IsDirty,
582         IDirectMusicGraphImpl_IPersistStream_Load,
583         IDirectMusicGraphImpl_IPersistStream_Save,
584         IDirectMusicGraphImpl_IPersistStream_GetSizeMax
585 };
586
587 /* for ClassFactory */
588 HRESULT WINAPI DMUSIC_CreateDirectMusicGraphImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter) {
589         IDirectMusicGraphImpl* obj;
590         
591         obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicGraphImpl));
592         if (NULL == obj) {
593                 *ppobj = (LPVOID) NULL;
594                 return E_OUTOFMEMORY;
595         }
596         obj->UnknownVtbl = &DirectMusicGraph_Unknown_Vtbl;
597         obj->GraphVtbl = &DirectMusicGraph_Graph_Vtbl;
598         obj->ObjectVtbl = &DirectMusicGraph_Object_Vtbl;
599         obj->PersistStreamVtbl = &DirectMusicGraph_PersistStream_Vtbl;
600         obj->pDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DMUS_OBJECTDESC));
601         DM_STRUCT_INIT(obj->pDesc);
602         obj->pDesc->dwValidData |= DMUS_OBJ_CLASS;
603         memcpy (&obj->pDesc->guidClass, &CLSID_DirectMusicGraph, sizeof (CLSID));
604         obj->ref = 0; /* will be inited by QueryInterface */
605         
606         return IDirectMusicGraphImpl_IUnknown_QueryInterface ((LPUNKNOWN)&obj->UnknownVtbl, lpcGUID, ppobj);
607 }