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