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