d3drm: Display new ref in trace for AddRef and Release for IDirect3DRMMesh.
[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 refCount = InterlockedIncrement(&This->ref);
82
83         TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
84
85         DMUSIC_LockModule();
86
87         return refCount;
88 }
89
90 static ULONG WINAPI IDirectMusicCollectionImpl_IDirectMusicCollection_Release(LPDIRECTMUSICCOLLECTION iface)
91 {
92         IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
93         ULONG refCount = InterlockedDecrement(&This->ref);
94
95         TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
96
97         if (!refCount) {
98                 HeapFree(GetProcessHeap(), 0, This);
99         }
100
101         DMUSIC_UnlockModule();
102
103         return refCount;
104 }
105
106 /* IDirectMusicCollection Interface follows: */
107 static HRESULT WINAPI IDirectMusicCollectionImpl_IDirectMusicCollection_GetInstrument(LPDIRECTMUSICCOLLECTION iface, DWORD dwPatch, IDirectMusicInstrument** ppInstrument)
108 {
109         IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
110         DMUS_PRIVATE_INSTRUMENTENTRY *tmpEntry;
111         struct list *listEntry;
112         DWORD dwInstPatch;
113
114         TRACE("(%p, %d, %p)\n", This, dwPatch, ppInstrument);
115         
116         LIST_FOR_EACH (listEntry, &This->Instruments) {
117                 tmpEntry = LIST_ENTRY(listEntry, DMUS_PRIVATE_INSTRUMENTENTRY, entry);
118                 IDirectMusicInstrument_GetPatch (tmpEntry->pInstrument, &dwInstPatch);
119                 if (dwPatch == dwInstPatch) {
120                         *ppInstrument = tmpEntry->pInstrument;
121                         IDirectMusicInstrument_AddRef (tmpEntry->pInstrument);
122                         IDirectMusicInstrumentImpl_Custom_Load (tmpEntry->pInstrument, This->pStm); /* load instrument before returning it */
123                         TRACE(": returning instrument %p\n", *ppInstrument);
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 dwIndex, DWORD* pdwPatch, LPWSTR pwszName, DWORD dwNameLen)
134 {
135         IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
136         unsigned int r = 0;
137         DMUS_PRIVATE_INSTRUMENTENTRY *tmpEntry;
138         struct list *listEntry;
139        DWORD dwLen;
140                 
141         TRACE("(%p, %d, %p, %p, %d)\n", This, dwIndex, pdwPatch, pwszName, dwNameLen);
142         LIST_FOR_EACH (listEntry, &This->Instruments) {
143                 tmpEntry = LIST_ENTRY(listEntry, DMUS_PRIVATE_INSTRUMENTENTRY, entry);
144                 if (r == dwIndex) {
145                         IDirectMusicInstrumentImpl *pInstrument = impl_from_IDirectMusicInstrument(tmpEntry->pInstrument);
146                         IDirectMusicInstrument_GetPatch (tmpEntry->pInstrument, pdwPatch);
147                        if (pwszName) {
148                                dwLen = min(strlenW(pInstrument->wszName),dwNameLen-1);
149                                memcpy (pwszName, pInstrument->wszName, dwLen * sizeof(WCHAR));
150                                pwszName[dwLen] = '\0';
151                        }
152                         return S_OK;
153                 }
154                 r++;            
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* pStm)
489 {
490         IDirectMusicCollectionImpl *This = impl_from_IPersistStream(iface);
491         DMUS_PRIVATE_CHUNK Chunk;
492         DWORD StreamSize, StreamCount, ListSize[3], ListCount[3];
493         LARGE_INTEGER liMove; /* used when skipping chunks */
494         ULARGE_INTEGER dlibCollectionPosition, dlibInstrumentPosition, dlibWavePoolPosition;
495         
496         IStream_AddRef (pStm); /* add count for later references */
497         liMove.QuadPart = 0;
498         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, &dlibCollectionPosition); /* store offset, in case it'll be needed later */
499         This->liCollectionPosition.QuadPart = dlibCollectionPosition.QuadPart;
500         This->pStm = pStm;
501         
502         IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
503         TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
504         switch (Chunk.fccID) {  
505                 case FOURCC_RIFF: {
506                         IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);                                
507                         TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(Chunk.fccID));
508                         StreamSize = Chunk.dwSize - sizeof(FOURCC);
509                         StreamCount = 0;
510                         switch (Chunk.fccID) {
511                                 case FOURCC_DLS: {
512                                         TRACE_(dmfile)(": collection form\n");
513                                         do {
514                                                 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
515                                                 StreamCount += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
516                                                 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
517                                                 switch (Chunk.fccID) {
518                                                         case FOURCC_COLH: {
519                                                                 TRACE_(dmfile)(": collection header chunk\n");
520                                                                 This->pHeader = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize);
521                                                                 IStream_Read (pStm, This->pHeader, Chunk.dwSize, NULL);
522                                                                 break;                                                          
523                                                         }
524                                                         case FOURCC_DLID: {
525                                                                 TRACE_(dmfile)(": DLID (GUID) chunk\n");
526                                                                 This->pDesc->dwValidData |= DMUS_OBJ_OBJECT;
527                                                                 IStream_Read (pStm, &This->pDesc->guidObject, Chunk.dwSize, NULL);
528                                                                 break;
529                                                         }
530                                                         case FOURCC_VERS: {
531                                                                 TRACE_(dmfile)(": version chunk\n");
532                                                                 This->pDesc->dwValidData |= DMUS_OBJ_VERSION;
533                                                                 IStream_Read (pStm, &This->pDesc->vVersion, Chunk.dwSize, NULL);
534                                                                 break;
535                                                         }
536                                                         case FOURCC_PTBL: {
537                                                                 TRACE_(dmfile)(": pool table chunk\n");
538                                                                 This->pPoolTable = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(POOLTABLE));
539                                                                 IStream_Read (pStm, This->pPoolTable, sizeof(POOLTABLE), NULL);
540                                                                 Chunk.dwSize -= sizeof(POOLTABLE);
541                                                                 This->pPoolCues = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, This->pPoolTable->cCues*sizeof(POOLCUE));
542                                                                 IStream_Read (pStm, This->pPoolCues, Chunk.dwSize, NULL);
543                                                                 break;
544                                                         }
545                                                         case FOURCC_LIST: {
546                                                                 IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);                                
547                                                                 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
548                                                                 ListSize[0] = Chunk.dwSize - sizeof(FOURCC);
549                                                                 ListCount[0] = 0;
550                                                                 switch (Chunk.fccID) {
551                                                                         case mmioFOURCC('I','N','F','O'): {
552                                                                                 TRACE_(dmfile)(": INFO list\n");
553                                                                                 do {
554                                                                                         IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
555                                                                                         ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
556                                                                                         TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
557                                                                                         switch (Chunk.fccID) {
558                                                                                                 case mmioFOURCC('I','N','A','M'): {
559                                                                                                         CHAR szName[DMUS_MAX_NAME];
560                                                                                                         TRACE_(dmfile)(": name chunk\n");
561                                                                                                         This->pDesc->dwValidData |= DMUS_OBJ_NAME;
562                                                                                                         IStream_Read (pStm, szName, Chunk.dwSize, NULL);
563                                                                                                         MultiByteToWideChar (CP_ACP, 0, szName, -1, This->pDesc->wszName, DMUS_MAX_NAME);
564                                                                                                         if (even_or_odd(Chunk.dwSize)) {
565                                                                                                                 ListCount[0] ++;
566                                                                                                                 liMove.QuadPart = 1;
567                                                                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
568                                                                                                         }
569                                                                                                         break;
570                                                                                                 }
571                                                                                                 case mmioFOURCC('I','A','R','T'): {
572                                                                                                         TRACE_(dmfile)(": artist chunk (ignored)\n");
573                                                                                                         if (even_or_odd(Chunk.dwSize)) {
574                                                                                                                 ListCount[0] ++;
575                                                                                                                 Chunk.dwSize++;
576                                                                                                         }
577                                                                                                         liMove.QuadPart = Chunk.dwSize;
578                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
579                                                                                                         break;
580                                                                                                 }
581                                                                                                 case mmioFOURCC('I','C','O','P'): {
582                                                                                                         TRACE_(dmfile)(": copyright chunk\n");
583                                                                                                         This->szCopyright = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize);
584                                                                                                         IStream_Read (pStm, This->szCopyright, Chunk.dwSize, NULL);
585                                                                                                         if (even_or_odd(Chunk.dwSize)) {
586                                                                                                                 ListCount[0] ++;
587                                                                                                                 liMove.QuadPart = 1;
588                                                                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
589                                                                                                         }
590                                                                                                         break;
591                                                                                                 }
592                                                                                                 case mmioFOURCC('I','S','B','J'): {
593                                                                                                         TRACE_(dmfile)(": subject chunk (ignored)\n");
594                                                                                                         if (even_or_odd(Chunk.dwSize)) {
595                                                                                                                 ListCount[0] ++;
596                                                                                                                 Chunk.dwSize++;
597                                                                                                         }
598                                                                                                         liMove.QuadPart = Chunk.dwSize;
599                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
600                                                                                                         break;
601                                                                                                 }
602                                                                                                 case mmioFOURCC('I','C','M','T'): {
603                                                                                                         TRACE_(dmfile)(": comment chunk (ignored)\n");
604                                                                                                         if (even_or_odd(Chunk.dwSize)) {
605                                                                                                                 ListCount[0] ++;
606                                                                                                                 Chunk.dwSize++;
607                                                                                                         }
608                                                                                                         liMove.QuadPart = Chunk.dwSize;
609                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
610                                                                                                         break;
611                                                                                                 }
612                                                                                                 default: {
613                                                                                                         TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
614                                                                                                         if (even_or_odd(Chunk.dwSize)) {
615                                                                                                                 ListCount[0] ++;
616                                                                                                                 Chunk.dwSize++;
617                                                                                                         }
618                                                                                                         liMove.QuadPart = Chunk.dwSize;
619                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
620                                                                                                         break;                                          
621                                                                                                 }
622                                                                                         }
623                                                                                         TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
624                                                                                 } while (ListCount[0] < ListSize[0]);
625                                                                                 break;
626                                                                         }
627                                                                         case FOURCC_WVPL: {
628                                                                                 TRACE_(dmfile)(": wave pool list (mark & skip)\n");
629                                                                                 liMove.QuadPart = 0;
630                                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, &dlibWavePoolPosition); /* store position */
631                                                                                 This->liWavePoolTablePosition.QuadPart = dlibWavePoolPosition.QuadPart;
632                                                                                 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
633                                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
634                                                                                 break;  
635                                                                         }
636                                                                         case FOURCC_LINS: {
637                                                                                 TRACE_(dmfile)(": instruments list\n");
638                                                                                 do {
639                                                                                         IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
640                                                                                         ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
641                                                                                         TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
642                                                                                         switch (Chunk.fccID) {
643                                                                                                 case FOURCC_LIST: {
644                                                                                                         IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);                                
645                                                                                                         TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
646                                                                                                         ListSize[1] = Chunk.dwSize - sizeof(FOURCC);
647                                                                                                         ListCount[1] = 0;                                                                                                       
648                                                                                                         switch (Chunk.fccID) {
649                                                                                                                 case FOURCC_INS: {
650                                                                                                                         LPDMUS_PRIVATE_INSTRUMENTENTRY pNewInstrument = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_INSTRUMENTENTRY));
651                                                                                                                         TRACE_(dmfile)(": instrument list\n");
652                                                                                                                         DMUSIC_CreateDirectMusicInstrumentImpl (&IID_IDirectMusicInstrument, (LPVOID*)&pNewInstrument->pInstrument, NULL); /* only way to create this one... even M$ does it discretely */
653                                                                                                                         {
654                                                                                                                             IDirectMusicInstrumentImpl *pInstrument = impl_from_IDirectMusicInstrument(pNewInstrument->pInstrument);
655                                                                                                                             liMove.QuadPart = 0;
656                                                                                                                             IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, &dlibInstrumentPosition);
657                                                                                                                             pInstrument->liInstrumentPosition.QuadPart = dlibInstrumentPosition.QuadPart - (2*sizeof(FOURCC) + sizeof(DWORD)); /* store offset, it'll be needed later */
658
659                                                                                                                             do {
660                                                                                                                                 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
661                                                                                                                                 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
662                                                                                                                                 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
663                                                                                                                                 switch (Chunk.fccID) {
664                                                                                                                                         case FOURCC_INSH: {
665                                                                                                                                                 TRACE_(dmfile)(": instrument header chunk\n");
666                                                                                                                                                 pInstrument->pHeader = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize);
667                                                                                                                                                 IStream_Read (pStm, pInstrument->pHeader, Chunk.dwSize, NULL);
668                                                                                                                                                 break;  
669                                                                                                                                         }
670                                                                                                                                         case FOURCC_DLID: {
671                                                                                                                                                 TRACE_(dmfile)(": DLID (GUID) chunk\n");
672                                                                                                                                                 pInstrument->pInstrumentID = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize);
673                                                                                                                                                 IStream_Read (pStm, pInstrument->pInstrumentID, Chunk.dwSize, NULL);
674                                                                                                                                                 break;
675                                                                                                                                         }
676                                                                                                                                         case FOURCC_LIST: {
677                                                                                                                                                 IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);                                
678                                                                                                                                                 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
679                                                                                                                                                 ListSize[2] = Chunk.dwSize - sizeof(FOURCC);
680                                                                                                                                                 ListCount[2] = 0;
681                                                                                                                                                 switch (Chunk.fccID) {
682                                                                                                                                                         default: {
683                                                                                                                                                                 TRACE_(dmfile)(": unknown (skipping)\n");
684                                                                                                                                                                 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
685                                                                                                                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
686                                                                                                                                                                 break;                                          
687                                                                                                                                                         }
688                                                                                                                                                 }
689                                                                                                                                                 break;
690                                                                                                                                         }                               
691                                                                                                                                         default: {
692                                                                                                                                                 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
693                                                                                                                                                 liMove.QuadPart = Chunk.dwSize;
694                                                                                                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
695                                                                                                                                                 break;                                          
696                                                                                                                                         }
697                                                                                                                                 }
698                                                                                                                                 TRACE_(dmfile)(": ListCount[1] = %d < ListSize[1] = %d\n", ListCount[1], ListSize[1]);
699                                                                                                                             } while (ListCount[1] < ListSize[1]);
700                                                                                                                             /* DEBUG: dumps whole instrument object tree: */
701                                                                                                                             if (TRACE_ON(dmusic)) {
702                                                                                                                                 TRACE("*** IDirectMusicInstrument (%p) ***\n", pInstrument);
703                                                                                                                                 if (pInstrument->pInstrumentID)
704                                                                                                                                         TRACE(" - GUID = %s\n", debugstr_dmguid(pInstrument->pInstrumentID));
705                                                                                                                                 
706                                                                                                                                 TRACE(" - Instrument header:\n");
707                                                                                                                                 TRACE("    - cRegions: %d\n", pInstrument->pHeader->cRegions);
708                                                                                                                                 TRACE("    - Locale:\n");
709                                                                                                                                 TRACE("       - ulBank: %d\n", pInstrument->pHeader->Locale.ulBank);
710                                                                                                                                 TRACE("       - ulInstrument: %d\n", pInstrument->pHeader->Locale.ulInstrument);
711                                                                                                                                 TRACE("       => dwPatch: %d\n", MIDILOCALE2Patch(&pInstrument->pHeader->Locale));
712                                                                                                                             }
713                                                                                                                             list_add_tail (&This->Instruments, &pNewInstrument->entry);
714                                                                                                                         }
715                                                                                                                         break;
716                                                                                                                 }
717                                                                                                         }
718                                                                                                         break;
719                                                                                                 }
720                                                                                                 default: {
721                                                                                                         TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
722                                                                                                         liMove.QuadPart = Chunk.dwSize;
723                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
724                                                                                                         break;                                          
725                                                                                                 }
726                                                                                         }
727                                                                                         TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
728                                                                                 } while (ListCount[0] < ListSize[0]);
729                                                                                 break;
730                                                                         }
731                                                                         default: {
732                                                                                 TRACE_(dmfile)(": unknown (skipping)\n");
733                                                                                 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
734                                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
735                                                                                 break;                                          
736                                                                         }
737                                                                 }
738                                                                 break;
739                                                         }       
740                                                         default: {
741                                                                 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
742                                                                 liMove.QuadPart = Chunk.dwSize;
743                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
744                                                                 break;                                          
745                                                         }
746                                                 }
747                                                 TRACE_(dmfile)(": StreamCount = %d < StreamSize = %d\n", StreamCount, StreamSize);
748                                         } while (StreamCount < StreamSize);
749                                         break;
750                                 }
751                                 default: {
752                                         TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
753                                         liMove.QuadPart = StreamSize;
754                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
755                                         return E_FAIL;
756                                 }
757                         }
758                         TRACE_(dmfile)(": reading finished\n");
759                         break;
760                 }
761                 default: {
762                         TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
763                         liMove.QuadPart = Chunk.dwSize;
764                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
765                         return E_FAIL;
766                 }
767         }
768
769         /* DEBUG: dumps whole collection object tree: */
770         if (TRACE_ON(dmusic)) {
771                 int r = 0;
772                 DMUS_PRIVATE_INSTRUMENTENTRY *tmpEntry;
773                 struct list *listEntry;
774
775                 TRACE("*** IDirectMusicCollection (%p) ***\n", &This->IDirectMusicCollection_iface);
776                 if (This->pDesc->dwValidData & DMUS_OBJ_OBJECT)
777                         TRACE(" - GUID = %s\n", debugstr_dmguid(&This->pDesc->guidObject));
778                 if (This->pDesc->dwValidData & DMUS_OBJ_VERSION)
779                         TRACE(" - Version = %i,%i,%i,%i\n", (This->pDesc->vVersion.dwVersionMS >> 8) & 0x0000FFFF, This->pDesc->vVersion.dwVersionMS & 0x0000FFFF,
780                                 (This->pDesc->vVersion.dwVersionLS >> 8) & 0x0000FFFF, This->pDesc->vVersion.dwVersionLS & 0x0000FFFF);
781                 if (This->pDesc->dwValidData & DMUS_OBJ_NAME)
782                         TRACE(" - Name = %s\n", debugstr_w(This->pDesc->wszName));
783                 
784                 TRACE(" - Collection header:\n");
785                 TRACE("    - cInstruments: %d\n", This->pHeader->cInstruments);
786                 TRACE(" - Instruments:\n");
787                 
788                 LIST_FOR_EACH (listEntry, &This->Instruments) {
789                         tmpEntry = LIST_ENTRY( listEntry, DMUS_PRIVATE_INSTRUMENTENTRY, entry );
790                         TRACE("    - Instrument[%i]: %p\n", r, tmpEntry->pInstrument);
791                         r++;
792                 }
793         }
794         
795         return S_OK;
796 }
797
798 static HRESULT WINAPI IDirectMusicCollectionImpl_IPersistStream_Save(LPPERSISTSTREAM iface, IStream* pStm, BOOL fClearDirty)
799 {
800     return E_NOTIMPL;
801 }
802
803 static HRESULT WINAPI IDirectMusicCollectionImpl_IPersistStream_GetSizeMax(LPPERSISTSTREAM iface, ULARGE_INTEGER* pcbSize)
804 {
805     return E_NOTIMPL;
806 }
807
808 static const IPersistStreamVtbl DirectMusicCollection_PersistStream_Vtbl = {
809         IDirectMusicCollectionImpl_IPersistStream_QueryInterface,
810         IDirectMusicCollectionImpl_IPersistStream_AddRef,
811         IDirectMusicCollectionImpl_IPersistStream_Release,
812         IDirectMusicCollectionImpl_IPersistStream_GetClassID,
813         IDirectMusicCollectionImpl_IPersistStream_IsDirty,
814         IDirectMusicCollectionImpl_IPersistStream_Load,
815         IDirectMusicCollectionImpl_IPersistStream_Save,
816         IDirectMusicCollectionImpl_IPersistStream_GetSizeMax
817 };
818
819
820 /* for ClassFactory */
821 HRESULT WINAPI DMUSIC_CreateDirectMusicCollectionImpl(LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter)
822 {
823         IDirectMusicCollectionImpl* obj;
824         
825         obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicCollectionImpl));
826         if (NULL == obj) {
827                 *ppobj = NULL;
828                 return E_OUTOFMEMORY;
829         }
830         obj->IDirectMusicCollection_iface.lpVtbl = &DirectMusicCollection_Collection_Vtbl;
831         obj->IDirectMusicObject_iface.lpVtbl = &DirectMusicCollection_Object_Vtbl;
832         obj->IPersistStream_iface.lpVtbl = &DirectMusicCollection_PersistStream_Vtbl;
833         obj->pDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DMUS_OBJECTDESC));
834         DM_STRUCT_INIT(obj->pDesc);
835         obj->pDesc->dwValidData |= DMUS_OBJ_CLASS;
836         obj->pDesc->guidClass = CLSID_DirectMusicCollection;
837         obj->ref = 0; /* will be inited by QueryInterface */
838         list_init (&obj->Instruments);
839
840         return IDirectMusicCollection_QueryInterface(&obj->IDirectMusicCollection_iface, lpcGUID, ppobj);
841 }