msxml3: Implement get_xml.
[wine] / dlls / dmloader / container.c
1 /* IDirectMusicContainerImpl
2  *
3  * Copyright (C) 2003-2004 Rok Mandeljc
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #include "dmloader_private.h"
21
22 WINE_DEFAULT_DEBUG_CHANNEL(dmloader);
23 WINE_DECLARE_DEBUG_CHANNEL(dmfile);
24 WINE_DECLARE_DEBUG_CHANNEL(dmdump);
25
26 #define DMUS_MAX_CATEGORY_SIZE DMUS_MAX_CATEGORY*sizeof(WCHAR)
27 #define DMUS_MAX_NAME_SIZE     DMUS_MAX_NAME*sizeof(WCHAR)
28 #define DMUS_MAX_FILENAME_SIZE DMUS_MAX_FILENAME*sizeof(WCHAR)
29
30 static ULONG WINAPI IDirectMusicContainerImpl_IDirectMusicContainer_AddRef (LPDIRECTMUSICCONTAINER iface);
31 static ULONG WINAPI IDirectMusicContainerImpl_IDirectMusicObject_AddRef (LPDIRECTMUSICOBJECT iface);
32 static ULONG WINAPI IDirectMusicContainerImpl_IPersistStream_AddRef (LPPERSISTSTREAM iface);
33
34 /*****************************************************************************
35  * IDirectMusicContainerImpl implementation
36  */
37 /* IUnknown/IDirectMusicContainer part: */
38 static HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicContainer_QueryInterface (LPDIRECTMUSICCONTAINER iface, REFIID riid, LPVOID *ppobj) {
39         ICOM_THIS_MULTI(IDirectMusicContainerImpl, ContainerVtbl, iface);
40         
41         TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj);
42         if (IsEqualIID (riid, &IID_IUnknown) ||
43                 IsEqualIID (riid, &IID_IDirectMusicContainer)) {
44                 *ppobj = (LPVOID)&This->ContainerVtbl;
45                 IDirectMusicContainerImpl_IDirectMusicContainer_AddRef ((LPDIRECTMUSICCONTAINER)&This->ContainerVtbl);
46                 return S_OK;
47         } else if (IsEqualIID (riid, &IID_IDirectMusicObject)) {
48                 *ppobj = (LPVOID)&This->ObjectVtbl;
49                 IDirectMusicContainerImpl_IDirectMusicObject_AddRef ((LPDIRECTMUSICOBJECT)&This->ObjectVtbl);           
50                 return S_OK;
51         } else if (IsEqualIID (riid, &IID_IPersistStream)) {
52                 *ppobj = (LPVOID)&This->PersistStreamVtbl;
53                 IDirectMusicContainerImpl_IPersistStream_AddRef ((LPPERSISTSTREAM)&This->PersistStreamVtbl);            
54                 return S_OK;
55         }
56         
57         WARN(": not found\n");
58         return E_NOINTERFACE;
59 }
60
61 static ULONG WINAPI IDirectMusicContainerImpl_IDirectMusicContainer_AddRef (LPDIRECTMUSICCONTAINER iface) {
62         ICOM_THIS_MULTI(IDirectMusicContainerImpl, ContainerVtbl, iface);
63         TRACE("(%p): AddRef from %d\n", This, This->dwRef);
64         return InterlockedIncrement (&This->dwRef);
65 }
66
67 static ULONG WINAPI IDirectMusicContainerImpl_IDirectMusicContainer_Release (LPDIRECTMUSICCONTAINER iface) {
68         ICOM_THIS_MULTI(IDirectMusicContainerImpl, ContainerVtbl, iface);
69         
70         DWORD dwRef = InterlockedDecrement (&This->dwRef);
71         TRACE("(%p): ReleaseRef to %d\n", This, dwRef);
72         if (dwRef == 0) {
73                 DMUSIC_DestroyDirectMusicContainerImpl (iface);
74                 HeapFree(GetProcessHeap(), 0, This);
75         }
76         
77         return dwRef;
78 }
79
80 static HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicContainer_EnumObject (LPDIRECTMUSICCONTAINER iface, REFGUID rguidClass, DWORD dwIndex, LPDMUS_OBJECTDESC pDesc, WCHAR* pwszAlias) {
81         ICOM_THIS_MULTI(IDirectMusicContainerImpl, ContainerVtbl, iface);       
82         struct list *pEntry;
83         LPWINE_CONTAINER_ENTRY pContainedObject;
84         DWORD dwCount = 0;
85
86         TRACE("(%p, %s, %d, %p, %p)\n", This, debugstr_dmguid(rguidClass), dwIndex, pDesc, pwszAlias);
87
88         /* check if we can write to whole pDesc */
89         if (pDesc) {
90                 if (IsBadReadPtr (pDesc, sizeof(DWORD))) {
91                         ERR(": pDesc->dwSize bad read pointer\n");
92                         return E_POINTER;
93                 }
94                 if (pDesc->dwSize != sizeof(DMUS_OBJECTDESC)) {
95                         ERR(": invalid pDesc->dwSize\n");
96                         return E_INVALIDARG;
97                 }
98                 if (IsBadWritePtr (pDesc, sizeof(DMUS_OBJECTDESC))) {
99                         ERR(": pDesc bad write pointer\n");
100                         return E_POINTER;
101                 }
102         }
103         /* check if we wszAlias is big enough */
104         if (pwszAlias && IsBadWritePtr (pwszAlias, DMUS_MAX_FILENAME_SIZE)) {
105                 ERR(": wszAlias bad write pointer\n");
106                 return E_POINTER;               
107         }
108         
109         DM_STRUCT_INIT(pDesc);
110         
111         LIST_FOR_EACH (pEntry, This->pContainedObjects) {
112                 pContainedObject = LIST_ENTRY (pEntry, WINE_CONTAINER_ENTRY, entry);
113                 
114                 if (IsEqualGUID (rguidClass, &GUID_DirectMusicAllTypes) || IsEqualGUID (rguidClass, &pContainedObject->Desc.guidClass)) {
115                         if (dwCount == dwIndex) {
116                                 HRESULT result = S_OK;
117                                 if (pwszAlias) {
118                                         lstrcpynW (pwszAlias, pContainedObject->wszAlias, DMUS_MAX_FILENAME);
119                                         if (strlenW (pContainedObject->wszAlias) > DMUS_MAX_FILENAME)
120                                                 result = DMUS_S_STRING_TRUNCATED;
121                                 }
122                                 if (pDesc)
123                                         memcpy (pDesc, &pContainedObject->Desc, sizeof(DMUS_OBJECTDESC));
124                                 return result;
125                         }
126                         dwCount++;
127                 }
128         }               
129         
130         TRACE(": not found\n");
131         return S_FALSE;
132 }
133
134 static const IDirectMusicContainerVtbl DirectMusicContainer_Container_Vtbl = {
135         IDirectMusicContainerImpl_IDirectMusicContainer_QueryInterface,
136         IDirectMusicContainerImpl_IDirectMusicContainer_AddRef,
137         IDirectMusicContainerImpl_IDirectMusicContainer_Release,
138         IDirectMusicContainerImpl_IDirectMusicContainer_EnumObject
139 };
140
141 /* IDirectMusicObject part: */
142 static HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicObject_QueryInterface (LPDIRECTMUSICOBJECT iface, REFIID riid, LPVOID *ppobj) {
143         ICOM_THIS_MULTI(IDirectMusicContainerImpl, ObjectVtbl, iface);
144         return IDirectMusicContainerImpl_IDirectMusicContainer_QueryInterface ((LPDIRECTMUSICCONTAINER)&This->ContainerVtbl, riid, ppobj);
145 }
146
147 static ULONG WINAPI IDirectMusicContainerImpl_IDirectMusicObject_AddRef (LPDIRECTMUSICOBJECT iface) {
148         ICOM_THIS_MULTI(IDirectMusicContainerImpl, ObjectVtbl, iface);
149         return IDirectMusicContainerImpl_IDirectMusicContainer_AddRef ((LPDIRECTMUSICCONTAINER)&This->ContainerVtbl);
150 }
151
152 static ULONG WINAPI IDirectMusicContainerImpl_IDirectMusicObject_Release (LPDIRECTMUSICOBJECT iface) {
153         ICOM_THIS_MULTI(IDirectMusicContainerImpl, ObjectVtbl, iface);
154         return IDirectMusicContainerImpl_IDirectMusicContainer_Release ((LPDIRECTMUSICCONTAINER)&This->ContainerVtbl);
155 }
156
157 static HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicObject_GetDescriptor (LPDIRECTMUSICOBJECT iface, LPDMUS_OBJECTDESC pDesc) {
158         ICOM_THIS_MULTI(IDirectMusicContainerImpl, ObjectVtbl, iface);
159         TRACE("(%p, %p):\n", This, pDesc);
160         
161         /* check if whe can write to whole pDesc */
162         if (IsBadReadPtr (pDesc, sizeof(DWORD))) {
163                 ERR(": pDesc->dwSize bad read pointer\n");
164                 return E_POINTER;
165         }
166         if (pDesc->dwSize != sizeof(DMUS_OBJECTDESC)) {
167                 ERR(": invalid pDesc->dwSize\n");
168                 return E_INVALIDARG;
169         }
170         if (IsBadWritePtr (pDesc, sizeof(DMUS_OBJECTDESC))) {
171                 ERR(": pDesc bad write pointer\n");
172                 return E_POINTER;
173         }
174         
175         DM_STRUCT_INIT(pDesc);
176         memcpy (pDesc, &This->Desc, sizeof(DMUS_OBJECTDESC));
177         
178         return S_OK;
179 }
180
181 static HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicObject_SetDescriptor (LPDIRECTMUSICOBJECT iface, LPDMUS_OBJECTDESC pDesc) {
182         DWORD dwNewFlags = 0;
183         DWORD dwFlagDifference;
184         ICOM_THIS_MULTI(IDirectMusicContainerImpl, ObjectVtbl, iface);
185         TRACE("(%p, %p):\n", This, pDesc);
186
187         /* check if whe can read whole pDesc */
188         if (IsBadReadPtr (pDesc, sizeof(DWORD))) {
189                 ERR(": pDesc->dwSize bad read pointer\n");
190                 return E_POINTER;
191         }
192         if (pDesc->dwSize != sizeof(DMUS_OBJECTDESC)) {
193                 ERR(": invalid pDesc->dwSize\n");
194                 return E_INVALIDARG;
195         }
196         if (IsBadReadPtr (pDesc, sizeof(DMUS_OBJECTDESC))) {
197                 ERR(": pDesc bad read pointer\n");
198                 return E_POINTER;
199         }
200
201         if (pDesc->dwValidData & DMUS_OBJ_OBJECT) {
202                 memcpy (&This->Desc.guidObject, &pDesc->guidObject, sizeof(GUID));
203                 dwNewFlags |= DMUS_OBJ_OBJECT;
204         }
205         if (pDesc->dwValidData & DMUS_OBJ_NAME) {
206                 lstrcpynW (This->Desc.wszName, pDesc->wszName, DMUS_MAX_NAME);
207                 dwNewFlags |= DMUS_OBJ_NAME;
208         }
209         if (pDesc->dwValidData & DMUS_OBJ_CATEGORY) {
210                 lstrcpynW (This->Desc.wszCategory, pDesc->wszCategory, DMUS_MAX_CATEGORY);
211                 dwNewFlags |= DMUS_OBJ_CATEGORY;
212         }
213         if (pDesc->dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) {
214                 lstrcpynW (This->Desc.wszFileName, pDesc->wszFileName, DMUS_MAX_FILENAME);
215                 dwNewFlags |= (pDesc->dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH));
216         }
217         if (pDesc->dwValidData & DMUS_OBJ_VERSION) {
218                 This->Desc.vVersion.dwVersionLS = pDesc->vVersion.dwVersionLS;
219                 This->Desc.vVersion.dwVersionMS = pDesc->vVersion.dwVersionMS;
220                 dwNewFlags |= DMUS_OBJ_VERSION;
221         }
222         if (pDesc->dwValidData & DMUS_OBJ_DATE) {
223                 This->Desc.ftDate.dwHighDateTime = pDesc->ftDate.dwHighDateTime;
224                 This->Desc.ftDate.dwLowDateTime = pDesc->ftDate.dwLowDateTime;
225                 dwNewFlags |= DMUS_OBJ_DATE;
226         }
227         /* set new flags */
228         This->Desc.dwValidData |= dwNewFlags;
229         
230         dwFlagDifference = pDesc->dwValidData - dwNewFlags;
231         if (dwFlagDifference) {
232                 pDesc->dwValidData &= ~dwFlagDifference; /* and with bitwise complement */
233                 return S_FALSE;
234         } else return S_OK;
235 }
236
237 static HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicObject_ParseDescriptor (LPDIRECTMUSICOBJECT iface, LPSTREAM pStream, LPDMUS_OBJECTDESC pDesc) {
238         ICOM_THIS_MULTI(IDirectMusicContainerImpl, ObjectVtbl, iface);
239         WINE_CHUNK Chunk;
240         DWORD StreamSize, StreamCount, ListSize[1], ListCount[1];
241         LARGE_INTEGER liMove; /* used when skipping chunks */
242
243         TRACE("(%p, %p, %p)\n", This, pStream, pDesc);
244         
245         /* check whether arguments are OK */
246         if (IsBadReadPtr (pStream, sizeof(LPVOID))) {
247                 ERR(": pStream bad read pointer\n");
248                 return E_POINTER;
249         }
250         /* check whether pDesc is OK */
251         if (IsBadReadPtr (pDesc, sizeof(DWORD))) {
252                 ERR(": pDesc->dwSize bad read pointer\n");
253                 return E_POINTER;
254         }
255         if (pDesc->dwSize != sizeof(DMUS_OBJECTDESC)) {
256                 ERR(": invalid pDesc->dwSize\n");
257                 return E_INVALIDARG;
258         }
259         if (IsBadWritePtr (pDesc, sizeof(DMUS_OBJECTDESC))) {
260                 ERR(": pDesc bad write pointer\n");
261                 return E_POINTER;
262         }
263
264         DM_STRUCT_INIT(pDesc);
265         
266         /* here we go... */
267         IStream_Read (pStream, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
268         TRACE_(dmfile)(": %s chunk (size = 0x%08X)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
269         switch (Chunk.fccID) {  
270                 case FOURCC_RIFF: {
271                         IStream_Read (pStream, &Chunk.fccID, sizeof(FOURCC), NULL);                             
272                         TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(Chunk.fccID));
273                         StreamSize = Chunk.dwSize - sizeof(FOURCC);
274                         StreamCount = 0;
275                         if (Chunk.fccID == DMUS_FOURCC_CONTAINER_FORM) {
276                                 TRACE_(dmfile)(": container form\n");
277                                 /* set guidClass */
278                                 pDesc->dwValidData |= DMUS_OBJ_CLASS;
279                                 memcpy (&pDesc->guidClass, &CLSID_DirectMusicContainer, sizeof(CLSID));                         
280                                 do {
281                                         IStream_Read (pStream, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
282                                         StreamCount += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
283                                         TRACE_(dmfile)(": %s chunk (size = 0x%08X)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
284                                         switch (Chunk.fccID) {
285                                                 case DMUS_FOURCC_GUID_CHUNK: {
286                                                         TRACE_(dmfile)(": GUID chunk\n");
287                                                         pDesc->dwValidData |= DMUS_OBJ_OBJECT;
288                                                         IStream_Read (pStream, &pDesc->guidObject, Chunk.dwSize, NULL);
289                                                         TRACE_(dmdump)(": GUID: %s\n", debugstr_guid(&pDesc->guidObject));
290                                                         break;
291                                                 }
292                                                 case DMUS_FOURCC_VERSION_CHUNK: {
293                                                         TRACE_(dmfile)(": version chunk\n");
294                                                         pDesc->dwValidData |= DMUS_OBJ_VERSION;
295                                                         IStream_Read (pStream, &pDesc->vVersion, Chunk.dwSize, NULL);
296                                                         TRACE_(dmdump)(": version: %s\n", debugstr_dmversion(&pDesc->vVersion));
297                                                         break;
298                                                 }
299                                                 case DMUS_FOURCC_DATE_CHUNK: {
300                                                         TRACE_(dmfile)(": date chunk\n");
301                                                         IStream_Read (pStream, &pDesc->ftDate, Chunk.dwSize, NULL);
302                                                         pDesc->dwValidData |= DMUS_OBJ_DATE;
303                                                         TRACE_(dmdump)(": date: %s\n", debugstr_filetime(&pDesc->ftDate));
304                                                         break;
305                                                 }                                                               
306                                                 case DMUS_FOURCC_CATEGORY_CHUNK: {
307                                                         TRACE_(dmfile)(": category chunk\n");
308                                                         /* if it happens that string is too long,
309                                                            read what we can and skip the rest*/
310                                                         if (Chunk.dwSize > DMUS_MAX_CATEGORY_SIZE) {
311                                                                 IStream_Read (pStream, pDesc->wszCategory, DMUS_MAX_CATEGORY_SIZE, NULL);
312                                                                 liMove.QuadPart = Chunk.dwSize - DMUS_MAX_CATEGORY_SIZE;
313                                                                 IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
314                                                         } else {
315                                                                 IStream_Read (pStream, pDesc->wszCategory, Chunk.dwSize, NULL);
316                                                         }
317                                                         pDesc->dwValidData |= DMUS_OBJ_CATEGORY;
318                                                         TRACE_(dmdump)(": category: %s\n", debugstr_w(pDesc->wszCategory));                                                     
319                                                         break;
320                                                 }
321                                                 case FOURCC_LIST: {
322                                                         IStream_Read (pStream, &Chunk.fccID, sizeof(FOURCC), NULL);                             
323                                                         TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
324                                                         ListSize[0] = Chunk.dwSize - sizeof(FOURCC);
325                                                         ListCount[0] = 0;
326                                                         switch (Chunk.fccID) {
327                                                                 /* evil M$ UNFO list, which can (!?) contain INFO elements */
328                                                                 case DMUS_FOURCC_UNFO_LIST: {
329                                                                         TRACE_(dmfile)(": UNFO list\n");
330                                                                         do {
331                                                                                 IStream_Read (pStream, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
332                                                                                 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
333                                                                                 TRACE_(dmfile)(": %s chunk (size = 0x%08X)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
334                                                                                 switch (Chunk.fccID) {
335                                                                                         /* don't ask me why, but M$ puts INFO elements in UNFO list sometimes
336                                              (though strings seem to be valid unicode) */
337                                                                                         case mmioFOURCC('I','N','A','M'):
338                                                                                         case DMUS_FOURCC_UNAM_CHUNK: {
339                                                                                                 TRACE_(dmfile)(": name chunk\n");
340                                                                                                 /* if it happens that string is too long,
341                                                                                                            read what we can and skip the rest*/
342                                                                                                 if (Chunk.dwSize > DMUS_MAX_NAME_SIZE) {
343                                                                                                         IStream_Read (pStream, pDesc->wszName, DMUS_MAX_NAME_SIZE, NULL);
344                                                                                                         liMove.QuadPart = Chunk.dwSize - DMUS_MAX_NAME_SIZE;
345                                                                                                         IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
346                                                                                                 } else {
347                                                                                                         IStream_Read (pStream, pDesc->wszName, Chunk.dwSize, NULL);
348                                                                                                 }
349                                                                                                 pDesc->dwValidData |= DMUS_OBJ_NAME;
350                                                                                                 TRACE_(dmdump)(": name: %s\n", debugstr_w(pDesc->wszName));
351                                                                                                 break;
352                                                                                         }
353                                                                                         default: {
354                                                                                                 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
355                                                                                                 liMove.QuadPart = Chunk.dwSize;
356                                                                                                 IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
357                                                                                                 break;                                          
358                                                                                         }
359                                                                                 }
360                                                                                 TRACE_(dmfile)(": ListCount[0] = 0x%08X < ListSize[0] = 0x%08X\n", ListCount[0], ListSize[0]);
361                                                                         } while (ListCount[0] < ListSize[0]);
362                                                                         break;
363                                                                 }
364                                                                 default: {
365                                                                         TRACE_(dmfile)(": unknown (skipping)\n");
366                                                                         liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
367                                                                         IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
368                                                                         break;                                          
369                                                                 }
370                                                         }
371                                                         break;
372                                                 }       
373                                                 default: {
374                                                         TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
375                                                         liMove.QuadPart = Chunk.dwSize;
376                                                         IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
377                                                         break;                                          
378                                                 }
379                                         }
380                                         TRACE_(dmfile)(": StreamCount[0] = 0x%08X < StreamSize[0] = 0x%08X\n", StreamCount, StreamSize);
381                                 } while (StreamCount < StreamSize);
382                         } else {
383                                 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
384                                 liMove.QuadPart = StreamSize;
385                                 IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
386                                 return E_FAIL;
387                         }
388                 
389                         TRACE_(dmfile)(": reading finished\n");
390                         break;
391                 }
392                 default: {
393                         TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
394                         liMove.QuadPart = Chunk.dwSize;
395                         IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
396                         return DMUS_E_INVALIDFILE;
397                 }
398         }       
399         
400         TRACE(": returning descriptor:\n%s\n", debugstr_DMUS_OBJECTDESC(pDesc));
401         return S_OK;    
402 }
403
404 static const IDirectMusicObjectVtbl DirectMusicContainer_Object_Vtbl = {
405         IDirectMusicContainerImpl_IDirectMusicObject_QueryInterface,
406         IDirectMusicContainerImpl_IDirectMusicObject_AddRef,
407         IDirectMusicContainerImpl_IDirectMusicObject_Release,
408         IDirectMusicContainerImpl_IDirectMusicObject_GetDescriptor,
409         IDirectMusicContainerImpl_IDirectMusicObject_SetDescriptor,
410         IDirectMusicContainerImpl_IDirectMusicObject_ParseDescriptor
411 };
412
413 /* IPersistStream part: */
414 static HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_QueryInterface (LPPERSISTSTREAM iface, REFIID riid, LPVOID *ppobj) {
415         ICOM_THIS_MULTI(IDirectMusicContainerImpl, PersistStreamVtbl, iface);
416         return IDirectMusicContainerImpl_IDirectMusicContainer_QueryInterface ((LPDIRECTMUSICCONTAINER)&This->ContainerVtbl, riid, ppobj);
417 }
418
419 static ULONG WINAPI IDirectMusicContainerImpl_IPersistStream_AddRef (LPPERSISTSTREAM iface) {
420         ICOM_THIS_MULTI(IDirectMusicContainerImpl, PersistStreamVtbl, iface);
421         return IDirectMusicContainerImpl_IDirectMusicContainer_AddRef ((LPDIRECTMUSICCONTAINER)&This->ContainerVtbl);
422 }
423
424 static ULONG WINAPI IDirectMusicContainerImpl_IPersistStream_Release (LPPERSISTSTREAM iface) {
425         ICOM_THIS_MULTI(IDirectMusicContainerImpl, PersistStreamVtbl, iface);
426         return IDirectMusicContainerImpl_IDirectMusicContainer_Release ((LPDIRECTMUSICCONTAINER)&This->ContainerVtbl);
427 }
428
429 static HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_GetClassID (LPPERSISTSTREAM iface, CLSID* pClassID) {
430         ICOM_THIS_MULTI(IDirectMusicContainerImpl, PersistStreamVtbl, iface);
431         
432         TRACE("(%p, %p)\n", This, pClassID);
433         if (IsBadWritePtr (pClassID, sizeof(CLSID))) {
434                 ERR(": pClassID bad write pointer\n");
435                 return E_POINTER;
436         }
437         
438         *pClassID = CLSID_DirectMusicContainer;
439         return S_OK;
440 }
441
442 static HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_IsDirty (LPPERSISTSTREAM iface) {
443         /* FIXME: is implemented (somehow) */
444         return E_NOTIMPL;
445 }
446
447 static HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_Load (LPPERSISTSTREAM iface, IStream* pStm) {
448         ICOM_THIS_MULTI(IDirectMusicContainerImpl, PersistStreamVtbl, iface);
449         WINE_CHUNK Chunk;
450         DWORD StreamSize, StreamCount, ListSize[3], ListCount[3];
451         LARGE_INTEGER liMove; /* used when skipping chunks */
452         ULARGE_INTEGER uliPos; /* needed when dealing with RIFF chunks */
453         LPDIRECTMUSICGETLOADER pGetLoader;
454         LPDIRECTMUSICLOADER pLoader;
455         HRESULT result = S_OK;
456
457         TRACE("(%p, %p):\n", This, pStm);
458         
459         /* check whether pStm is valid read pointer */
460         if (IsBadReadPtr (pStm, sizeof(LPVOID))) {
461                 ERR(": pStm bad read pointer\n");
462                 return E_POINTER;
463         }
464         /* if stream is already set, this means we're loaded already */
465         if (This->pStream) {
466                 TRACE(": stream is already set, which means container is already loaded\n");
467                 return DMUS_E_ALREADY_LOADED;
468         }
469
470         /* get loader since it will be needed later */
471         if (FAILED(IStream_QueryInterface (pStm, &IID_IDirectMusicGetLoader, (LPVOID*)&pGetLoader))) {
472                 ERR(": stream not supported\n");
473                 return DMUS_E_UNSUPPORTED_STREAM;
474         }
475         IDirectMusicGetLoader_GetLoader (pGetLoader, &pLoader);
476         IDirectMusicGetLoader_Release (pGetLoader);
477         
478         This->pStream = pStm;
479         IStream_AddRef (pStm); /* add count for later references */
480         
481         /* start with load */
482         IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
483         TRACE_(dmfile)(": %s chunk (size = 0x%08X)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
484         switch (Chunk.fccID) {  
485                 case FOURCC_RIFF: {
486                         IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);                                
487                         TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(Chunk.fccID));
488                         StreamSize = Chunk.dwSize - sizeof(FOURCC);
489                         StreamCount = 0;
490                         switch (Chunk.fccID) {
491                                 case DMUS_FOURCC_CONTAINER_FORM: {
492                                         TRACE_(dmfile)(": container form\n");
493                                         memcpy (&This->Desc.guidClass, &CLSID_DirectMusicContainer, sizeof(CLSID));
494                                         This->Desc.dwValidData |= DMUS_OBJ_CLASS;
495                                         do {
496                                                 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
497                                                 StreamCount += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
498                                                 TRACE_(dmfile)(": %s chunk (size = 0x%08X)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
499                                                 switch (Chunk.fccID) {
500                                                         case DMUS_FOURCC_CONTAINER_CHUNK: {
501                                                                 TRACE_(dmfile)(": container header chunk\n");
502                                                                 IStream_Read (pStm, &This->Header, Chunk.dwSize, NULL);
503                                                                 TRACE_(dmdump)(": container header chunk:\n%s\n", debugstr_DMUS_IO_CONTAINER_HEADER(&This->Header));
504                                                                 break;  
505                                                         }
506                                                         case DMUS_FOURCC_GUID_CHUNK: {
507                                                                 TRACE_(dmfile)(": GUID chunk\n");
508                                                                 IStream_Read (pStm, &This->Desc.guidObject, Chunk.dwSize, NULL);
509                                                                 This->Desc.dwValidData |= DMUS_OBJ_OBJECT;
510                                                                 TRACE_(dmdump)(": GUID: %s\n", debugstr_guid(&This->Desc.guidObject));
511                                                                 break;
512                                                         }
513                                                         case DMUS_FOURCC_VERSION_CHUNK: {
514                                                                 TRACE_(dmfile)(": version chunk\n");
515                                                                 IStream_Read (pStm, &This->Desc.vVersion, Chunk.dwSize, NULL);
516                                                                 This->Desc.dwValidData |= DMUS_OBJ_VERSION;
517                                                                 TRACE_(dmdump)(": version: %s\n", debugstr_dmversion(&This->Desc.vVersion));
518                                                                 break;
519                                                         }
520                                                         case DMUS_FOURCC_DATE_CHUNK: {
521                                                                 TRACE_(dmfile)(": date chunk\n");
522                                                                 IStream_Read (pStm, &This->Desc.ftDate, Chunk.dwSize, NULL);
523                                                                 This->Desc.dwValidData |= DMUS_OBJ_DATE;
524                                                                 TRACE_(dmdump)(": date: %s\n", debugstr_filetime(&This->Desc.ftDate));
525                                                                 break;
526                                                         }                                                       
527                                                         case DMUS_FOURCC_CATEGORY_CHUNK: {
528                                                                 TRACE_(dmfile)(": category chunk\n");
529                                                                 /* if it happens that string is too long,
530                                                                    read what we can and skip the rest*/
531                                                                 if (Chunk.dwSize > DMUS_MAX_CATEGORY_SIZE) {
532                                                                         IStream_Read (pStm, This->Desc.wszCategory, DMUS_MAX_CATEGORY_SIZE, NULL);
533                                                                         liMove.QuadPart = Chunk.dwSize - DMUS_MAX_CATEGORY_SIZE;
534                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
535                                                                 } else {
536                                                                         IStream_Read (pStm, This->Desc.wszCategory, Chunk.dwSize, NULL);
537                                                                 }
538                                                                 This->Desc.dwValidData |= DMUS_OBJ_CATEGORY;
539                                                                 TRACE_(dmdump)(": category: %s\n", debugstr_w(This->Desc.wszCategory));                                                         
540                                                                 break;
541                                                         }
542                                                         case FOURCC_LIST: {
543                                                                 IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);                                
544                                                                 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
545                                                                 ListSize[0] = Chunk.dwSize - sizeof(FOURCC);
546                                                                 ListCount[0] = 0;
547                                                                 switch (Chunk.fccID) {
548                                                                         case DMUS_FOURCC_UNFO_LIST: {
549                                                                                 TRACE_(dmfile)(": UNFO list\n");
550                                                                                 do {
551                                                                                         IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
552                                                                                         ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
553                                                                                         TRACE_(dmfile)(": %s chunk (size = 0x%08X)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
554                                                                                         switch (Chunk.fccID) {
555                                                                                                 /* don't ask me why, but M$ puts INFO elements in UNFO list sometimes
556                                               (though strings seem to be valid unicode) */
557                                                                                                 case mmioFOURCC('I','N','A','M'):
558                                                                                                 case DMUS_FOURCC_UNAM_CHUNK: {
559                                                                                                         TRACE_(dmfile)(": name chunk\n");
560                                                                                                         /* if it happens that string is too long,
561                                                                                                            read what we can and skip the rest*/
562                                                                                                         if (Chunk.dwSize > DMUS_MAX_NAME_SIZE) {
563                                                                                                                 IStream_Read (pStm, This->Desc.wszName, DMUS_MAX_NAME_SIZE, NULL);
564                                                                                                                 liMove.QuadPart = Chunk.dwSize - DMUS_MAX_NAME_SIZE;
565                                                                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
566                                                                                                         } else {
567                                                                                                                 IStream_Read (pStm, This->Desc.wszName, Chunk.dwSize, NULL);
568                                                                                                         }
569                                                                                                         This->Desc.dwValidData |= DMUS_OBJ_NAME;
570                                                                                                         TRACE_(dmdump)(": name: %s\n", debugstr_w(This->Desc.wszName));
571                                                                                                         break;
572                                                                                                 }
573                                                                                                 default: {
574                                                                                                         TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
575                                                                                                         liMove.QuadPart = Chunk.dwSize;
576                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
577                                                                                                         break;                                          
578                                                                                                 }
579                                                                                         }
580                                                                                         TRACE_(dmfile)(": ListCount[0] = 0x%08X < ListSize[0] = 0x%08X\n", ListCount[0], ListSize[0]);
581                                                                                 } while (ListCount[0] < ListSize[0]);
582                                                                                 break;
583                                                                         }
584                                                                         case DMUS_FOURCC_CONTAINED_OBJECTS_LIST: {
585                                                                                 TRACE_(dmfile)(": contained objects list\n");
586                                                                                 do {
587                                                                                         IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
588                                                                                         ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
589                                                                                         TRACE_(dmfile)(": %s chunk (size = 0x%08X)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
590                                                                                         switch (Chunk.fccID) {
591                                                                                                 case FOURCC_LIST: {
592                                                                                                         IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);                                
593                                                                                                         TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
594                                                                                                         ListSize[1] = Chunk.dwSize - sizeof(FOURCC);
595                                                                                                         ListCount[1] = 0;
596                                                                                                         switch (Chunk.fccID) {
597                                                                                                                 case DMUS_FOURCC_CONTAINED_OBJECT_LIST: {
598                                                                                                                         LPWINE_CONTAINER_ENTRY pNewEntry;
599                                                                                                                         TRACE_(dmfile)(": contained object list\n");
600                                                                                                                         pNewEntry = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(WINE_CONTAINER_ENTRY));
601                                                                                                                         DM_STRUCT_INIT(&pNewEntry->Desc);
602                                                                                                                         do {
603                                                                                                                                 IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
604                                                                                                                                 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
605                                                                                                                                 TRACE_(dmfile)(": %s chunk (size = 0x%08X)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
606                                                                                                                                 switch (Chunk.fccID) {
607                                                                                                                                         case DMUS_FOURCC_CONTAINED_ALIAS_CHUNK: {
608                                                                                                                                                 TRACE_(dmfile)(": alias chunk\n");
609                                                                                                                                                 pNewEntry->wszAlias = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize);
610                                                                                                                                                 IStream_Read (pStm, pNewEntry->wszAlias, Chunk.dwSize, NULL);
611                                                                                                                                                 TRACE_(dmdump)(": alias: %s\n", debugstr_w(pNewEntry->wszAlias));
612                                                                                                                                                 break;
613                                                                                                                                         }
614                                                                                                                                         case DMUS_FOURCC_CONTAINED_OBJECT_CHUNK: {
615                                                                                                                                                 DMUS_IO_CONTAINED_OBJECT_HEADER tmpObjectHeader;
616                                                                                                                                                 TRACE_(dmfile)(": contained object header chunk\n");
617                                                                                                                                                 IStream_Read (pStm, &tmpObjectHeader, Chunk.dwSize, NULL);
618                                                                                                                                                 TRACE_(dmdump)(": contained object header: \n%s\n", debugstr_DMUS_IO_CONTAINED_OBJECT_HEADER(&tmpObjectHeader));
619                                                                                                                                                 /* copy guidClass */
620                                                                                                                                                 pNewEntry->Desc.dwValidData |= DMUS_OBJ_CLASS;
621                                                                                                                                                 memcpy (&pNewEntry->Desc.guidClass, &tmpObjectHeader.guidClassID, sizeof(GUID));
622                                                                                                                                                 /* store flags */
623                                                                                                                                                 pNewEntry->dwFlags = tmpObjectHeader.dwFlags;
624                                                                                                                                                 break;
625                                                                                                                                         }
626                                                                                                                                         /* now read data... it may be safe to read everything after object header chunk, 
627                                                                                                                                                 but I'm not comfortable with MSDN's "the header is *normally* followed by ..." */
628                                                                                                                                         case FOURCC_LIST: {
629                                                                                                                                                 IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);                                
630                                                                                                                                                 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
631                                                                                                                                                 ListSize[2] = Chunk.dwSize - sizeof(FOURCC);
632                                                                                                                                                 ListCount[2] = 0;
633                                                                                                                                                 switch (Chunk.fccID) {
634                                                                                                                                                         case DMUS_FOURCC_REF_LIST: {
635                                                                                                                                                                 TRACE_(dmfile)(": reference list\n");
636                                                                                                                                                                 pNewEntry->bIsRIFF = 0;
637                                                                                                                                                                 do {
638                                                                                                                                                                         IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
639                                                                                                                                                                         ListCount[2] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
640                                                                                                                                                                         TRACE_(dmfile)(": %s chunk (size = 0x%08X)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
641                                                                                                                                                                         switch (Chunk.fccID) {
642                                                                                                                                                                                 case DMUS_FOURCC_REF_CHUNK: {
643                                                                                                                                                                                         DMUS_IO_REFERENCE tmpReferenceHeader; /* temporary structure */
644                                                                                                                                                                                         TRACE_(dmfile)(": reference header chunk\n");
645                                                                                                                                                                                         memset (&tmpReferenceHeader, 0, sizeof(DMUS_IO_REFERENCE));
646                                                                                                                                                                                         IStream_Read (pStm, &tmpReferenceHeader, Chunk.dwSize, NULL);
647                                                                                                                                                                                         /* copy retrieved data to DMUS_OBJECTDESC */
648                                                                                                                                                                                         if (!IsEqualCLSID (&pNewEntry->Desc.guidClass, &tmpReferenceHeader.guidClassID)) ERR(": object header declares different CLSID than reference header?\n");
649                                                                                                                                                                                         /* it shouldn't be necessary to copy guidClass, since it was set in contained object header already...
650                                                                                                                                                                                            yet if they happen to be different, I'd rather stick to this one */
651                                                                                                                                                                                         memcpy (&pNewEntry->Desc.guidClass, &tmpReferenceHeader.guidClassID, sizeof(GUID));
652                                                                                                                                                                                         pNewEntry->Desc.dwValidData |= tmpReferenceHeader.dwValidData;
653                                                                                                                                                                                         break;                                                                                                                                  
654                                                                                                                                                                                 }
655                                                                                                                                                                                 case DMUS_FOURCC_GUID_CHUNK: {
656                                                                                                                                                                                         TRACE_(dmfile)(": guid chunk\n");
657                                                                                                                                                                                         /* no need to set flags since they were copied from reference header */
658                                                                                                                                                                                         IStream_Read (pStm, &pNewEntry->Desc.guidObject, Chunk.dwSize, NULL);
659                                                                                                                                                                                         break;
660                                                                                                                                                                                 }
661                                                                                                                                                                                 case DMUS_FOURCC_DATE_CHUNK: {
662                                                                                                                                                                                         TRACE_(dmfile)(": file date chunk\n");
663                                                                                                                                                                                         /* no need to set flags since they were copied from reference header */
664                                                                                                                                                                                         IStream_Read (pStm, &pNewEntry->Desc.ftDate, Chunk.dwSize, NULL);
665                                                                                                                                                                                         break;
666                                                                                                                                                                                 }
667                                                                                                                                                                                 case DMUS_FOURCC_NAME_CHUNK: {
668                                                                                                                                                                                         TRACE_(dmfile)(": name chunk\n");
669                                                                                                                                                                                         /* no need to set flags since they were copied from reference header */
670                                                                                                                                                                                         IStream_Read (pStm, pNewEntry->Desc.wszName, Chunk.dwSize, NULL);
671                                                                                                                                                                                         break;
672                                                                                                                                                                                 }
673                                                                                                                                                                                 case DMUS_FOURCC_FILE_CHUNK: {
674                                                                                                                                                                                         TRACE_(dmfile)(": file name chunk\n");
675                                                                                                                                                                                         /* no need to set flags since they were copied from reference header */
676                                                                                                                                                                                         IStream_Read (pStm, pNewEntry->Desc.wszFileName, Chunk.dwSize, NULL);
677                                                                                                                                                                                         break;
678                                                                                                                                                                                 }
679                                                                                                                                                                                 case DMUS_FOURCC_CATEGORY_CHUNK: {
680                                                                                                                                                                                         TRACE_(dmfile)(": category chunk\n");
681                                                                                                                                                                                         /* no need to set flags since they were copied from reference header */
682                                                                                                                                                                                         IStream_Read (pStm, pNewEntry->Desc.wszCategory, Chunk.dwSize, NULL);
683                                                                                                                                                                                         break;
684                                                                                                                                                                                 }
685                                                                                                                                                                                 case DMUS_FOURCC_VERSION_CHUNK: {
686                                                                                                                                                                                         TRACE_(dmfile)(": version chunk\n");
687                                                                                                                                                                                         /* no need to set flags since they were copied from reference header */
688                                                                                                                                                                                         IStream_Read (pStm, &pNewEntry->Desc.vVersion, Chunk.dwSize, NULL);
689                                                                                                                                                                                         break;
690                                                                                                                                                                                 }
691                                                                                                                                                                                 default: {
692                                                                                                                                                                                         TRACE_(dmfile)(": unknown chunk (skipping)\n");
693                                                                                                                                                                                         liMove.QuadPart = Chunk.dwSize;
694                                                                                                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip this chunk */
695                                                                                                                                                                                         break;
696                                                                                                                                                                                 }
697                                                                                                                                                                         }
698                                                                                                                                                                         TRACE_(dmfile)(": ListCount[2] = 0x%08X < ListSize[2] = 0x%08X\n", ListCount[2], ListSize[2]);
699                                                                                                                                                                 } while (ListCount[2] < ListSize[2]);
700                                                                                                                                                                 break;
701                                                                                                                                                         }
702                                                                                                                                                         default: {
703                                                                                                                                                                 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
704                                                                                                                                                                 return E_FAIL;
705                                                                                                                                                         }
706                                                                                                                                                 }
707                                                                                                                                                 break;
708                                                                                                                                         }
709                                                                                                                                         
710                                                                                                                                         case FOURCC_RIFF: {
711                                                                                                                                                 IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
712                                                                                                                                                 TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(Chunk.fccID));
713                                                                                                                                                 if (IS_VALID_DMFORM (Chunk.fccID)) {
714                                                                                                                                                         TRACE_(dmfile)(": valid DMUSIC form\n");
715                                                                                                                                                         pNewEntry->bIsRIFF = 1;
716                                                                                                                                                         /* we'll have to skip whole RIFF chunk after SetObject is called */
717                                                                                                                                                         liMove.QuadPart = 0;
718                                                                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, &uliPos);
719                                                                                                                                                         uliPos.QuadPart += (Chunk.dwSize - sizeof(FOURCC)); /* set uliPos at the end of RIFF chunk */                                                                                                                                                   
720                                                                                                                                                         /* move at the beginning of RIFF chunk */
721                                                                                                                                                         liMove.QuadPart = 0;
722                                                                                                                                                         liMove.QuadPart -= (sizeof(FOURCC)+sizeof(DWORD)+sizeof(FOURCC));
723                                                                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
724                                                                                                                                                         /* put pointer to stream in descriptor */
725                                                                                                                                                         pNewEntry->Desc.dwValidData |= DMUS_OBJ_STREAM;
726                                                                                                                                                         pNewEntry->Desc.pStream = pStm; /* we don't have to worry about cloning, since SetObject will perform it */
727                                                                                                                                                         /* wait till we get on the end of object list */
728                                                                                                                                                 } else {
729                                                                                                                                                         TRACE_(dmfile)(": invalid DMUSIC form (skipping)\n");
730                                                                                                                                                         liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
731                                                                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
732                                                                                                                                                         /* FIXME: should we return E_FAIL? */
733                                                                                                                                                 }
734                                                                                                                                                 break;
735                                                                                                                                         }
736                                                                                                                                         default: {
737                                                                                                                                                 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
738                                                                                                                                                 liMove.QuadPart = Chunk.dwSize;
739                                                                                                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
740                                                                                                                                                 break;                                          
741                                                                                                                                         }
742                                                                                                                                 }
743                                                                                                                                 TRACE_(dmfile)(": ListCount[1] = 0x%08X < ListSize[1] = 0x%08X\n", ListCount[1], ListSize[1]);
744                                                                                                                         } while (ListCount[1] < ListSize[1]);
745                                                                                                                         /* SetObject: this will fill descriptor with additional info    and add alias in loader's cache */
746                                                                                                                         IDirectMusicLoader_SetObject (pLoader, &pNewEntry->Desc);
747                                                                                                                         /* now that SetObject collected appropriate info into descriptor we can live happily ever after;
748                                                                                                                            or not, since we have to clean evidence of loading through stream... *sigh*
749                                                                                                                            and we have to skip rest of the chunk, if we loaded through RIFF */
750                                                                                                                         if (pNewEntry->bIsRIFF) {
751                                                                                                                                 liMove.QuadPart = uliPos.QuadPart;
752                                                                                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_SET, NULL);
753                                                                                                                                 pNewEntry->Desc.dwValidData &= ~DMUS_OBJ_STREAM; /* clear flag (and with bitwise complement) */
754                                                                                                                                 pNewEntry->Desc.pStream = NULL;                                                                                 
755                                                                                                                         }
756                                                                                                                         /* add entry to list of objects */
757                                                                                                                         list_add_tail (This->pContainedObjects, &pNewEntry->entry);
758                                                                                                                         break;
759                                                                                                                 }
760                                                                                                                 default: {
761                                                                                                                         TRACE_(dmfile)(": unknown (skipping)\n");
762                                                                                                                         liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
763                                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
764                                                                                                                         break;                                          
765                                                                                                                 }
766                                                                                                         }
767                                                                                                         break;
768                                                                                                 }
769                                                                                                 default: {
770                                                                                                         TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
771                                                                                                         liMove.QuadPart = Chunk.dwSize;
772                                                                                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
773                                                                                                         break;                                          
774                                                                                                 }
775                                                                                         }
776                                                                                         TRACE_(dmfile)(": ListCount[0] = 0x%08X < ListSize[0] = 0x%08X\n", ListCount[0], ListSize[0]);
777                                                                                 } while (ListCount[0] < ListSize[0]);
778                                                                                 break;
779                                                                         }                                                                       
780                                                                         default: {
781                                                                                 TRACE_(dmfile)(": unknown (skipping)\n");
782                                                                                 liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
783                                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
784                                                                                 break;                                          
785                                                                         }
786                                                                 }
787                                                                 break;
788                                                         }       
789                                                         default: {
790                                                                 TRACE_(dmfile)(": unknown chunk (irrevelant & skipping)\n");
791                                                                 liMove.QuadPart = Chunk.dwSize;
792                                                                 IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
793                                                                 break;                                          
794                                                         }
795                                                 }
796                                                 TRACE_(dmfile)(": StreamCount[0] = 0x%08X < StreamSize[0] = 0x%08X\n", StreamCount, StreamSize);
797                                         } while (StreamCount < StreamSize);
798                                         break;
799                                 }
800                                 default: {
801                                         TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
802                                         liMove.QuadPart = StreamSize;
803                                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
804                                         return E_FAIL;
805                                 }
806                         }
807                         TRACE_(dmfile)(": reading finished\n");
808                         This->Desc.dwValidData |= DMUS_OBJ_LOADED;
809                         break;
810                 }
811                 default: {
812                         TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
813                         liMove.QuadPart = Chunk.dwSize;
814                         IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
815                         return E_FAIL;
816                 }
817         }
818         
819         /* now, if DMUS_CONTAINER_NOLOADS is not set, we are supposed to load contained objects;
820            so when we call GetObject later, they'll already be in cache */
821         if (!(This->Header.dwFlags & DMUS_CONTAINER_NOLOADS)) {
822                 struct list *pEntry;
823                 LPWINE_CONTAINER_ENTRY pContainedObject;
824
825                 TRACE(": DMUS_CONTAINER_NOLOADS not set... load all objects\n");
826                 
827                 LIST_FOR_EACH (pEntry, This->pContainedObjects) {
828                         IDirectMusicObject* pObject;
829                         pContainedObject = LIST_ENTRY (pEntry, WINE_CONTAINER_ENTRY, entry);            
830                         /* get object from loader and then release it */
831                         if (SUCCEEDED(IDirectMusicLoader_GetObject (pLoader, &pContainedObject->Desc, &IID_IDirectMusicObject, (LPVOID*)&pObject))) {
832                                 pContainedObject->pObject = pObject; /* for final release */
833                                 IDirectMusicObject_Release (pObject); /* we don't really need this one */
834                         } else {
835                                 WARN(": failed to load contained object\n");
836                                 result = DMUS_S_PARTIALLOAD;
837                         }
838                 }
839         }
840         
841         IDirectMusicLoader_Release (pLoader); /* release loader */
842
843 #if 0
844         /* DEBUG: dumps whole container object tree: */
845         if (TRACE_ON(dmloader)) {
846                 int r = 0;
847                 LPWINE_CONTAINER_ENTRY tmpEntry;
848                 struct list *listEntry;
849
850                 TRACE("*** IDirectMusicContainer (%p) ***\n", This->ContainerVtbl);
851                 TRACE(" - Objects:\n");
852                 LIST_FOR_EACH (listEntry, This->pContainedObjects) {
853                         tmpEntry = LIST_ENTRY( listEntry, WINE_CONTAINER_ENTRY, entry );
854                         TRACE("    - Object[%i]:\n", r);
855                         TRACE("       - wszAlias: %s\n", debugstr_w(tmpEntry->wszAlias));
856                         TRACE("       - Object descriptor:\n%s\n", debugstr_DMUS_OBJECTDESC(&tmpEntry->Desc));
857                         r++;
858                 }
859         }
860 #endif
861
862         return result;
863 }
864
865 static HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_Save (LPPERSISTSTREAM iface, IStream* pStm, BOOL fClearDirty) {
866         ERR(": should not be needed\n");
867         return E_NOTIMPL;
868 }
869
870 static HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_GetSizeMax (LPPERSISTSTREAM iface, ULARGE_INTEGER* pcbSize) {
871         ERR(": should not be needed\n");
872         return E_NOTIMPL;
873 }
874
875 static const IPersistStreamVtbl DirectMusicContainer_PersistStream_Vtbl = {
876         IDirectMusicContainerImpl_IPersistStream_QueryInterface,
877         IDirectMusicContainerImpl_IPersistStream_AddRef,
878         IDirectMusicContainerImpl_IPersistStream_Release,
879         IDirectMusicContainerImpl_IPersistStream_GetClassID,
880         IDirectMusicContainerImpl_IPersistStream_IsDirty,
881         IDirectMusicContainerImpl_IPersistStream_Load,
882         IDirectMusicContainerImpl_IPersistStream_Save,
883         IDirectMusicContainerImpl_IPersistStream_GetSizeMax
884 };
885
886 /* for ClassFactory */
887 HRESULT WINAPI DMUSIC_CreateDirectMusicContainerImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter) {
888         IDirectMusicContainerImpl* obj;
889
890         obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicContainerImpl));
891         if (NULL == obj) {
892                 *ppobj = NULL;
893                 return E_OUTOFMEMORY;
894         }
895         obj->ContainerVtbl = &DirectMusicContainer_Container_Vtbl;
896         obj->ObjectVtbl = &DirectMusicContainer_Object_Vtbl;
897         obj->PersistStreamVtbl = &DirectMusicContainer_PersistStream_Vtbl;
898         obj->dwRef = 0; /* will be inited by QueryInterface */
899         obj->pContainedObjects = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(struct list));
900         list_init (obj->pContainedObjects);
901
902         /* increase number of instances */
903         InterlockedIncrement (&dwDirectMusicContainer);
904         
905         return IDirectMusicContainerImpl_IDirectMusicContainer_QueryInterface ((LPDIRECTMUSICCONTAINER)&obj->ContainerVtbl, lpcGUID, ppobj);
906 }
907
908 HRESULT WINAPI DMUSIC_DestroyDirectMusicContainerImpl (LPDIRECTMUSICCONTAINER iface) {
909         ICOM_THIS_MULTI(IDirectMusicContainerImpl, ContainerVtbl, iface);
910         LPDIRECTMUSICLOADER pLoader;
911         LPDIRECTMUSICGETLOADER pGetLoader;
912         struct list *pEntry;
913         LPWINE_CONTAINER_ENTRY pContainedObject;
914
915         /* get loader (from stream we loaded from) */
916         TRACE(": getting loader\n");
917         IStream_QueryInterface (This->pStream, &IID_IDirectMusicGetLoader, (LPVOID*)&pGetLoader);
918         IDirectMusicGetLoader_GetLoader (pGetLoader, &pLoader);
919         IDirectMusicGetLoader_Release (pGetLoader);
920         
921         /* release objects from loader's cache (if appropriate) */
922         TRACE(": releasing objects from loader's cache\n");
923         LIST_FOR_EACH (pEntry, This->pContainedObjects) {
924                 pContainedObject = LIST_ENTRY (pEntry, WINE_CONTAINER_ENTRY, entry);
925                 /* my tests indicate that container releases objects *only* 
926                    if they were loaded at it's load-time (makes sense, it doesn't
927                    have pointers to objects otherwise); BTW: native container seems
928                    ti ignore the flags (I won't) */
929                 if (pContainedObject->pObject && !(pContainedObject->dwFlags & DMUS_CONTAINED_OBJF_KEEP)) {
930                         /* flags say it shouldn't be kept in loader's cache */
931                         IDirectMusicLoader_ReleaseObject (pLoader, pContainedObject->pObject);
932                 }
933         }       
934         IDirectMusicLoader_Release (pLoader);
935         
936         /* release stream we loaded from */
937         IStream_Release (This->pStream);
938         
939         /* FIXME: release allocated entries */
940         
941         /* decrease number of instances */
942         InterlockedDecrement (&dwDirectMusicContainer); 
943         
944         return S_OK;
945 }