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