Release 1.5.0.
[wine/multimedia.git] / dlls / dmime / graph.c
blob30edd2a648e8248592c10bbf95c195270c150d25
1 /* IDirectMusicGraph
3 * Copyright (C) 2003-2004 Rok Mandeljc
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
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 GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "dmime_private.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(dmime);
23 WINE_DECLARE_DEBUG_CHANNEL(dmfile);
25 /*****************************************************************************
26 * IDirectMusicGraphImpl implementation
28 /* IDirectMusicGraphImpl IUnknown part: */
29 static 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);
33 if (IsEqualIID (riid, &IID_IUnknown)) {
34 *ppobj = &This->UnknownVtbl;
35 IUnknown_AddRef (iface);
36 return S_OK;
37 } else if (IsEqualIID (riid, &IID_IDirectMusicGraph)) {
38 *ppobj = &This->GraphVtbl;
39 IUnknown_AddRef (iface);
40 return S_OK;
41 } else if (IsEqualIID (riid, &IID_IDirectMusicObject)) {
42 *ppobj = &This->ObjectVtbl;
43 IUnknown_AddRef (iface);
44 return S_OK;
45 } else if (IsEqualIID (riid, &IID_IPersistStream)) {
46 *ppobj = &This->PersistStreamVtbl;
47 IUnknown_AddRef (iface);
48 return S_OK;
51 WARN("(%p, %s, %p): not found\n", This, debugstr_guid(riid), ppobj);
52 return E_NOINTERFACE;
55 static ULONG WINAPI IDirectMusicGraphImpl_IUnknown_AddRef (LPUNKNOWN iface) {
56 ICOM_THIS_MULTI(IDirectMusicGraphImpl, UnknownVtbl, iface);
57 ULONG ref = InterlockedIncrement(&This->ref);
59 TRACE("(%p): AddRef from %d\n", This, ref - 1);
61 DMIME_LockModule();
63 return ref;
66 static ULONG WINAPI IDirectMusicGraphImpl_IUnknown_Release (LPUNKNOWN iface) {
67 ICOM_THIS_MULTI(IDirectMusicGraphImpl, UnknownVtbl, iface);
68 ULONG ref = InterlockedDecrement(&This->ref);
69 TRACE("(%p): ReleaseRef to %d\n", This, ref);
71 if (ref == 0) {
72 HeapFree(GetProcessHeap(), 0, This);
75 DMIME_UnlockModule();
77 return ref;
80 static const IUnknownVtbl DirectMusicGraph_Unknown_Vtbl = {
81 IDirectMusicGraphImpl_IUnknown_QueryInterface,
82 IDirectMusicGraphImpl_IUnknown_AddRef,
83 IDirectMusicGraphImpl_IUnknown_Release
86 /* IDirectMusicGraphImpl IDirectMusicGraph part: */
87 static HRESULT WINAPI IDirectMusicGraphImpl_IDirectMusicGraph_QueryInterface (LPDIRECTMUSICGRAPH iface, REFIID riid, LPVOID *ppobj) {
88 ICOM_THIS_MULTI(IDirectMusicGraphImpl, GraphVtbl, iface);
89 return IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
92 static ULONG WINAPI IDirectMusicGraphImpl_IDirectMusicGraph_AddRef (LPDIRECTMUSICGRAPH iface) {
93 ICOM_THIS_MULTI(IDirectMusicGraphImpl, GraphVtbl, iface);
94 return IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
97 static ULONG WINAPI IDirectMusicGraphImpl_IDirectMusicGraph_Release (LPDIRECTMUSICGRAPH iface) {
98 ICOM_THIS_MULTI(IDirectMusicGraphImpl, GraphVtbl, iface);
99 return IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
102 static HRESULT WINAPI IDirectMusicGraphImpl_IDirectMusicGraph_StampPMsg (LPDIRECTMUSICGRAPH iface, DMUS_PMSG* pPMSG) {
103 ICOM_THIS_MULTI(IDirectMusicGraphImpl, GraphVtbl, iface);
104 FIXME("(%p, %p): stub\n", This, pPMSG);
105 return S_OK;
108 static HRESULT WINAPI IDirectMusicGraphImpl_IDirectMusicGraph_InsertTool (LPDIRECTMUSICGRAPH iface, IDirectMusicTool* pTool, DWORD* pdwPChannels, DWORD cPChannels, LONG lIndex) {
109 ICOM_THIS_MULTI(IDirectMusicGraphImpl, GraphVtbl, iface);
111 struct list* pEntry = NULL;
112 struct list* pPrevEntry = NULL;
113 LPDMUS_PRIVATE_GRAPH_TOOL pIt = NULL;
114 LPDMUS_PRIVATE_GRAPH_TOOL pNewTool = NULL;
117 FIXME("(%p, %p, %p, %d, %i): use of pdwPChannels\n", This, pTool, pdwPChannels, cPChannels, lIndex);
119 if (NULL == pTool) {
120 return E_POINTER;
123 if (0 > lIndex) {
124 lIndex = This->num_tools + lIndex;
127 pPrevEntry = &This->Tools;
128 LIST_FOR_EACH (pEntry, &This->Tools) {
129 pIt = LIST_ENTRY(pEntry, DMUS_PRIVATE_GRAPH_TOOL, entry);
130 if (pIt->dwIndex == lIndex) {
131 return DMUS_E_ALREADY_EXISTS;
133 if (pIt->dwIndex > lIndex) {
134 break ;
136 pPrevEntry = pEntry;
139 ++This->num_tools;
140 pNewTool = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_GRAPH_TOOL));
141 pNewTool->pTool = pTool;
142 pNewTool->dwIndex = lIndex;
143 IDirectMusicTool8_AddRef(pTool);
144 IDirectMusicTool8_Init(pTool, iface);
145 list_add_tail (pPrevEntry->next, &pNewTool->entry);
147 #if 0
148 DWORD dwNum = 0;
149 IDirectMusicTool8_GetMediaTypes(pTool, &dwNum);
150 #endif
152 return DS_OK;
155 static HRESULT WINAPI IDirectMusicGraphImpl_IDirectMusicGraph_GetTool (LPDIRECTMUSICGRAPH iface, DWORD dwIndex, IDirectMusicTool** ppTool) {
156 ICOM_THIS_MULTI(IDirectMusicGraphImpl, GraphVtbl, iface);
157 struct list* pEntry = NULL;
158 LPDMUS_PRIVATE_GRAPH_TOOL pIt = NULL;
160 FIXME("(%p, %d, %p): stub\n", This, dwIndex, ppTool);
162 LIST_FOR_EACH (pEntry, &This->Tools) {
163 pIt = LIST_ENTRY(pEntry, DMUS_PRIVATE_GRAPH_TOOL, entry);
164 if (pIt->dwIndex == dwIndex) {
165 *ppTool = pIt->pTool;
166 if (NULL != *ppTool) {
167 IDirectMusicTool8_AddRef((LPDIRECTMUSICTOOL8) *ppTool);
169 return S_OK;
171 if (pIt->dwIndex > dwIndex) {
172 break ;
176 return DMUS_E_NOT_FOUND;
179 static HRESULT WINAPI IDirectMusicGraphImpl_IDirectMusicGraph_RemoveTool (LPDIRECTMUSICGRAPH iface, IDirectMusicTool* pTool) {
180 ICOM_THIS_MULTI(IDirectMusicGraphImpl, GraphVtbl, iface);
181 FIXME("(%p, %p): stub\n", This, pTool);
182 return S_OK;
185 static const IDirectMusicGraphVtbl DirectMusicGraph_Graph_Vtbl = {
186 IDirectMusicGraphImpl_IDirectMusicGraph_QueryInterface,
187 IDirectMusicGraphImpl_IDirectMusicGraph_AddRef,
188 IDirectMusicGraphImpl_IDirectMusicGraph_Release,
189 IDirectMusicGraphImpl_IDirectMusicGraph_StampPMsg,
190 IDirectMusicGraphImpl_IDirectMusicGraph_InsertTool,
191 IDirectMusicGraphImpl_IDirectMusicGraph_GetTool,
192 IDirectMusicGraphImpl_IDirectMusicGraph_RemoveTool
196 /* IDirectMusicGraphImpl IDirectMusicObject part: */
197 static HRESULT WINAPI IDirectMusicGraphImpl_IDirectMusicObject_QueryInterface (LPDIRECTMUSICOBJECT iface, REFIID riid, LPVOID *ppobj) {
198 ICOM_THIS_MULTI(IDirectMusicGraphImpl, ObjectVtbl, iface);
199 return IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
202 static ULONG WINAPI IDirectMusicGraphImpl_IDirectMusicObject_AddRef (LPDIRECTMUSICOBJECT iface) {
203 ICOM_THIS_MULTI(IDirectMusicGraphImpl, ObjectVtbl, iface);
204 return IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
207 static ULONG WINAPI IDirectMusicGraphImpl_IDirectMusicObject_Release (LPDIRECTMUSICOBJECT iface) {
208 ICOM_THIS_MULTI(IDirectMusicGraphImpl, ObjectVtbl, iface);
209 return IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
212 static HRESULT WINAPI IDirectMusicGraphImpl_IDirectMusicObject_GetDescriptor (LPDIRECTMUSICOBJECT iface, LPDMUS_OBJECTDESC pDesc) {
213 ICOM_THIS_MULTI(IDirectMusicGraphImpl, ObjectVtbl, iface);
214 TRACE("(%p, %p)\n", This, pDesc);
215 /* I think we shouldn't return pointer here since then values can be changed; it'd be a mess */
216 memcpy (pDesc, This->pDesc, This->pDesc->dwSize);
217 return S_OK;
220 static HRESULT WINAPI IDirectMusicGraphImpl_IDirectMusicObject_SetDescriptor (LPDIRECTMUSICOBJECT iface, LPDMUS_OBJECTDESC pDesc) {
221 ICOM_THIS_MULTI(IDirectMusicGraphImpl, ObjectVtbl, iface);
222 TRACE("(%p, %p): setting descriptor:\n%s\n", This, pDesc, debugstr_DMUS_OBJECTDESC (pDesc));
224 /* According to MSDN, we should copy only given values, not whole struct */
225 if (pDesc->dwValidData & DMUS_OBJ_OBJECT)
226 This->pDesc->guidObject = pDesc->guidObject;
227 if (pDesc->dwValidData & DMUS_OBJ_CLASS)
228 This->pDesc->guidClass = pDesc->guidClass;
229 if (pDesc->dwValidData & DMUS_OBJ_NAME)
230 lstrcpynW (This->pDesc->wszName, pDesc->wszName, DMUS_MAX_NAME);
231 if (pDesc->dwValidData & DMUS_OBJ_CATEGORY)
232 lstrcpynW (This->pDesc->wszCategory, pDesc->wszCategory, DMUS_MAX_CATEGORY);
233 if (pDesc->dwValidData & DMUS_OBJ_FILENAME)
234 lstrcpynW (This->pDesc->wszFileName, pDesc->wszFileName, DMUS_MAX_FILENAME);
235 if (pDesc->dwValidData & DMUS_OBJ_VERSION)
236 This->pDesc->vVersion = pDesc->vVersion;
237 if (pDesc->dwValidData & DMUS_OBJ_DATE)
238 This->pDesc->ftDate = pDesc->ftDate;
239 if (pDesc->dwValidData & DMUS_OBJ_MEMORY) {
240 This->pDesc->llMemLength = pDesc->llMemLength;
241 memcpy (This->pDesc->pbMemData, pDesc->pbMemData, pDesc->llMemLength);
243 if (pDesc->dwValidData & DMUS_OBJ_STREAM) {
244 /* according to MSDN, we copy the stream */
245 IStream_Clone (pDesc->pStream, &This->pDesc->pStream);
248 /* add new flags */
249 This->pDesc->dwValidData |= pDesc->dwValidData;
251 return S_OK;
254 static HRESULT WINAPI IDirectMusicGraphImpl_IDirectMusicObject_ParseDescriptor (LPDIRECTMUSICOBJECT iface, LPSTREAM pStream, LPDMUS_OBJECTDESC pDesc) {
255 ICOM_THIS_MULTI(IDirectMusicGraphImpl, ObjectVtbl, iface);
256 DMUS_PRIVATE_CHUNK Chunk;
257 DWORD StreamSize, StreamCount, ListSize[1], ListCount[1];
258 LARGE_INTEGER liMove; /* used when skipping chunks */
260 TRACE("(%p, %p, %p)\n", This, pStream, pDesc);
262 /* FIXME: should this be determined from stream? */
263 pDesc->dwValidData |= DMUS_OBJ_CLASS;
264 pDesc->guidClass = CLSID_DirectMusicGraph;
266 IStream_Read (pStream, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
267 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
268 switch (Chunk.fccID) {
269 case FOURCC_RIFF: {
270 IStream_Read (pStream, &Chunk.fccID, sizeof(FOURCC), NULL);
271 TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(Chunk.fccID));
272 StreamSize = Chunk.dwSize - sizeof(FOURCC);
273 StreamCount = 0;
274 if (Chunk.fccID == DMUS_FOURCC_TOOLGRAPH_FORM) {
275 TRACE_(dmfile)(": graph form\n");
276 do {
277 IStream_Read (pStream, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
278 StreamCount += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
279 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
280 switch (Chunk.fccID) {
281 case DMUS_FOURCC_GUID_CHUNK: {
282 TRACE_(dmfile)(": GUID chunk\n");
283 pDesc->dwValidData |= DMUS_OBJ_OBJECT;
284 IStream_Read (pStream, &pDesc->guidObject, Chunk.dwSize, NULL);
285 break;
287 case DMUS_FOURCC_VERSION_CHUNK: {
288 TRACE_(dmfile)(": version chunk\n");
289 pDesc->dwValidData |= DMUS_OBJ_VERSION;
290 IStream_Read (pStream, &pDesc->vVersion, Chunk.dwSize, NULL);
291 break;
293 case DMUS_FOURCC_CATEGORY_CHUNK: {
294 TRACE_(dmfile)(": category chunk\n");
295 pDesc->dwValidData |= DMUS_OBJ_CATEGORY;
296 IStream_Read (pStream, pDesc->wszCategory, Chunk.dwSize, NULL);
297 break;
299 case FOURCC_LIST: {
300 IStream_Read (pStream, &Chunk.fccID, sizeof(FOURCC), NULL);
301 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
302 ListSize[0] = Chunk.dwSize - sizeof(FOURCC);
303 ListCount[0] = 0;
304 switch (Chunk.fccID) {
305 /* evil M$ UNFO list, which can (!?) contain INFO elements */
306 case DMUS_FOURCC_UNFO_LIST: {
307 TRACE_(dmfile)(": UNFO list\n");
308 do {
309 IStream_Read (pStream, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
310 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
311 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
312 switch (Chunk.fccID) {
313 /* don't ask me why, but M$ puts INFO elements in UNFO list sometimes
314 (though strings seem to be valid unicode) */
315 case mmioFOURCC('I','N','A','M'):
316 case DMUS_FOURCC_UNAM_CHUNK: {
317 TRACE_(dmfile)(": name chunk\n");
318 pDesc->dwValidData |= DMUS_OBJ_NAME;
319 IStream_Read (pStream, pDesc->wszName, Chunk.dwSize, NULL);
320 break;
322 case mmioFOURCC('I','A','R','T'):
323 case DMUS_FOURCC_UART_CHUNK: {
324 TRACE_(dmfile)(": artist chunk (ignored)\n");
325 liMove.QuadPart = Chunk.dwSize;
326 IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
327 break;
329 case mmioFOURCC('I','C','O','P'):
330 case DMUS_FOURCC_UCOP_CHUNK: {
331 TRACE_(dmfile)(": copyright chunk (ignored)\n");
332 liMove.QuadPart = Chunk.dwSize;
333 IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
334 break;
336 case mmioFOURCC('I','S','B','J'):
337 case DMUS_FOURCC_USBJ_CHUNK: {
338 TRACE_(dmfile)(": subject chunk (ignored)\n");
339 liMove.QuadPart = Chunk.dwSize;
340 IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
341 break;
343 case mmioFOURCC('I','C','M','T'):
344 case DMUS_FOURCC_UCMT_CHUNK: {
345 TRACE_(dmfile)(": comment chunk (ignored)\n");
346 liMove.QuadPart = Chunk.dwSize;
347 IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
348 break;
350 default: {
351 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
352 liMove.QuadPart = Chunk.dwSize;
353 IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
354 break;
357 TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
358 } while (ListCount[0] < ListSize[0]);
359 break;
361 default: {
362 TRACE_(dmfile)(": unknown (skipping)\n");
363 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
364 IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
365 break;
368 break;
370 default: {
371 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
372 liMove.QuadPart = Chunk.dwSize;
373 IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
374 break;
377 TRACE_(dmfile)(": StreamCount[0] = %d < StreamSize[0] = %d\n", StreamCount, StreamSize);
378 } while (StreamCount < StreamSize);
379 } else {
380 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
381 liMove.QuadPart = StreamSize;
382 IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
383 return E_FAIL;
386 TRACE_(dmfile)(": reading finished\n");
387 break;
389 default: {
390 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
391 liMove.QuadPart = Chunk.dwSize;
392 IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
393 return DMUS_E_INVALIDFILE;
397 TRACE(": returning descriptor:\n%s\n", debugstr_DMUS_OBJECTDESC (pDesc));
399 return S_OK;
402 static const IDirectMusicObjectVtbl DirectMusicGraph_Object_Vtbl = {
403 IDirectMusicGraphImpl_IDirectMusicObject_QueryInterface,
404 IDirectMusicGraphImpl_IDirectMusicObject_AddRef,
405 IDirectMusicGraphImpl_IDirectMusicObject_Release,
406 IDirectMusicGraphImpl_IDirectMusicObject_GetDescriptor,
407 IDirectMusicGraphImpl_IDirectMusicObject_SetDescriptor,
408 IDirectMusicGraphImpl_IDirectMusicObject_ParseDescriptor
411 /* IDirectMusicGraphImpl IPersistStream part: */
412 static HRESULT WINAPI IDirectMusicGraphImpl_IPersistStream_QueryInterface (LPPERSISTSTREAM iface, REFIID riid, LPVOID *ppobj) {
413 ICOM_THIS_MULTI(IDirectMusicGraphImpl, PersistStreamVtbl, iface);
414 return IDirectMusicGraphImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
417 static ULONG WINAPI IDirectMusicGraphImpl_IPersistStream_AddRef (LPPERSISTSTREAM iface) {
418 ICOM_THIS_MULTI(IDirectMusicGraphImpl, PersistStreamVtbl, iface);
419 return IDirectMusicGraphImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
422 static ULONG WINAPI IDirectMusicGraphImpl_IPersistStream_Release (LPPERSISTSTREAM iface) {
423 ICOM_THIS_MULTI(IDirectMusicGraphImpl, PersistStreamVtbl, iface);
424 return IDirectMusicGraphImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
427 static HRESULT WINAPI IDirectMusicGraphImpl_IPersistStream_GetClassID (LPPERSISTSTREAM iface, CLSID* pClassID) {
428 return E_NOTIMPL;
431 static HRESULT WINAPI IDirectMusicGraphImpl_IPersistStream_IsDirty (LPPERSISTSTREAM iface) {
432 return E_NOTIMPL;
435 static HRESULT WINAPI IDirectMusicGraphImpl_IPersistStream_Load (LPPERSISTSTREAM iface, IStream* pStm) {
436 ICOM_THIS_MULTI(IDirectMusicGraphImpl, PersistStreamVtbl, iface);
437 FOURCC chunkID;
438 DWORD chunkSize, StreamSize, StreamCount, ListSize[3], ListCount[3];
439 LARGE_INTEGER liMove; /* used when skipping chunks */
441 FIXME("(%p, %p): Loading not implemented yet\n", This, pStm);
442 IStream_Read (pStm, &chunkID, sizeof(FOURCC), NULL);
443 IStream_Read (pStm, &chunkSize, sizeof(DWORD), NULL);
444 TRACE_(dmfile)(": %s chunk (size = %d)", debugstr_fourcc (chunkID), chunkSize);
445 switch (chunkID) {
446 case FOURCC_RIFF: {
447 IStream_Read (pStm, &chunkID, sizeof(FOURCC), NULL);
448 TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(chunkID));
449 StreamSize = chunkSize - sizeof(FOURCC);
450 StreamCount = 0;
451 switch (chunkID) {
452 case DMUS_FOURCC_TOOLGRAPH_FORM: {
453 TRACE_(dmfile)(": graph form\n");
454 do {
455 IStream_Read (pStm, &chunkID, sizeof(FOURCC), NULL);
456 IStream_Read (pStm, &chunkSize, sizeof(FOURCC), NULL);
457 StreamCount += sizeof(FOURCC) + sizeof(DWORD) + chunkSize;
458 TRACE_(dmfile)(": %s chunk (size = %d)", debugstr_fourcc (chunkID), chunkSize);
459 switch (chunkID) {
460 case DMUS_FOURCC_GUID_CHUNK: {
461 TRACE_(dmfile)(": GUID chunk\n");
462 This->pDesc->dwValidData |= DMUS_OBJ_OBJECT;
463 IStream_Read (pStm, &This->pDesc->guidObject, chunkSize, NULL);
464 break;
466 case DMUS_FOURCC_VERSION_CHUNK: {
467 TRACE_(dmfile)(": version chunk\n");
468 This->pDesc->dwValidData |= DMUS_OBJ_VERSION;
469 IStream_Read (pStm, &This->pDesc->vVersion, chunkSize, NULL);
470 break;
472 case DMUS_FOURCC_CATEGORY_CHUNK: {
473 TRACE_(dmfile)(": category chunk\n");
474 This->pDesc->dwValidData |= DMUS_OBJ_CATEGORY;
475 IStream_Read (pStm, This->pDesc->wszCategory, chunkSize, NULL);
476 break;
478 case FOURCC_LIST: {
479 IStream_Read (pStm, &chunkID, sizeof(FOURCC), NULL);
480 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunkID));
481 ListSize[0] = chunkSize - sizeof(FOURCC);
482 ListCount[0] = 0;
483 switch (chunkID) {
484 case DMUS_FOURCC_UNFO_LIST: {
485 TRACE_(dmfile)(": UNFO list\n");
486 do {
487 IStream_Read (pStm, &chunkID, sizeof(FOURCC), NULL);
488 IStream_Read (pStm, &chunkSize, sizeof(FOURCC), NULL);
489 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + chunkSize;
490 TRACE_(dmfile)(": %s chunk (size = %d)", debugstr_fourcc (chunkID), chunkSize);
491 switch (chunkID) {
492 /* don't ask me why, but M$ puts INFO elements in UNFO list sometimes
493 (though strings seem to be valid unicode) */
494 case mmioFOURCC('I','N','A','M'):
495 case DMUS_FOURCC_UNAM_CHUNK: {
496 TRACE_(dmfile)(": name chunk\n");
497 This->pDesc->dwValidData |= DMUS_OBJ_NAME;
498 IStream_Read (pStm, This->pDesc->wszName, chunkSize, NULL);
499 break;
501 case mmioFOURCC('I','A','R','T'):
502 case DMUS_FOURCC_UART_CHUNK: {
503 TRACE_(dmfile)(": artist chunk (ignored)\n");
504 liMove.QuadPart = chunkSize;
505 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
506 break;
508 case mmioFOURCC('I','C','O','P'):
509 case DMUS_FOURCC_UCOP_CHUNK: {
510 TRACE_(dmfile)(": copyright chunk (ignored)\n");
511 liMove.QuadPart = chunkSize;
512 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
513 break;
515 case mmioFOURCC('I','S','B','J'):
516 case DMUS_FOURCC_USBJ_CHUNK: {
517 TRACE_(dmfile)(": subject chunk (ignored)\n");
518 liMove.QuadPart = chunkSize;
519 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
520 break;
522 case mmioFOURCC('I','C','M','T'):
523 case DMUS_FOURCC_UCMT_CHUNK: {
524 TRACE_(dmfile)(": comment chunk (ignored)\n");
525 liMove.QuadPart = chunkSize;
526 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
527 break;
529 default: {
530 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
531 liMove.QuadPart = chunkSize;
532 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
533 break;
536 TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
537 } while (ListCount[0] < ListSize[0]);
538 break;
540 default: {
541 TRACE_(dmfile)(": unknown (skipping)\n");
542 liMove.QuadPart = chunkSize - sizeof(FOURCC);
543 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
544 break;
547 break;
549 default: {
550 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
551 liMove.QuadPart = chunkSize;
552 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
553 break;
556 TRACE_(dmfile)(": StreamCount[0] = %d < StreamSize[0] = %d\n", StreamCount, StreamSize);
557 } while (StreamCount < StreamSize);
558 break;
560 default: {
561 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
562 liMove.QuadPart = StreamSize;
563 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
564 return E_FAIL;
567 TRACE_(dmfile)(": reading finished\n");
568 break;
570 default: {
571 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
572 liMove.QuadPart = chunkSize;
573 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
574 return E_FAIL;
578 return S_OK;
581 static HRESULT WINAPI IDirectMusicGraphImpl_IPersistStream_Save (LPPERSISTSTREAM iface, IStream* pStm, BOOL fClearDirty) {
582 return E_NOTIMPL;
585 static HRESULT WINAPI IDirectMusicGraphImpl_IPersistStream_GetSizeMax (LPPERSISTSTREAM iface, ULARGE_INTEGER* pcbSize) {
586 return E_NOTIMPL;
589 static const IPersistStreamVtbl DirectMusicGraph_PersistStream_Vtbl = {
590 IDirectMusicGraphImpl_IPersistStream_QueryInterface,
591 IDirectMusicGraphImpl_IPersistStream_AddRef,
592 IDirectMusicGraphImpl_IPersistStream_Release,
593 IDirectMusicGraphImpl_IPersistStream_GetClassID,
594 IDirectMusicGraphImpl_IPersistStream_IsDirty,
595 IDirectMusicGraphImpl_IPersistStream_Load,
596 IDirectMusicGraphImpl_IPersistStream_Save,
597 IDirectMusicGraphImpl_IPersistStream_GetSizeMax
600 /* for ClassFactory */
601 HRESULT WINAPI DMUSIC_CreateDirectMusicGraphImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter) {
602 IDirectMusicGraphImpl* obj;
604 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicGraphImpl));
605 if (NULL == obj) {
606 *ppobj = NULL;
607 return E_OUTOFMEMORY;
609 obj->UnknownVtbl = &DirectMusicGraph_Unknown_Vtbl;
610 obj->GraphVtbl = &DirectMusicGraph_Graph_Vtbl;
611 obj->ObjectVtbl = &DirectMusicGraph_Object_Vtbl;
612 obj->PersistStreamVtbl = &DirectMusicGraph_PersistStream_Vtbl;
613 obj->pDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DMUS_OBJECTDESC));
614 DM_STRUCT_INIT(obj->pDesc);
615 obj->pDesc->dwValidData |= DMUS_OBJ_CLASS;
616 obj->pDesc->guidClass = CLSID_DirectMusicGraph;
617 obj->ref = 0; /* will be inited by QueryInterface */
618 list_init (&obj->Tools);
620 return IDirectMusicGraphImpl_IUnknown_QueryInterface ((LPUNKNOWN)&obj->UnknownVtbl, lpcGUID, ppobj);