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