dmusic: Use generic "unimplemented" methods for IPersistStream.
[wine.git] / dlls / dmusic / collection.c
blobc7084dbec06a24377097de7c30de3c0713a3dade
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 "dmobject.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(dmusic);
25 WINE_DECLARE_DEBUG_CHANNEL(dmfile);
27 /*****************************************************************************
28 * IDirectMusicCollectionImpl implementation
30 typedef struct IDirectMusicCollectionImpl {
31 IDirectMusicCollection IDirectMusicCollection_iface;
32 struct dmobject dmobj;
33 LONG ref;
34 /* IDirectMusicCollectionImpl fields */
35 IStream *pStm; /* stream from which we load collection and later instruments */
36 LARGE_INTEGER liCollectionPosition; /* offset in a stream where collection was loaded from */
37 LARGE_INTEGER liWavePoolTablePosition; /* offset in a stream where wave pool table can be found */
38 DMUS_OBJECTDESC *pDesc;
39 CHAR *szCopyright; /* FIXME: should probably placed somewhere else */
40 DLSHEADER *pHeader;
41 /* pool table */
42 POOLTABLE *pPoolTable;
43 POOLCUE *pPoolCues;
44 /* instruments */
45 struct list Instruments;
46 } IDirectMusicCollectionImpl;
48 static inline IDirectMusicCollectionImpl *impl_from_IDirectMusicCollection(IDirectMusicCollection *iface)
50 return CONTAINING_RECORD(iface, IDirectMusicCollectionImpl, IDirectMusicCollection_iface);
53 static inline struct dmobject *impl_from_IDirectMusicObject(IDirectMusicObject *iface)
55 return CONTAINING_RECORD(iface, struct dmobject, IDirectMusicObject_iface);
58 static inline IDirectMusicCollectionImpl *impl_from_IPersistStream(IPersistStream *iface)
60 return CONTAINING_RECORD(iface, IDirectMusicCollectionImpl, dmobj.IPersistStream_iface);
63 /* IDirectMusicCollectionImpl IUnknown part: */
64 static HRESULT WINAPI IDirectMusicCollectionImpl_IDirectMusicCollection_QueryInterface(LPDIRECTMUSICCOLLECTION iface, REFIID riid, LPVOID *ret_iface)
66 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
68 TRACE("(%p/%p)->(%s, %p)\n", iface, This, debugstr_dmguid(riid), ret_iface);
70 *ret_iface = NULL;
72 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectMusicCollection))
73 *ret_iface = iface;
74 else if (IsEqualIID(riid, &IID_IDirectMusicObject))
75 *ret_iface = &This->dmobj.IDirectMusicObject_iface;
76 else if (IsEqualIID(riid, &IID_IPersistStream))
77 *ret_iface = &This->dmobj.IPersistStream_iface;
78 else
80 WARN("(%p/%p)->(%s, %p): not found\n", iface, This, debugstr_dmguid(riid), ret_iface);
81 return E_NOINTERFACE;
84 IUnknown_AddRef((IUnknown*)*ret_iface);
85 return S_OK;
88 static ULONG WINAPI IDirectMusicCollectionImpl_IDirectMusicCollection_AddRef(LPDIRECTMUSICCOLLECTION iface)
90 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
91 ULONG ref = InterlockedIncrement(&This->ref);
93 TRACE("(%p/%p)->(): new ref = %u\n", iface, This, ref);
95 return ref;
98 static ULONG WINAPI IDirectMusicCollectionImpl_IDirectMusicCollection_Release(LPDIRECTMUSICCOLLECTION iface)
100 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
101 ULONG ref = InterlockedDecrement(&This->ref);
103 TRACE("(%p/%p)->(): new ref = %u\n", iface, This, ref);
105 if (!ref) {
106 HeapFree(GetProcessHeap(), 0, This);
107 DMUSIC_UnlockModule();
110 return ref;
113 /* IDirectMusicCollection Interface follows: */
114 static HRESULT WINAPI IDirectMusicCollectionImpl_IDirectMusicCollection_GetInstrument(LPDIRECTMUSICCOLLECTION iface, DWORD patch, IDirectMusicInstrument** instrument)
116 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
117 DMUS_PRIVATE_INSTRUMENTENTRY *inst_entry;
118 struct list *list_entry;
119 DWORD inst_patch;
121 TRACE("(%p/%p)->(%u, %p)\n", iface, This, patch, instrument);
123 LIST_FOR_EACH(list_entry, &This->Instruments) {
124 inst_entry = LIST_ENTRY(list_entry, DMUS_PRIVATE_INSTRUMENTENTRY, entry);
125 IDirectMusicInstrument_GetPatch(inst_entry->pInstrument, &inst_patch);
126 if (patch == inst_patch) {
127 *instrument = inst_entry->pInstrument;
128 IDirectMusicInstrument_AddRef(inst_entry->pInstrument);
129 IDirectMusicInstrumentImpl_CustomLoad(inst_entry->pInstrument, This->pStm);
130 TRACE(": returning instrument %p\n", *instrument);
131 return S_OK;
135 TRACE(": instrument not found\n");
137 return DMUS_E_INVALIDPATCH;
140 static HRESULT WINAPI IDirectMusicCollectionImpl_IDirectMusicCollection_EnumInstrument(LPDIRECTMUSICCOLLECTION iface, DWORD index, DWORD* patch, LPWSTR name, DWORD name_length)
142 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
143 DWORD i = 0;
144 DMUS_PRIVATE_INSTRUMENTENTRY *inst_entry;
145 struct list *list_entry;
146 DWORD length;
148 TRACE("(%p/%p)->(%d, %p, %p, %d)\n", iface, This, index, patch, name, name_length);
150 LIST_FOR_EACH(list_entry, &This->Instruments) {
151 inst_entry = LIST_ENTRY(list_entry, DMUS_PRIVATE_INSTRUMENTENTRY, entry);
152 if (i == index) {
153 IDirectMusicInstrumentImpl *instrument = impl_from_IDirectMusicInstrument(inst_entry->pInstrument);
154 IDirectMusicInstrument_GetPatch(inst_entry->pInstrument, patch);
155 if (name) {
156 length = min(strlenW(instrument->wszName), name_length - 1);
157 memcpy(name, instrument->wszName, length * sizeof(WCHAR));
158 name[length] = '\0';
160 return S_OK;
162 i++;
165 return S_FALSE;
168 static const IDirectMusicCollectionVtbl DirectMusicCollection_Collection_Vtbl = {
169 IDirectMusicCollectionImpl_IDirectMusicCollection_QueryInterface,
170 IDirectMusicCollectionImpl_IDirectMusicCollection_AddRef,
171 IDirectMusicCollectionImpl_IDirectMusicCollection_Release,
172 IDirectMusicCollectionImpl_IDirectMusicCollection_GetInstrument,
173 IDirectMusicCollectionImpl_IDirectMusicCollection_EnumInstrument
176 /* IDirectMusicCollectionImpl IDirectMusicObject part: */
177 static HRESULT read_from_stream(IStream *stream, void *data, ULONG size)
179 ULONG read;
180 HRESULT hr;
182 hr = IStream_Read(stream, data, size, &read);
183 if (FAILED(hr)) {
184 TRACE("IStream_Read failed: %08x\n", hr);
185 return hr;
187 if (read < size) {
188 TRACE("Didn't read full chunk: %u < %u\n", read, size);
189 return E_FAIL;
192 return S_OK;
195 static HRESULT WINAPI IDirectMusicCollectionImpl_IDirectMusicObject_ParseDescriptor(LPDIRECTMUSICOBJECT iface, LPSTREAM stream, LPDMUS_OBJECTDESC desc)
197 struct dmobject *This = impl_from_IDirectMusicObject(iface);
198 DMUS_PRIVATE_CHUNK chunk;
199 DWORD StreamSize, StreamCount, ListSize[1], ListCount[1];
200 LARGE_INTEGER liMove; /* used when skipping chunks */
201 HRESULT hr;
203 TRACE("(%p)->(%p, %p)\n", This, stream, desc);
205 /* FIXME: should this be determined from stream? */
206 desc->dwValidData |= DMUS_OBJ_CLASS;
207 desc->guidClass = This->desc.guidClass;
209 hr = read_from_stream(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD));
210 if (FAILED(hr))
211 return hr;
212 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
214 if (chunk.fccID != FOURCC_RIFF) {
215 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
216 liMove.QuadPart = chunk.dwSize;
217 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
218 return DMUS_E_INVALIDFILE;
221 hr = read_from_stream(stream, &chunk.fccID, sizeof(FOURCC));
222 if (FAILED(hr))
223 return hr;
224 TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(chunk.fccID));
225 StreamSize = chunk.dwSize - sizeof(FOURCC);
227 if (chunk.fccID != FOURCC_DLS) {
228 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
229 liMove.QuadPart = StreamSize;
230 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
231 return E_FAIL;
234 StreamCount = 0;
235 TRACE_(dmfile)(": collection form\n");
237 do {
238 hr = read_from_stream(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD));
239 if (FAILED(hr))
240 return hr;
241 StreamCount += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
242 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
243 switch (chunk.fccID) {
244 case FOURCC_DLID:
245 TRACE_(dmfile)(": GUID chunk\n");
246 desc->dwValidData |= DMUS_OBJ_OBJECT;
247 hr = read_from_stream(stream, &desc->guidObject, chunk.dwSize);
248 if (FAILED(hr))
249 return hr;
250 break;
252 case DMUS_FOURCC_VERSION_CHUNK:
253 TRACE_(dmfile)(": version chunk\n");
254 desc->dwValidData |= DMUS_OBJ_VERSION;
255 hr = read_from_stream(stream, &desc->vVersion, chunk.dwSize);
256 if (FAILED(hr))
257 return hr;
258 break;
260 case DMUS_FOURCC_CATEGORY_CHUNK:
261 TRACE_(dmfile)(": category chunk\n");
262 desc->dwValidData |= DMUS_OBJ_CATEGORY;
263 hr = read_from_stream(stream, desc->wszCategory, chunk.dwSize);
264 if (FAILED(hr))
265 return hr;
266 break;
268 case FOURCC_LIST:
269 hr = read_from_stream(stream, &chunk.fccID, sizeof(FOURCC));
270 if (FAILED(hr))
271 return hr;
272 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID));
273 ListSize[0] = chunk.dwSize - sizeof(FOURCC);
274 ListCount[0] = 0;
275 switch (chunk.fccID) {
276 /* pure INFO list, such can be found in dls collections */
277 case DMUS_FOURCC_INFO_LIST:
278 TRACE_(dmfile)(": INFO list\n");
279 do {
280 hr = read_from_stream(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD));
281 if (FAILED(hr))
282 return hr;
283 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
284 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
285 switch (chunk.fccID) {
286 case mmioFOURCC('I','N','A','M'): {
287 CHAR szName[DMUS_MAX_NAME];
288 TRACE_(dmfile)(": name chunk\n");
289 desc->dwValidData |= DMUS_OBJ_NAME;
290 hr = read_from_stream(stream, szName, chunk.dwSize);
291 if (FAILED(hr))
292 return hr;
293 MultiByteToWideChar (CP_ACP, 0, szName, -1, desc->wszName, DMUS_MAX_NAME);
294 if (even_or_odd(chunk.dwSize)) {
295 ListCount[0]++;
296 liMove.QuadPart = 1;
297 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
299 break;
302 case mmioFOURCC('I','A','R','T'):
303 TRACE_(dmfile)(": artist chunk (ignored)\n");
304 if (even_or_odd(chunk.dwSize)) {
305 ListCount[0]++;
306 chunk.dwSize++;
308 liMove.QuadPart = chunk.dwSize;
309 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
310 break;
312 case mmioFOURCC('I','C','O','P'):
313 TRACE_(dmfile)(": copyright chunk (ignored)\n");
314 if (even_or_odd(chunk.dwSize)) {
315 ListCount[0]++;
316 chunk.dwSize++;
318 liMove.QuadPart = chunk.dwSize;
319 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
320 break;
322 case mmioFOURCC('I','S','B','J'):
323 TRACE_(dmfile)(": subject chunk (ignored)\n");
324 if (even_or_odd(chunk.dwSize)) {
325 ListCount[0]++;
326 chunk.dwSize++;
328 liMove.QuadPart = chunk.dwSize;
329 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
330 break;
332 case mmioFOURCC('I','C','M','T'):
333 TRACE_(dmfile)(": comment chunk (ignored)\n");
334 if (even_or_odd(chunk.dwSize)) {
335 ListCount[0]++;
336 chunk.dwSize++;
337 liMove.QuadPart = chunk.dwSize;
338 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
339 break;
342 default:
343 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
344 if (even_or_odd(chunk.dwSize)) {
345 ListCount[0] ++;
346 chunk.dwSize++;
348 liMove.QuadPart = chunk.dwSize;
349 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
350 break;
352 TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
353 } while (ListCount[0] < ListSize[0]);
354 break;
356 default:
357 TRACE_(dmfile)(": unknown (skipping)\n");
358 liMove.QuadPart = chunk.dwSize - sizeof(FOURCC);
359 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
360 break;
362 break;
364 default:
365 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
366 liMove.QuadPart = chunk.dwSize;
367 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
368 break;
370 TRACE_(dmfile)(": StreamCount[0] = %d < StreamSize[0] = %d\n", StreamCount, StreamSize);
371 } while (StreamCount < StreamSize);
373 TRACE_(dmfile)(": reading finished\n");
375 if (TRACE_ON(dmusic)) {
376 TRACE("Returning descriptor:\n");
377 dump_DMUS_OBJECTDESC(desc);
380 return S_OK;
383 static const IDirectMusicObjectVtbl dmobject_vtbl = {
384 dmobj_IDirectMusicObject_QueryInterface,
385 dmobj_IDirectMusicObject_AddRef,
386 dmobj_IDirectMusicObject_Release,
387 dmobj_IDirectMusicObject_GetDescriptor,
388 dmobj_IDirectMusicObject_SetDescriptor,
389 IDirectMusicCollectionImpl_IDirectMusicObject_ParseDescriptor
392 /* IDirectMusicCollectionImpl IPersistStream part: */
393 static HRESULT WINAPI IDirectMusicCollectionImpl_IPersistStream_Load(LPPERSISTSTREAM iface, IStream* stream)
395 IDirectMusicCollectionImpl *This = impl_from_IPersistStream(iface);
396 DMUS_PRIVATE_CHUNK chunk;
397 DWORD StreamSize, StreamCount, ListSize[2], ListCount[2];
398 LARGE_INTEGER liMove; /* used when skipping chunks */
399 ULARGE_INTEGER dlibCollectionPosition, dlibInstrumentPosition, dlibWavePoolPosition;
401 IStream_AddRef(stream); /* add count for later references */
402 liMove.QuadPart = 0;
403 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dlibCollectionPosition); /* store offset, in case it'll be needed later */
404 This->liCollectionPosition.QuadPart = dlibCollectionPosition.QuadPart;
405 This->pStm = stream;
407 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
408 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
410 if (chunk.fccID != FOURCC_RIFF) {
411 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
412 liMove.QuadPart = chunk.dwSize;
413 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
414 return E_FAIL;
417 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL);
418 TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(chunk.fccID));
419 StreamSize = chunk.dwSize - sizeof(FOURCC);
420 StreamCount = 0;
422 if (chunk.fccID != FOURCC_DLS) {
423 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
424 liMove.QuadPart = StreamSize;
425 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
426 return E_FAIL;
429 TRACE_(dmfile)(": collection form\n");
430 do {
431 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
432 StreamCount += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
433 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
434 switch (chunk.fccID) {
435 case FOURCC_COLH: {
436 TRACE_(dmfile)(": collection header chunk\n");
437 This->pHeader = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, chunk.dwSize);
438 IStream_Read(stream, This->pHeader, chunk.dwSize, NULL);
439 break;
441 case FOURCC_DLID: {
442 TRACE_(dmfile)(": DLID (GUID) chunk\n");
443 This->pDesc->dwValidData |= DMUS_OBJ_OBJECT;
444 IStream_Read(stream, &This->pDesc->guidObject, chunk.dwSize, NULL);
445 break;
447 case FOURCC_VERS: {
448 TRACE_(dmfile)(": version chunk\n");
449 This->pDesc->dwValidData |= DMUS_OBJ_VERSION;
450 IStream_Read(stream, &This->pDesc->vVersion, chunk.dwSize, NULL);
451 break;
453 case FOURCC_PTBL: {
454 TRACE_(dmfile)(": pool table chunk\n");
455 This->pPoolTable = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(POOLTABLE));
456 IStream_Read(stream, This->pPoolTable, sizeof(POOLTABLE), NULL);
457 chunk.dwSize -= sizeof(POOLTABLE);
458 This->pPoolCues = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pPoolTable->cCues * sizeof(POOLCUE));
459 IStream_Read(stream, This->pPoolCues, chunk.dwSize, NULL);
460 break;
462 case FOURCC_LIST: {
463 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL);
464 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID));
465 ListSize[0] = chunk.dwSize - sizeof(FOURCC);
466 ListCount[0] = 0;
467 switch (chunk.fccID) {
468 case DMUS_FOURCC_INFO_LIST: {
469 TRACE_(dmfile)(": INFO list\n");
470 do {
471 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
472 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
473 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
474 switch (chunk.fccID) {
475 case mmioFOURCC('I','N','A','M'): {
476 CHAR szName[DMUS_MAX_NAME];
477 TRACE_(dmfile)(": name chunk\n");
478 This->pDesc->dwValidData |= DMUS_OBJ_NAME;
479 IStream_Read(stream, szName, chunk.dwSize, NULL);
480 MultiByteToWideChar(CP_ACP, 0, szName, -1, This->pDesc->wszName, DMUS_MAX_NAME);
481 if (even_or_odd(chunk.dwSize)) {
482 ListCount[0]++;
483 liMove.QuadPart = 1;
484 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
486 break;
488 case mmioFOURCC('I','A','R','T'): {
489 TRACE_(dmfile)(": artist chunk (ignored)\n");
490 if (even_or_odd(chunk.dwSize)) {
491 ListCount[0]++;
492 chunk.dwSize++;
494 liMove.QuadPart = chunk.dwSize;
495 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
496 break;
498 case mmioFOURCC('I','C','O','P'): {
499 TRACE_(dmfile)(": copyright chunk\n");
500 This->szCopyright = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, chunk.dwSize);
501 IStream_Read(stream, This->szCopyright, chunk.dwSize, NULL);
502 if (even_or_odd(chunk.dwSize)) {
503 ListCount[0]++;
504 liMove.QuadPart = 1;
505 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
507 break;
509 case mmioFOURCC('I','S','B','J'): {
510 TRACE_(dmfile)(": subject chunk (ignored)\n");
511 if (even_or_odd(chunk.dwSize)) {
512 ListCount[0]++;
513 chunk.dwSize++;
515 liMove.QuadPart = chunk.dwSize;
516 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
517 break;
519 case mmioFOURCC('I','C','M','T'): {
520 TRACE_(dmfile)(": comment chunk (ignored)\n");
521 if (even_or_odd(chunk.dwSize)) {
522 ListCount[0]++;
523 chunk.dwSize++;
525 liMove.QuadPart = chunk.dwSize;
526 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
527 break;
529 default: {
530 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
531 if (even_or_odd(chunk.dwSize)) {
532 ListCount[0]++;
533 chunk.dwSize++;
535 liMove.QuadPart = chunk.dwSize;
536 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
537 break;
540 TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
541 } while (ListCount[0] < ListSize[0]);
542 break;
544 case FOURCC_WVPL: {
545 TRACE_(dmfile)(": wave pool list (mark & skip)\n");
546 liMove.QuadPart = 0;
547 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dlibWavePoolPosition); /* store position */
548 This->liWavePoolTablePosition.QuadPart = dlibWavePoolPosition.QuadPart;
549 liMove.QuadPart = chunk.dwSize - sizeof(FOURCC);
550 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
551 break;
553 case FOURCC_LINS: {
554 TRACE_(dmfile)(": instruments list\n");
555 do {
556 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
557 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
558 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
559 switch (chunk.fccID) {
560 case FOURCC_LIST: {
561 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL);
562 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID));
563 ListSize[1] = chunk.dwSize - sizeof(FOURCC);
564 ListCount[1] = 0;
565 switch (chunk.fccID) {
566 case FOURCC_INS: {
567 LPDMUS_PRIVATE_INSTRUMENTENTRY new_instrument = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_INSTRUMENTENTRY));
568 TRACE_(dmfile)(": instrument list\n");
569 /* Only way to create this one... even M$ does it discretely */
570 DMUSIC_CreateDirectMusicInstrumentImpl(&IID_IDirectMusicInstrument, (void**)&new_instrument->pInstrument, NULL);
572 IDirectMusicInstrumentImpl *instrument = impl_from_IDirectMusicInstrument(new_instrument->pInstrument);
573 /* Store offset and length, they will be needed when loading the instrument */
574 liMove.QuadPart = 0;
575 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dlibInstrumentPosition);
576 instrument->liInstrumentPosition.QuadPart = dlibInstrumentPosition.QuadPart;
577 instrument->length = ListSize[1];
578 do {
579 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
580 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
581 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
582 switch (chunk.fccID) {
583 case FOURCC_INSH: {
584 TRACE_(dmfile)(": instrument header chunk\n");
585 IStream_Read(stream, &instrument->header, chunk.dwSize, NULL);
586 break;
588 case FOURCC_DLID: {
589 TRACE_(dmfile)(": DLID (GUID) chunk\n");
590 IStream_Read(stream, &instrument->id, chunk.dwSize, NULL);
591 break;
593 case FOURCC_LIST: {
594 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL);
595 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID));
596 switch (chunk.fccID) {
597 default: {
598 TRACE_(dmfile)(": unknown (skipping)\n");
599 liMove.QuadPart = chunk.dwSize - sizeof(FOURCC);
600 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
601 break;
604 break;
606 default: {
607 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
608 liMove.QuadPart = chunk.dwSize;
609 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
610 break;
613 TRACE_(dmfile)(": ListCount[1] = %d < ListSize[1] = %d\n", ListCount[1], ListSize[1]);
614 } while (ListCount[1] < ListSize[1]);
615 /* DEBUG: dumps whole instrument object tree: */
616 if (TRACE_ON(dmusic)) {
617 TRACE("*** IDirectMusicInstrument (%p) ***\n", instrument);
618 if (!IsEqualGUID(&instrument->id, &GUID_NULL))
619 TRACE(" - GUID = %s\n", debugstr_dmguid(&instrument->id));
620 TRACE(" - Instrument header:\n");
621 TRACE(" - cRegions: %d\n", instrument->header.cRegions);
622 TRACE(" - Locale:\n");
623 TRACE(" - ulBank: %d\n", instrument->header.Locale.ulBank);
624 TRACE(" - ulInstrument: %d\n", instrument->header.Locale.ulInstrument);
625 TRACE(" => dwPatch: %d\n", MIDILOCALE2Patch(&instrument->header.Locale));
627 list_add_tail(&This->Instruments, &new_instrument->entry);
629 break;
632 break;
634 default: {
635 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
636 liMove.QuadPart = chunk.dwSize;
637 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
638 break;
641 TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
642 } while (ListCount[0] < ListSize[0]);
643 break;
645 default: {
646 TRACE_(dmfile)(": unknown (skipping)\n");
647 liMove.QuadPart = chunk.dwSize - sizeof(FOURCC);
648 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
649 break;
652 break;
654 default: {
655 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
656 liMove.QuadPart = chunk.dwSize;
657 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
658 break;
661 TRACE_(dmfile)(": StreamCount = %d < StreamSize = %d\n", StreamCount, StreamSize);
662 } while (StreamCount < StreamSize);
664 TRACE_(dmfile)(": reading finished\n");
667 /* DEBUG: dumps whole collection object tree: */
668 if (TRACE_ON(dmusic)) {
669 int r = 0;
670 DMUS_PRIVATE_INSTRUMENTENTRY *tmpEntry;
671 struct list *listEntry;
673 TRACE("*** IDirectMusicCollection (%p) ***\n", &This->IDirectMusicCollection_iface);
674 if (This->pDesc->dwValidData & DMUS_OBJ_OBJECT)
675 TRACE(" - GUID = %s\n", debugstr_dmguid(&This->pDesc->guidObject));
676 if (This->pDesc->dwValidData & DMUS_OBJ_VERSION)
677 TRACE(" - Version = %i,%i,%i,%i\n", (This->pDesc->vVersion.dwVersionMS >> 8) & 0x0000FFFF, This->pDesc->vVersion.dwVersionMS & 0x0000FFFF,
678 (This->pDesc->vVersion.dwVersionLS >> 8) & 0x0000FFFF, This->pDesc->vVersion.dwVersionLS & 0x0000FFFF);
679 if (This->pDesc->dwValidData & DMUS_OBJ_NAME)
680 TRACE(" - Name = %s\n", debugstr_w(This->pDesc->wszName));
682 TRACE(" - Collection header:\n");
683 TRACE(" - cInstruments: %d\n", This->pHeader->cInstruments);
684 TRACE(" - Instruments:\n");
686 LIST_FOR_EACH(listEntry, &This->Instruments) {
687 tmpEntry = LIST_ENTRY( listEntry, DMUS_PRIVATE_INSTRUMENTENTRY, entry );
688 TRACE(" - Instrument[%i]: %p\n", r, tmpEntry->pInstrument);
689 r++;
693 return S_OK;
696 static const IPersistStreamVtbl persiststream_vtbl = {
697 dmobj_IPersistStream_QueryInterface,
698 dmobj_IPersistStream_AddRef,
699 dmobj_IPersistStream_Release,
700 unimpl_IPersistStream_GetClassID,
701 unimpl_IPersistStream_IsDirty,
702 IDirectMusicCollectionImpl_IPersistStream_Load,
703 unimpl_IPersistStream_Save,
704 unimpl_IPersistStream_GetSizeMax
708 HRESULT WINAPI DMUSIC_CreateDirectMusicCollectionImpl(LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter)
710 IDirectMusicCollectionImpl* obj;
711 HRESULT hr;
713 *ppobj = NULL;
714 if (pUnkOuter)
715 return CLASS_E_NOAGGREGATION;
717 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicCollectionImpl));
718 if (!obj)
719 return E_OUTOFMEMORY;
721 obj->IDirectMusicCollection_iface.lpVtbl = &DirectMusicCollection_Collection_Vtbl;
722 obj->ref = 1;
723 dmobject_init(&obj->dmobj, &CLSID_DirectMusicCollection,
724 (IUnknown*)&obj->IDirectMusicCollection_iface);
725 obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl;
726 obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl;
727 obj->pDesc = &obj->dmobj.desc;
729 list_init (&obj->Instruments);
731 DMUSIC_LockModule();
732 hr = IDirectMusicCollection_QueryInterface(&obj->IDirectMusicCollection_iface, lpcGUID, ppobj);
733 IDirectMusicCollection_Release(&obj->IDirectMusicCollection_iface);
735 return hr;