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