* Sync up to trunk head (r64377).
[reactos.git] / dll / directx / wine / dmusic / collection.c
1 /*
2 * IDirectMusicCollection Implementation
3 *
4 * Copyright (C) 2003-2004 Rok Mandeljc
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "dmusic_private.h"
22
23 #include <dmusicf.h>
24
25 WINE_DECLARE_DEBUG_CHANNEL(dmfile);
26
27 /*****************************************************************************
28 * IDirectMusicCollectionImpl implementation
29 */
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 CHAR *szCopyright; /* FIXME: should probably be placed somewhere else */
39 DLSHEADER *pHeader;
40 /* pool table */
41 POOLTABLE *pPoolTable;
42 POOLCUE *pPoolCues;
43 /* instruments */
44 struct list Instruments;
45 } IDirectMusicCollectionImpl;
46
47 static inline IDirectMusicCollectionImpl *impl_from_IDirectMusicCollection(IDirectMusicCollection *iface)
48 {
49 return CONTAINING_RECORD(iface, IDirectMusicCollectionImpl, IDirectMusicCollection_iface);
50 }
51
52 static inline struct dmobject *impl_from_IDirectMusicObject(IDirectMusicObject *iface)
53 {
54 return CONTAINING_RECORD(iface, struct dmobject, IDirectMusicObject_iface);
55 }
56
57 static inline IDirectMusicCollectionImpl *impl_from_IPersistStream(IPersistStream *iface)
58 {
59 return CONTAINING_RECORD(iface, IDirectMusicCollectionImpl, dmobj.IPersistStream_iface);
60 }
61
62 /* IDirectMusicCollectionImpl IUnknown part: */
63 static HRESULT WINAPI IDirectMusicCollectionImpl_QueryInterface(IDirectMusicCollection *iface,
64 REFIID riid, void **ret_iface)
65 {
66 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
67
68 TRACE("(%p/%p)->(%s, %p)\n", iface, This, debugstr_dmguid(riid), ret_iface);
69
70 *ret_iface = NULL;
71
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
79 {
80 WARN("(%p/%p)->(%s, %p): not found\n", iface, This, debugstr_dmguid(riid), ret_iface);
81 return E_NOINTERFACE;
82 }
83
84 IUnknown_AddRef((IUnknown*)*ret_iface);
85 return S_OK;
86 }
87
88 static ULONG WINAPI IDirectMusicCollectionImpl_AddRef(IDirectMusicCollection *iface)
89 {
90 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
91 ULONG ref = InterlockedIncrement(&This->ref);
92
93 TRACE("(%p/%p)->(): new ref = %u\n", iface, This, ref);
94
95 return ref;
96 }
97
98 static ULONG WINAPI IDirectMusicCollectionImpl_Release(IDirectMusicCollection *iface)
99 {
100 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
101 ULONG ref = InterlockedDecrement(&This->ref);
102
103 TRACE("(%p/%p)->(): new ref = %u\n", iface, This, ref);
104
105 if (!ref) {
106 HeapFree(GetProcessHeap(), 0, This);
107 DMUSIC_UnlockModule();
108 }
109
110 return ref;
111 }
112
113 /* IDirectMusicCollection Interface follows: */
114 static HRESULT WINAPI IDirectMusicCollectionImpl_GetInstrument(IDirectMusicCollection *iface,
115 DWORD patch, IDirectMusicInstrument **instrument)
116 {
117 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
118 DMUS_PRIVATE_INSTRUMENTENTRY *inst_entry;
119 struct list *list_entry;
120 DWORD inst_patch;
121
122 TRACE("(%p/%p)->(%u, %p)\n", iface, This, patch, instrument);
123
124 LIST_FOR_EACH(list_entry, &This->Instruments) {
125 inst_entry = LIST_ENTRY(list_entry, DMUS_PRIVATE_INSTRUMENTENTRY, entry);
126 IDirectMusicInstrument_GetPatch(inst_entry->pInstrument, &inst_patch);
127 if (patch == inst_patch) {
128 *instrument = inst_entry->pInstrument;
129 IDirectMusicInstrument_AddRef(inst_entry->pInstrument);
130 IDirectMusicInstrumentImpl_CustomLoad(inst_entry->pInstrument, This->pStm);
131 TRACE(": returning instrument %p\n", *instrument);
132 return S_OK;
133 }
134 }
135
136 TRACE(": instrument not found\n");
137
138 return DMUS_E_INVALIDPATCH;
139 }
140
141 static HRESULT WINAPI IDirectMusicCollectionImpl_EnumInstrument(IDirectMusicCollection *iface,
142 DWORD index, DWORD *patch, LPWSTR name, DWORD name_length)
143 {
144 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
145 DWORD i = 0;
146 DMUS_PRIVATE_INSTRUMENTENTRY *inst_entry;
147 struct list *list_entry;
148 DWORD length;
149
150 TRACE("(%p/%p)->(%d, %p, %p, %d)\n", iface, This, index, patch, name, name_length);
151
152 LIST_FOR_EACH(list_entry, &This->Instruments) {
153 inst_entry = LIST_ENTRY(list_entry, DMUS_PRIVATE_INSTRUMENTENTRY, entry);
154 if (i == index) {
155 IDirectMusicInstrumentImpl *instrument = impl_from_IDirectMusicInstrument(inst_entry->pInstrument);
156 IDirectMusicInstrument_GetPatch(inst_entry->pInstrument, patch);
157 if (name) {
158 length = min(strlenW(instrument->wszName), name_length - 1);
159 memcpy(name, instrument->wszName, length * sizeof(WCHAR));
160 name[length] = '\0';
161 }
162 return S_OK;
163 }
164 i++;
165 }
166
167 return S_FALSE;
168 }
169
170 static const IDirectMusicCollectionVtbl DirectMusicCollection_Collection_Vtbl = {
171 IDirectMusicCollectionImpl_QueryInterface,
172 IDirectMusicCollectionImpl_AddRef,
173 IDirectMusicCollectionImpl_Release,
174 IDirectMusicCollectionImpl_GetInstrument,
175 IDirectMusicCollectionImpl_EnumInstrument
176 };
177
178 /* IDirectMusicCollectionImpl IDirectMusicObject part: */
179 static HRESULT read_from_stream(IStream *stream, void *data, ULONG size)
180 {
181 ULONG read;
182 HRESULT hr;
183
184 hr = IStream_Read(stream, data, size, &read);
185 if (FAILED(hr)) {
186 TRACE("IStream_Read failed: %08x\n", hr);
187 return hr;
188 }
189 if (read < size) {
190 TRACE("Didn't read full chunk: %u < %u\n", read, size);
191 return E_FAIL;
192 }
193
194 return S_OK;
195 }
196
197 static HRESULT WINAPI IDirectMusicObjectImpl_ParseDescriptor(IDirectMusicObject *iface,
198 IStream *stream, DMUS_OBJECTDESC *desc)
199 {
200 struct dmobject *This = impl_from_IDirectMusicObject(iface);
201 DMUS_PRIVATE_CHUNK chunk;
202 DWORD StreamSize, StreamCount, ListSize[1], ListCount[1];
203 LARGE_INTEGER liMove; /* used when skipping chunks */
204 HRESULT hr;
205
206 TRACE("(%p)->(%p, %p)\n", This, stream, desc);
207
208 /* FIXME: should this be determined from stream? */
209 desc->dwValidData |= DMUS_OBJ_CLASS;
210 desc->guidClass = This->desc.guidClass;
211
212 hr = read_from_stream(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD));
213 if (FAILED(hr))
214 return hr;
215 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
216
217 if (chunk.fccID != FOURCC_RIFF) {
218 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
219 liMove.QuadPart = chunk.dwSize;
220 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
221 return DMUS_E_INVALIDFILE;
222 }
223
224 hr = read_from_stream(stream, &chunk.fccID, sizeof(FOURCC));
225 if (FAILED(hr))
226 return hr;
227 TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(chunk.fccID));
228 StreamSize = chunk.dwSize - sizeof(FOURCC);
229
230 if (chunk.fccID != FOURCC_DLS) {
231 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
232 liMove.QuadPart = StreamSize;
233 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
234 return E_FAIL;
235 }
236
237 StreamCount = 0;
238 TRACE_(dmfile)(": collection form\n");
239
240 do {
241 hr = read_from_stream(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD));
242 if (FAILED(hr))
243 return hr;
244 StreamCount += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
245 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
246 switch (chunk.fccID) {
247 case FOURCC_DLID:
248 TRACE_(dmfile)(": GUID chunk\n");
249 desc->dwValidData |= DMUS_OBJ_OBJECT;
250 hr = read_from_stream(stream, &desc->guidObject, chunk.dwSize);
251 if (FAILED(hr))
252 return hr;
253 break;
254
255 case DMUS_FOURCC_VERSION_CHUNK:
256 TRACE_(dmfile)(": version chunk\n");
257 desc->dwValidData |= DMUS_OBJ_VERSION;
258 hr = read_from_stream(stream, &desc->vVersion, chunk.dwSize);
259 if (FAILED(hr))
260 return hr;
261 break;
262
263 case DMUS_FOURCC_CATEGORY_CHUNK:
264 TRACE_(dmfile)(": category chunk\n");
265 desc->dwValidData |= DMUS_OBJ_CATEGORY;
266 hr = read_from_stream(stream, desc->wszCategory, chunk.dwSize);
267 if (FAILED(hr))
268 return hr;
269 break;
270
271 case FOURCC_LIST:
272 hr = read_from_stream(stream, &chunk.fccID, sizeof(FOURCC));
273 if (FAILED(hr))
274 return hr;
275 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID));
276 ListSize[0] = chunk.dwSize - sizeof(FOURCC);
277 ListCount[0] = 0;
278 switch (chunk.fccID) {
279 /* pure INFO list, such can be found in dls collections */
280 case DMUS_FOURCC_INFO_LIST:
281 TRACE_(dmfile)(": INFO list\n");
282 do {
283 hr = read_from_stream(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD));
284 if (FAILED(hr))
285 return hr;
286 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
287 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
288 switch (chunk.fccID) {
289 case mmioFOURCC('I','N','A','M'): {
290 CHAR szName[DMUS_MAX_NAME];
291 TRACE_(dmfile)(": name chunk\n");
292 desc->dwValidData |= DMUS_OBJ_NAME;
293 hr = read_from_stream(stream, szName, chunk.dwSize);
294 if (FAILED(hr))
295 return hr;
296 MultiByteToWideChar (CP_ACP, 0, szName, -1, desc->wszName, DMUS_MAX_NAME);
297 if (even_or_odd(chunk.dwSize)) {
298 ListCount[0]++;
299 liMove.QuadPart = 1;
300 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
301 }
302 break;
303 }
304
305 case mmioFOURCC('I','A','R','T'):
306 TRACE_(dmfile)(": artist chunk (ignored)\n");
307 if (even_or_odd(chunk.dwSize)) {
308 ListCount[0]++;
309 chunk.dwSize++;
310 }
311 liMove.QuadPart = chunk.dwSize;
312 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
313 break;
314
315 case mmioFOURCC('I','C','O','P'):
316 TRACE_(dmfile)(": copyright chunk (ignored)\n");
317 if (even_or_odd(chunk.dwSize)) {
318 ListCount[0]++;
319 chunk.dwSize++;
320 }
321 liMove.QuadPart = chunk.dwSize;
322 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
323 break;
324
325 case mmioFOURCC('I','S','B','J'):
326 TRACE_(dmfile)(": subject chunk (ignored)\n");
327 if (even_or_odd(chunk.dwSize)) {
328 ListCount[0]++;
329 chunk.dwSize++;
330 }
331 liMove.QuadPart = chunk.dwSize;
332 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
333 break;
334
335 case mmioFOURCC('I','C','M','T'):
336 TRACE_(dmfile)(": comment chunk (ignored)\n");
337 if (even_or_odd(chunk.dwSize)) {
338 ListCount[0]++;
339 chunk.dwSize++;
340 liMove.QuadPart = chunk.dwSize;
341 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
342 break;
343 }
344
345 default:
346 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
347 if (even_or_odd(chunk.dwSize)) {
348 ListCount[0] ++;
349 chunk.dwSize++;
350 }
351 liMove.QuadPart = chunk.dwSize;
352 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
353 break;
354 }
355 TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
356 } while (ListCount[0] < ListSize[0]);
357 break;
358
359 default:
360 TRACE_(dmfile)(": unknown (skipping)\n");
361 liMove.QuadPart = chunk.dwSize - sizeof(FOURCC);
362 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
363 break;
364 }
365 break;
366
367 default:
368 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
369 liMove.QuadPart = chunk.dwSize;
370 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
371 break;
372 }
373 TRACE_(dmfile)(": StreamCount[0] = %d < StreamSize[0] = %d\n", StreamCount, StreamSize);
374 } while (StreamCount < StreamSize);
375
376 TRACE_(dmfile)(": reading finished\n");
377
378 if (TRACE_ON(dmusic)) {
379 TRACE("Returning descriptor:\n");
380 dump_DMUS_OBJECTDESC(desc);
381 }
382
383 return S_OK;
384 }
385
386 static const IDirectMusicObjectVtbl dmobject_vtbl = {
387 dmobj_IDirectMusicObject_QueryInterface,
388 dmobj_IDirectMusicObject_AddRef,
389 dmobj_IDirectMusicObject_Release,
390 dmobj_IDirectMusicObject_GetDescriptor,
391 dmobj_IDirectMusicObject_SetDescriptor,
392 IDirectMusicObjectImpl_ParseDescriptor
393 };
394
395 /* IDirectMusicCollectionImpl IPersistStream part: */
396 static HRESULT WINAPI IPersistStreamImpl_Load(IPersistStream *iface,
397 IStream *stream)
398 {
399 IDirectMusicCollectionImpl *This = impl_from_IPersistStream(iface);
400 DMUS_PRIVATE_CHUNK chunk;
401 DWORD StreamSize, StreamCount, ListSize[2], ListCount[2];
402 LARGE_INTEGER liMove; /* used when skipping chunks */
403 ULARGE_INTEGER dlibCollectionPosition, dlibInstrumentPosition, dlibWavePoolPosition;
404
405 IStream_AddRef(stream); /* add count for later references */
406 liMove.QuadPart = 0;
407 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dlibCollectionPosition); /* store offset, in case it'll be needed later */
408 This->liCollectionPosition.QuadPart = dlibCollectionPosition.QuadPart;
409 This->pStm = stream;
410
411 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
412 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
413
414 if (chunk.fccID != FOURCC_RIFF) {
415 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
416 liMove.QuadPart = chunk.dwSize;
417 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
418 return E_FAIL;
419 }
420
421 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL);
422 TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(chunk.fccID));
423 StreamSize = chunk.dwSize - sizeof(FOURCC);
424 StreamCount = 0;
425
426 if (chunk.fccID != FOURCC_DLS) {
427 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
428 liMove.QuadPart = StreamSize;
429 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
430 return E_FAIL;
431 }
432
433 TRACE_(dmfile)(": collection form\n");
434 do {
435 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
436 StreamCount += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
437 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
438 switch (chunk.fccID) {
439 case FOURCC_COLH: {
440 TRACE_(dmfile)(": collection header chunk\n");
441 This->pHeader = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, chunk.dwSize);
442 IStream_Read(stream, This->pHeader, chunk.dwSize, NULL);
443 break;
444 }
445 case FOURCC_DLID: {
446 TRACE_(dmfile)(": DLID (GUID) chunk\n");
447 This->dmobj.desc.dwValidData |= DMUS_OBJ_OBJECT;
448 IStream_Read(stream, &This->dmobj.desc.guidObject, chunk.dwSize, NULL);
449 break;
450 }
451 case FOURCC_VERS: {
452 TRACE_(dmfile)(": version chunk\n");
453 This->dmobj.desc.dwValidData |= DMUS_OBJ_VERSION;
454 IStream_Read(stream, &This->dmobj.desc.vVersion, chunk.dwSize, NULL);
455 break;
456 }
457 case FOURCC_PTBL: {
458 TRACE_(dmfile)(": pool table chunk\n");
459 This->pPoolTable = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(POOLTABLE));
460 IStream_Read(stream, This->pPoolTable, sizeof(POOLTABLE), NULL);
461 chunk.dwSize -= sizeof(POOLTABLE);
462 This->pPoolCues = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pPoolTable->cCues * sizeof(POOLCUE));
463 IStream_Read(stream, This->pPoolCues, chunk.dwSize, NULL);
464 break;
465 }
466 case FOURCC_LIST: {
467 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL);
468 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID));
469 ListSize[0] = chunk.dwSize - sizeof(FOURCC);
470 ListCount[0] = 0;
471 switch (chunk.fccID) {
472 case DMUS_FOURCC_INFO_LIST: {
473 TRACE_(dmfile)(": INFO list\n");
474 do {
475 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
476 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
477 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
478 switch (chunk.fccID) {
479 case mmioFOURCC('I','N','A','M'): {
480 CHAR szName[DMUS_MAX_NAME];
481 TRACE_(dmfile)(": name chunk\n");
482 This->dmobj.desc.dwValidData |= DMUS_OBJ_NAME;
483 IStream_Read(stream, szName, chunk.dwSize, NULL);
484 MultiByteToWideChar(CP_ACP, 0, szName, -1, This->dmobj.desc.wszName, DMUS_MAX_NAME);
485 if (even_or_odd(chunk.dwSize)) {
486 ListCount[0]++;
487 liMove.QuadPart = 1;
488 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
489 }
490 break;
491 }
492 case mmioFOURCC('I','A','R','T'): {
493 TRACE_(dmfile)(": artist chunk (ignored)\n");
494 if (even_or_odd(chunk.dwSize)) {
495 ListCount[0]++;
496 chunk.dwSize++;
497 }
498 liMove.QuadPart = chunk.dwSize;
499 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
500 break;
501 }
502 case mmioFOURCC('I','C','O','P'): {
503 TRACE_(dmfile)(": copyright chunk\n");
504 This->szCopyright = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, chunk.dwSize);
505 IStream_Read(stream, This->szCopyright, chunk.dwSize, NULL);
506 if (even_or_odd(chunk.dwSize)) {
507 ListCount[0]++;
508 liMove.QuadPart = 1;
509 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
510 }
511 break;
512 }
513 case mmioFOURCC('I','S','B','J'): {
514 TRACE_(dmfile)(": subject chunk (ignored)\n");
515 if (even_or_odd(chunk.dwSize)) {
516 ListCount[0]++;
517 chunk.dwSize++;
518 }
519 liMove.QuadPart = chunk.dwSize;
520 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
521 break;
522 }
523 case mmioFOURCC('I','C','M','T'): {
524 TRACE_(dmfile)(": comment chunk (ignored)\n");
525 if (even_or_odd(chunk.dwSize)) {
526 ListCount[0]++;
527 chunk.dwSize++;
528 }
529 liMove.QuadPart = chunk.dwSize;
530 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
531 break;
532 }
533 default: {
534 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
535 if (even_or_odd(chunk.dwSize)) {
536 ListCount[0]++;
537 chunk.dwSize++;
538 }
539 liMove.QuadPart = chunk.dwSize;
540 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
541 break;
542 }
543 }
544 TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
545 } while (ListCount[0] < ListSize[0]);
546 break;
547 }
548 case FOURCC_WVPL: {
549 TRACE_(dmfile)(": wave pool list (mark & skip)\n");
550 liMove.QuadPart = 0;
551 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dlibWavePoolPosition); /* store position */
552 This->liWavePoolTablePosition.QuadPart = dlibWavePoolPosition.QuadPart;
553 liMove.QuadPart = chunk.dwSize - sizeof(FOURCC);
554 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
555 break;
556 }
557 case FOURCC_LINS: {
558 TRACE_(dmfile)(": instruments list\n");
559 do {
560 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
561 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
562 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
563 switch (chunk.fccID) {
564 case FOURCC_LIST: {
565 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL);
566 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID));
567 ListSize[1] = chunk.dwSize - sizeof(FOURCC);
568 ListCount[1] = 0;
569 switch (chunk.fccID) {
570 case FOURCC_INS: {
571 LPDMUS_PRIVATE_INSTRUMENTENTRY new_instrument = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_INSTRUMENTENTRY));
572 TRACE_(dmfile)(": instrument list\n");
573 /* Only way to create this one... even M$ does it discretely */
574 DMUSIC_CreateDirectMusicInstrumentImpl(&IID_IDirectMusicInstrument, (void**)&new_instrument->pInstrument, NULL);
575 {
576 IDirectMusicInstrumentImpl *instrument = impl_from_IDirectMusicInstrument(new_instrument->pInstrument);
577 /* Store offset and length, they will be needed when loading the instrument */
578 liMove.QuadPart = 0;
579 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dlibInstrumentPosition);
580 instrument->liInstrumentPosition.QuadPart = dlibInstrumentPosition.QuadPart;
581 instrument->length = ListSize[1];
582 do {
583 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
584 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
585 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
586 switch (chunk.fccID) {
587 case FOURCC_INSH: {
588 TRACE_(dmfile)(": instrument header chunk\n");
589 IStream_Read(stream, &instrument->header, chunk.dwSize, NULL);
590 break;
591 }
592 case FOURCC_DLID: {
593 TRACE_(dmfile)(": DLID (GUID) chunk\n");
594 IStream_Read(stream, &instrument->id, chunk.dwSize, NULL);
595 break;
596 }
597 case FOURCC_LIST: {
598 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL);
599 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID));
600 switch (chunk.fccID) {
601 default: {
602 TRACE_(dmfile)(": unknown (skipping)\n");
603 liMove.QuadPart = chunk.dwSize - sizeof(FOURCC);
604 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
605 break;
606 }
607 }
608 break;
609 }
610 default: {
611 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
612 liMove.QuadPart = chunk.dwSize;
613 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
614 break;
615 }
616 }
617 TRACE_(dmfile)(": ListCount[1] = %d < ListSize[1] = %d\n", ListCount[1], ListSize[1]);
618 } while (ListCount[1] < ListSize[1]);
619 /* DEBUG: dumps whole instrument object tree: */
620 if (TRACE_ON(dmusic)) {
621 TRACE("*** IDirectMusicInstrument (%p) ***\n", instrument);
622 if (!IsEqualGUID(&instrument->id, &GUID_NULL))
623 TRACE(" - GUID = %s\n", debugstr_dmguid(&instrument->id));
624 TRACE(" - Instrument header:\n");
625 TRACE(" - cRegions: %d\n", instrument->header.cRegions);
626 TRACE(" - Locale:\n");
627 TRACE(" - ulBank: %d\n", instrument->header.Locale.ulBank);
628 TRACE(" - ulInstrument: %d\n", instrument->header.Locale.ulInstrument);
629 TRACE(" => dwPatch: %d\n", MIDILOCALE2Patch(&instrument->header.Locale));
630 }
631 list_add_tail(&This->Instruments, &new_instrument->entry);
632 }
633 break;
634 }
635 }
636 break;
637 }
638 default: {
639 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
640 liMove.QuadPart = chunk.dwSize;
641 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
642 break;
643 }
644 }
645 TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
646 } while (ListCount[0] < ListSize[0]);
647 break;
648 }
649 default: {
650 TRACE_(dmfile)(": unknown (skipping)\n");
651 liMove.QuadPart = chunk.dwSize - sizeof(FOURCC);
652 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
653 break;
654 }
655 }
656 break;
657 }
658 default: {
659 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
660 liMove.QuadPart = chunk.dwSize;
661 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
662 break;
663 }
664 }
665 TRACE_(dmfile)(": StreamCount = %d < StreamSize = %d\n", StreamCount, StreamSize);
666 } while (StreamCount < StreamSize);
667
668 TRACE_(dmfile)(": reading finished\n");
669
670
671 /* DEBUG: dumps whole collection object tree: */
672 if (TRACE_ON(dmusic)) {
673 int r = 0;
674 DMUS_PRIVATE_INSTRUMENTENTRY *tmpEntry;
675 struct list *listEntry;
676
677 TRACE("*** IDirectMusicCollection (%p) ***\n", &This->IDirectMusicCollection_iface);
678 if (This->dmobj.desc.dwValidData & DMUS_OBJ_OBJECT)
679 TRACE(" - GUID = %s\n", debugstr_dmguid(&This->dmobj.desc.guidObject));
680 if (This->dmobj.desc.dwValidData & DMUS_OBJ_VERSION)
681 TRACE(" - Version = %i,%i,%i,%i\n", (This->dmobj.desc.vVersion.dwVersionMS >> 8) & 0x0000FFFF, This->dmobj.desc.vVersion.dwVersionMS & 0x0000FFFF,
682 (This->dmobj.desc.vVersion.dwVersionLS >> 8) & 0x0000FFFF, This->dmobj.desc.vVersion.dwVersionLS & 0x0000FFFF);
683 if (This->dmobj.desc.dwValidData & DMUS_OBJ_NAME)
684 TRACE(" - Name = %s\n", debugstr_w(This->dmobj.desc.wszName));
685
686 TRACE(" - Collection header:\n");
687 TRACE(" - cInstruments: %d\n", This->pHeader->cInstruments);
688 TRACE(" - Instruments:\n");
689
690 LIST_FOR_EACH(listEntry, &This->Instruments) {
691 tmpEntry = LIST_ENTRY( listEntry, DMUS_PRIVATE_INSTRUMENTENTRY, entry );
692 TRACE(" - Instrument[%i]: %p\n", r, tmpEntry->pInstrument);
693 r++;
694 }
695 }
696
697 return S_OK;
698 }
699
700 static const IPersistStreamVtbl persiststream_vtbl = {
701 dmobj_IPersistStream_QueryInterface,
702 dmobj_IPersistStream_AddRef,
703 dmobj_IPersistStream_Release,
704 unimpl_IPersistStream_GetClassID,
705 unimpl_IPersistStream_IsDirty,
706 IPersistStreamImpl_Load,
707 unimpl_IPersistStream_Save,
708 unimpl_IPersistStream_GetSizeMax
709 };
710
711
712 HRESULT WINAPI DMUSIC_CreateDirectMusicCollectionImpl(LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter)
713 {
714 IDirectMusicCollectionImpl* obj;
715 HRESULT hr;
716
717 *ppobj = NULL;
718 if (pUnkOuter)
719 return CLASS_E_NOAGGREGATION;
720
721 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicCollectionImpl));
722 if (!obj)
723 return E_OUTOFMEMORY;
724
725 obj->IDirectMusicCollection_iface.lpVtbl = &DirectMusicCollection_Collection_Vtbl;
726 obj->ref = 1;
727 dmobject_init(&obj->dmobj, &CLSID_DirectMusicCollection,
728 (IUnknown*)&obj->IDirectMusicCollection_iface);
729 obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl;
730 obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl;
731
732 list_init (&obj->Instruments);
733
734 DMUSIC_LockModule();
735 hr = IDirectMusicCollection_QueryInterface(&obj->IDirectMusicCollection_iface, lpcGUID, ppobj);
736 IDirectMusicCollection_Release(&obj->IDirectMusicCollection_iface);
737
738 return hr;
739 }