ntdll: Add ACTCTX field limit checks to RtlCreateActivationContext().
[wine.git] / dlls / dmusic / collection.c
blob5cf129cfdd1cbb1217358563fbe47de66847ed1d
1 /*
2 * IDirectMusicCollection Implementation
4 * Copyright (C) 2003-2004 Rok Mandeljc
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "dmusic_private.h"
22 #include "soundfont.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(dmusic);
26 struct instrument_entry
28 struct list entry;
29 DWORD patch;
30 DMUS_OBJECTDESC desc;
31 IDirectMusicInstrument *instrument;
34 struct pool
36 POOLTABLE table;
37 POOLCUE cues[];
40 C_ASSERT(sizeof(struct pool) == offsetof(struct pool, cues[0]));
42 struct wave_entry
44 struct list entry;
45 IDirectMusicObject *wave;
46 DWORD offset;
49 struct collection
51 IDirectMusicCollection IDirectMusicCollection_iface;
52 struct dmobject dmobj;
53 LONG internal_ref;
54 LONG ref;
56 DLSHEADER header;
57 struct pool *pool;
58 struct list instruments;
59 struct list waves;
62 void collection_internal_addref(struct collection *collection)
64 ULONG ref = InterlockedIncrement( &collection->internal_ref );
65 TRACE( "collection %p, internal ref %lu.\n", collection, ref );
68 void collection_internal_release(struct collection *collection)
70 ULONG ref = InterlockedDecrement( &collection->internal_ref );
71 TRACE( "collection %p, internal ref %lu.\n", collection, ref );
73 if (!ref)
74 free(collection);
77 HRESULT collection_get_wave(struct collection *collection, DWORD index, IDirectMusicObject **out)
79 struct wave_entry *wave_entry;
80 DWORD offset;
82 if (index >= collection->pool->table.cCues) return E_INVALIDARG;
83 offset = collection->pool->cues[index].ulOffset;
85 LIST_FOR_EACH_ENTRY(wave_entry, &collection->waves, struct wave_entry, entry)
87 if (offset == wave_entry->offset)
89 *out = wave_entry->wave;
90 IUnknown_AddRef(wave_entry->wave);
91 return S_OK;
95 return E_FAIL;
98 static inline struct collection *impl_from_IDirectMusicCollection(IDirectMusicCollection *iface)
100 return CONTAINING_RECORD(iface, struct collection, IDirectMusicCollection_iface);
103 static inline struct collection *impl_from_IPersistStream(IPersistStream *iface)
105 return CONTAINING_RECORD(iface, struct collection, dmobj.IPersistStream_iface);
108 static HRESULT WINAPI collection_QueryInterface(IDirectMusicCollection *iface,
109 REFIID riid, void **ret_iface)
111 struct collection *This = impl_from_IDirectMusicCollection(iface);
113 TRACE("(%p, %s, %p)\n", iface, debugstr_dmguid(riid), ret_iface);
115 *ret_iface = NULL;
117 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectMusicCollection))
118 *ret_iface = iface;
119 else if (IsEqualIID(riid, &IID_IDirectMusicObject))
120 *ret_iface = &This->dmobj.IDirectMusicObject_iface;
121 else if (IsEqualIID(riid, &IID_IPersistStream))
122 *ret_iface = &This->dmobj.IPersistStream_iface;
123 else
125 WARN("(%p, %s, %p): not found\n", iface, debugstr_dmguid(riid), ret_iface);
126 return E_NOINTERFACE;
129 IUnknown_AddRef((IUnknown*)*ret_iface);
130 return S_OK;
133 static ULONG WINAPI collection_AddRef(IDirectMusicCollection *iface)
135 struct collection *This = impl_from_IDirectMusicCollection(iface);
136 ULONG ref = InterlockedIncrement(&This->ref);
138 TRACE("(%p): new ref = %lu\n", iface, ref);
140 return ref;
143 static ULONG WINAPI collection_Release(IDirectMusicCollection *iface)
145 struct collection *This = impl_from_IDirectMusicCollection(iface);
146 ULONG ref = InterlockedDecrement(&This->ref);
148 TRACE("(%p): new ref = %lu\n", iface, ref);
150 if (!ref)
152 struct instrument_entry *instrument_entry;
153 struct wave_entry *wave_entry;
154 void *next;
156 LIST_FOR_EACH_ENTRY_SAFE(instrument_entry, next, &This->instruments, struct instrument_entry, entry)
158 list_remove(&instrument_entry->entry);
159 IDirectMusicInstrument_Release(instrument_entry->instrument);
160 free(instrument_entry);
163 LIST_FOR_EACH_ENTRY_SAFE(wave_entry, next, &This->waves, struct wave_entry, entry)
165 list_remove(&wave_entry->entry);
166 IDirectMusicInstrument_Release(wave_entry->wave);
167 free(wave_entry);
170 collection_internal_release(This);
173 return ref;
176 static HRESULT WINAPI collection_GetInstrument(IDirectMusicCollection *iface,
177 DWORD patch, IDirectMusicInstrument **instrument)
179 struct collection *This = impl_from_IDirectMusicCollection(iface);
180 struct instrument_entry *entry;
182 TRACE("(%p, %lu, %p)\n", iface, patch, instrument);
184 LIST_FOR_EACH_ENTRY(entry, &This->instruments, struct instrument_entry, entry)
186 if (patch == entry->patch)
188 *instrument = entry->instrument;
189 IDirectMusicInstrument_AddRef(entry->instrument);
190 TRACE(": returning instrument %p\n", entry->instrument);
191 return S_OK;
195 TRACE(": instrument not found\n");
196 return DMUS_E_INVALIDPATCH;
199 static HRESULT WINAPI collection_EnumInstrument(IDirectMusicCollection *iface,
200 DWORD index, DWORD *patch, LPWSTR name, DWORD name_length)
202 struct collection *This = impl_from_IDirectMusicCollection(iface);
203 struct instrument_entry *entry;
205 TRACE("(%p, %ld, %p, %p, %ld)\n", iface, index, patch, name, name_length);
207 LIST_FOR_EACH_ENTRY(entry, &This->instruments, struct instrument_entry, entry)
209 if (index--) continue;
210 *patch = entry->patch;
211 if (name) lstrcpynW(name, entry->desc.wszName, name_length);
212 return S_OK;
215 return S_FALSE;
218 static const IDirectMusicCollectionVtbl collection_vtbl =
220 collection_QueryInterface,
221 collection_AddRef,
222 collection_Release,
223 collection_GetInstrument,
224 collection_EnumInstrument,
227 static HRESULT parse_lins_list(struct collection *This, IStream *stream, struct chunk_entry *parent)
229 struct chunk_entry chunk = {.parent = parent};
230 struct instrument_entry *entry;
231 HRESULT hr;
233 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
235 switch (MAKE_IDTYPE(chunk.id, chunk.type))
237 case MAKE_IDTYPE(FOURCC_LIST, FOURCC_INS):
238 if (!(entry = malloc(sizeof(*entry)))) return E_OUTOFMEMORY;
239 hr = instrument_create_from_chunk(stream, &chunk, This, &entry->desc, &entry->instrument);
240 if (SUCCEEDED(hr)) hr = IDirectMusicInstrument_GetPatch(entry->instrument, &entry->patch);
241 if (SUCCEEDED(hr)) list_add_tail(&This->instruments, &entry->entry);
242 else free(entry);
243 break;
245 default:
246 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
247 break;
250 if (FAILED(hr)) break;
253 return hr;
256 static HRESULT parse_wvpl_list(struct collection *This, IStream *stream, struct chunk_entry *parent)
258 struct chunk_entry chunk = {.parent = parent};
259 struct wave_entry *entry;
260 HRESULT hr;
262 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
264 switch (MAKE_IDTYPE(chunk.id, chunk.type))
266 case MAKE_IDTYPE(FOURCC_LIST, FOURCC_wave):
267 if (!(entry = malloc(sizeof(*entry)))) return E_OUTOFMEMORY;
268 if (FAILED(hr = wave_create_from_chunk(stream, &chunk, &entry->wave))) free(entry);
269 else
271 entry->offset = chunk.offset.QuadPart - parent->offset.QuadPart - 12;
272 list_add_tail(&This->waves, &entry->entry);
274 break;
276 default:
277 FIXME("Skipping unknown chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
278 break;
281 if (FAILED(hr)) break;
284 return hr;
287 static HRESULT parse_ptbl_chunk(struct collection *This, IStream *stream, struct chunk_entry *chunk)
289 struct pool *pool;
290 POOLTABLE table;
291 HRESULT hr;
292 UINT size;
294 if (chunk->size < sizeof(table)) return E_INVALIDARG;
295 if (FAILED(hr = stream_read(stream, &table, sizeof(table)))) return hr;
296 if (chunk->size != table.cbSize + sizeof(POOLCUE) * table.cCues) return E_INVALIDARG;
297 if (table.cbSize != sizeof(table)) return E_INVALIDARG;
299 size = offsetof(struct pool, cues[table.cCues]);
300 if (!(pool = malloc(size))) return E_OUTOFMEMORY;
301 pool->table = table;
303 size = sizeof(POOLCUE) * table.cCues;
304 if (FAILED(hr = stream_read(stream, pool->cues, size))) free(pool);
305 else This->pool = pool;
307 return hr;
310 static HRESULT parse_dls_chunk(struct collection *This, IStream *stream, struct chunk_entry *parent)
312 struct chunk_entry chunk = {.parent = parent};
313 HRESULT hr;
315 if (FAILED(hr = dmobj_parsedescriptor(stream, parent, &This->dmobj.desc,
316 DMUS_OBJ_NAME_INFO|DMUS_OBJ_VERSION|DMUS_OBJ_OBJECT|DMUS_OBJ_GUID_DLID))
317 || FAILED(hr = stream_reset_chunk_data(stream, parent)))
318 return hr;
320 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
322 switch (MAKE_IDTYPE(chunk.id, chunk.type))
324 case FOURCC_DLID:
325 case FOURCC_VERS:
326 case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_INFO_LIST):
327 /* already parsed by dmobj_parsedescriptor */
328 break;
330 case FOURCC_COLH:
331 hr = stream_chunk_get_data(stream, &chunk, &This->header, sizeof(This->header));
332 break;
334 case FOURCC_PTBL:
335 hr = parse_ptbl_chunk(This, stream, &chunk);
336 break;
338 case MAKE_IDTYPE(FOURCC_LIST, FOURCC_LINS):
339 hr = parse_lins_list(This, stream, &chunk);
340 break;
342 case MAKE_IDTYPE(FOURCC_LIST, FOURCC_WVPL):
343 hr = parse_wvpl_list(This, stream, &chunk);
344 break;
346 default:
347 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
348 break;
351 if (FAILED(hr)) break;
354 return hr;
357 static HRESULT parse_sdta_list(struct collection *This, IStream *stream, struct chunk_entry *parent,
358 struct soundfont *soundfont)
360 struct chunk_entry chunk = {.parent = parent};
361 HRESULT hr;
363 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
365 switch (MAKE_IDTYPE(chunk.id, chunk.type))
367 case mmioFOURCC('s','m','p','l'):
368 if (soundfont->sdta) return E_INVALIDARG;
369 if (!(soundfont->sdta = malloc(chunk.size))) return E_OUTOFMEMORY;
370 hr = stream_chunk_get_data(stream, &chunk, soundfont->sdta, chunk.size);
371 break;
373 default:
374 FIXME("Skipping unknown chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
375 break;
378 if (FAILED(hr)) break;
381 return hr;
384 static HRESULT parse_pdta_list(struct collection *This, IStream *stream, struct chunk_entry *parent,
385 struct soundfont *soundfont)
387 struct chunk_entry chunk = {.parent = parent};
388 HRESULT hr;
390 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
392 switch (MAKE_IDTYPE(chunk.id, chunk.type))
394 case mmioFOURCC('p','h','d','r'):
395 if (soundfont->phdr) return E_INVALIDARG;
396 if (!(soundfont->phdr = malloc(chunk.size))) return E_OUTOFMEMORY;
397 hr = stream_chunk_get_data(stream, &chunk, soundfont->phdr, chunk.size);
398 soundfont->preset_count = chunk.size / sizeof(*soundfont->phdr) - 1;
399 break;
401 case mmioFOURCC('p','b','a','g'):
402 if (soundfont->pbag) return E_INVALIDARG;
403 if (!(soundfont->pbag = malloc(chunk.size))) return E_OUTOFMEMORY;
404 hr = stream_chunk_get_data(stream, &chunk, soundfont->pbag, chunk.size);
405 break;
407 case mmioFOURCC('p','m','o','d'):
408 if (soundfont->pmod) return E_INVALIDARG;
409 if (!(soundfont->pmod = malloc(chunk.size))) return E_OUTOFMEMORY;
410 hr = stream_chunk_get_data(stream, &chunk, soundfont->pmod, chunk.size);
411 break;
413 case mmioFOURCC('p','g','e','n'):
414 if (soundfont->pgen) return E_INVALIDARG;
415 if (!(soundfont->pgen = malloc(chunk.size))) return E_OUTOFMEMORY;
416 hr = stream_chunk_get_data(stream, &chunk, soundfont->pgen, chunk.size);
417 break;
419 case mmioFOURCC('i','n','s','t'):
420 if (soundfont->inst) return E_INVALIDARG;
421 if (!(soundfont->inst = malloc(chunk.size))) return E_OUTOFMEMORY;
422 hr = stream_chunk_get_data(stream, &chunk, soundfont->inst, chunk.size);
423 soundfont->instrument_count = chunk.size / sizeof(*soundfont->inst) - 1;
424 break;
426 case mmioFOURCC('i','b','a','g'):
427 if (soundfont->ibag) return E_INVALIDARG;
428 if (!(soundfont->ibag = malloc(chunk.size))) return E_OUTOFMEMORY;
429 hr = stream_chunk_get_data(stream, &chunk, soundfont->ibag, chunk.size);
430 break;
432 case mmioFOURCC('i','m','o','d'):
433 if (soundfont->imod) return E_INVALIDARG;
434 if (!(soundfont->imod = malloc(chunk.size))) return E_OUTOFMEMORY;
435 hr = stream_chunk_get_data(stream, &chunk, soundfont->imod, chunk.size);
436 break;
438 case mmioFOURCC('i','g','e','n'):
439 if (soundfont->igen) return E_INVALIDARG;
440 if (!(soundfont->igen = malloc(chunk.size))) return E_OUTOFMEMORY;
441 hr = stream_chunk_get_data(stream, &chunk, soundfont->igen, chunk.size);
442 break;
444 case mmioFOURCC('s','h','d','r'):
445 if (soundfont->shdr) return E_INVALIDARG;
446 if (!(soundfont->shdr = malloc(chunk.size))) return E_OUTOFMEMORY;
447 hr = stream_chunk_get_data(stream, &chunk, soundfont->shdr, chunk.size);
448 soundfont->sample_count = chunk.size / sizeof(*soundfont->shdr) - 1;
449 break;
451 default:
452 FIXME("Skipping unknown chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
453 break;
456 if (FAILED(hr)) break;
459 return hr;
462 static HRESULT parse_sfbk_chunk(struct collection *This, IStream *stream, struct chunk_entry *parent)
464 struct chunk_entry chunk = {.parent = parent};
465 struct soundfont soundfont = {0};
466 UINT i, j, k;
467 HRESULT hr;
469 if (FAILED(hr = dmobj_parsedescriptor(stream, parent, &This->dmobj.desc,
470 DMUS_OBJ_NAME_INFO|DMUS_OBJ_VERSION|DMUS_OBJ_OBJECT|DMUS_OBJ_GUID_DLID))
471 || FAILED(hr = stream_reset_chunk_data(stream, parent)))
472 return hr;
474 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
476 switch (MAKE_IDTYPE(chunk.id, chunk.type))
478 case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_INFO_LIST):
479 /* already parsed by dmobj_parsedescriptor */
480 break;
482 case MAKE_IDTYPE(FOURCC_LIST, mmioFOURCC('s','d','t','a')):
483 hr = parse_sdta_list(This, stream, &chunk, &soundfont);
484 break;
486 case MAKE_IDTYPE(FOURCC_LIST, mmioFOURCC('p','d','t','a')):
487 hr = parse_pdta_list(This, stream, &chunk, &soundfont);
488 break;
490 default:
491 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
492 break;
495 if (FAILED(hr)) break;
498 if (SUCCEEDED(hr))
500 TRACE("presets:\n");
501 for (i = 0; i < soundfont.preset_count; i++)
503 struct sf_preset *preset = soundfont.phdr + i;
505 TRACE("preset[%u]:\n", i);
506 TRACE(" - name: %s\n", debugstr_a(preset->name));
507 TRACE(" - preset: %u\n", preset->preset);
508 TRACE(" - bank: %u\n", preset->bank);
509 TRACE(" - preset_bag_ndx: %u\n", preset->bag_ndx);
510 TRACE(" - library: %lu\n", preset->library);
511 TRACE(" - genre: %lu\n", preset->genre);
512 TRACE(" - morphology: %#lx\n", preset->morphology);
514 for (j = preset->bag_ndx; j < (preset + 1)->bag_ndx; j++)
516 struct sf_bag *bag = soundfont.pbag + j;
517 TRACE(" - bag[%u]:\n", j);
518 TRACE(" - gen_ndx: %u\n", bag->gen_ndx);
519 TRACE(" - mod_ndx: %u\n", bag->mod_ndx);
521 for (k = bag->gen_ndx; k < (bag + 1)->gen_ndx; k++)
523 struct sf_gen *gen = soundfont.pgen + k;
524 TRACE(" - gen[%u]: %s\n", k, debugstr_sf_gen(gen));
527 for (k = bag->mod_ndx; k < (bag + 1)->mod_ndx; k++)
529 struct sf_mod *mod = soundfont.pmod + k;
530 TRACE(" - mod[%u]: %s\n", k, debugstr_sf_mod(mod));
535 TRACE("instruments:\n");
536 for (i = 0; i < soundfont.instrument_count; i++)
538 struct sf_instrument *instrument = soundfont.inst + i;
539 TRACE("instrument[%u]:\n", i);
540 TRACE(" - name: %s\n", debugstr_a(instrument->name));
541 TRACE(" - bag_ndx: %u\n", instrument->bag_ndx);
543 for (j = instrument->bag_ndx; j < (instrument + 1)->bag_ndx; j++)
545 struct sf_bag *bag = soundfont.ibag + j;
546 TRACE(" - bag[%u]:\n", j);
547 TRACE(" - wGenNdx: %u\n", bag->gen_ndx);
548 TRACE(" - wModNdx: %u\n", bag->mod_ndx);
550 for (k = bag->gen_ndx; k < (bag + 1)->gen_ndx; k++)
552 struct sf_gen *gen = soundfont.igen + k;
553 TRACE(" - gen[%u]: %s\n", k, debugstr_sf_gen(gen));
556 for (k = bag->mod_ndx; k < (bag + 1)->mod_ndx; k++)
558 struct sf_mod *mod = soundfont.imod + k;
559 TRACE(" - mod[%u]: %s\n", k, debugstr_sf_mod(mod));
564 TRACE("samples:\n");
565 for (i = 0; i < soundfont.sample_count; i++)
567 struct sf_sample *sample = soundfont.shdr + i;
569 TRACE("sample[%u]:\n", i);
570 TRACE(" - name: %s\n", debugstr_a(sample->name));
571 TRACE(" - start: %lu\n", sample->start);
572 TRACE(" - end: %lu\n", sample->end);
573 TRACE(" - start_loop: %lu\n", sample->start_loop);
574 TRACE(" - end_loop: %lu\n", sample->end_loop);
575 TRACE(" - sample_rate: %lu\n", sample->sample_rate);
576 TRACE(" - original_key: %u\n", sample->original_key);
577 TRACE(" - correction: %d\n", sample->correction);
578 TRACE(" - sample_link: %#x\n", sample->sample_link);
579 TRACE(" - sample_type: %#x\n", sample->sample_type);
583 for (i = 0; SUCCEEDED(hr) && i < soundfont.preset_count; i++)
585 struct instrument_entry *entry;
587 if (!(entry = malloc(sizeof(*entry)))) return E_OUTOFMEMORY;
588 hr = instrument_create_from_soundfont(&soundfont, i, This, &entry->desc, &entry->instrument);
589 if (SUCCEEDED(hr)) hr = IDirectMusicInstrument_GetPatch(entry->instrument, &entry->patch);
590 if (SUCCEEDED(hr)) list_add_tail(&This->instruments, &entry->entry);
591 else free(entry);
594 if (SUCCEEDED(hr))
596 UINT size = offsetof(struct pool, cues[soundfont.sample_count]);
597 if (!(This->pool = calloc(1, size))) return E_OUTOFMEMORY;
598 This->pool->table.cbSize = sizeof(This->pool->table);
601 for (i = 0; SUCCEEDED(hr) && i < soundfont.sample_count; i++)
603 struct wave_entry *entry;
605 if (!(entry = malloc(sizeof(*entry)))) return E_OUTOFMEMORY;
606 hr = wave_create_from_soundfont(&soundfont, i, &entry->wave);
607 if (FAILED(hr)) free(entry);
608 else
610 entry->offset = i;
611 This->pool->table.cCues++;
612 This->pool->cues[i].ulOffset = i;
613 list_add_tail(&This->waves, &entry->entry);
617 free(soundfont.phdr);
618 free(soundfont.pbag);
619 free(soundfont.pmod);
620 free(soundfont.pgen);
621 free(soundfont.inst);
622 free(soundfont.ibag);
623 free(soundfont.imod);
624 free(soundfont.igen);
625 free(soundfont.shdr);
626 free(soundfont.sdta);
628 return hr;
631 static HRESULT WINAPI collection_object_ParseDescriptor(IDirectMusicObject *iface,
632 IStream *stream, DMUS_OBJECTDESC *desc)
634 struct chunk_entry riff = {0};
635 HRESULT hr;
637 TRACE("(%p, %p, %p)\n", iface, stream, desc);
639 if (!stream || !desc)
640 return E_POINTER;
642 if ((hr = stream_get_chunk(stream, &riff)) != S_OK)
643 return hr;
644 if (riff.id != FOURCC_RIFF || (riff.type != FOURCC_DLS && riff.type != mmioFOURCC('s','f','b','k'))) {
645 TRACE("loading failed: unexpected %s\n", debugstr_chunk(&riff));
646 stream_skip_chunk(stream, &riff);
647 return DMUS_E_NOTADLSCOL;
650 hr = dmobj_parsedescriptor(stream, &riff, desc, DMUS_OBJ_NAME_INFO|DMUS_OBJ_VERSION);
651 if (FAILED(hr))
652 return hr;
654 desc->guidClass = CLSID_DirectMusicCollection;
655 desc->dwValidData |= DMUS_OBJ_CLASS;
657 TRACE("returning descriptor:\n");
658 dump_DMUS_OBJECTDESC(desc);
659 return S_OK;
662 static const IDirectMusicObjectVtbl collection_object_vtbl =
664 dmobj_IDirectMusicObject_QueryInterface,
665 dmobj_IDirectMusicObject_AddRef,
666 dmobj_IDirectMusicObject_Release,
667 dmobj_IDirectMusicObject_GetDescriptor,
668 dmobj_IDirectMusicObject_SetDescriptor,
669 collection_object_ParseDescriptor,
672 static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, IStream *stream)
674 struct collection *This = impl_from_IPersistStream(iface);
675 struct chunk_entry chunk = {0};
676 HRESULT hr;
678 TRACE("(%p, %p)\n", This, stream);
680 if ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
682 switch (MAKE_IDTYPE(chunk.id, chunk.type))
684 case MAKE_IDTYPE(FOURCC_RIFF, FOURCC_DLS):
685 hr = parse_dls_chunk(This, stream, &chunk);
686 break;
688 case MAKE_IDTYPE(FOURCC_RIFF, mmioFOURCC('s','f','b','k')):
689 hr = parse_sfbk_chunk(This, stream, &chunk);
690 break;
692 default:
693 WARN("Invalid collection chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
694 hr = DMUS_E_UNSUPPORTED_STREAM;
695 break;
699 if (FAILED(hr)) return hr;
701 if (TRACE_ON(dmusic))
703 struct instrument_entry *entry;
704 struct wave_entry *wave_entry;
705 int i = 0;
707 TRACE("*** IDirectMusicCollection (%p) ***\n", &This->IDirectMusicCollection_iface);
708 dump_DMUS_OBJECTDESC(&This->dmobj.desc);
710 TRACE(" - Collection header:\n");
711 TRACE(" - cInstruments: %ld\n", This->header.cInstruments);
712 TRACE(" - Instruments:\n");
714 LIST_FOR_EACH_ENTRY(entry, &This->instruments, struct instrument_entry, entry)
716 TRACE(" - Instrument[%i]: %p\n", i, entry->instrument);
717 i++;
720 TRACE(" - cues:\n");
721 for (i = 0; This->pool && i < This->pool->table.cCues; i++)
722 TRACE(" - index: %u, offset: %lu\n", i, This->pool->cues[i].ulOffset);
724 TRACE(" - waves:\n");
725 LIST_FOR_EACH_ENTRY(wave_entry, &This->waves, struct wave_entry, entry)
726 TRACE(" - offset: %lu, wave %p\n", wave_entry->offset, wave_entry->wave);
729 stream_skip_chunk(stream, &chunk);
730 return S_OK;
733 static const IPersistStreamVtbl collection_stream_vtbl =
735 dmobj_IPersistStream_QueryInterface,
736 dmobj_IPersistStream_AddRef,
737 dmobj_IPersistStream_Release,
738 unimpl_IPersistStream_GetClassID,
739 unimpl_IPersistStream_IsDirty,
740 collection_stream_Load,
741 unimpl_IPersistStream_Save,
742 unimpl_IPersistStream_GetSizeMax,
745 HRESULT collection_create(IUnknown **ret_iface)
747 struct collection *collection;
749 *ret_iface = NULL;
750 if (!(collection = calloc(1, sizeof(*collection)))) return E_OUTOFMEMORY;
751 collection->IDirectMusicCollection_iface.lpVtbl = &collection_vtbl;
752 collection->internal_ref = 1;
753 collection->ref = 1;
754 dmobject_init(&collection->dmobj, &CLSID_DirectMusicCollection,
755 (IUnknown *)&collection->IDirectMusicCollection_iface);
756 collection->dmobj.IDirectMusicObject_iface.lpVtbl = &collection_object_vtbl;
757 collection->dmobj.IPersistStream_iface.lpVtbl = &collection_stream_vtbl;
758 list_init(&collection->instruments);
759 list_init(&collection->waves);
761 TRACE("Created DirectMusicCollection %p\n", collection);
762 *ret_iface = (IUnknown *)&collection->IDirectMusicCollection_iface;
763 return S_OK;