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"
23 WINE_DEFAULT_DEBUG_CHANNEL(dmime
);
24 WINE_DECLARE_DEBUG_CHANNEL(dmfile
);
26 struct IDirectMusicGraphImpl
{
27 IDirectMusicGraph IDirectMusicGraph_iface
;
28 struct dmobject dmobj
;
34 static inline IDirectMusicGraphImpl
*impl_from_IDirectMusicGraph(IDirectMusicGraph
*iface
)
36 return CONTAINING_RECORD(iface
, IDirectMusicGraphImpl
, IDirectMusicGraph_iface
);
39 static inline IDirectMusicGraphImpl
*impl_from_IDirectMusicObject(IDirectMusicObject
*iface
)
41 return CONTAINING_RECORD(iface
, IDirectMusicGraphImpl
, dmobj
.IDirectMusicObject_iface
);
44 static inline IDirectMusicGraphImpl
*impl_from_IPersistStream(IPersistStream
*iface
)
46 return CONTAINING_RECORD(iface
, IDirectMusicGraphImpl
, dmobj
.IPersistStream_iface
);
49 static HRESULT WINAPI
DirectMusicGraph_QueryInterface(IDirectMusicGraph
*iface
, REFIID riid
, void **ret_iface
)
51 IDirectMusicGraphImpl
*This
= impl_from_IDirectMusicGraph(iface
);
53 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ret_iface
);
57 if (IsEqualIID(riid
, &IID_IUnknown
) ||
58 IsEqualIID(riid
, &IID_IDirectMusicGraph
))
60 *ret_iface
= &This
->IDirectMusicGraph_iface
;
62 else if (IsEqualIID(riid
, &IID_IDirectMusicObject
))
63 *ret_iface
= &This
->dmobj
.IDirectMusicObject_iface
;
64 else if (IsEqualIID(riid
, &IID_IPersistStream
))
65 *ret_iface
= &This
->dmobj
.IPersistStream_iface
;
69 IDirectMusicGraph_AddRef(iface
);
73 WARN("(%p, %s, %p): not found\n", This
, debugstr_guid(riid
), ret_iface
);
77 static ULONG WINAPI
DirectMusicGraph_AddRef(IDirectMusicGraph
*iface
)
79 IDirectMusicGraphImpl
*This
= impl_from_IDirectMusicGraph(iface
);
80 ULONG ref
= InterlockedIncrement(&This
->ref
);
82 TRACE("(%p): %d\n", This
, ref
);
88 static ULONG WINAPI
DirectMusicGraph_Release(IDirectMusicGraph
*iface
)
90 IDirectMusicGraphImpl
*This
= impl_from_IDirectMusicGraph(iface
);
91 ULONG ref
= InterlockedDecrement(&This
->ref
);
93 TRACE("(%p): %d\n", This
, ref
);
96 HeapFree(GetProcessHeap(), 0, This
);
102 static HRESULT WINAPI
DirectMusicGraph_StampPMsg(IDirectMusicGraph
*iface
, DMUS_PMSG
*msg
)
104 IDirectMusicGraphImpl
*This
= impl_from_IDirectMusicGraph(iface
);
105 FIXME("(%p, %p): stub\n", This
, msg
);
109 static HRESULT WINAPI
DirectMusicGraph_InsertTool(IDirectMusicGraph
*iface
, IDirectMusicTool
* pTool
, DWORD
* pdwPChannels
, DWORD cPChannels
, LONG lIndex
)
111 IDirectMusicGraphImpl
*This
= impl_from_IDirectMusicGraph(iface
);
112 struct list
* pEntry
= NULL
;
113 struct list
* pPrevEntry
= NULL
;
114 LPDMUS_PRIVATE_GRAPH_TOOL pIt
= NULL
;
115 LPDMUS_PRIVATE_GRAPH_TOOL pNewTool
= NULL
;
117 FIXME("(%p, %p, %p, %d, %i): use of pdwPChannels\n", This
, pTool
, pdwPChannels
, cPChannels
, lIndex
);
123 lIndex
= This
->num_tools
+ lIndex
;
125 pPrevEntry
= &This
->Tools
;
126 LIST_FOR_EACH(pEntry
, &This
->Tools
)
128 pIt
= LIST_ENTRY(pEntry
, DMUS_PRIVATE_GRAPH_TOOL
, entry
);
129 if (pIt
->dwIndex
== lIndex
)
130 return DMUS_E_ALREADY_EXISTS
;
132 if (pIt
->dwIndex
> lIndex
)
138 pNewTool
= HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY
, sizeof(DMUS_PRIVATE_GRAPH_TOOL
));
139 pNewTool
->pTool
= pTool
;
140 pNewTool
->dwIndex
= lIndex
;
141 IDirectMusicTool8_AddRef(pTool
);
142 IDirectMusicTool8_Init(pTool
, iface
);
143 list_add_tail (pPrevEntry
->next
, &pNewTool
->entry
);
147 IDirectMusicTool8_GetMediaTypes(pTool
, &dwNum
);
153 static HRESULT WINAPI
DirectMusicGraph_GetTool(IDirectMusicGraph
*iface
, DWORD dwIndex
, IDirectMusicTool
** ppTool
)
155 IDirectMusicGraphImpl
*This
= impl_from_IDirectMusicGraph(iface
);
156 struct list
* pEntry
= NULL
;
157 LPDMUS_PRIVATE_GRAPH_TOOL pIt
= NULL
;
159 FIXME("(%p, %d, %p): stub\n", This
, dwIndex
, ppTool
);
161 LIST_FOR_EACH (pEntry
, &This
->Tools
)
163 pIt
= LIST_ENTRY(pEntry
, DMUS_PRIVATE_GRAPH_TOOL
, entry
);
164 if (pIt
->dwIndex
== dwIndex
)
166 *ppTool
= pIt
->pTool
;
168 IDirectMusicTool_AddRef(*ppTool
);
171 if (pIt
->dwIndex
> dwIndex
)
175 return DMUS_E_NOT_FOUND
;
178 static HRESULT WINAPI
DirectMusicGraph_RemoveTool(IDirectMusicGraph
*iface
, IDirectMusicTool
* pTool
)
180 IDirectMusicGraphImpl
*This
= impl_from_IDirectMusicGraph(iface
);
181 FIXME("(%p, %p): stub\n", This
, pTool
);
185 static const IDirectMusicGraphVtbl DirectMusicGraphVtbl
=
187 DirectMusicGraph_QueryInterface
,
188 DirectMusicGraph_AddRef
,
189 DirectMusicGraph_Release
,
190 DirectMusicGraph_StampPMsg
,
191 DirectMusicGraph_InsertTool
,
192 DirectMusicGraph_GetTool
,
193 DirectMusicGraph_RemoveTool
196 static HRESULT WINAPI
DirectMusicObject_ParseDescriptor(IDirectMusicObject
*iface
, IStream
*pStream
, DMUS_OBJECTDESC
*pDesc
)
198 IDirectMusicGraphImpl
*This
= impl_from_IDirectMusicObject(iface
);
199 DMUS_PRIVATE_CHUNK Chunk
;
200 DWORD StreamSize
, StreamCount
, ListSize
[1], ListCount
[1];
201 LARGE_INTEGER liMove
; /* used when skipping chunks */
203 TRACE("(%p, %p, %p)\n", This
, pStream
, pDesc
);
205 /* FIXME: should this be determined from stream? */
206 pDesc
->dwValidData
|= DMUS_OBJ_CLASS
;
207 pDesc
->guidClass
= CLSID_DirectMusicGraph
;
209 IStream_Read (pStream
, &Chunk
, sizeof(FOURCC
)+sizeof(DWORD
), NULL
);
210 TRACE_(dmfile
)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk
.fccID
), Chunk
.dwSize
);
211 switch (Chunk
.fccID
) {
213 IStream_Read (pStream
, &Chunk
.fccID
, sizeof(FOURCC
), NULL
);
214 TRACE_(dmfile
)(": RIFF chunk of type %s", debugstr_fourcc(Chunk
.fccID
));
215 StreamSize
= Chunk
.dwSize
- sizeof(FOURCC
);
217 if (Chunk
.fccID
== DMUS_FOURCC_TOOLGRAPH_FORM
) {
218 TRACE_(dmfile
)(": graph form\n");
220 IStream_Read (pStream
, &Chunk
, sizeof(FOURCC
)+sizeof(DWORD
), NULL
);
221 StreamCount
+= sizeof(FOURCC
) + sizeof(DWORD
) + Chunk
.dwSize
;
222 TRACE_(dmfile
)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk
.fccID
), Chunk
.dwSize
);
223 switch (Chunk
.fccID
) {
224 case DMUS_FOURCC_GUID_CHUNK
: {
225 TRACE_(dmfile
)(": GUID chunk\n");
226 pDesc
->dwValidData
|= DMUS_OBJ_OBJECT
;
227 IStream_Read (pStream
, &pDesc
->guidObject
, Chunk
.dwSize
, NULL
);
230 case DMUS_FOURCC_VERSION_CHUNK
: {
231 TRACE_(dmfile
)(": version chunk\n");
232 pDesc
->dwValidData
|= DMUS_OBJ_VERSION
;
233 IStream_Read (pStream
, &pDesc
->vVersion
, Chunk
.dwSize
, NULL
);
236 case DMUS_FOURCC_CATEGORY_CHUNK
: {
237 TRACE_(dmfile
)(": category chunk\n");
238 pDesc
->dwValidData
|= DMUS_OBJ_CATEGORY
;
239 IStream_Read (pStream
, pDesc
->wszCategory
, Chunk
.dwSize
, NULL
);
243 IStream_Read (pStream
, &Chunk
.fccID
, sizeof(FOURCC
), NULL
);
244 TRACE_(dmfile
)(": LIST chunk of type %s", debugstr_fourcc(Chunk
.fccID
));
245 ListSize
[0] = Chunk
.dwSize
- sizeof(FOURCC
);
247 switch (Chunk
.fccID
) {
248 /* evil M$ UNFO list, which can (!?) contain INFO elements */
249 case DMUS_FOURCC_UNFO_LIST
: {
250 TRACE_(dmfile
)(": UNFO list\n");
252 IStream_Read (pStream
, &Chunk
, sizeof(FOURCC
)+sizeof(DWORD
), NULL
);
253 ListCount
[0] += sizeof(FOURCC
) + sizeof(DWORD
) + Chunk
.dwSize
;
254 TRACE_(dmfile
)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk
.fccID
), Chunk
.dwSize
);
255 switch (Chunk
.fccID
) {
256 /* don't ask me why, but M$ puts INFO elements in UNFO list sometimes
257 (though strings seem to be valid unicode) */
258 case mmioFOURCC('I','N','A','M'):
259 case DMUS_FOURCC_UNAM_CHUNK
: {
260 TRACE_(dmfile
)(": name chunk\n");
261 pDesc
->dwValidData
|= DMUS_OBJ_NAME
;
262 IStream_Read (pStream
, pDesc
->wszName
, Chunk
.dwSize
, NULL
);
265 case mmioFOURCC('I','A','R','T'):
266 case DMUS_FOURCC_UART_CHUNK
: {
267 TRACE_(dmfile
)(": artist chunk (ignored)\n");
268 liMove
.QuadPart
= Chunk
.dwSize
;
269 IStream_Seek (pStream
, liMove
, STREAM_SEEK_CUR
, NULL
);
272 case mmioFOURCC('I','C','O','P'):
273 case DMUS_FOURCC_UCOP_CHUNK
: {
274 TRACE_(dmfile
)(": copyright chunk (ignored)\n");
275 liMove
.QuadPart
= Chunk
.dwSize
;
276 IStream_Seek (pStream
, liMove
, STREAM_SEEK_CUR
, NULL
);
279 case mmioFOURCC('I','S','B','J'):
280 case DMUS_FOURCC_USBJ_CHUNK
: {
281 TRACE_(dmfile
)(": subject chunk (ignored)\n");
282 liMove
.QuadPart
= Chunk
.dwSize
;
283 IStream_Seek (pStream
, liMove
, STREAM_SEEK_CUR
, NULL
);
286 case mmioFOURCC('I','C','M','T'):
287 case DMUS_FOURCC_UCMT_CHUNK
: {
288 TRACE_(dmfile
)(": comment chunk (ignored)\n");
289 liMove
.QuadPart
= Chunk
.dwSize
;
290 IStream_Seek (pStream
, liMove
, STREAM_SEEK_CUR
, NULL
);
294 TRACE_(dmfile
)(": unknown chunk (irrelevant & skipping)\n");
295 liMove
.QuadPart
= Chunk
.dwSize
;
296 IStream_Seek (pStream
, liMove
, STREAM_SEEK_CUR
, NULL
);
300 TRACE_(dmfile
)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount
[0], ListSize
[0]);
301 } while (ListCount
[0] < ListSize
[0]);
305 TRACE_(dmfile
)(": unknown (skipping)\n");
306 liMove
.QuadPart
= Chunk
.dwSize
- sizeof(FOURCC
);
307 IStream_Seek (pStream
, liMove
, STREAM_SEEK_CUR
, NULL
);
314 TRACE_(dmfile
)(": unknown chunk (irrelevant & skipping)\n");
315 liMove
.QuadPart
= Chunk
.dwSize
;
316 IStream_Seek (pStream
, liMove
, STREAM_SEEK_CUR
, NULL
);
320 TRACE_(dmfile
)(": StreamCount[0] = %d < StreamSize[0] = %d\n", StreamCount
, StreamSize
);
321 } while (StreamCount
< StreamSize
);
323 TRACE_(dmfile
)(": unexpected chunk; loading failed)\n");
324 liMove
.QuadPart
= StreamSize
;
325 IStream_Seek (pStream
, liMove
, STREAM_SEEK_CUR
, NULL
); /* skip the rest of the chunk */
329 TRACE_(dmfile
)(": reading finished\n");
333 TRACE_(dmfile
)(": unexpected chunk; loading failed)\n");
334 liMove
.QuadPart
= Chunk
.dwSize
;
335 IStream_Seek (pStream
, liMove
, STREAM_SEEK_CUR
, NULL
); /* skip the rest of the chunk */
336 return DMUS_E_INVALIDFILE
;
340 TRACE(": returning descriptor:\n%s\n", debugstr_DMUS_OBJECTDESC (pDesc
));
345 static const IDirectMusicObjectVtbl dmobject_vtbl
= {
346 dmobj_IDirectMusicObject_QueryInterface
,
347 dmobj_IDirectMusicObject_AddRef
,
348 dmobj_IDirectMusicObject_Release
,
349 dmobj_IDirectMusicObject_GetDescriptor
,
350 dmobj_IDirectMusicObject_SetDescriptor
,
351 DirectMusicObject_ParseDescriptor
354 static HRESULT WINAPI
PersistStream_Load(IPersistStream
*iface
, IStream
* pStm
)
356 IDirectMusicGraphImpl
*This
= impl_from_IPersistStream(iface
);
358 DWORD chunkSize
, StreamSize
, StreamCount
, ListSize
[3], ListCount
[3];
359 LARGE_INTEGER liMove
; /* used when skipping chunks */
361 FIXME("(%p, %p): Loading not implemented yet\n", This
, pStm
);
362 IStream_Read (pStm
, &chunkID
, sizeof(FOURCC
), NULL
);
363 IStream_Read (pStm
, &chunkSize
, sizeof(DWORD
), NULL
);
364 TRACE_(dmfile
)(": %s chunk (size = %d)", debugstr_fourcc (chunkID
), chunkSize
);
367 IStream_Read (pStm
, &chunkID
, sizeof(FOURCC
), NULL
);
368 TRACE_(dmfile
)(": RIFF chunk of type %s", debugstr_fourcc(chunkID
));
369 StreamSize
= chunkSize
- sizeof(FOURCC
);
372 case DMUS_FOURCC_TOOLGRAPH_FORM
: {
373 TRACE_(dmfile
)(": graph form\n");
375 IStream_Read (pStm
, &chunkID
, sizeof(FOURCC
), NULL
);
376 IStream_Read (pStm
, &chunkSize
, sizeof(FOURCC
), NULL
);
377 StreamCount
+= sizeof(FOURCC
) + sizeof(DWORD
) + chunkSize
;
378 TRACE_(dmfile
)(": %s chunk (size = %d)", debugstr_fourcc (chunkID
), chunkSize
);
380 case DMUS_FOURCC_GUID_CHUNK
: {
381 TRACE_(dmfile
)(": GUID chunk\n");
382 This
->dmobj
.desc
.dwValidData
|= DMUS_OBJ_OBJECT
;
383 IStream_Read (pStm
, &This
->dmobj
.desc
.guidObject
, chunkSize
, NULL
);
386 case DMUS_FOURCC_VERSION_CHUNK
: {
387 TRACE_(dmfile
)(": version chunk\n");
388 This
->dmobj
.desc
.dwValidData
|= DMUS_OBJ_VERSION
;
389 IStream_Read (pStm
, &This
->dmobj
.desc
.vVersion
, chunkSize
, NULL
);
392 case DMUS_FOURCC_CATEGORY_CHUNK
: {
393 TRACE_(dmfile
)(": category chunk\n");
394 This
->dmobj
.desc
.dwValidData
|= DMUS_OBJ_CATEGORY
;
395 IStream_Read (pStm
, This
->dmobj
.desc
.wszCategory
, chunkSize
, NULL
);
399 IStream_Read (pStm
, &chunkID
, sizeof(FOURCC
), NULL
);
400 TRACE_(dmfile
)(": LIST chunk of type %s", debugstr_fourcc(chunkID
));
401 ListSize
[0] = chunkSize
- sizeof(FOURCC
);
404 case DMUS_FOURCC_UNFO_LIST
: {
405 TRACE_(dmfile
)(": UNFO list\n");
407 IStream_Read (pStm
, &chunkID
, sizeof(FOURCC
), NULL
);
408 IStream_Read (pStm
, &chunkSize
, sizeof(FOURCC
), NULL
);
409 ListCount
[0] += sizeof(FOURCC
) + sizeof(DWORD
) + chunkSize
;
410 TRACE_(dmfile
)(": %s chunk (size = %d)", debugstr_fourcc (chunkID
), chunkSize
);
412 /* don't ask me why, but M$ puts INFO elements in UNFO list sometimes
413 (though strings seem to be valid unicode) */
414 case mmioFOURCC('I','N','A','M'):
415 case DMUS_FOURCC_UNAM_CHUNK
: {
416 TRACE_(dmfile
)(": name chunk\n");
417 This
->dmobj
.desc
.dwValidData
|= DMUS_OBJ_NAME
;
418 IStream_Read (pStm
, This
->dmobj
.desc
.wszName
, chunkSize
, NULL
);
421 case mmioFOURCC('I','A','R','T'):
422 case DMUS_FOURCC_UART_CHUNK
: {
423 TRACE_(dmfile
)(": artist chunk (ignored)\n");
424 liMove
.QuadPart
= chunkSize
;
425 IStream_Seek (pStm
, liMove
, STREAM_SEEK_CUR
, NULL
);
428 case mmioFOURCC('I','C','O','P'):
429 case DMUS_FOURCC_UCOP_CHUNK
: {
430 TRACE_(dmfile
)(": copyright chunk (ignored)\n");
431 liMove
.QuadPart
= chunkSize
;
432 IStream_Seek (pStm
, liMove
, STREAM_SEEK_CUR
, NULL
);
435 case mmioFOURCC('I','S','B','J'):
436 case DMUS_FOURCC_USBJ_CHUNK
: {
437 TRACE_(dmfile
)(": subject chunk (ignored)\n");
438 liMove
.QuadPart
= chunkSize
;
439 IStream_Seek (pStm
, liMove
, STREAM_SEEK_CUR
, NULL
);
442 case mmioFOURCC('I','C','M','T'):
443 case DMUS_FOURCC_UCMT_CHUNK
: {
444 TRACE_(dmfile
)(": comment chunk (ignored)\n");
445 liMove
.QuadPart
= chunkSize
;
446 IStream_Seek (pStm
, liMove
, STREAM_SEEK_CUR
, NULL
);
450 TRACE_(dmfile
)(": unknown chunk (irrelevant & skipping)\n");
451 liMove
.QuadPart
= chunkSize
;
452 IStream_Seek (pStm
, liMove
, STREAM_SEEK_CUR
, NULL
);
456 TRACE_(dmfile
)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount
[0], ListSize
[0]);
457 } while (ListCount
[0] < ListSize
[0]);
461 TRACE_(dmfile
)(": unknown (skipping)\n");
462 liMove
.QuadPart
= chunkSize
- sizeof(FOURCC
);
463 IStream_Seek (pStm
, liMove
, STREAM_SEEK_CUR
, NULL
);
470 TRACE_(dmfile
)(": unknown chunk (irrelevant & skipping)\n");
471 liMove
.QuadPart
= chunkSize
;
472 IStream_Seek (pStm
, liMove
, STREAM_SEEK_CUR
, NULL
);
476 TRACE_(dmfile
)(": StreamCount[0] = %d < StreamSize[0] = %d\n", StreamCount
, StreamSize
);
477 } while (StreamCount
< StreamSize
);
481 TRACE_(dmfile
)(": unexpected chunk; loading failed)\n");
482 liMove
.QuadPart
= StreamSize
;
483 IStream_Seek (pStm
, liMove
, STREAM_SEEK_CUR
, NULL
); /* skip the rest of the chunk */
487 TRACE_(dmfile
)(": reading finished\n");
491 TRACE_(dmfile
)(": unexpected chunk; loading failed)\n");
492 liMove
.QuadPart
= chunkSize
;
493 IStream_Seek (pStm
, liMove
, STREAM_SEEK_CUR
, NULL
); /* skip the rest of the chunk */
501 static const IPersistStreamVtbl persiststream_vtbl
= {
502 dmobj_IPersistStream_QueryInterface
,
503 dmobj_IPersistStream_AddRef
,
504 dmobj_IPersistStream_Release
,
505 dmobj_IPersistStream_GetClassID
,
506 unimpl_IPersistStream_IsDirty
,
508 unimpl_IPersistStream_Save
,
509 unimpl_IPersistStream_GetSizeMax
512 /* for ClassFactory */
513 HRESULT WINAPI
create_dmgraph(REFIID riid
, void **ret_iface
)
515 IDirectMusicGraphImpl
* obj
;
520 obj
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IDirectMusicGraphImpl
));
522 return E_OUTOFMEMORY
;
524 obj
->IDirectMusicGraph_iface
.lpVtbl
= &DirectMusicGraphVtbl
;
526 dmobject_init(&obj
->dmobj
, &CLSID_DirectMusicGraph
, (IUnknown
*)&obj
->IDirectMusicGraph_iface
);
527 obj
->dmobj
.IDirectMusicObject_iface
.lpVtbl
= &dmobject_vtbl
;
528 obj
->dmobj
.IPersistStream_iface
.lpVtbl
= &persiststream_vtbl
;
529 list_init(&obj
->Tools
);
531 hr
= IDirectMusicGraph_QueryInterface(&obj
->IDirectMusicGraph_iface
, riid
, ret_iface
);
532 IDirectMusicGraph_Release(&obj
->IDirectMusicGraph_iface
);