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
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
) {
39 #define X(guid) { &guid, #guid }
45 X(CLSID_AudioVBScript
),
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
),
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
),
137 X(IID_IPersistStream
),
139 X(IID_IClassFactory
),
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
),
150 X(GUID_CommandParam
),
151 X(GUID_CommandParam2
),
152 X(GUID_CommandParamNext
),
153 X(GUID_IDirectMusicBand
),
154 X(GUID_IDirectMusicChordMap
),
155 X(GUID_IDirectMusicStyle
),
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
),
168 X(GUID_DownloadToAudioPath
),
169 X(GUID_Enable_Auto_Download
),
171 X(GUID_EnableTimeSig
),
172 X(GUID_IgnoreBankSelectForGM
),
173 X(GUID_SeedVariations
),
174 X(GUID_StandardMIDIFile
),
176 X(GUID_UnloadFromAudioPath
),
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
),
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
)
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
))
228 TRACE_(dmfile
)("DMUS_OBJECTDESC (%p):", desc
);
229 TRACE_(dmfile
)(" - dwSize = %lu\n", desc
->dwSize
);
231 #define X(flag) if (desc->dwValidData & flag) TRACE_(dmfile)(#flag " ")
232 TRACE_(dmfile
)(" - dwValidData = %#08lx ( ", desc
->dwValidData
);
236 X(DMUS_OBJ_CATEGORY
);
237 X(DMUS_OBJ_FILENAME
);
238 X(DMUS_OBJ_FULLPATH
);
245 TRACE_(dmfile
)(")\n");
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
) {
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
= "";
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 %lu", debugstr_fourcc(chunk
->id
), type
, chunk
->size
);
291 static HRESULT
stream_read(IStream
*stream
, void *data
, ULONG size
)
296 hr
= IStream_Read(stream
, data
, size
, &read
);
298 TRACE_(dmfile
)("IStream_Read failed: %#lx\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: %lu < %lu\n", read
, size
);
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;
314 hr
= IStream_Seek(stream
, zero
, STREAM_SEEK_CUR
, &chunk
->offset
);
317 assert(!(chunk
->offset
.QuadPart
& 1));
319 p_end
= chunk
->parent
->offset
.QuadPart
+ CHUNK_HDR_SIZE
+ ((chunk
->parent
->size
+ 1) & ~1);
320 if (chunk
->offset
.QuadPart
== p_end
)
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
));
330 hr
= stream_read(stream
, chunk
, CHUNK_HDR_SIZE
);
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
));
342 if (chunk
->id
== FOURCC_LIST
|| chunk
->id
== FOURCC_RIFF
) {
343 hr
= stream_read(stream
, &chunk
->type
, sizeof(FOURCC
));
345 return hr
!= S_FALSE
? hr
: E_FAIL
;
348 TRACE_(dmfile
)("Returning %s\n", debugstr_chunk(chunk
));
353 HRESULT
stream_skip_chunk(IStream
*stream
, const struct chunk_entry
*chunk
)
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
)
367 hr
= stream_skip_chunk(stream
, chunk
);
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
)
389 if (chunk
->size
< sizeof(DWORD
)) {
390 WARN_(dmfile
)("%s: Too short to read element size\n", debugstr_chunk(chunk
));
393 if (FAILED(hr
= stream_read(stream
, &size
, sizeof(DWORD
))))
395 if (size
!= elem_size
) {
396 WARN_(dmfile
)("%s: Array element size mismatch: got %lu, expected %lu\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
))) {
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
);
419 HRESULT
stream_chunk_get_data(IStream
*stream
, const struct chunk_entry
*chunk
, void *data
,
422 if (chunk
->size
!= size
) {
423 WARN_(dmfile
)("Chunk %s (size %lu, offset %s) doesn't contains the expected data size %lu\n",
424 debugstr_fourcc(chunk
->id
), chunk
->size
,
425 wine_dbgstr_longlong(chunk
->offset
.QuadPart
), size
);
428 return stream_read(stream
, data
, size
);
431 HRESULT
stream_chunk_get_wstr(IStream
*stream
, const struct chunk_entry
*chunk
, WCHAR
*str
,
437 hr
= IStream_Read(stream
, str
, min(chunk
->size
, size
), &len
);
441 /* Don't assume the string is properly zero terminated */
442 str
[min(len
, size
- 1)] = 0;
444 if (len
< chunk
->size
)
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
,
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
);
486 memcpy(desc
, &This
->desc
, This
->desc
.dwSize
);
491 HRESULT WINAPI
dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject
*iface
,
492 DMUS_OBJECTDESC
*desc
)
494 struct dmobject
*This
= impl_from_IDirectMusicObject(iface
);
497 TRACE("(%p, %p)\n", iface
, desc
);
502 /* Immutable property */
503 if (desc
->dwValidData
& DMUS_OBJ_CLASS
)
505 desc
->dwValidData
&= ~DMUS_OBJ_CLASS
;
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
;
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
];
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
);
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
};
570 TRACE("Looking for %#lx 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
) {
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
;
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
;
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
;
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
;
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
;
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
;
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
);
615 TRACE("Found %#lx\n", desc
->dwValidData
);
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
;
630 if (FAILED(hr
= stream_next_chunk(stream
, &chunk
)))
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
));
639 TRACE("REFERENCE guidClassID %s, dwValidData %#lx\n", debugstr_dmguid(&reference
.guidClassID
),
640 reference
.dwValidData
);
642 if (FAILED(hr
= dmobj_parsedescriptor(stream
, list
, &desc
, reference
.dwValidData
)))
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
)))
650 hr
= IDirectMusicGetLoader_GetLoader(getloader
, &loader
);
651 IDirectMusicGetLoader_Release(getloader
);
655 hr
= IDirectMusicLoader_GetObject(loader
, &desc
, &IID_IDirectMusicObject
, (void**)dmobj
);
656 IDirectMusicLoader_Release(loader
);
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
,
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);
695 *class = This
->desc
.guidClass
;
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);
707 HRESULT WINAPI
unimpl_IPersistStream_IsDirty(IPersistStream
*iface
)
709 TRACE("(%p): method not implemented, always returning S_FALSE\n", iface
);
713 HRESULT WINAPI
unimpl_IPersistStream_Save(IPersistStream
*iface
, IStream
*stream
,
716 TRACE("(%p, %p, %d): method not implemented\n", iface
, stream
, clear_dirty
);
720 HRESULT WINAPI
unimpl_IPersistStream_GetSizeMax(IPersistStream
*iface
, ULARGE_INTEGER
*size
)
722 TRACE("(%p, %p): method not implemented\n", iface
, size
);
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;