winepulse: Set pulse master volume to 0 when session is muted.
[wine.git] / dlls / dmime / dmobject.c
blobe6a1ce906a7cc9f980f8f47d883cfd87ad566b0c
1 /*
2 * Base IDirectMusicObject Implementation
3 * Keep in sync with the master in dlls/dmusic/dmobject.c
5 * Copyright (C) 2003-2004 Rok Mandeljc
6 * Copyright (C) 2014 Michael Stefaniuc
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define COBJMACROS
24 #include <assert.h>
25 #include "objbase.h"
26 #include "dmusici.h"
27 #include "dmusicf.h"
28 #include "dmusics.h"
29 #include "dmobject.h"
30 #include "wine/debug.h"
31 #include "wine/heap.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(dmobj);
34 WINE_DECLARE_DEBUG_CHANNEL(dmfile);
36 /* Debugging helpers */
37 const char *debugstr_dmguid(const GUID *id) {
38 unsigned int i;
39 #define X(guid) { &guid, #guid }
40 static const struct {
41 const GUID *guid;
42 const char *name;
43 } guids[] = {
44 /* CLSIDs */
45 X(CLSID_AudioVBScript),
46 X(CLSID_DirectMusic),
47 X(CLSID_DirectMusicAudioPathConfig),
48 X(CLSID_DirectMusicAuditionTrack),
49 X(CLSID_DirectMusicBand),
50 X(CLSID_DirectMusicBandTrack),
51 X(CLSID_DirectMusicChordMapTrack),
52 X(CLSID_DirectMusicChordMap),
53 X(CLSID_DirectMusicChordTrack),
54 X(CLSID_DirectMusicCollection),
55 X(CLSID_DirectMusicCommandTrack),
56 X(CLSID_DirectMusicComposer),
57 X(CLSID_DirectMusicContainer),
58 X(CLSID_DirectMusicGraph),
59 X(CLSID_DirectMusicLoader),
60 X(CLSID_DirectMusicLyricsTrack),
61 X(CLSID_DirectMusicMarkerTrack),
62 X(CLSID_DirectMusicMelodyFormulationTrack),
63 X(CLSID_DirectMusicMotifTrack),
64 X(CLSID_DirectMusicMuteTrack),
65 X(CLSID_DirectMusicParamControlTrack),
66 X(CLSID_DirectMusicPatternTrack),
67 X(CLSID_DirectMusicPerformance),
68 X(CLSID_DirectMusicScript),
69 X(CLSID_DirectMusicScriptAutoImpSegment),
70 X(CLSID_DirectMusicScriptAutoImpPerformance),
71 X(CLSID_DirectMusicScriptAutoImpSegmentState),
72 X(CLSID_DirectMusicScriptAutoImpAudioPathConfig),
73 X(CLSID_DirectMusicScriptAutoImpAudioPath),
74 X(CLSID_DirectMusicScriptAutoImpSong),
75 X(CLSID_DirectMusicScriptSourceCodeLoader),
76 X(CLSID_DirectMusicScriptTrack),
77 X(CLSID_DirectMusicSection),
78 X(CLSID_DirectMusicSegment),
79 X(CLSID_DirectMusicSegmentState),
80 X(CLSID_DirectMusicSegmentTriggerTrack),
81 X(CLSID_DirectMusicSegTriggerTrack),
82 X(CLSID_DirectMusicSeqTrack),
83 X(CLSID_DirectMusicSignPostTrack),
84 X(CLSID_DirectMusicSong),
85 X(CLSID_DirectMusicStyle),
86 X(CLSID_DirectMusicStyleTrack),
87 X(CLSID_DirectMusicSynth),
88 X(CLSID_DirectMusicSynthSink),
89 X(CLSID_DirectMusicSysExTrack),
90 X(CLSID_DirectMusicTemplate),
91 X(CLSID_DirectMusicTempoTrack),
92 X(CLSID_DirectMusicTimeSigTrack),
93 X(CLSID_DirectMusicWaveTrack),
94 X(CLSID_DirectSoundWave),
95 /* IIDs */
96 X(IID_IDirectMusic),
97 X(IID_IDirectMusic2),
98 X(IID_IDirectMusic8),
99 X(IID_IDirectMusicAudioPath),
100 X(IID_IDirectMusicBand),
101 X(IID_IDirectMusicBuffer),
102 X(IID_IDirectMusicChordMap),
103 X(IID_IDirectMusicCollection),
104 X(IID_IDirectMusicComposer),
105 X(IID_IDirectMusicContainer),
106 X(IID_IDirectMusicDownload),
107 X(IID_IDirectMusicDownloadedInstrument),
108 X(IID_IDirectMusicGetLoader),
109 X(IID_IDirectMusicGraph),
110 X(IID_IDirectMusicInstrument),
111 X(IID_IDirectMusicLoader),
112 X(IID_IDirectMusicLoader8),
113 X(IID_IDirectMusicObject),
114 X(IID_IDirectMusicPatternTrack),
115 X(IID_IDirectMusicPerformance),
116 X(IID_IDirectMusicPerformance2),
117 X(IID_IDirectMusicPerformance8),
118 X(IID_IDirectMusicPort),
119 X(IID_IDirectMusicPortDownload),
120 X(IID_IDirectMusicScript),
121 X(IID_IDirectMusicSegment),
122 X(IID_IDirectMusicSegment2),
123 X(IID_IDirectMusicSegment8),
124 X(IID_IDirectMusicSegmentState),
125 X(IID_IDirectMusicSegmentState8),
126 X(IID_IDirectMusicStyle),
127 X(IID_IDirectMusicStyle8),
128 X(IID_IDirectMusicSynth),
129 X(IID_IDirectMusicSynth8),
130 X(IID_IDirectMusicSynthSink),
131 X(IID_IDirectMusicThru),
132 X(IID_IDirectMusicTool),
133 X(IID_IDirectMusicTool8),
134 X(IID_IDirectMusicTrack),
135 X(IID_IDirectMusicTrack8),
136 X(IID_IUnknown),
137 X(IID_IPersistStream),
138 X(IID_IStream),
139 X(IID_IClassFactory),
140 /* GUIDs */
141 X(GUID_DirectMusicAllTypes),
142 X(GUID_NOTIFICATION_CHORD),
143 X(GUID_NOTIFICATION_COMMAND),
144 X(GUID_NOTIFICATION_MEASUREANDBEAT),
145 X(GUID_NOTIFICATION_PERFORMANCE),
146 X(GUID_NOTIFICATION_RECOMPOSE),
147 X(GUID_NOTIFICATION_SEGMENT),
148 X(GUID_BandParam),
149 X(GUID_ChordParam),
150 X(GUID_CommandParam),
151 X(GUID_CommandParam2),
152 X(GUID_CommandParamNext),
153 X(GUID_IDirectMusicBand),
154 X(GUID_IDirectMusicChordMap),
155 X(GUID_IDirectMusicStyle),
156 X(GUID_MuteParam),
157 X(GUID_Play_Marker),
158 X(GUID_RhythmParam),
159 X(GUID_TempoParam),
160 X(GUID_TimeSignature),
161 X(GUID_Valid_Start_Time),
162 X(GUID_Clear_All_Bands),
163 X(GUID_ConnectToDLSCollection),
164 X(GUID_Disable_Auto_Download),
165 X(GUID_DisableTempo),
166 X(GUID_DisableTimeSig),
167 X(GUID_Download),
168 X(GUID_DownloadToAudioPath),
169 X(GUID_Enable_Auto_Download),
170 X(GUID_EnableTempo),
171 X(GUID_EnableTimeSig),
172 X(GUID_IgnoreBankSelectForGM),
173 X(GUID_SeedVariations),
174 X(GUID_StandardMIDIFile),
175 X(GUID_Unload),
176 X(GUID_UnloadFromAudioPath),
177 X(GUID_Variations),
178 X(GUID_PerfMasterTempo),
179 X(GUID_PerfMasterVolume),
180 X(GUID_PerfMasterGrooveLevel),
181 X(GUID_PerfAutoDownload),
182 X(GUID_DefaultGMCollection),
183 X(GUID_Synth_Default),
184 X(GUID_Buffer_Reverb),
185 X(GUID_Buffer_EnvReverb),
186 X(GUID_Buffer_Stereo),
187 X(GUID_Buffer_3D_Dry),
188 X(GUID_Buffer_Mono),
189 X(GUID_DMUS_PROP_GM_Hardware),
190 X(GUID_DMUS_PROP_GS_Capable),
191 X(GUID_DMUS_PROP_GS_Hardware),
192 X(GUID_DMUS_PROP_DLS1),
193 X(GUID_DMUS_PROP_DLS2),
194 X(GUID_DMUS_PROP_Effects),
195 X(GUID_DMUS_PROP_INSTRUMENT2),
196 X(GUID_DMUS_PROP_LegacyCaps),
197 X(GUID_DMUS_PROP_MemorySize),
198 X(GUID_DMUS_PROP_SampleMemorySize),
199 X(GUID_DMUS_PROP_SamplePlaybackRate),
200 X(GUID_DMUS_PROP_SetSynthSink),
201 X(GUID_DMUS_PROP_SinkUsesDSound),
202 X(GUID_DMUS_PROP_SynthSink_DSOUND),
203 X(GUID_DMUS_PROP_SynthSink_WAVE),
204 X(GUID_DMUS_PROP_Volume),
205 X(GUID_DMUS_PROP_WavesReverb),
206 X(GUID_DMUS_PROP_WriteLatency),
207 X(GUID_DMUS_PROP_WritePeriod),
208 X(GUID_DMUS_PROP_XG_Capable),
209 X(GUID_DMUS_PROP_XG_Hardware)
211 #undef X
213 if (!id)
214 return "(null)";
216 for (i = 0; i < ARRAY_SIZE(guids); i++)
217 if (IsEqualGUID(id, guids[i].guid))
218 return guids[i].name;
220 return debugstr_guid(id);
223 void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc)
225 if (!desc || !TRACE_ON(dmfile))
226 return;
228 TRACE_(dmfile)("DMUS_OBJECTDESC (%p):", desc);
229 TRACE_(dmfile)(" - dwSize = %u\n", desc->dwSize);
231 #define X(flag) if (desc->dwValidData & flag) TRACE_(dmfile)(#flag " ")
232 TRACE_(dmfile)(" - dwValidData = %#08x ( ", desc->dwValidData);
233 X(DMUS_OBJ_OBJECT);
234 X(DMUS_OBJ_CLASS);
235 X(DMUS_OBJ_NAME);
236 X(DMUS_OBJ_CATEGORY);
237 X(DMUS_OBJ_FILENAME);
238 X(DMUS_OBJ_FULLPATH);
239 X(DMUS_OBJ_URL);
240 X(DMUS_OBJ_VERSION);
241 X(DMUS_OBJ_DATE);
242 X(DMUS_OBJ_LOADED);
243 X(DMUS_OBJ_MEMORY);
244 X(DMUS_OBJ_STREAM);
245 TRACE_(dmfile)(")\n");
246 #undef X
248 if (desc->dwValidData & DMUS_OBJ_CLASS)
249 TRACE_(dmfile)(" - guidClass = %s\n", debugstr_dmguid(&desc->guidClass));
250 if (desc->dwValidData & DMUS_OBJ_OBJECT)
251 TRACE_(dmfile)(" - guidObject = %s\n", debugstr_guid(&desc->guidObject));
253 if (desc->dwValidData & DMUS_OBJ_DATE) {
254 SYSTEMTIME time;
255 FileTimeToSystemTime(&desc->ftDate, &time);
256 TRACE_(dmfile)(" - ftDate = \'%04u-%02u-%02u %02u:%02u:%02u\'\n",
257 time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond);
259 if (desc->dwValidData & DMUS_OBJ_VERSION)
260 TRACE_(dmfile)(" - vVersion = \'%u,%u,%u,%u\'\n",
261 HIWORD(desc->vVersion.dwVersionMS), LOWORD(desc->vVersion.dwVersionMS),
262 HIWORD(desc->vVersion.dwVersionLS), LOWORD(desc->vVersion.dwVersionLS));
263 if (desc->dwValidData & DMUS_OBJ_NAME)
264 TRACE_(dmfile)(" - wszName = %s\n", debugstr_w(desc->wszName));
265 if (desc->dwValidData & DMUS_OBJ_CATEGORY)
266 TRACE_(dmfile)(" - wszCategory = %s\n", debugstr_w(desc->wszCategory));
267 if (desc->dwValidData & DMUS_OBJ_FILENAME)
268 TRACE_(dmfile)(" - wszFileName = %s\n", debugstr_w(desc->wszFileName));
269 if (desc->dwValidData & DMUS_OBJ_MEMORY)
270 TRACE_(dmfile)(" - llMemLength = 0x%s - pbMemData = %p\n",
271 wine_dbgstr_longlong(desc->llMemLength), desc->pbMemData);
272 if (desc->dwValidData & DMUS_OBJ_STREAM)
273 TRACE_(dmfile)(" - pStream = %p\n", desc->pStream);
277 /* RIFF format parsing */
278 #define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD))
280 const char *debugstr_chunk(const struct chunk_entry *chunk)
282 const char *type = "";
284 if (!chunk)
285 return "(null)";
286 if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST)
287 type = wine_dbg_sprintf("type %s, ", debugstr_fourcc(chunk->type));
288 return wine_dbg_sprintf("%s chunk, %ssize %u", debugstr_fourcc(chunk->id), type, chunk->size);
291 static HRESULT stream_read(IStream *stream, void *data, ULONG size)
293 ULONG read;
294 HRESULT hr;
296 hr = IStream_Read(stream, data, size, &read);
297 if (FAILED(hr))
298 TRACE_(dmfile)("IStream_Read failed: %08x\n", hr);
299 else if (!read && read < size) {
300 /* All or nothing: Handle a partial read due to end of stream as an error */
301 TRACE_(dmfile)("Short read: %u < %u\n", read, size);
302 return E_FAIL;
305 return hr;
308 HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk)
310 static const LARGE_INTEGER zero;
311 ULONGLONG ck_end = 0, p_end = 0;
312 HRESULT hr;
314 hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &chunk->offset);
315 if (FAILED(hr))
316 return hr;
317 assert(!(chunk->offset.QuadPart & 1));
318 if (chunk->parent) {
319 p_end = chunk->parent->offset.QuadPart + CHUNK_HDR_SIZE + ((chunk->parent->size + 1) & ~1);
320 if (chunk->offset.QuadPart == p_end)
321 return S_FALSE;
322 ck_end = chunk->offset.QuadPart + CHUNK_HDR_SIZE;
323 if (ck_end > p_end) {
324 WARN_(dmfile)("No space for sub-chunk header in parent chunk: ends at offset %s > %s\n",
325 wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end));
326 return E_FAIL;
330 hr = stream_read(stream, chunk, CHUNK_HDR_SIZE);
331 if (hr != S_OK)
332 return hr;
333 if (chunk->parent) {
334 ck_end += (chunk->size + 1) & ~1;
335 if (ck_end > p_end) {
336 WARN_(dmfile)("No space for sub-chunk data in parent chunk: ends at offset %s > %s\n",
337 wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end));
338 return E_FAIL;
342 if (chunk->id == FOURCC_LIST || chunk->id == FOURCC_RIFF) {
343 hr = stream_read(stream, &chunk->type, sizeof(FOURCC));
344 if (hr != S_OK)
345 return hr != S_FALSE ? hr : E_FAIL;
348 TRACE_(dmfile)("Returning %s\n", debugstr_chunk(chunk));
350 return S_OK;
353 HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk)
355 LARGE_INTEGER end;
357 end.QuadPart = (chunk->offset.QuadPart + CHUNK_HDR_SIZE + chunk->size + 1) & ~(ULONGLONG)1;
359 return IStream_Seek(stream, end, STREAM_SEEK_SET, NULL);
362 HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk)
364 HRESULT hr;
366 if (chunk->id) {
367 hr = stream_skip_chunk(stream, chunk);
368 if (FAILED(hr))
369 return hr;
372 return stream_get_chunk(stream, chunk);
375 /* Reads chunk data of the form:
376 DWORD - size of array element
377 element[] - Array of elements
378 The caller needs to heap_free() the array.
380 HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array,
381 unsigned int *count, DWORD elem_size)
383 DWORD size;
384 HRESULT hr;
386 *array = NULL;
387 *count = 0;
389 if (chunk->size < sizeof(DWORD)) {
390 WARN_(dmfile)("%s: Too short to read element size\n", debugstr_chunk(chunk));
391 return E_FAIL;
393 if (FAILED(hr = stream_read(stream, &size, sizeof(DWORD))))
394 return hr;
395 if (size != elem_size) {
396 WARN_(dmfile)("%s: Array element size mismatch: got %u, expected %u\n",
397 debugstr_chunk(chunk), size, elem_size);
398 return DMUS_E_UNSUPPORTED_STREAM;
401 *count = (chunk->size - sizeof(DWORD)) / elem_size;
402 size = *count * elem_size;
403 if (!(*array = heap_alloc(size)))
404 return E_OUTOFMEMORY;
405 if (FAILED(hr = stream_read(stream, *array, size))) {
406 heap_free(*array);
407 *array = NULL;
408 return hr;
411 if (chunk->size > size + sizeof(DWORD)) {
412 WARN_(dmfile)("%s: Extraneous data at end of array\n", debugstr_chunk(chunk));
413 stream_skip_chunk(stream, chunk);
414 return S_FALSE;
416 return S_OK;
419 HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
420 ULONG size)
422 if (chunk->size != size) {
423 WARN_(dmfile)("Chunk %s (size %u, offset %s) doesn't contains the expected data size %u\n",
424 debugstr_fourcc(chunk->id), chunk->size,
425 wine_dbgstr_longlong(chunk->offset.QuadPart), size);
426 return E_FAIL;
428 return stream_read(stream, data, size);
431 HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
432 ULONG size)
434 ULONG len;
435 HRESULT hr;
437 hr = IStream_Read(stream, str, min(chunk->size, size), &len);
438 if (FAILED(hr))
439 return hr;
441 /* Don't assume the string is properly zero terminated */
442 str[min(len, size - 1)] = 0;
444 if (len < chunk->size)
445 return S_FALSE;
446 return S_OK;
451 /* Generic IDirectMusicObject methods */
452 static inline struct dmobject *impl_from_IDirectMusicObject(IDirectMusicObject *iface)
454 return CONTAINING_RECORD(iface, struct dmobject, IDirectMusicObject_iface);
457 HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid,
458 void **ret_iface)
460 struct dmobject *This = impl_from_IDirectMusicObject(iface);
461 return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface);
464 ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface)
466 struct dmobject *This = impl_from_IDirectMusicObject(iface);
467 return IUnknown_AddRef(This->outer_unk);
470 ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface)
472 struct dmobject *This = impl_from_IDirectMusicObject(iface);
473 return IUnknown_Release(This->outer_unk);
476 HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface,
477 DMUS_OBJECTDESC *desc)
479 struct dmobject *This = impl_from_IDirectMusicObject(iface);
481 TRACE("(%p/%p)->(%p)\n", iface, This, desc);
483 if (!desc)
484 return E_POINTER;
486 memcpy(desc, &This->desc, This->desc.dwSize);
488 return S_OK;
491 HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface,
492 DMUS_OBJECTDESC *desc)
494 struct dmobject *This = impl_from_IDirectMusicObject(iface);
495 HRESULT ret = S_OK;
497 TRACE("(%p, %p)\n", iface, desc);
499 if (!desc)
500 return E_POINTER;
502 /* Immutable property */
503 if (desc->dwValidData & DMUS_OBJ_CLASS)
505 desc->dwValidData &= ~DMUS_OBJ_CLASS;
506 ret = S_FALSE;
508 /* Set only valid fields */
509 if (desc->dwValidData & DMUS_OBJ_OBJECT)
510 This->desc.guidObject = desc->guidObject;
511 if (desc->dwValidData & DMUS_OBJ_NAME)
512 lstrcpynW(This->desc.wszName, desc->wszName, DMUS_MAX_NAME);
513 if (desc->dwValidData & DMUS_OBJ_CATEGORY)
514 lstrcpynW(This->desc.wszCategory, desc->wszCategory, DMUS_MAX_CATEGORY);
515 if (desc->dwValidData & DMUS_OBJ_FILENAME)
516 lstrcpynW(This->desc.wszFileName, desc->wszFileName, DMUS_MAX_FILENAME);
517 if (desc->dwValidData & DMUS_OBJ_VERSION)
518 This->desc.vVersion = desc->vVersion;
519 if (desc->dwValidData & DMUS_OBJ_DATE)
520 This->desc.ftDate = desc->ftDate;
521 if (desc->dwValidData & DMUS_OBJ_MEMORY) {
522 This->desc.llMemLength = desc->llMemLength;
523 memcpy(This->desc.pbMemData, desc->pbMemData, desc->llMemLength);
525 if (desc->dwValidData & DMUS_OBJ_STREAM)
526 IStream_Clone(desc->pStream, &This->desc.pStream);
528 This->desc.dwValidData |= desc->dwValidData;
530 return ret;
533 /* Helper for IDirectMusicObject::ParseDescriptor */
534 static inline void info_get_name(IStream *stream, const struct chunk_entry *info,
535 DMUS_OBJECTDESC *desc)
537 struct chunk_entry chunk = {.parent = info};
538 char name[DMUS_MAX_NAME];
539 ULONG len;
540 HRESULT hr = E_FAIL;
542 while (stream_next_chunk(stream, &chunk) == S_OK)
543 if (chunk.id == mmioFOURCC('I','N','A','M'))
544 hr = IStream_Read(stream, name, min(chunk.size, sizeof(name)), &len);
546 if (SUCCEEDED(hr)) {
547 len = MultiByteToWideChar(CP_ACP, 0, name, len, desc->wszName, sizeof(desc->wszName));
548 desc->wszName[min(len, sizeof(desc->wszName) - 1)] = 0;
549 desc->dwValidData |= DMUS_OBJ_NAME;
553 static inline void unfo_get_name(IStream *stream, const struct chunk_entry *unfo,
554 DMUS_OBJECTDESC *desc, BOOL inam)
556 struct chunk_entry chunk = {.parent = unfo};
558 while (stream_next_chunk(stream, &chunk) == S_OK)
559 if (chunk.id == DMUS_FOURCC_UNAM_CHUNK || (inam && chunk.id == mmioFOURCC('I','N','A','M')))
560 if (stream_chunk_get_wstr(stream, &chunk, desc->wszName, sizeof(desc->wszName)) == S_OK)
561 desc->dwValidData |= DMUS_OBJ_NAME;
564 HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
565 DMUS_OBJECTDESC *desc, DWORD supported)
567 struct chunk_entry chunk = {.parent = riff};
568 HRESULT hr;
570 TRACE("Looking for %#x in %p: %s\n", supported, stream, debugstr_chunk(riff));
572 desc->dwValidData = 0;
573 desc->dwSize = sizeof(*desc);
575 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) {
576 switch (chunk.id) {
577 case DMUS_FOURCC_CATEGORY_CHUNK:
578 if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
579 desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
580 desc->dwValidData |= DMUS_OBJ_CATEGORY;
581 break;
582 case DMUS_FOURCC_DATE_CHUNK:
583 if ((supported & DMUS_OBJ_DATE) && stream_chunk_get_data(stream, &chunk,
584 &desc->ftDate, sizeof(desc->ftDate)) == S_OK)
585 desc->dwValidData |= DMUS_OBJ_DATE;
586 break;
587 case DMUS_FOURCC_FILE_CHUNK:
588 if ((supported & DMUS_OBJ_FILENAME) && stream_chunk_get_wstr(stream, &chunk,
589 desc->wszFileName, sizeof(desc->wszFileName)) == S_OK)
590 desc->dwValidData |= DMUS_OBJ_FILENAME;
591 break;
592 case DMUS_FOURCC_GUID_CHUNK:
593 if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk,
594 &desc->guidObject, sizeof(desc->guidObject)) == S_OK)
595 desc->dwValidData |= DMUS_OBJ_OBJECT;
596 break;
597 case DMUS_FOURCC_NAME_CHUNK:
598 if ((supported & DMUS_OBJ_NAME) && stream_chunk_get_wstr(stream, &chunk,
599 desc->wszName, sizeof(desc->wszName)) == S_OK)
600 desc->dwValidData |= DMUS_OBJ_NAME;
601 break;
602 case DMUS_FOURCC_VERSION_CHUNK:
603 if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk,
604 &desc->vVersion, sizeof(desc->vVersion)) == S_OK)
605 desc->dwValidData |= DMUS_OBJ_VERSION;
606 break;
607 case FOURCC_LIST:
608 if (chunk.type == DMUS_FOURCC_UNFO_LIST && (supported & DMUS_OBJ_NAME))
609 unfo_get_name(stream, &chunk, desc, supported & DMUS_OBJ_NAME_INAM);
610 else if (chunk.type == DMUS_FOURCC_INFO_LIST && (supported & DMUS_OBJ_NAME_INFO))
611 info_get_name(stream, &chunk, desc);
612 break;
615 TRACE("Found %#x\n", desc->dwValidData);
617 return hr;
620 HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list,
621 IDirectMusicObject **dmobj)
623 struct chunk_entry chunk = {.parent = list};
624 IDirectMusicGetLoader *getloader;
625 IDirectMusicLoader *loader;
626 DMUS_OBJECTDESC desc;
627 DMUS_IO_REFERENCE reference;
628 HRESULT hr;
630 if (FAILED(hr = stream_next_chunk(stream, &chunk)))
631 return hr;
632 if (chunk.id != DMUS_FOURCC_REF_CHUNK)
633 return DMUS_E_UNSUPPORTED_STREAM;
635 if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &reference, sizeof(reference)))) {
636 WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
637 return hr;
639 TRACE("REFERENCE guidClassID %s, dwValidData %#x\n", debugstr_dmguid(&reference.guidClassID),
640 reference.dwValidData);
642 if (FAILED(hr = dmobj_parsedescriptor(stream, list, &desc, reference.dwValidData)))
643 return hr;
644 desc.guidClass = reference.guidClassID;
645 desc.dwValidData |= DMUS_OBJ_CLASS;
646 dump_DMUS_OBJECTDESC(&desc);
648 if (FAILED(hr = IStream_QueryInterface(stream, &IID_IDirectMusicGetLoader, (void**)&getloader)))
649 return hr;
650 hr = IDirectMusicGetLoader_GetLoader(getloader, &loader);
651 IDirectMusicGetLoader_Release(getloader);
652 if (FAILED(hr))
653 return hr;
655 hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicObject, (void**)dmobj);
656 IDirectMusicLoader_Release(loader);
658 return hr;
661 /* Generic IPersistStream methods */
662 static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface)
664 return CONTAINING_RECORD(iface, struct dmobject, IPersistStream_iface);
667 HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid,
668 void **ret_iface)
670 struct dmobject *This = impl_from_IPersistStream(iface);
671 return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface);
674 ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface)
676 struct dmobject *This = impl_from_IPersistStream(iface);
677 return IUnknown_AddRef(This->outer_unk);
680 ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface)
682 struct dmobject *This = impl_from_IPersistStream(iface);
683 return IUnknown_Release(This->outer_unk);
686 HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class)
688 struct dmobject *This = impl_from_IPersistStream(iface);
690 TRACE("(%p, %p)\n", This, class);
692 if (!class)
693 return E_POINTER;
695 *class = This->desc.guidClass;
697 return S_OK;
700 /* IPersistStream methods not implemented in native */
701 HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class)
703 TRACE("(%p, %p): method not implemented\n", iface, class);
704 return E_NOTIMPL;
707 HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface)
709 TRACE("(%p): method not implemented, always returning S_FALSE\n", iface);
710 return S_FALSE;
713 HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream,
714 BOOL clear_dirty)
716 TRACE("(%p, %p, %d): method not implemented\n", iface, stream, clear_dirty);
717 return E_NOTIMPL;
720 HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, ULARGE_INTEGER *size)
722 TRACE("(%p, %p): method not implemented\n", iface, size);
723 return E_NOTIMPL;
727 void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk)
729 dmobj->outer_unk = outer_unk;
730 dmobj->desc.dwSize = sizeof(dmobj->desc);
731 dmobj->desc.dwValidData = DMUS_OBJ_CLASS;
732 dmobj->desc.guidClass = *class;