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